diff --git a/doc/src/sgml/ref/drop_trigger.sgmlin b/doc/src/sgml/ref/drop_trigger.sgmlin index a45ae62c2..1b932b670 100644 --- a/doc/src/sgml/ref/drop_trigger.sgmlin +++ b/doc/src/sgml/ref/drop_trigger.sgmlin @@ -15,6 +15,8 @@ DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ] +In B compatibility also support: +DROP TRIGGER [ IF EXISTS ] name [ CASCADE | RESTRICT ] diff --git a/src/common/backend/catalog/objectaddress.cpp b/src/common/backend/catalog/objectaddress.cpp index 62060c6c3..63af81027 100644 --- a/src/common/backend/catalog/objectaddress.cpp +++ b/src/common/backend/catalog/objectaddress.cpp @@ -700,12 +700,19 @@ static ObjectAddress get_object_address_relobject(ObjectType objtype, List* objn * work. But objects other than rules don't get this special * treatment. */ - if (objtype != OBJECT_RULE) - ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NODE_STATE), errmsg("must specify relation and object name"))); - address.classId = RewriteRelationId; - address.objectId = get_rewrite_oid_without_relid(depname, &reloid, missing_ok); - address.objectSubId = 0; - + /*mysql drop trigger syntax*/ + if (objtype == OBJECT_TRIGGER && u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) + { + address.classId = TriggerRelationId; + address.objectId = get_trigger_oid_b(depname, &reloid, missing_ok); + address.objectSubId = 0; + } else { + if (objtype != OBJECT_RULE) + ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NODE_STATE), errmsg("must specify relation and object name"))); + address.classId = RewriteRelationId; + address.objectId = get_rewrite_oid_without_relid(depname, &reloid, missing_ok); + address.objectSubId = 0; + } /* * Caller is expecting to get back the relation, even though we didn't * end up using it to find the rule. diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index c7d1d7279..1131e616d 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -11197,6 +11197,52 @@ DropTrigStmt: n->concurrent = false; $$ = (Node *) n; } + | DROP TRIGGER name opt_drop_behavior + { +#ifdef ENABLE_MULTIPLE_NODES + const char* message = "drop trigger name is not yet supported in distributed database."; + InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc); + ereport(errstate, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("drop trigger name is not yet supported in distributed database."))); +#endif + if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) { + ereport(errstate, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("drop trigger without table name only support in B-format database"))); + } + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_TRIGGER; + n->objects = list_make1(list_make1(makeString($3))); + n->arguments = NIL; + n->behavior = $4; + n->missing_ok = false; + n->concurrent = false; + $$ = (Node *) n; + } + | DROP TRIGGER IF_P EXISTS name opt_drop_behavior + { +#ifdef ENABLE_MULTIPLE_NODES + const char* message = "drop trigger if exists name is not yet supported in distributed database."; + InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc); + ereport(errstate, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("drop trigger if exists name is not yet supported in distributed database."))); +#endif + if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) { + ereport(errstate, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("drop trigger without table name only support in B-format database"))); + } + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_TRIGGER; + n->objects = list_make1(list_make1(makeString($5))); + n->arguments = NIL; + n->behavior = $6; + n->missing_ok = true; + n->concurrent = false; + $$ = (Node *) n; + } ; diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index caab07249..08fc64ed4 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -59,7 +59,7 @@ bool open_join_children = true; bool will_shutdown = false; /* hard-wired binary version number */ -const uint32 GRAND_VERSION_NUM = 92836; +const uint32 GRAND_VERSION_NUM = 92837; const uint32 SELECT_INTO_VAR_VERSION_NUM = 92834; const uint32 DOLPHIN_ENABLE_DROP_NUM = 92830; diff --git a/src/gausskernel/optimizer/commands/dropcmds.cpp b/src/gausskernel/optimizer/commands/dropcmds.cpp index 3655f1b31..ee93a7674 100644 --- a/src/gausskernel/optimizer/commands/dropcmds.cpp +++ b/src/gausskernel/optimizer/commands/dropcmds.cpp @@ -376,10 +376,16 @@ static void does_not_exist_skipping(ObjectType objtype, List* objname, List* obj args = format_type_be(typenameTypeId(NULL, (TypeName*)linitial(objargs))); break; case OBJECT_TRIGGER: - msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist"); - name = NameListToString(objname); - args = NameListToString(list_truncate(list_copy(objname), list_length(objname) - 1)); - break; + if (list_length(objname) == 1) { + msg = gettext_noop("trigger \"%s\" does not exist"); + name = NameListToString(objname); + break; + } else { + msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist"); + name = NameListToString(objname); + args = NameListToString(list_truncate(list_copy(objname), list_length(objname) - 1)); + break; + } case OBJECT_RULE: msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist"); name = strVal(llast(objname)); diff --git a/src/gausskernel/optimizer/commands/trigger.cpp b/src/gausskernel/optimizer/commands/trigger.cpp index 6037176b8..2acd6a742 100644 --- a/src/gausskernel/optimizer/commands/trigger.cpp +++ b/src/gausskernel/optimizer/commands/trigger.cpp @@ -467,23 +467,38 @@ Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid * relation, so the trigger set won't be changing underneath us. */ if (!isInternal) { - ScanKeyInit( - &key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); - tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true, NULL, 1, &key); - while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { - Form_pg_trigger pg_trigger = (Form_pg_trigger)GETSTRUCT(tuple); - if (namestrcmp(&(pg_trigger->tgname), trigname) == 0) { + if (stmt->funcSource != NULL && u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) { + ScanKeyInit( + &key, Anum_pg_trigger_tgname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(trigname)); + tgscan = systable_beginscan(tgrel, TriggerNameIndexId, true, NULL, 1, &key); + if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { if (stmt->if_not_exists) { ereport(NOTICE, - (errmsg("trigger \"%s\" for relation \"%s\" already exists,skipping", - trigname, - RelationGetRelationName(rel)))); + (errmsg("trigger \"%s\" already exists, skipping", + trigname))); systable_endscan(tgscan); heap_close(tgrel, RowExclusiveLock); heap_close(rel, NoLock); return trigoid; } else { + systable_endscan(tgscan); + heap_close(tgrel, RowExclusiveLock); + heap_close(rel, NoLock); + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("trigger \"%s\" already exists", + trigname))); + } + } + systable_endscan(tgscan); + } else { + ScanKeyInit( + &key, Anum_pg_trigger_tgrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); + tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true, NULL, 1, &key); + while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { + Form_pg_trigger pg_trigger = (Form_pg_trigger)GETSTRUCT(tuple); + if (namestrcmp(&(pg_trigger->tgname), trigname) == 0) { systable_endscan(tgscan); heap_close(tgrel, RowExclusiveLock); heap_close(rel, NoLock); @@ -494,11 +509,10 @@ Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid RelationGetRelationName(rel)))); } } + systable_endscan(tgscan); } - systable_endscan(tgscan); } - if (stmt->funcSource != NULL && u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) { CreateFunctionStmt* n = makeNode(CreateFunctionStmt); n->isOraStyle = false; @@ -1302,6 +1316,53 @@ Oid get_trigger_oid(Oid relid, const char* trigname, bool missing_ok) return oid; } +Oid get_trigger_oid_b(const char* trigname, Oid* reloid, bool missing_ok) +{ + Relation tgrel; + ScanKeyData skey; + SysScanDesc tgscan; + HeapTuple tup; + Oid oid; + int count = 0; + + /* + * Find the trigger, verify permissions, set up object address + */ + tgrel = heap_open(TriggerRelationId, AccessShareLock); + + ScanKeyInit(&skey, Anum_pg_trigger_tgname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(trigname)); + + tgscan = systable_beginscan(tgrel, TriggerNameIndexId, true, NULL, 1, &skey); + + while (HeapTupleIsValid(tup = systable_getnext(tgscan))) { + count ++; + if (count == 1) { + Form_pg_trigger pg_trigger = (Form_pg_trigger)GETSTRUCT(tup); + *reloid = pg_trigger->tgrelid; + oid = HeapTupleGetOid(tup); + } else if (count > 1) { + systable_endscan(tgscan); + heap_close(tgrel, AccessShareLock); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("trigger named \"%s\" has more than one trigger, please use drop trigger on syntax", trigname))); + } + } + if (count == 0) { + if (!missing_ok) { + systable_endscan(tgscan); + heap_close(tgrel, AccessShareLock); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("trigger \"%s\" does not exist", trigname))); + } + oid = InvalidOid; + } + + systable_endscan(tgscan); + heap_close(tgrel, AccessShareLock); + return oid; +} /* * Perform permissions and integrity checks before acquiring a relation lock. */ diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 4bd3aab9f..9d4678414 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -270,6 +270,8 @@ DECLARE_UNIQUE_INDEX(pg_tablespace_spcname_index, 2698, on pg_tablespace using b /* This following index is not used for a cache and is not unique */ DECLARE_INDEX(pg_trigger_tgconstraint_index, 2699, on pg_trigger using btree(tgconstraint oid_ops)); #define TriggerConstraintIndexId 2699 +DECLARE_INDEX(pg_trigger_tgname_index, 2700, on pg_trigger using btree(tgname name_ops)); +#define TriggerNameIndexId 2700 DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, on pg_trigger using btree(tgrelid oid_ops, tgname name_ops)); #define TriggerRelidNameIndexId 2701 DECLARE_UNIQUE_INDEX(pg_trigger_oid_index, 2702, on pg_trigger using btree(oid oid_ops)); diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback_catalog_maindb_92_837.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback_catalog_maindb_92_837.sql new file mode 100644 index 000000000..a12848706 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback_catalog_maindb_92_837.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS pg_catalog.pg_trigger_tgname_index; diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback_catalog_otherdb_92_837.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback_catalog_otherdb_92_837.sql new file mode 100644 index 000000000..a12848706 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback_catalog_otherdb_92_837.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS pg_catalog.pg_trigger_tgname_index; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade_catalog_maindb_92_837.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade_catalog_maindb_92_837.sql new file mode 100755 index 000000000..4b7b0b291 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade_catalog_maindb_92_837.sql @@ -0,0 +1,3 @@ +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_CATALOG, false, true, 0, 0, 0, 2700; +CREATE INDEX pg_catalog.pg_trigger_tgname_index ON pg_catalog.pg_trigger USING BTREE(tgname name_ops); +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_CATALOG, false, true, 0, 0, 0, 0; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade_catalog_otherdb_92_837.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade_catalog_otherdb_92_837.sql new file mode 100755 index 000000000..4b7b0b291 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade_catalog_otherdb_92_837.sql @@ -0,0 +1,3 @@ +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_CATALOG, false, true, 0, 0, 0, 2700; +CREATE INDEX pg_catalog.pg_trigger_tgname_index ON pg_catalog.pg_trigger USING BTREE(tgname name_ops); +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_CATALOG, false, true, 0, 0, 0, 0; diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index a75eeef2f..033003d6e 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -104,6 +104,7 @@ extern Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relO extern void RemoveTriggerById(Oid trigOid); extern Oid get_trigger_oid(Oid relid, const char* name, bool missing_ok); +extern Oid get_trigger_oid_b(const char* name, Oid* reloid, bool missing_ok); extern void renametrig(RenameStmt* stmt); diff --git a/src/test/regress/expected/mysql_syntax.out b/src/test/regress/expected/mysql_syntax.out index b4bbb8c4b..c70a85614 100644 --- a/src/test/regress/expected/mysql_syntax.out +++ b/src/test/regress/expected/mysql_syntax.out @@ -152,7 +152,7 @@ begin insert into food(id, foodtype, remark, time_flag) values (1,'ice cream', 'sdsdsdsd', now()); end; / -ERROR: trigger "animal_trigger1" for relation "animals" already exists +ERROR: trigger "animal_trigger1" already exists create trigger if not exists animal_trigger1 after insert on animals for each row @@ -160,7 +160,31 @@ begin insert into food(id, foodtype, remark, time_flag) values (1,'ice cream', 'sdsdsdsd', now()); end; / -NOTICE: trigger "animal_trigger1" for relation "animals" already exists,skipping +NOTICE: trigger "animal_trigger1" already exists, skipping +CREATE OR REPLACE FUNCTION tri_insert_func() RETURNS TRIGGER AS +$$ +DECLARE +BEGIN +INSERT INTO food(id, foodtype, remark, time_flag) values (1,'ice cream', 'sdsdsdsd', now()); +RETURN NEW; +END +$$ LANGUAGE PLPGSQL; +create trigger trigger_rename_test +after insert on animals +for each row +EXECUTE PROCEDURE tri_insert_func(); +create trigger trigger_rename_test +after insert on food +for each row +EXECUTE PROCEDURE tri_insert_func(); +drop trigger trigger_rename_test; +ERROR: trigger named "trigger_rename_test" has more than one trigger, please use drop trigger on syntax +-- drop trigger test +drop trigger animal_trigger1; +drop trigger animal_trigger1; +ERROR: trigger "animal_trigger1" does not exist +drop trigger if exists animal_trigger1; +NOTICE: trigger "animal_trigger1" does not exist, skipping drop table food; drop table animals; DROP TABLE t_trigger cascade; @@ -331,6 +355,10 @@ END; ERROR: bad SQLSTATE '00000' CONTEXT: compilation of PL/pgSQL function "test_condition_6" near line 3 \c regression +drop trigger animal_trigger1; +ERROR: drop trigger without table name only support in B-format database +drop trigger if exists animal_trigger1; +ERROR: drop trigger without table name only support in B-format database drop database db_mysql; -- test declare condition in other compatibility create or replace procedure test_condition_1 as diff --git a/src/test/regress/expected/xc_triggers_1.out b/src/test/regress/expected/xc_triggers_1.out index 3bf4129cf..e27c56a7c 100644 --- a/src/test/regress/expected/xc_triggers_1.out +++ b/src/test/regress/expected/xc_triggers_1.out @@ -642,6 +642,8 @@ Command: DROP TRIGGER Description: remove a trigger Syntax: DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ] +In B compatibility also support: +DROP TRIGGER [ IF EXISTS ] name [ CASCADE | RESTRICT ] \h alter table Command: ALTER TABLE diff --git a/src/test/regress/sql/mysql_syntax.sql b/src/test/regress/sql/mysql_syntax.sql index 8a5cb2aaa..4ffeb793b 100644 --- a/src/test/regress/sql/mysql_syntax.sql +++ b/src/test/regress/sql/mysql_syntax.sql @@ -139,6 +139,31 @@ begin insert into food(id, foodtype, remark, time_flag) values (1,'ice cream', 'sdsdsdsd', now()); end; / + +CREATE OR REPLACE FUNCTION tri_insert_func() RETURNS TRIGGER AS +$$ +DECLARE +BEGIN +INSERT INTO food(id, foodtype, remark, time_flag) values (1,'ice cream', 'sdsdsdsd', now()); +RETURN NEW; +END +$$ LANGUAGE PLPGSQL; + +create trigger trigger_rename_test +after insert on animals +for each row +EXECUTE PROCEDURE tri_insert_func(); + +create trigger trigger_rename_test +after insert on food +for each row +EXECUTE PROCEDURE tri_insert_func(); + +drop trigger trigger_rename_test; +-- drop trigger test +drop trigger animal_trigger1; +drop trigger animal_trigger1; +drop trigger if exists animal_trigger1; drop table food; drop table animals; @@ -263,6 +288,8 @@ END; / \c regression +drop trigger animal_trigger1; +drop trigger if exists animal_trigger1; drop database db_mysql; -- test declare condition in other compatibility