From 3f88672a4e4d8e648d24ccc65937da61c7660854 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Tue, 30 Dec 2014 13:57:23 -0300 Subject: [PATCH] Use TypeName to represent type names in certain commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In COMMENT, DROP, SECURITY LABEL, and the new pg_get_object_address function, we were representing types as a list of names, same as other objects; but types are special objects that require their own representation to be totally accurate. In the original COMMENT code we had a note about fixing it which was lost in the course of c10575ff005. Change all those places to use TypeName instead, as suggested by that comment. Right now the original coding doesn't cause any bugs, so no backpatch. It is more problematic for proposed future code that operate with object addresses from the SQL interface; type details such as array-ness are lost when working with the degraded representation. Thanks to Petr JelĂ­nek and Dimitri Fontaine for offlist help on finding a solution to a shift/reduce grammar conflict. --- src/backend/catalog/objectaddress.c | 43 ++-------- src/backend/commands/dropcmds.c | 10 ++- src/backend/parser/gram.y | 100 +++++++++++++++++++++--- src/test/regress/sql/object_address.sql | 2 +- 4 files changed, 107 insertions(+), 48 deletions(-) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 7cb46e1278..9ca609d886 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -646,13 +646,11 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, 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); + domaddr = get_object_address_type(OBJECT_DOMAIN, objname, missing_ok); + constrname = strVal(linitial(objargs)); address.classId = ConstraintRelationId; address.objectId = get_domain_constraint_oid(domaddr.objectId, @@ -1291,14 +1289,13 @@ get_object_address_attrdef(ObjectType objtype, List *objname, * Find the ObjectAddress for a type or domain */ static ObjectAddress -get_object_address_type(ObjectType objtype, - List *objname, bool missing_ok) +get_object_address_type(ObjectType objtype, List *objname, bool missing_ok) { ObjectAddress address; TypeName *typename; Type tup; - typename = makeTypeNameFromNameList(objname); + typename = (TypeName *) linitial(objname); address.classId = TypeRelationId; address.objectId = InvalidOid; @@ -1428,27 +1425,8 @@ pg_get_object_address(PG_FUNCTION_ARGS) * given object type. Most use a simple string Values list, but there * are some exceptions. */ - if (type == OBJECT_TYPE || type == OBJECT_DOMAIN) - { - Datum *elems; - bool *nulls; - int nelems; - TypeName *typname; - - deconstruct_array(namearr, TEXTOID, -1, false, 'i', - &elems, &nulls, &nelems); - if (nelems != 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("name list length must be exactly %d", 1))); - if (nulls[0]) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("name or argument lists may not contain nulls"))); - typname = typeStringToTypeName(TextDatumGetCString(elems[0])); - name = typname->names; - } - else if (type == OBJECT_CAST) + if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST || + type == OBJECT_DOMCONSTRAINT) { Datum *elems; bool *nulls; @@ -1533,18 +1511,13 @@ pg_get_object_address(PG_FUNCTION_ARGS) */ switch (type) { - case OBJECT_DOMCONSTRAINT: - if (list_length(name) < 2) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("name list length must be at least %d", 2))); - break; case OBJECT_LARGEOBJECT: if (list_length(name) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("name list length must be %d", 1))); + errmsg("name list length must be exactly %d", 1))); break; + case OBJECT_DOMCONSTRAINT: case OBJECT_OPCLASS: case OBJECT_OPFAMILY: case OBJECT_CAST: diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 858358166d..21a2ae441a 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -264,10 +264,14 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) { case OBJECT_TYPE: case OBJECT_DOMAIN: - if (!schema_does_not_exist_skipping(objname, &msg, &name)) { - msg = gettext_noop("type \"%s\" does not exist, skipping"); - name = TypeNameToString(makeTypeNameFromNameList(objname)); + TypeName *typ = linitial(objname); + + if (!schema_does_not_exist_skipping(typ->names, &msg, &name)) + { + msg = gettext_noop("type \"%s\" does not exist, skipping"); + name = TypeNameToString(typ); + } } break; case OBJECT_COLLATION: diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 6431601c66..eaaf2c2333 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -351,7 +351,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); opt_column_list columnList opt_name_list sort_clause opt_sort_clause sortby_list index_params name_list role_list from_clause from_list opt_array_bounds - qualified_name_list any_name any_name_list + qualified_name_list any_name any_name_list type_name_list any_operator expr_list attrs target_list opt_target_list insert_column_list set_target_list set_clause_list set_clause multiple_set_clause @@ -5471,6 +5471,46 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior n->concurrent = false; $$ = (Node *)n; } + | DROP TYPE_P type_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_TYPE; + n->missing_ok = FALSE; + n->objects = $3; + n->behavior = $4; + n->concurrent = false; + $$ = (Node *) n; + } + | DROP TYPE_P IF_P EXISTS type_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_TYPE; + n->missing_ok = TRUE; + n->objects = $5; + n->behavior = $6; + n->concurrent = false; + $$ = (Node *) n; + } + | DROP DOMAIN_P type_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_DOMAIN; + n->missing_ok = FALSE; + n->objects = $3; + n->behavior = $4; + n->concurrent = false; + $$ = (Node *) n; + } + | DROP DOMAIN_P IF_P EXISTS type_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_DOMAIN; + n->missing_ok = TRUE; + n->objects = $5; + n->behavior = $6; + n->concurrent = false; + $$ = (Node *) n; + } | DROP INDEX CONCURRENTLY any_name_list opt_drop_behavior { DropStmt *n = makeNode(DropStmt); @@ -5503,8 +5543,6 @@ drop_type: TABLE { $$ = OBJECT_TABLE; } | INDEX { $$ = OBJECT_INDEX; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } - | TYPE_P { $$ = OBJECT_TYPE; } - | DOMAIN_P { $$ = OBJECT_DOMAIN; } | COLLATION { $$ = OBJECT_COLLATION; } | CONVERSION_P { $$ = OBJECT_CONVERSION; } | SCHEMA { $$ = OBJECT_SCHEMA; } @@ -5530,6 +5568,9 @@ attrs: '.' attr_name { $$ = lappend($1, makeString($3)); } ; +type_name_list: + Typename { $$ = list_make1(list_make1($1)); } + | type_name_list ',' Typename { $$ = lappend($1, list_make1($3)); } /***************************************************************************** * @@ -5594,6 +5635,24 @@ CommentStmt: n->comment = $6; $$ = (Node *) n; } + | COMMENT ON TYPE_P Typename IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_TYPE; + n->objname = list_make1($4); + n->objargs = NIL; + n->comment = $6; + $$ = (Node *) n; + } + | COMMENT ON DOMAIN_P Typename IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_DOMAIN; + n->objname = list_make1($4); + n->objargs = NIL; + n->comment = $6; + $$ = (Node *) n; + } | COMMENT ON AGGREGATE func_name aggr_args IS comment_text { CommentStmt *n = makeNode(CommentStmt); @@ -5634,8 +5693,13 @@ CommentStmt: { CommentStmt *n = makeNode(CommentStmt); n->objtype = OBJECT_DOMCONSTRAINT; - n->objname = lappend($7, makeString($4)); - n->objargs = NIL; + /* + * should use Typename not any_name in the production, but + * there's a shift/reduce conflict if we do that, so fix it + * up here. + */ + n->objname = list_make1(makeTypeNameFromNameList($7)); + n->objargs = list_make1(makeString($4)); n->comment = $9; $$ = (Node *) n; } @@ -5730,8 +5794,6 @@ comment_type: | INDEX { $$ = OBJECT_INDEX; } | SEQUENCE { $$ = OBJECT_SEQUENCE; } | TABLE { $$ = OBJECT_TABLE; } - | DOMAIN_P { $$ = OBJECT_DOMAIN; } - | TYPE_P { $$ = OBJECT_TYPE; } | VIEW { $$ = OBJECT_VIEW; } | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } | COLLATION { $$ = OBJECT_COLLATION; } @@ -5776,6 +5838,28 @@ SecLabelStmt: n->label = $8; $$ = (Node *) n; } + | SECURITY LABEL opt_provider ON TYPE_P Typename + IS security_label + { + SecLabelStmt *n = makeNode(SecLabelStmt); + n->provider = $3; + n->objtype = OBJECT_TYPE; + n->objname = list_make1($6); + n->objargs = NIL; + n->label = $8; + $$ = (Node *) n; + } + | SECURITY LABEL opt_provider ON DOMAIN_P Typename + IS security_label + { + SecLabelStmt *n = makeNode(SecLabelStmt); + n->provider = $3; + n->objtype = OBJECT_TYPE; + n->objname = list_make1($6); + n->objargs = NIL; + n->label = $8; + $$ = (Node *) n; + } | SECURITY LABEL opt_provider ON AGGREGATE func_name aggr_args IS security_label { @@ -5834,10 +5918,8 @@ security_label_type: | SCHEMA { $$ = OBJECT_SCHEMA; } | SEQUENCE { $$ = OBJECT_SEQUENCE; } | TABLE { $$ = OBJECT_TABLE; } - | DOMAIN_P { $$ = OBJECT_TYPE; } | ROLE { $$ = OBJECT_ROLE; } | TABLESPACE { $$ = OBJECT_TABLESPACE; } - | TYPE_P { $$ = OBJECT_TYPE; } | VIEW { $$ = OBJECT_VIEW; } | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } ; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index e5209b9e44..dc55895d93 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -132,7 +132,7 @@ WITH objects (type, name, args) AS (VALUES ('cast', '{int8}', '{int4}'), ('collation', '{default}', '{}'), ('table constraint', '{addr_nsp, gentable, a_chk}', '{}'), - ('domain constraint', '{addr_nsp, gendomain, domconstr}', '{}'), + ('domain constraint', '{addr_nsp.gendomain}', '{domconstr}'), ('conversion', '{pg_catalog, ascii_to_mic}', '{}'), ('default value', '{addr_nsp, gentable, b}', '{}'), ('language', '{plpgsql}', '{}'),