Ensure that typmod decoration on a datatype name is validated in all cases,
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 11 Nov 2007 19:22:49 +0000 (19:22 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 11 Nov 2007 19:22:49 +0000 (19:22 +0000)
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.

18 files changed:
src/backend/access/common/tupdesc.c
src/backend/commands/aggregatecmds.c
src/backend/commands/comment.c
src/backend/commands/functioncmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/operatorcmds.c
src/backend/commands/prepare.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_type.c
src/backend/parser/parse_utilcmd.c
src/backend/utils/misc/guc.c
src/include/parser/parse_type.h
src/pl/plpgsql/src/pl_comp.c

index 4aa0fb6c4eaa813256c152cd942bb168ccc570ca..84dbdcc3920d82815f7df244da81529280042782 100644 (file)
@@ -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)
index c6a9f1e43a7512431b50c4d9491c4984c6964ea6..b9ca7169bec0f616a17b4de0da32a20045242b4a 100644 (file)
@@ -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,
index f88ea1579604b05248399ef7301ad6a1cff92100..56e6fbe39ab3bd217af3e153fe2c609efdcaddc1 100644 (file)
@@ -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),
index fa42ec61a99624982329428fef87ff21d05c9a5e..39e0da21ac0e5a55bf1942abe3e11776c56fa27d 100644 (file)
@@ -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),
index fd8ae1c1162f5d1b02738ef4501e46b1d6fcff42..3930b2b9bd1e3469243baae9acd3bba57afcd954 100644 (file)
@@ -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;
index e07ec3e99e23e3a4c30708b7f100cd2385cef033..a87cdbef9b5ff3ed1f60e2184bda24d71e1c874a 100644 (file)
@@ -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..
index 6f428241fbdbe1f34ea33b8a35fe79cc8975a390..a18f268a3a6946e69271f347a583f89105aa35a8 100644 (file)
@@ -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;
                }
index f029811196a63d117cdcfed8923b7a39ebe03207..95d76c4192915e66f12e4cb3f38703d9b791968f 100644 (file)
@@ -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
index 11ae6f4b8b31efd159c5fe4e8914c1ad586b1c0d..323e47dd3911bd501a225ac247d69587fabe43bd 100644 (file)
@@ -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()))
index 7818456b5158a048ae11a016c7a7a47790e1742b..f9d74bf0812af8f0294954f04c4fa0f09d898306 100644 (file)
@@ -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 */
index 3637f05cc1d037ddc96db65bf49003c9fbd178a4..8bda57b78d377eac213008e13a38fbf224c98cf8 100644 (file)
@@ -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++;
        }
 
index 82f4b3377a5decc02414266b97cee1852b1e0eaf..ef3e164e798f08d3b30845142f7854b1279b206b 100644 (file)
@@ -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);
index f57e1a43481bd552f48c42a9db0de2664254df74..00d9ef84f386becc031a488d556f0f700d05e5b8 100644 (file)
@@ -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);
index f03bbc890f99b8f2cb6dd4537b54aae81e1fb7dd..734e93cfdfab2fd3369d6db968de4a76a2addf6e 100644 (file)
 #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);
 
index af6451b4f38427b1e523aa485964f1188617a0e8..d3a5f0ecc733e1ae3d8d1c031d0684415647d622 100644 (file)
@@ -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);
 }
index 25f6022d97b722b4e96fe1233736ca33ae560acf..3db53d7cf044308e0311686faf64fa5a75c345e5 100644 (file)
@@ -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,
index 5f2e72ab0ebc3ada2652350e2cc2118e7a6d8bfe..33d2f7ad56cb3a2137215f62ea0ee3ad7a760d2c 100644 (file)
@@ -1,8 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * 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
 
 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)
 
index 7e59837193a5a3ebf6ae5ffc82cc5a211373464e..0272a57878ec3f0af60bdb476f65bb0321d2519a 100644 (file)
@@ -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;
        }
 
        /*