1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Support type modifiers for user-defined types, and pull most knowledge

about typmod representation for standard types out into type-specific
typmod I/O functions.  Teodor Sigaev, with some editorialization by
Tom Lane.
This commit is contained in:
Tom Lane
2006-12-30 21:21:56 +00:00
parent 24b1f14eae
commit 5725b9d9af
47 changed files with 1628 additions and 685 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.118 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.119 2006/12/30 21:21:52 tgl Exp $
*
* NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be
@@ -508,6 +508,7 @@ BuildDescForRelation(List *schema)
AttrDefault *attrdef = NULL;
TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
char *attname;
Oid atttypid;
int32 atttypmod;
int attdim;
int ndef = 0;
@@ -533,7 +534,8 @@ BuildDescForRelation(List *schema)
attnum++;
attname = entry->colname;
atttypmod = entry->typename->typmod;
atttypid = typenameTypeId(NULL, entry->typename);
atttypmod = typenameTypeMod(NULL, entry->typename, atttypid);
attdim = list_length(entry->typename->arrayBounds);
if (entry->typename->setof)
@@ -543,8 +545,7 @@ BuildDescForRelation(List *schema)
attname)));
TupleDescInitEntry(desc, attnum, attname,
typenameTypeId(NULL, entry->typename),
atttypmod, attdim);
atttypid, atttypmod, attdim);
/* Fill in additional stuff not handled by TupleDescInitEntry */
if (entry->is_not_null)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.314 2006/11/05 22:42:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.315 2006/12/30 21:21:52 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -724,6 +724,8 @@ AddNewRelationType(const char *typeName,
F_RECORD_OUT, /* output procedure */
F_RECORD_RECV, /* receive procedure */
F_RECORD_SEND, /* send procedure */
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
InvalidOid, /* array element type - irrelevant */
InvalidOid, /* domain base type - irrelevant */

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.108 2006/10/04 00:29:50 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.109 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -94,6 +94,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* typoutput */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typmodin */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typmodout */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
values[i++] = CharGetDatum('i'); /* typalign */
values[i++] = CharGetDatum('p'); /* typstorage */
@@ -132,6 +134,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
InvalidOid,
InvalidOid,
InvalidOid,
InvalidOid,
InvalidOid,
NULL,
false);
@@ -164,6 +168,8 @@ TypeCreate(const char *typeName,
Oid outputProcedure,
Oid receiveProcedure,
Oid sendProcedure,
Oid typmodinProcedure,
Oid typmodoutProcedure,
Oid analyzeProcedure,
Oid elementType,
Oid baseType,
@@ -243,6 +249,8 @@ TypeCreate(const char *typeName,
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */
values[i++] = ObjectIdGetDatum(sendProcedure); /* typsend */
values[i++] = ObjectIdGetDatum(typmodinProcedure); /* typmodin */
values[i++] = ObjectIdGetDatum(typmodoutProcedure); /* typmodout */
values[i++] = ObjectIdGetDatum(analyzeProcedure); /* typanalyze */
values[i++] = CharGetDatum(alignment); /* typalign */
values[i++] = CharGetDatum(storage); /* typstorage */
@@ -341,6 +349,8 @@ TypeCreate(const char *typeName,
outputProcedure,
receiveProcedure,
sendProcedure,
typmodinProcedure,
typmodoutProcedure,
analyzeProcedure,
elementType,
baseType,
@@ -374,6 +384,8 @@ GenerateTypeDependencies(Oid typeNamespace,
Oid outputProcedure,
Oid receiveProcedure,
Oid sendProcedure,
Oid typmodinProcedure,
Oid typmodoutProcedure,
Oid analyzeProcedure,
Oid elementType,
Oid baseType,
@@ -436,6 +448,22 @@ GenerateTypeDependencies(Oid typeNamespace,
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(typmodinProcedure))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = typmodinProcedure;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(typmodoutProcedure))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = typmodoutProcedure;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(analyzeProcedure))
{
referenced.classId = ProcedureRelationId;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.207 2006/12/23 00:43:09 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.208 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -889,6 +889,9 @@ MergeAttributes(List *schema, List *supers, bool istemp,
exist_attno = findAttrByName(attributeName, inhSchema);
if (exist_attno > 0)
{
Oid defTypeId;
int32 deftypmod;
/*
* Yes, try to merge the two column definitions. They must
* have the same type and typmod.
@@ -897,8 +900,10 @@ MergeAttributes(List *schema, List *supers, bool istemp,
(errmsg("merging multiple inherited definitions of column \"%s\"",
attributeName)));
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
if (typenameTypeId(NULL, def->typename) != attribute->atttypid ||
def->typename->typmod != attribute->atttypmod)
defTypeId = typenameTypeId(NULL, def->typename);
deftypmod = typenameTypeMod(NULL, def->typename, defTypeId);
if (defTypeId != attribute->atttypid ||
deftypmod != attribute->atttypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("inherited column \"%s\" has a type conflict",
@@ -1029,6 +1034,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
if (exist_attno > 0)
{
ColumnDef *def;
Oid defTypeId, newTypeId;
int32 deftypmod, newtypmod;
/*
* Yes, try to merge the two column definitions. They must
@@ -1038,8 +1045,11 @@ MergeAttributes(List *schema, List *supers, bool istemp,
(errmsg("merging column \"%s\" with inherited definition",
attributeName)));
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
if (typenameTypeId(NULL, def->typename) != typenameTypeId(NULL, newdef->typename) ||
def->typename->typmod != newdef->typename->typmod)
defTypeId = typenameTypeId(NULL, def->typename);
deftypmod = typenameTypeMod(NULL, def->typename, defTypeId);
newTypeId = typenameTypeId(NULL, newdef->typename);
newtypmod = typenameTypeMod(NULL, newdef->typename, newTypeId);
if (defTypeId != newTypeId || deftypmod != newtypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" has a type conflict",
@@ -3092,6 +3102,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
maxatts;
HeapTuple typeTuple;
Oid typeOid;
int32 typmod;
Form_pg_type tform;
Expr *defval;
@@ -3110,10 +3121,14 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
if (HeapTupleIsValid(tuple))
{
Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
Oid ctypeId;
int32 ctypmod;
/* Okay if child matches by type */
if (typenameTypeId(NULL, colDef->typename) != childatt->atttypid ||
colDef->typename->typmod != childatt->atttypmod)
ctypeId = typenameTypeId(NULL, colDef->typename);
ctypmod = typenameTypeMod(NULL, colDef->typename, ctypeId);
if (ctypeId != childatt->atttypid ||
ctypmod != childatt->atttypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("child table \"%s\" has different type for column \"%s\"",
@@ -3169,6 +3184,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
typeTuple = typenameType(NULL, colDef->typename);
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);
@@ -3186,7 +3202,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
attribute->attstattarget = -1;
attribute->attlen = tform->typlen;
attribute->attcacheoff = -1;
attribute->atttypmod = colDef->typename->typmod;
attribute->atttypmod = typmod;
attribute->attnum = i;
attribute->attbyval = tform->typbyval;
attribute->attndims = list_length(colDef->typename->arrayBounds);
@@ -3278,7 +3294,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
(Node *) defval,
basetype,
typeOid,
colDef->typename->typmod,
typmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (defval == NULL) /* should not happen */
@@ -4877,6 +4893,7 @@ ATPrepAlterColumnType(List **wqueue,
Form_pg_attribute attTup;
AttrNumber attnum;
Oid targettype;
int32 targettypmod;
Node *transform;
NewColumnValue *newval;
ParseState *pstate = make_parsestate(NULL);
@@ -4907,6 +4924,7 @@ ATPrepAlterColumnType(List **wqueue,
/* Look up the target type */
targettype = typenameTypeId(NULL, typename);
targettypmod = typenameTypeMod(NULL, typename, targettype);
/* make sure datatype is legal for a column */
CheckAttributeType(colName, targettype);
@@ -4958,7 +4976,7 @@ ATPrepAlterColumnType(List **wqueue,
transform = coerce_to_target_type(pstate,
transform, exprType(transform),
targettype, typename->typmod,
targettype, targettypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (transform == NULL)
@@ -5004,6 +5022,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
HeapTuple typeTuple;
Form_pg_type tform;
Oid targettype;
int32 targettypmod;
Node *defaultexpr;
Relation attrelation;
Relation depRel;
@@ -5035,6 +5054,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
typeTuple = typenameType(NULL, typename);
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
@@ -5055,7 +5075,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
defaultexpr = strip_implicit_coercions(defaultexpr);
defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
defaultexpr, exprType(defaultexpr),
targettype, typename->typmod,
targettype, targettypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (defaultexpr == NULL)
@@ -5272,7 +5292,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
* copy of the syscache entry, so okay to scribble on.)
*/
attTup->atttypid = targettype;
attTup->atttypmod = typename->typmod;
attTup->atttypmod = targettypmod;
attTup->attndims = list_length(typename->arrayBounds);
attTup->attlen = tform->typlen;
attTup->attbyval = tform->typbyval;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.97 2006/10/04 00:29:51 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.98 2006/12/30 21:21:53 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -75,6 +75,8 @@ static Oid findTypeInputFunction(List *procname, Oid typeOid);
static Oid findTypeOutputFunction(List *procname, Oid typeOid);
static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
static Oid findTypeSendFunction(List *procname, Oid typeOid);
static Oid findTypeTypmodinFunction(List *procname);
static Oid findTypeTypmodoutFunction(List *procname);
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
static void checkDomainOwner(HeapTuple tup, TypeName *typename);
@@ -100,6 +102,8 @@ DefineType(List *names, List *parameters)
List *outputName = NIL;
List *receiveName = NIL;
List *sendName = NIL;
List *typmodinName = NIL;
List *typmodoutName = NIL;
List *analyzeName = NIL;
char *defaultValue = NULL;
bool byValue = false;
@@ -110,6 +114,8 @@ DefineType(List *names, List *parameters)
Oid outputOid;
Oid receiveOid = InvalidOid;
Oid sendOid = InvalidOid;
Oid typmodinOid = InvalidOid;
Oid typmodoutOid = InvalidOid;
Oid analyzeOid = InvalidOid;
char *shadow_type;
ListCell *pl;
@@ -182,6 +188,10 @@ DefineType(List *names, List *parameters)
receiveName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "send") == 0)
sendName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
typmodinName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
typmodoutName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
pg_strcasecmp(defel->defname, "analyse") == 0)
analyzeName = defGetQualifiedName(defel);
@@ -268,6 +278,11 @@ DefineType(List *names, List *parameters)
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("type output function must be specified")));
if (typmodinName == NIL && typmodoutName != NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("type modifier output function is useless without a type modifier input function")));
/*
* Convert I/O proc names to OIDs
*/
@@ -335,6 +350,14 @@ DefineType(List *names, List *parameters)
NameListToString(sendName))));
}
/*
* Convert typmodin/out function proc names to OIDs.
*/
if (typmodinName)
typmodinOid = findTypeTypmodinFunction(typmodinName);
if (typmodoutName)
typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
/*
* Convert analysis function proc name to an OID. If no analysis function
* is specified, we'll use zero to select the built-in default algorithm.
@@ -362,6 +385,12 @@ DefineType(List *names, List *parameters)
if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(sendName));
if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(typmodinName));
if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(typmodoutName));
if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(analyzeName));
@@ -381,6 +410,8 @@ DefineType(List *names, List *parameters)
outputOid, /* output procedure */
receiveOid, /* receive procedure */
sendOid, /* send procedure */
typmodinOid, /* typmodin procedure */
typmodoutOid,/* typmodout procedure */
analyzeOid, /* analyze procedure */
elemType, /* element type ID */
InvalidOid, /* base type ID (only for domains) */
@@ -413,6 +444,8 @@ DefineType(List *names, List *parameters)
F_ARRAY_OUT, /* output procedure */
F_ARRAY_RECV, /* receive procedure */
F_ARRAY_SEND, /* send procedure */
typmodinOid, /* typmodin procedure */
typmodoutOid, /* typmodout procedure */
InvalidOid, /* analyze procedure - default */
typoid, /* element type ID */
InvalidOid, /* base type ID */
@@ -552,6 +585,7 @@ DefineDomain(CreateDomainStmt *stmt)
Oid basetypeoid;
Oid domainoid;
Form_pg_type baseType;
int32 basetypeMod;
/* Convert list of names to a name and namespace */
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
@@ -581,9 +615,9 @@ DefineDomain(CreateDomainStmt *stmt)
* Look up the base type.
*/
typeTup = typenameType(NULL, stmt->typename);
baseType = (Form_pg_type) GETSTRUCT(typeTup);
basetypeoid = HeapTupleGetOid(typeTup);
basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
/*
* Base type must be a plain base type or another domain. Domains over
@@ -621,6 +655,8 @@ DefineDomain(CreateDomainStmt *stmt)
receiveProcedure = F_DOMAIN_RECV;
sendProcedure = baseType->typsend;
/* Domains never accept typmods, so no typmodin/typmodout needed */
/* Analysis function */
analyzeProcedure = baseType->typanalyze;
@@ -681,7 +717,7 @@ DefineDomain(CreateDomainStmt *stmt)
*/
defaultExpr = cookDefault(pstate, constr->raw_expr,
basetypeoid,
stmt->typename->typmod,
basetypeMod,
domainName);
/*
@@ -768,6 +804,8 @@ DefineDomain(CreateDomainStmt *stmt)
outputProcedure, /* output procedure */
receiveProcedure, /* receive procedure */
sendProcedure, /* send procedure */
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
analyzeProcedure, /* analyze procedure */
typelem, /* element type ID */
basetypeoid, /* base type ID */
@@ -776,7 +814,7 @@ DefineDomain(CreateDomainStmt *stmt)
byValue, /* passed by value */
alignment, /* required alignment */
storage, /* TOAST strategy */
stmt->typename->typmod, /* typeMod value */
basetypeMod, /* typeMod value */
typNDims, /* Array dimensions for base type */
typNotNull); /* Type NOT NULL */
@@ -793,7 +831,7 @@ DefineDomain(CreateDomainStmt *stmt)
{
case CONSTR_CHECK:
domainAddConstraint(domainoid, domainNamespace,
basetypeoid, stmt->typename->typmod,
basetypeoid, basetypeMod,
constr, domainName);
break;
@@ -1067,6 +1105,60 @@ findTypeSendFunction(List *procname, Oid typeOid)
return InvalidOid; /* keep compiler quiet */
}
static Oid
findTypeTypmodinFunction(List *procname)
{
Oid argList[1];
Oid procOid;
/*
* typmodin functions always take one int4[] argument and return int4.
*/
argList[0] = INT4ARRAYOID;
procOid = LookupFuncName(procname, 1, argList, true);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist",
func_signature_string(procname, 1, argList))));
if (get_func_rettype(procOid) != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("typmod_in function %s must return type \"integer\"",
NameListToString(procname))));
return procOid;
}
static Oid
findTypeTypmodoutFunction(List *procname)
{
Oid argList[1];
Oid procOid;
/*
* typmodout functions always take one int4 argument and return cstring.
*/
argList[0] = INT4OID;
procOid = LookupFuncName(procname, 1, argList, true);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist",
func_signature_string(procname, 1, argList))));
if (get_func_rettype(procOid) != CSTRINGOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("typmod_out function %s must return type \"cstring\"",
NameListToString(procname))));
return procOid;
}
static Oid
findTypeAnalyzeFunction(List *procname, Oid typeOid)
{
@@ -1244,6 +1336,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
typTup->typoutput,
typTup->typreceive,
typTup->typsend,
typTup->typmodin,
typTup->typmodout,
typTup->typanalyze,
typTup->typelem,
typTup->typbasetype,

View File

@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.357 2006/12/24 00:29:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.358 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1584,7 +1584,8 @@ _copyTypeName(TypeName *from)
COPY_SCALAR_FIELD(timezone);
COPY_SCALAR_FIELD(setof);
COPY_SCALAR_FIELD(pct_type);
COPY_SCALAR_FIELD(typmod);
COPY_NODE_FIELD(typmods);
COPY_SCALAR_FIELD(typemod);
COPY_NODE_FIELD(arrayBounds);
COPY_SCALAR_FIELD(location);

View File

@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.291 2006/12/24 00:29:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.292 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1614,7 +1614,8 @@ _equalTypeName(TypeName *a, TypeName *b)
COMPARE_SCALAR_FIELD(timezone);
COMPARE_SCALAR_FIELD(setof);
COMPARE_SCALAR_FIELD(pct_type);
COMPARE_SCALAR_FIELD(typmod);
COMPARE_NODE_FIELD(typmods);
COMPARE_SCALAR_FIELD(typemod);
COMPARE_NODE_FIELD(arrayBounds);
COMPARE_SCALAR_FIELD(location);

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.52 2006/10/04 00:29:53 momjian Exp $
* $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.53 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -262,12 +262,7 @@ makeRangeVar(char *schemaname, char *relname)
TypeName *
makeTypeName(char *typnam)
{
TypeName *n = makeNode(TypeName);
n->names = list_make1(makeString(typnam));
n->typmod = -1;
n->location = -1;
return n;
return makeTypeNameFromNameList(list_make1(makeString(typnam)));
}
/*
@@ -282,14 +277,15 @@ makeTypeNameFromNameList(List *names)
TypeName *n = makeNode(TypeName);
n->names = names;
n->typmod = -1;
n->typmods = NIL;
n->typemod = -1;
n->location = -1;
return n;
}
/*
* makeTypeNameFromOid -
* build a TypeName node to represent a type already known by OID.
* build a TypeName node to represent a type already known by OID/typmod.
*/
TypeName *
makeTypeNameFromOid(Oid typeid, int32 typmod)
@@ -297,7 +293,7 @@ makeTypeNameFromOid(Oid typeid, int32 typmod)
TypeName *n = makeNode(TypeName);
n->typeid = typeid;
n->typmod = typmod;
n->typemod = typmod;
n->location = -1;
return n;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.289 2006/12/24 00:29:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.290 2006/12/30 21:21:53 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1476,7 +1476,8 @@ _outTypeName(StringInfo str, TypeName *node)
WRITE_BOOL_FIELD(timezone);
WRITE_BOOL_FIELD(setof);
WRITE_BOOL_FIELD(pct_type);
WRITE_INT_FIELD(typmod);
WRITE_NODE_FIELD(typmods);
WRITE_INT_FIELD(typemod);
WRITE_NODE_FIELD(arrayBounds);
WRITE_INT_FIELD(location);
}

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.570 2006/12/24 00:29:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.571 2006/12/30 21:21:53 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -206,7 +206,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <str> relation_name copy_file_name
database_name access_method_clause access_method attr_name
index_name name function_name file_name
index_name name file_name
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
opt_class opt_validator
@@ -242,7 +242,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list
transaction_mode_list_or_empty
TableFuncElementList
TableFuncElementList opt_type_modifiers
prep_type_clause prep_type_list
execute_param_clause using_clause returning_clause
@@ -319,20 +319,19 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <str> character
%type <str> extract_arg
%type <str> opt_charset
%type <ival> opt_numeric opt_decimal
%type <boolean> opt_varying opt_timezone
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text
%type <str> RoleId opt_granted_by opt_boolean ColId_or_Sconst
%type <list> var_list var_list_or_default
%type <str> ColId ColLabel var_name type_name param_name
%type <str> ColId ColLabel var_name type_function_name param_name
%type <node> var_value zone_value
%type <keyword> unreserved_keyword func_name_keyword
%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword
%type <node> TableConstraint TableLikeClause
%type <node> TableConstraint TableLikeClause
%type <list> TableLikeOptionList
%type <ival> TableLikeOption
%type <list> ColQualList
@@ -1180,35 +1179,20 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
n->typename->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $3);
n->typename->typmods = list_make1(makeIntConst($3));
}
$$ = (Node *)n;
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
A_Const *n = (A_Const *) makeStringConst($5, $1);
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision must not be negative",
$3)));
if ($3 > MAX_INTERVAL_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
$3, MAX_INTERVAL_PRECISION)));
$3 = MAX_INTERVAL_PRECISION;
}
if (($6 != INTERVAL_FULL_RANGE)
&& (($6 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
n->typename->typmod = INTERVAL_TYPMOD($3, $6);
n->typename->typmods = list_make2(makeIntConst($6),
makeIntConst($3));
$$ = (Node *)n;
}
| NumericOnly { $$ = makeAConst($1); }
@@ -2823,7 +2807,7 @@ DefineStmt:
n->definition = $4;
$$ = (Node *)n;
}
| CREATE TYPE_P any_name
| CREATE TYPE_P any_name
{
/* Shell type (identified by lack of definition) */
DefineStmt *n = makeNode(DefineStmt);
@@ -2889,7 +2873,6 @@ def_elem: ColLabel '=' def_arg
/* Note: any simple identifier will be returned as a type name! */
def_arg: func_type { $$ = (Node *)$1; }
| func_name_keyword { $$ = (Node *)makeString(pstrdup($1)); }
| reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); }
| qual_all_Op { $$ = (Node *)$1; }
| NumericOnly { $$ = (Node *)$1; }
@@ -3047,7 +3030,7 @@ ReassignOwnedStmt:
*
* QUERY:
*
* DROP itemtype [ IF EXISTS ] itemname [, itemname ...]
* DROP itemtype [ IF EXISTS ] itemname [, itemname ...]
* [ RESTRICT | CASCADE ]
*
*****************************************************************************/
@@ -3872,7 +3855,7 @@ arg_class: IN_P { $$ = FUNC_PARAM_IN; }
/*
* Ideally param_name should be ColId, but that causes too many conflicts.
*/
param_name: function_name
param_name: type_function_name
;
func_return:
@@ -3888,23 +3871,20 @@ func_return:
/*
* We would like to make the %TYPE productions here be ColId attrs etc,
* but that causes reduce/reduce conflicts. type_name is next best choice.
* but that causes reduce/reduce conflicts. type_function_name
* is next best choice.
*/
func_type: Typename { $$ = $1; }
| type_name attrs '%' TYPE_P
| type_function_name attrs '%' TYPE_P
{
$$ = makeNode(TypeName);
$$->names = lcons(makeString($1), $2);
$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
$$->pct_type = true;
$$->typmod = -1;
$$->location = @1;
}
| SETOF type_name attrs '%' TYPE_P
| SETOF type_function_name attrs '%' TYPE_P
{
$$ = makeNode(TypeName);
$$->names = lcons(makeString($2), $3);
$$ = makeTypeNameFromNameList(lcons(makeString($2), $3));
$$->pct_type = true;
$$->typmod = -1;
$$->setof = TRUE;
$$->location = @2;
}
@@ -5552,7 +5532,7 @@ multiple_set_clause:
res_col->val = res_val;
}
$$ = $2;
}
;
@@ -6363,14 +6343,6 @@ opt_array_bounds:
{ $$ = NIL; }
;
/*
* XXX ideally, the production for a qualified typename should be ColId attrs
* (there's no obvious reason why the first name should need to be restricted)
* and should be an alternative of GenericType (so that it can be used to
* specify a type for a literal in AExprConst). However doing either causes
* reduce/reduce conflicts that I haven't been able to find a workaround
* for. FIXME later.
*/
SimpleTypename:
GenericType { $$ = $1; }
| Numeric { $$ = $1; }
@@ -6381,32 +6353,13 @@ SimpleTypename:
{
$$ = $1;
if ($2 != INTERVAL_FULL_RANGE)
$$->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $2);
$$->typmods = list_make1(makeIntConst($2));
}
| ConstInterval '(' Iconst ')' opt_interval
{
$$ = $1;
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision must not be negative",
$3)));
if ($3 > MAX_INTERVAL_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
$3, MAX_INTERVAL_PRECISION)));
$3 = MAX_INTERVAL_PRECISION;
}
$$->typmod = INTERVAL_TYPMOD($3, $5);
}
| type_name attrs
{
$$ = makeNode(TypeName);
$$->names = lcons(makeString($1), $2);
$$->typmod = -1;
$$->location = @1;
$$->typmods = list_make2(makeIntConst($5),
makeIntConst($3));
}
;
@@ -6417,80 +6370,112 @@ SimpleTypename:
* where there is an obvious better choice to make.
* Note that ConstInterval is not included here since it must
* be pushed up higher in the rules to accomodate the postfix
* options (e.g. INTERVAL '1' YEAR).
* options (e.g. INTERVAL '1' YEAR). Likewise, we have to handle
* the generic-type-name case in AExprConst to avoid premature
* reduce/reduce conflicts against function names.
*/
ConstTypename:
GenericType { $$ = $1; }
| Numeric { $$ = $1; }
Numeric { $$ = $1; }
| ConstBit { $$ = $1; }
| ConstCharacter { $$ = $1; }
| ConstDatetime { $$ = $1; }
;
/*
* GenericType covers all type names that don't have special syntax mandated
* by the standard, including qualified names. We also allow type modifiers.
* To avoid parsing conflicts against function invocations, the modifiers
* have to be shown as expr_list here, but parse analysis will only accept
* integer constants for them.
*/
GenericType:
type_name
type_function_name opt_type_modifiers
{
$$ = makeTypeName($1);
$$->typmods = $2;
$$->location = @1;
}
| type_function_name attrs opt_type_modifiers
{
$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
$$->typmods = $3;
$$->location = @1;
}
;
/* SQL92 numeric data types
* Check FLOAT() precision limits assuming IEEE floating types.
* - thomas 1997-09-18
* Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30
opt_type_modifiers: '(' expr_list ')' { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }
;
/*
* SQL92 numeric data types
*/
Numeric: INT_P
{
$$ = SystemTypeName("int4");
$$->location = @1;
}
| INTEGER
{
$$ = SystemTypeName("int4");
$$->location = @1;
}
| SMALLINT
{
$$ = SystemTypeName("int2");
$$->location = @1;
}
| BIGINT
{
$$ = SystemTypeName("int8");
$$->location = @1;
}
| REAL
{
$$ = SystemTypeName("float4");
$$->location = @1;
}
| FLOAT_P opt_float
{
$$ = $2;
$$->location = @1;
}
| DOUBLE_P PRECISION
{
$$ = SystemTypeName("float8");
$$->location = @1;
}
| DECIMAL_P opt_decimal
| DECIMAL_P opt_type_modifiers
{
$$ = SystemTypeName("numeric");
$$->typmod = $2;
$$->typmods = $2;
$$->location = @1;
}
| DEC opt_decimal
| DEC opt_type_modifiers
{
$$ = SystemTypeName("numeric");
$$->typmod = $2;
$$->typmods = $2;
$$->location = @1;
}
| NUMERIC opt_numeric
| NUMERIC opt_type_modifiers
{
$$ = SystemTypeName("numeric");
$$->typmod = $2;
$$->typmods = $2;
$$->location = @1;
}
| BOOLEAN_P
{
$$ = SystemTypeName("bool");
$$->location = @1;
}
;
opt_float: '(' Iconst ')'
{
/*
* Check FLOAT() precision limits assuming IEEE floating
* types - thomas 1997-09-18
*/
if ($2 < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -6510,73 +6495,6 @@ opt_float: '(' Iconst ')'
}
;
opt_numeric:
'(' Iconst ',' Iconst ')'
{
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC precision %d must be between 1 and %d",
$2, NUMERIC_MAX_PRECISION)));
if ($4 < 0 || $4 > $2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC scale %d must be between 0 and precision %d",
$4, $2)));
$$ = (($2 << 16) | $4) + VARHDRSZ;
}
| '(' Iconst ')'
{
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC precision %d must be between 1 and %d",
$2, NUMERIC_MAX_PRECISION)));
$$ = ($2 << 16) + VARHDRSZ;
}
| /*EMPTY*/
{
/* Insert "-1" meaning "no limit" */
$$ = -1;
}
;
opt_decimal:
'(' Iconst ',' Iconst ')'
{
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("DECIMAL precision %d must be between 1 and %d",
$2, NUMERIC_MAX_PRECISION)));
if ($4 < 0 || $4 > $2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("DECIMAL scale %d must be between 0 and precision %d",
$4, $2)));
$$ = (($2 << 16) | $4) + VARHDRSZ;
}
| '(' Iconst ')'
{
if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("DECIMAL precision %d must be between 1 and %d",
$2, NUMERIC_MAX_PRECISION)));
$$ = ($2 << 16) + VARHDRSZ;
}
| /*EMPTY*/
{
/* Insert "-1" meaning "no limit" */
$$ = -1;
}
;
/*
* SQL92 bit-field data types
* The following implements BIT() and BIT VARYING().
@@ -6600,28 +6518,19 @@ ConstBit: BitWithLength
| BitWithoutLength
{
$$ = $1;
$$->typmod = -1;
$$->typmods = NIL;
}
;
BitWithLength:
BIT opt_varying '(' Iconst ')'
BIT opt_varying '(' expr_list ')'
{
char *typname;
typname = $2 ? "varbit" : "bit";
$$ = SystemTypeName(typname);
if ($4 < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s must be at least 1",
typname)));
else if ($4 > (MaxAttrSize * BITS_PER_BYTE))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s cannot exceed %d",
typname, MaxAttrSize * BITS_PER_BYTE)));
$$->typmod = $4;
$$->typmods = $4;
$$->location = @1;
}
;
@@ -6632,13 +6541,13 @@ BitWithoutLength:
if ($2)
{
$$ = SystemTypeName("varbit");
$$->typmod = -1;
}
else
{
$$ = SystemTypeName("bit");
$$->typmod = 1;
$$->typmods = list_make1(makeIntConst(1));
}
$$->location = @1;
}
;
@@ -6670,7 +6579,7 @@ ConstCharacter: CharacterWithLength
* was not specified.
*/
$$ = $1;
$$->typmod = -1;
$$->typmods = NIL;
}
;
@@ -6688,24 +6597,8 @@ CharacterWithLength: character '(' Iconst ')' opt_charset
}
$$ = SystemTypeName($1);
if ($3 < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s must be at least 1",
$1)));
else if ($3 > MaxAttrSize)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s cannot exceed %d",
$1, MaxAttrSize)));
/* we actually implement these like a varlen, so
* the first 4 bytes is the length. (the difference
* between these and "text" is that we blank-pad and
* truncate where necessary)
*/
$$->typmod = VARHDRSZ + $3;
$$->typmods = list_make1(makeIntConst($3));
$$->location = @1;
}
;
@@ -6726,9 +6619,9 @@ CharacterWithoutLength: character opt_charset
/* char defaults to char(1), varchar to no limit */
if (strcmp($1, "bpchar") == 0)
$$->typmod = VARHDRSZ + 1;
else
$$->typmod = -1;
$$->typmods = list_make1(makeIntConst(1));
$$->location = @1;
}
;
@@ -6756,6 +6649,9 @@ opt_charset:
| /*EMPTY*/ { $$ = NULL; }
;
/*
* SQL92 date/time types
*/
ConstDatetime:
TIMESTAMP '(' Iconst ')' opt_timezone
{
@@ -6767,21 +6663,8 @@ ConstDatetime:
* - thomas 2001-09-06
*/
$$->timezone = $5;
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIMESTAMP(%d)%s precision must not be negative",
$3, ($5 ? " WITH TIME ZONE": ""))));
if ($3 > MAX_TIMESTAMP_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
$3, ($5 ? " WITH TIME ZONE": ""),
MAX_TIMESTAMP_PRECISION)));
$3 = MAX_TIMESTAMP_PRECISION;
}
$$->typmod = $3;
$$->typmods = list_make1(makeIntConst($3));
$$->location = @1;
}
| TIMESTAMP opt_timezone
{
@@ -6793,6 +6676,7 @@ ConstDatetime:
* - thomas 2001-09-06
*/
$$->timezone = $2;
$$->location = @1;
}
| TIME '(' Iconst ')' opt_timezone
{
@@ -6800,21 +6684,8 @@ ConstDatetime:
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIME(%d)%s precision must not be negative",
$3, ($5 ? " WITH TIME ZONE": ""))));
if ($3 > MAX_TIME_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
$3, ($5 ? " WITH TIME ZONE": ""),
MAX_TIME_PRECISION)));
$3 = MAX_TIME_PRECISION;
}
$$->typmod = $3;
$$->typmods = list_make1(makeIntConst($3));
$$->location = @1;
}
| TIME opt_timezone
{
@@ -6822,11 +6693,16 @@ ConstDatetime:
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
$$->location = @1;
}
;
ConstInterval:
INTERVAL { $$ = SystemTypeName("interval"); }
INTERVAL
{
$$ = SystemTypeName("interval");
$$->location = @1;
}
;
opt_timezone:
@@ -7520,20 +7396,7 @@ func_expr: func_name '(' ')'
s->val.val.str = "now";
s->typename = SystemTypeName("text");
d = SystemTypeName("timetz");
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("CURRENT_TIME(%d) precision must not be negative",
$3)));
if ($3 > MAX_TIME_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("CURRENT_TIME(%d) precision reduced to maximum allowed, %d",
$3, MAX_TIME_PRECISION)));
$3 = MAX_TIME_PRECISION;
}
d->typmod = $3;
d->typmods = list_make1(makeIntConst($3));
$$ = (Node *)makeTypeCast((Node *)s, d);
}
@@ -7565,20 +7428,7 @@ func_expr: func_name '(' ')'
s->typename = SystemTypeName("text");
d = SystemTypeName("timestamptz");
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("CURRENT_TIMESTAMP(%d) precision must not be negative",
$3)));
if ($3 > MAX_TIMESTAMP_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("CURRENT_TIMESTAMP(%d) precision reduced to maximum allowed, %d",
$3, MAX_TIMESTAMP_PRECISION)));
$3 = MAX_TIMESTAMP_PRECISION;
}
d->typmod = $3;
d->typmods = list_make1(makeIntConst($3));
$$ = (Node *)makeTypeCast((Node *)s, d);
}
@@ -7612,20 +7462,7 @@ func_expr: func_name '(' ')'
s->val.val.str = "now";
s->typename = SystemTypeName("text");
d = SystemTypeName("time");
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALTIME(%d) precision must not be negative",
$3)));
if ($3 > MAX_TIME_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALTIME(%d) precision reduced to maximum allowed, %d",
$3, MAX_TIME_PRECISION)));
$3 = MAX_TIME_PRECISION;
}
d->typmod = $3;
d->typmods = list_make1(makeIntConst($3));
$$ = (Node *)makeTypeCast((Node *)s, d);
}
@@ -7660,20 +7497,7 @@ func_expr: func_name '(' ')'
s->typename = SystemTypeName("text");
d = SystemTypeName("timestamp");
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALTIMESTAMP(%d) precision must not be negative",
$3)));
if ($3 > MAX_TIMESTAMP_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("LOCALTIMESTAMP(%d) precision reduced to maximum allowed, %d",
$3, MAX_TIMESTAMP_PRECISION)));
$3 = MAX_TIMESTAMP_PRECISION;
}
d->typmod = $3;
d->typmods = list_make1(makeIntConst($3));
$$ = (Node *)makeTypeCast((Node *)s, d);
}
@@ -7880,7 +7704,7 @@ func_expr: func_name '(' ')'
$$ = (Node *)v;
}
| XMLCONCAT '(' expr_list ')'
{
{
$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3);
}
| XMLELEMENT '(' NAME_P ColLabel ')'
@@ -7985,7 +7809,7 @@ xml_attribute_el: a_expr AS ColLabel
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = NULL;
$$->val = (Node *) $1;
$$->val = (Node *) $1;
$$->location = @1;
}
;
@@ -8486,12 +8310,12 @@ file_name: Sconst { $$ = $1; };
/*
* The production for a qualified func_name has to exactly match the
* production for a qualified columnref, because we cannot tell which we
* are parsing until we see what comes after it ('(' for a func_name,
* are parsing until we see what comes after it ('(' or Sconst for a func_name,
* anything else for a columnref). Therefore we allow 'indirection' which
* may contain subscripts, and reject that case in the C code. (If we
* ever implement SQL99-like methods, such syntax may actually become legal!)
*/
func_name: function_name
func_name: type_function_name
{ $$ = list_make1(makeString($1)); }
| relation_name indirection
{ $$ = check_func_name(lcons(makeString($1), $2)); }
@@ -8541,6 +8365,27 @@ AexprConst: Iconst
n->val.val.str = $1;
$$ = (Node *)n;
}
| func_name Sconst
{
/* generic type 'literal' syntax */
A_Const *n = makeNode(A_Const);
n->typename = makeTypeNameFromNameList($1);
n->typename->location = @1;
n->val.type = T_String;
n->val.val.str = $2;
$$ = (Node *)n;
}
| func_name '(' expr_list ')' Sconst
{
/* generic syntax with a type modifier */
A_Const *n = makeNode(A_Const);
n->typename = makeTypeNameFromNameList($1);
n->typename->typmods = $3;
n->typename->location = @1;
n->val.type = T_String;
n->val.val.str = $5;
$$ = (Node *)n;
}
| ConstTypename Sconst
{
A_Const *n = makeNode(A_Const);
@@ -8557,7 +8402,7 @@ AexprConst: Iconst
n->val.val.str = $2;
/* precision is not specified, but fields may be... */
if ($3 != INTERVAL_FULL_RANGE)
n->typename->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $3);
n->typename->typmods = list_make1(makeIntConst($3));
$$ = (Node *)n;
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
@@ -8566,21 +8411,8 @@ AexprConst: Iconst
n->typename = $1;
n->val.type = T_String;
n->val.val.str = $5;
/* precision specified, and fields may be... */
if ($3 < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision must not be negative",
$3)));
if ($3 > MAX_INTERVAL_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
$3, MAX_INTERVAL_PRECISION)));
$3 = MAX_INTERVAL_PRECISION;
}
n->typename->typmod = INTERVAL_TYPMOD($3, $6);
n->typename->typmods = list_make2(makeIntConst($6),
makeIntConst($3));
$$ = (Node *)n;
}
| TRUE_P
@@ -8625,18 +8457,11 @@ ColId: IDENT { $$ = $1; }
| col_name_keyword { $$ = pstrdup($1); }
;
/* Type identifier --- names that can be type names.
/* Type/function identifier --- names that can be type or function names.
*/
type_name: IDENT { $$ = $1; }
type_function_name: IDENT { $$ = $1; }
| unreserved_keyword { $$ = pstrdup($1); }
;
/* Function identifier --- names that can be function names.
*/
function_name:
IDENT { $$ = $1; }
| unreserved_keyword { $$ = pstrdup($1); }
| func_name_keyword { $$ = pstrdup($1); }
| type_func_name_keyword { $$ = pstrdup($1); }
;
/* Column label --- allowed labels in "AS" clauses.
@@ -8645,7 +8470,7 @@ function_name:
ColLabel: IDENT { $$ = $1; }
| unreserved_keyword { $$ = pstrdup($1); }
| col_name_keyword { $$ = pstrdup($1); }
| func_name_keyword { $$ = pstrdup($1); }
| type_func_name_keyword { $$ = pstrdup($1); }
| reserved_keyword { $$ = pstrdup($1); }
;
@@ -8940,7 +8765,7 @@ col_name_keyword:
| XMLSERIALIZE
;
/* Function identifier --- keywords that can be function names.
/* Type/function identifier --- keywords that can be type or function names.
*
* Most of these are keywords that are used as operators in expressions;
* in general such keywords can't be column names because they would be
@@ -8950,7 +8775,7 @@ col_name_keyword:
* productions in a_expr to support the goofy SQL9x argument syntax.
* - thomas 2000-11-28
*/
func_name_keyword:
type_func_name_keyword:
AUTHORIZATION
| BETWEEN
| BINARY
@@ -9383,12 +9208,8 @@ SystemFuncName(char *name)
TypeName *
SystemTypeName(char *name)
{
TypeName *n = makeNode(TypeName);
n->names = list_make2(makeString("pg_catalog"), makeString(name));
n->typmod = -1;
n->location = -1;
return n;
return makeTypeNameFromNameList(list_make2(makeString("pg_catalog"),
makeString(name)));
}
/* parser_init()

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.202 2006/12/24 00:29:19 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.203 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1810,29 +1810,6 @@ exprTypmod(Node *expr)
{
case T_Var:
return ((Var *) expr)->vartypmod;
case T_Const:
{
/* Be smart about string constants... */
Const *con = (Const *) expr;
switch (con->consttype)
{
case BPCHAROID:
if (!con->constisnull)
{
int32 len = VARSIZE(DatumGetPointer(con->constvalue)) - VARHDRSZ;
/* if multi-byte, take len and find # characters */
if (pg_database_encoding_max_length() > 1)
len = pg_mbstrlen_with_len(VARDATA(DatumGetPointer(con->constvalue)), len);
return len + VARHDRSZ;
}
break;
default:
break;
}
}
break;
case T_Param:
return ((Param *) expr)->paramtypmod;
case T_FuncExpr:
@@ -2024,14 +2001,16 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
{
Oid inputType = exprType(expr);
Oid targetType;
int32 targetTypmod;
targetType = typenameTypeId(pstate, typename);
targetTypmod = typenameTypeMod(pstate, typename, targetType);
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
expr = coerce_to_target_type(pstate, expr, inputType,
targetType, typename->typmod,
targetType, targetTypmod,
COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST);
if (expr == NULL)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.125 2006/10/04 00:29:56 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.126 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -901,9 +901,9 @@ addRangeTableEntryForFunction(ParseState *pstate,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" cannot be declared SETOF",
attrname)));
eref->colnames = lappend(eref->colnames, makeString(attrname));
attrtype = typenameTypeId(pstate, n->typename);
attrtypmod = n->typename->typmod;
attrtypmod = typenameTypeMod(pstate, n->typename, attrtype);
eref->colnames = lappend(eref->colnames, makeString(attrname));
rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
rte->funccoltypmods = lappend_int(rte->funccoltypmods, attrtypmod);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.85 2006/10/04 00:29:56 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.86 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,7 @@
#include "nodes/makefuncs.h"
#include "parser/parser.h"
#include "parser/parse_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -245,9 +246,81 @@ typenameTypeId(ParseState *pstate, const TypeName *typename)
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 an integer
* array. Currently, we only allow simple integer constants, though
* possibly this could be extended.
*/
datums = (Datum *) palloc(list_length(typename->typmods) * sizeof(Datum));
n = 0;
foreach(l, typename->typmods)
{
A_Const *ac = (A_Const *) lfirst(l);
if (!IsA(ac, A_Const) ||
!IsA(&ac->val, Integer))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("type modifiers must be integer constants"),
parser_errposition(pstate, typename->location)));
datums[n++] = Int32GetDatum(ac->val.val.ival);
}
/* hardwired knowledge about int4's representation details here */
arrtypmod = construct_array(datums, n, INT4OID,
sizeof(int4), true, 'i');
result = DatumGetInt32(OidFunctionCall1(typmodin,
PointerGetDatum(arrtypmod)));
pfree(datums);
pfree(arrtypmod);
return result;
}
/*
* typenameType - given a TypeName, return a Type structure
*
@@ -490,7 +563,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
goto fail;
*type_id = typenameTypeId(NULL, typename);
*typmod = typename->typmod;
*typmod = typenameTypeMod(NULL, typename, *type_id);
pfree(buf.data);

View File

@@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayutils.c,v 1.21 2006/03/05 15:58:41 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayutils.c,v 1.22 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_type.h"
#include "utils/array.h"
#include "utils/memutils.h"
@@ -188,3 +189,30 @@ mda_next_tuple(int n, int *curr, const int *span)
return -1;
}
/*
* ArrayGetTypmods: verify that argument is a 1-D integer array,
* return its length and a pointer to the first contained integer.
*/
int32 *
ArrayGetTypmods(ArrayType *arr, int *n)
{
if (ARR_ELEMTYPE(arr) != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("typmod array must be type integer[]")));
if (ARR_NDIM(arr) != 1)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("typmod array must be one-dimensional")));
if (ARR_HASNULL(arr))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("typmod array must not contain nulls")));
*n = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
return (int32 *) ARR_DATA_PTR(arr);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.125 2006/07/14 14:52:23 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.126 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,6 +24,7 @@
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "parser/scansup.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/nabstime.h"
@@ -43,6 +44,60 @@ static int tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
static int tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
/* common code for timetypmodin and timetztypmodin */
static int32
anytime_typmodin(bool istz, ArrayType *ta)
{
int32 typmod;
int32 *tl;
int n;
tl = ArrayGetTypmods(ta, &n);
/*
* we're not too tense about good error message here because grammar
* shouldn't allow wrong number of modifiers for TIME
*/
if (n != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid type modifier")));
if (*tl < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIME(%d)%s precision must not be negative",
*tl, (istz ? " WITH TIME ZONE" : ""))));
if (*tl > MAX_TIME_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
*tl, (istz ? " WITH TIME ZONE" : "" ),
MAX_TIME_PRECISION)));
typmod = MAX_TIME_PRECISION;
} else
typmod = *tl;
return typmod;
}
/* common code for timetypmodout and timetztypmodout */
static char *
anytime_typmodout(bool istz, int32 typmod)
{
char *res = (char *) palloc(64);
const char *tz = istz ? " with time zone" : " without time zone";
if (typmod >= 0)
snprintf(res, 64, "(%d)%s", (int) typmod, tz);
else
snprintf(res, 64, "%s", tz);
return res;
}
/*****************************************************************************
* Date ADT
*****************************************************************************/
@@ -1029,6 +1084,22 @@ time_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
timetypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anytime_typmodin(false, ta));
}
Datum
timetypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
}
/* time_scale()
* Adjust time type for specified scale factor.
@@ -1830,6 +1901,22 @@ timetz_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
timetztypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anytime_typmodin(true, ta));
}
Datum
timetztypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
}
/* timetz2tm()
* Convert TIME WITH TIME ZONE data type to POSIX time structure.

View File

@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.44 2006/07/14 14:52:24 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.45 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,6 @@
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
#include "utils/lsyscache.h"
#include "utils/numeric.h"
#include "utils/syscache.h"
@@ -31,6 +30,7 @@
static char *format_type_internal(Oid type_oid, int32 typemod,
bool typemod_given, bool allow_invalid);
static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
static char *
psnprintf(size_t len, const char *fmt,...)
/* This lets gcc check the format string for consistency. */
@@ -186,8 +186,7 @@ format_type_internal(Oid type_oid, int32 typemod,
{
case BITOID:
if (with_typemod)
buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)",
(int) typemod);
buf = printTypmod("bit", typemod, typeform->typmodout);
else if (typemod_given)
{
/*
@@ -206,8 +205,7 @@ format_type_internal(Oid type_oid, int32 typemod,
case BPCHAROID:
if (with_typemod)
buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)",
(int) (typemod - VARHDRSZ));
buf = printTypmod("character", typemod, typeform->typmodout);
else if (typemod_given)
{
/*
@@ -242,136 +240,56 @@ format_type_internal(Oid type_oid, int32 typemod,
case NUMERICOID:
if (with_typemod)
buf = psnprintf(10 + 2 * MAX_INT32_LEN + 1, "numeric(%d,%d)",
((typemod - VARHDRSZ) >> 16) & 0xffff,
(typemod - VARHDRSZ) & 0xffff);
buf = printTypmod("numeric", typemod, typeform->typmodout);
else
buf = pstrdup("numeric");
break;
case INTERVALOID:
if (with_typemod)
{
int fields = INTERVAL_RANGE(typemod);
int precision = INTERVAL_PRECISION(typemod);
const char *fieldstr;
switch (fields)
{
case INTERVAL_MASK(YEAR):
fieldstr = " year";
break;
case INTERVAL_MASK(MONTH):
fieldstr = " month";
break;
case INTERVAL_MASK(DAY):
fieldstr = " day";
break;
case INTERVAL_MASK(HOUR):
fieldstr = " hour";
break;
case INTERVAL_MASK(MINUTE):
fieldstr = " minute";
break;
case INTERVAL_MASK(SECOND):
fieldstr = " second";
break;
case INTERVAL_MASK(YEAR)
| INTERVAL_MASK(MONTH):
fieldstr = " year to month";
break;
case INTERVAL_MASK(DAY)
| INTERVAL_MASK(HOUR):
fieldstr = " day to hour";
break;
case INTERVAL_MASK(DAY)
| INTERVAL_MASK(HOUR)
| INTERVAL_MASK(MINUTE):
fieldstr = " day to minute";
break;
case INTERVAL_MASK(DAY)
| INTERVAL_MASK(HOUR)
| INTERVAL_MASK(MINUTE)
| INTERVAL_MASK(SECOND):
fieldstr = " day to second";
break;
case INTERVAL_MASK(HOUR)
| INTERVAL_MASK(MINUTE):
fieldstr = " hour to minute";
break;
case INTERVAL_MASK(HOUR)
| INTERVAL_MASK(MINUTE)
| INTERVAL_MASK(SECOND):
fieldstr = " hour to second";
break;
case INTERVAL_MASK(MINUTE)
| INTERVAL_MASK(SECOND):
fieldstr = " minute to second";
break;
case INTERVAL_FULL_RANGE:
fieldstr = "";
break;
default:
elog(ERROR, "invalid INTERVAL typmod: 0x%x", typemod);
fieldstr = "";
break;
}
if (precision != INTERVAL_FULL_PRECISION)
buf = psnprintf(100, "interval(%d)%s",
precision, fieldstr);
else
buf = psnprintf(100, "interval%s",
fieldstr);
}
buf = printTypmod("interval", typemod, typeform->typmodout);
else
buf = pstrdup("interval");
break;
case TIMEOID:
if (with_typemod)
buf = psnprintf(50, "time(%d) without time zone",
typemod);
buf = printTypmod("time", typemod, typeform->typmodout);
else
buf = pstrdup("time without time zone");
break;
case TIMETZOID:
if (with_typemod)
buf = psnprintf(50, "time(%d) with time zone",
typemod);
buf = printTypmod("time", typemod, typeform->typmodout);
else
buf = pstrdup("time with time zone");
break;
case TIMESTAMPOID:
if (with_typemod)
buf = psnprintf(50, "timestamp(%d) without time zone",
typemod);
buf = printTypmod("timestamp", typemod, typeform->typmodout);
else
buf = pstrdup("timestamp without time zone");
break;
case TIMESTAMPTZOID:
if (with_typemod)
buf = psnprintf(50, "timestamp(%d) with time zone",
typemod);
buf = printTypmod("timestamp", typemod, typeform->typmodout);
else
buf = pstrdup("timestamp with time zone");
break;
case VARBITOID:
if (with_typemod)
buf = psnprintf(13 + MAX_INT32_LEN + 1, "bit varying(%d)",
(int) typemod);
buf = printTypmod("bit varying", typemod, typeform->typmodout);
else
buf = pstrdup("bit varying");
break;
case VARCHAROID:
if (with_typemod)
buf = psnprintf(19 + MAX_INT32_LEN + 1,
"character varying(%d)",
(int) (typemod - VARHDRSZ));
buf = printTypmod("character varying", typemod, typeform->typmodout);
else
buf = pstrdup("character varying");
break;
@@ -396,6 +314,9 @@ format_type_internal(Oid type_oid, int32 typemod,
typname = NameStr(typeform->typname);
buf = quote_qualified_identifier(nspname, typname);
if (with_typemod)
buf = printTypmod(buf, typemod, typeform->typmodout);
}
if (is_array)
@@ -407,6 +328,38 @@ format_type_internal(Oid type_oid, int32 typemod,
}
/*
* Add typmod decoration to the basic type name
*/
static char *
printTypmod(const char *typname, int32 typmod, Oid typmodout)
{
char *res;
/* Shouldn't be called if typmod is -1 */
Assert(typmod >= 0);
if (typmodout == InvalidOid)
{
/* Default behavior: just print the integer typmod with parens */
res = psnprintf(strlen(typname) + MAX_INT32_LEN + 3, "%s(%d)",
typname, (int) typmod);
}
else
{
/* Use the type-specific typmodout procedure */
char *tmstr;
tmstr = DatumGetCString(OidFunctionCall1(typmodout,
Int32GetDatum(typmod)));
res = psnprintf(strlen(typname) + strlen(tmstr) + 1, "%s%s",
typname, tmstr);
}
return res;
}
/*
* type_maximum_size --- determine maximum width of a variable-width column
*
@@ -417,7 +370,9 @@ format_type_internal(Oid type_oid, int32 typemod,
*
* This may appear unrelated to format_type(), but in fact the two routines
* share knowledge of the encoding of typmod for different types, so it's
* convenient to keep them together.
* convenient to keep them together. (XXX now that most of this knowledge
* has been pushed out of format_type into the typmodout functions, it's
* interesting to wonder if it's worth trying to factor this code too...)
*/
int32
type_maximum_size(Oid type_oid, int32 typemod)

View File

@@ -14,7 +14,7 @@
* Copyright (c) 1998-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.96 2006/10/04 00:29:59 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.97 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -470,7 +470,7 @@ numeric_send(PG_FUNCTION_ARGS)
* scale of the attribute have to be applied on the value.
*/
Datum
numeric (PG_FUNCTION_ARGS)
numeric(PG_FUNCTION_ARGS)
{
Numeric num = PG_GETARG_NUMERIC(0);
int32 typmod = PG_GETARG_INT32(1);
@@ -537,6 +537,67 @@ numeric (PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(new);
}
Datum
numerictypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
int32 *tl;
int n;
int32 typmod;
tl = ArrayGetTypmods(ta, &n);
if (n == 2)
{
if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC precision %d must be between 1 and %d",
tl[0], NUMERIC_MAX_PRECISION)));
if (tl[1] < 0 || tl[1] > tl[0])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC scale %d must be between 0 and precision %d",
tl[1], tl[0])));
typmod = ((tl[0] << 16) | tl[1]) + VARHDRSZ;
}
else if (n == 1)
{
if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC precision %d must be between 1 and %d",
tl[0], NUMERIC_MAX_PRECISION)));
/* scale defaults to zero */
typmod = (tl[0] << 16) + VARHDRSZ;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid NUMERIC type modifier")));
typmod = 0; /* keep compiler quiet */
}
PG_RETURN_INT32(typmod);
}
Datum
numerictypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
char *res = (char *) palloc(64);
if (typmod >= 0)
snprintf(res, 64, "(%d,%d)",
((typmod - VARHDRSZ) >> 16) & 0xffff,
(typmod - VARHDRSZ) & 0xffff);
else
*res = '\0';
PG_RETURN_CSTRING(res);
}
/* ----------------------------------------------------------------------
*

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.169 2006/11/11 01:14:19 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.170 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,6 +56,60 @@ static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
static TimestampTz timestamp2timestamptz(Timestamp timestamp);
/* common code for timestamptypmodin and timestamptztypmodin */
static int32
anytimestamp_typmodin(bool istz, ArrayType *ta)
{
int32 typmod;
int32 *tl;
int n;
tl = ArrayGetTypmods(ta, &n);
/*
* we're not too tense about good error message here because grammar
* shouldn't allow wrong number of modifiers for TIMESTAMP
*/
if (n != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid type modifier")));
if (*tl < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIMESTAMP(%d)%s precision must not be negative",
*tl, (istz ? " WITH TIME ZONE" : ""))));
if (*tl > MAX_TIMESTAMP_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
*tl, (istz ? " WITH TIME ZONE" : ""),
MAX_TIMESTAMP_PRECISION)));
typmod = MAX_TIMESTAMP_PRECISION;
} else
typmod = *tl;
return typmod;
}
/* common code for timestamptypmodout and timestamptztypmodout */
static char *
anytimestamp_typmodout(bool istz, int32 typmod)
{
char *res = (char *) palloc(64);
const char *tz = istz ? " with time zone" : " without time zone";
if (typmod >= 0)
snprintf(res, 64, "(%d)%s", (int) typmod, tz);
else
snprintf(res, 64, "%s", tz);
return res;
}
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
@@ -215,6 +269,22 @@ timestamp_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
timestamptypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
}
Datum
timestamptypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
}
/* timestamp_scale()
* Adjust time type for specified scale factor.
@@ -461,6 +531,22 @@ timestamptz_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
timestamptztypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
}
Datum
timestamptztypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
}
/* timestamptz_scale()
* Adjust time type for specified scale factor.
@@ -625,6 +711,162 @@ interval_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
intervaltypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
int32 *tl;
int n;
int32 typmod;
tl = ArrayGetTypmods(ta, &n);
/*
* tl[0] - opt_interval
* tl[1] - Iconst (optional)
*
* Note we must validate tl[0] even though it's normally guaranteed
* correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
*/
if (n > 0)
{
switch (tl[0])
{
case INTERVAL_MASK(YEAR):
case INTERVAL_MASK(MONTH):
case INTERVAL_MASK(DAY):
case INTERVAL_MASK(HOUR):
case INTERVAL_MASK(MINUTE):
case INTERVAL_MASK(SECOND):
case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
case INTERVAL_FULL_RANGE:
/* all OK */
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid INTERVAL type modifier")));
}
}
if (n == 1)
{
if (tl[0] != INTERVAL_FULL_RANGE)
typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
else
typmod = -1;
}
else if (n == 2)
{
if (tl[1] < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision must not be negative",
tl[1])));
if (tl[1] > MAX_INTERVAL_PRECISION)
{
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
tl[1], MAX_INTERVAL_PRECISION)));
typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
}
else
typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid INTERVAL type modifier")));
typmod = 0; /* keep compiler quiet */
}
PG_RETURN_INT32(typmod);
}
Datum
intervaltypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
char *res = (char *) palloc(64);
int fields;
int precision;
const char *fieldstr;
if (typmod < 0)
{
*res = '\0';
PG_RETURN_CSTRING(res);
}
fields = INTERVAL_RANGE(typmod);
precision = INTERVAL_PRECISION(typmod);
switch (fields)
{
case INTERVAL_MASK(YEAR):
fieldstr = " year";
break;
case INTERVAL_MASK(MONTH):
fieldstr = " month";
break;
case INTERVAL_MASK(DAY):
fieldstr = " day";
break;
case INTERVAL_MASK(HOUR):
fieldstr = " hour";
break;
case INTERVAL_MASK(MINUTE):
fieldstr = " minute";
break;
case INTERVAL_MASK(SECOND):
fieldstr = " second";
break;
case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
fieldstr = " year to month";
break;
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
fieldstr = " day to hour";
break;
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
fieldstr = " day to minute";
break;
case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
fieldstr = " day to second";
break;
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
fieldstr = " hour to minute";
break;
case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
fieldstr = " hour to second";
break;
case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
fieldstr = " minute to second";
break;
case INTERVAL_FULL_RANGE:
fieldstr = "";
break;
default:
elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
fieldstr = "";
break;
}
if (precision != INTERVAL_FULL_PRECISION)
snprintf(res, 64, "(%d)%s", precision, fieldstr);
else
snprintf(res, 64, "%s", fieldstr);
PG_RETURN_CSTRING(res);
}
/* interval_scale()
* Adjust interval type for specified fields.

View File

@@ -9,19 +9,71 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.50 2006/07/14 14:52:24 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.51 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/htup.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/varbit.h"
#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A'))
/* common code for bittypmodin and varbittypmodin */
static int32
anybit_typmodin(ArrayType *ta, const char *typename)
{
int32 typmod;
int32 *tl;
int n;
tl = ArrayGetTypmods(ta, &n);
/*
* we're not too tense about good error message here because grammar
* shouldn't allow wrong number of modifiers for BIT
*/
if (n != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid type modifier")));
if (*tl < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s must be at least 1",
typename)));
if (*tl > (MaxAttrSize * BITS_PER_BYTE))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s cannot exceed %d",
typename, MaxAttrSize * BITS_PER_BYTE)));
typmod = *tl;
return typmod;
}
/* common code for bittypmodout and varbittypmodout */
static char *
anybit_typmodout(int32 typmod)
{
char *res = (char *) palloc(64);
if (typmod >= 0)
snprintf(res, 64, "(%d)", typmod);
else
*res = '\0';
return res;
}
/*----------
* attypmod -- contains the length of the bit string in bits, or for
* varying bits the maximum length.
@@ -325,6 +377,23 @@ bit(PG_FUNCTION_ARGS)
PG_RETURN_VARBIT_P(result);
}
Datum
bittypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anybit_typmodin(ta, "bit"));
}
Datum
bittypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anybit_typmodout(typmod));
}
/*
* varbit_in -
* converts a string to the internal representation of a bitstring.
@@ -603,6 +672,22 @@ varbit(PG_FUNCTION_ARGS)
PG_RETURN_VARBIT_P(result);
}
Datum
varbittypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anybit_typmodin(ta, "varbit"));
}
Datum
varbittypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anybit_typmodout(typmod));
}
/*
* Comparison operators

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.119 2006/10/04 00:30:00 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.120 2006/12/30 21:21:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,10 +17,65 @@
#include "access/hash.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "mb/pg_wchar.h"
/* common code for bpchartypmodin and varchartypmodin */
static int32
anychar_typmodin(ArrayType *ta, const char *typename)
{
int32 typmod;
int32 *tl;
int n;
tl = ArrayGetTypmods(ta, &n);
/*
* we're not too tense about good error message here because grammar
* shouldn't allow wrong number of modifiers for CHAR
*/
if (n != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid type modifier")));
if (*tl < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s must be at least 1", typename)));
if (*tl > MaxAttrSize)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length for type %s cannot exceed %d",
typename, MaxAttrSize)));
/*
* For largely historical reasons, the typmod is VARHDRSZ plus the
* number of characters; there is enough client-side code that knows
* about that that we'd better not change it.
*/
typmod = VARHDRSZ + *tl;
return typmod;
}
/* common code for bpchartypmodout and varchartypmodout */
static char *
anychar_typmodout(int32 typmod)
{
char *res = (char *) palloc(64);
if (typmod > VARHDRSZ)
snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
else
*res = '\0';
return res;
}
/*
* CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR()
* is for blank-padded string whose length is specified in CREATE TABLE.
@@ -359,6 +414,22 @@ name_bpchar(PG_FUNCTION_ARGS)
PG_RETURN_BPCHAR_P(result);
}
Datum
bpchartypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anychar_typmodin(ta, "char"));
}
Datum
bpchartypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anychar_typmodout(typmod));
}
/*****************************************************************************
* varchar - varchar(n)
@@ -536,6 +607,22 @@ varchar(PG_FUNCTION_ARGS)
PG_RETURN_VARCHAR_P(result);
}
Datum
varchartypmodin(PG_FUNCTION_ARGS)
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
}
Datum
varchartypmodout(PG_FUNCTION_ARGS)
{
int32 typmod = PG_GETARG_INT32(0);
PG_RETURN_CSTRING(anychar_typmodout(typmod));
}
/*****************************************************************************
* Exported functions

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.139 2006/12/23 00:43:11 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.140 2006/12/30 21:21:54 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -2016,6 +2016,60 @@ getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
ReleaseSysCache(typeTuple);
}
/*
* get_typmodin
*
* Given the type OID, return the type's typmodin procedure, if any.
*/
Oid
get_typmodin(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
Oid result;
result = typtup->typmodin;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
#ifdef NOT_USED
/*
* get_typmodout
*
* Given the type OID, return the type's typmodout procedure, if any.
*/
Oid
get_typmodout(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
Oid result;
result = typtup->typmodout;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
#endif /* NOT_USED */
/* ---------- STATISTICS CACHE ---------- */

View File

@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.363 2006/12/23 00:52:40 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.364 2006/12/30 21:21:54 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -45,6 +45,7 @@
#include "parser/gramparse.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/scansup.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
@@ -4523,14 +4524,17 @@ flatten_set_variable_args(const char *name, List *args)
* to interval and back to normalize the value and account
* for any typmod.
*/
int32 typmod;
Datum interval;
char *intervalout;
typmod = typenameTypeMod(NULL, arg->typename, INTERVALOID);
interval =
DirectFunctionCall3(interval_in,
CStringGetDatum(val),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(arg->typename->typmod));
Int32GetDatum(typmod));
intervalout =
DatumGetCString(DirectFunctionCall1(interval_out,