Alvaro Herrera wrote: > Andres Freund wrote: > > > Having reread the patch just now I basically see two things to > > criticize: > > a) why isn't this accessible at SQL level? That seems easy to address. > > b) Arguably some of this could well be done in separate commits. > > Fair comments. I will split it up.
Here's a split version. The last part is still missing some polish -- in particular handling for OBJECT_POLICY, and the SQL interface which would also allow us to get something in the regression tests. Note: in this patch series you can find the ObjectTypeMap thing that you thought was obsolete in the DDL deparse patch ... -- Álvaro Herrera http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
>From 92816868c1c717519a76a83e65cd0b48e3726fbf Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 4 Apr 2014 16:05:48 -0300 Subject: [PATCH 1/3] add normal/original flags to pg_event_trigger_dropped_objects --- doc/src/sgml/func.sgml | 13 ++++++++++ src/backend/catalog/dependency.c | 21 ++++++++++----- src/backend/commands/event_trigger.c | 16 +++++++++--- src/include/catalog/pg_proc.h | 2 +- src/include/commands/event_trigger.h | 3 ++- src/test/regress/expected/event_trigger.out | 40 +++++++++++++++++++++++++++++ src/test/regress/sql/event_trigger.sql | 30 ++++++++++++++++++++++ 7 files changed, 114 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 7e5bcd9..45f3efa 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17583,6 +17583,19 @@ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); <entry>Object sub-id (e.g. attribute number for columns)</entry> </row> <row> + <entry><literal>original</literal></entry> + <entry><type>bool</type></entry> + <entry>Flag used to identify the root object of the deletion</entry> + </row> + <row> + <entry><literal>normal</literal></entry> + <entry><type>bool</type></entry> + <entry> + Flag indicating that there's a normal dependency relationship + in the dependency graph leading to this object + </entry> + </row> + <row> <entry><literal>object_type</literal></entry> <entry><type>text</type></entry> <entry>Type of the object</entry> diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 256486c..6485e3d 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -205,16 +205,25 @@ deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, /* * Keep track of objects for event triggers, if necessary. */ - if (trackDroppedObjectsNeeded()) + if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL)) { for (i = 0; i < targetObjects->numrefs; i++) { - ObjectAddress *thisobj = targetObjects->refs + i; - - if ((!(flags & PERFORM_DELETION_INTERNAL)) && - EventTriggerSupportsObjectClass(getObjectClass(thisobj))) + const ObjectAddress *thisobj = &targetObjects->refs[i]; + const ObjectAddressExtra *extra = &targetObjects->extras[i]; + bool original = false; + bool normal = false; + + if (extra->flags & DEPFLAG_ORIGINAL) + original = true; + if (extra->flags & DEPFLAG_NORMAL) + normal = true; + if (extra->flags & DEPFLAG_REVERSE) + normal = true; + + if (EventTriggerSupportsObjectClass(getObjectClass(thisobj))) { - EventTriggerSQLDropAddObject(thisobj); + EventTriggerSQLDropAddObject(thisobj, original, normal); } } } diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 1b8c94b..0bab971 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -112,6 +112,8 @@ typedef struct SQLDropObject const char *objname; const char *objidentity; const char *objecttype; + bool original; + bool normal; slist_node next; } SQLDropObject; @@ -1105,7 +1107,7 @@ trackDroppedObjectsNeeded(void) * Register one object as being dropped by the current command. */ void -EventTriggerSQLDropAddObject(ObjectAddress *object) +EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal) { SQLDropObject *obj; MemoryContext oldcxt; @@ -1124,6 +1126,8 @@ EventTriggerSQLDropAddObject(ObjectAddress *object) obj = palloc0(sizeof(SQLDropObject)); obj->address = *object; + obj->original = original; + obj->normal = normal; /* * Obtain schema names from the object's catalog tuple, if one exists; @@ -1251,8 +1255,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) { SQLDropObject *obj; int i = 0; - Datum values[7]; - bool nulls[7]; + Datum values[9]; + bool nulls[9]; obj = slist_container(SQLDropObject, next, iter.cur); @@ -1268,6 +1272,12 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) /* objsubid */ values[i++] = Int32GetDatum(obj->address.objectSubId); + /* original */ + values[i++] = BoolGetDatum(obj->original); + + /* normal */ + values[i++] = BoolGetDatum(obj->normal); + /* object_type */ values[i++] = CStringGetTextDatum(obj->objecttype); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 4736532..c4e932f 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4988,7 +4988,7 @@ DATA(insert OID = 3785 ( pg_logical_slot_peek_binary_changes PGNSP PGUID 12 100 DESCR("peek at binary changes from replication slot"); /* event triggers */ -DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25}" "{o,o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ )); +DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,16,16,25,25,25,25}" "{o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ )); DESCR("list objects dropped by the current command"); /* generic transition functions for ordered-set aggregates */ diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 0233f4c..7ef01cb 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -50,6 +50,7 @@ extern void EventTriggerSQLDrop(Node *parsetree); extern bool EventTriggerBeginCompleteQuery(void); extern void EventTriggerEndCompleteQuery(void); extern bool trackDroppedObjectsNeeded(void); -extern void EventTriggerSQLDropAddObject(ObjectAddress *object); +extern void EventTriggerSQLDropAddObject(const ObjectAddress *object, + bool original, bool normal); #endif /* EVENT_TRIGGER_H */ diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index d4723b2..cb21792 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -294,3 +294,43 @@ SELECT * FROM dropped_objects WHERE type = 'schema'; DROP ROLE regression_bob; DROP EVENT TRIGGER regress_event_trigger_drop_objects; DROP EVENT TRIGGER undroppable; +CREATE OR REPLACE FUNCTION event_trigger_report_dropped() + RETURNS event_trigger + LANGUAGE plpgsql +AS $$ +DECLARE r record; +BEGIN + FOR r IN SELECT * from pg_event_trigger_dropped_objects() + LOOP + IF NOT r.normal AND NOT r.original THEN + CONTINUE; + END IF; + RAISE NOTICE 'NORMAL: orig=% normal=% type=% identity=%', + r.original, r.normal, r.object_type, r.object_identity; + END LOOP; +END; $$; +CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop + EXECUTE PROCEDURE event_trigger_report_dropped(); +CREATE SCHEMA evttrig + CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two') + CREATE INDEX one_idx ON one (col_b) + CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42); +ALTER TABLE evttrig.two DROP COLUMN col_c; +NOTICE: NORMAL: orig=t normal=f type=table column identity=evttrig.two.col_c +NOTICE: NORMAL: orig=f normal=t type=table constraint identity=two_col_c_check on evttrig.two +ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT; +NOTICE: NORMAL: orig=t normal=f type=default value identity=for evttrig.one.col_b +ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey; +NOTICE: NORMAL: orig=t normal=f type=table constraint identity=one_pkey on evttrig.one +DROP INDEX evttrig.one_idx; +NOTICE: NORMAL: orig=t normal=f type=index identity=evttrig.one_idx +DROP SCHEMA evttrig CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table evttrig.one +drop cascades to table evttrig.two +NOTICE: NORMAL: orig=t normal=f type=schema identity=evttrig +NOTICE: NORMAL: orig=f normal=t type=table identity=evttrig.one +NOTICE: NORMAL: orig=f normal=t type=sequence identity=evttrig.one_col_a_seq +NOTICE: NORMAL: orig=f normal=t type=default value identity=for evttrig.one.col_a +NOTICE: NORMAL: orig=f normal=t type=table identity=evttrig.two +DROP EVENT TRIGGER regress_event_trigger_report_dropped; diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 11d2ce5..c82380b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -206,3 +206,33 @@ DROP ROLE regression_bob; DROP EVENT TRIGGER regress_event_trigger_drop_objects; DROP EVENT TRIGGER undroppable; + +CREATE OR REPLACE FUNCTION event_trigger_report_dropped() + RETURNS event_trigger + LANGUAGE plpgsql +AS $$ +DECLARE r record; +BEGIN + FOR r IN SELECT * from pg_event_trigger_dropped_objects() + LOOP + IF NOT r.normal AND NOT r.original THEN + CONTINUE; + END IF; + RAISE NOTICE 'NORMAL: orig=% normal=% type=% identity=%', + r.original, r.normal, r.object_type, r.object_identity; + END LOOP; +END; $$; +CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop + EXECUTE PROCEDURE event_trigger_report_dropped(); +CREATE SCHEMA evttrig + CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two') + CREATE INDEX one_idx ON one (col_b) + CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42); + +ALTER TABLE evttrig.two DROP COLUMN col_c; +ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT; +ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey; +DROP INDEX evttrig.one_idx; +DROP SCHEMA evttrig CASCADE; + +DROP EVENT TRIGGER regress_event_trigger_report_dropped; -- 1.9.1
>From a424f151c888aa6e94867da2edfe84f251f2798a Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Wed, 15 Oct 2014 18:02:45 -0300 Subject: [PATCH 2/3] add support for OBJECT_DEFAULT in get_object_address --- src/backend/catalog/objectaddress.c | 91 ++++++++++++++++++++++++++++++++++++ src/backend/commands/event_trigger.c | 1 + src/include/nodes/parsenodes.h | 1 + 3 files changed, 93 insertions(+) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index b69b75b..a443e84 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -441,6 +441,9 @@ static ObjectAddress get_object_address_relobject(ObjectType objtype, static ObjectAddress get_object_address_attribute(ObjectType objtype, List *objname, Relation *relp, LOCKMODE lockmode, bool missing_ok); +static ObjectAddress get_object_address_attrdef(ObjectType objtype, + List *objname, Relation *relp, LOCKMODE lockmode, + bool missing_ok); static ObjectAddress get_object_address_type(ObjectType objtype, List *objname, bool missing_ok); static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname, @@ -528,6 +531,12 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, &relation, lockmode, missing_ok); break; + case OBJECT_DEFAULT: + address = + get_object_address_attrdef(objtype, objname, + &relation, lockmode, + missing_ok); + break; case OBJECT_RULE: case OBJECT_TRIGGER: case OBJECT_CONSTRAINT: @@ -1080,6 +1089,88 @@ get_object_address_attribute(ObjectType objtype, List *objname, } /* + * Find the ObjectAddress for an attribute's default value. + */ +static ObjectAddress +get_object_address_attrdef(ObjectType objtype, List *objname, + Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + ObjectAddress address; + List *relname; + Oid reloid; + Relation relation; + const char *attname; + AttrNumber attnum; + TupleDesc tupdesc; + Oid defoid; + + /* Extract relation name and open relation. */ + if (list_length(objname) < 2) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("column name must be qualified"))); + attname = strVal(llast(objname)); + relname = list_truncate(list_copy(objname), list_length(objname) - 1); + /* XXX no missing_ok support here */ + relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode); + reloid = RelationGetRelid(relation); + + tupdesc = RelationGetDescr(relation); + + /* Look up attribute number and scan pg_attrdef to find its tuple */ + attnum = get_attnum(reloid, attname); + defoid = InvalidOid; + if (attnum != InvalidAttrNumber && tupdesc->constr != NULL) + { + Relation attrdef; + ScanKeyData keys[2]; + SysScanDesc scan; + HeapTuple tup; + + attrdef = relation_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&keys[0], + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(reloid)); + ScanKeyInit(&keys[1], + Anum_pg_attrdef_adnum, + BTEqualStrategyNumber, + F_INT2EQ, + Int16GetDatum(attnum)); + scan = systable_beginscan(attrdef, AttrDefaultIndexId, true, + NULL, 2, keys); + if (HeapTupleIsValid(tup = systable_getnext(scan))) + defoid = HeapTupleGetOid(tup); + + systable_endscan(scan); + relation_close(attrdef, AccessShareLock); + } + if (!OidIsValid(defoid)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("default value for column \"%s\" of relation \"%s\" does not exist", + attname, NameListToString(relname)))); + + address.classId = AttrDefaultRelationId; + address.objectId = InvalidOid; + address.objectSubId = InvalidAttrNumber; + relation_close(relation, lockmode); + return address; + } + + address.classId = AttrDefaultRelationId; + address.objectId = defoid; + address.objectSubId = 0; + + *relp = relation; + return address; +} + +/* * Find the ObjectAddress for a type or domain */ static ObjectAddress diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 0bab971..6cb067e 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -926,6 +926,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_CONSTRAINT: case OBJECT_COLLATION: case OBJECT_CONVERSION: + case OBJECT_DEFAULT: case OBJECT_DOMAIN: case OBJECT_EXTENSION: case OBJECT_FDW: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index cef9544..5a092d8 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1212,6 +1212,7 @@ typedef enum ObjectType OBJECT_COLLATION, OBJECT_CONVERSION, OBJECT_DATABASE, + OBJECT_DEFAULT, OBJECT_DOMAIN, OBJECT_EVENT_TRIGGER, OBJECT_EXTENSION, -- 1.9.1
>From 5525571e41b91ff70c03b08ac914c020dc489e87 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Wed, 15 Oct 2014 18:03:22 -0300 Subject: [PATCH 3/3] add objname/objargs support --- doc/src/sgml/func.sgml | 16 ++ src/backend/catalog/objectaddress.c | 315 ++++++++++++++++++++++++++++++++--- src/backend/commands/alter.c | 3 +- src/backend/commands/event_trigger.c | 57 ++++++- src/backend/commands/tablecmds.c | 2 +- src/backend/parser/gram.y | 16 +- src/backend/parser/parse_type.c | 46 +++-- src/backend/parser/parse_utilcmd.c | 2 +- src/backend/tcop/utility.c | 5 +- src/backend/utils/adt/regproc.c | 60 +++++++ src/include/catalog/objectaddress.h | 3 + src/include/catalog/pg_proc.h | 3 +- src/include/nodes/parsenodes.h | 5 +- src/include/parser/parse_type.h | 1 + src/include/utils/builtins.h | 4 + 15 files changed, 481 insertions(+), 57 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 45f3efa..dec2a67 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -17625,6 +17625,22 @@ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger(); identifier present in the identity is quoted if necessary. </entry> </row> + <row> + <entry><literal>address_names</literal></entry> + <entry><type>text[]</type></entry> + <entry> + An array that, together with <literal>address_args</literal>, + can be used by the C-language function getObjectAddress() to + recreate the object address in a remote server containing a similar object. + </entry> + </row> + <row> + <entry><literal>address_args</literal></entry> + <entry><type>text[]</type></entry> + <entry> + See <literal>address_names</literal> above. + </entry> + </row> </tbody> </tgroup> </informaltable> diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index a443e84..4d0726c 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -431,6 +431,97 @@ static const ObjectPropertyType ObjectProperty[] = } }; +/* + * This struct maps the object types as returned by getObjectTypeDescription + * into ObjType enum values. Note that some enum values can be obtained by + * different names, and that some string object types do not have corresponding + * values in the enum. The user of this map must be careful to test for + * invalid values being returned. + * + * To ease maintenance, this follows the order of getObjectTypeDescription. + */ +static const struct object_type_map +{ + const char *tm_name; + ObjectType tm_type; +} +ObjectTypeMap[] = +{ + /* OCLASS_CLASS */ + { "table", OBJECT_TABLE }, + { "index", OBJECT_INDEX }, + { "sequence", OBJECT_SEQUENCE }, + { "toast table", -1 }, /* unmapped */ + { "view", OBJECT_VIEW }, + { "materialized view", OBJECT_MATVIEW }, + { "composite type", OBJECT_COMPOSITE }, + { "foreign table", OBJECT_FOREIGN_TABLE }, + { "table column", OBJECT_COLUMN }, + /* OCLASS_PROC */ + { "aggregate", OBJECT_AGGREGATE }, + { "function", OBJECT_FUNCTION }, + /* OCLASS_TYPE */ + { "type", OBJECT_TYPE }, + /* OCLASS_CAST */ + { "cast", OBJECT_CAST }, + /* OCLASS_COLLATION */ + { "collation", OBJECT_COLLATION }, + /* OCLASS_CONSTRAINT */ + { "table constraint", OBJECT_TABCONSTRAINT }, + { "domain constraint", OBJECT_DOMCONSTRAINT }, + /* OCLASS_CONVERSION */ + { "conversion", OBJECT_CONVERSION }, + /* OCLASS_DEFAULT */ + { "default value", OBJECT_DEFAULT }, + /* OCLASS_LANGUAGE */ + { "language", OBJECT_LANGUAGE }, + /* OCLASS_LARGEOBJECT */ + { "large object", OBJECT_LARGEOBJECT }, + /* OCLASS_OPERATOR */ + { "operator", OBJECT_OPERATOR }, + /* OCLASS_OPCLASS */ + { "operator class", OBJECT_OPCLASS }, + /* OCLASS_OPFAMILY */ + { "operator family", OBJECT_OPFAMILY }, + /* OCLASS_AMOP */ + { "operator of access method", -1 }, /* unmapped */ + /* OCLASS_AMPROC */ + { "function of access method", -1 }, /* unmapped */ + /* OCLASS_REWRITE */ + { "rule", OBJECT_RULE }, + /* OCLASS_TRIGGER */ + { "trigger", OBJECT_TRIGGER }, + /* OCLASS_SCHEMA */ + { "schema", OBJECT_SCHEMA }, + /* OCLASS_TSPARSER */ + { "text search parser", OBJECT_TSPARSER }, + /* OCLASS_TSDICT */ + { "text search dictionary", OBJECT_TSDICTIONARY }, + /* OCLASS_TSTEMPLATE */ + { "text search template", OBJECT_TSTEMPLATE }, + /* OCLASS_TSCONFIG */ + { "text search configuration", OBJECT_TSCONFIGURATION }, + /* OCLASS_ROLE */ + { "role", OBJECT_ROLE }, + /* OCLASS_DATABASE */ + { "database", OBJECT_DATABASE }, + /* OCLASS_TBLSPACE */ + { "tablespace", OBJECT_TABLESPACE }, + /* OCLASS_FDW */ + { "foreign-data wrapper", OBJECT_FDW }, + /* OCLASS_FOREIGN_SERVER */ + { "server", OBJECT_FOREIGN_SERVER }, + /* OCLASS_USER_MAPPING */ + { "user mapping", OBJECT_USER_MAPPING }, + /* OCLASS_DEFACL */ + { "default acl", -1 }, /* unmapped */ + /* OCLASS_EXTENSION */ + { "extension", OBJECT_EXTENSION }, + /* OCLASS_EVENT_TRIGGER */ + { "event trigger", OBJECT_EVENT_TRIGGER } +}; + + static ObjectAddress get_object_address_unqualified(ObjectType objtype, List *qualname, bool missing_ok); static ObjectAddress get_relation_by_qualified_name(ObjectType objtype, @@ -456,8 +547,9 @@ static void getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId); static void getProcedureTypeDescription(StringInfo buffer, Oid procid); static void getConstraintTypeDescription(StringInfo buffer, Oid constroid); -static void getOpFamilyIdentity(StringInfo buffer, Oid opfid); -static void getRelationIdentity(StringInfo buffer, Oid relid); +static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, + List **objargs); +static void getRelationIdentity(StringInfo buffer, Oid relid, List **objname); /* * Translate an object name and arguments (as passed by the parser) to an @@ -539,11 +631,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, break; case OBJECT_RULE: case OBJECT_TRIGGER: - case OBJECT_CONSTRAINT: + case OBJECT_TABCONSTRAINT: case OBJECT_POLICY: address = get_object_address_relobject(objtype, objname, &relation, missing_ok); break; + case OBJECT_DOMCONSTRAINT: + { + List *domname; + ObjectAddress domaddr; + char *constrname; + + domname = list_truncate(list_copy(objname), list_length(objname) - 1); + constrname = strVal(llast(objname)); + domaddr = get_object_address_type(OBJECT_DOMAIN, domname, missing_ok); + + address.classId = ConstraintRelationId; + address.objectId = get_domain_constraint_oid(domaddr.objectId, + constrname, missing_ok); + address.objectSubId = 0; + + } + break; case OBJECT_DATABASE: case OBJECT_EXTENSION: case OBJECT_TABLESPACE: @@ -943,7 +1052,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, const char *depname; /* Extract name of dependent object. */ - depname = strVal(lfirst(list_tail(objname))); + depname = strVal(llast(objname)); /* Separate relation name from dependent object name. */ nnames = list_length(objname); @@ -999,7 +1108,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, get_trigger_oid(reloid, depname, missing_ok) : InvalidOid; address.objectSubId = 0; break; - case OBJECT_CONSTRAINT: + case OBJECT_TABCONSTRAINT: address.classId = ConstraintRelationId; address.objectId = relation ? get_relation_constraint_oid(reloid, depname, missing_ok) : @@ -1269,7 +1378,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, case OBJECT_RULE: case OBJECT_TRIGGER: case OBJECT_POLICY: - case OBJECT_CONSTRAINT: + case OBJECT_TABCONSTRAINT: if (!pg_class_ownercheck(RelationGetRelid(relation), roleid)) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(relation)); @@ -1282,6 +1391,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, case OBJECT_TYPE: case OBJECT_DOMAIN: case OBJECT_ATTRIBUTE: + case OBJECT_DOMCONSTRAINT: if (!pg_type_ownercheck(address.objectId, roleid)) aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId); break; @@ -1461,6 +1571,34 @@ get_object_namespace(const ObjectAddress *address) } /* + * Return ObjectType for the given object type as given by + * getObjectTypeDescription; if no valid ObjectType code exists, but it's a + * possible output type from getObjectTypeDescription, return -1. + * Otherwise, an error is thrown. + */ +int +unstringify_objtype(const char *objtype) +{ + ObjectType type; + int i; + + for (i = 0; i < lengthof(ObjectTypeMap); i++) + { + if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0) + { + type = ObjectTypeMap[i].tm_type; + break; + } + } + if (i >= lengthof(ObjectTypeMap)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized object type \"%s\"", objtype))); + + return type; +} + +/* * Interfaces to reference fields of ObjectPropertyType */ Oid @@ -2591,6 +2729,8 @@ pg_identify_object(PG_FUNCTION_ARGS) /* * Return a palloc'ed string that describes the type of object that the * passed address is for. + * + * Keep ObjectTypeMap in sync with this. */ char * getObjectTypeDescription(const ObjectAddress *object) @@ -2838,7 +2978,7 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid) } /* - * Return a palloc'ed string that identifies an object. + * Obtain a given object's identity, as a palloc'ed string. * * This is for machine consumption, so it's not translated. All elements are * schema-qualified when appropriate. @@ -2846,14 +2986,42 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid) char * getObjectIdentity(const ObjectAddress *object) { + return getObjectIdentityParts(object, NULL, NULL); +} + +/* + * As above, but more detailed. + * + * There are two sets of return values: the identity itself as a palloc'd + * string is returned. objname and objargs, if not NULL, are output parameters + * that receive lists of strings that are useful to give back to + * get_object_address() to reconstruct the ObjectAddress. + */ +char * +getObjectIdentityParts(const ObjectAddress *object, + List **objname, List **objargs) +{ StringInfoData buffer; initStringInfo(&buffer); + /* + * Make sure that both objname and objargs were passed, or none was; and + * initialize them to empty lists. For objname this is useless because it + * will be initialized in all cases inside the switch; but we do it anyway + * so that we can Assert() below that no branch leaves it unset. + */ + Assert(PointerIsValid(objname) == PointerIsValid(objargs)); + if (objname) + { + *objname = NIL; + *objargs = NIL; + } + switch (getObjectClass(object)) { case OCLASS_CLASS: - getRelationIdentity(&buffer, object->objectId); + getRelationIdentity(&buffer, object->objectId, objname); if (object->objectSubId != 0) { char *attr; @@ -2861,17 +3029,27 @@ getObjectIdentity(const ObjectAddress *object) attr = get_relid_attribute_name(object->objectId, object->objectSubId); appendStringInfo(&buffer, ".%s", quote_identifier(attr)); + if (objname) + *objname = lappend(*objname, attr); } break; case OCLASS_PROC: appendStringInfoString(&buffer, format_procedure_qualified(object->objectId)); + if (objname) + format_procedure_parts(object->objectId, objname, objargs); break; case OCLASS_TYPE: - appendStringInfoString(&buffer, - format_type_be_qualified(object->objectId)); + { + char *typeout; + + typeout = format_type_be_qualified(object->objectId); + appendStringInfoString(&buffer, typeout); + if (objname) + *objname = list_make1(typeout); + } break; case OCLASS_CAST: @@ -2894,6 +3072,10 @@ getObjectIdentity(const ObjectAddress *object) format_type_be_qualified(castForm->castsource), format_type_be_qualified(castForm->casttarget)); + if (objname) + *objname = list_make2(format_type_be_qualified(castForm->castsource), + format_type_be_qualified(castForm->casttarget)); + heap_close(castRel, AccessShareLock); break; } @@ -2914,6 +3096,8 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfoString(&buffer, quote_qualified_identifier(schema, NameStr(coll->collname))); + if (objname) + *objname = list_make2(schema, NameStr(coll->collname)); ReleaseSysCache(collTup); break; } @@ -2934,7 +3118,9 @@ getObjectIdentity(const ObjectAddress *object) { appendStringInfo(&buffer, "%s on ", quote_identifier(NameStr(con->conname))); - getRelationIdentity(&buffer, con->conrelid); + getRelationIdentity(&buffer, con->conrelid, objname); + if (objname) + *objname = lappend(*objname, pstrdup(NameStr(con->conname))); } else { @@ -2946,7 +3132,10 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfo(&buffer, "%s on %s", quote_identifier(NameStr(con->conname)), - getObjectIdentity(&domain)); + getObjectIdentityParts(&domain, objname, + objargs)); + if (objname) + *objname = lappend(*objname, pstrdup(NameStr(con->conname))); } ReleaseSysCache(conTup); @@ -2966,6 +3155,8 @@ getObjectIdentity(const ObjectAddress *object) conForm = (Form_pg_conversion) GETSTRUCT(conTup); appendStringInfoString(&buffer, quote_identifier(NameStr(conForm->conname))); + if (objname) + *objname = list_make1(pstrdup(NameStr(conForm->conname))); ReleaseSysCache(conTup); break; } @@ -3003,7 +3194,8 @@ getObjectIdentity(const ObjectAddress *object) colobject.objectSubId = attrdef->adnum; appendStringInfo(&buffer, "for %s", - getObjectIdentity(&colobject)); + getObjectIdentityParts(&colobject, + objname, objargs)); systable_endscan(adscan); heap_close(attrdefDesc, AccessShareLock); @@ -3023,17 +3215,23 @@ getObjectIdentity(const ObjectAddress *object) langForm = (Form_pg_language) GETSTRUCT(langTup); appendStringInfoString(&buffer, quote_identifier(NameStr(langForm->lanname))); + if (objname) + *objname = list_make1(pstrdup(NameStr(langForm->lanname))); ReleaseSysCache(langTup); break; } case OCLASS_LARGEOBJECT: appendStringInfo(&buffer, "%u", object->objectId); + if (objname) + *objname = list_make1(psprintf("%u", object->objectId)); break; case OCLASS_OPERATOR: appendStringInfoString(&buffer, format_operator_qualified(object->objectId)); + if (objname) + format_operator_parts(object->objectId, objname, objargs); break; case OCLASS_OPCLASS: @@ -3064,14 +3262,19 @@ getObjectIdentity(const ObjectAddress *object) NameStr(opcForm->opcname))); appendStringInfo(&buffer, " for %s", quote_identifier(NameStr(amForm->amname))); - + if (objname) + { + *objname = list_make2(pstrdup(schema), + pstrdup(NameStr(opcForm->opcname))); + *objargs = list_make1(pstrdup(NameStr(amForm->amname))); + } ReleaseSysCache(amTup); ReleaseSysCache(opcTup); break; } case OCLASS_OPFAMILY: - getOpFamilyIdentity(&buffer, object->objectId); + getOpFamilyIdentity(&buffer, object->objectId, objname, objargs); break; case OCLASS_AMOP: @@ -3083,6 +3286,10 @@ getObjectIdentity(const ObjectAddress *object) Form_pg_amop amopForm; StringInfoData opfam; + /* no objname support here */ + if (objname) + *objname = NIL; + amopDesc = heap_open(AccessMethodOperatorRelationId, AccessShareLock); @@ -3103,7 +3310,7 @@ getObjectIdentity(const ObjectAddress *object) amopForm = (Form_pg_amop) GETSTRUCT(tup); initStringInfo(&opfam); - getOpFamilyIdentity(&opfam, amopForm->amopfamily); + getOpFamilyIdentity(&opfam, amopForm->amopfamily, NULL, NULL); appendStringInfo(&buffer, "operator %d (%s, %s) of %s", amopForm->amopstrategy, @@ -3127,6 +3334,10 @@ getObjectIdentity(const ObjectAddress *object) Form_pg_amproc amprocForm; StringInfoData opfam; + /* no objname support here */ + if (objname) + *objname = NIL; + amprocDesc = heap_open(AccessMethodProcedureRelationId, AccessShareLock); @@ -3147,7 +3358,7 @@ getObjectIdentity(const ObjectAddress *object) amprocForm = (Form_pg_amproc) GETSTRUCT(tup); initStringInfo(&opfam); - getOpFamilyIdentity(&opfam, amprocForm->amprocfamily); + getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, NULL, NULL); appendStringInfo(&buffer, "function %d (%s, %s) of %s", amprocForm->amprocnum, @@ -3180,7 +3391,9 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfo(&buffer, "%s on ", quote_identifier(NameStr(rule->rulename))); - getRelationIdentity(&buffer, rule->ev_class); + getRelationIdentity(&buffer, rule->ev_class, objname); + if (objname) + *objname = lappend(*objname, NameStr(rule->rulename)); heap_close(ruleDesc, AccessShareLock); break; @@ -3204,7 +3417,9 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfo(&buffer, "%s on ", quote_identifier(NameStr(trig->tgname))); - getRelationIdentity(&buffer, trig->tgrelid); + getRelationIdentity(&buffer, trig->tgrelid, objname); + if (objname) + *objname = lappend(*objname, NameStr(trig->tgname)); heap_close(trigDesc, AccessShareLock); break; @@ -3220,6 +3435,8 @@ getObjectIdentity(const ObjectAddress *object) object->objectId); appendStringInfoString(&buffer, quote_identifier(nspname)); + if (objname) + *objname = list_make1(nspname); break; } @@ -3239,6 +3456,9 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfoString(&buffer, quote_qualified_identifier(schema, NameStr(formParser->prsname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formParser->prsname))); ReleaseSysCache(tup); break; } @@ -3259,6 +3479,9 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfoString(&buffer, quote_qualified_identifier(schema, NameStr(formDict->dictname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formDict->dictname))); ReleaseSysCache(tup); break; } @@ -3279,7 +3502,9 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfoString(&buffer, quote_qualified_identifier(schema, NameStr(formTmpl->tmplname))); - pfree(schema); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formTmpl->tmplname))); ReleaseSysCache(tup); break; } @@ -3300,6 +3525,9 @@ getObjectIdentity(const ObjectAddress *object) appendStringInfoString(&buffer, quote_qualified_identifier(schema, NameStr(formCfg->cfgname))); + if (objname) + *objname = list_make2(schema, + pstrdup(NameStr(formCfg->cfgname))); ReleaseSysCache(tup); break; } @@ -3308,6 +3536,9 @@ getObjectIdentity(const ObjectAddress *object) { char *username; + /* no objname support here */ + Assert(objname == NULL); + username = GetUserNameFromId(object->objectId); appendStringInfoString(&buffer, quote_identifier(username)); @@ -3318,6 +3549,9 @@ getObjectIdentity(const ObjectAddress *object) { char *datname; + /* no objname support here */ + Assert(objname == NULL); + datname = get_database_name(object->objectId); if (!datname) elog(ERROR, "cache lookup failed for database %u", @@ -3331,6 +3565,9 @@ getObjectIdentity(const ObjectAddress *object) { char *tblspace; + /* no objname support here */ + Assert(objname == NULL); + tblspace = get_tablespace_name(object->objectId); if (!tblspace) elog(ERROR, "cache lookup failed for tablespace %u", @@ -3346,6 +3583,8 @@ getObjectIdentity(const ObjectAddress *object) fdw = GetForeignDataWrapper(object->objectId); appendStringInfoString(&buffer, quote_identifier(fdw->fdwname)); + if (objname) + *objname = list_make1(pstrdup(fdw->fdwname)); break; } @@ -3356,6 +3595,8 @@ getObjectIdentity(const ObjectAddress *object) srv = GetForeignServer(object->objectId); appendStringInfoString(&buffer, quote_identifier(srv->servername)); + if (objname) + *objname = list_make1(pstrdup(srv->servername)); break; } @@ -3365,6 +3606,8 @@ getObjectIdentity(const ObjectAddress *object) Oid useid; const char *usename; + /* XXX get_object_address doesn't seem to support this */ + tup = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup)) @@ -3389,10 +3632,15 @@ getObjectIdentity(const ObjectAddress *object) Relation defaclrel; ScanKeyData skey[1]; SysScanDesc rcscan; - HeapTuple tup; Form_pg_default_acl defacl; + /* + * There is no valid representation for default ACL objects for + * get_object_address; disallow callers from asking for it. + */ + Assert(!objname); + defaclrel = heap_open(DefaultAclRelationId, AccessShareLock); ScanKeyInit(&skey[0], @@ -3459,6 +3707,8 @@ getObjectIdentity(const ObjectAddress *object) elog(ERROR, "cache lookup failed for extension %u", object->objectId); appendStringInfoString(&buffer, quote_identifier(extname)); + if (objname) + *objname = list_make1(extname); break; } @@ -3467,6 +3717,9 @@ getObjectIdentity(const ObjectAddress *object) HeapTuple tup; Form_pg_event_trigger trigForm; + /* no objname support here */ + Assert(objname == NULL); + tup = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup)) @@ -3487,11 +3740,18 @@ getObjectIdentity(const ObjectAddress *object) break; } + /* + * If a get_object_address representation was requested, make sure we are + * providing one. We don't check for objargs, because many of the cases + * above leave it as NIL. + */ + Assert(!objname || *objname != NIL); + return buffer.data; } static void -getOpFamilyIdentity(StringInfo buffer, Oid opfid) +getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, List **objargs) { HeapTuple opfTup; Form_pg_opfamily opfForm; @@ -3516,6 +3776,13 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid) NameStr(opfForm->opfname)), NameStr(amForm->amname)); + if (objname) + { + *objname = list_make2(pstrdup(schema), + pstrdup(NameStr(opfForm->opfname))); + *objargs = list_make1(pstrdup(NameStr(amForm->amname))); + } + ReleaseSysCache(amTup); ReleaseSysCache(opfTup); } @@ -3525,7 +3792,7 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid) * StringInfo. */ static void -getRelationIdentity(StringInfo buffer, Oid relid) +getRelationIdentity(StringInfo buffer, Oid relid, List **objname) { HeapTuple relTup; Form_pg_class relForm; @@ -3541,6 +3808,8 @@ getRelationIdentity(StringInfo buffer, Oid relid) appendStringInfoString(buffer, quote_qualified_identifier(schema, NameStr(relForm->relname))); + if (objname) + *objname = list_make2(schema, pstrdup(NameStr(relForm->relname))); ReleaseSysCache(relTup); } diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index c9a9baf..e7f4ef3 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -305,7 +305,8 @@ ExecRenameStmt(RenameStmt *stmt) { switch (stmt->renameType) { - case OBJECT_CONSTRAINT: + case OBJECT_TABCONSTRAINT: + case OBJECT_DOMCONSTRAINT: return RenameConstraint(stmt); case OBJECT_DATABASE: diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 6cb067e..bb55bbc 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -112,6 +112,8 @@ typedef struct SQLDropObject const char *objname; const char *objidentity; const char *objecttype; + List *addrnames; + List *addrargs; bool original; bool normal; slist_node next; @@ -923,11 +925,12 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_ATTRIBUTE: case OBJECT_CAST: case OBJECT_COLUMN: - case OBJECT_CONSTRAINT: + case OBJECT_COMPOSITE: case OBJECT_COLLATION: case OBJECT_CONVERSION: case OBJECT_DEFAULT: case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: case OBJECT_EXTENSION: case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: @@ -944,6 +947,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_RULE: case OBJECT_SCHEMA: case OBJECT_SEQUENCE: + case OBJECT_TABCONSTRAINT: case OBJECT_TABLE: case OBJECT_TRIGGER: case OBJECT_TSCONFIGURATION: @@ -951,6 +955,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_TYPE: + case OBJECT_USER_MAPPING: case OBJECT_VIEW: return true; } @@ -1190,10 +1195,11 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no heap_close(catalog, AccessShareLock); } - /* object identity */ - obj->objidentity = getObjectIdentity(&obj->address); + /* object identity, objname and objargs */ + obj->objidentity = + getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs); - /* and object type, too */ + /* object type */ obj->objecttype = getObjectTypeDescription(&obj->address); slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next); @@ -1202,6 +1208,33 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no } /* + * helper for pg_event_trigger_dropped_object + * + * Make an array of text Datum out of a list of C strings. + */ +static Datum +strlist_to_textarray(List *list) +{ + ArrayType *arr; + Datum *datums; + int j = 0; + ListCell *cell; + + datums = palloc(sizeof(text *) * list_length(list)); + foreach(cell, list) + { + char *name = lfirst(cell); + + datums[j++] = CStringGetTextDatum(name); + } + + arr = construct_array(datums, list_length(list), + TEXTOID, -1, false, 'i'); + + return PointerGetDatum(arr); +} + +/* * pg_event_trigger_dropped_objects * * Make the list of dropped objects available to the user function run by the @@ -1256,8 +1289,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) { SQLDropObject *obj; int i = 0; - Datum values[9]; - bool nulls[9]; + Datum values[11]; + bool nulls[11]; obj = slist_container(SQLDropObject, next, iter.cur); @@ -1300,6 +1333,18 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS) else nulls[i++] = true; + /* address_names */ + if (obj->addrnames) + values[i++] = strlist_to_textarray(obj->addrnames); + else + nulls[i++] = true; + + /* address_args */ + if (obj->addrargs) + values[i++] = strlist_to_textarray(obj->addrargs); + else + nulls[i++] = true; + tuplestore_putvalues(tupstore, tupdesc, values, nulls); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index ecdff1e..c6e06f0 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -2457,7 +2457,7 @@ RenameConstraint(RenameStmt *stmt) Oid relid = InvalidOid; Oid typid = InvalidOid; - if (stmt->relationType == OBJECT_DOMAIN) + if (stmt->renameType == OBJECT_DOMCONSTRAINT) { Relation rel; HeapTuple tup; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c98c27a..8ea581e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -5611,12 +5611,21 @@ CommentStmt: | COMMENT ON CONSTRAINT name ON any_name IS comment_text { CommentStmt *n = makeNode(CommentStmt); - n->objtype = OBJECT_CONSTRAINT; + n->objtype = OBJECT_TABCONSTRAINT; n->objname = lappend($6, makeString($4)); n->objargs = NIL; n->comment = $8; $$ = (Node *) n; } + | COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_DOMCONSTRAINT; + n->objname = lappend($7, makeString($4)); + n->objargs = NIL; + n->comment = $9; + $$ = (Node *) n; + } | COMMENT ON RULE name ON any_name IS comment_text { CommentStmt *n = makeNode(CommentStmt); @@ -7301,8 +7310,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name { RenameStmt *n = makeNode(RenameStmt); - n->renameType = OBJECT_CONSTRAINT; - n->relationType = OBJECT_DOMAIN; + n->renameType = OBJECT_DOMCONSTRAINT; n->object = $3; n->subname = $6; n->newname = $8; @@ -7570,7 +7578,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name | ALTER TABLE relation_expr RENAME CONSTRAINT name TO name { RenameStmt *n = makeNode(RenameStmt); - n->renameType = OBJECT_CONSTRAINT; + n->renameType = OBJECT_TABCONSTRAINT; n->relationType = OBJECT_TABLE; n->relation = $3; n->subname = $6; diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index d0803df..299cc53 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -705,13 +705,11 @@ pts_error_callback(void *arg) /* * Given a string that is supposed to be a SQL-compatible type declaration, * such as "int4" or "integer" or "character varying(32)", parse - * the string and convert it to a type OID and type modifier. - * If missing_ok is true, InvalidOid is returned rather than raising an error - * when the type name is not found. + * the string and return the result as a TypeName. + * If the string cannot be parsed as a type, an error is raised. */ -void -parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, - bool missing_ok) +TypeName * +typeStringToTypeName(const char *str) { StringInfoData buf; List *raw_parsetree_list; @@ -720,7 +718,6 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, TypeCast *typecast; TypeName *typeName; ErrorContextCallback ptserrcontext; - Type tup; /* make sure we give useful error for empty input */ if (strspn(str, " \t\n\r\f") == strlen(str)) @@ -779,6 +776,7 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, typecast->arg == NULL || !IsA(typecast->arg, A_Const)) goto fail; + typeName = typecast->typeName; if (typeName == NULL || !IsA(typeName, TypeName)) @@ -786,6 +784,31 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, if (typeName->setof) goto fail; + pfree(buf.data); + + return typeName; + +fail: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid type name \"%s\"", str))); +} + +/* + * Given a string that is supposed to be a SQL-compatible type declaration, + * such as "int4" or "integer" or "character varying(32)", parse + * the string and convert it to a type OID and type modifier. + * If missing_ok is true, InvalidOid is returned rather than raising an error + * when the type name is not found. + */ +void +parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok) +{ + TypeName *typeName; + Type tup; + + typeName = typeStringToTypeName(str); + tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok); if (tup == NULL) { @@ -808,13 +831,4 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, *typeid_p = HeapTupleGetOid(tup); ReleaseSysCache(tup); } - - pfree(buf.data); - - return; - -fail: - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid type name \"%s\"", str))); } diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 7c1939f..04c8595 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -871,7 +871,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla { CommentStmt *stmt = makeNode(CommentStmt); - stmt->objtype = OBJECT_CONSTRAINT; + stmt->objtype = OBJECT_TABCONSTRAINT; stmt->objname = list_make3(makeString(cxt->relation->schemaname), makeString(cxt->relation->relname), makeString(n->conname)); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 4a2a339..2b93015 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1587,9 +1587,6 @@ AlterObjectTypeCommandTag(ObjectType objtype) case OBJECT_COLUMN: tag = "ALTER TABLE"; break; - case OBJECT_CONSTRAINT: - tag = "ALTER TABLE"; - break; case OBJECT_CONVERSION: tag = "ALTER CONVERSION"; break; @@ -1597,6 +1594,7 @@ AlterObjectTypeCommandTag(ObjectType objtype) tag = "ALTER DATABASE"; break; case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: tag = "ALTER DOMAIN"; break; case OBJECT_EXTENSION: @@ -1648,6 +1646,7 @@ AlterObjectTypeCommandTag(ObjectType objtype) tag = "ALTER SEQUENCE"; break; case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: tag = "ALTER TABLE"; break; case OBJECT_TABLESPACE: diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index c0314ee..8cda52b 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -439,6 +439,41 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify) } /* + * Output a objname/objargs representation for the procedure with the + * given OID. If it doesn't exist, an error is thrown. + * + * This can be used to feed get_object_address. + */ +void +format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs) +{ + HeapTuple proctup; + Form_pg_proc procform; + int nargs; + int i; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid)); + + if (!HeapTupleIsValid(proctup)) + elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid); + + procform = (Form_pg_proc) GETSTRUCT(proctup); + nargs = procform->pronargs; + + *objnames = list_make2(get_namespace_name(procform->pronamespace), + pstrdup(NameStr(procform->proname))); + *objargs = NIL; + for (i = 0; i < nargs; i++) + { + Oid thisargtype = procform->proargtypes.values[i]; + + *objargs = lappend(*objargs, format_type_be_qualified(thisargtype)); + } + + ReleaseSysCache(proctup); +} + +/* * regprocedureout - converts proc OID to "pro_name(args)" */ Datum @@ -875,6 +910,31 @@ format_operator_qualified(Oid operator_oid) return format_operator_internal(operator_oid, true); } +void +format_operator_parts(Oid operator_oid, List **objnames, List **objargs) +{ + HeapTuple opertup; + Form_pg_operator oprForm; + + opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid)); + if (!HeapTupleIsValid(opertup)) + elog(ERROR, "cache lookup failed for operator with OID %u", + operator_oid); + + oprForm = (Form_pg_operator) GETSTRUCT(opertup); + *objnames = list_make2(get_namespace_name(oprForm->oprnamespace), + pstrdup(NameStr(oprForm->oprname))); + *objargs = NIL; + if (oprForm->oprleft) + *objargs = lappend(*objargs, + format_type_be_qualified(oprForm->oprleft)); + if (oprForm->oprright) + *objargs = lappend(*objargs, + format_type_be_qualified(oprForm->oprright)); + + ReleaseSysCache(opertup); +} + /* * regoperatorout - converts operator OID to "opr_name(args)" */ diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h index 2a9431d..997a156 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -55,7 +55,10 @@ extern HeapTuple get_catalog_object_by_oid(Relation catalog, extern char *getObjectDescription(const ObjectAddress *object); extern char *getObjectDescriptionOids(Oid classid, Oid objid); +extern int unstringify_objtype(const char *objtype); extern char *getObjectTypeDescription(const ObjectAddress *object); extern char *getObjectIdentity(const ObjectAddress *address); +extern char *getObjectIdentityParts(const ObjectAddress *address, + List **objname, List **objargs); #endif /* OBJECTADDRESS_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index c4e932f..a5c8b05 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4988,7 +4988,8 @@ DATA(insert OID = 3785 ( pg_logical_slot_peek_binary_changes PGNSP PGUID 12 100 DESCR("peek at binary changes from replication slot"); /* event triggers */ -DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,16,16,25,25,25,25}" "{o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ )); +DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,16,16,25,25,25,25,1009,1009}" "{o,o,o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, object_type, schema_name, object_name, object_identity, address_names, address_args}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ )); + DESCR("list objects dropped by the current command"); /* generic transition functions for ordered-set aggregates */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 5a092d8..54f6082 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1208,12 +1208,13 @@ typedef enum ObjectType OBJECT_ATTRIBUTE, /* type's attribute, when distinct from column */ OBJECT_CAST, OBJECT_COLUMN, - OBJECT_CONSTRAINT, + OBJECT_COMPOSITE, OBJECT_COLLATION, OBJECT_CONVERSION, OBJECT_DATABASE, OBJECT_DEFAULT, OBJECT_DOMAIN, + OBJECT_DOMCONSTRAINT, OBJECT_EVENT_TRIGGER, OBJECT_EXTENSION, OBJECT_FDW, @@ -1232,6 +1233,7 @@ typedef enum ObjectType OBJECT_RULE, OBJECT_SCHEMA, OBJECT_SEQUENCE, + OBJECT_TABCONSTRAINT, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TRIGGER, @@ -1240,6 +1242,7 @@ typedef enum ObjectType OBJECT_TSPARSER, OBJECT_TSTEMPLATE, OBJECT_TYPE, + OBJECT_USER_MAPPING, OBJECT_VIEW } ObjectType; diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index fa9cc59..152bdbb 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -47,6 +47,7 @@ extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod); extern Oid typeidTypeRelid(Oid type_id); +extern TypeName *typeStringToTypeName(const char *str); extern void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok); #define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid) diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index fb1b4a4..c4c8473 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -642,8 +642,12 @@ extern Datum text_regclass(PG_FUNCTION_ARGS); extern List *stringToQualifiedNameList(const char *string); extern char *format_procedure(Oid procedure_oid); extern char *format_procedure_qualified(Oid procedure_oid); +extern void format_procedure_parts(Oid operator_oid, List **objnames, + List **objargs); extern char *format_operator(Oid operator_oid); extern char *format_operator_qualified(Oid operator_oid); +extern void format_operator_parts(Oid operator_oid, List **objnames, + List **objargs); /* rowtypes.c */ extern Datum record_in(PG_FUNCTION_ARGS); -- 1.9.1
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers