21
21
#include "access/htup_details.h"
22
22
#include "access/xact.h"
23
23
#include "catalog/indexing.h"
24
+ #include "catalog/pg_trigger.h"
24
25
#include "catalog/pg_type.h"
25
26
#include "commands/tablespace.h"
26
27
#include "commands/trigger.h"
27
28
#include "funcapi.h"
28
29
#include "miscadmin.h"
29
30
#include "utils/builtins.h"
31
+ #include "utils/fmgroids.h"
30
32
#include "utils/inval.h"
31
33
#include "utils/jsonb.h"
32
34
#include "utils/snapmgr.h"
35
37
36
38
37
39
static Oid get_partition_for_key (const PartRelationInfo * prel , Datum key );
40
+ static void create_single_update_trigger_internal (Oid relid ,
41
+ const char * attname );
42
+ static bool update_trigger_exists (Oid relid , char * trigname );
38
43
39
44
40
45
/* Function declarations */
@@ -74,7 +79,9 @@ PG_FUNCTION_INFO_V1( check_security_policy );
74
79
PG_FUNCTION_INFO_V1 ( debug_capture );
75
80
PG_FUNCTION_INFO_V1 ( get_pathman_lib_version );
76
81
82
+ PG_FUNCTION_INFO_V1 ( create_update_triggers );
77
83
PG_FUNCTION_INFO_V1 ( update_trigger_func );
84
+ PG_FUNCTION_INFO_V1 ( create_single_update_trigger );
78
85
79
86
80
87
/*
@@ -97,16 +104,6 @@ static void on_partitions_updated_internal(Oid partitioned_table, bool add_callb
97
104
static void on_partitions_removed_internal (Oid partitioned_table , bool add_callbacks );
98
105
99
106
100
- /*
101
- * Extracted common check.
102
- */
103
- static bool
104
- check_relation_exists (Oid relid )
105
- {
106
- return get_rel_type_id (relid ) != InvalidOid ;
107
- }
108
-
109
-
110
107
/*
111
108
* ----------------------------
112
109
* Partition events callbacks
@@ -543,11 +540,7 @@ build_update_trigger_name(PG_FUNCTION_ARGS)
543
540
Oid relid = PG_GETARG_OID (0 );
544
541
const char * result ; /* trigger's name can't be qualified */
545
542
546
- /* Check that relation exists */
547
- if (!check_relation_exists (relid ))
548
- elog (ERROR , "Invalid relation %u" , relid );
549
-
550
- result = quote_identifier (psprintf ("%s_upd_trig" , get_rel_name (relid )));
543
+ result = build_update_trigger_name_internal (relid );
551
544
552
545
PG_RETURN_TEXT_P (cstring_to_text (result ));
553
546
}
@@ -1020,6 +1013,7 @@ update_trigger_func(PG_FUNCTION_ARGS)
1020
1013
PG_RETURN_VOID ();
1021
1014
}
1022
1015
1016
+
1023
1017
/*
1024
1018
* Returns Oid of partition corresponding to partitioning key value. Throws
1025
1019
* an error if no partition found
@@ -1042,3 +1036,127 @@ get_partition_for_key(const PartRelationInfo *prel, Datum key)
1042
1036
else
1043
1037
return parts [0 ];
1044
1038
}
1039
+
1040
+ /*
1041
+ * Create UPDATE triggers for all partitions
1042
+ */
1043
+ Datum
1044
+ create_update_triggers (PG_FUNCTION_ARGS )
1045
+ {
1046
+ const PartRelationInfo * prel ;
1047
+ Oid parent = PG_GETARG_OID (0 );
1048
+ Oid * children ;
1049
+ char * attname ,
1050
+ * trigname ;
1051
+ int i ;
1052
+
1053
+ prel = get_pathman_relation_info (parent );
1054
+ shout_if_prel_is_invalid (parent , prel , PT_INDIFFERENT );
1055
+
1056
+ attname = get_attname (prel -> key , prel -> attnum );
1057
+ children = PrelGetChildrenArray (prel );
1058
+ trigname = build_update_trigger_name_internal (parent );
1059
+
1060
+ /* Create triggers for each partition */
1061
+ for (i = 0 ; i < PrelChildrenCount (prel ); i ++ )
1062
+ {
1063
+ if (update_trigger_exists (children [i ], trigname ))
1064
+ ereport (ERROR ,
1065
+ (errcode (ERRCODE_DUPLICATE_OBJECT ),
1066
+ errmsg ("trigger \"%s\" for relation \"%s\" already exists" ,
1067
+ trigname , get_rel_name_or_relid (children [i ]))));
1068
+
1069
+ create_single_update_trigger_internal (children [i ], attname );
1070
+ }
1071
+
1072
+ PG_RETURN_VOID ();
1073
+ }
1074
+
1075
+ static bool
1076
+ update_trigger_exists (Oid relid , char * trigname )
1077
+ {
1078
+ bool res = false;
1079
+ Relation tgrel ;
1080
+ SysScanDesc tgscan ;
1081
+ ScanKeyData key ;
1082
+ HeapTuple tuple ;
1083
+
1084
+ tgrel = heap_open (TriggerRelationId , RowExclusiveLock );
1085
+
1086
+ ScanKeyInit (& key ,
1087
+ Anum_pg_trigger_tgrelid ,
1088
+ BTEqualStrategyNumber , F_OIDEQ ,
1089
+ ObjectIdGetDatum (relid ));
1090
+ tgscan = systable_beginscan (tgrel , TriggerRelidNameIndexId , true,
1091
+ NULL , 1 , & key );
1092
+ while (HeapTupleIsValid (tuple = systable_getnext (tgscan )))
1093
+ {
1094
+ Form_pg_trigger pg_trigger = (Form_pg_trigger ) GETSTRUCT (tuple );
1095
+
1096
+ if (namestrcmp (& (pg_trigger -> tgname ), trigname ) == 0 )
1097
+ {
1098
+ res = true;
1099
+ break ;
1100
+ }
1101
+ }
1102
+ systable_endscan (tgscan );
1103
+ heap_close (tgrel , RowExclusiveLock );
1104
+
1105
+ return res ;
1106
+ }
1107
+
1108
+ /*
1109
+ * Create an UPDATE trigger for partition
1110
+ */
1111
+ Datum
1112
+ create_single_update_trigger (PG_FUNCTION_ARGS )
1113
+ {
1114
+ const PartRelationInfo * prel ;
1115
+ Oid partition = PG_GETARG_OID (0 );
1116
+ Oid parent ;
1117
+ PartParentSearch parent_search ;
1118
+ char * attname ;
1119
+
1120
+ /* Get parent's Oid */
1121
+ parent = get_parent_of_partition (partition , & parent_search );
1122
+ if (parent_search != PPS_ENTRY_PART_PARENT )
1123
+ elog (ERROR , "\"%s\" is not a partition" ,
1124
+ get_rel_name_or_relid (partition ));
1125
+
1126
+ /* Determine partitioning key name */
1127
+ prel = get_pathman_relation_info (parent );
1128
+ shout_if_prel_is_invalid (partition , prel , PT_INDIFFERENT );
1129
+ attname = get_attname (prel -> key , prel -> attnum );
1130
+
1131
+ create_single_update_trigger_internal (partition , attname );
1132
+
1133
+ PG_RETURN_VOID ();
1134
+ }
1135
+
1136
+ static void
1137
+ create_single_update_trigger_internal (Oid relid , const char * attname )
1138
+ {
1139
+ CreateTrigStmt * stmt ;
1140
+ List * func ;
1141
+
1142
+ func = list_make2 (makeString (get_namespace_name (get_pathman_schema ())),
1143
+ makeString ("update_trigger_func" ));
1144
+
1145
+ stmt = makeNode (CreateTrigStmt );
1146
+ stmt -> trigname = build_update_trigger_name_internal (relid );
1147
+ stmt -> relation = makeRangeVarFromRelid (relid );
1148
+ stmt -> funcname = func ;
1149
+ stmt -> args = NIL ;
1150
+ stmt -> row = true;
1151
+ stmt -> timing = TRIGGER_TYPE_BEFORE ;
1152
+ stmt -> events = TRIGGER_TYPE_UPDATE ;
1153
+ stmt -> columns = list_make1 (makeString ((char * ) attname ));
1154
+ stmt -> whenClause = NULL ;
1155
+ stmt -> isconstraint = false;
1156
+ stmt -> deferrable = false;
1157
+ stmt -> initdeferred = false;
1158
+ stmt -> constrrel = NULL ;
1159
+
1160
+ (void ) CreateTrigger (stmt , NULL , InvalidOid , InvalidOid ,
1161
+ InvalidOid , InvalidOid , false);
1162
+ }
0 commit comments