提交 a1a233af 编写于 作者: T Tom Lane

Further review of range-types patch.

Lots of documentation cleanup today, and still more type_sanity tests.
上级 c1458cc4
......@@ -4607,7 +4607,9 @@
</indexterm>
<para>
The catalog <structname>pg_range</structname> stores information about range types.
The catalog <structname>pg_range</structname> stores information about
range types. This is in addition to the types' entries in
<link linkend="catalog-pg-type"><structname>pg_type</structname></link>.
</para>
<table>
......@@ -4628,47 +4630,57 @@
<entry><structfield>rngtypid</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>The type that is a range type</entry>
<entry>OID of the range type</entry>
</row>
<row>
<entry><structfield>rngsubtype</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Subtype of this range type, e.g. <type>integer</type> is the subtype of <type>int4range</type></entry>
<entry>OID of the element type (subtype) of this range type</entry>
</row>
<row>
<entry><structfield>rngcollation</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-collation"><structname>pg_collation</structname></link>.oid</literal></entry>
<entry>The collation used when comparing range boundaries</entry>
<entry>OID of the collation used for range comparisons, or 0 if none</entry>
</row>
<row>
<entry><structfield>rngsubopc</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
<entry>The operator class used when comparing range boundaries</entry>
<entry>OID of the subtype's operator class used for range comparisons</entry>
</row>
<row>
<entry><structfield>rngcanonical</structfield></entry>
<entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>A function to convert a range into its canonical form</entry>
<entry>OID of the function to convert a range value into canonical form,
or 0 if none</entry>
</row>
<row>
<entry><structfield>rngsubdiff</structfield></entry>
<entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>A function to return the distance between two lower and upper bound, as a <type>double precision</type>. Used for GiST support</entry>
<entry>OID of the function to return the difference between two element
values as <type>double precision</type>, or 0 if none</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<structfield>rngsubopc</> (plus <structfield>rngcollation</>, if the
element type is collatable) determines the sort ordering used by the range
type. <structfield>rngcanonical</> is used when the element type is
discrete. <structfield>rngsubdiff</> is optional but should be supplied to
improve performance of GiST indexes on the range type.
</para>
</sect1>
<sect1 id="catalog-pg-rewrite">
......@@ -6059,7 +6071,8 @@
<literal>c</literal> for a composite type (e.g., a table's row type),
<literal>d</literal> for a domain,
<literal>e</literal> for an enum type,
or <literal>p</literal> for a pseudo-type.
<literal>p</literal> for a pseudo-type, or
<literal>r</literal> for a range type.
See also <structfield>typrelid</structfield> and
<structfield>typbasetype</structfield>.
</entry>
......@@ -6429,6 +6442,10 @@
<entry><literal>P</literal></entry>
<entry>Pseudo-types</entry>
</row>
<row>
<entry><literal>R</literal></entry>
<entry>Range types</entry>
</row>
<row>
<entry><literal>S</literal></entry>
<entry>String types</entry>
......
......@@ -200,13 +200,13 @@
<para>
Five pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, <type>anynonarray</>, <type>anyenum</>,
and <type>anyrange</>, which are collectively
called <firstterm>polymorphic types</>. Any function declared
using these types is said to be a <firstterm>polymorphic
function</>. A polymorphic function can operate on many
different data types, with the specific data type(s) being
determined by the data types actually passed to it in a
particular call.
and <type>anyrange</>,
which are collectively called <firstterm>polymorphic types</>.
Any function declared using these types is said to be
a <firstterm>polymorphic function</>. A polymorphic function can
operate on many different data types, with the specific data type(s)
being determined by the data types actually passed to it in a particular
call.
</para>
<para>
......@@ -217,15 +217,16 @@
data type, but in any given call they must all be the
<emphasis>same</emphasis> actual type. Each
position declared as <type>anyarray</type> can have any array data type,
but similarly they must all be the same type. If there are
but similarly they must all be the same type. And similarly,
positions declared as <type>anyrange</type> must all be the same range
type. Furthermore, if there are
positions declared <type>anyarray</type> and others declared
<type>anyelement</type>, the actual array type in the
<type>anyarray</type> positions must be an array whose elements are
the same type appearing in the <type>anyelement</type> positions.
Similarly, if there are positions declared <type>anyrange</type>
and others declared
<type>anyelement</type>, the actual range type in the
<type>anyrange</type> positions must be a range whose subtype is
and others declared <type>anyelement</type>, the actual range type in
the <type>anyrange</type> positions must be a range whose subtype is
the same type appearing in the <type>anyelement</type> positions.
<type>anynonarray</> is treated exactly the same as <type>anyelement</>,
but adds the additional constraint that the actual type must not be
......
......@@ -10525,18 +10525,32 @@ SELECT NULLIF(value, '(none)') ...
<row>
<entry> <literal>@&gt;</literal> </entry>
<entry>contains</entry>
<entry>contains range</entry>
<entry><literal>int4range(2,4) @&gt; int4range(2,3)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>@&gt;</literal> </entry>
<entry>contains element</entry>
<entry><literal>'[2011-01-01,2011-03-01)'::tsrange @&gt; '2011-01-10'::timestamp</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;@</literal> </entry>
<entry>is contained by</entry>
<entry>range is contained by</entry>
<entry><literal>int4range(2,4) &lt;@ int4range(1,7)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;@</literal> </entry>
<entry>element is contained by</entry>
<entry><literal>42 &lt;@ int4range(1,7)</literal></entry>
<entry><literal>f</literal></entry>
</row>
<row>
<entry> <literal>&amp;&amp;</literal> </entry>
<entry>overlap (have points in common)</entry>
......
此差异已折叠。
......@@ -28,12 +28,12 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
SUBTYPE = <replaceable class="parameter">subtype</replaceable>,
SUBTYPE = <replaceable class="parameter">subtype</replaceable>
[ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
[ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
[ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
[ , CANONICAL = <replaceable class="parameter">canonical_function</replaceable> ]
[ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
[ , ANALYZE = <replaceable class="parameter">analyze_function</replaceable> ]
[ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
)
CREATE TYPE <replaceable class="parameter">name</replaceable> (
......@@ -79,6 +79,18 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
table in the same schema.)
</para>
<para>
There are five forms of <command>CREATE TYPE</command>, as shown in the
syntax synopsis above. They respectively create a <firstterm>composite
type</>, an <firstterm>enum type</>, a <firstterm>range type</>, a
<firstterm>base type</>, or a <firstterm>shell type</>. The first four
of these are discussed in turn below. A shell type is simply a placeholder
for a type to be defined later; it is created by issuing <command>CREATE
TYPE</command> with no parameters except for the type name. Shell types
are needed as forward references when creating range types and base types,
as discussed in those sections.
</para>
<refsect2>
<title>Composite Types</title>
......@@ -102,59 +114,65 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
The second form of <command>CREATE TYPE</command> creates an enumerated
(enum) type, as described in <xref linkend="datatype-enum">.
Enum types take a list of one or more quoted labels, each of which
must be less than <symbol>NAMEDATALEN</symbol> bytes long (64 in a standard
<productname>PostgreSQL</productname> build).
must be less than <symbol>NAMEDATALEN</symbol> bytes long (64 bytes in a
standard <productname>PostgreSQL</productname> build).
</para>
</refsect2>
<refsect2 id="SQL-CREATETYPE-RANGE">
<title>Range Types</title>
<para>
<para>
The third form of <command>CREATE TYPE</command> creates a new
range type, as described in <xref linkend="rangetypes">.
</para>
<para>
The <replaceable class="parameter">subtype</replaceable> parameter
can be any type with an associated btree opclass (uses the type's
default btree operator class unless specified with
<replaceable class="parameter">subtype_operator_class</replaceable>).
</para>
</para>
<para>
The <replaceable class="parameter">subtype_diff</replaceable>
function takes two values of type
<replaceable class="parameter">subtype</replaceable> as argument, and
returns the distance between the two values as
<type>double precision</type>. This function is used for GiST indexing
(see <xref linkend="gist"> for more information), and should be provided
for efficiency.
</para>
<para>
The range type's <replaceable class="parameter">subtype</replaceable> can
be any type with an associated btree operator class (to determine the
ordering of values for the range type). Normally the subtype's default
btree operator class is used to determine ordering; to use a non-default
opclass, specify its name with <replaceable
class="parameter">subtype_opclass</replaceable>. If the subtype is
collatable, and you want to use a non-default collation in the range's
ordering, specify the desired collation with the <replaceable
class="parameter">collation</replaceable> option.
</para>
<para>
The <replaceable class="parameter">canonical</replaceable>
function takes an argument and returns a value, both of the same
type being defined. This is used to convert the range value to a
canonical form, when applicable. See <xref linkend="rangetypes">
<para>
The optional <replaceable class="parameter">canonical</replaceable>
function must take one argument of the range type being defined, and
return a value of the same type. This is used to convert the range value
to a canonical form, when applicable. See <xref linkend="rangetypes">
for more information. To define
a <replaceable class="parameter">canonical</replaceable> function,
you must first create a <firstterm>shell type</>, which is a
the <replaceable class="parameter">canonical</replaceable> function,
you must first create a shell type, which is a
placeholder type that has no properties except a name and an
owner. This is done by issuing the command <literal>CREATE TYPE
<replaceable>name</></literal>, with no additional parameters.
</para>
<replaceable>name</></literal>, with no additional parameters. Then
the function can be declared, and finally the range type can be declared,
replacing the shell type entry with a valid range type.
</para>
<para>
The <replaceable class="parameter">analyze</replaceable>
function is the same as for creating a base type.
</para>
<para>
The optional <replaceable class="parameter">subtype_diff</replaceable>
function must take two values of the
<replaceable class="parameter">subtype</replaceable> type as argument,
and return a <type>double precision</type> value representing the
difference between the two given values. While this is optional,
providing it allows much greater efficiency of GiST indexes on columns of
the range type. Note that the <replaceable
class="parameter">subtype_diff</replaceable> function should agree with
the sort ordering implied by the selected operator class and collation;
that is, its result should be positive whenever its first argument is
greater than its second according to the sort ordering.
</para>
<para>
The <replaceable class="parameter">collation</replaceable> option
specifies the collation used when determining the total order for
the range.
</para>
<para>
The optional <replaceable class="parameter">analyze</replaceable>
function performs type-specific statistics collection for columns of the
range type. This is defined the same as for base types; see below.
</para>
</refsect2>
<refsect2>
......@@ -431,7 +449,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<para>
Whenever a user-defined type is created,
<productname>PostgreSQL</productname> automatically creates an
associated array type, whose name consists of the base type's
associated array type, whose name consists of the element type's
name prepended with an underscore, and truncated if necessary to keep
it less than <symbol>NAMEDATALEN</symbol> bytes long. (If the name
so generated collides with an existing type name, the process is
......@@ -496,6 +514,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">collation</replaceable></term>
<listitem>
<para>
The name of an existing collation to be associated with a column of
a composite type, or with a range type.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">label</replaceable></term>
<listitem>
......@@ -506,6 +534,43 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">subtype</replaceable></term>
<listitem>
<para>
The name of the element type that the range type will represent ranges
of.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">subtype_operator_class</replaceable></term>
<listitem>
<para>
The name of a btree operator class for the subtype.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">canonical_function</replaceable></term>
<listitem>
<para>
The name of the canonicalization function for the range type.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">subtype_diff_function</replaceable></term>
<listitem>
<para>
The name of a difference function for the subtype.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">input_function</replaceable></term>
<listitem>
......@@ -699,8 +764,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
<para>
Because there are no restrictions on use of a data type once it's been
created, creating a base type is tantamount to granting public execute
permission on the functions mentioned in the type definition.
created, creating a base type or range type is tantamount to granting
public execute permission on the functions mentioned in the type definition.
This is usually
not an issue for the sorts of functions that are useful in a type
definition. But you might want to think twice before designing a type
......@@ -730,7 +795,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</para>
<para>
Before <productname>PostgreSQL</productname> version 8.2, the syntax
Before <productname>PostgreSQL</productname> version 8.2, the shell-type
creation syntax
<literal>CREATE TYPE <replaceable>name</></literal> did not exist.
The way to create a new base type was to create its input function first.
In this approach, <productname>PostgreSQL</productname> will first see
......@@ -787,6 +853,13 @@ CREATE TABLE bug (
</programlisting>
</para>
<para>
This example creates a range type:
<programlisting>
CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);
</programlisting>
</para>
<para>
This example creates the base data type <type>box</type> and then uses the
type in a table definition:
......@@ -860,7 +933,7 @@ CREATE TABLE big_objs (
<para>
The ability to create a composite type with zero attributes is
a <productname>PostgreSQL</productname>-specific deviation from the
standard (analogous to <command>CREATE TABLE</command>).
standard (analogous to the same case in <command>CREATE TABLE</command>).
</para>
</refsect1>
......
......@@ -243,7 +243,7 @@ INSERT INTO mytab (complex_col.r, complex_col.i) VALUES(1.1, 2.2);
</para>
</sect2>
<sect2>
<sect2 id="rowtypes-io-syntax">
<title>Composite Type Input and Output Syntax</title>
<para>
......
......@@ -2986,7 +2986,8 @@ getTypes(int *numTypes)
/*
* If it's a base type, make a DumpableObject representing a shell
* definition of the type. We will need to dump that ahead of the I/O
* functions for the type.
* functions for the type. Similarly, range types need a shell
* definition in case they have a canonicalize function.
*
* Note: the shell type doesn't have a catId. You might think it
* should copy the base type's catId, but then it might capture the
......@@ -3006,8 +3007,8 @@ getTypes(int *numTypes)
/*
* Initially mark the shell type as not to be dumped. We'll only
* dump it if the I/O functions need to be dumped; this is taken
* care of while sorting dependencies.
* dump it if the I/O or canonicalize functions need to be dumped;
* this is taken care of while sorting dependencies.
*/
stinfo->dobj.dump = false;
......@@ -7340,6 +7341,9 @@ dumpType(Archive *fout, TypeInfo *tyinfo)
dumpEnumType(fout, tyinfo);
else if (tyinfo->typtype == TYPTYPE_RANGE)
dumpRangeType(fout, tyinfo);
else
write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
tyinfo->dobj.name);
}
/*
......
......@@ -636,7 +636,8 @@ findLoop(DumpableObject *obj,
/*
* A user-defined datatype will have a dependency loop with each of its
* I/O functions (since those have the datatype as input or output).
* Break the loop and make the I/O function depend on the associated
* Similarly, a range type will have a loop with its canonicalize function,
* if any. Break the loop by making the function depend on the associated
* shell type, instead.
*/
static void
......@@ -651,7 +652,7 @@ repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
if (typeInfo->shellType)
{
addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
/* Mark shell type as to be dumped if any I/O function is */
/* Mark shell type as to be dumped if any such function is */
if (funcobj->dump)
typeInfo->shellType->dobj.dump = true;
}
......@@ -789,7 +790,7 @@ repairDependencyLoop(DumpableObject **loop,
int i,
j;
/* Datatype and one of its I/O functions */
/* Datatype and one of its I/O or canonicalize functions */
if (nLoop == 2 &&
loop[0]->objType == DO_TYPE &&
loop[1]->objType == DO_FUNC)
......
......@@ -34,7 +34,7 @@
CATALOG(pg_range,3541) BKI_WITHOUT_OIDS
{
Oid rngtypid; /* OID of owning range type */
Oid rngsubtype; /* OID of range's subtype */
Oid rngsubtype; /* OID of range's element type (subtype) */
Oid rngcollation; /* collation for this range type, or 0 */
Oid rngsubopc; /* subtype's btree opclass */
regproc rngcanonical; /* canonicalize range, or 0 */
......
......@@ -61,8 +61,9 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
/*
* typtype is 'b' for a base type, 'c' for a composite type (e.g., a
* table's rowtype), 'd' for a domain type, 'e' for an enum type, or 'p'
* for a pseudo-type. (Use the TYPTYPE macros below.)
* table's rowtype), 'd' for a domain, 'e' for an enum type,
* 'p' for a pseudo-type, or 'r' for a range type.
* (Use the TYPTYPE macros below.)
*
* If typtype is 'c', typrelid is the OID of the class' entry in pg_class.
*/
......
......@@ -56,11 +56,14 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
-----+---------
(0 rows)
-- Look for basic or enum types that don't have an array type.
-- Look for types that should have an array type according to their typtype,
-- but don't. We exclude composites here because we have not bothered to
-- make array types corresponding to the system catalogs' rowtypes.
-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%'
AND NOT EXISTS
(SELECT 1 FROM pg_type as p2
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid and p1.typarray = p2.oid);
......@@ -150,6 +153,19 @@ ORDER BY 1;
30 | oidvector | 54 | oidvectorin
(2 rows)
-- Composites, domains, enums, ranges should all use the same input routines
SELECT DISTINCT typtype, typinput
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'p')
ORDER BY 1;
typtype | typinput
---------+-----------
c | record_in
d | domain_in
e | enum_in
r | range_in
(4 rows)
-- Check for bogus typoutput routines
-- As of 8.0, this check finds refcursor, which is borrowing
-- other types' I/O routines
......@@ -174,6 +190,26 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
-----+---------+-----+---------
(0 rows)
-- Composites, enums, ranges should all use the same output routines
SELECT DISTINCT typtype, typoutput
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'd', 'p')
ORDER BY 1;
typtype | typoutput
---------+------------
c | record_out
e | enum_out
r | range_out
(3 rows)
-- Domains should have same typoutput as their base types
SELECT p1.oid, p1.typname, p2.oid, p2.typname
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
WHERE p1.typtype = 'd' AND p1.typoutput IS DISTINCT FROM p2.typoutput;
oid | typname | oid | typname
-----+---------+-----+---------
(0 rows)
-- Check for bogus typreceive routines
SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
......@@ -222,6 +258,19 @@ WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
-----+---------+-----+---------+-----+---------
(0 rows)
-- Composites, domains, enums, ranges should all use the same receive routines
SELECT DISTINCT typtype, typreceive
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'p')
ORDER BY 1;
typtype | typreceive
---------+-------------
c | record_recv
d | domain_recv
e | enum_recv
r | range_recv
(4 rows)
-- Check for bogus typsend routines
-- As of 7.4, this check finds refcursor, which is borrowing
-- other types' I/O routines
......@@ -246,10 +295,30 @@ WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
-----+---------+-----+---------
(0 rows)
-- Composites, enums, ranges should all use the same send routines
SELECT DISTINCT typtype, typsend
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'd', 'p')
ORDER BY 1;
typtype | typsend
---------+-------------
c | record_send
e | enum_send
r | range_send
(3 rows)
-- Domains should have same typsend as their base types
SELECT p1.oid, p1.typname, p2.oid, p2.typname
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
WHERE p1.typtype = 'd' AND p1.typsend IS DISTINCT FROM p2.typsend;
oid | typname | oid | typname
-----+---------+-----+---------
(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
WHERE p1.typmodin = p2.oid AND NOT
(p2.pronargs = 1 AND
p2.proargtypes[0] = 'cstring[]'::regtype AND
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
......@@ -260,7 +329,7 @@ WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT
-- 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
WHERE p1.typmodout = p2.oid AND NOT
(p2.pronargs = 1 AND
p2.proargtypes[0] = 'int4'::regtype AND
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
......@@ -298,7 +367,7 @@ WHERE p1.typarray = p2.oid AND
-- 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
WHERE p1.typanalyze = p2.oid AND NOT
(p2.pronargs = 1 AND
p2.proargtypes[0] = 'internal'::regtype AND
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
......
......@@ -50,12 +50,15 @@ FROM pg_type as p1
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
(p1.typtype != 'c' AND p1.typrelid != 0);
-- Look for basic or enum types that don't have an array type.
-- Look for types that should have an array type according to their typtype,
-- but don't. We exclude composites here because we have not bothered to
-- make array types corresponding to the system catalogs' rowtypes.
-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%'
AND NOT EXISTS
(SELECT 1 FROM pg_type as p2
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid and p1.typarray = p2.oid);
......@@ -117,6 +120,12 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND
(p2.oid = 'array_in'::regproc)
ORDER BY 1;
-- Composites, domains, enums, ranges should all use the same input routines
SELECT DISTINCT typtype, typinput
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'p')
ORDER BY 1;
-- Check for bogus typoutput routines
-- As of 8.0, this check finds refcursor, which is borrowing
......@@ -135,6 +144,17 @@ FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
(p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
-- Composites, enums, ranges should all use the same output routines
SELECT DISTINCT typtype, typoutput
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'd', 'p')
ORDER BY 1;
-- Domains should have same typoutput as their base types
SELECT p1.oid, p1.typname, p2.oid, p2.typname
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
WHERE p1.typtype = 'd' AND p1.typoutput IS DISTINCT FROM p2.typoutput;
-- Check for bogus typreceive routines
SELECT p1.oid, p1.typname, p2.oid, p2.proname
......@@ -169,6 +189,12 @@ FROM pg_type AS p1, pg_proc AS p2, pg_proc AS p3
WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
p2.pronargs != p3.pronargs;
-- Composites, domains, enums, ranges should all use the same receive routines
SELECT DISTINCT typtype, typreceive
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'p')
ORDER BY 1;
-- Check for bogus typsend routines
-- As of 7.4, this check finds refcursor, which is borrowing
......@@ -187,11 +213,22 @@ 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);
-- Composites, enums, ranges should all use the same send routines
SELECT DISTINCT typtype, typsend
FROM pg_type AS p1
WHERE p1.typtype not in ('b', 'd', 'p')
ORDER BY 1;
-- Domains should have same typsend as their base types
SELECT p1.oid, p1.typname, p2.oid, p2.typname
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
WHERE p1.typtype = 'd' AND p1.typsend IS DISTINCT FROM p2.typsend;
-- 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
WHERE p1.typmodin = p2.oid AND NOT
(p2.pronargs = 1 AND
p2.proargtypes[0] = 'cstring[]'::regtype AND
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
......@@ -200,7 +237,7 @@ WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT
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
WHERE p1.typmodout = p2.oid AND NOT
(p2.pronargs = 1 AND
p2.proargtypes[0] = 'int4'::regtype AND
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
......@@ -230,7 +267,7 @@ WHERE p1.typarray = p2.oid AND
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
WHERE p1.typanalyze = p2.oid AND NOT
(p2.pronargs = 1 AND
p2.proargtypes[0] = 'internal'::regtype AND
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册