*
  *
  * 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
        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)
 
  *
  *
  * 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
        {
            numArgs = 1;
            aggArgTypes = (Oid *) palloc(sizeof(Oid));
-           aggArgTypes[0] = typenameTypeId(NULL, baseType);
+           aggArgTypes[0] = typenameTypeId(NULL, baseType, NULL);
        }
    }
    else
        {
            TypeName   *curTypeName = (TypeName *) lfirst(lc);
 
-           aggArgTypes[i++] = typenameTypeId(NULL, curTypeName);
+           aggArgTypes[i++] = typenameTypeId(NULL, curTypeName, NULL);
        }
    }
 
     * 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,
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
    /* Find the type's oid */
 
-   oid = typenameTypeId(NULL, tname);
+   oid = typenameTypeId(NULL, tname, NULL);
 
    /* Check object security */
 
    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),
 
  *
  *
  * 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
                    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,
                         errmsg("return type %s is only a shell",
                                TypeNameToString(returnType))));
        }
+       rettype = typeTypeId(typtup);
+       ReleaseSysCache(typtup);
    }
    else
    {
                    (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),
        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)
                             errmsg("argument type %s is only a shell",
                                    TypeNameToString(t))));
            }
+           toid = typeTypeId(typtup);
+           ReleaseSysCache(typtup);
        }
        else
        {
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("type %s does not exist",
                            TypeNameToString(t))));
+           toid = InvalidOid;  /* keep compiler quiet */
        }
 
        if (t->setof)
    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)
    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),
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
                 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 */
                    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 */
    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;
 
  *
  *
  * 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
 
    /* 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..
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
        foreach(l, stmt->argtypes)
        {
            TypeName   *tn = lfirst(l);
-           Oid         toid = typenameTypeId(pstate, tn);
+           Oid         toid = typenameTypeId(pstate, tn, NULL);
 
            argtypes[i++] = toid;
        }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
                        (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,
                   (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),
            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,
                        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);
                        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);
                        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
 
  *
  *
  * 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
        }
        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,
    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)
        {
        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 */
    /*
     * 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.
    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)
        {
        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()) &&
 
    /* 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);
 
    /* 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);
 
    /* 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);
 
    /* 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);
    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);
 
    /*
 
    /* 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()))
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    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;
                                                     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. */
    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 */
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 #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,
         */
        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);
    }
 }
 
+/*
+ * 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.
    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
    {
        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);
    }
 
    {
        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++;
    }
 
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    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);
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
                        (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);
 
  *
  *
  * 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);
                     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);
        ereport(NOTICE,
                (errmsg("type reference %s converted to %s",
                        TypeNameToString(typename),
-                       format_type_be(restype))));
+                       format_type_be(typoid))));
    }
    else
    {
            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;
 }
  * 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;
    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,
 }
 
 /*
- * 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 */
  * 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;
    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);
 
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    /*
     * 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);
 }
 
  *
  * 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 $
  *
  *--------------------------------------------------------------------
  */
                     * 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,
 
 /*-------------------------------------------------------------------------
  *
  * 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);
 
 
 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)
 
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 {
    PLpgSQL_nsitem *nse;
    bool        old_nsstate;
-   Oid         typeOid;
+   HeapTuple   typeTup;
    char       *cp[2];
    int         i;
 
 
    /*
     * 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;
    }
 
    /*