From 5725b9d9afc8c3ba24e94cbc7020889fe8ad7ef9 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> 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 a906623ac9a..2d42280f50e 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.139 2006/12/23 00:43:08 tgl Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.140 2006/12/30 21:21:52 tgl Exp $ --> <!-- Documentation of the system catalogs, directed toward PostgreSQL developers --> @@ -4393,6 +4393,20 @@ <entry>Output conversion function (binary format), or 0 if none</entry> </row> + <row> + <entry><structfield>typmodin</structfield></entry> + <entry><type>regproc</type></entry> + <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry> + <entry>Type modifier input function, or 0 if type does not support modifiers</entry> + </row> + + <row> + <entry><structfield>typmodout</structfield></entry> + <entry><type>regproc</type></entry> + <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry> + <entry>Type modifier output function, or 0 to use the standard format</entry> + </row> + <row> <entry><structfield>typanalyze</structfield></entry> <entry><type>regproc</type></entry> diff --git a/doc/src/sgml/keywords.sgml b/doc/src/sgml/keywords.sgml index c82b3b6f1b9..b9565b3283c 100644 --- a/doc/src/sgml/keywords.sgml +++ b/doc/src/sgml/keywords.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.18 2006/10/08 20:51:52 petere Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.19 2006/12/30 21:21:52 tgl Exp $ --> <appendix id="sql-keywords-appendix"> <title><acronym>SQL</acronym> Key Words</title> @@ -45,16 +45,17 @@ In <xref linkend="keywords-table"> in the column for <productname>PostgreSQL</productname> we classify as <quote>non-reserved</quote> 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 - <quote>reserved</quote> are those tokens that are only allowed as - <quote>AS</quote> 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. + <quote>reserved</quote> 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 + <quote>AS</quote> column label name. </para> <para> @@ -326,7 +327,7 @@ </row> <row> <entry><token>AUTHORIZATION</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -368,7 +369,7 @@ </row> <row> <entry><token>BETWEEN</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>non-reserved</entry> <entry>reserved</entry> @@ -382,7 +383,7 @@ </row> <row> <entry><token>BINARY</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry></entry> @@ -956,7 +957,7 @@ </row> <row> <entry><token>CROSS</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -1642,7 +1643,7 @@ </row> <row> <entry><token>FREEZE</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry></entry> <entry></entry> <entry></entry> @@ -1656,7 +1657,7 @@ </row> <row> <entry><token>FULL</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -1831,7 +1832,7 @@ </row> <row> <entry><token>ILIKE</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry></entry> <entry></entry> <entry></entry> @@ -1943,7 +1944,7 @@ </row> <row> <entry><token>INNER</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -2048,14 +2049,14 @@ </row> <row> <entry><token>IS</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> </row> <row> <entry><token>ISNULL</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry></entry> <entry></entry> <entry></entry> @@ -2076,7 +2077,7 @@ </row> <row> <entry><token>JOIN</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -2160,7 +2161,7 @@ </row> <row> <entry><token>LEFT</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -2188,7 +2189,7 @@ </row> <row> <entry><token>LIKE</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -2475,7 +2476,7 @@ </row> <row> <entry><token>NATURAL</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -2608,7 +2609,7 @@ </row> <row> <entry><token>NOTNULL</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry></entry> <entry></entry> <entry></entry> @@ -2811,7 +2812,7 @@ </row> <row> <entry><token>OUTER</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -2832,7 +2833,7 @@ </row> <row> <entry><token>OVERLAPS</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>non-reserved</entry> <entry>reserved</entry> @@ -3385,7 +3386,7 @@ </row> <row> <entry><token>RIGHT</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>reserved</entry> <entry>reserved</entry> @@ -3658,7 +3659,7 @@ </row> <row> <entry><token>SIMILAR</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry>reserved</entry> <entry>non-reserved</entry> <entry></entry> @@ -4414,7 +4415,7 @@ </row> <row> <entry><token>VERBOSE</token></entry> - <entry>reserved (can be function)</entry> + <entry>reserved (can be function or type)</entry> <entry></entry> <entry></entry> <entry></entry> diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index e85c94dbe74..2f1f6eab3c4 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.65 2006/12/23 01:28:09 momjian Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.66 2006/12/30 21:21:52 tgl Exp $ PostgreSQL documentation --> @@ -28,6 +28,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ( OUTPUT = <replaceable class="parameter">output_function</replaceable> [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ] [ , SEND = <replaceable class="parameter">send_function</replaceable> ] + [ , TYPMOD_IN = <replaceable class="parameter">type_modifier_input_function</replaceable> ] + [ , TYPMOD_OUT = <replaceable class="parameter">type_modifier_output_function</replaceable> ] [ , ANALYZE = <replaceable class="parameter">analyze_function</replaceable> ] [ , INTERNALLENGTH = { <replaceable class="parameter">internallength</replaceable> | VARIABLE } ] [ , PASSEDBYVALUE ] @@ -83,12 +85,14 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (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 <command>CREATE FUNCTION</command>) before - defining the type. The support functions + defining the type. The support functions <replaceable class="parameter">input_function</replaceable> and <replaceable class="parameter">output_function</replaceable> are required, while the functions <replaceable class="parameter">receive_function</replaceable>, - <replaceable class="parameter">send_function</replaceable> and + <replaceable class="parameter">send_function</replaceable>, + <replaceable class="parameter">type_modifier_input_function</replaceable>, + <replaceable class="parameter">type_modifier_output_function</replaceable> and <replaceable class="parameter">analyze_function</replaceable> are optional. Generally these functions have to be coded in C or another low-level language. @@ -169,6 +173,34 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> used normally. </para> + <para> + The optional + <replaceable class="parameter">type_modifier_input_function</replaceable> + and <replaceable class="parameter">type_modifier_output_function</replaceable> + are needed if the type supports modifiers, that is optional constraints + attached to a type declaration, such as <literal>char(5)</> or + <literal>numeric(30,2)</>. <productname>PostgreSQL</productname> 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 + <replaceable class="parameter">type_modifier_input_function</replaceable> + is passed the declared modifier(s) in the form of an <type>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 + <type>integer</> value that will be stored as the column <quote>typmod</>. + Type modifiers will be rejected if the type does not have a + <replaceable class="parameter">type_modifier_input_function</replaceable>. + The <replaceable class="parameter">type_modifier_output_function</replaceable> + converts the internal integer typmod value back to the correct form for + user display. It must return a <type>cstring</> value that is the exact + string to append to the type name; for example <type>numeric</>'s + function might return <literal>(30,2)</>. + It is allowed to omit the + <replaceable class="parameter">type_modifier_output_function</replaceable>, + in which case the default display format is just the stored typmod value + enclosed in parentheses. + </para> + <para> The optional <replaceable class="parameter">analyze_function</replaceable> performs type-specific statistics collection for columns of the data type. @@ -265,7 +297,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> <title>Array Types</title> <para> - Whenever a user-defined base data type is created, + Whenever a user-defined base data type is created, <productname>PostgreSQL</productname> 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 <replaceable class="parameter">name</replaceable> </para> </refsect2> </refsect1> - + <refsect1> <title>Parameters</title> @@ -371,6 +403,26 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> </listitem> </varlistentry> + <varlistentry> + <term><replaceable class="parameter">type_modifier_input_function</replaceable></term> + <listitem> + <para> + The name of a function that converts numeric modifier(s) for the type + into internal form. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><replaceable class="parameter">type_modifier_output_function</replaceable></term> + <listitem> + <para> + The name of a function that converts the internal form of the type's + modifier(s) to external textual form. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><replaceable class="parameter">analyze_function</replaceable></term> <listitem> @@ -499,7 +551,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> </para> </refsect1> - + <refsect1> <title>Examples</title> diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 6242afa20f3..be5665db79c 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 d6822c73c69..41ef41c7c17 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 32de0b90dc1..74517124fbd 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 2a1116f7580..c30aa69c555 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 53cca73a9dd..2b26f2dfa14 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 d46ed57d830..c8c9b907c9c 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 29bff448c7f..57e61f0e2a2 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 9f6aa22707b..277103e4a18 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 4911d6ed404..2b21eae6a10 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 a1511870f28..c4820190f07 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 <str> relation_name copy_file_name database_name access_method_clause access_method attr_name - index_name name function_name file_name + index_name name file_name %type <list> func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_validator @@ -242,7 +242,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) group_clause TriggerFuncArgs select_limit opt_select_limit opclass_item_list transaction_mode_list_or_empty - TableFuncElementList + TableFuncElementList opt_type_modifiers prep_type_clause prep_type_list execute_param_clause using_clause returning_clause @@ -319,20 +319,19 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) %type <str> character %type <str> extract_arg %type <str> opt_charset -%type <ival> opt_numeric opt_decimal %type <boolean> opt_varying opt_timezone %type <ival> Iconst SignedIconst %type <str> Sconst comment_text %type <str> RoleId opt_granted_by opt_boolean ColId_or_Sconst %type <list> var_list var_list_or_default -%type <str> ColId ColLabel var_name type_name param_name +%type <str> ColId ColLabel var_name type_function_name param_name %type <node> var_value zone_value -%type <keyword> unreserved_keyword func_name_keyword +%type <keyword> unreserved_keyword type_func_name_keyword %type <keyword> col_name_keyword reserved_keyword -%type <node> TableConstraint TableLikeClause +%type <node> TableConstraint TableLikeClause %type <list> TableLikeOptionList %type <ival> TableLikeOption %type <list> ColQualList @@ -1180,35 +1179,20 @@ zone_value: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("time zone interval must be HOUR or HOUR TO MINUTE"))); - n->typename->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $3); + n->typename->typmods = list_make1(makeIntConst($3)); } $$ = (Node *)n; } | ConstInterval '(' Iconst ')' Sconst opt_interval { A_Const *n = (A_Const *) makeStringConst($5, $1); - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("INTERVAL(%d) precision must not be negative", - $3))); - if ($3 > MAX_INTERVAL_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", - $3, MAX_INTERVAL_PRECISION))); - $3 = MAX_INTERVAL_PRECISION; - } - if (($6 != INTERVAL_FULL_RANGE) && (($6 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("time zone interval must be HOUR or HOUR TO MINUTE"))); - - n->typename->typmod = INTERVAL_TYPMOD($3, $6); - + n->typename->typmods = list_make2(makeIntConst($6), + makeIntConst($3)); $$ = (Node *)n; } | NumericOnly { $$ = makeAConst($1); } @@ -2823,7 +2807,7 @@ DefineStmt: n->definition = $4; $$ = (Node *)n; } - | CREATE TYPE_P any_name + | CREATE TYPE_P any_name { /* Shell type (identified by lack of definition) */ DefineStmt *n = makeNode(DefineStmt); @@ -2889,7 +2873,6 @@ def_elem: ColLabel '=' def_arg /* Note: any simple identifier will be returned as a type name! */ def_arg: func_type { $$ = (Node *)$1; } - | func_name_keyword { $$ = (Node *)makeString(pstrdup($1)); } | reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); } | qual_all_Op { $$ = (Node *)$1; } | NumericOnly { $$ = (Node *)$1; } @@ -3047,7 +3030,7 @@ ReassignOwnedStmt: * * QUERY: * - * DROP itemtype [ IF EXISTS ] itemname [, itemname ...] + * DROP itemtype [ IF EXISTS ] itemname [, itemname ...] * [ RESTRICT | CASCADE ] * *****************************************************************************/ @@ -3872,7 +3855,7 @@ arg_class: IN_P { $$ = FUNC_PARAM_IN; } /* * Ideally param_name should be ColId, but that causes too many conflicts. */ -param_name: function_name +param_name: type_function_name ; func_return: @@ -3888,23 +3871,20 @@ func_return: /* * We would like to make the %TYPE productions here be ColId attrs etc, - * but that causes reduce/reduce conflicts. type_name is next best choice. + * but that causes reduce/reduce conflicts. type_function_name + * is next best choice. */ func_type: Typename { $$ = $1; } - | type_name attrs '%' TYPE_P + | type_function_name attrs '%' TYPE_P { - $$ = makeNode(TypeName); - $$->names = lcons(makeString($1), $2); + $$ = makeTypeNameFromNameList(lcons(makeString($1), $2)); $$->pct_type = true; - $$->typmod = -1; $$->location = @1; } - | SETOF type_name attrs '%' TYPE_P + | SETOF type_function_name attrs '%' TYPE_P { - $$ = makeNode(TypeName); - $$->names = lcons(makeString($2), $3); + $$ = makeTypeNameFromNameList(lcons(makeString($2), $3)); $$->pct_type = true; - $$->typmod = -1; $$->setof = TRUE; $$->location = @2; } @@ -5552,7 +5532,7 @@ multiple_set_clause: res_col->val = res_val; } - + $$ = $2; } ; @@ -6363,14 +6343,6 @@ opt_array_bounds: { $$ = NIL; } ; -/* - * XXX ideally, the production for a qualified typename should be ColId attrs - * (there's no obvious reason why the first name should need to be restricted) - * and should be an alternative of GenericType (so that it can be used to - * specify a type for a literal in AExprConst). However doing either causes - * reduce/reduce conflicts that I haven't been able to find a workaround - * for. FIXME later. - */ SimpleTypename: GenericType { $$ = $1; } | Numeric { $$ = $1; } @@ -6381,32 +6353,13 @@ SimpleTypename: { $$ = $1; if ($2 != INTERVAL_FULL_RANGE) - $$->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $2); + $$->typmods = list_make1(makeIntConst($2)); } | ConstInterval '(' Iconst ')' opt_interval { $$ = $1; - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("INTERVAL(%d) precision must not be negative", - $3))); - if ($3 > MAX_INTERVAL_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", - $3, MAX_INTERVAL_PRECISION))); - $3 = MAX_INTERVAL_PRECISION; - } - $$->typmod = INTERVAL_TYPMOD($3, $5); - } - | type_name attrs - { - $$ = makeNode(TypeName); - $$->names = lcons(makeString($1), $2); - $$->typmod = -1; - $$->location = @1; + $$->typmods = list_make2(makeIntConst($5), + makeIntConst($3)); } ; @@ -6417,80 +6370,112 @@ SimpleTypename: * where there is an obvious better choice to make. * Note that ConstInterval is not included here since it must * be pushed up higher in the rules to accomodate the postfix - * options (e.g. INTERVAL '1' YEAR). + * options (e.g. INTERVAL '1' YEAR). Likewise, we have to handle + * the generic-type-name case in AExprConst to avoid premature + * reduce/reduce conflicts against function names. */ ConstTypename: - GenericType { $$ = $1; } - | Numeric { $$ = $1; } + Numeric { $$ = $1; } | ConstBit { $$ = $1; } | ConstCharacter { $$ = $1; } | ConstDatetime { $$ = $1; } ; +/* + * GenericType covers all type names that don't have special syntax mandated + * by the standard, including qualified names. We also allow type modifiers. + * To avoid parsing conflicts against function invocations, the modifiers + * have to be shown as expr_list here, but parse analysis will only accept + * integer constants for them. + */ GenericType: - type_name + type_function_name opt_type_modifiers { $$ = makeTypeName($1); + $$->typmods = $2; + $$->location = @1; + } + | type_function_name attrs opt_type_modifiers + { + $$ = makeTypeNameFromNameList(lcons(makeString($1), $2)); + $$->typmods = $3; $$->location = @1; } ; -/* SQL92 numeric data types - * Check FLOAT() precision limits assuming IEEE floating types. - * - thomas 1997-09-18 - * Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30 +opt_type_modifiers: '(' expr_list ')' { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; + +/* + * SQL92 numeric data types */ Numeric: INT_P { $$ = SystemTypeName("int4"); + $$->location = @1; } | INTEGER { $$ = SystemTypeName("int4"); + $$->location = @1; } | SMALLINT { $$ = SystemTypeName("int2"); + $$->location = @1; } | BIGINT { $$ = SystemTypeName("int8"); + $$->location = @1; } | REAL { $$ = SystemTypeName("float4"); + $$->location = @1; } | FLOAT_P opt_float { $$ = $2; + $$->location = @1; } | DOUBLE_P PRECISION { $$ = SystemTypeName("float8"); + $$->location = @1; } - | DECIMAL_P opt_decimal + | DECIMAL_P opt_type_modifiers { $$ = SystemTypeName("numeric"); - $$->typmod = $2; + $$->typmods = $2; + $$->location = @1; } - | DEC opt_decimal + | DEC opt_type_modifiers { $$ = SystemTypeName("numeric"); - $$->typmod = $2; + $$->typmods = $2; + $$->location = @1; } - | NUMERIC opt_numeric + | NUMERIC opt_type_modifiers { $$ = SystemTypeName("numeric"); - $$->typmod = $2; + $$->typmods = $2; + $$->location = @1; } | BOOLEAN_P { $$ = SystemTypeName("bool"); + $$->location = @1; } ; opt_float: '(' Iconst ')' { + /* + * Check FLOAT() precision limits assuming IEEE floating + * types - thomas 1997-09-18 + */ if ($2 < 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -6510,73 +6495,6 @@ opt_float: '(' Iconst ')' } ; -opt_numeric: - '(' Iconst ',' Iconst ')' - { - if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("NUMERIC precision %d must be between 1 and %d", - $2, NUMERIC_MAX_PRECISION))); - if ($4 < 0 || $4 > $2) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("NUMERIC scale %d must be between 0 and precision %d", - $4, $2))); - - $$ = (($2 << 16) | $4) + VARHDRSZ; - } - | '(' Iconst ')' - { - if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("NUMERIC precision %d must be between 1 and %d", - $2, NUMERIC_MAX_PRECISION))); - - $$ = ($2 << 16) + VARHDRSZ; - } - | /*EMPTY*/ - { - /* Insert "-1" meaning "no limit" */ - $$ = -1; - } - ; - -opt_decimal: - '(' Iconst ',' Iconst ')' - { - if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("DECIMAL precision %d must be between 1 and %d", - $2, NUMERIC_MAX_PRECISION))); - if ($4 < 0 || $4 > $2) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("DECIMAL scale %d must be between 0 and precision %d", - $4, $2))); - - $$ = (($2 << 16) | $4) + VARHDRSZ; - } - | '(' Iconst ')' - { - if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("DECIMAL precision %d must be between 1 and %d", - $2, NUMERIC_MAX_PRECISION))); - - $$ = ($2 << 16) + VARHDRSZ; - } - | /*EMPTY*/ - { - /* Insert "-1" meaning "no limit" */ - $$ = -1; - } - ; - - /* * SQL92 bit-field data types * The following implements BIT() and BIT VARYING(). @@ -6600,28 +6518,19 @@ ConstBit: BitWithLength | BitWithoutLength { $$ = $1; - $$->typmod = -1; + $$->typmods = NIL; } ; BitWithLength: - BIT opt_varying '(' Iconst ')' + BIT opt_varying '(' expr_list ')' { char *typname; typname = $2 ? "varbit" : "bit"; $$ = SystemTypeName(typname); - if ($4 < 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("length for type %s must be at least 1", - typname))); - else if ($4 > (MaxAttrSize * BITS_PER_BYTE)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("length for type %s cannot exceed %d", - typname, MaxAttrSize * BITS_PER_BYTE))); - $$->typmod = $4; + $$->typmods = $4; + $$->location = @1; } ; @@ -6632,13 +6541,13 @@ BitWithoutLength: if ($2) { $$ = SystemTypeName("varbit"); - $$->typmod = -1; } else { $$ = SystemTypeName("bit"); - $$->typmod = 1; + $$->typmods = list_make1(makeIntConst(1)); } + $$->location = @1; } ; @@ -6670,7 +6579,7 @@ ConstCharacter: CharacterWithLength * was not specified. */ $$ = $1; - $$->typmod = -1; + $$->typmods = NIL; } ; @@ -6688,24 +6597,8 @@ CharacterWithLength: character '(' Iconst ')' opt_charset } $$ = SystemTypeName($1); - - if ($3 < 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("length for type %s must be at least 1", - $1))); - else if ($3 > MaxAttrSize) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("length for type %s cannot exceed %d", - $1, MaxAttrSize))); - - /* we actually implement these like a varlen, so - * the first 4 bytes is the length. (the difference - * between these and "text" is that we blank-pad and - * truncate where necessary) - */ - $$->typmod = VARHDRSZ + $3; + $$->typmods = list_make1(makeIntConst($3)); + $$->location = @1; } ; @@ -6726,9 +6619,9 @@ CharacterWithoutLength: character opt_charset /* char defaults to char(1), varchar to no limit */ if (strcmp($1, "bpchar") == 0) - $$->typmod = VARHDRSZ + 1; - else - $$->typmod = -1; + $$->typmods = list_make1(makeIntConst(1)); + + $$->location = @1; } ; @@ -6756,6 +6649,9 @@ opt_charset: | /*EMPTY*/ { $$ = NULL; } ; +/* + * SQL92 date/time types + */ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone { @@ -6767,21 +6663,8 @@ ConstDatetime: * - thomas 2001-09-06 */ $$->timezone = $5; - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("TIMESTAMP(%d)%s precision must not be negative", - $3, ($5 ? " WITH TIME ZONE": "")))); - if ($3 > MAX_TIMESTAMP_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d", - $3, ($5 ? " WITH TIME ZONE": ""), - MAX_TIMESTAMP_PRECISION))); - $3 = MAX_TIMESTAMP_PRECISION; - } - $$->typmod = $3; + $$->typmods = list_make1(makeIntConst($3)); + $$->location = @1; } | TIMESTAMP opt_timezone { @@ -6793,6 +6676,7 @@ ConstDatetime: * - thomas 2001-09-06 */ $$->timezone = $2; + $$->location = @1; } | TIME '(' Iconst ')' opt_timezone { @@ -6800,21 +6684,8 @@ ConstDatetime: $$ = SystemTypeName("timetz"); else $$ = SystemTypeName("time"); - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("TIME(%d)%s precision must not be negative", - $3, ($5 ? " WITH TIME ZONE": "")))); - if ($3 > MAX_TIME_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("TIME(%d)%s precision reduced to maximum allowed, %d", - $3, ($5 ? " WITH TIME ZONE": ""), - MAX_TIME_PRECISION))); - $3 = MAX_TIME_PRECISION; - } - $$->typmod = $3; + $$->typmods = list_make1(makeIntConst($3)); + $$->location = @1; } | TIME opt_timezone { @@ -6822,11 +6693,16 @@ ConstDatetime: $$ = SystemTypeName("timetz"); else $$ = SystemTypeName("time"); + $$->location = @1; } ; ConstInterval: - INTERVAL { $$ = SystemTypeName("interval"); } + INTERVAL + { + $$ = SystemTypeName("interval"); + $$->location = @1; + } ; opt_timezone: @@ -7520,20 +7396,7 @@ func_expr: func_name '(' ')' s->val.val.str = "now"; s->typename = SystemTypeName("text"); d = SystemTypeName("timetz"); - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("CURRENT_TIME(%d) precision must not be negative", - $3))); - if ($3 > MAX_TIME_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("CURRENT_TIME(%d) precision reduced to maximum allowed, %d", - $3, MAX_TIME_PRECISION))); - $3 = MAX_TIME_PRECISION; - } - d->typmod = $3; + d->typmods = list_make1(makeIntConst($3)); $$ = (Node *)makeTypeCast((Node *)s, d); } @@ -7565,20 +7428,7 @@ func_expr: func_name '(' ')' s->typename = SystemTypeName("text"); d = SystemTypeName("timestamptz"); - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("CURRENT_TIMESTAMP(%d) precision must not be negative", - $3))); - if ($3 > MAX_TIMESTAMP_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("CURRENT_TIMESTAMP(%d) precision reduced to maximum allowed, %d", - $3, MAX_TIMESTAMP_PRECISION))); - $3 = MAX_TIMESTAMP_PRECISION; - } - d->typmod = $3; + d->typmods = list_make1(makeIntConst($3)); $$ = (Node *)makeTypeCast((Node *)s, d); } @@ -7612,20 +7462,7 @@ func_expr: func_name '(' ')' s->val.val.str = "now"; s->typename = SystemTypeName("text"); d = SystemTypeName("time"); - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("LOCALTIME(%d) precision must not be negative", - $3))); - if ($3 > MAX_TIME_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("LOCALTIME(%d) precision reduced to maximum allowed, %d", - $3, MAX_TIME_PRECISION))); - $3 = MAX_TIME_PRECISION; - } - d->typmod = $3; + d->typmods = list_make1(makeIntConst($3)); $$ = (Node *)makeTypeCast((Node *)s, d); } @@ -7660,20 +7497,7 @@ func_expr: func_name '(' ')' s->typename = SystemTypeName("text"); d = SystemTypeName("timestamp"); - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("LOCALTIMESTAMP(%d) precision must not be negative", - $3))); - if ($3 > MAX_TIMESTAMP_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("LOCALTIMESTAMP(%d) precision reduced to maximum allowed, %d", - $3, MAX_TIMESTAMP_PRECISION))); - $3 = MAX_TIMESTAMP_PRECISION; - } - d->typmod = $3; + d->typmods = list_make1(makeIntConst($3)); $$ = (Node *)makeTypeCast((Node *)s, d); } @@ -7880,7 +7704,7 @@ func_expr: func_name '(' ')' $$ = (Node *)v; } | XMLCONCAT '(' expr_list ')' - { + { $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3); } | XMLELEMENT '(' NAME_P ColLabel ')' @@ -7985,7 +7809,7 @@ xml_attribute_el: a_expr AS ColLabel $$ = makeNode(ResTarget); $$->name = NULL; $$->indirection = NULL; - $$->val = (Node *) $1; + $$->val = (Node *) $1; $$->location = @1; } ; @@ -8486,12 +8310,12 @@ file_name: Sconst { $$ = $1; }; /* * The production for a qualified func_name has to exactly match the * production for a qualified columnref, because we cannot tell which we - * are parsing until we see what comes after it ('(' for a func_name, + * are parsing until we see what comes after it ('(' or Sconst for a func_name, * anything else for a columnref). Therefore we allow 'indirection' which * may contain subscripts, and reject that case in the C code. (If we * ever implement SQL99-like methods, such syntax may actually become legal!) */ -func_name: function_name +func_name: type_function_name { $$ = list_make1(makeString($1)); } | relation_name indirection { $$ = check_func_name(lcons(makeString($1), $2)); } @@ -8541,6 +8365,27 @@ AexprConst: Iconst n->val.val.str = $1; $$ = (Node *)n; } + | func_name Sconst + { + /* generic type 'literal' syntax */ + A_Const *n = makeNode(A_Const); + n->typename = makeTypeNameFromNameList($1); + n->typename->location = @1; + n->val.type = T_String; + n->val.val.str = $2; + $$ = (Node *)n; + } + | func_name '(' expr_list ')' Sconst + { + /* generic syntax with a type modifier */ + A_Const *n = makeNode(A_Const); + n->typename = makeTypeNameFromNameList($1); + n->typename->typmods = $3; + n->typename->location = @1; + n->val.type = T_String; + n->val.val.str = $5; + $$ = (Node *)n; + } | ConstTypename Sconst { A_Const *n = makeNode(A_Const); @@ -8557,7 +8402,7 @@ AexprConst: Iconst n->val.val.str = $2; /* precision is not specified, but fields may be... */ if ($3 != INTERVAL_FULL_RANGE) - n->typename->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $3); + n->typename->typmods = list_make1(makeIntConst($3)); $$ = (Node *)n; } | ConstInterval '(' Iconst ')' Sconst opt_interval @@ -8566,21 +8411,8 @@ AexprConst: Iconst n->typename = $1; n->val.type = T_String; n->val.val.str = $5; - /* precision specified, and fields may be... */ - if ($3 < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("INTERVAL(%d) precision must not be negative", - $3))); - if ($3 > MAX_INTERVAL_PRECISION) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", - $3, MAX_INTERVAL_PRECISION))); - $3 = MAX_INTERVAL_PRECISION; - } - n->typename->typmod = INTERVAL_TYPMOD($3, $6); + n->typename->typmods = list_make2(makeIntConst($6), + makeIntConst($3)); $$ = (Node *)n; } | TRUE_P @@ -8625,18 +8457,11 @@ ColId: IDENT { $$ = $1; } | col_name_keyword { $$ = pstrdup($1); } ; -/* Type identifier --- names that can be type names. - */ -type_name: IDENT { $$ = $1; } - | unreserved_keyword { $$ = pstrdup($1); } - ; - -/* Function identifier --- names that can be function names. +/* Type/function identifier --- names that can be type or function names. */ -function_name: - IDENT { $$ = $1; } +type_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 7dbbb9a33a8..383013c9a10 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 75d5a50702a..f6d4fcae4aa 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 93c7db6b52a..6aeabb57498 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 2a732ad63bb..2913d0a1d8b 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 9efc7125b19..e2781dec485 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 22d9bc156f6..d2b6323f0f2 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 35b0221b85d..11dd881011f 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 f94413e3f32..f9b0bb2c992 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 e0a67d340ef..4a810b955da 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 937cf96ebef..9cc2f5e34e3 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 824ef4a1efe..8c4cbef66cb 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 6c6ff1fb5a3..377c6d87c3a 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.363 2006/12/23 00:52:40 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.364 2006/12/30 21:21:54 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -45,6 +45,7 @@ #include "parser/gramparse.h" #include "parser/parse_expr.h" #include "parser/parse_relation.h" +#include "parser/parse_type.h" #include "parser/scansup.h" #include "pgstat.h" #include "postmaster/autovacuum.h" @@ -4523,14 +4524,17 @@ flatten_set_variable_args(const char *name, List *args) * to interval and back to normalize the value and account * for any typmod. */ + int32 typmod; Datum interval; char *intervalout; + typmod = typenameTypeMod(NULL, arg->typename, INTERVALOID); + interval = DirectFunctionCall3(interval_in, CStringGetDatum(val), ObjectIdGetDatum(InvalidOid), - Int32GetDatum(arg->typename->typmod)); + Int32GetDatum(typmod)); intervalout = DatumGetCString(DirectFunctionCall1(interval_out, diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index ae8d54936f1..637af90d91c 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 1b1e07bd719..1200af0c6e6 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 3fcc5ed6746..2c38c2b88f8 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 75aee92e512..155b4c7bc32 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 b5913007095..f98717a978f 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 9a95ef305ba..65f8b9deea8 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("@ <number> <units>, 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 bc62c90f4dc..5d7fa50673c 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 0d2cf087d15..1e9e616d09c 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 791f6ebd999..9c9ff140873 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 e1ed7b862b3..56e63d7f73c 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 44eb8e81143..48a6ae1cee1 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 272b321e642..e78236b2185 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 0c6e59cc92f..3bbd63ba456 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 793d28d3835..f0fb87e71e7 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 3e2edeb1e0b..133ad857ac1 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 3aa8e3714bf..f8cc66492ce 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 cc82b12e027..5945753a1b3 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 73d51925c2f..11c9298e9ae 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 097d51fc925..c6e391d8104 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 bf713e9fa7c..5eb440f0f54 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 3969b4cce2e..3677b90ceb9 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 aec8f1bd8de..598aab2bbd1 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 --------------------------------------------------------------------------- -- GitLab