@@ -70,6 +70,7 @@ PG_FUNCTION_INFO_V1( invoke_on_partition_created_callback );
7070PG_FUNCTION_INFO_V1 ( check_security_policy );
7171
7272PG_FUNCTION_INFO_V1 ( create_update_triggers );
73+ PG_FUNCTION_INFO_V1 ( drop_update_triggers );
7374PG_FUNCTION_INFO_V1 ( pathman_update_trigger_func );
7475PG_FUNCTION_INFO_V1 ( create_single_update_trigger );
7576PG_FUNCTION_INFO_V1 ( has_update_trigger );
@@ -113,6 +114,9 @@ static void pathman_update_trigger_func_move_tuple(Relation source_rel,
113114 HeapTuple old_tuple ,
114115 HeapTuple new_tuple );
115116
117+ static void create_update_triggers_internal (Oid relid );
118+ static void drop_update_triggers_internal (Oid relid );
119+
116120static void collect_update_trigger_columns (Oid relid , List * * columns );
117121static Oid find_target_partition (Relation source_rel , HeapTuple tuple );
118122static Oid find_topmost_parent (Oid partition );
@@ -150,6 +154,7 @@ get_parent_of_partition_pl(PG_FUNCTION_ARGS)
150154 Oid partition = PG_GETARG_OID (0 );
151155 PartParentSearch parent_search ;
152156 Oid parent ;
157+ bool emit_error = PG_GETARG_BOOL (1 );
153158
154159 /* Fetch parent & write down search status */
155160 parent = get_parent_of_partition (partition , & parent_search );
@@ -160,14 +165,13 @@ get_parent_of_partition_pl(PG_FUNCTION_ARGS)
160165 /* It must be parent known by pg_pathman */
161166 if (parent_search == PPS_ENTRY_PART_PARENT )
162167 PG_RETURN_OID (parent );
163- else
164- {
168+
169+ if ( emit_error )
165170 ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
166171 errmsg ("\"%s\" is not a partition" ,
167172 get_rel_name_or_relid (partition ))));
168173
169- PG_RETURN_NULL ();
170- }
174+ PG_RETURN_NULL ();
171175}
172176
173177/*
@@ -1480,36 +1484,72 @@ pathman_update_trigger_func_move_tuple(Relation source_rel,
14801484 FreeTupleDesc (target_tupdesc );
14811485}
14821486
1483- /* Create UPDATE triggers for all partitions */
1487+ /*
1488+ * Create UPDATE triggers for all partitions and subpartitions
1489+ */
14841490Datum
14851491create_update_triggers (PG_FUNCTION_ARGS )
14861492{
1487- Oid parent = PG_GETARG_OID (0 );
1493+ Oid relid = PG_GETARG_OID (0 ),
1494+ parent ;
1495+ PartParentSearch parent_search ;
1496+
1497+ /*
1498+ * If table has parent then we should check that parent has update trigger.
1499+ * In the ideal world this error should never be thrown since we create and
1500+ * drop update triggers for the whole partitions tree and not its parts
1501+ */
1502+ parent = get_parent_of_partition (relid , & parent_search );
1503+ if (parent_search == PPS_ENTRY_PART_PARENT )
1504+ if (!has_update_trigger_internal (parent ))
1505+ ereport (ERROR ,
1506+ (errmsg ("Parent table must have an update trigger" ),
1507+ errhint ("Try to perform SELECT %s.create_update_triggers('%s');" ,
1508+ get_namespace_name (get_pathman_schema ()),
1509+ get_qualified_rel_name (parent ))));
1510+
1511+ /* Recursively add triggers */
1512+ create_update_triggers_internal (relid );
1513+ PG_RETURN_VOID ();
1514+ }
1515+
1516+ /*
1517+ * Create UPDATE triggers recursively
1518+ */
1519+ static void
1520+ create_update_triggers_internal (Oid relid )
1521+ {
14881522 Oid * children ;
14891523 const char * trigname ;
14901524 const PartRelationInfo * prel ;
14911525 uint32 i ;
14921526 List * columns = NIL ;
14931527
14941528 /* Check that table is partitioned */
1495- prel = get_pathman_relation_info (parent );
1496- shout_if_prel_is_invalid (parent , prel , PT_ANY );
1529+ prel = get_pathman_relation_info (relid );
1530+ /* TODO: check this only for topmost relid? */
1531+ // shout_if_prel_is_invalid(relid, prel, PT_ANY);
1532+ if (!prel )
1533+ return ;
14971534
1498- /* Acquire trigger and attribute names */
1499- trigname = build_update_trigger_name_internal (parent );
1535+ /* Acquire trigger name */
1536+ trigname = build_update_trigger_name_internal (relid );
15001537
15011538 /* Create trigger for parent */
1502- collect_update_trigger_columns (parent , & columns );
1503- create_single_update_trigger_internal (parent , trigname , columns );
1539+ collect_update_trigger_columns (relid , & columns );
1540+ create_single_update_trigger_internal (relid , trigname , columns );
15041541
15051542 /* Fetch children array */
15061543 children = PrelGetChildrenArray (prel );
15071544
15081545 /* Create triggers for each partition */
15091546 for (i = 0 ; i < PrelChildrenCount (prel ); i ++ )
1547+ {
15101548 create_single_update_trigger_internal (children [i ], trigname , columns );
15111549
1512- PG_RETURN_VOID ();
1550+ /* Perform the same procedure on subpartitions */
1551+ create_update_triggers_internal (children [i ]);
1552+ }
15131553}
15141554
15151555static void
@@ -1558,6 +1598,67 @@ create_single_update_trigger(PG_FUNCTION_ARGS)
15581598 PG_RETURN_VOID ();
15591599}
15601600
1601+ /*
1602+ * Drop UPDATE triggers for all partitions and subpartitions
1603+ */
1604+ Datum
1605+ drop_update_triggers (PG_FUNCTION_ARGS )
1606+ {
1607+ Oid relid = PG_GETARG_OID (0 ),
1608+ parent ;
1609+ PartParentSearch parent_search ;
1610+
1611+ /*
1612+ * We can drop triggers only if relid is the topmost parent table (or if
1613+ * its parent doesn't have update triggers (which should never happen in
1614+ * the ideal world)
1615+ */
1616+ parent = get_parent_of_partition (relid , & parent_search );
1617+ if (parent_search == PPS_ENTRY_PART_PARENT )
1618+ if (has_update_trigger_internal (parent ))
1619+ ereport (ERROR ,
1620+ (errmsg ("Parent table must not have an update trigger" ),
1621+ errhint ("Try to perform SELECT %s.drop_triggers('%s');" ,
1622+ get_namespace_name (get_pathman_schema ()),
1623+ get_qualified_rel_name (parent ))));
1624+
1625+ /* Recursively drop triggers */
1626+ drop_update_triggers_internal (relid );
1627+ PG_RETURN_VOID ();
1628+ }
1629+
1630+ static void
1631+ drop_update_triggers_internal (Oid relid )
1632+ {
1633+ Oid * children ;
1634+ const char * trigname ;
1635+ const PartRelationInfo * prel ;
1636+ uint32 i ;
1637+
1638+ prel = get_pathman_relation_info (relid );
1639+ if (!prel )
1640+ return ;
1641+
1642+ /* Acquire trigger name */
1643+ trigname = build_update_trigger_name_internal (relid );
1644+
1645+ /* Fetch children array */
1646+ children = PrelGetChildrenArray (prel );
1647+
1648+ /* Drop triggers on partitions */
1649+ for (i = 0 ; i < PrelChildrenCount (prel ); i ++ )
1650+ {
1651+ drop_single_update_trigger_internal (children [i ], trigname );
1652+
1653+ /* Recursively drop triggers on subpartitions */
1654+ drop_update_triggers_internal (children [i ]);
1655+
1656+ }
1657+
1658+ /* Drop trigger on parent */
1659+ drop_single_update_trigger_internal (relid , trigname );
1660+ }
1661+
15611662/* Check if relation has pg_pathman's update trigger */
15621663Datum
15631664has_update_trigger (PG_FUNCTION_ARGS )
0 commit comments