From 5725b9d9afc8c3ba24e94cbc7020889fe8ad7ef9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 30 Dec 2006 21:21:56 +0000 Subject: [PATCH] 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. --- doc/src/sgml/catalogs.sgml | 16 +- doc/src/sgml/keywords.sgml | 55 +-- doc/src/sgml/ref/create_type.sgml | 64 +++- src/backend/access/common/tupdesc.c | 9 +- src/backend/catalog/heap.c | 4 +- src/backend/catalog/pg_type.c | 30 +- src/backend/commands/tablecmds.c | 44 ++- src/backend/commands/typecmds.c | 104 ++++- src/backend/nodes/copyfuncs.c | 5 +- src/backend/nodes/equalfuncs.c | 5 +- src/backend/nodes/makefuncs.c | 16 +- src/backend/nodes/outfuncs.c | 5 +- src/backend/parser/gram.y | 447 +++++++--------------- src/backend/parser/parse_expr.c | 29 +- src/backend/parser/parse_relation.c | 6 +- src/backend/parser/parse_type.c | 77 +++- src/backend/utils/adt/arrayutils.c | 30 +- src/backend/utils/adt/date.c | 89 ++++- src/backend/utils/adt/format_type.c | 145 +++---- src/backend/utils/adt/numeric.c | 65 +++- src/backend/utils/adt/timestamp.c | 244 +++++++++++- src/backend/utils/adt/varbit.c | 87 ++++- src/backend/utils/adt/varchar.c | 89 ++++- src/backend/utils/cache/lsyscache.c | 56 ++- src/backend/utils/misc/guc.c | 8 +- src/bin/pg_dump/pg_dump.c | 48 ++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_attribute.h | 42 +- src/include/catalog/pg_class.h | 4 +- src/include/catalog/pg_proc.h | 42 +- src/include/catalog/pg_type.h | 266 +++++++------ src/include/nodes/parsenodes.h | 7 +- src/include/parser/parse_type.h | 4 +- src/include/utils/array.h | 3 +- src/include/utils/builtins.h | 10 +- src/include/utils/date.h | 6 +- src/include/utils/lsyscache.h | 3 +- src/include/utils/timestamp.h | 8 +- src/include/utils/varbit.h | 6 +- src/test/regress/expected/create_type.out | 14 + src/test/regress/expected/horology.out | 4 + src/test/regress/expected/oidjoins.out | 16 + src/test/regress/expected/type_sanity.out | 42 ++ src/test/regress/sql/create_type.sql | 11 + src/test/regress/sql/oidjoins.sql | 8 + src/test/regress/sql/type_sanity.sql | 34 ++ src/tools/findoidjoins/README | 2 + 47 files changed, 1628 insertions(+), 685 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index a906623ac9..2d42280f50 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ - + @@ -4393,6 +4393,20 @@ Output conversion function (binary format), or 0 if none + + typmodin + regproc + pg_proc.oid + Type modifier input function, or 0 if type does not support modifiers + + + + typmodout + regproc + pg_proc.oid + Type modifier output function, or 0 to use the standard format + + typanalyze regproc diff --git a/doc/src/sgml/keywords.sgml b/doc/src/sgml/keywords.sgml index c82b3b6f1b..b9565b3283 100644 --- a/doc/src/sgml/keywords.sgml +++ b/doc/src/sgml/keywords.sgml @@ -1,4 +1,4 @@ - + <acronym>SQL</acronym> Key Words @@ -45,16 +45,17 @@ In in the column for PostgreSQL we classify as non-reserved those key words that are explicitly - known to the parser but are allowed in most or all contexts where an - identifier is expected. Some key words that are otherwise + known to the parser but are allowed as column or table names. + Some key words that are otherwise non-reserved cannot be used as function or data type names and are marked accordingly. (Most of these words represent built-in functions or data types with special syntax. The function or type is still available but it cannot be redefined by the user.) Labeled - reserved are those tokens that are only allowed as - AS column label names (and perhaps in very few other - contexts). Some reserved key words are allowable as names for - functions; this is also shown in the table. + reserved are those tokens that are not allowed as + column or table names. Some reserved key words are + allowable as names for functions or data types; this is also shown in the + table. If not so marked, a reserved key word is only allowed as an + AS column label name. @@ -326,7 +327,7 @@ AUTHORIZATION - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -368,7 +369,7 @@ BETWEEN - reserved (can be function) + reserved (can be function or type) reserved non-reserved reserved @@ -382,7 +383,7 @@ BINARY - reserved (can be function) + reserved (can be function or type) reserved reserved @@ -956,7 +957,7 @@ CROSS - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -1642,7 +1643,7 @@ FREEZE - reserved (can be function) + reserved (can be function or type) @@ -1656,7 +1657,7 @@ FULL - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -1831,7 +1832,7 @@ ILIKE - reserved (can be function) + reserved (can be function or type) @@ -1943,7 +1944,7 @@ INNER - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -2048,14 +2049,14 @@ IS - reserved (can be function) + reserved (can be function or type) reserved reserved reserved ISNULL - reserved (can be function) + reserved (can be function or type) @@ -2076,7 +2077,7 @@ JOIN - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -2160,7 +2161,7 @@ LEFT - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -2188,7 +2189,7 @@ LIKE - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -2475,7 +2476,7 @@ NATURAL - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -2608,7 +2609,7 @@ NOTNULL - reserved (can be function) + reserved (can be function or type) @@ -2811,7 +2812,7 @@ OUTER - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -2832,7 +2833,7 @@ OVERLAPS - reserved (can be function) + reserved (can be function or type) reserved non-reserved reserved @@ -3385,7 +3386,7 @@ RIGHT - reserved (can be function) + reserved (can be function or type) reserved reserved reserved @@ -3658,7 +3659,7 @@ SIMILAR - reserved (can be function) + reserved (can be function or type) reserved non-reserved @@ -4414,7 +4415,7 @@ VERBOSE - reserved (can be function) + reserved (can be function or type) diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index e85c94dbe7..2f1f6eab3c 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -1,5 +1,5 @@ @@ -28,6 +28,8 @@ CREATE TYPE name ( OUTPUT = output_function [ , RECEIVE = receive_function ] [ , SEND = send_function ] + [ , TYPMOD_IN = type_modifier_input_function ] + [ , TYPMOD_OUT = type_modifier_output_function ] [ , ANALYZE = analyze_function ] [ , INTERNALLENGTH = { internallength | VARIABLE } ] [ , PASSEDBYVALUE ] @@ -83,12 +85,14 @@ CREATE TYPE name (scalar type). The parameters may appear in any order, not only that illustrated above, and most are optional. You must register two or more functions (using CREATE FUNCTION) before - defining the type. The support functions + defining the type. The support functions input_function and output_function are required, while the functions receive_function, - send_function and + send_function, + type_modifier_input_function, + type_modifier_output_function and analyze_function are optional. Generally these functions have to be coded in C or another low-level language. @@ -169,6 +173,34 @@ CREATE TYPE name used normally. + + The optional + type_modifier_input_function + and type_modifier_output_function + are needed if the type supports modifiers, that is optional constraints + attached to a type declaration, such as char(5) or + numeric(30,2). PostgreSQL allows + user-defined types to take one or more integer constants as modifiers; + however, this information must be capable of being packed into a single + non-negative integer value for storage in the system catalogs. The + type_modifier_input_function + is passed the declared modifier(s) in the form of an integer + array. It must check the values for validity (throwing an error if they + are wrong), and if they are correct, return a single non-negative + integer value that will be stored as the column typmod. + Type modifiers will be rejected if the type does not have a + type_modifier_input_function. + The type_modifier_output_function + converts the internal integer typmod value back to the correct form for + user display. It must return a cstring value that is the exact + string to append to the type name; for example numeric's + function might return (30,2). + It is allowed to omit the + type_modifier_output_function, + in which case the default display format is just the stored typmod value + enclosed in parentheses. + + The optional analyze_function performs type-specific statistics collection for columns of the data type. @@ -265,7 +297,7 @@ CREATE TYPE name Array Types - Whenever a user-defined base data type is created, + Whenever a user-defined base data type is created, PostgreSQL automatically creates an associated array type, whose name consists of the base type's name prepended with an underscore. The parser understands this @@ -298,7 +330,7 @@ CREATE TYPE name - + Parameters @@ -371,6 +403,26 @@ CREATE TYPE name + + type_modifier_input_function + + + The name of a function that converts numeric modifier(s) for the type + into internal form. + + + + + + type_modifier_output_function + + + The name of a function that converts the internal form of the type's + modifier(s) to external textual form. + + + + analyze_function @@ -499,7 +551,7 @@ CREATE TYPE name - + Examples diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 6242afa20f..be5665db79 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -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) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index d6822c73c6..41ef41c7c1 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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 */ diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 32de0b90dc..74517124fb 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -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; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 2a1116f758..c30aa69c55 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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; diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 53cca73a9d..2b26f2dfa1 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -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, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index d46ed57d83..c8c9b907c9 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 29bff448c7..57e61f0e2a 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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); diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 9f6aa22707..277103e4a1 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -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; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 4911d6ed40..2b21eae6a1 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a1511870f2..c4820190f0 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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 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 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 character %type extract_arg %type opt_charset -%type opt_numeric opt_decimal %type opt_varying opt_timezone %type Iconst SignedIconst %type Sconst comment_text %type RoleId opt_granted_by opt_boolean ColId_or_Sconst %type var_list var_list_or_default -%type ColId ColLabel var_name type_name param_name +%type ColId ColLabel var_name type_function_name param_name %type var_value zone_value -%type unreserved_keyword func_name_keyword +%type unreserved_keyword type_func_name_keyword %type col_name_keyword reserved_keyword -%type TableConstraint TableLikeClause +%type TableConstraint TableLikeClause %type TableLikeOptionList %type TableLikeOption %type 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() diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 7dbbb9a33a..383013c9a1 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -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) diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 75d5a50702..f6d4fcae4a 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -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); } diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 93c7db6b52..6aeabb5749 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -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); diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c index 2a732ad63b..2913d0a1d8 100644 --- a/src/backend/utils/adt/arrayutils.c +++ b/src/backend/utils/adt/arrayutils.c @@ -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); +} diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 9efc7125b1..e2781dec48 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -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. diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 22d9bc156f..d2b6323f0f 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -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) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 35b0221b85..11dd881011 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -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); +} + /* ---------------------------------------------------------------------- * diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index f94413e3f3..f9b0bb2c99 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -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. diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index e0a67d340e..4a810b955d 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -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 diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index 937cf96ebe..9cc2f5e34e 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -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 diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 824ef4a1ef..8c4cbef66c 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -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 ---------- */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 6c6ff1fb5a..377c6d87c3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * 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, diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index ae8d54936f..637af90d91 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.454 2006/12/23 00:43:12 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.455 2006/12/30 21:21:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -5007,11 +5007,15 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) char *typoutput; char *typreceive; char *typsend; + char *typmodin; + char *typmodout; char *typanalyze; Oid typinputoid; Oid typoutputoid; Oid typreceiveoid; Oid typsendoid; + Oid typmodinoid; + Oid typmodoutoid; Oid typanalyzeoid; char *typdelim; char *typbyval; @@ -5024,15 +5028,35 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) selectSourceSchema(tinfo->dobj.namespace->dobj.name); /* Fetch type-specific details */ - if (fout->remoteVersion >= 80000) + if (fout->remoteVersion >= 80300) { appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, typreceive, typsend, " + "typmodin, typmodout, typanalyze, " + "typinput::pg_catalog.oid as typinputoid, " + "typoutput::pg_catalog.oid as typoutputoid, " + "typreceive::pg_catalog.oid as typreceiveoid, " + "typsend::pg_catalog.oid as typsendoid, " + "typmodin::pg_catalog.oid as typmodinoid, " + "typmodout::pg_catalog.oid as typmodoutoid, " + "typanalyze::pg_catalog.oid as typanalyzeoid, " + "typdelim, typbyval, typalign, typstorage, " + "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault " + "FROM pg_catalog.pg_type " + "WHERE oid = '%u'::pg_catalog.oid", + tinfo->dobj.catId.oid); + } + else if (fout->remoteVersion >= 80000) + { + appendPQExpBuffer(query, "SELECT typlen, " + "typinput, typoutput, typreceive, typsend, " + "'-' as typmodin, '-' as typmodout, " "typanalyze, " "typinput::pg_catalog.oid as typinputoid, " "typoutput::pg_catalog.oid as typoutputoid, " "typreceive::pg_catalog.oid as typreceiveoid, " "typsend::pg_catalog.oid as typsendoid, " + "0 as typmodinoid, 0 as typmodoutoid, " "typanalyze::pg_catalog.oid as typanalyzeoid, " "typdelim, typbyval, typalign, typstorage, " "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault " @@ -5044,11 +5068,13 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) { appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, typreceive, typsend, " + "'-' as typmodin, '-' as typmodout, " "'-' as typanalyze, " "typinput::pg_catalog.oid as typinputoid, " "typoutput::pg_catalog.oid as typoutputoid, " "typreceive::pg_catalog.oid as typreceiveoid, " "typsend::pg_catalog.oid as typsendoid, " + "0 as typmodinoid, 0 as typmodoutoid, " "0 as typanalyzeoid, " "typdelim, typbyval, typalign, typstorage, " "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault " @@ -5061,10 +5087,12 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typmodin, '-' as typmodout, " "'-' as typanalyze, " "typinput::pg_catalog.oid as typinputoid, " "typoutput::pg_catalog.oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typmodinoid, 0 as typmodoutoid, " "0 as typanalyzeoid, " "typdelim, typbyval, typalign, typstorage, " "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault " @@ -5081,10 +5109,12 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typmodin, '-' as typmodout, " "'-' as typanalyze, " "typinput::oid as typinputoid, " "typoutput::oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typmodinoid, 0 as typmodoutoid, " "0 as typanalyzeoid, " "typdelim, typbyval, typalign, typstorage, " "NULL as typdefaultbin, typdefault " @@ -5101,10 +5131,12 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typmodin, '-' as typmodout, " "'-' as typanalyze, " "typinput::oid as typinputoid, " "typoutput::oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typmodinoid, 0 as typmodoutoid, " "0 as typanalyzeoid, " "typdelim, typbyval, typalign, typstorage, " "NULL as typdefaultbin, NULL as typdefault " @@ -5117,10 +5149,12 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typmodin, '-' as typmodout, " "'-' as typanalyze, " "typinput::oid as typinputoid, " "typoutput::oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typmodinoid, 0 as typmodoutoid, " "0 as typanalyzeoid, " "typdelim, typbyval, typalign, " "'p'::char as typstorage, " @@ -5147,11 +5181,15 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput")); typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive")); typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend")); + typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin")); + typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout")); typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze")); typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid"))); typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid"))); typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid"))); typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid"))); + typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid"))); + typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid"))); typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid"))); typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim")); typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval")); @@ -5193,6 +5231,10 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive); if (OidIsValid(typsendoid)) appendPQExpBuffer(q, ",\n SEND = %s", typsend); + if (OidIsValid(typmodinoid)) + appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin); + if (OidIsValid(typmodoutoid)) + appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout); if (OidIsValid(typanalyzeoid)) appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze); } @@ -5202,7 +5244,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) /* cannot combine these because fmtId uses static result area */ appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput)); appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput)); - /* no chance that receive/send/analyze need be printed */ + /* receive/send/typmodin/typmodout/analyze need not be printed */ } if (typdefault != NULL) diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1b1e07bd71..1200af0c6e 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.367 2006/12/28 14:28:36 petere Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.368 2006/12/30 21:21:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200612281 +#define CATALOG_VERSION_NO 200612291 #endif diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 3fcc5ed674..2c38c2b88f 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.126 2006/11/05 22:42:10 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.127 2006/12/30 21:21:55 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -236,15 +236,17 @@ typedef FormData_pg_attribute *Form_pg_attribute; { 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ -{ 1247, {"typanalyze"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ -{ 1247, {"typalign"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ -{ 1247, {"typstorage"}, 18, -1, 1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ -{ 1247, {"typnotnull"}, 16, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ -{ 1247, {"typbasetype"}, 26, -1, 4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ -{ 1247, {"typtypmod"}, 23, -1, 4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ -{ 1247, {"typndims"}, 23, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ -{ 1247, {"typdefaultbin"}, 25, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ -{ 1247, {"typdefault"}, 25, -1, -1, 23, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 } +{ 1247, {"typmodin"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typmodout"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typanalyze"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typalign"}, 18, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typstorage"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typnotnull"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 1247, {"typbasetype"}, 26, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typtypmod"}, 23, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typndims"}, 23, -1, 4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 1247, {"typdefaultbin"}, 25, -1, -1, 24, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 1247, {"typdefault"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 } DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); @@ -260,15 +262,17 @@ DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p i t f f t 0)); -DATA(insert ( 1247 typanalyze 24 -1 4 15 0 -1 -1 t p i t f f t 0)); -DATA(insert ( 1247 typalign 18 -1 1 16 0 -1 -1 t p c t f f t 0)); -DATA(insert ( 1247 typstorage 18 -1 1 17 0 -1 -1 t p c t f f t 0)); -DATA(insert ( 1247 typnotnull 16 -1 1 18 0 -1 -1 t p c t f f t 0)); -DATA(insert ( 1247 typbasetype 26 -1 4 19 0 -1 -1 t p i t f f t 0)); -DATA(insert ( 1247 typtypmod 23 -1 4 20 0 -1 -1 t p i t f f t 0)); -DATA(insert ( 1247 typndims 23 -1 4 21 0 -1 -1 t p i t f f t 0)); -DATA(insert ( 1247 typdefaultbin 25 -1 -1 22 0 -1 -1 f x i f f f t 0)); -DATA(insert ( 1247 typdefault 25 -1 -1 23 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1247 typmodin 24 -1 4 15 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typmodout 24 -1 4 16 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typanalyze 24 -1 4 17 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typalign 18 -1 1 18 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typstorage 18 -1 1 19 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typnotnull 16 -1 1 20 0 -1 -1 t p c t f f t 0)); +DATA(insert ( 1247 typbasetype 26 -1 4 21 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typtypmod 23 -1 4 22 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typndims 23 -1 4 23 0 -1 -1 t p i t f f t 0)); +DATA(insert ( 1247 typdefaultbin 25 -1 -1 24 0 -1 -1 f x i f f f t 0)); +DATA(insert ( 1247 typdefault 25 -1 -1 25 0 -1 -1 f x i f f f t 0)); DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 75aee92e51..155b4c7bc3 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.97 2006/11/05 22:42:10 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.98 2006/12/30 21:21:55 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -132,7 +132,7 @@ typedef FormData_pg_class *Form_pg_class; */ /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ -DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 23 0 0 0 0 0 t f f f 3 _null_ _null_ )); +DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ )); DESCR(""); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index b591300709..f98717a978 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.433 2006/12/28 14:28:36 petere Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.434 2006/12/30 21:21:55 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -1335,10 +1335,18 @@ DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 f f t f i 3 1042 "2275 26 DESCR("I/O"); DATA(insert OID = 1045 ( bpcharout PGNSP PGUID 12 f f t f i 1 2275 "1042" _null_ _null_ _null_ bpcharout - _null_ )); DESCR("I/O"); +DATA(insert OID = 2913 ( bpchartypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ bpchartypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2914 ( bpchartypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ bpchartypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1046 ( varcharin PGNSP PGUID 12 f f t f i 3 1043 "2275 26 23" _null_ _null_ _null_ varcharin - _null_ )); DESCR("I/O"); DATA(insert OID = 1047 ( varcharout PGNSP PGUID 12 f f t f i 1 2275 "1043" _null_ _null_ _null_ varcharout - _null_ )); DESCR("I/O"); +DATA(insert OID = 2915 ( varchartypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ varchartypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2916 ( varchartypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ varchartypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1048 ( bpchareq PGNSP PGUID 12 f f t f i 2 16 "1042 1042" _null_ _null_ _null_ bpchareq - _null_ )); DESCR("equal"); DATA(insert OID = 1049 ( bpcharlt PGNSP PGUID 12 f f t f i 2 16 "1042 1042" _null_ _null_ _null_ bpcharlt - _null_ )); @@ -1408,6 +1416,10 @@ DATA(insert OID = 1143 ( time_in PGNSP PGUID 12 f f t f s 3 1083 "2275 26 2 DESCR("I/O"); DATA(insert OID = 1144 ( time_out PGNSP PGUID 12 f f t f i 1 2275 "1083" _null_ _null_ _null_ time_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2909 ( timetypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ timetypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2910 ( timetypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ timetypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1145 ( time_eq PGNSP PGUID 12 f f t f i 2 16 "1083 1083" _null_ _null_ _null_ time_eq - _null_ )); DESCR("equal"); @@ -1424,6 +1436,10 @@ DATA(insert OID = 1150 ( timestamptz_in PGNSP PGUID 12 f f t f s 3 1184 "2275 DESCR("I/O"); DATA(insert OID = 1151 ( timestamptz_out PGNSP PGUID 12 f f t f s 1 2275 "1184" _null_ _null_ _null_ timestamptz_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2907 ( timestamptztypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ timestamptztypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2908 ( timestamptztypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ timestamptztypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1152 ( timestamptz_eq PGNSP PGUID 12 f f t f i 2 16 "1184 1184" _null_ _null_ _null_ timestamp_eq - _null_ )); DESCR("equal"); DATA(insert OID = 1153 ( timestamptz_ne PGNSP PGUID 12 f f t f i 2 16 "1184 1184" _null_ _null_ _null_ timestamp_ne - _null_ )); @@ -1445,6 +1461,10 @@ DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f f t f s 3 1186 "2275 2 DESCR("I/O"); DATA(insert OID = 1161 ( interval_out PGNSP PGUID 12 f f t f i 1 2275 "1186" _null_ _null_ _null_ interval_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2903 ( intervaltypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ intervaltypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2904 ( intervaltypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ intervaltypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1162 ( interval_eq PGNSP PGUID 12 f f t f i 2 16 "1186 1186" _null_ _null_ _null_ interval_eq - _null_ )); DESCR("equal"); DATA(insert OID = 1163 ( interval_ne PGNSP PGUID 12 f f t f i 2 16 "1186 1186" _null_ _null_ _null_ interval_ne - _null_ )); @@ -1668,6 +1688,10 @@ DATA(insert OID = 1312 ( timestamp_in PGNSP PGUID 12 f f t f s 3 1114 "2275 2 DESCR("I/O"); DATA(insert OID = 1313 ( timestamp_out PGNSP PGUID 12 f f t f s 1 2275 "1114" _null_ _null_ _null_ timestamp_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2905 ( timestamptypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ timestamptypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2906 ( timestamptypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ timestamptypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1314 ( timestamptz_cmp PGNSP PGUID 12 f f t f i 2 23 "1184 1184" _null_ _null_ _null_ timestamp_cmp - _null_ )); DESCR("less-equal-greater"); DATA(insert OID = 1315 ( interval_cmp PGNSP PGUID 12 f f t f i 2 23 "1186 1186" _null_ _null_ _null_ interval_cmp - _null_ )); @@ -1721,6 +1745,10 @@ DATA(insert OID = 1350 ( timetz_in PGNSP PGUID 12 f f t f s 3 1266 "2275 26 DESCR("I/O"); DATA(insert OID = 1351 ( timetz_out PGNSP PGUID 12 f f t f i 1 2275 "1266" _null_ _null_ _null_ timetz_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2911 ( timetztypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ timetztypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2912 ( timetztypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ timetztypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1352 ( timetz_eq PGNSP PGUID 12 f f t f i 2 16 "1266 1266" _null_ _null_ _null_ timetz_eq - _null_ )); DESCR("equal"); DATA(insert OID = 1353 ( timetz_ne PGNSP PGUID 12 f f t f i 2 16 "1266 1266" _null_ _null_ _null_ timetz_ne - _null_ )); @@ -2053,6 +2081,10 @@ DATA(insert OID = 1564 ( bit_in PGNSP PGUID 12 f f t f i 3 1560 "2275 26 23" DESCR("I/O"); DATA(insert OID = 1565 ( bit_out PGNSP PGUID 12 f f t f i 1 2275 "1560" _null_ _null_ _null_ bit_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2919 ( bittypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ bittypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2920 ( bittypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ bittypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1569 ( like PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ textlike - _null_ )); DESCR("matches LIKE expression"); @@ -2078,6 +2110,10 @@ DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 f f t f i 3 1562 "2275 26 2 DESCR("I/O"); DATA(insert OID = 1580 ( varbit_out PGNSP PGUID 12 f f t f i 1 2275 "1562" _null_ _null_ _null_ varbit_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2902 ( varbittypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ varbittypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2921 ( varbittypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ varbittypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1581 ( biteq PGNSP PGUID 12 f f t f i 2 16 "1560 1560" _null_ _null_ _null_ biteq - _null_ )); DESCR("equal"); @@ -2498,6 +2534,10 @@ DATA(insert OID = 1701 ( numeric_in PGNSP PGUID 12 f f t f i 3 1700 "2275 26 DESCR("I/O"); DATA(insert OID = 1702 ( numeric_out PGNSP PGUID 12 f f t f i 1 2275 "1700" _null_ _null_ _null_ numeric_out - _null_ )); DESCR("I/O"); +DATA(insert OID = 2917 ( numerictypmodin PGNSP PGUID 12 f f t f i 1 23 "1007" _null_ _null_ _null_ numerictypmodin - _null_ )); +DESCR("I/O typmod"); +DATA(insert OID = 2918 ( numerictypmodout PGNSP PGUID 12 f f t f i 1 2275 "23" _null_ _null_ _null_ numerictypmodout - _null_ )); +DESCR("I/O typmod"); DATA(insert OID = 1703 ( numeric PGNSP PGUID 12 f f t f i 2 1700 "1700 23" _null_ _null_ _null_ numeric - _null_ )); DESCR("adjust numeric to typmod precision/scale"); DATA(insert OID = 1704 ( numeric_abs PGNSP PGUID 12 f f t f i 1 1700 "1700" _null_ _null_ _null_ numeric_abs - _null_ )); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 9a95ef305b..65f8b9deea 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.175 2006/12/28 14:28:36 petere Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.176 2006/12/30 21:21:55 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -104,6 +104,12 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP regproc typreceive; /* binary format (optional) */ regproc typsend; + /* + * I/O functions for optional type modifiers. + */ + regproc typmodin; + regproc typmodout; + /* * Custom ANALYZE procedure for the datatype (0 selects the default). */ @@ -205,7 +211,7 @@ typedef FormData_pg_type *Form_pg_type; * compiler constants for pg_type * ---------------- */ -#define Natts_pg_type 23 +#define Natts_pg_type 25 #define Anum_pg_type_typname 1 #define Anum_pg_type_typnamespace 2 #define Anum_pg_type_typowner 3 @@ -220,15 +226,17 @@ typedef FormData_pg_type *Form_pg_type; #define Anum_pg_type_typoutput 12 #define Anum_pg_type_typreceive 13 #define Anum_pg_type_typsend 14 -#define Anum_pg_type_typanalyze 15 -#define Anum_pg_type_typalign 16 -#define Anum_pg_type_typstorage 17 -#define Anum_pg_type_typnotnull 18 -#define Anum_pg_type_typbasetype 19 -#define Anum_pg_type_typtypmod 20 -#define Anum_pg_type_typndims 21 -#define Anum_pg_type_typdefaultbin 22 -#define Anum_pg_type_typdefault 23 +#define Anum_pg_type_typmodin 15 +#define Anum_pg_type_typmodout 16 +#define Anum_pg_type_typanalyze 17 +#define Anum_pg_type_typalign 18 +#define Anum_pg_type_typstorage 19 +#define Anum_pg_type_typnotnull 20 +#define Anum_pg_type_typbasetype 21 +#define Anum_pg_type_typtypmod 22 +#define Anum_pg_type_typndims 23 +#define Anum_pg_type_typdefaultbin 24 +#define Anum_pg_type_typdefault 25 /* ---------------- @@ -244,86 +252,86 @@ typedef FormData_pg_type *Form_pg_type; */ /* OIDS 1 - 99 */ -DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b t \054 0 0 boolin boolout boolrecv boolsend - c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b t \054 0 0 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 _null_ _null_ )); DESCR("boolean, 'true'/'false'"); #define BOOLOID 16 -DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b t \054 0 0 byteain byteaout bytearecv byteasend - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b t \054 0 0 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length string, binary values escaped"); #define BYTEAOID 17 -DATA(insert OID = 18 ( char PGNSP PGUID 1 t b t \054 0 0 charin charout charrecv charsend - c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 18 ( char PGNSP PGUID 1 t b t \054 0 0 charin charout charrecv charsend - - - c p f 0 -1 0 _null_ _null_ )); DESCR("single character"); #define CHAROID 18 -DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout namerecv namesend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout namerecv namesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("63-character type for storing system identifiers"); #define NAMEOID 19 -DATA(insert OID = 20 ( int8 PGNSP PGUID 8 f b t \054 0 0 int8in int8out int8recv int8send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 20 ( int8 PGNSP PGUID 8 f b t \054 0 0 int8in int8out int8recv int8send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("~18 digit integer, 8-byte storage"); #define INT8OID 20 -DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b t \054 0 0 int2in int2out int2recv int2send - s p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b t \054 0 0 int2in int2out int2recv int2send - - - s p f 0 -1 0 _null_ _null_ )); DESCR("-32 thousand to 32 thousand, 2-byte storage"); #define INT2OID 21 -DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("array of int2, used in system tables"); #define INT2VECTOROID 22 -DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b t \054 0 0 int4in int4out int4recv int4send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b t \054 0 0 int4in int4out int4recv int4send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("-2 billion to 2 billion integer, 4-byte storage"); #define INT4OID 23 -DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b t \054 0 0 regprocin regprocout regprocrecv regprocsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b t \054 0 0 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered procedure"); #define REGPROCOID 24 -DATA(insert OID = 25 ( text PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 25 ( text PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend - - - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length string, no limit specified"); #define TEXTOID 25 -DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b t \054 0 0 oidin oidout oidrecv oidsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b t \054 0 0 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("object identifier(oid), maximum 4 billion"); #define OIDOID 26 -DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b t \054 0 0 tidin tidout tidrecv tidsend - s p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b t \054 0 0 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 _null_ _null_ )); DESCR("(Block, offset), physical location of tuple"); #define TIDOID 27 -DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b t \054 0 0 xidin xidout xidrecv xidsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b t \054 0 0 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("transaction id"); #define XIDOID 28 -DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b t \054 0 0 cidin cidout cidrecv cidsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b t \054 0 0 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("command identifier type, sequence in transaction id"); #define CIDOID 29 -DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b t \054 0 26 oidvectorin oidvectorout oidvectorrecv oidvectorsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b t \054 0 26 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("array of oids, used in system tables"); #define OIDVECTOROID 30 /* hand-built rowtype entries for bootstrapped catalogs: */ -DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c t \054 1247 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c t \054 1247 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); #define PG_TYPE_RELTYPE_OID 71 -DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c t \054 1249 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c t \054 1249 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); #define PG_ATTRIBUTE_RELTYPE_OID 75 -DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c t \054 1255 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c t \054 1255 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); #define PG_PROC_RELTYPE_OID 81 -DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c t \054 1259 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c t \054 1259 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); #define PG_CLASS_RELTYPE_OID 83 /* OIDS 100 - 199 */ -DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b t \054 0 0 xml_in xml_out xml_recv xml_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b t \054 0 0 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 _null_ _null_ )); DESCR("XML content"); #define XMLOID 142 -DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b t \054 0 142 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b t \054 0 142 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); /* OIDS 200 - 299 */ -DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b t \054 0 0 smgrin smgrout - - - s p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b t \054 0 0 smgrin smgrout - - - - - s p f 0 -1 0 _null_ _null_ )); DESCR("storage manager"); /* OIDS 300 - 399 */ @@ -333,194 +341,194 @@ DESCR("storage manager"); /* OIDS 500 - 599 */ /* OIDS 600 - 699 */ -DATA(insert OID = 600 ( point PGNSP PGUID 16 f b t \054 0 701 point_in point_out point_recv point_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 600 ( point PGNSP PGUID 16 f b t \054 0 701 point_in point_out point_recv point_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric point '(x, y)'"); #define POINTOID 600 -DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out lseg_recv lseg_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric line segment '(pt1,pt2)'"); #define LSEGOID 601 -DATA(insert OID = 602 ( path PGNSP PGUID -1 f b t \054 0 0 path_in path_out path_recv path_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 602 ( path PGNSP PGUID -1 f b t \054 0 0 path_in path_out path_recv path_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR("geometric path '(pt1,...)'"); #define PATHOID 602 -DATA(insert OID = 603 ( box PGNSP PGUID 32 f b t \073 0 600 box_in box_out box_recv box_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 603 ( box PGNSP PGUID 32 f b t \073 0 600 box_in box_out box_recv box_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric box '(lower left,upper right)'"); #define BOXOID 603 -DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b t \054 0 0 poly_in poly_out poly_recv poly_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b t \054 0 0 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR("geometric polygon '(pt1,...)'"); #define POLYGONOID 604 -DATA(insert OID = 628 ( line PGNSP PGUID 32 f b t \054 0 701 line_in line_out line_recv line_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 628 ( line PGNSP PGUID 32 f b t \054 0 701 line_in line_out line_recv line_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric line (not implemented)'"); #define LINEOID 628 -DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b t \054 0 628 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b t \054 0 628 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR(""); /* OIDS 700 - 799 */ -DATA(insert OID = 700 ( float4 PGNSP PGUID 4 f b t \054 0 0 float4in float4out float4recv float4send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 700 ( float4 PGNSP PGUID 4 f b t \054 0 0 float4in float4out float4recv float4send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("single-precision floating point number, 4-byte storage"); #define FLOAT4OID 700 -DATA(insert OID = 701 ( float8 PGNSP PGUID 8 f b t \054 0 0 float8in float8out float8recv float8send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 701 ( float8 PGNSP PGUID 8 f b t \054 0 0 float8in float8out float8recv float8send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("double-precision floating point number, 8-byte storage"); #define FLOAT8OID 701 -DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b t \054 0 0 abstimein abstimeout abstimerecv abstimesend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b t \054 0 0 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("absolute, limited-range date and time (Unix system time)"); #define ABSTIMEOID 702 -DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b t \054 0 0 reltimein reltimeout reltimerecv reltimesend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b t \054 0 0 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("relative, limited-range time interval (Unix delta time)"); #define RELTIMEOID 703 -DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b t \054 0 0 tintervalin tintervalout tintervalrecv tintervalsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b t \054 0 0 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("(abstime,abstime), time interval"); #define TINTERVALOID 704 -DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 _null_ _null_ )); DESCR(""); #define UNKNOWNOID 705 -DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b t \054 0 0 circle_in circle_out circle_recv circle_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b t \054 0 0 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric circle '(center,radius)'"); #define CIRCLEOID 718 -DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b t \054 0 718 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 790 ( money PGNSP PGUID 4 f b t \054 0 0 cash_in cash_out cash_recv cash_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b t \054 0 718 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 790 ( money PGNSP PGUID 4 f b t \054 0 0 cash_in cash_out cash_recv cash_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("monetary amounts, $d,ddd.cc"); #define CASHOID 790 -DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b t \054 0 790 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b t \054 0 790 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); /* OIDS 800 - 899 */ -DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b t \054 0 0 macaddr_in macaddr_out macaddr_recv macaddr_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b t \054 0 0 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("XX:XX:XX:XX:XX:XX, MAC address"); #define MACADDROID 829 -DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b t \054 0 0 inet_in inet_out inet_recv inet_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b t \054 0 0 inet_in inet_out inet_recv inet_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("IP address/netmask, host address, netmask optional"); #define INETOID 869 -DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b t \054 0 0 cidr_in cidr_out cidr_recv cidr_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b t \054 0 0 cidr_in cidr_out cidr_recv cidr_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("network IP address/netmask, network address"); #define CIDROID 650 /* OIDS 900 - 999 */ /* OIDS 1000 - 1099 */ -DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b t \054 0 16 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b t \054 0 17 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b t \054 0 18 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b t \054 0 19 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b t \054 0 21 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b t \054 0 22 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b t \054 0 23 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b t \054 0 16 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b t \054 0 17 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b t \054 0 18 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b t \054 0 19 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b t \054 0 21 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b t \054 0 22 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b t \054 0 23 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define INT4ARRAYOID 1007 -DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b t \054 0 24 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b t \054 0 25 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b t \054 0 26 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b t \054 0 27 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b t \054 0 28 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b t \054 0 29 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b t \054 0 30 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b t \054 0 1042 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b t \054 0 1043 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b t \054 0 20 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b t \054 0 600 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b t \054 0 601 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b t \054 0 602 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b t \073 0 603 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b t \054 0 700 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b t \054 0 24 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b t \054 0 25 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b t \054 0 26 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b t \054 0 27 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b t \054 0 28 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b t \054 0 29 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b t \054 0 30 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b t \054 0 1042 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b t \054 0 1043 array_in array_out array_recv array_send varchartypmodin varchartypmodout - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b t \054 0 20 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b t \054 0 600 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b t \054 0 601 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b t \054 0 602 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b t \073 0 603 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b t \054 0 700 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define FLOAT4ARRAYOID 1021 -DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b t \054 0 701 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b t \054 0 702 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b t \054 0 703 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b t \054 0 704 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b t \054 0 604 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b t \054 0 0 aclitemin aclitemout - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b t \054 0 701 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b t \054 0 702 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b t \054 0 703 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b t \054 0 704 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b t \054 0 604 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b t \054 0 0 aclitemin aclitemout - - - - - i p f 0 -1 0 _null_ _null_ )); DESCR("access control list"); #define ACLITEMOID 1033 -DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b t \054 0 1033 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b t \054 0 829 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b t \054 0 869 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b t \054 0 650 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b t \054 0 0 bpcharin bpcharout bpcharrecv bpcharsend - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b t \054 0 1033 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b t \054 0 829 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b t \054 0 869 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b t \054 0 650 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b t \054 0 0 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("char(length), blank-padded string, fixed storage length"); #define BPCHAROID 1042 -DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b t \054 0 0 varcharin varcharout varcharrecv varcharsend - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b t \054 0 0 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("varchar(length), non-blank-padded string, variable storage length"); #define VARCHAROID 1043 -DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b t \054 0 0 date_in date_out date_recv date_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b t \054 0 0 date_in date_out date_recv date_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("ANSI SQL date"); #define DATEOID 1082 -DATA(insert OID = 1083 ( time PGNSP PGUID 8 f b t \054 0 0 time_in time_out time_recv time_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1083 ( time PGNSP PGUID 8 f b t \054 0 0 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("hh:mm:ss, ANSI SQL time"); #define TIMEOID 1083 /* OIDS 1100 - 1199 */ -DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 f b t \054 0 0 timestamp_in timestamp_out timestamp_recv timestamp_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 f b t \054 0 0 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("date and time"); #define TIMESTAMPOID 1114 -DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b t \054 0 1114 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b t \054 0 1082 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b t \054 0 1083 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 f b t \054 0 0 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b t \054 0 1114 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b t \054 0 1082 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b t \054 0 1083 array_in array_out array_recv array_send timetypmodin timetypmodout - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 f b t \054 0 0 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("date and time with time zone"); #define TIMESTAMPTZOID 1184 -DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0 1184 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b t \054 0 0 interval_in interval_out interval_recv interval_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0 1184 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b t \054 0 0 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("@ , time interval"); #define INTERVALOID 1186 -DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b t \054 0 1186 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b t \054 0 1186 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout - d x f 0 -1 0 _null_ _null_ )); /* OIDS 1200 - 1299 */ -DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b t \054 0 1700 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b t \054 0 0 timetz_in timetz_out timetz_recv timetz_send - d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b t \054 0 1700 array_in array_out array_recv array_send numerictypmodin numerictypmodout - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b t \054 0 0 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("hh:mm:ss, ANSI SQL time"); #define TIMETZOID 1266 -DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b t \054 0 1266 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b t \054 0 1266 array_in array_out array_recv array_send timetztypmodin timetztypmodout - d x f 0 -1 0 _null_ _null_ )); /* OIDS 1500 - 1599 */ -DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b t \054 0 0 bit_in bit_out bit_recv bit_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b t \054 0 0 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("fixed-length bit string"); #define BITOID 1560 -DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b t \054 0 1560 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b t \054 0 0 varbit_in varbit_out varbit_recv varbit_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b t \054 0 1560 array_in array_out array_recv array_send bittypmodin bittypmodout - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b t \054 0 0 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length bit string"); #define VARBITOID 1562 -DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b t \054 0 1562 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b t \054 0 1562 array_in array_out array_recv array_send varbittypmodin varbittypmodout - i x f 0 -1 0 _null_ _null_ )); /* OIDS 1600 - 1699 */ /* OIDS 1700 - 1799 */ -DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b t \054 0 0 numeric_in numeric_out numeric_recv numeric_send - i m f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b t \054 0 0 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f 0 -1 0 _null_ _null_ )); DESCR("numeric(precision, decimal), arbitrary precision number"); #define NUMERICOID 1700 -DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend - - - i x f 0 -1 0 _null_ _null_ )); DESCR("reference cursor (portal name)"); #define REFCURSOROID 1790 /* OIDS 2200 - 2299 */ -DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b t \054 0 1790 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b t \054 0 1790 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b t \054 0 0 regprocedurein regprocedureout regprocedurerecv regproceduresend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b t \054 0 0 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered procedure (with args)"); #define REGPROCEDUREOID 2202 -DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b t \054 0 0 regoperin regoperout regoperrecv regopersend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b t \054 0 0 regoperin regoperout regoperrecv regopersend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered operator"); #define REGOPEROID 2203 -DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b t \054 0 0 regoperatorin regoperatorout regoperatorrecv regoperatorsend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b t \054 0 0 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered operator (with args)"); #define REGOPERATOROID 2204 -DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b t \054 0 0 regclassin regclassout regclassrecv regclasssend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b t \054 0 0 regclassin regclassout regclassrecv regclasssend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered class"); #define REGCLASSOID 2205 -DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b t \054 0 0 regtypein regtypeout regtyperecv regtypesend - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b t \054 0 0 regtypein regtypeout regtyperecv regtypesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered type"); #define REGTYPEOID 2206 -DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b t \054 0 2202 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b t \054 0 2203 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b t \054 0 2204 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b t \054 0 2205 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b t \054 0 2202 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b t \054 0 2203 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b t \054 0 2204 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b t \054 0 2205 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define REGTYPEARRAYOID 2211 /* @@ -532,25 +540,25 @@ DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in a * argument and result types (if supported by the function's implementation * language). */ -DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p t \054 0 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p t \054 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); #define RECORDOID 2249 -DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out cstring_recv cstring_send - c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out cstring_recv cstring_send - - - c p f 0 -1 0 _null_ _null_ )); #define CSTRINGOID 2275 -DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p t \054 0 0 any_in any_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p t \054 0 0 any_in any_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define ANYOID 2276 -DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f 0 -1 0 _null_ _null_ )); #define ANYARRAYOID 2277 -DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p t \054 0 0 void_in void_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p t \054 0 0 void_in void_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define VOIDOID 2278 -DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p t \054 0 0 trigger_in trigger_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p t \054 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define TRIGGEROID 2279 -DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p t \054 0 0 language_handler_in language_handler_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p t \054 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define LANGUAGE_HANDLEROID 2280 -DATA(insert OID = 2281 ( internal PGNSP PGUID 4 t p t \054 0 0 internal_in internal_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2281 ( internal PGNSP PGUID 4 t p t \054 0 0 internal_in internal_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define INTERNALOID 2281 -DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define OPAQUEOID 2282 -DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define ANYELEMENTOID 2283 /* @@ -569,6 +577,8 @@ extern Oid TypeCreate(const char *typeName, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, + Oid typmodinProcedure, + Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, Oid baseType, @@ -590,6 +600,8 @@ extern void GenerateTypeDependencies(Oid typeNamespace, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, + Oid typmodinProcedure, + Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, Oid baseType, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index bc62c90f4d..5d7fa50673 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.335 2006/12/23 00:43:12 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.336 2006/12/30 21:21:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -167,6 +167,8 @@ typedef struct Query * For TypeName structures generated internally, it is often easier to * specify the type by OID than by name. If "names" is NIL then the * actual type OID is given by typeid, otherwise typeid is unused. + * Similarly, if "typmods" is NIL then the actual typmod is expected to + * be prespecified in typemod, otherwise typemod is unused. * * If pct_type is TRUE, then names is actually a field name and we look up * the type of that field. Otherwise (the normal case), names is a type @@ -180,7 +182,8 @@ typedef struct TypeName bool timezone; /* timezone specified? */ bool setof; /* is a set? */ bool pct_type; /* %TYPE specified? */ - int32 typmod; /* type modifier */ + List *typmods; /* type modifier expression(s) */ + int32 typemod; /* prespecified type modifier */ List *arrayBounds; /* array bounds */ int location; /* token location, or -1 if unknown */ } TypeName; diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index 0d2cf087d1..1e9e616d09 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.33 2006/09/25 15:17:34 tgl Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.34 2006/12/30 21:21:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,8 @@ extern Oid LookupTypeName(ParseState *pstate, const TypeName *typename); 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); diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 791f6ebd99..9c9ff14087 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -49,7 +49,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.60 2006/11/08 19:24:38 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.61 2006/12/30 21:21:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -255,6 +255,7 @@ extern void mda_get_range(int n, int *span, const int *st, const int *endp); extern void mda_get_prod(int n, const int *range, int *prod); extern void mda_get_offset_values(int n, int *dist, const int *prod, const int *span); extern int mda_next_tuple(int n, int *curr, const int *span); +extern int32 *ArrayGetTypmods(ArrayType *arr, int *n); /* * prototypes for functions defined in array_userfuncs.c diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index e1ed7b862b..56e63d7f73 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.282 2006/09/18 22:40:40 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.283 2006/12/30 21:21:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -565,6 +565,8 @@ extern Datum bpcharin(PG_FUNCTION_ARGS); extern Datum bpcharout(PG_FUNCTION_ARGS); extern Datum bpcharrecv(PG_FUNCTION_ARGS); extern Datum bpcharsend(PG_FUNCTION_ARGS); +extern Datum bpchartypmodin(PG_FUNCTION_ARGS); +extern Datum bpchartypmodout(PG_FUNCTION_ARGS); extern Datum bpchar(PG_FUNCTION_ARGS); extern Datum char_bpchar(PG_FUNCTION_ARGS); extern Datum name_bpchar(PG_FUNCTION_ARGS); @@ -586,6 +588,8 @@ extern Datum varcharin(PG_FUNCTION_ARGS); extern Datum varcharout(PG_FUNCTION_ARGS); extern Datum varcharrecv(PG_FUNCTION_ARGS); extern Datum varcharsend(PG_FUNCTION_ARGS); +extern Datum varchartypmodin(PG_FUNCTION_ARGS); +extern Datum varchartypmodout(PG_FUNCTION_ARGS); extern Datum varchar(PG_FUNCTION_ARGS); /* varlena.c */ @@ -789,7 +793,9 @@ extern Datum numeric_in(PG_FUNCTION_ARGS); extern Datum numeric_out(PG_FUNCTION_ARGS); extern Datum numeric_recv(PG_FUNCTION_ARGS); extern Datum numeric_send(PG_FUNCTION_ARGS); -extern Datum numeric (PG_FUNCTION_ARGS); +extern Datum numerictypmodin(PG_FUNCTION_ARGS); +extern Datum numerictypmodout(PG_FUNCTION_ARGS); +extern Datum numeric(PG_FUNCTION_ARGS); extern Datum numeric_abs(PG_FUNCTION_ARGS); extern Datum numeric_uminus(PG_FUNCTION_ARGS); extern Datum numeric_uplus(PG_FUNCTION_ARGS); diff --git a/src/include/utils/date.h b/src/include/utils/date.h index 44eb8e8114..48a6ae1cee 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/date.h,v 1.34 2006/07/13 16:49:20 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/date.h,v 1.35 2006/12/30 21:21:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -140,6 +140,8 @@ extern Datum time_in(PG_FUNCTION_ARGS); extern Datum time_out(PG_FUNCTION_ARGS); extern Datum time_recv(PG_FUNCTION_ARGS); extern Datum time_send(PG_FUNCTION_ARGS); +extern Datum timetypmodin(PG_FUNCTION_ARGS); +extern Datum timetypmodout(PG_FUNCTION_ARGS); extern Datum time_scale(PG_FUNCTION_ARGS); extern Datum time_eq(PG_FUNCTION_ARGS); extern Datum time_ne(PG_FUNCTION_ARGS); @@ -166,6 +168,8 @@ extern Datum timetz_in(PG_FUNCTION_ARGS); extern Datum timetz_out(PG_FUNCTION_ARGS); extern Datum timetz_recv(PG_FUNCTION_ARGS); extern Datum timetz_send(PG_FUNCTION_ARGS); +extern Datum timetztypmodin(PG_FUNCTION_ARGS); +extern Datum timetztypmodout(PG_FUNCTION_ARGS); extern Datum timetz_scale(PG_FUNCTION_ARGS); extern Datum timetz_eq(PG_FUNCTION_ARGS); extern Datum timetz_ne(PG_FUNCTION_ARGS); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 272b321e64..e78236b218 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.108 2006/12/23 00:43:13 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.109 2006/12/30 21:21:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -100,6 +100,7 @@ extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam); extern void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena); extern void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam); extern void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena); +extern Oid get_typmodin(Oid typid); extern Oid getBaseType(Oid typid); extern Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod); extern int32 get_typavgwidth(Oid typid, int32 typmod); diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 0c6e59cc92..3bbd63ba45 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.64 2006/10/04 00:30:11 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.65 2006/12/30 21:21:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -200,6 +200,8 @@ extern Datum timestamp_in(PG_FUNCTION_ARGS); extern Datum timestamp_out(PG_FUNCTION_ARGS); extern Datum timestamp_recv(PG_FUNCTION_ARGS); extern Datum timestamp_send(PG_FUNCTION_ARGS); +extern Datum timestamptypmodin(PG_FUNCTION_ARGS); +extern Datum timestamptypmodout(PG_FUNCTION_ARGS); extern Datum timestamp_scale(PG_FUNCTION_ARGS); extern Datum timestamp_eq(PG_FUNCTION_ARGS); extern Datum timestamp_ne(PG_FUNCTION_ARGS); @@ -232,6 +234,8 @@ extern Datum interval_in(PG_FUNCTION_ARGS); extern Datum interval_out(PG_FUNCTION_ARGS); extern Datum interval_recv(PG_FUNCTION_ARGS); extern Datum interval_send(PG_FUNCTION_ARGS); +extern Datum intervaltypmodin(PG_FUNCTION_ARGS); +extern Datum intervaltypmodout(PG_FUNCTION_ARGS); extern Datum interval_scale(PG_FUNCTION_ARGS); extern Datum interval_eq(PG_FUNCTION_ARGS); extern Datum interval_ne(PG_FUNCTION_ARGS); @@ -264,6 +268,8 @@ extern Datum timestamptz_in(PG_FUNCTION_ARGS); extern Datum timestamptz_out(PG_FUNCTION_ARGS); extern Datum timestamptz_recv(PG_FUNCTION_ARGS); extern Datum timestamptz_send(PG_FUNCTION_ARGS); +extern Datum timestamptztypmodin(PG_FUNCTION_ARGS); +extern Datum timestamptztypmodout(PG_FUNCTION_ARGS); extern Datum timestamptz_scale(PG_FUNCTION_ARGS); extern Datum timestamptz_timestamp(PG_FUNCTION_ARGS); extern Datum timestamptz_zone(PG_FUNCTION_ARGS); diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h index 793d28d383..f0fb87e71e 100644 --- a/src/include/utils/varbit.h +++ b/src/include/utils/varbit.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/varbit.h,v 1.23 2006/03/05 15:59:08 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/varbit.h,v 1.24 2006/12/30 21:21:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,10 +64,14 @@ extern Datum bit_in(PG_FUNCTION_ARGS); extern Datum bit_out(PG_FUNCTION_ARGS); extern Datum bit_recv(PG_FUNCTION_ARGS); extern Datum bit_send(PG_FUNCTION_ARGS); +extern Datum bittypmodin(PG_FUNCTION_ARGS); +extern Datum bittypmodout(PG_FUNCTION_ARGS); extern Datum varbit_in(PG_FUNCTION_ARGS); extern Datum varbit_out(PG_FUNCTION_ARGS); extern Datum varbit_recv(PG_FUNCTION_ARGS); extern Datum varbit_send(PG_FUNCTION_ARGS); +extern Datum varbittypmodin(PG_FUNCTION_ARGS); +extern Datum varbittypmodout(PG_FUNCTION_ARGS); extern Datum bit(PG_FUNCTION_ARGS); extern Datum varbit(PG_FUNCTION_ARGS); extern Datum biteq(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 3e2edeb1e0..133ad857ac 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -10,6 +10,8 @@ CREATE TYPE widget ( internallength = 24, input = widget_in, output = widget_out, + typmod_in = numerictypmodin, + typmod_out = numerictypmodout, alignment = double ); CREATE TYPE city_budget ( @@ -99,3 +101,15 @@ ERROR: type "text_w_default" already exists DROP TYPE default_test_row CASCADE; NOTICE: drop cascades to function get_default_test() DROP TABLE default_test; +-- Check usage of typmod with a user-defined type +-- (we have borrowed numeric's typmod functions) +CREATE TEMP TABLE mytab (foo widget(42,13,7)); -- should fail +ERROR: invalid NUMERIC type modifier +CREATE TEMP TABLE mytab (foo widget(42,13)); +SELECT format_type(atttypid,atttypmod) FROM pg_attribute +WHERE attrelid = 'mytab'::regclass AND attnum > 0; + format_type +--------------- + widget(42,13) +(1 row) + diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index 3aa8e3714b..f8cc66492c 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -840,8 +840,12 @@ SELECT time '03:30' + interval '1 month 04:01' AS "07:31:00"; SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01"; ERROR: cannot cast type time with time zone to interval +LINE 1: SELECT CAST(time with time zone '01:02-08' AS interval) AS "... + ^ SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08"; ERROR: cannot cast type interval to time with time zone +LINE 1: SELECT CAST(interval '02:03' AS time with time zone) AS "02:... + ^ SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08"; 23:29:00-08 ------------- diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index cc82b12e02..5945753a1b 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -753,6 +753,22 @@ WHERE typsend != 0 AND ------+--------- (0 rows) +SELECT ctid, typmodin +FROM pg_catalog.pg_type fk +WHERE typmodin != 0 AND + NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin); + ctid | typmodin +------+---------- +(0 rows) + +SELECT ctid, typmodout +FROM pg_catalog.pg_type fk +WHERE typmodout != 0 AND + NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout); + ctid | typmodout +------+----------- +(0 rows) + SELECT ctid, typbasetype FROM pg_catalog.pg_type fk WHERE typbasetype != 0 AND diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 73d51925c2..11c9298e9a 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -212,6 +212,48 @@ WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT -----+---------+-----+--------- (0 rows) +-- Check for bogus typmodin routines +SELECT p1.oid, p1.typname, p2.oid, p2.proname +FROM pg_type AS p1, pg_proc AS p2 +WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT + (p2.pronargs = 1 AND + p2.proargtypes[0] = 'int4[]'::regtype AND + p2.prorettype = 'int4'::regtype AND NOT p2.proretset); + oid | typname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- Check for bogus typmodout routines +SELECT p1.oid, p1.typname, p2.oid, p2.proname +FROM pg_type AS p1, pg_proc AS p2 +WHERE p1.typmodout = p2.oid AND p1.typtype in ('b', 'p') AND NOT + (p2.pronargs = 1 AND + p2.proargtypes[0] = 'int4'::regtype AND + p2.prorettype = 'cstring'::regtype AND NOT p2.proretset); + oid | typname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- Array types should have same typmodin/out as their element types +SELECT p1.oid, p1.typname, p2.oid, p2.typname +FROM pg_type AS p1, pg_type AS p2 +WHERE p1.typelem = p2.oid AND NOT + (p1.typmodin = p2.typmodin AND p1.typmodout = p2.typmodout); + oid | typname | oid | typname +-----+---------+-----+--------- +(0 rows) + +-- Check for bogus typanalyze routines +SELECT p1.oid, p1.typname, p2.oid, p2.proname +FROM pg_type AS p1, pg_proc AS p2 +WHERE p1.typanalyze = p2.oid AND p1.typtype in ('b', 'p') AND NOT + (p2.pronargs = 1 AND + p2.proargtypes[0] = 'internal'::regtype AND + p2.prorettype = 'bool'::regtype AND NOT p2.proretset); + oid | typname | oid | proname +-----+---------+-----+--------- +(0 rows) + -- **************** pg_class **************** -- Look for illegal values in pg_class fields SELECT p1.oid, p1.relname diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index 097d51fc92..c6e391d810 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -11,6 +11,8 @@ CREATE TYPE widget ( internallength = 24, input = widget_in, output = widget_out, + typmod_in = numerictypmodin, + typmod_out = numerictypmodout, alignment = double ); @@ -98,3 +100,12 @@ CREATE TYPE text_w_default; -- should fail DROP TYPE default_test_row CASCADE; DROP TABLE default_test; + +-- Check usage of typmod with a user-defined type +-- (we have borrowed numeric's typmod functions) + +CREATE TEMP TABLE mytab (foo widget(42,13,7)); -- should fail +CREATE TEMP TABLE mytab (foo widget(42,13)); + +SELECT format_type(atttypid,atttypmod) FROM pg_attribute +WHERE attrelid = 'mytab'::regclass AND attnum > 0; diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql index bf713e9fa7..5eb440f0f5 100644 --- a/src/test/regress/sql/oidjoins.sql +++ b/src/test/regress/sql/oidjoins.sql @@ -377,6 +377,14 @@ SELECT ctid, typsend FROM pg_catalog.pg_type fk WHERE typsend != 0 AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend); +SELECT ctid, typmodin +FROM pg_catalog.pg_type fk +WHERE typmodin != 0 AND + NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodin); +SELECT ctid, typmodout +FROM pg_catalog.pg_type fk +WHERE typmodout != 0 AND + NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typmodout); SELECT ctid, typbasetype FROM pg_catalog.pg_type fk WHERE typbasetype != 0 AND diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 3969b4cce2..3677b90ceb 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -163,6 +163,40 @@ FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT (p2.prorettype = 'bytea'::regtype AND NOT p2.proretset); +-- Check for bogus typmodin routines + +SELECT p1.oid, p1.typname, p2.oid, p2.proname +FROM pg_type AS p1, pg_proc AS p2 +WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT + (p2.pronargs = 1 AND + p2.proargtypes[0] = 'int4[]'::regtype AND + p2.prorettype = 'int4'::regtype AND NOT p2.proretset); + +-- Check for bogus typmodout routines + +SELECT p1.oid, p1.typname, p2.oid, p2.proname +FROM pg_type AS p1, pg_proc AS p2 +WHERE p1.typmodout = p2.oid AND p1.typtype in ('b', 'p') AND NOT + (p2.pronargs = 1 AND + p2.proargtypes[0] = 'int4'::regtype AND + p2.prorettype = 'cstring'::regtype AND NOT p2.proretset); + +-- Array types should have same typmodin/out as their element types + +SELECT p1.oid, p1.typname, p2.oid, p2.typname +FROM pg_type AS p1, pg_type AS p2 +WHERE p1.typelem = p2.oid AND NOT + (p1.typmodin = p2.typmodin AND p1.typmodout = p2.typmodout); + +-- Check for bogus typanalyze routines + +SELECT p1.oid, p1.typname, p2.oid, p2.proname +FROM pg_type AS p1, pg_proc AS p2 +WHERE p1.typanalyze = p2.oid AND p1.typtype in ('b', 'p') AND NOT + (p2.pronargs = 1 AND + p2.proargtypes[0] = 'internal'::regtype AND + p2.prorettype = 'bool'::regtype AND NOT p2.proretset); + -- **************** pg_class **************** -- Look for illegal values in pg_class fields diff --git a/src/tools/findoidjoins/README b/src/tools/findoidjoins/README index aec8f1bd8d..598aab2bbd 100644 --- a/src/tools/findoidjoins/README +++ b/src/tools/findoidjoins/README @@ -130,6 +130,8 @@ Join pg_catalog.pg_type.typinput => pg_catalog.pg_proc.oid Join pg_catalog.pg_type.typoutput => pg_catalog.pg_proc.oid Join pg_catalog.pg_type.typreceive => pg_catalog.pg_proc.oid Join pg_catalog.pg_type.typsend => pg_catalog.pg_proc.oid +Join pg_catalog.pg_type.typmodin => pg_catalog.pg_proc.oid +Join pg_catalog.pg_type.typmodout => pg_catalog.pg_proc.oid Join pg_catalog.pg_type.typbasetype => pg_catalog.pg_type.oid ---------------------------------------------------------------------------