Commit 5725b9d9 authored by Tom Lane's avatar Tom Lane

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.
parent 24b1f14e
<!-- $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>
......
<!-- $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>
......
<!--
$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>
......
......@@ -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)
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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;
......
......@@ -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,
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
}
......
This diff is collapsed.
......@@ -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)
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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);
}
......@@ -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.
......
......@@ -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)
......
......@@ -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);
}
/* ----------------------------------------------------------------------
*
......
......@@ -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.
......
......@@ -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
......
......@@ -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
......
......@@ -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 ---------- */
......
......@@ -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,
......
......@@ -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)
......
......@@ -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
......@@ -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));
......
......@@ -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("");
......
......@@ -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_ ));
......
This diff is collapsed.
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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)
......@@ -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
-------------
......
......@@ -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
......
......@@ -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
......
......@@ -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;
......@@ -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
......
......@@ -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
......
......@@ -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
---------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment