* ExecInitPartitionDispatchInfo * Lock the partitioned table (if not locked already) and initialize * PartitionDispatch for a partitioned table and store it in the next * available slot in the proute->partition_dispatch_info array. Also, * record the index into this array in the parent_pd->indexes[] array in * the partidx element so that we can properly retrieve the newly created * Pa
| 1048 | * PartitionDispatch later. |
| 1049 | */ |
| 1050 | static PartitionDispatch |
| 1051 | ExecInitPartitionDispatchInfo(EState *estate, |
| 1052 | PartitionTupleRouting *proute, Oid partoid, |
| 1053 | PartitionDispatch parent_pd, int partidx, |
| 1054 | ResultRelInfo *rootResultRelInfo) |
| 1055 | { |
| 1056 | Relation rel; |
| 1057 | PartitionDesc partdesc; |
| 1058 | PartitionDispatch pd; |
| 1059 | int dispatchidx; |
| 1060 | MemoryContext oldcxt; |
| 1061 | |
| 1062 | /* |
| 1063 | * For data modification, it is better that executor does not include |
| 1064 | * partitions being detached, except when running in snapshot-isolation |
| 1065 | * mode. This means that a read-committed transaction immediately gets a |
| 1066 | * "no partition for tuple" error when a tuple is inserted into a |
| 1067 | * partition that's being detached concurrently, but a transaction in |
| 1068 | * repeatable-read mode can still use such a partition. |
| 1069 | */ |
| 1070 | if (estate->es_partition_directory == NULL) |
| 1071 | estate->es_partition_directory = |
| 1072 | CreatePartitionDirectory(estate->es_query_cxt, |
| 1073 | !IsolationUsesXactSnapshot()); |
| 1074 | |
| 1075 | oldcxt = MemoryContextSwitchTo(proute->memcxt); |
| 1076 | |
| 1077 | /* |
| 1078 | * Only sub-partitioned tables need to be locked here. The root |
| 1079 | * partitioned table will already have been locked as it's referenced in |
| 1080 | * the query's rtable. |
| 1081 | */ |
| 1082 | if (partoid != RelationGetRelid(proute->partition_root)) |
| 1083 | rel = table_open(partoid, RowExclusiveLock); |
| 1084 | else |
| 1085 | rel = proute->partition_root; |
| 1086 | partdesc = PartitionDirectoryLookup(estate->es_partition_directory, rel); |
| 1087 | |
| 1088 | pd = (PartitionDispatch) palloc(offsetof(PartitionDispatchData, indexes) + |
| 1089 | partdesc->nparts * sizeof(int)); |
| 1090 | pd->reldesc = rel; |
| 1091 | pd->key = RelationGetPartitionKey(rel); |
| 1092 | pd->keystate = NIL; |
| 1093 | pd->partdesc = partdesc; |
| 1094 | if (parent_pd != NULL) |
| 1095 | { |
| 1096 | TupleDesc tupdesc = RelationGetDescr(rel); |
| 1097 | |
| 1098 | /* |
| 1099 | * For sub-partitioned tables where the column order differs from its |
| 1100 | * direct parent partitioned table, we must store a tuple table slot |
| 1101 | * initialized with its tuple descriptor and a tuple conversion map to |
| 1102 | * convert a tuple from its parent's rowtype to its own. This is to |
| 1103 | * make sure that we are looking at the correct row using the correct |
| 1104 | * tuple descriptor when computing its partition key for tuple |
| 1105 | * routing. |
| 1106 | */ |
| 1107 | pd->tupmap = build_attrmap_by_name_if_req(RelationGetDescr(parent_pd->reldesc), |
no test coverage detected