Skip to content

Commit 73b8a41

Browse files
committed
trigger creation rewrited in C
1 parent 165a724 commit 73b8a41

File tree

5 files changed

+167
-51
lines changed

5 files changed

+167
-51
lines changed

init.sql

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -560,31 +560,9 @@ LANGUAGE C;
560560
/*
561561
* Creates an update trigger
562562
*/
563-
CREATE OR REPLACE FUNCTION @extschema@.create_update_triggers(
564-
IN parent_relid REGCLASS)
565-
RETURNS VOID AS
566-
$$
567-
DECLARE
568-
trigger TEXT := 'CREATE TRIGGER %s
569-
BEFORE UPDATE ON %s
570-
FOR EACH ROW EXECUTE PROCEDURE
571-
@extschema@.update_trigger_func()';
572-
triggername TEXT;
573-
rec RECORD;
574-
575-
BEGIN
576-
triggername := @extschema@.build_update_trigger_name(parent_relid);
577-
578-
/* Create trigger on every partition */
579-
FOR rec in (SELECT * FROM pg_catalog.pg_inherits
580-
WHERE inhparent = parent_relid)
581-
LOOP
582-
EXECUTE format(trigger,
583-
triggername,
584-
rec.inhrelid::REGCLASS::TEXT);
585-
END LOOP;
586-
END
587-
$$ LANGUAGE plpgsql;
563+
CREATE OR REPLACE FUNCTION @extschema@.create_update_triggers(parent_relid REGCLASS)
564+
RETURNS VOID AS 'pg_pathman', 'create_update_triggers'
565+
LANGUAGE C;
588566

589567
/*
590568
* Drop triggers

src/partition_creation.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ static Constraint *make_constraint_common(char *name, Node *raw_expr);
7777
static Value make_string_value_struct(char *str);
7878
static Value make_int_value_struct(int int_val);
7979

80-
static RangeVar *makeRangeVarFromRelid(Oid relid);
81-
8280

8381
/*
8482
* ---------------------------------------
@@ -1402,15 +1400,6 @@ make_int_value_struct(int int_val)
14021400
return val;
14031401
}
14041402

1405-
static RangeVar *
1406-
makeRangeVarFromRelid(Oid relid)
1407-
{
1408-
char *relname = get_rel_name(relid);
1409-
char *namespace = get_namespace_name(get_rel_namespace(relid));
1410-
1411-
return makeRangeVar(namespace, relname, -1);
1412-
}
1413-
14141403

14151404
/*
14161405
* ---------------------

src/pl_funcs.c

Lines changed: 133 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
#include "access/htup_details.h"
2222
#include "access/xact.h"
2323
#include "catalog/indexing.h"
24+
#include "catalog/pg_trigger.h"
2425
#include "catalog/pg_type.h"
2526
#include "commands/tablespace.h"
2627
#include "commands/trigger.h"
2728
#include "funcapi.h"
2829
#include "miscadmin.h"
2930
#include "utils/builtins.h"
31+
#include "utils/fmgroids.h"
3032
#include "utils/inval.h"
3133
#include "utils/jsonb.h"
3234
#include "utils/snapmgr.h"
@@ -35,6 +37,9 @@
3537

3638

3739
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);
3843

3944

4045
/* Function declarations */
@@ -74,7 +79,9 @@ PG_FUNCTION_INFO_V1( check_security_policy );
7479
PG_FUNCTION_INFO_V1( debug_capture );
7580
PG_FUNCTION_INFO_V1( get_pathman_lib_version );
7681

82+
PG_FUNCTION_INFO_V1( create_update_triggers );
7783
PG_FUNCTION_INFO_V1( update_trigger_func );
84+
PG_FUNCTION_INFO_V1( create_single_update_trigger );
7885

7986

8087
/*
@@ -97,16 +104,6 @@ static void on_partitions_updated_internal(Oid partitioned_table, bool add_callb
97104
static void on_partitions_removed_internal(Oid partitioned_table, bool add_callbacks);
98105

99106

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-
110107
/*
111108
* ----------------------------
112109
* Partition events callbacks
@@ -543,11 +540,7 @@ build_update_trigger_name(PG_FUNCTION_ARGS)
543540
Oid relid = PG_GETARG_OID(0);
544541
const char *result; /* trigger's name can't be qualified */
545542

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);
551544

552545
PG_RETURN_TEXT_P(cstring_to_text(result));
553546
}
@@ -1020,6 +1013,7 @@ update_trigger_func(PG_FUNCTION_ARGS)
10201013
PG_RETURN_VOID();
10211014
}
10221015

1016+
10231017
/*
10241018
* Returns Oid of partition corresponding to partitioning key value. Throws
10251019
* an error if no partition found
@@ -1042,3 +1036,127 @@ get_partition_for_key(const PartRelationInfo *prel, Datum key)
10421036
else
10431037
return parts[0];
10441038
}
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+
}

src/utils.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,18 @@ check_security_policy_internal(Oid relid, Oid role)
103103
return true;
104104
}
105105

106+
/*
107+
* Create an update trigger name
108+
*/
109+
char *
110+
build_update_trigger_name_internal(Oid relid)
111+
{
112+
/* Check that relation exists */
113+
if (!check_relation_exists(relid))
114+
elog(ERROR, "Invalid relation %u", relid);
106115

116+
return (char *) quote_identifier(psprintf("%s_upd_trig", get_rel_name(relid)));
117+
}
107118

108119
/*
109120
* Return pg_pathman schema's Oid or InvalidOid if that's not possible.
@@ -255,6 +266,23 @@ get_rel_persistence(Oid relid)
255266
}
256267
#endif
257268

269+
RangeVar *
270+
makeRangeVarFromRelid(Oid relid)
271+
{
272+
char *relname = get_rel_name(relid);
273+
char *namespace = get_namespace_name(get_rel_namespace(relid));
274+
275+
return makeRangeVar(namespace, relname, -1);
276+
}
277+
278+
/*
279+
* Extracted common check.
280+
*/
281+
bool
282+
check_relation_exists(Oid relid)
283+
{
284+
return get_rel_type_id(relid) != InvalidOid;
285+
}
258286

259287

260288
/*

src/utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
bool clause_contains_params(Node *clause);
2828
bool is_date_type_internal(Oid typid);
2929
bool check_security_policy_internal(Oid relid, Oid role);
30+
char *build_update_trigger_name_internal(Oid relid);
3031

3132
/*
3233
* Misc.
@@ -43,6 +44,8 @@ Oid get_attribute_type(Oid relid, const char *attname, bool missing_ok);
4344
#if PG_VERSION_NUM < 90600
4445
char get_rel_persistence(Oid relid);
4546
#endif
47+
RangeVar *makeRangeVarFromRelid(Oid relid);
48+
bool check_relation_exists(Oid relid);
4649

4750
/*
4851
* Operator-related stuff.

0 commit comments

Comments
 (0)