Commit bac3e836 authored by Tom Lane's avatar Tom Lane

Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()

with system catalog lookups, as was foreseen to be necessary almost since
their creation.  Instead put the information into two new pg_type columns,
typcategory and typispreferred.  Add support for setting these when
creating a user-defined base type.

The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character.  This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.

In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums.  In particular the default preferred state
for user-defined types remains TRUE.  That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
parent ab9907f5
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.171 2008/07/18 03:32:51 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.172 2008/07/30 17:05:04 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
......@@ -994,7 +994,7 @@
<entry><type>int4</type></entry>
<entry></entry>
<entry>
The number of direct ancestors this column has. A column with a
The number of direct ancestors this column has. A column with a
nonzero number of ancestors cannot be dropped nor renamed
</entry>
</row>
......@@ -1005,7 +1005,7 @@
<para>
In a dropped column's <structname>pg_attribute</structname> entry,
<structfield>atttypid</structfield> is reset to zero, but
<structfield>atttypid</structfield> is reset to zero, but
<structfield>attlen</structfield> and the other fields copied from
<structname>pg_type</> are still valid. This arrangement is needed
to cope with the situation where the dropped column's data type was
......@@ -1118,7 +1118,7 @@
<entry><structfield>rolconnlimit</structfield></entry>
<entry><type>int4</type></entry>
<entry>
For roles that can log in, this sets maximum number of concurrent
For roles that can log in, this sets maximum number of concurrent
connections this role can make. -1 means no limit
</entry>
</row>
......@@ -2169,7 +2169,7 @@
<entry><type>int4</type></entry>
<entry></entry>
<entry>
Sets maximum number of concurrent connections that can be made
Sets maximum number of concurrent connections that can be made
to this database. -1 means no limit
</entry>
</row>
......@@ -4855,7 +4855,7 @@
<para>
The catalog <structname>pg_type</structname> stores information about data
types. Base types (scalar types) are created with
types. Base types and enum types (scalar types) are created with
<xref linkend="sql-createtype" endterm="sql-createtype-title">, and
domains with
<xref linkend="sql-createdomain" endterm="sql-createdomain-title">.
......@@ -4926,8 +4926,7 @@
where Datum is 8 bytes).
Variable-length types are always passed by reference. Note that
<structfield>typbyval</structfield> can be false even if the
length would allow pass-by-value; this is currently true for
type <type>float4</type>, for example
length would allow pass-by-value
</entry>
</row>
......@@ -4947,6 +4946,28 @@
</entry>
</row>
<row>
<entry><structfield>typcategory</structfield></entry>
<entry><type>char</type></entry>
<entry></entry>
<entry>
<structfield>typcategory</structfield> is an arbitrary classification
of data types that is used by the parser to determine which implicit
casts should be <quote>preferred</>.
See <xref linkend="catalog-typcategory-table">
</entry>
</row>
<row>
<entry><structfield>typispreferred</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>
True if the type is a preferred cast target within its
<structfield>typcategory</structfield>
</entry>
</row>
<row>
<entry><structfield>typisdefined</structfield></entry>
<entry><type>bool</type></entry>
......@@ -5217,6 +5238,86 @@
</tbody>
</tgroup>
</table>
<para>
<xref linkend="catalog-typcategory-table"> lists the system-defined values
of <structfield>typcategory</>. Any future additions to this list will
also be upper-case ASCII letters. All other ASCII characters are reserved
for user-defined categories.
</para>
<table id="catalog-typcategory-table">
<title><structfield>typcategory</> Codes</title>
<tgroup cols=2>
<thead>
<row>
<entry>Code</entry>
<entry>Category</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>A</literal></entry>
<entry>Array types</entry>
</row>
<row>
<entry><literal>B</literal></entry>
<entry>Boolean types</entry>
</row>
<row>
<entry><literal>C</literal></entry>
<entry>Composite types</entry>
</row>
<row>
<entry><literal>D</literal></entry>
<entry>Date/time types</entry>
</row>
<row>
<entry><literal>E</literal></entry>
<entry>Enum types</entry>
</row>
<row>
<entry><literal>G</literal></entry>
<entry>Geometric types</entry>
</row>
<row>
<entry><literal>I</literal></entry>
<entry>Network address types</entry>
</row>
<row>
<entry><literal>N</literal></entry>
<entry>Numeric types</entry>
</row>
<row>
<entry><literal>P</literal></entry>
<entry>Pseudo-types</entry>
</row>
<row>
<entry><literal>S</literal></entry>
<entry>String types</entry>
</row>
<row>
<entry><literal>T</literal></entry>
<entry>Timespan types</entry>
</row>
<row>
<entry><literal>U</literal></entry>
<entry>User-defined types</entry>
</row>
<row>
<entry><literal>V</literal></entry>
<entry>Bit-string types</entry>
</row>
<row>
<entry><literal>X</literal></entry>
<entry><type>unknown</> type</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="views-overview">
......@@ -5787,7 +5888,7 @@
for another transaction, it does so by attempting to acquire share lock on
the other transaction ID (either virtual or permanent ID depending on the
situation). That will succeed only when the other transaction
terminates and releases its locks.
terminates and releases its locks.
</para>
<para>
......@@ -6036,7 +6137,7 @@
<para>
The view <structname>pg_roles</structname> provides access to
information about database roles. This is simply a publicly
readable view of
readable view of
<link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>
that blanks out the password field.
</para>
......@@ -6121,7 +6222,7 @@
<entry><type>int4</type></entry>
<entry></entry>
<entry>
For roles that can log in, this sets maximum number of concurrent
For roles that can log in, this sets maximum number of concurrent
connections this role can make. -1 means no limit
</entry>
</row>
......@@ -6316,7 +6417,7 @@
</tbody>
</tgroup>
</table>
<para>
The <structname>pg_settings</structname> view cannot be inserted into or
deleted from, but it can be updated. An <command>UPDATE</command> applied
......@@ -6774,7 +6875,7 @@
<para>
The view <structname>pg_user</structname> provides access to
information about database users. This is simply a publicly
readable view of
readable view of
<link linkend="view-pg-shadow"><structname>pg_shadow</structname></link>
that blanks out the password field.
</para>
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.74 2008/05/27 18:05:13 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.75 2008/07/30 17:05:04 tgl Exp $
PostgreSQL documentation
-->
......@@ -38,6 +38,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
[ , PASSEDBYVALUE ]
[ , ALIGNMENT = <replaceable class="parameter">alignment</replaceable> ]
[ , STORAGE = <replaceable class="parameter">storage</replaceable> ]
[ , CATEGORY = <replaceable class="parameter">category</replaceable> ]
[ , PREFERRED = <replaceable class="parameter">preferred</replaceable> ]
[ , DEFAULT = <replaceable class="parameter">default</replaceable> ]
[ , ELEMENT = <replaceable class="parameter">element</replaceable> ]
[ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
......@@ -281,6 +283,27 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<literal>external</literal> items.)
</para>
<para>
The <replaceable class="parameter">category</replaceable> and
<replaceable class="parameter">preferred</replaceable> parameters can be
used to help control which implicit cast will be applied in ambiguous
situations. Each data type belongs to a category named by a single ASCII
character, and each type is either <quote>preferred</> or not within its
category. The parser will prefer casting to preferred types (but only from
other types within the same category) when this rule is helpful in
resolving overloaded functions or operators. For more details see <xref
linkend="typeconv">. For types that have no implicit casts to or from any
other types, it is sufficient to leave these settings at the defaults.
However, for a group of related types that have implicit casts, it is often
helpful to mark them all as belonging to a category and select one or two
of the <quote>most general</> types as being preferred within the category.
The <replaceable class="parameter">category</replaceable> parameter is
especially useful when adding a user-defined type to an existing built-in
category, such as the numeric or string types. However, it is also
possible to create new entirely-user-defined type categories. Select any
ASCII character other than an upper-case letter to name such a category.
</para>
<para>
A default value can be specified, in case a user wants columns of the
data type to default to something other than the null value.
......@@ -494,6 +517,31 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">category</replaceable></term>
<listitem>
<para>
The category code (a single ASCII character) for this type.
The default is <literal>'U'</> for <quote>user-defined type</>.
Other standard category codes can be found in
<xref linkend="catalog-typcategory-table">. You may also choose
other ASCII characters in order to create custom categories.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">preferred</replaceable></term>
<listitem>
<para>
True if this type is a preferred type within its type category,
else false. The default is true (which is appropriate for
all entries in category <literal>U</>, but is usually not
appropriate for new types in other categories &mdash; beware!).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">default</replaceable></term>
<listitem>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.55 2008/07/16 01:30:21 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.56 2008/07/30 17:05:04 tgl Exp $ -->
<chapter Id="typeconv">
<title>Type Conversion</title>
......@@ -10,7 +10,7 @@
<para>
<acronym>SQL</acronym> statements can, intentionally or not, require
mixing of different data types in the same expression.
mixing of different data types in the same expression.
<productname>PostgreSQL</productname> has extensive facilities for
evaluating mixed-type expressions.
</para>
......@@ -153,19 +153,32 @@ altered.)
<para>
An additional heuristic is provided in the parser to allow better guesses
at proper behavior for <acronym>SQL</acronym> standard types. There are
several basic <firstterm>type categories</firstterm> defined: <type>boolean</type>,
<type>numeric</type>, <type>string</type>, <type>bitstring</type>, <type>datetime</type>, <type>timespan</type>, <type>geometric</type>, <type>network</type>,
and user-defined. Each category, with the exception of user-defined, has
one or more <firstterm>preferred types</firstterm> which are preferentially
selected when there is ambiguity.
In the user-defined category, each type is its own preferred type.
Ambiguous expressions (those with multiple candidate parsing solutions)
can therefore often be resolved when there are multiple possible built-in types, but
they will raise an error when there are multiple choices for user-defined
types.
at proper casting behavior among groups of types that have implicit casts.
Data types are divided into several basic <firstterm>type
categories</firstterm>, including <type>boolean</type>, <type>numeric</type>,
<type>string</type>, <type>bitstring</type>, <type>datetime</type>,
<type>timespan</type>, <type>geometric</type>, <type>network</type>, and
user-defined. (For a list see <xref linkend="catalog-typcategory-table">;
but note it is also possible to create custom type categories.) Within each
category there are one or more <firstterm>preferred types</firstterm>, which
are preferentially selected when there is ambiguity. With careful selection
of preferred types and available implicit casts, it is possible to ensure that
ambiguous expressions (those with multiple candidate parsing solutions) can be
resolved in a useful way.
</para>
<note>
<para>
For what are now historical reasons, types in the <quote>user-defined</>
category are normally always marked as <quote>preferred</>. Since all types
in this category are preferred, the heuristic that favors preferred types
accomplishes nothing, and thus this situation is equivalent to treating them
all as non-preferred. The <quote>preferred</> marking is useful within the
system-defined type categories, and can be useful within custom type
categories.
</para>
</note>
<para>
All type conversion rules are designed with several principles in mind:
......@@ -176,23 +189,6 @@ Implicit conversions should never have surprising or unpredictable outcomes.
</para>
</listitem>
<listitem>
<para>
User-defined types, of which the parser has no <foreignphrase>a priori</> knowledge, should be
<quote>higher</quote> in the type hierarchy. In mixed-type expressions, native types shall always
be converted to a user-defined type (of course, only if conversion is necessary).
</para>
</listitem>
<listitem>
<para>
User-defined types are not related. Currently, <productname>PostgreSQL</productname>
does not have information available to it on relationships between types, other than
hardcoded heuristics for built-in types and implicit relationships based on
available functions and casts.
</para>
</listitem>
<listitem>
<para>
There should be no extra overhead from the parser or executor
......@@ -317,7 +313,7 @@ all the remaining candidates accept the same type category, select that
category; otherwise fail because the correct choice cannot be deduced
without more clues. Now discard
candidates that do not accept the selected type category. Furthermore,
if any candidate accepts a preferred type at a given argument position,
if any candidate accepts a preferred type in that category,
discard candidates that accept non-preferred types for that argument.
</para>
</step>
......@@ -341,7 +337,7 @@ Some examples follow.
<para>
There is only one factorial operator (postfix <literal>!</>)
defined in the standard catalog, and it takes an argument of type
defined in the standard catalog, and it takes an argument of type
<type>bigint</type>.
The scanner assigns an initial type of <type>integer</type> to the argument
in this query expression:
......@@ -407,7 +403,7 @@ In this case there is no initial hint for which type to use, since no types
are specified in the query. So, the parser looks for all candidate operators
and finds that there are candidates accepting both string-category and
bit-string-category inputs. Since string category is preferred when available,
that category is selected, and then the
that category is selected, and then the
preferred type for strings, <type>text</type>, is used as the specific
type to resolve the unknown literals to.
</para>
......@@ -585,7 +581,7 @@ If only one candidate remains, use it; else continue to the next step.
<step performance="required">
<para>
If any input arguments are <type>unknown</type>, check the type categories
accepted
accepted
at those argument positions by the remaining candidates. At each position,
select the <type>string</type> category if any candidate accepts that category.
(This bias towards string
......@@ -594,9 +590,8 @@ Otherwise, if all the remaining candidates accept the same type category,
select that category; otherwise fail because
the correct choice cannot be deduced without more clues.
Now discard candidates that do not accept the selected type category.
Furthermore, if any candidate accepts a preferred type at a given argument
position, discard candidates that accept non-preferred types for that
argument.
Furthermore, if any candidate accepts a preferred type in that category,
discard candidates that accept non-preferred types for that argument.
</para>
</step>
<step performance="required">
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.334 2008/05/12 00:00:46 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.335 2008/07/30 17:05:04 tgl Exp $
*
*
* INTERFACE ROUTINES
......@@ -761,6 +761,8 @@ AddNewRelationType(const char *typeName,
new_rel_kind, /* relation kind */
-1, /* internal size (varlena) */
TYPTYPE_COMPOSITE, /* type-type (composite) */
TYPCATEGORY_COMPOSITE, /* type-category (ditto) */
true, /* all composite types are preferred */
DEFAULT_TYPDELIM, /* default array delimiter */
F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */
......@@ -938,6 +940,8 @@ heap_create_with_catalog(const char *relname,
0, /* relkind, also N/A here */
-1, /* Internal size (varlena) */
TYPTYPE_BASE, /* Not composite - typelem is */
TYPCATEGORY_ARRAY, /* type-category (array) */
true, /* all array types are preferred */
DEFAULT_TYPDELIM, /* default array delimiter */
F_ARRAY_IN, /* array input proc */
F_ARRAY_OUT, /* array output proc */
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.119 2008/06/19 00:46:04 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.120 2008/07/30 17:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -91,6 +91,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
values[i++] = BoolGetDatum(true); /* typbyval */
values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
values[i++] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE); /* typcategory */
values[i++] = BoolGetDatum(false); /* typispreferred */
values[i++] = BoolGetDatum(false); /* typisdefined */
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
......@@ -173,6 +175,8 @@ TypeCreate(Oid newTypeOid,
char relationKind, /* ditto */
int16 internalSize,
char typeType,
char typeCategory,
bool typePreferred,
char typDelim,
Oid inputProcedure,
Oid outputProcedure,
......@@ -253,6 +257,8 @@ TypeCreate(Oid newTypeOid,
values[i++] = Int16GetDatum(internalSize); /* typlen */
values[i++] = BoolGetDatum(passedByValue); /* typbyval */
values[i++] = CharGetDatum(typeType); /* typtype */
values[i++] = CharGetDatum(typeCategory); /* typcategory */
values[i++] = BoolGetDatum(typePreferred); /* typispreferred */
values[i++] = BoolGetDatum(true); /* typisdefined */
values[i++] = CharGetDatum(typDelim); /* typdelim */
values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.177 2008/06/14 18:04:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.178 2008/07/30 17:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1012,7 +1012,7 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
ScanKeyData skey[1];
SysScanDesc scan;
HeapTuple tup;
CATEGORY tcategory;
TYPCATEGORY tcategory;
/* If it's a domain, look at the base type instead */
type_id = getBaseType(type_id);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.119 2008/06/14 18:04:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.120 2008/07/30 17:05:04 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
......@@ -111,6 +111,8 @@ DefineType(List *names, List *parameters)
List *analyzeName = NIL;
char *defaultValue = NULL;
bool byValue = false;
char category = TYPCATEGORY_USER;
bool preferred = true;
char delimiter = DEFAULT_TYPDELIM;
char alignment = 'i'; /* default alignment */
char storage = 'p'; /* default TOAST storage method */
......@@ -188,8 +190,6 @@ DefineType(List *names, List *parameters)
if (pg_strcasecmp(defel->defname, "internallength") == 0)
internalLength = defGetTypeLength(defel);
else if (pg_strcasecmp(defel->defname, "externallength") == 0)
; /* ignored -- remove after 7.3 */
else if (pg_strcasecmp(defel->defname, "input") == 0)
inputName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "output") == 0)
......@@ -205,11 +205,26 @@ DefineType(List *names, List *parameters)
else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
pg_strcasecmp(defel->defname, "analyse") == 0)
analyzeName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "category") == 0)
{
char *p = defGetString(defel);
category = p[0];
/* restrict to non-control ASCII */
if (category < 32 || category > 126)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid type category \"%s\": must be simple ASCII",
p)));
}
else if (pg_strcasecmp(defel->defname, "preferred") == 0)
preferred = defGetBoolean(defel);
else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
{
char *p = defGetString(defel);
delimiter = p[0];
/* XXX shouldn't we restrict the delimiter? */
}
else if (pg_strcasecmp(defel->defname, "element") == 0)
{
......@@ -421,6 +436,8 @@ DefineType(List *names, List *parameters)
0, /* relation kind (ditto) */
internalLength, /* internal size */
TYPTYPE_BASE, /* type-type (base type) */
category, /* type-category */
preferred, /* is it a preferred type? */
delimiter, /* array element delimiter */
inputOid, /* input procedure */
outputOid, /* output procedure */
......@@ -457,6 +474,8 @@ DefineType(List *names, List *parameters)
0, /* relation kind (ditto) */
-1, /* internal size (always varlena) */
TYPTYPE_BASE, /* type-type (base type) */
TYPCATEGORY_ARRAY, /* type-category (array) */
true, /* all array types are preferred */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
F_ARRAY_OUT, /* output procedure */
......@@ -624,6 +643,7 @@ DefineDomain(CreateDomainStmt *stmt)
Oid analyzeProcedure;
bool byValue;
Oid typelem;
char category;
char delimiter;
char alignment;
char storage;
......@@ -705,6 +725,9 @@ DefineDomain(CreateDomainStmt *stmt)
/* Storage Length */
internalLength = baseType->typlen;
/* Type Category */
category = baseType->typcategory;
/* Array element type (in case base type is an array) */
typelem = baseType->typelem;
......@@ -895,6 +918,8 @@ DefineDomain(CreateDomainStmt *stmt)
0, /* relation kind (ditto) */
internalLength, /* internal size */
TYPTYPE_DOMAIN, /* type-type (domain type) */
category, /* type-category */
false, /* domains are never preferred types */
delimiter, /* array element delimiter */
inputProcedure, /* input procedure */
outputProcedure, /* output procedure */
......@@ -1006,6 +1031,8 @@ DefineEnum(CreateEnumStmt *stmt)
0, /* relation kind (ditto) */
sizeof(Oid), /* internal size */
TYPTYPE_ENUM, /* type-type (enum type) */
TYPCATEGORY_ENUM, /* type-category (enum type) */
true, /* all enum types are preferred */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ENUM_IN, /* input procedure */
F_ENUM_OUT, /* output procedure */
......@@ -1042,6 +1069,8 @@ DefineEnum(CreateEnumStmt *stmt)
0, /* relation kind (ditto) */
-1, /* internal size (always varlena) */
TYPTYPE_BASE, /* type-type (base type) */
TYPCATEGORY_ARRAY, /* type-category (array) */
true, /* all array types are preferred */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
F_ARRAY_OUT, /* output procedure */
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.161 2008/01/11 18:39:40 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.162 2008/07/30 17:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -967,7 +967,8 @@ Oid
select_common_type(List *typeids, const char *context)
{
Oid ptype;
CATEGORY pcategory;
TYPCATEGORY pcategory;
bool pispreferred;
ListCell *type_item;
Assert(typeids != NIL);
......@@ -993,7 +994,7 @@ select_common_type(List *typeids, const char *context)
/* Nope, so set up for the full algorithm */
ptype = getBaseType(ptype);
pcategory = TypeCategory(ptype);
get_type_category_preferred(ptype, &pcategory, &pispreferred);
for_each_cell(type_item, lnext(list_head(typeids)))
{
......@@ -1002,13 +1003,18 @@ select_common_type(List *typeids, const char *context)
/* move on to next one if no new information... */
if (ntype != UNKNOWNOID && ntype != ptype)
{
TYPCATEGORY ncategory;
bool nispreferred;
get_type_category_preferred(ntype, &ncategory, &nispreferred);
if (ptype == UNKNOWNOID)
{
/* so far, only unknowns so take anything... */
ptype = ntype;
pcategory = TypeCategory(ptype);
pcategory = ncategory;
pispreferred = nispreferred;
}
else if (TypeCategory(ntype) != pcategory)
else if (ncategory != pcategory)
{
/*
* both types in different categories? then not much hope...
......@@ -1023,7 +1029,7 @@ select_common_type(List *typeids, const char *context)
format_type_be(ptype),
format_type_be(ntype))));
}
else if (!IsPreferredType(pcategory, ptype) &&
else if (!pispreferred &&
can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
!can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT))
{
......@@ -1032,7 +1038,8 @@ select_common_type(List *typeids, const char *context)
* other way; but if we have a preferred type, stay on it.
*/
ptype = ntype;
pcategory = TypeCategory(ptype);
pcategory = ncategory;
pispreferred = nispreferred;
}
}
}
......@@ -1549,202 +1556,39 @@ resolve_generic_type(Oid declared_type,
/* TypeCategory()
* Assign a category to the specified type OID.
*
* NB: this must not return INVALID_TYPE.
*
* XXX This should be moved to system catalog lookups
* to allow for better type extensibility.
* - thomas 2001-09-30
* NB: this must not return TYPCATEGORY_INVALID.
*/
CATEGORY
TypeCategory(Oid inType)
TYPCATEGORY
TypeCategory(Oid type)
{
CATEGORY result;
char typcategory;
bool typispreferred;
switch (inType)
{
case (BOOLOID):
result = BOOLEAN_TYPE;
break;
case (CHAROID):
case (NAMEOID):
case (BPCHAROID):
case (VARCHAROID):
case (TEXTOID):
result = STRING_TYPE;
break;
case (BITOID):
case (VARBITOID):
result = BITSTRING_TYPE;
break;
case (OIDOID):
case (REGPROCOID):
case (REGPROCEDUREOID):
case (REGOPEROID):
case (REGOPERATOROID):
case (REGCLASSOID):
case (REGTYPEOID):
case (REGCONFIGOID):
case (REGDICTIONARYOID):
case (INT2OID):
case (INT4OID):
case (INT8OID):
case (FLOAT4OID):
case (FLOAT8OID):
case (NUMERICOID):
case (CASHOID):
result = NUMERIC_TYPE;
break;
case (DATEOID):
case (TIMEOID):
case (TIMETZOID):
case (ABSTIMEOID):
case (TIMESTAMPOID):
case (TIMESTAMPTZOID):
result = DATETIME_TYPE;
break;
case (RELTIMEOID):
case (TINTERVALOID):
case (INTERVALOID):
result = TIMESPAN_TYPE;
break;
case (POINTOID):
case (LSEGOID):
case (PATHOID):
case (BOXOID):
case (POLYGONOID):
case (LINEOID):
case (CIRCLEOID):
result = GEOMETRIC_TYPE;
break;
case (INETOID):
case (CIDROID):
result = NETWORK_TYPE;
break;
case (UNKNOWNOID):
case (InvalidOid):
result = UNKNOWN_TYPE;
break;
case (RECORDOID):
case (CSTRINGOID):
case (ANYOID):
case (ANYARRAYOID):
case (VOIDOID):
case (TRIGGEROID):
case (LANGUAGE_HANDLEROID):
case (INTERNALOID):
case (OPAQUEOID):
case (ANYELEMENTOID):
case (ANYNONARRAYOID):
case (ANYENUMOID):
result = GENERIC_TYPE;
break;
default:
result = USER_TYPE;
break;
}
return result;
} /* TypeCategory() */
get_type_category_preferred(type, &typcategory, &typispreferred);
Assert(typcategory != TYPCATEGORY_INVALID);
return (TYPCATEGORY) typcategory;
}
/* IsPreferredType()
* Check if this type is a preferred type for the given category.
*
* If category is INVALID_TYPE, then we'll return TRUE for preferred types
* of any category; otherwise, only for preferred types of that category.
*
* XXX This should be moved to system catalog lookups
* to allow for better type extensibility.
* - thomas 2001-09-30
* If category is TYPCATEGORY_INVALID, then we'll return TRUE for preferred
* types of any category; otherwise, only for preferred types of that
* category.
*/
bool
IsPreferredType(CATEGORY category, Oid type)
IsPreferredType(TYPCATEGORY category, Oid type)
{
Oid preftype;
char typcategory;
bool typispreferred;
if (category == INVALID_TYPE)
category = TypeCategory(type);
else if (category != TypeCategory(type))
get_type_category_preferred(type, &typcategory, &typispreferred);
if (category == typcategory || category == TYPCATEGORY_INVALID)
return typispreferred;
else
return false;
/*
* This switch should agree with TypeCategory(), above. Note that at this
* point, category certainly matches the type.
*/
switch (category)
{
case (UNKNOWN_TYPE):
case (GENERIC_TYPE):
preftype = UNKNOWNOID;
break;
case (BOOLEAN_TYPE):
preftype = BOOLOID;
break;
case (STRING_TYPE):
preftype = TEXTOID;
break;
case (BITSTRING_TYPE):
preftype = VARBITOID;
break;
case (NUMERIC_TYPE):
if (type == OIDOID ||
type == REGPROCOID ||
type == REGPROCEDUREOID ||
type == REGOPEROID ||
type == REGOPERATOROID ||
type == REGCLASSOID ||
type == REGTYPEOID ||
type == REGCONFIGOID ||
type == REGDICTIONARYOID)
preftype = OIDOID;
else
preftype = FLOAT8OID;
break;
case (DATETIME_TYPE):
if (type == DATEOID)
preftype = TIMESTAMPOID;
else
preftype = TIMESTAMPTZOID;
break;
case (TIMESPAN_TYPE):
preftype = INTERVALOID;
break;
case (GEOMETRIC_TYPE):
preftype = type;
break;
case (NETWORK_TYPE):
preftype = INETOID;
break;
case (USER_TYPE):
preftype = type;
break;
default:
elog(ERROR, "unrecognized type category: %d", (int) category);
preftype = UNKNOWNOID;
break;
}
return (type == preftype);
} /* IsPreferredType() */
}
/* IsBinaryCoercible()
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.203 2008/07/16 01:30:22 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.204 2008/07/30 17:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -439,8 +439,9 @@ func_select_candidate(int nargs,
int nbestMatch,
nmatch;
Oid input_base_typeids[FUNC_MAX_ARGS];
CATEGORY slot_category[FUNC_MAX_ARGS],
TYPCATEGORY slot_category[FUNC_MAX_ARGS],
current_category;
bool current_is_preferred;
bool slot_has_preferred_type[FUNC_MAX_ARGS];
bool resolved_unknowns;
......@@ -591,7 +592,7 @@ func_select_candidate(int nargs,
if (input_base_typeids[i] != UNKNOWNOID)
continue;
resolved_unknowns = true; /* assume we can do it */
slot_category[i] = INVALID_TYPE;
slot_category[i] = TYPCATEGORY_INVALID;
slot_has_preferred_type[i] = false;
have_conflict = false;
for (current_candidate = candidates;
......@@ -600,29 +601,28 @@ func_select_candidate(int nargs,
{
current_typeids = current_candidate->args;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
if (slot_category[i] == INVALID_TYPE)
get_type_category_preferred(current_type,
&current_category,
&current_is_preferred);
if (slot_category[i] == TYPCATEGORY_INVALID)
{
/* first candidate */
slot_category[i] = current_category;
slot_has_preferred_type[i] =
IsPreferredType(current_category, current_type);
slot_has_preferred_type[i] = current_is_preferred;
}
else if (current_category == slot_category[i])
{
/* more candidates in same category */
slot_has_preferred_type[i] |=
IsPreferredType(current_category, current_type);
slot_has_preferred_type[i] |= current_is_preferred;
}
else
{
/* category conflict! */
if (current_category == STRING_TYPE)
if (current_category == TYPCATEGORY_STRING)
{
/* STRING always wins if available */
slot_category[i] = current_category;
slot_has_preferred_type[i] =
IsPreferredType(current_category, current_type);
slot_has_preferred_type[i] = current_is_preferred;
}
else
{
......@@ -633,7 +633,7 @@ func_select_candidate(int nargs,
}
}
}
if (have_conflict && slot_category[i] != STRING_TYPE)
if (have_conflict && slot_category[i] != TYPCATEGORY_STRING)
{
/* Failed to resolve category conflict at this position */
resolved_unknowns = false;
......@@ -658,14 +658,15 @@ func_select_candidate(int nargs,
if (input_base_typeids[i] != UNKNOWNOID)
continue;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
get_type_category_preferred(current_type,
&current_category,
&current_is_preferred);
if (current_category != slot_category[i])
{
keepit = false;
break;
}
if (slot_has_preferred_type[i] &&
!IsPreferredType(current_category, current_type))
if (slot_has_preferred_type[i] && !current_is_preferred)
{
keepit = false;
break;
......
......@@ -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.157 2008/04/13 20:51:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.158 2008/07/30 17:05:04 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
......@@ -2167,6 +2167,29 @@ type_is_enum(Oid typid)
return (get_typtype(typid) == TYPTYPE_ENUM);
}
/*
* get_type_category_preferred
*
* Given the type OID, fetch its category and preferred-type status.
* Throws error on failure.
*/
void
get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
{
HeapTuple tp;
Form_pg_type typtup;
tp = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for type %u", typid);
typtup = (Form_pg_type) GETSTRUCT(tp);
*typcategory = typtup->typcategory;
*typispreferred = typtup->typispreferred;
ReleaseSysCache(tp);
}
/*
* get_typ_typrelid
*
......
......@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.497 2008/07/20 18:43:30 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.498 2008/07/30 17:05:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -5736,6 +5736,8 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
Oid typmodinoid;
Oid typmodoutoid;
Oid typanalyzeoid;
char *typcategory;
char *typispreferred;
char *typdelim;
char *typbyval;
char *typalign;
......@@ -5747,7 +5749,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
selectSourceSchema(tinfo->dobj.namespace->dobj.name);
/* Fetch type-specific details */
if (fout->remoteVersion >= 80300)
if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT typlen, "
"typinput, typoutput, typreceive, typsend, "
......@@ -5759,6 +5761,26 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"typmodin::pg_catalog.oid as typmodinoid, "
"typmodout::pg_catalog.oid as typmodoutoid, "
"typanalyze::pg_catalog.oid as typanalyzeoid, "
"typcategory, typispreferred, "
"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 >= 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, "
"'U' as typcategory, true as typispreferred, "
"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 "
......@@ -5777,6 +5799,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"typsend::pg_catalog.oid as typsendoid, "
"0 as typmodinoid, 0 as typmodoutoid, "
"typanalyze::pg_catalog.oid as typanalyzeoid, "
"'U' as typcategory, true as typispreferred, "
"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 "
......@@ -5795,6 +5818,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"typsend::pg_catalog.oid as typsendoid, "
"0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"'U' as typcategory, true as typispreferred, "
"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 "
......@@ -5813,6 +5837,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"0 as typreceiveoid, 0 as typsendoid, "
"0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"'U' as typcategory, true as typispreferred, "
"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 "
......@@ -5835,6 +5860,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"0 as typreceiveoid, 0 as typsendoid, "
"0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"'U' as typcategory, true as typispreferred, "
"typdelim, typbyval, typalign, typstorage, "
"NULL as typdefaultbin, typdefault "
"FROM pg_type "
......@@ -5857,6 +5883,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"0 as typreceiveoid, 0 as typsendoid, "
"0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"'U' as typcategory, true as typispreferred, "
"typdelim, typbyval, typalign, typstorage, "
"NULL as typdefaultbin, NULL as typdefault "
"FROM pg_type "
......@@ -5875,6 +5902,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
"0 as typreceiveoid, 0 as typsendoid, "
"0 as typmodinoid, 0 as typmodoutoid, "
"0 as typanalyzeoid, "
"'U' as typcategory, true as typispreferred, "
"typdelim, typbyval, typalign, "
"'p'::char as typstorage, "
"NULL as typdefaultbin, NULL as typdefault "
......@@ -5910,6 +5938,8 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
......@@ -5986,6 +6016,15 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
free(elemType);
}
if (strcmp(typcategory, "U") != 0)
{
appendPQExpBuffer(q, ",\n CATEGORY = ");
appendStringLiteralAH(q, typcategory, fout);
}
if (strcmp(typispreferred, "f") == 0)
appendPQExpBuffer(q, ",\n PREFERRED = false");
if (typdelim && strcmp(typdelim, ",") != 0)
{
appendPQExpBuffer(q, ",\n DELIMITER = ");
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.471 2008/07/18 03:32:52 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.472 2008/07/30 17:05:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200807171
#define CATALOG_VERSION_NO 200807291
#endif
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.139 2008/07/16 16:55:24 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.140 2008/07/30 17:05:05 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -223,26 +223,28 @@ typedef FormData_pg_attribute *Form_pg_attribute;
{ 1247, {"typlen"}, 21, -1, 2, 4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1247, {"typbyval"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typtype"}, 18, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typisdefined"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typdelim"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typelem"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typarray"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typinput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typoutput"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typreceive"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typsend"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodin"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodout"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typanalyze"}, 24, -1, 4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typalign"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typstorage"}, 18, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typnotnull"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typbasetype"}, 26, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typtypmod"}, 23, -1, 4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typndims"}, 23, -1, 4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typdefaultbin"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1247, {"typdefault"}, 25, -1, -1, 26, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
{ 1247, {"typcategory"}, 18, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typispreferred"},16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typisdefined"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typdelim"}, 18, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typrelid"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typelem"}, 26, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typarray"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typinput"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typoutput"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typreceive"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typsend"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodin"}, 24, -1, 4, 18, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typmodout"}, 24, -1, 4, 19, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typanalyze"}, 24, -1, 4, 20, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typalign"}, 18, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typstorage"}, 18, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typnotnull"}, 16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1247, {"typbasetype"}, 26, -1, 4, 24, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typtypmod"}, 23, -1, 4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typndims"}, 23, -1, 4, 26, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1247, {"typdefaultbin"}, 25, -1, -1, 27, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1247, {"typdefault"}, 25, -1, -1, 28, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p c t f f t 0));
DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
......@@ -250,26 +252,28 @@ DATA(insert ( 1247 typowner 26 -1 4 3 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typlen 21 -1 2 4 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1247 typbyval 16 -1 1 5 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typtype 18 -1 1 6 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typisdefined 16 -1 1 7 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typdelim 18 -1 1 8 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typelem 26 -1 4 10 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typarray 26 -1 4 11 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typinput 24 -1 4 12 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typoutput 24 -1 4 13 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typreceive 24 -1 4 14 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typsend 24 -1 4 15 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodin 24 -1 4 16 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodout 24 -1 4 17 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typanalyze 24 -1 4 18 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typalign 18 -1 1 19 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typstorage 18 -1 1 20 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typnotnull 16 -1 1 21 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typbasetype 26 -1 4 22 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typtypmod 23 -1 4 23 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typndims 23 -1 4 24 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typdefaultbin 25 -1 -1 25 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 typdefault 25 -1 -1 26 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 typcategory 18 -1 1 7 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typispreferred 16 -1 1 8 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typisdefined 16 -1 1 9 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typdelim 18 -1 1 10 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typrelid 26 -1 4 11 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typelem 26 -1 4 12 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typarray 26 -1 4 13 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typinput 24 -1 4 14 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typoutput 24 -1 4 15 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typreceive 24 -1 4 16 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typsend 24 -1 4 17 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodin 24 -1 4 18 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typmodout 24 -1 4 19 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typanalyze 24 -1 4 20 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typalign 18 -1 1 21 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typstorage 18 -1 1 22 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typnotnull 16 -1 1 23 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1247 typbasetype 26 -1 4 24 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typtypmod 23 -1 4 25 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typndims 23 -1 4 26 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1247 typdefaultbin 25 -1 -1 27 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1247 typdefault 25 -1 -1 28 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-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.106 2008/07/16 16:55:24 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.107 2008/07/30 17:05:05 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -127,7 +127,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 26 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 28 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("");
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type_fn.h,v 1.1 2008/03/27 03:57:34 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type_fn.h,v 1.2 2008/07/30 17:05:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -26,6 +26,8 @@ extern Oid TypeCreate(Oid newTypeOid,
char relationKind,
int16 internalSize,
char typeType,
char typeCategory,
bool typePreferred,
char typDelim,
Oid inputProcedure,
Oid outputProcedure,
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.75 2008/01/11 18:39:41 tgl Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.76 2008/07/30 17:05:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -17,22 +17,8 @@
#include "parser/parse_node.h"
/* Type categories (kluge ... ought to be extensible) */
typedef enum CATEGORY
{
INVALID_TYPE,
UNKNOWN_TYPE,
GENERIC_TYPE,
BOOLEAN_TYPE,
STRING_TYPE,
BITSTRING_TYPE,
NUMERIC_TYPE,
DATETIME_TYPE,
TIMESPAN_TYPE,
GEOMETRIC_TYPE,
NETWORK_TYPE,
USER_TYPE
} CATEGORY;
/* Type categories (see TYPCATEGORY_xxx symbols in catalog/pg_type.h) */
typedef char TYPCATEGORY;
/* Result codes for find_coercion_pathway */
typedef enum CoercionPathType
......@@ -46,8 +32,8 @@ typedef enum CoercionPathType
extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
extern bool IsPreferredType(CATEGORY category, Oid type);
extern CATEGORY TypeCategory(Oid type);
extern bool IsPreferredType(TYPCATEGORY category, Oid type);
extern TYPCATEGORY TypeCategory(Oid type);
extern Node *coerce_to_target_type(ParseState *pstate,
Node *expr, Oid exprtype,
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.123 2008/04/13 20:51:21 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.124 2008/07/30 17:05:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -106,6 +106,9 @@ extern Node *get_typdefault(Oid typid);
extern char get_typtype(Oid typid);
extern bool type_is_rowtype(Oid typid);
extern bool type_is_enum(Oid typid);
extern void get_type_category_preferred(Oid typid,
char *typcategory,
bool *typispreferred);
extern Oid get_typ_typrelid(Oid typid);
extern Oid get_element_type(Oid typid);
extern Oid get_array_type(Oid typid);
......
......@@ -18,7 +18,9 @@ CREATE TYPE city_budget (
internallength = 16,
input = int44in,
output = int44out,
element = int4
element = int4,
category = 'x', -- just to verify the system will take it
preferred = false -- ditto
);
-- Test creation and destruction of shell types
CREATE TYPE shell;
......
......@@ -20,7 +20,9 @@ CREATE TYPE city_budget (
internallength = 16,
input = int44in,
output = int44out,
element = int4
element = int4,
category = 'x', -- just to verify the system will take it
preferred = false -- ditto
);
-- Test creation and destruction of shell types
......
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