@@ -113,6 +113,10 @@ static void pathman_update_trigger_func_move_tuple(Relation source_rel,
113113 HeapTuple old_tuple ,
114114 HeapTuple new_tuple );
115115
116+ static Oid find_target_partition (Relation source_rel , HeapTuple tuple );
117+ static Oid find_topmost_parent (Oid partition );
118+ static Oid find_deepest_partition (Oid parent , Relation source_rel , HeapTuple tuple );
119+
116120
117121/*
118122 * ------------------------
@@ -1086,26 +1090,26 @@ pathman_update_trigger_func(PG_FUNCTION_ARGS)
10861090
10871091 Relation source_rel ;
10881092
1089- Oid parent_relid ,
1090- source_relid ,
1093+ // Oid parent_relid,
1094+ Oid source_relid ,
10911095 target_relid ;
10921096
10931097 HeapTuple old_tuple ,
10941098 new_tuple ;
10951099
1096- Datum value ;
1097- Oid value_type ;
1098- bool isnull ;
1099- ExprDoneCond itemIsDone ;
1100+ // Datum value;
1101+ // Oid value_type;
1102+ // bool isnull;
1103+ // ExprDoneCond itemIsDone;
11001104
1101- Oid * parts ;
1102- int nparts ;
1105+ // Oid *parts;
1106+ // int nparts;
11031107
1104- ExprContext * econtext ;
1105- ExprState * expr_state ;
1106- MemoryContext old_mcxt ;
1107- PartParentSearch parent_search ;
1108- const PartRelationInfo * prel ;
1108+ // ExprContext *econtext;
1109+ // ExprState *expr_state;
1110+ // MemoryContext old_mcxt;
1111+ // PartParentSearch parent_search;
1112+ // const PartRelationInfo *prel;
11091113
11101114 /* Handle user calls */
11111115 if (!CALLED_AS_TRIGGER (fcinfo ))
@@ -1128,22 +1132,161 @@ pathman_update_trigger_func(PG_FUNCTION_ARGS)
11281132 old_tuple = trigdata -> tg_trigtuple ;
11291133 new_tuple = trigdata -> tg_newtuple ;
11301134
1131- /* Find parent relation and partitioning info */
1132- parent_relid = get_parent_of_partition (source_relid , & parent_search );
1133- if (parent_search != PPS_ENTRY_PART_PARENT )
1135+ // /* Find parent relation and partitioning info */
1136+ // parent_relid = get_parent_of_partition(source_relid, &parent_search);
1137+ // if (parent_search != PPS_ENTRY_PART_PARENT)
1138+ // elog(ERROR, "relation \"%s\" is not a partition",
1139+ // RelationGetRelationName(source_rel));
1140+
1141+ // /* Fetch partition dispatch info */
1142+ // prel = get_pathman_relation_info(parent_relid);
1143+ // shout_if_prel_is_invalid(parent_relid, prel, PT_ANY);
1144+
1145+ // /* Execute partitioning expression */
1146+ // econtext = CreateStandaloneExprContext();
1147+ // old_mcxt = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
1148+ // expr_state = pathman_update_trigger_build_expr_state(prel,
1149+ // source_rel,
1150+ // new_tuple,
1151+ // &value_type);
1152+ // value = ExecEvalExpr(expr_state, econtext, &isnull, &itemIsDone);
1153+ // MemoryContextSwitchTo(old_mcxt);
1154+
1155+ // if (isnull)
1156+ // elog(ERROR, ERR_PART_ATTR_NULL);
1157+
1158+ // if (itemIsDone != ExprSingleResult)
1159+ // elog(ERROR, ERR_PART_ATTR_MULTIPLE_RESULTS);
1160+
1161+ // /* Search for matching partitions */
1162+ // parts = find_partitions_for_value(value, value_type, prel, &nparts);
1163+
1164+
1165+ // /* We can free expression context now */
1166+ // FreeExprContext(econtext, false);
1167+
1168+ // if (nparts > 1)
1169+ // elog(ERROR, ERR_PART_ATTR_MULTIPLE);
1170+ // else if (nparts == 0)
1171+ // {
1172+ // target_relid = create_partitions_for_value(PrelParentRelid(prel),
1173+ // value, value_type);
1174+
1175+ // /* get_pathman_relation_info() will refresh this entry */
1176+ // invalidate_pathman_relation_info(PrelParentRelid(prel), NULL);
1177+ // }
1178+ // else target_relid = parts[0];
1179+
1180+ // pfree(parts);
1181+ target_relid = find_target_partition (source_rel , new_tuple );
1182+
1183+ /* Convert tuple if target partition has changed */
1184+ if (target_relid != source_relid )
1185+ {
1186+ Relation target_rel ;
1187+ LOCKMODE lockmode = RowExclusiveLock ; /* UPDATE */
1188+
1189+ /* Lock partition and check if it exists */
1190+ LockRelationOid (target_relid , lockmode );
1191+ if (!SearchSysCacheExists1 (RELOID , ObjectIdGetDatum (target_relid )))
1192+ /* TODO: !!! */
1193+ elog (ERROR , ERR_PART_ATTR_NO_PART , "()" );
1194+ // elog(ERROR, ERR_PART_ATTR_NO_PART, datum_to_cstring(value, value_type));
1195+
1196+ /* Open partition */
1197+ target_rel = heap_open (target_relid , lockmode );
1198+
1199+ /* Move tuple from source relation to the selected partition */
1200+ pathman_update_trigger_func_move_tuple (source_rel , target_rel ,
1201+ old_tuple , new_tuple );
1202+
1203+ /* Close partition */
1204+ heap_close (target_rel , lockmode );
1205+
1206+ /* We've made some changes */
1207+ PG_RETURN_VOID ();
1208+ }
1209+
1210+ /* Just return NEW tuple */
1211+ PG_RETURN_POINTER (new_tuple );
1212+ }
1213+
1214+ /*
1215+ * Find partition satisfying values of the tuple
1216+ */
1217+ static Oid
1218+ find_target_partition (Relation source_rel , HeapTuple tuple )
1219+ {
1220+ Oid source_relid ,
1221+ target_relid ,
1222+ parent_relid ;
1223+
1224+ source_relid = RelationGetRelid (source_rel );
1225+ parent_relid = find_topmost_parent (source_relid );
1226+ target_relid = find_deepest_partition (parent_relid , source_rel , tuple );
1227+
1228+ return target_relid ;
1229+ }
1230+
1231+ static Oid
1232+ find_topmost_parent (Oid relid )
1233+ {
1234+ Oid last ;
1235+ PartParentSearch parent_search ;
1236+
1237+ last = relid ;
1238+
1239+ /* Iterate through parents until the topmost */
1240+ while (1 )
1241+ {
1242+ Oid parent = get_parent_of_partition (last , & parent_search );
1243+
1244+ if (parent_search != PPS_ENTRY_PART_PARENT )
1245+ break ;
1246+ last = parent ;
1247+ }
1248+
1249+ /* If relation doesn't have parent then just throw an error */
1250+ if (last == relid )
11341251 elog (ERROR , "relation \"%s\" is not a partition" ,
1135- RelationGetRelationName (source_rel ));
1252+ get_rel_name (relid ));
1253+
1254+ return last ;
1255+ }
1256+
1257+ /*
1258+ * Recursive search for the deepest partition satisfying the given tuple
1259+ */
1260+ static Oid
1261+ find_deepest_partition (Oid parent , Relation source_rel , HeapTuple tuple )
1262+ {
1263+ const PartRelationInfo * prel ;
1264+ Oid * parts ;
1265+ int nparts ;
1266+
1267+ ExprContext * econtext ;
1268+ ExprState * expr_state ;
1269+ MemoryContext old_mcxt ;
1270+
1271+ Datum value ;
1272+ Oid value_type ;
1273+ bool isnull ;
1274+ ExprDoneCond itemIsDone ;
1275+
1276+ Oid target_relid ;
1277+ Oid subpartition ;
11361278
11371279 /* Fetch partition dispatch info */
1138- prel = get_pathman_relation_info (parent_relid );
1139- shout_if_prel_is_invalid (parent_relid , prel , PT_ANY );
1280+ prel = get_pathman_relation_info (parent );
1281+ if (!prel )
1282+ return InvalidOid ;
11401283
11411284 /* Execute partitioning expression */
11421285 econtext = CreateStandaloneExprContext ();
11431286 old_mcxt = MemoryContextSwitchTo (econtext -> ecxt_per_tuple_memory );
11441287 expr_state = pathman_update_trigger_build_expr_state (prel ,
11451288 source_rel ,
1146- new_tuple ,
1289+ tuple ,
11471290 & value_type );
11481291 value = ExecEvalExpr (expr_state , econtext , & isnull , & itemIsDone );
11491292 MemoryContextSwitchTo (old_mcxt );
@@ -1170,37 +1313,16 @@ pathman_update_trigger_func(PG_FUNCTION_ARGS)
11701313 /* get_pathman_relation_info() will refresh this entry */
11711314 invalidate_pathman_relation_info (PrelParentRelid (prel ), NULL );
11721315 }
1173- else target_relid = parts [ 0 ];
1174-
1316+ else
1317+ target_relid = parts [ 0 ];
11751318 pfree (parts );
11761319
1177- /* Convert tuple if target partition has changed */
1178- if (target_relid != source_relid )
1179- {
1180- Relation target_rel ;
1181- LOCKMODE lockmode = RowExclusiveLock ; /* UPDATE */
1182-
1183- /* Lock partition and check if it exists */
1184- LockRelationOid (target_relid , lockmode );
1185- if (!SearchSysCacheExists1 (RELOID , ObjectIdGetDatum (target_relid )))
1186- elog (ERROR , ERR_PART_ATTR_NO_PART , datum_to_cstring (value , value_type ));
1187-
1188- /* Open partition */
1189- target_rel = heap_open (target_relid , lockmode );
1190-
1191- /* Move tuple from source relation to the selected partition */
1192- pathman_update_trigger_func_move_tuple (source_rel , target_rel ,
1193- old_tuple , new_tuple );
1194-
1195- /* Close partition */
1196- heap_close (target_rel , lockmode );
1197-
1198- /* We've made some changes */
1199- PG_RETURN_VOID ();
1200- }
1320+ /* Try to go deeper recursively and see if there is subpartition */
1321+ subpartition = find_deepest_partition (target_relid , source_rel , tuple );
1322+ if (OidIsValid (subpartition ))
1323+ return subpartition ;
12011324
1202- /* Just return NEW tuple */
1203- PG_RETURN_POINTER (new_tuple );
1325+ return target_relid ;
12041326}
12051327
12061328struct replace_vars_cxt
0 commit comments