Re: extension patch of CREATE OR REPLACE TRIGGER - Mailing list pgsql-hackers

From Peter Smith
Subject Re: extension patch of CREATE OR REPLACE TRIGGER
Date
Msg-id CAHut+Pt=dqj+HENBAqxayQzPMjBCo7gTTOiCvKd2CUDmKr2W7A@mail.gmail.com
Whole thread Raw
In response to RE: extension patch of CREATE OR REPLACE TRIGGER  ("osumi.takamichi@fujitsu.com" <osumi.takamichi@fujitsu.com>)
Responses RE: extension patch of CREATE OR REPLACE TRIGGER  ("osumi.takamichi@fujitsu.com" <osumi.takamichi@fujitsu.com>)
List pgsql-hackers
Hello Osumi-san.

Below are my v14 patch review comments for your consideration.

===

(1) COMMENT
File: NA
Maybe next time consider using format-patch to make the patch. Then
you can include a comment to give the background/motivation for this
change.

===

(2) COMMENT
File: doc/src/sgml/ref/create_trigger.sgml
@@ -446,6 +454,13 @@ UPDATE OF <replaceable>column_name1</replaceable>
[, <replaceable>column_name2</
Currently it says:
When replacing an existing trigger with CREATE OR REPLACE TRIGGER,
there are restrictions. You cannot replace constraint triggers. That
means it is impossible to replace a regular trigger with a constraint
trigger and to replace a constraint trigger with another constraint
trigger.

--

Is that correct wording? I don't think so. Saying "to replace a
regular trigger with a constraint trigger" is NOT the same as "replace
a constraint trigger".

Maybe I am mistaken but I think the help and the code are no longer in
sync anymore. e.g. In previous versions of this patch you used to
verify replacement trigger kinds (regular/constraint) match. AFAIK you
are not doing that in the current code (but you should be). So
although you say "impossible to replace a regular trigger with a
constraint trigger" I don't see any code to check/enforce that ( ?? )

IMO when you simplified this v14 patch you may have removed some extra
trigger kind conditions that should not have been removed.

Also, the test code should have detected this problem, but I think the
tests have also been broken in v14. See later COMMENT (9).

===

(3) COMMENT
File: src/backend/commands/trigger.c
@@ -185,6 +185,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char
*queryString,
+ bool internal_trigger = false;

--

There is potential for confusion of "isInternal" versus
"internal_trigger". The meaning is not apparent from the names, but
IIUC isInternal seems to be when creating an internal trigger, whereas
internal_trigger seems to be when you found an existing trigger that
was previously created as isInternal.

Maybe something like "existing_isInternal" would be a better name
instead of "internal_trigger".

===

(4) COMMENT
File: src/backend/commands/trigger.c
@@ -185,6 +185,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char
*queryString,
+ bool is_update = false;

Consider if "was_replaced" might be a better name than "is_update".

===

(5) COMMENT
File: src/backend/commands/trigger.c
@@ -669,6 +673,81 @@ CreateTrigger(CreateTrigStmt *stmt, const char
*queryString,
+ if (!stmt->replace)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("trigger \"%s\" for relation \"%s\" already exists",
+ stmt->trigname, RelationGetRelationName(rel))));
+ else
+ {
+ /*
+ * An internal trigger cannot be replaced by another user defined
+ * trigger. This should exclude the case that internal trigger is
+ * child trigger of partition table and needs to be rewritten when
+ * the parent trigger is replaced by user.
+ */
+ if (internal_trigger && isInternal == false && in_partition == false)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("trigger \"%s\" for relation \"%s\" is an internal trigger",
+ stmt->trigname, RelationGetRelationName(rel))));
+
+ /*
+ * CREATE OR REPLACE TRIGGER command can't replace constraint
+ * trigger.
+ */
+ if (OidIsValid(existing_constraint_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("trigger \"%s\" for relation \"%s\" is a constraint trigger",
+ stmt->trigname, RelationGetRelationName(rel))));
+ }

It is not really necessary for the "OR REPLACE" code to need to be
inside an "else" block like that because the "if (!stmt->replace)" has
already been tested above. Consider removing the "else {" to remove
unnecessary indent if you want to.

===

(6) COMMENT
File: src/backend/commands/trigger.c
(same code block as above)

Condition is strangely written:
e.g.
Before: if (internal_trigger && isInternal == false && in_partition == false)
After: if (internal_trigger && !isInternal && !in_partition)

===

(7) COMMENT
File: src/backend/commands/trigger.c
(same code block as above)
/*
 * CREATE OR REPLACE TRIGGER command can't replace constraint
 * trigger.
 */

--

Only need to say
/* Can't replace a constraint trigger. */

===

(8) COMMENT
File: src/include/nodes/parsenodes.h
@@ -2429,6 +2429,9 @@ typedef struct CreateAmStmt

The comment does not need to say "when true,". Just saying "replace
trigger if already exists" is enough.

===

(9) COMMENT
File: src/test/regress/expected/triggers.out
+-- test for detecting incompatible replacement of trigger
+create table my_table (id integer);
+create function funcA() returns trigger as $$
+begin
+  raise notice 'hello from funcA';
+  return null;
+end; $$ language plpgsql;
+create function funcB() returns trigger as $$
+begin
+  raise notice 'hello from funcB';
+  return null;
+end; $$ language plpgsql;
+create or replace trigger my_trig
+  after insert on my_table
+  for each row execute procedure funcA();
+create constraint trigger my_trig
+  after insert on my_table
+  for each row execute procedure funcB(); -- should fail
+ERROR:  trigger "my_trig" for relation "my_table" already exists

--

I think this test has been broken in v14. That last "create constraint
trigger my_trig" above can never be expected to work simply because
you are not specifying the "OR REPLACE" syntax. So in fact this is not
properly testing for incompatible types at all. It needs to say
"create OR REPLACE constraint trigger my_trig" to be testing what it
claims to be testing.

I also think there is a missing check in the code - see COMMENT (2) -
for handling this scenario. But since this test case is broken you do
not then notice the code check is missing.

===

Kind Regards,
Peter Smith.
Fujitsu Australia



pgsql-hackers by date:

Previous
From: Kyotaro Horiguchi
Date:
Subject: Re: Dereference before NULL check (src/backend/storage/ipc/latch.c)
Next
From: Amit Kapila
Date:
Subject: Re: Parallel copy