From 0bd4da23a4bee4fb3b6b61cb0fadc43c054c5ddb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 11 Nov 2007 19:22:49 +0000 Subject: [PATCH] Ensure that typmod decoration on a datatype name is validated in all cases, even in code paths where we don't pay any subsequent attention to the typmod value. This seems needed in view of the fact that 8.3's generalized typmod support will accept a lot of bogus syntax, such as "timestamp(foo)" or "record(int, 42)" --- if we allow such things to pass without comment, users will get confused. Per a recent example from Greg Stark. To implement this in a way that's not very vulnerable to future bugs-of-omission, refactor the API of parse_type.c's TypeName lookup routines so that typmod validation is folded into the base lookup operation. Callers can still choose not to receive the encoded typmod, but we'll check the decoration anyway if it's present. --- src/backend/access/common/tupdesc.c | 5 +- src/backend/commands/aggregatecmds.c | 8 +- src/backend/commands/comment.c | 8 +- src/backend/commands/functioncmds.c | 36 +++- src/backend/commands/opclasscmds.c | 10 +- src/backend/commands/operatorcmds.c | 6 +- src/backend/commands/prepare.c | 4 +- src/backend/commands/tablecmds.c | 23 +- src/backend/commands/typecmds.c | 57 +++-- src/backend/parser/parse_expr.c | 10 +- src/backend/parser/parse_func.c | 74 +++++-- src/backend/parser/parse_oper.c | 6 +- src/backend/parser/parse_relation.c | 5 +- src/backend/parser/parse_type.c | 310 +++++++++++++++------------ src/backend/parser/parse_utilcmd.c | 4 +- src/backend/utils/misc/guc.c | 6 +- src/include/parser/parse_type.h | 19 +- src/pl/plpgsql/src/pl_comp.c | 38 ++-- 18 files changed, 341 insertions(+), 288 deletions(-) diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 50e41ade60..6e2ac69cc4 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.120 2007/01/05 22:19:21 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.121 2007/11/11 19:22:48 tgl Exp $ * * NOTES * some of the executor utility code such as "ExecTypeFromTL" should be @@ -534,8 +534,7 @@ BuildDescForRelation(List *schema) attnum++; attname = entry->colname; - atttypid = typenameTypeId(NULL, entry->typename); - atttypmod = typenameTypeMod(NULL, entry->typename, atttypid); + atttypid = typenameTypeId(NULL, entry->typename, &atttypmod); attdim = list_length(entry->typename->arrayBounds); if (entry->typename->setof) diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 89ea00d89a..e49a7da3a2 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.43 2007/04/02 03:49:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.44 2007/11/11 19:22:48 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -142,7 +142,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) { numArgs = 1; aggArgTypes = (Oid *) palloc(sizeof(Oid)); - aggArgTypes[0] = typenameTypeId(NULL, baseType); + aggArgTypes[0] = typenameTypeId(NULL, baseType, NULL); } } else @@ -164,7 +164,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) { TypeName *curTypeName = (TypeName *) lfirst(lc); - aggArgTypes[i++] = typenameTypeId(NULL, curTypeName); + aggArgTypes[i++] = typenameTypeId(NULL, curTypeName, NULL); } } @@ -175,7 +175,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters) * values of the transtype. However, we can allow polymorphic transtype * in some cases (AggregateCreate will check). */ - transTypeId = typenameTypeId(NULL, transType); + transTypeId = typenameTypeId(NULL, transType, NULL); if (get_typtype(transTypeId) == TYPTYPE_PSEUDO && !IsPolymorphicType(transTypeId)) ereport(ERROR, diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 89158251aa..c175523c36 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1996-2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.97 2007/08/21 01:11:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.98 2007/11/11 19:22:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -874,7 +874,7 @@ CommentType(List *typename, char *comment) /* Find the type's oid */ - oid = typenameTypeId(NULL, tname); + oid = typenameTypeId(NULL, tname, NULL); /* Check object security */ @@ -1451,8 +1451,8 @@ CommentCast(List *qualname, List *arguments, char *comment) targettype = (TypeName *) linitial(arguments); Assert(IsA(targettype, TypeName)); - sourcetypeid = typenameTypeId(NULL, sourcetype); - targettypeid = typenameTypeId(NULL, targettype); + sourcetypeid = typenameTypeId(NULL, sourcetype, NULL); + targettypeid = typenameTypeId(NULL, targettype, NULL); tuple = SearchSysCache(CASTSOURCETARGET, ObjectIdGetDatum(sourcetypeid), diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 9e5d0b1095..3a55661502 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.85 2007/09/03 18:46:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.86 2007/11/11 19:22:48 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -76,12 +76,13 @@ compute_return_type(TypeName *returnType, Oid languageOid, Oid *prorettype_p, bool *returnsSet_p) { Oid rettype; + Type typtup; - rettype = LookupTypeName(NULL, returnType); + typtup = LookupTypeName(NULL, returnType, NULL); - if (OidIsValid(rettype)) + if (typtup) { - if (!get_typisdefined(rettype)) + if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) { if (languageOid == SQLlanguageId) ereport(ERROR, @@ -94,6 +95,8 @@ compute_return_type(TypeName *returnType, Oid languageOid, errmsg("return type %s is only a shell", TypeNameToString(returnType)))); } + rettype = typeTypeId(typtup); + ReleaseSysCache(typtup); } else { @@ -114,6 +117,13 @@ compute_return_type(TypeName *returnType, Oid languageOid, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", typnam))); + /* Reject if there's typmod decoration, too */ + if (returnType->typmods != NIL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("type modifier cannot be specified for shell type \"%s\"", + typnam))); + /* Otherwise, go ahead and make a shell type */ ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -175,11 +185,12 @@ examine_parameter_list(List *parameters, Oid languageOid, FunctionParameter *fp = (FunctionParameter *) lfirst(x); TypeName *t = fp->argType; Oid toid; + Type typtup; - toid = LookupTypeName(NULL, t); - if (OidIsValid(toid)) + typtup = LookupTypeName(NULL, t, NULL); + if (typtup) { - if (!get_typisdefined(toid)) + if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) { /* As above, hard error if language is SQL */ if (languageOid == SQLlanguageId) @@ -193,6 +204,8 @@ examine_parameter_list(List *parameters, Oid languageOid, errmsg("argument type %s is only a shell", TypeNameToString(t)))); } + toid = typeTypeId(typtup); + ReleaseSysCache(typtup); } else { @@ -200,6 +213,7 @@ examine_parameter_list(List *parameters, Oid languageOid, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type %s does not exist", TypeNameToString(t)))); + toid = InvalidOid; /* keep compiler quiet */ } if (t->setof) @@ -1341,8 +1355,8 @@ CreateCast(CreateCastStmt *stmt) ObjectAddress myself, referenced; - sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); - targettypeid = typenameTypeId(NULL, stmt->targettype); + sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL); + targettypeid = typenameTypeId(NULL, stmt->targettype, NULL); /* No pseudo-types allowed */ if (get_typtype(sourcetypeid) == TYPTYPE_PSEUDO) @@ -1567,8 +1581,8 @@ DropCast(DropCastStmt *stmt) ObjectAddress object; /* when dropping a cast, the types must exist even if you use IF EXISTS */ - sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); - targettypeid = typenameTypeId(NULL, stmt->targettype); + sourcetypeid = typenameTypeId(NULL, stmt->sourcetype, NULL); + targettypeid = typenameTypeId(NULL, stmt->targettype, NULL); tuple = SearchSysCache(CASTSOURCETARGET, ObjectIdGetDatum(sourcetypeid), diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 12bca5119f..cc15e2b2cd 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.54 2007/02/01 19:10:26 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.55 2007/11/11 19:22:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -327,7 +327,7 @@ DefineOpClass(CreateOpClassStmt *stmt) errmsg("must be superuser to create an operator class"))); /* Look up the datatype */ - typeoid = typenameTypeId(NULL, stmt->datatype); + typeoid = typenameTypeId(NULL, stmt->datatype, NULL); #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ @@ -481,7 +481,7 @@ DefineOpClass(CreateOpClassStmt *stmt) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("storage type specified more than once"))); - storageoid = typenameTypeId(NULL, item->storedtype); + storageoid = typenameTypeId(NULL, item->storedtype, NULL); #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ @@ -1035,12 +1035,12 @@ processTypesSpec(List *args, Oid *lefttype, Oid *righttype) Assert(args != NIL); typeName = (TypeName *) linitial(args); - *lefttype = typenameTypeId(NULL, typeName); + *lefttype = typenameTypeId(NULL, typeName, NULL); if (list_length(args) > 1) { typeName = (TypeName *) lsecond(args); - *righttype = typenameTypeId(NULL, typeName); + *righttype = typenameTypeId(NULL, typeName, NULL); } else *righttype = *lefttype; diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index dd872d6a64..8de6b4bebf 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.36 2007/06/02 23:36:35 petere Exp $ + * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.37 2007/11/11 19:22:48 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -149,9 +149,9 @@ DefineOperator(List *names, List *parameters) /* Transform type names to type OIDs */ if (typeName1) - typeId1 = typenameTypeId(NULL, typeName1); + typeId1 = typenameTypeId(NULL, typeName1, NULL); if (typeName2) - typeId2 = typenameTypeId(NULL, typeName2); + typeId2 = typenameTypeId(NULL, typeName2, NULL); /* * now have OperatorCreate do all the work.. diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index 38055997fa..0a7f565316 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.77 2007/06/23 22:12:50 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.78 2007/11/11 19:22:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -90,7 +90,7 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) foreach(l, stmt->argtypes) { TypeName *tn = lfirst(l); - Oid toid = typenameTypeId(pstate, tn); + Oid toid = typenameTypeId(pstate, tn, NULL); argtypes[i++] = toid; } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 0af90cb4ac..23f3619369 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.234 2007/10/12 18:55:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.235 2007/11/11 19:22:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -899,8 +899,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, (errmsg("merging multiple inherited definitions of column \"%s\"", attributeName))); def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1); - defTypeId = typenameTypeId(NULL, def->typename); - deftypmod = typenameTypeMod(NULL, def->typename, defTypeId); + defTypeId = typenameTypeId(NULL, def->typename, &deftypmod); if (defTypeId != attribute->atttypid || deftypmod != attribute->atttypmod) ereport(ERROR, @@ -1044,10 +1043,8 @@ MergeAttributes(List *schema, List *supers, bool istemp, (errmsg("merging column \"%s\" with inherited definition", attributeName))); def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1); - defTypeId = typenameTypeId(NULL, def->typename); - deftypmod = typenameTypeMod(NULL, def->typename, defTypeId); - newTypeId = typenameTypeId(NULL, newdef->typename); - newtypmod = typenameTypeMod(NULL, newdef->typename, newTypeId); + defTypeId = typenameTypeId(NULL, def->typename, &deftypmod); + newTypeId = typenameTypeId(NULL, newdef->typename, &newtypmod); if (defTypeId != newTypeId || deftypmod != newtypmod) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -3018,8 +3015,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, int32 ctypmod; /* Okay if child matches by type */ - ctypeId = typenameTypeId(NULL, colDef->typename); - ctypmod = typenameTypeMod(NULL, colDef->typename, ctypeId); + ctypeId = typenameTypeId(NULL, colDef->typename, &ctypmod); if (ctypeId != childatt->atttypid || ctypmod != childatt->atttypmod) ereport(ERROR, @@ -3074,10 +3070,9 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, MaxHeapAttributeNumber))); i = minattnum + 1; - typeTuple = typenameType(NULL, colDef->typename); + typeTuple = typenameType(NULL, colDef->typename, &typmod); tform = (Form_pg_type) GETSTRUCT(typeTuple); typeOid = HeapTupleGetOid(typeTuple); - typmod = typenameTypeMod(NULL, colDef->typename, typeOid); /* make sure datatype is legal for a column */ CheckAttributeType(colDef->colname, typeOid); @@ -4777,8 +4772,7 @@ ATPrepAlterColumnType(List **wqueue, colName))); /* Look up the target type */ - targettype = typenameTypeId(NULL, typename); - targettypmod = typenameTypeMod(NULL, typename, targettype); + targettype = typenameTypeId(NULL, typename, &targettypmod); /* make sure datatype is legal for a column */ CheckAttributeType(colName, targettype); @@ -4905,10 +4899,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, colName))); /* Look up the target type (should not fail, since prep found it) */ - typeTuple = typenameType(NULL, typename); + typeTuple = typenameType(NULL, typename, &targettypmod); tform = (Form_pg_type) GETSTRUCT(typeTuple); targettype = HeapTupleGetOid(typeTuple); - targettypmod = typenameTypeMod(NULL, typename, targettype); /* * If there is a default expression for the column, get it and ensure we diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 1f58d989f2..230004c59b 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.109 2007/10/29 19:40:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.110 2007/11/11 19:22:48 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -211,7 +211,7 @@ DefineType(List *names, List *parameters) } else if (pg_strcasecmp(defel->defname, "element") == 0) { - elemType = typenameTypeId(NULL, defGetTypeName(defel)); + elemType = typenameTypeId(NULL, defGetTypeName(defel), NULL); /* disallow arrays of pseudotypes */ if (get_typtype(elemType) == TYPTYPE_PSEUDO) ereport(ERROR, @@ -497,8 +497,8 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok) typename = makeTypeNameFromNameList(names); /* Use LookupTypeName here so that shell types can be removed. */ - typeoid = LookupTypeName(NULL, typename); - if (!OidIsValid(typeoid)) + tup = LookupTypeName(NULL, typename, NULL); + if (tup == NULL) { if (!missing_ok) { @@ -517,11 +517,7 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok) return; } - tup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typeoid), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for type %u", typeoid); + typeoid = typeTypeId(tup); typ = (Form_pg_type) GETSTRUCT(tup); /* Permission check: must own type or its namespace */ @@ -650,10 +646,9 @@ DefineDomain(CreateDomainStmt *stmt) /* * Look up the base type. */ - typeTup = typenameType(NULL, stmt->typename); + typeTup = typenameType(NULL, stmt->typename, &basetypeMod); baseType = (Form_pg_type) GETSTRUCT(typeTup); basetypeoid = HeapTupleGetOid(typeTup); - basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid); /* * Base type must be a plain base type, another domain or an enum. @@ -946,8 +941,8 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok) typename = makeTypeNameFromNameList(names); /* Use LookupTypeName here so that shell types can be removed. */ - typeoid = LookupTypeName(NULL, typename); - if (!OidIsValid(typeoid)) + tup = LookupTypeName(NULL, typename, NULL); + if (tup == NULL) { if (!missing_ok) { @@ -966,11 +961,7 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok) return; } - tup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typeoid), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for type %u", typeoid); + typeoid = typeTypeId(tup); /* Permission check: must own type or its namespace */ if (!pg_type_ownercheck(typeoid, GetUserId()) && @@ -1443,7 +1434,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); - domainoid = typenameTypeId(NULL, typename); + domainoid = typenameTypeId(NULL, typename, NULL); /* Look up the domain in the type table */ rel = heap_open(TypeRelationId, RowExclusiveLock); @@ -1573,7 +1564,7 @@ AlterDomainNotNull(List *names, bool notNull) /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); - domainoid = typenameTypeId(NULL, typename); + domainoid = typenameTypeId(NULL, typename, NULL); /* Look up the domain in the type table */ typrel = heap_open(TypeRelationId, RowExclusiveLock); @@ -1675,7 +1666,7 @@ AlterDomainDropConstraint(List *names, const char *constrName, /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); - domainoid = typenameTypeId(NULL, typename); + domainoid = typenameTypeId(NULL, typename, NULL); /* Look up the domain in the type table */ rel = heap_open(TypeRelationId, RowExclusiveLock); @@ -1750,7 +1741,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); - domainoid = typenameTypeId(NULL, typename); + domainoid = typenameTypeId(NULL, typename, NULL); /* Look up the domain in the type table */ typrel = heap_open(TypeRelationId, RowExclusiveLock); @@ -2358,28 +2349,28 @@ AlterTypeOwner(List *names, Oid newOwnerId) Oid typeOid; Relation rel; HeapTuple tup; + HeapTuple newtup; Form_pg_type typTup; AclResult aclresult; + rel = heap_open(TypeRelationId, RowExclusiveLock); + /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); /* Use LookupTypeName here so that shell types can be processed */ - typeOid = LookupTypeName(NULL, typename); - if (!OidIsValid(typeOid)) + tup = LookupTypeName(NULL, typename, NULL); + if (tup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); + typeOid = typeTypeId(tup); - /* Look up the type in the type table */ - rel = heap_open(TypeRelationId, RowExclusiveLock); - - tup = SearchSysCacheCopy(TYPEOID, - ObjectIdGetDatum(typeOid), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) - elog(ERROR, "cache lookup failed for type %u", typeOid); + /* Copy the syscache entry so we can scribble on it below */ + newtup = heap_copytuple(tup); + ReleaseSysCache(tup); + tup = newtup; typTup = (Form_pg_type) GETSTRUCT(tup); /* @@ -2526,7 +2517,7 @@ AlterTypeNamespace(List *names, const char *newschema) /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); - typeOid = typenameTypeId(NULL, typename); + typeOid = typenameTypeId(NULL, typename, NULL); /* check permissions on type */ if (!pg_type_ownercheck(typeOid, GetUserId())) diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 86fddc4a7a..52957e825e 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.222 2007/10/29 19:40:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.223 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -829,7 +829,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a) ltype = exprType(lexpr); foreach(telem, (List *) a->rexpr) { - rtype = typenameTypeId(pstate, lfirst(telem)); + rtype = typenameTypeId(pstate, lfirst(telem), NULL); matched = (rtype == ltype); if (matched) break; @@ -1550,8 +1550,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs) XMLOID, "XMLSERIALIZE")); - targetType = typenameTypeId(pstate, xs->typename); - targetTypmod = typenameTypeMod(pstate, xs->typename, targetType); + targetType = typenameTypeId(pstate, xs->typename, &targetTypmod); xexpr->xmloption = xs->xmloption; /* We actually only need these to be able to parse back the expression. */ @@ -2227,8 +2226,7 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename) Oid targetType; int32 targetTypmod; - targetType = typenameTypeId(pstate, typename); - targetTypmod = typenameTypeMod(pstate, typename, targetType); + targetType = typenameTypeId(pstate, typename, &targetTypmod); if (inputType == InvalidOid) return expr; /* do nothing if NULL input */ diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 393fa6c41a..76dcd29185 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.197 2007/06/06 23:00:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.198 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #include "utils/syscache.h" +static Oid FuncNameAsType(List *funcname); static Node *ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg, int location); static void unknown_attribute(ParseState *pstate, Node *relref, char *attname, @@ -752,12 +753,9 @@ func_get_detail(List *funcname, */ if (nargs == 1 && fargs != NIL) { - Oid targetType; + Oid targetType = FuncNameAsType(funcname); - targetType = LookupTypeName(NULL, - makeTypeNameFromNameList(funcname)); - if (OidIsValid(targetType) && - !ISCOMPLEX(targetType)) + if (OidIsValid(targetType)) { Oid sourceType = argtypes[0]; Node *arg1 = linitial(fargs); @@ -985,6 +983,33 @@ make_fn_arguments(ParseState *pstate, } } +/* + * FuncNameAsType - + * convenience routine to see if a function name matches a type name + * + * Returns the OID of the matching type, or InvalidOid if none. We ignore + * shell types and complex types. + */ +static Oid +FuncNameAsType(List *funcname) +{ + Oid result; + Type typtup; + + typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL); + if (typtup == NULL) + return InvalidOid; + + if (((Form_pg_type) GETSTRUCT(typtup))->typisdefined && + !OidIsValid(typeTypeRelid(typtup))) + result = typeTypeId(typtup); + else + result = InvalidOid; + + ReleaseSysCache(typtup); + return result; +} + /* * ParseComplexProjection - * handles function calls with a single argument that is of complex type. @@ -1180,6 +1205,27 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) return InvalidOid; } +/* + * LookupTypeNameOid + * Convenience routine to look up a type, silently accepting shell types + */ +static Oid +LookupTypeNameOid(const TypeName *typename) +{ + Oid result; + Type typtup; + + typtup = LookupTypeName(NULL, typename, NULL); + if (typtup == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" does not exist", + TypeNameToString(typename)))); + result = typeTypeId(typtup); + ReleaseSysCache(typtup); + return result; +} + /* * LookupFuncNameTypeNames * Like LookupFuncName, but the argument types are specified by a @@ -1205,14 +1251,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError) { TypeName *t = (TypeName *) lfirst(args_item); - argoids[i] = LookupTypeName(NULL, t); - - if (!OidIsValid(argoids[i])) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type \"%s\" does not exist", - TypeNameToString(t)))); - + argoids[i] = LookupTypeNameOid(t); args_item = lnext(args_item); } @@ -1250,12 +1289,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError) { TypeName *t = (TypeName *) lfirst(lc); - argoids[i] = LookupTypeName(NULL, t); - if (!OidIsValid(argoids[i])) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type \"%s\" does not exist", - TypeNameToString(t)))); + argoids[i] = LookupTypeNameOid(t); i++; } diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 42bd04fa01..a51a4d6215 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.95 2007/04/02 03:49:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.96 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -110,12 +110,12 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername, if (oprleft == NULL) leftoid = InvalidOid; else - leftoid = typenameTypeId(pstate, oprleft); + leftoid = typenameTypeId(pstate, oprleft, NULL); if (oprright == NULL) rightoid = InvalidOid; else - rightoid = typenameTypeId(pstate, oprright); + rightoid = typenameTypeId(pstate, oprright, NULL); return LookupOperName(pstate, opername, leftoid, rightoid, noError, location); diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 10726573e9..f337ded99f 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.128 2007/09/06 17:31:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.129 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -901,8 +901,7 @@ addRangeTableEntryForFunction(ParseState *pstate, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" cannot be declared SETOF", attrname))); - attrtype = typenameTypeId(pstate, n->typename); - attrtypmod = typenameTypeMod(pstate, n->typename, attrtype); + attrtype = typenameTypeId(pstate, n->typename, &attrtypmod); eref->colnames = lappend(eref->colnames, makeString(attrname)); rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype); rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod); diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index f86dd43d54..e61cf08576 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.91 2007/06/15 20:56:50 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.92 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,26 +26,46 @@ #include "utils/syscache.h" +static int32 typenameTypeMod(ParseState *pstate, const TypeName *typename, + Type typ); + + /* * LookupTypeName - * Given a TypeName object, get the OID of the referenced type. - * Returns InvalidOid if no such type can be found. + * Given a TypeName object, lookup the pg_type syscache entry of the type. + * Returns NULL if no such type can be found. If the type is found, + * the typmod value represented in the TypeName struct is computed and + * stored into *typmod_p. + * + * NB: on success, the caller must ReleaseSysCache the type tuple when done + * with it. + * + * NB: direct callers of this function MUST check typisdefined before assuming + * that the type is fully valid. Most code should go through typenameType + * or typenameTypeId instead. * - * NB: even if the returned OID is not InvalidOid, the type might be - * just a shell. Caller should check typisdefined before using the type. + * typmod_p can be passed as NULL if the caller does not care to know the + * typmod value, but the typmod decoration (if any) will be validated anyway, + * except in the case where the type is not found. Note that if the type is + * found but is a shell, and there is typmod decoration, an error will be + * thrown --- this is intentional. * * pstate is only used for error location info, and may be NULL. */ -Oid -LookupTypeName(ParseState *pstate, const TypeName *typename) +Type +LookupTypeName(ParseState *pstate, const TypeName *typename, + int32 *typmod_p) { - Oid restype; + Oid typoid; + HeapTuple tup; + int32 typmod; - /* Easy if it's an internally generated TypeName */ if (typename->names == NIL) - return typename->typeid; - - if (typename->pct_type) + { + /* We have the OID already if it's an internally generated TypeName */ + typoid = typename->typeid; + } + else if (typename->pct_type) { /* Handle %TYPE reference to type of an existing field */ RangeVar *rel = makeRangeVar(NULL, NULL); @@ -96,7 +116,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typename) errmsg("column \"%s\" of relation \"%s\" does not exist", field, rel->relname), parser_errposition(pstate, typename->location))); - restype = get_atttype(relid, attnum); + typoid = get_atttype(relid, attnum); /* this construct should never have an array indicator */ Assert(typename->arrayBounds == NIL); @@ -105,7 +125,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typename) ereport(NOTICE, (errmsg("type reference %s converted to %s", TypeNameToString(typename), - format_type_be(restype)))); + format_type_be(typoid)))); } else { @@ -122,130 +142,86 @@ LookupTypeName(ParseState *pstate, const TypeName *typename) Oid namespaceId; namespaceId = LookupExplicitNamespace(schemaname); - restype = GetSysCacheOid(TYPENAMENSP, - PointerGetDatum(typname), - ObjectIdGetDatum(namespaceId), - 0, 0); + typoid = GetSysCacheOid(TYPENAMENSP, + PointerGetDatum(typname), + ObjectIdGetDatum(namespaceId), + 0, 0); } else { /* Unqualified type name, so search the search path */ - restype = TypenameGetTypid(typname); + typoid = TypenameGetTypid(typname); } /* If an array reference, return the array type instead */ if (typename->arrayBounds != NIL) - restype = get_array_type(restype); + typoid = get_array_type(typoid); } - return restype; -} - -/* - * appendTypeNameToBuffer - * Append a string representing the name of a TypeName to a StringInfo. - * This is the shared guts of TypeNameToString and TypeNameListToString. - * - * NB: this must work on TypeNames that do not describe any actual type; - * it is mostly used for reporting lookup errors. - */ -static void -appendTypeNameToBuffer(const TypeName *typename, StringInfo string) -{ - if (typename->names != NIL) - { - /* Emit possibly-qualified name as-is */ - ListCell *l; - - foreach(l, typename->names) - { - if (l != list_head(typename->names)) - appendStringInfoChar(string, '.'); - appendStringInfoString(string, strVal(lfirst(l))); - } - } - else + if (!OidIsValid(typoid)) { - /* Look up internally-specified type */ - appendStringInfoString(string, format_type_be(typename->typeid)); + if (typmod_p) + *typmod_p = -1; + return NULL; } - /* - * Add decoration as needed, but only for fields considered by - * LookupTypeName - */ - if (typename->pct_type) - appendStringInfoString(string, "%TYPE"); - - if (typename->arrayBounds != NIL) - appendStringInfoString(string, "[]"); -} - -/* - * TypeNameToString - * Produce a string representing the name of a TypeName. - * - * NB: this must work on TypeNames that do not describe any actual type; - * it is mostly used for reporting lookup errors. - */ -char * -TypeNameToString(const TypeName *typename) -{ - StringInfoData string; - - initStringInfo(&string); - appendTypeNameToBuffer(typename, &string); - return string.data; -} + tup = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typoid), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for type %u", typoid); -/* - * TypeNameListToString - * Produce a string representing the name(s) of a List of TypeNames - */ -char * -TypeNameListToString(List *typenames) -{ - StringInfoData string; - ListCell *l; + typmod = typenameTypeMod(pstate, typename, (Type) tup); - initStringInfo(&string); - foreach(l, typenames) - { - TypeName *typename = (TypeName *) lfirst(l); + if (typmod_p) + *typmod_p = typmod; - Assert(IsA(typename, TypeName)); - if (l != list_head(typenames)) - appendStringInfoChar(&string, ','); - appendTypeNameToBuffer(typename, &string); - } - return string.data; + return (Type) tup; } /* - * typenameTypeId - given a TypeName, return the type's OID + * typenameType - given a TypeName, return a Type structure and typmod * * This is equivalent to LookupTypeName, except that this will report * a suitable error message if the type cannot be found or is not defined. + * Callers of this can therefore assume the result is a fully valid type. */ -Oid -typenameTypeId(ParseState *pstate, const TypeName *typename) +Type +typenameType(ParseState *pstate, const TypeName *typename, int32 *typmod_p) { - Oid typoid; + Type tup; - typoid = LookupTypeName(pstate, typename); - if (!OidIsValid(typoid)) + tup = LookupTypeName(pstate, typename, typmod_p); + if (tup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)), parser_errposition(pstate, typename->location))); - - if (!get_typisdefined(typoid)) + if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" is only a shell", TypeNameToString(typename)), parser_errposition(pstate, typename->location))); + return tup; +} + +/* + * typenameTypeId - given a TypeName, return the type's OID and typmod + * + * This is equivalent to typenameType, but we only hand back the type OID + * not the syscache entry. + */ +Oid +typenameTypeId(ParseState *pstate, const TypeName *typename, int32 *typmod_p) +{ + Oid typoid; + Type tup; + + tup = typenameType(pstate, typename, typmod_p); + typoid = HeapTupleGetOid(tup); + ReleaseSysCache(tup); return typoid; } @@ -257,13 +233,12 @@ typenameTypeId(ParseState *pstate, const TypeName *typename) * illegal for the data type. * * The actual type OID represented by the TypeName must already have been - * determined (usually by typenameTypeId()), and is passed as typeId. + * looked up, and is passed as "typ". * * pstate is only used for error location info, and may be NULL. */ -int32 -typenameTypeMod(ParseState *pstate, const TypeName *typename, - Oid typeId) +static int32 +typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ) { int32 result; Oid typmodin; @@ -272,14 +247,23 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename, ListCell *l; ArrayType *arrtypmod; - Assert(OidIsValid(typeId)); - /* Return prespecified typmod if no typmod expressions */ if (typename->typmods == NIL) return typename->typemod; - /* Else, type had better accept typmods */ - typmodin = get_typmodin(typeId); + /* + * Else, type had better accept typmods. We give a special error + * message for the shell-type case, since a shell couldn't possibly + * have a typmodin function. + */ + if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("type modifier cannot be specified for shell type \"%s\"", + TypeNameToString(typename)), + parser_errposition(pstate, typename->location))); + + typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin; if (typmodin == InvalidOid) ereport(ERROR, @@ -349,36 +333,83 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename, } /* - * typenameType - given a TypeName, return a Type structure + * appendTypeNameToBuffer + * Append a string representing the name of a TypeName to a StringInfo. + * This is the shared guts of TypeNameToString and TypeNameListToString. * - * This is equivalent to typenameTypeId + syscache fetch of Type tuple. - * NB: caller must ReleaseSysCache the type tuple when done with it. + * NB: this must work on TypeNames that do not describe any actual type; + * it is mostly used for reporting lookup errors. */ -Type -typenameType(ParseState *pstate, const TypeName *typename) +static void +appendTypeNameToBuffer(const TypeName *typename, StringInfo string) { - Oid typoid; - HeapTuple tup; + if (typename->names != NIL) + { + /* Emit possibly-qualified name as-is */ + ListCell *l; - typoid = LookupTypeName(pstate, typename); - if (!OidIsValid(typoid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type \"%s\" does not exist", - TypeNameToString(typename)), - parser_errposition(pstate, typename->location))); - tup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typoid), - 0, 0, 0); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "cache lookup failed for type %u", typoid); - if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type \"%s\" is only a shell", - TypeNameToString(typename)), - parser_errposition(pstate, typename->location))); - return (Type) tup; + foreach(l, typename->names) + { + if (l != list_head(typename->names)) + appendStringInfoChar(string, '.'); + appendStringInfoString(string, strVal(lfirst(l))); + } + } + else + { + /* Look up internally-specified type */ + appendStringInfoString(string, format_type_be(typename->typeid)); + } + + /* + * Add decoration as needed, but only for fields considered by + * LookupTypeName + */ + if (typename->pct_type) + appendStringInfoString(string, "%TYPE"); + + if (typename->arrayBounds != NIL) + appendStringInfoString(string, "[]"); +} + +/* + * TypeNameToString + * Produce a string representing the name of a TypeName. + * + * NB: this must work on TypeNames that do not describe any actual type; + * it is mostly used for reporting lookup errors. + */ +char * +TypeNameToString(const TypeName *typename) +{ + StringInfoData string; + + initStringInfo(&string); + appendTypeNameToBuffer(typename, &string); + return string.data; +} + +/* + * TypeNameListToString + * Produce a string representing the name(s) of a List of TypeNames + */ +char * +TypeNameListToString(List *typenames) +{ + StringInfoData string; + ListCell *l; + + initStringInfo(&string); + foreach(l, typenames) + { + TypeName *typename = (TypeName *) lfirst(l); + + Assert(IsA(typename, TypeName)); + if (l != list_head(typenames)) + appendStringInfoChar(&string, ','); + appendTypeNameToBuffer(typename, &string); + } + return string.data; } /* return a Type structure, given a type id */ @@ -507,7 +538,7 @@ pts_error_callback(void *arg) * the string and convert it to a type OID and type modifier. */ void -parseTypeString(const char *str, Oid *type_id, int32 *typmod) +parseTypeString(const char *str, Oid *type_id, int32 *typmod_p) { StringInfoData buf; List *raw_parsetree_list; @@ -579,8 +610,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod) if (typename->setof) goto fail; - *type_id = typenameTypeId(NULL, typename); - *typmod = typenameTypeMod(NULL, typename, *type_id); + *type_id = typenameTypeId(NULL, typename, typmod_p); pfree(buf.data); diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 287e82ddee..a6306a435c 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -19,7 +19,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.4 2007/10/29 19:40:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.5 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1955,7 +1955,7 @@ transformColumnType(ParseState *pstate, ColumnDef *column) /* * All we really need to do here is verify that the type is valid. */ - Type ctype = typenameType(pstate, column->typename); + Type ctype = typenameType(pstate, column->typename, NULL); ReleaseSysCache(ctype); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 49a4cc722e..02d5fd4bbe 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.424 2007/11/09 17:31:07 mha Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.425 2007/11/11 19:22:49 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -4872,11 +4872,13 @@ flatten_set_variable_args(const char *name, List *args) * to interval and back to normalize the value and account * for any typmod. */ + Oid typoid; int32 typmod; Datum interval; char *intervalout; - typmod = typenameTypeMod(NULL, arg->typename, INTERVALOID); + typoid = typenameTypeId(NULL, arg->typename, &typmod); + Assert(typoid == INTERVALOID); interval = DirectFunctionCall3(interval_in, diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index 3d07b08579..414dd09b91 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -1,13 +1,12 @@ /*------------------------------------------------------------------------- * * parse_type.h - * - * + * handle type operations for parser * * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.36 2007/04/02 03:49:41 tgl Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.37 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,13 +19,15 @@ typedef HeapTuple Type; -extern Oid LookupTypeName(ParseState *pstate, const TypeName *typename); +extern Type LookupTypeName(ParseState *pstate, const TypeName *typename, + int32 *typmod_p); +extern Type typenameType(ParseState *pstate, const TypeName *typename, + int32 *typmod_p); +extern Oid typenameTypeId(ParseState *pstate, const TypeName *typename, + int32 *typmod_p); + extern char *TypeNameToString(const TypeName *typename); extern char *TypeNameListToString(List *typenames); -extern Oid typenameTypeId(ParseState *pstate, const TypeName *typename); -extern int32 typenameTypeMod(ParseState *pstate, const TypeName *typename, - Oid typeId); -extern Type typenameType(ParseState *pstate, const TypeName *typename); extern Type typeidType(Oid id); @@ -39,7 +40,7 @@ extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod); extern Oid typeidTypeRelid(Oid type_id); -extern void parseTypeString(const char *str, Oid *type_id, int32 *typmod); +extern void parseTypeString(const char *str, Oid *type_id, int32 *typmod_p); #define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid) diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index db150632f0..7799cf7c65 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.117 2007/07/16 17:01:10 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.118 2007/11/11 19:22:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1099,7 +1099,7 @@ plpgsql_parse_wordtype(char *word) { PLpgSQL_nsitem *nse; bool old_nsstate; - Oid typeOid; + HeapTuple typeTup; char *cp[2]; int i; @@ -1138,34 +1138,26 @@ plpgsql_parse_wordtype(char *word) /* * Word wasn't found on the namestack. Try to find a data type with that - * name, but ignore pg_type entries that are in fact class types. + * name, but ignore shell types and complex types. */ - typeOid = LookupTypeName(NULL, makeTypeName(cp[0])); - if (OidIsValid(typeOid)) + typeTup = LookupTypeName(NULL, makeTypeName(cp[0]), NULL); + if (typeTup) { - HeapTuple typeTup; + Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typeOid), - 0, 0, 0); - if (HeapTupleIsValid(typeTup)) + if (!typeStruct->typisdefined || + typeStruct->typrelid != InvalidOid) { - Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - - if (!typeStruct->typisdefined || - typeStruct->typrelid != InvalidOid) - { - ReleaseSysCache(typeTup); - pfree(cp[0]); - return T_ERROR; - } - - plpgsql_yylval.dtype = build_datatype(typeTup, -1); - ReleaseSysCache(typeTup); pfree(cp[0]); - return T_DTYPE; + return T_ERROR; } + + plpgsql_yylval.dtype = build_datatype(typeTup, -1); + + ReleaseSysCache(typeTup); + pfree(cp[0]); + return T_DTYPE; } /* -- GitLab