mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-21 03:13:05 +08:00
Ensure that typmod decoration on a datatype name is validated in all cases,
even in code paths where we don't pay any subsequent attention to the typmod value. This seems needed in view of the fact that 8.3's generalized typmod support will accept a lot of bogus syntax, such as "timestamp(foo)" or "record(int, 42)" --- if we allow such things to pass without comment, users will get confused. Per a recent example from Greg Stark. To implement this in a way that's not very vulnerable to future bugs-of-omission, refactor the API of parse_type.c's TypeName lookup routines so that typmod validation is folded into the base lookup operation. Callers can still choose not to receive the encoded typmod, but we'll check the decoration anyway if it's present.
This commit is contained in:
parent
6b8cc88268
commit
0bd4da23a4
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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..
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()))
|
||||
|
@ -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 */
|
||||
|
@ -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++;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.91 2007/06/15 20:56:50 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.92 2007/11/11 19:22:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,26 +26,46 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static int32 typenameTypeMod(ParseState *pstate, const TypeName *typename,
|
||||
Type typ);
|
||||
|
||||
|
||||
/*
|
||||
* LookupTypeName
|
||||
* Given a TypeName object, get the OID of the referenced type.
|
||||
* Returns InvalidOid if no such type can be found.
|
||||
* Given a TypeName object, lookup the pg_type syscache entry of the type.
|
||||
* Returns NULL if no such type can be found. If the type is found,
|
||||
* the typmod value represented in the TypeName struct is computed and
|
||||
* stored into *typmod_p.
|
||||
*
|
||||
* NB: even if the returned OID is not InvalidOid, the type might be
|
||||
* just a shell. Caller should check typisdefined before using the type.
|
||||
* 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.
|
||||
*
|
||||
* 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,23 +142,194 @@ 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;
|
||||
if (!OidIsValid(typoid))
|
||||
{
|
||||
if (typmod_p)
|
||||
*typmod_p = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for type %u", typoid);
|
||||
|
||||
typmod = typenameTypeMod(pstate, typename, (Type) tup);
|
||||
|
||||
if (typmod_p)
|
||||
*typmod_p = typmod;
|
||||
|
||||
return (Type) tup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
Type
|
||||
typenameType(ParseState *pstate, const TypeName *typename, int32 *typmod_p)
|
||||
{
|
||||
Type tup;
|
||||
|
||||
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 (!((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;
|
||||
}
|
||||
|
||||
/*
|
||||
* typenameTypeMod - given a TypeName, return the internal typmod value
|
||||
*
|
||||
* This will throw an error if the TypeName includes type modifiers that are
|
||||
* illegal for the data type.
|
||||
*
|
||||
* The actual type OID represented by the TypeName must already have been
|
||||
* looked up, and is passed as "typ".
|
||||
*
|
||||
* pstate is only used for error location info, and may be NULL.
|
||||
*/
|
||||
static int32
|
||||
typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ)
|
||||
{
|
||||
int32 result;
|
||||
Oid typmodin;
|
||||
Datum *datums;
|
||||
int n;
|
||||
ListCell *l;
|
||||
ArrayType *arrtypmod;
|
||||
|
||||
/* Return prespecified typmod if no typmod expressions */
|
||||
if (typename->typmods == NIL)
|
||||
return typename->typemod;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("type modifier is not allowed for type \"%s\"",
|
||||
TypeNameToString(typename)),
|
||||
parser_errposition(pstate, typename->location)));
|
||||
|
||||
/*
|
||||
* Convert the list of raw-grammar-output expressions to a cstring array.
|
||||
* Currently, we allow simple numeric constants, string literals, and
|
||||
* identifiers; possibly this list could be extended.
|
||||
*/
|
||||
datums = (Datum *) palloc(list_length(typename->typmods) * sizeof(Datum));
|
||||
n = 0;
|
||||
foreach(l, typename->typmods)
|
||||
{
|
||||
Node *tm = (Node *) lfirst(l);
|
||||
char *cstr = NULL;
|
||||
|
||||
if (IsA(tm, A_Const))
|
||||
{
|
||||
A_Const *ac = (A_Const *) tm;
|
||||
|
||||
/*
|
||||
* The grammar hands back some integers with ::int4 attached,
|
||||
* so allow a cast decoration if it's an Integer value, but
|
||||
* not otherwise.
|
||||
*/
|
||||
if (IsA(&ac->val, Integer))
|
||||
{
|
||||
cstr = (char *) palloc(32);
|
||||
snprintf(cstr, 32, "%ld", (long) ac->val.val.ival);
|
||||
}
|
||||
else if (ac->typename == NULL) /* no casts allowed */
|
||||
{
|
||||
/* otherwise we can just use the str field directly. */
|
||||
cstr = ac->val.val.str;
|
||||
}
|
||||
}
|
||||
else if (IsA(tm, ColumnRef))
|
||||
{
|
||||
ColumnRef *cr = (ColumnRef *) tm;
|
||||
|
||||
if (list_length(cr->fields) == 1)
|
||||
cstr = strVal(linitial(cr->fields));
|
||||
}
|
||||
if (!cstr)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("type modifiers must be simple constants or identifiers"),
|
||||
parser_errposition(pstate, typename->location)));
|
||||
datums[n++] = CStringGetDatum(cstr);
|
||||
}
|
||||
|
||||
/* hardwired knowledge about cstring's representation details here */
|
||||
arrtypmod = construct_array(datums, n, CSTRINGOID,
|
||||
-2, false, 'c');
|
||||
|
||||
result = DatumGetInt32(OidFunctionCall1(typmodin,
|
||||
PointerGetDatum(arrtypmod)));
|
||||
|
||||
pfree(datums);
|
||||
pfree(arrtypmod);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -221,166 +412,6 @@ TypeNameListToString(List *typenames)
|
||||
return string.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* typenameTypeId - given a TypeName, return the type's OID
|
||||
*
|
||||
* This is equivalent to LookupTypeName, except that this will report
|
||||
* a suitable error message if the type cannot be found or is not defined.
|
||||
*/
|
||||
Oid
|
||||
typenameTypeId(ParseState *pstate, const TypeName *typename)
|
||||
{
|
||||
Oid typoid;
|
||||
|
||||
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)));
|
||||
|
||||
if (!get_typisdefined(typoid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("type \"%s\" is only a shell",
|
||||
TypeNameToString(typename)),
|
||||
parser_errposition(pstate, typename->location)));
|
||||
|
||||
return typoid;
|
||||
}
|
||||
|
||||
/*
|
||||
* typenameTypeMod - given a TypeName, return the internal typmod value
|
||||
*
|
||||
* This will throw an error if the TypeName includes type modifiers that are
|
||||
* 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.
|
||||
*
|
||||
* pstate is only used for error location info, and may be NULL.
|
||||
*/
|
||||
int32
|
||||
typenameTypeMod(ParseState *pstate, const TypeName *typename,
|
||||
Oid typeId)
|
||||
{
|
||||
int32 result;
|
||||
Oid typmodin;
|
||||
Datum *datums;
|
||||
int n;
|
||||
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);
|
||||
|
||||
if (typmodin == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("type modifier is not allowed for type \"%s\"",
|
||||
TypeNameToString(typename)),
|
||||
parser_errposition(pstate, typename->location)));
|
||||
|
||||
/*
|
||||
* Convert the list of raw-grammar-output expressions to a cstring array.
|
||||
* Currently, we allow simple numeric constants, string literals, and
|
||||
* identifiers; possibly this list could be extended.
|
||||
*/
|
||||
datums = (Datum *) palloc(list_length(typename->typmods) * sizeof(Datum));
|
||||
n = 0;
|
||||
foreach(l, typename->typmods)
|
||||
{
|
||||
Node *tm = (Node *) lfirst(l);
|
||||
char *cstr = NULL;
|
||||
|
||||
if (IsA(tm, A_Const))
|
||||
{
|
||||
A_Const *ac = (A_Const *) tm;
|
||||
|
||||
/*
|
||||
* The grammar hands back some integers with ::int4 attached,
|
||||
* so allow a cast decoration if it's an Integer value, but
|
||||
* not otherwise.
|
||||
*/
|
||||
if (IsA(&ac->val, Integer))
|
||||
{
|
||||
cstr = (char *) palloc(32);
|
||||
snprintf(cstr, 32, "%ld", (long) ac->val.val.ival);
|
||||
}
|
||||
else if (ac->typename == NULL) /* no casts allowed */
|
||||
{
|
||||
/* otherwise we can just use the str field directly. */
|
||||
cstr = ac->val.val.str;
|
||||
}
|
||||
}
|
||||
else if (IsA(tm, ColumnRef))
|
||||
{
|
||||
ColumnRef *cr = (ColumnRef *) tm;
|
||||
|
||||
if (list_length(cr->fields) == 1)
|
||||
cstr = strVal(linitial(cr->fields));
|
||||
}
|
||||
if (!cstr)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("type modifiers must be simple constants or identifiers"),
|
||||
parser_errposition(pstate, typename->location)));
|
||||
datums[n++] = CStringGetDatum(cstr);
|
||||
}
|
||||
|
||||
/* hardwired knowledge about cstring's representation details here */
|
||||
arrtypmod = construct_array(datums, n, CSTRINGOID,
|
||||
-2, false, 'c');
|
||||
|
||||
result = DatumGetInt32(OidFunctionCall1(typmodin,
|
||||
PointerGetDatum(arrtypmod)));
|
||||
|
||||
pfree(datums);
|
||||
pfree(arrtypmod);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* typenameType - given a TypeName, return a Type structure
|
||||
*
|
||||
* This is equivalent to typenameTypeId + syscache fetch of Type tuple.
|
||||
* NB: caller must ReleaseSysCache the type tuple when done with it.
|
||||
*/
|
||||
Type
|
||||
typenameType(ParseState *pstate, const TypeName *typename)
|
||||
{
|
||||
Oid typoid;
|
||||
HeapTuple tup;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* return a Type structure, given a type id */
|
||||
/* NB: caller must ReleaseSysCache the type tuple when done with it */
|
||||
Type
|
||||
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -1,13 +1,12 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* parse_type.h
|
||||
*
|
||||
*
|
||||
* handle type operations for parser
|
||||
*
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.36 2007/04/02 03:49:41 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.37 2007/11/11 19:22:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -20,13 +19,15 @@
|
||||
|
||||
typedef HeapTuple Type;
|
||||
|
||||
extern Oid LookupTypeName(ParseState *pstate, const TypeName *typename);
|
||||
extern Type LookupTypeName(ParseState *pstate, const TypeName *typename,
|
||||
int32 *typmod_p);
|
||||
extern Type typenameType(ParseState *pstate, const TypeName *typename,
|
||||
int32 *typmod_p);
|
||||
extern Oid typenameTypeId(ParseState *pstate, const TypeName *typename,
|
||||
int32 *typmod_p);
|
||||
|
||||
extern char *TypeNameToString(const TypeName *typename);
|
||||
extern char *TypeNameListToString(List *typenames);
|
||||
extern Oid typenameTypeId(ParseState *pstate, const TypeName *typename);
|
||||
extern int32 typenameTypeMod(ParseState *pstate, const TypeName *typename,
|
||||
Oid typeId);
|
||||
extern Type typenameType(ParseState *pstate, const TypeName *typename);
|
||||
|
||||
extern Type typeidType(Oid id);
|
||||
|
||||
@ -39,7 +40,7 @@ extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
|
||||
|
||||
extern Oid typeidTypeRelid(Oid type_id);
|
||||
|
||||
extern void parseTypeString(const char *str, Oid *type_id, int32 *typmod);
|
||||
extern void parseTypeString(const char *str, Oid *type_id, int32 *typmod_p);
|
||||
|
||||
#define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid)
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user