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 50e41ade60e7384e269abb0d79ed3aad0a8d573a..6e2ac69cc404e6c03192c691770f4f44e79c7401 100644 (file)
@@ -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)
index 89ea00d89a603c9bcf6bd35186d54497d8896eb7..e49a7da3a29c86c0430d5603ccbfb8361a348db2 100644 (file)
@@ -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,
index 89158251aa45a19b1bd6f5ae16cd352f1ce4e0d3..c175523c36b91239fe058f8b455917eacb530752 100644 (file)
@@ -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),
index 9e5d0b1095ba08f16c3cc0105f122dc5c7bd7d62..3a5566150269bc35d44257ed72042b288345e2b4 100644 (file)
@@ -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),
index 12bca5119fe306b5defca11be300a4fb73e8f02f..cc15e2b2cdb7ba261132f0597184d0037df40ae7 100644 (file)
@@ -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;
index dd872d6a642ebf00ef6bb0ffade578ed902de073..8de6b4bebfd3eaad66e1532b1e6f37d83817c75b 100644 (file)
@@ -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..
index 38055997faaf936ad36dec42106df312adc54702..0a7f5653167c758e635bc75c4c01abb5824ff551 100644 (file)
@@ -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;
        }
index 0af90cb4ac64f88a2b3c7e4d0fc739a833d1028d..23f3619369018f4e58c0a2178648d36dedf19cac 100644 (file)
@@ -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
index 1f58d989f266221a3090ca80bf29b692e43c6fc0..230004c59bb7c24cafc320db8b98c211e94c6814 100644 (file)
@@ -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()))
index 86fddc4a7a64ee1922738e16746395248ee021f4..52957e825e7f7a66041185b2660d037f595ba5e1 100644 (file)
@@ -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 */
index 393fa6c41ac43b727c6cab99af96023f237e4a7d..76dcd29185c71782d75680abcf3aedb4a07c2fbb 100644 (file)
@@ -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++;
    }
 
index 42bd04fa01ebee35ccd4671acd4ff6138d05a2a5..a51a4d6215df0e9578a255bfff29a4de5c6ce673 100644 (file)
@@ -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);
index 10726573e92b9f354a0e81809bda10a96b398141..f337ded99f7eda430785b6c10f9b604213d678f2 100644 (file)
@@ -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);
index f86dd43d54889c4c2a29b388f4f65357ceae9c4a..e61cf0857645619b5d54e3963c0a4d6c2296ad3b 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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 287e82ddeec10baecdb72da4e74f8e0b3570ec8e..a6306a435cc8f12b1e95dc041245c8ef915be611 100644 (file)
@@ -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);
 }
index 49a4cc722e02337109178d85331c4e23b3b624b9..02d5fd4bbe6f59f2049cd5a1736e6b920d02500d 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * 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,
index 3d07b085793561547d5c9937333f4a4677871acd..414dd09b91e61efaa448d2e9165c7dc4bbae1a11 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 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 db150632f0555d3e8e80543220e25504540b98bc..7799cf7c65675c3a90e0eda67d72a0f440ae44c7 100644 (file)
@@ -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;
    }
 
    /*