Use TypeName to represent type names in certain commands

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 c10575ff00.
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.
This commit is contained in:
Alvaro Herrera 2014-12-30 13:57:23 -03:00
parent 930fd68455
commit 3f88672a4e
4 changed files with 107 additions and 48 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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; }
;

View File

@ -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}', '{}'),