Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in operator/function resolution. Introduce a well-defined promotion hierarchy for numeric datatypes (int2->int4->int8->numeric->float4->float8). Change make_const to initially label numeric literals as int4, int8, or numeric (never float8 anymore). Explicitly mark Func and RelabelType nodes to indicate whether they came from a function call, explicit cast, or implicit cast; use this to do reverse-listing more accurately and without so many heuristics. Explicit casts to char, varchar, bit, varbit will truncate or pad without raising an error (the pre-7.2 behavior), while assigning to a column without any explicit cast will still raise an error for wrong-length data like 7.3. This more nearly follows the SQL spec than 7.2 behavior (we should be reporting a 'completion condition' in the explicit-cast cases, but we have no mechanism for that, so just do silent truncation). Fix some problems with enforcement of typmod for array elements; it didn't work at all in 'UPDATE ... SET array[n] = foo', for example. Provide a generalized array_length_coerce() function to replace the specialized per-array-type functions that used to be needed (and were missing for NUMERIC as well as all the datetime types). Add missing conversions int8<->float4, text<->numeric, oid<->int8. initdb forced.
This commit is contained in:
parent
cc70ba2e4d
commit
b26dfb9522
@ -1,6 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.59 2002/09/03 01:04:40 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.60 2002/09/18 21:35:20 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="catalogs">
|
<chapter id="catalogs">
|
||||||
@ -841,9 +841,8 @@
|
|||||||
<title>pg_cast</title>
|
<title>pg_cast</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<structname>pg_cast</structname> stores data type conversion paths
|
<structname>pg_cast</structname> stores data type conversion paths,
|
||||||
defined with <command>CREATE CAST</command> plus the built-in
|
both built-in paths and those defined with <command>CREATE CAST</command>.
|
||||||
conversions.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@ -879,17 +878,25 @@
|
|||||||
<entry><type>oid</type></entry>
|
<entry><type>oid</type></entry>
|
||||||
<entry>pg_proc.oid</entry>
|
<entry>pg_proc.oid</entry>
|
||||||
<entry>
|
<entry>
|
||||||
The OID of the function to use to perform this cast. A 0 is
|
The OID of the function to use to perform this cast. Zero is
|
||||||
stored if the data types are binary compatible (that is, no
|
stored if the data types are binary coercible (that is, no
|
||||||
function is needed to perform the cast).
|
run-time operation is needed to perform the cast).
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>castimplicit</entry>
|
<entry>castcontext</entry>
|
||||||
<entry><type>bool</type></entry>
|
<entry><type>char</type></entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
<entry>Indication whether this cast can be invoked implicitly</entry>
|
<entry>
|
||||||
|
Indicates what contexts the cast may be invoked in.
|
||||||
|
<literal>e</> means only as an explicit cast (using
|
||||||
|
<literal>CAST</>, <literal>::</>, or function-call syntax).
|
||||||
|
<literal>a</> means implicitly in assignment
|
||||||
|
to a target column, as well as explicitly.
|
||||||
|
<literal>i</> means implicitly in expressions, as well as the
|
||||||
|
other cases.
|
||||||
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.102 2002/08/23 02:54:18 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.103 2002/09/18 21:35:20 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="datatype">
|
<chapter id="datatype">
|
||||||
@ -823,8 +823,19 @@ CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
|
|||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
Prior to <productname>PostgreSQL</> 7.2, strings that were too long were silently
|
If one explicitly casts a value to
|
||||||
truncated, no error was raised.
|
<type>character(<replaceable>n</>)</type> or <type>character
|
||||||
|
varying(<replaceable>n</>)</type>, then an overlength value will
|
||||||
|
be truncated to <replaceable>n</> characters without raising an
|
||||||
|
error. (This too is required by the SQL standard.)
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Prior to <productname>PostgreSQL</> 7.2, strings that were too long were
|
||||||
|
always truncated without raising an error, in either explicit or
|
||||||
|
implicit casting contexts.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
@ -897,12 +908,14 @@ INSERT INTO test2 VALUES ('ok');
|
|||||||
INSERT INTO test2 VALUES ('good ');
|
INSERT INTO test2 VALUES ('good ');
|
||||||
INSERT INTO test2 VALUES ('too long');
|
INSERT INTO test2 VALUES ('too long');
|
||||||
<computeroutput>ERROR: value too long for type character varying(5)</computeroutput>
|
<computeroutput>ERROR: value too long for type character varying(5)</computeroutput>
|
||||||
|
INSERT INTO test2 VALUES ('too long'::varchar(5)); -- explicit truncation
|
||||||
SELECT b, char_length(b) FROM test2;
|
SELECT b, char_length(b) FROM test2;
|
||||||
<computeroutput>
|
<computeroutput>
|
||||||
b | char_length
|
b | char_length
|
||||||
-------+-------------
|
-------+-------------
|
||||||
ok | 2
|
ok | 2
|
||||||
good | 5
|
good | 5
|
||||||
|
too l | 5
|
||||||
</computeroutput>
|
</computeroutput>
|
||||||
</programlisting>
|
</programlisting>
|
||||||
<calloutlist>
|
<calloutlist>
|
||||||
@ -932,7 +945,7 @@ SELECT b, char_length(b) FROM test2;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table tocentry="1">
|
<table tocentry="1">
|
||||||
<title>Specialty Character Type</title>
|
<title>Specialty Character Types</title>
|
||||||
<tgroup cols="3">
|
<tgroup cols="3">
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
@ -2832,29 +2845,39 @@ SELECT * FROM test1 WHERE a;
|
|||||||
<para>
|
<para>
|
||||||
Bit strings are strings of 1's and 0's. They can be used to store
|
Bit strings are strings of 1's and 0's. They can be used to store
|
||||||
or visualize bit masks. There are two SQL bit types:
|
or visualize bit masks. There are two SQL bit types:
|
||||||
<type>BIT(<replaceable>x</replaceable>)</type> and <type>BIT
|
<type>BIT(<replaceable>n</replaceable>)</type> and <type>BIT
|
||||||
VARYING(<replaceable>x</replaceable>)</type>; where
|
VARYING(<replaceable>n</replaceable>)</type>, where
|
||||||
<replaceable>x</replaceable> is a positive integer.
|
<replaceable>n</replaceable> is a positive integer.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<type>BIT</type> type data must match the length
|
<type>BIT</type> type data must match the length
|
||||||
<replaceable>x</replaceable> exactly; it is an error to attempt to
|
<replaceable>n</replaceable> exactly; it is an error to attempt to
|
||||||
store shorter or longer bit strings. <type>BIT VARYING</type> is
|
store shorter or longer bit strings. <type>BIT VARYING</type> data is
|
||||||
of variable length up to the maximum length
|
of variable length up to the maximum length
|
||||||
<replaceable>x</replaceable>; longer strings will be rejected.
|
<replaceable>n</replaceable>; longer strings will be rejected.
|
||||||
<type>BIT</type> without length is equivalent to
|
Writing <type>BIT</type> without a length is equivalent to
|
||||||
<literal>BIT(1)</literal>, <type>BIT VARYING</type> without length
|
<literal>BIT(1)</literal>, while <type>BIT VARYING</type> without a length
|
||||||
specification means unlimited length.
|
specification means unlimited length.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
Prior to <productname>PostgreSQL</> 7.2, <type>BIT</type> type data was
|
If one explicitly casts a bit-string value to
|
||||||
zero-padded on the right. This was changed to comply with the
|
<type>BIT(<replaceable>n</>)</type>, it will be truncated or
|
||||||
SQL standard. To implement zero-padded bit strings, a
|
zero-padded on the right to be exactly <replaceable>n</> bits,
|
||||||
combination of the concatenation operator and the
|
without raising an error. Similarly,
|
||||||
<function>substring</function> function can be used.
|
if one explicitly casts a bit-string value to
|
||||||
|
<type>BIT VARYING(<replaceable>n</>)</type>, it will be truncated
|
||||||
|
on the right if it is more than <replaceable>n</> bits.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Prior to <productname>PostgreSQL</> 7.2, <type>BIT</type> data was
|
||||||
|
always silently truncated or zero-padded on the right, with or without an
|
||||||
|
explicit cast. This was changed to comply with the SQL standard.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
@ -2874,9 +2897,16 @@ CREATE TABLE test (a BIT(3), b BIT VARYING(5));
|
|||||||
INSERT INTO test VALUES (B'101', B'00');
|
INSERT INTO test VALUES (B'101', B'00');
|
||||||
INSERT INTO test VALUES (B'10', B'101');
|
INSERT INTO test VALUES (B'10', B'101');
|
||||||
<computeroutput>
|
<computeroutput>
|
||||||
ERROR: bit string length does not match type bit(3)
|
ERROR: Bit string length 2 does not match type BIT(3)
|
||||||
|
</computeroutput>
|
||||||
|
INSERT INTO test VALUES (B'10'::bit(3), B'101');
|
||||||
|
SELECT * FROM test;
|
||||||
|
<computeroutput>
|
||||||
|
a | b
|
||||||
|
-----+-----
|
||||||
|
101 | 00
|
||||||
|
100 | 101
|
||||||
</computeroutput>
|
</computeroutput>
|
||||||
SELECT SUBSTRING(b FROM 1 FOR 2) FROM test;
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.4 2002/09/15 13:04:16 petere Exp $ -->
|
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.5 2002/09/18 21:35:20 tgl Exp $ -->
|
||||||
|
|
||||||
<refentry id="SQL-CREATECAST">
|
<refentry id="SQL-CREATECAST">
|
||||||
<refmeta>
|
<refmeta>
|
||||||
@ -15,11 +15,11 @@
|
|||||||
<synopsis>
|
<synopsis>
|
||||||
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
|
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
|
||||||
WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtype</replaceable>)
|
WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtype</replaceable>)
|
||||||
[AS ASSIGNMENT]
|
[ AS ASSIGNMENT | AS IMPLICIT ]
|
||||||
|
|
||||||
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
|
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
|
||||||
WITHOUT FUNCTION
|
WITHOUT FUNCTION
|
||||||
[AS ASSIGNMENT]
|
[ AS ASSIGNMENT | AS IMPLICIT ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -49,20 +49,44 @@ SELECT CAST(42 AS text);
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
A cast can be marked <literal>AS ASSIGNMENT</>, which means that it
|
By default, a cast can be invoked only by an explicit cast request,
|
||||||
can be invoked implicitly in any context where the conversion it
|
that is an explicit <literal>CAST(<replaceable>x</> AS
|
||||||
defines is required. Cast functions not so marked can be invoked
|
<replaceable>typename</>)</literal>,
|
||||||
only by explicit <literal>CAST</>,
|
|
||||||
<replaceable>x</><literal>::</><replaceable>typename</>, or
|
<replaceable>x</><literal>::</><replaceable>typename</>, or
|
||||||
<replaceable>typename</>(<replaceable>x</>) constructs. For
|
<replaceable>typename</>(<replaceable>x</>) construct.
|
||||||
example, supposing that <literal>foo.f1</literal> is a column of
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If the cast is marked <literal>AS ASSIGNMENT</> then it can be invoked
|
||||||
|
implicitly when assigning to a column of the target data type.
|
||||||
|
For example, supposing that <literal>foo.f1</literal> is a column of
|
||||||
type <type>text</type>, then
|
type <type>text</type>, then
|
||||||
<programlisting>
|
<programlisting>
|
||||||
INSERT INTO foo(f1) VALUES(42);
|
INSERT INTO foo(f1) VALUES(42);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
will be allowed if the cast from type <type>integer</type> to type
|
will be allowed if the cast from type <type>integer</type> to type
|
||||||
<type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise
|
<type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise
|
||||||
not. (We generally use the term <firstterm>implicit
|
not.
|
||||||
|
(We generally use the term <firstterm>assignment
|
||||||
|
cast</firstterm> to describe this kind of cast.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If the cast is marked <literal>AS IMPLICIT</> then it can be invoked
|
||||||
|
implicitly in any context, whether assignment or internally in an
|
||||||
|
expression. For example, since <literal>||</> takes <type>text</>
|
||||||
|
arguments,
|
||||||
|
<programlisting>
|
||||||
|
SELECT 'The time is ' || now();
|
||||||
|
</programlisting>
|
||||||
|
will be allowed only if the cast from type <type>timestamp</> to
|
||||||
|
<type>text</type> is marked <literal>AS IMPLICIT</>. Otherwise it
|
||||||
|
will be necessary to write one of
|
||||||
|
<programlisting>
|
||||||
|
SELECT 'The time is ' || CAST(now() AS text);
|
||||||
|
SELECT 'The time is ' || now()::text;
|
||||||
|
</programlisting>
|
||||||
|
(We generally use the term <firstterm>implicit
|
||||||
cast</firstterm> to describe this kind of cast.)
|
cast</firstterm> to describe this kind of cast.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -74,10 +98,11 @@ INSERT INTO foo(f1) VALUES(42);
|
|||||||
all because there are multiple possible interpretations. A good
|
all because there are multiple possible interpretations. A good
|
||||||
rule of thumb is to make a cast implicitly invokable only for
|
rule of thumb is to make a cast implicitly invokable only for
|
||||||
information-preserving transformations between types in the same
|
information-preserving transformations between types in the same
|
||||||
general type category. For example, <type>int2</type> to
|
general type category. For example, the cast from <type>int2</type> to
|
||||||
<type>int4</type> casts can reasonably be implicit, but be wary of
|
<type>int4</type> can reasonably be implicit, but the cast from
|
||||||
marking <type>int4</type> to <type>text</type> or
|
<type>float8</type> to <type>int4</type> should probably be
|
||||||
<type>float8</type> to <type>int4</type> as implicit casts.
|
assignment-only. Cross-type-category casts, such as <type>text</>
|
||||||
|
to <type>int4</>, are best made explicit-only.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -138,7 +163,18 @@ INSERT INTO foo(f1) VALUES(42);
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Indicates that the cast may be invoked implicitly.
|
Indicates that the cast may be invoked implicitly in assignment
|
||||||
|
contexts.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>AS IMPLICIT</literal></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Indicates that the cast may be invoked implicitly in any context.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -163,10 +199,10 @@ INSERT INTO foo(f1) VALUES(42);
|
|||||||
data type, returned that data type, and took one argument of a
|
data type, returned that data type, and took one argument of a
|
||||||
different type was automatically a cast function. This convention has
|
different type was automatically a cast function. This convention has
|
||||||
been abandoned in face of the introduction of schemas and to be
|
been abandoned in face of the introduction of schemas and to be
|
||||||
able to represent binary compatible casts in the catalogs. The built-in
|
able to represent binary compatible casts in the catalogs. (The built-in
|
||||||
cast functions
|
cast functions
|
||||||
still follow this naming scheme, but they have to be declared as
|
still follow this naming scheme, but they have to be shown as
|
||||||
casts explicitly now.
|
casts in <literal>pg_cast</> now.)
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@ -191,7 +227,8 @@ CREATE CAST (text AS int4) WITH FUNCTION int4(text);
|
|||||||
<para>
|
<para>
|
||||||
The <command>CREATE CAST</command> command conforms to SQL99,
|
The <command>CREATE CAST</command> command conforms to SQL99,
|
||||||
except that SQL99 does not make provisions for binary compatible
|
except that SQL99 does not make provisions for binary compatible
|
||||||
types.
|
types. <literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname>
|
||||||
|
extension, too.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.158 2002/09/04 07:16:32 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.159 2002/09/18 21:35:20 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<appendix id="release">
|
<appendix id="release">
|
||||||
@ -24,6 +24,8 @@ CDATA means the content is "SGML-free", so you can write without
|
|||||||
worries about funny characters.
|
worries about funny characters.
|
||||||
-->
|
-->
|
||||||
<literallayout><![CDATA[
|
<literallayout><![CDATA[
|
||||||
|
Mixed numeric-and-float expressions are evaluated as float, per SQL spec
|
||||||
|
Explicit casts to char, varchar, bit, varbit will truncate or pad without error
|
||||||
CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE are available
|
CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE are available
|
||||||
No-autocommit mode is available (set autocommit to off)
|
No-autocommit mode is available (set autocommit to off)
|
||||||
Substantial improvements in functionality for functions returning sets
|
Substantial improvements in functionality for functions returning sets
|
||||||
|
@ -804,13 +804,9 @@ If the non-unknown inputs are not all of the same type category, fail.
|
|||||||
|
|
||||||
<step performance="required">
|
<step performance="required">
|
||||||
<para>
|
<para>
|
||||||
If one or more non-unknown inputs are of a preferred type in that category,
|
Choose the first non-unknown input type which is a preferred type in
|
||||||
resolve as that type.
|
that category or allows all the non-unknown inputs to be implicitly
|
||||||
</para></step>
|
coerced to it.
|
||||||
|
|
||||||
<step performance="required">
|
|
||||||
<para>
|
|
||||||
Otherwise, resolve as the type of the first non-unknown input.
|
|
||||||
</para></step>
|
</para></step>
|
||||||
|
|
||||||
<step performance="required">
|
<step performance="required">
|
||||||
@ -842,15 +838,16 @@ Here, the unknown-type literal <literal>'b'</literal> will be resolved as type t
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
<screen>
|
<screen>
|
||||||
tgl=> SELECT 1.2 AS "Double" UNION SELECT 1;
|
tgl=> SELECT 1.2 AS "Numeric" UNION SELECT 1;
|
||||||
Double
|
Numeric
|
||||||
--------
|
---------
|
||||||
1
|
1
|
||||||
1.2
|
1.2
|
||||||
(2 rows)
|
(2 rows)
|
||||||
</screen>
|
</screen>
|
||||||
The literal <literal>1.2</> is of type <type>double precision</>,
|
The literal <literal>1.2</> is of type <type>numeric</>,
|
||||||
the preferred type in the numeric category, so that type is used.
|
and the integer value <literal>1</> can be cast implicitly to
|
||||||
|
<type>numeric</>, so that type is used.
|
||||||
</para>
|
</para>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
@ -858,27 +855,18 @@ the preferred type in the numeric category, so that type is used.
|
|||||||
<title>Type Conversion in a Transposed Union</title>
|
<title>Type Conversion in a Transposed Union</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Here the output type of the union is forced to match the type of
|
|
||||||
the first clause in the union:
|
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
tgl=> SELECT 1 AS "All integers"
|
tgl=> SELECT 1 AS "Real"
|
||||||
tgl-> UNION SELECT CAST('2.2' AS REAL);
|
tgl-> UNION SELECT CAST('2.2' AS REAL);
|
||||||
All integers
|
Real
|
||||||
--------------
|
------
|
||||||
1
|
1
|
||||||
2
|
2.2
|
||||||
(2 rows)
|
(2 rows)
|
||||||
</screen>
|
</screen>
|
||||||
</para>
|
Here, since type <type>real</> cannot be implicitly cast to <type>integer</>,
|
||||||
<para>
|
but <type>integer</> can be implicitly cast to <type>real</>, the union
|
||||||
Since <type>REAL</type> is not a preferred type, the parser sees no reason
|
result type is resolved as <type>real</>.
|
||||||
to select it over <type>INTEGER</type> (which is what the 1 is), and instead
|
|
||||||
falls back on the use-the-first-alternative rule.
|
|
||||||
This example demonstrates that the preferred-type mechanism doesn't encode
|
|
||||||
as much information as we'd like. Future versions of
|
|
||||||
<productname>PostgreSQL</productname> may support a more general notion of
|
|
||||||
type preferences.
|
|
||||||
</para>
|
</para>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.226 2002/09/14 22:14:49 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.227 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -51,7 +51,6 @@
|
|||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "parser/parse_target.h"
|
|
||||||
#include "rewrite/rewriteRemove.h"
|
#include "rewrite/rewriteRemove.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
@ -1705,17 +1704,16 @@ cookDefault(ParseState *pstate,
|
|||||||
{
|
{
|
||||||
Oid type_id = exprType(expr);
|
Oid type_id = exprType(expr);
|
||||||
|
|
||||||
if (type_id != atttypid)
|
if (coerce_to_target_type(expr, type_id,
|
||||||
{
|
atttypid, atttypmod,
|
||||||
if (CoerceTargetExpr(pstate, expr, type_id,
|
COERCION_ASSIGNMENT,
|
||||||
atttypid, atttypmod, false) == NULL)
|
COERCE_IMPLICIT_CAST) == NULL)
|
||||||
elog(ERROR, "Column \"%s\" is of type %s"
|
elog(ERROR, "Column \"%s\" is of type %s"
|
||||||
" but default expression is of type %s"
|
" but default expression is of type %s"
|
||||||
"\n\tYou will need to rewrite or cast the expression",
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
attname,
|
attname,
|
||||||
format_type_be(atttypid),
|
format_type_be(atttypid),
|
||||||
format_type_be(type_id));
|
format_type_be(type_id));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.55 2002/09/04 20:31:14 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.56 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -95,7 +95,7 @@ AggregateCreate(const char *aggName,
|
|||||||
*/
|
*/
|
||||||
if (proc->proisstrict && agginitval == NULL)
|
if (proc->proisstrict && agginitval == NULL)
|
||||||
{
|
{
|
||||||
if (!IsBinaryCompatible(aggBaseType, aggTransType))
|
if (!IsBinaryCoercible(aggBaseType, aggTransType))
|
||||||
elog(ERROR, "must not omit initval when transfn is strict and transtype is not compatible with input type");
|
elog(ERROR, "must not omit initval when transfn is strict and transtype is not compatible with input type");
|
||||||
}
|
}
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.93 2002/09/04 20:31:14 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.94 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -369,7 +369,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
|
|||||||
format_type_be(rettype));
|
format_type_be(rettype));
|
||||||
|
|
||||||
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
|
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
|
||||||
if (!IsBinaryCompatible(restype, rettype))
|
if (!IsBinaryCoercible(restype, rettype))
|
||||||
elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
|
elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
|
||||||
format_type_be(rettype), format_type_be(restype));
|
format_type_be(rettype), format_type_be(restype));
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
|
|||||||
if (tlistlen == 1)
|
if (tlistlen == 1)
|
||||||
{
|
{
|
||||||
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
|
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
|
||||||
if (IsBinaryCompatible(restype, rettype))
|
if (IsBinaryCoercible(restype, rettype))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +426,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
|
|||||||
|
|
||||||
tletype = exprType(tle->expr);
|
tletype = exprType(tle->expr);
|
||||||
atttype = attr->atttypid;
|
atttype = attr->atttypid;
|
||||||
if (!IsBinaryCompatible(tletype, atttype))
|
if (!IsBinaryCoercible(tletype, atttype))
|
||||||
elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
|
elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
|
||||||
format_type_be(rettype),
|
format_type_be(rettype),
|
||||||
format_type_be(tletype),
|
format_type_be(tletype),
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.20 2002/09/15 13:04:16 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.21 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* These routines take the parse tree and pick out the
|
* These routines take the parse tree and pick out the
|
||||||
@ -601,14 +601,11 @@ CreateCast(CreateCastStmt *stmt)
|
|||||||
Oid sourcetypeid;
|
Oid sourcetypeid;
|
||||||
Oid targettypeid;
|
Oid targettypeid;
|
||||||
Oid funcid;
|
Oid funcid;
|
||||||
HeapTuple tuple;
|
char castcontext;
|
||||||
Relation relation;
|
Relation relation;
|
||||||
Form_pg_proc procstruct;
|
HeapTuple tuple;
|
||||||
|
Datum values[Natts_pg_cast];
|
||||||
Datum values[Natts_pg_proc];
|
char nulls[Natts_pg_cast];
|
||||||
char nulls[Natts_pg_proc];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ObjectAddress myself,
|
ObjectAddress myself,
|
||||||
referenced;
|
referenced;
|
||||||
|
|
||||||
@ -648,24 +645,17 @@ CreateCast(CreateCastStmt *stmt)
|
|||||||
TypeNameToString(stmt->sourcetype),
|
TypeNameToString(stmt->sourcetype),
|
||||||
TypeNameToString(stmt->targettype));
|
TypeNameToString(stmt->targettype));
|
||||||
|
|
||||||
relation = heap_openr(CastRelationName, RowExclusiveLock);
|
|
||||||
|
|
||||||
tuple = SearchSysCache(CASTSOURCETARGET,
|
|
||||||
ObjectIdGetDatum(sourcetypeid),
|
|
||||||
ObjectIdGetDatum(targettypeid),
|
|
||||||
0, 0);
|
|
||||||
if (HeapTupleIsValid(tuple))
|
|
||||||
elog(ERROR, "cast from data type %s to data type %s already exists",
|
|
||||||
TypeNameToString(stmt->sourcetype),
|
|
||||||
TypeNameToString(stmt->targettype));
|
|
||||||
|
|
||||||
if (stmt->func != NULL)
|
if (stmt->func != NULL)
|
||||||
{
|
{
|
||||||
|
Form_pg_proc procstruct;
|
||||||
|
|
||||||
funcid = LookupFuncNameTypeNames(stmt->func->funcname,
|
funcid = LookupFuncNameTypeNames(stmt->func->funcname,
|
||||||
stmt->func->funcargs,
|
stmt->func->funcargs,
|
||||||
"CreateCast");
|
"CreateCast");
|
||||||
|
|
||||||
tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0);
|
tuple = SearchSysCache(PROCOID,
|
||||||
|
ObjectIdGetDatum(funcid),
|
||||||
|
0, 0, 0);
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
elog(ERROR, "cache lookup of function %u failed", funcid);
|
elog(ERROR, "cache lookup of function %u failed", funcid);
|
||||||
|
|
||||||
@ -687,18 +677,51 @@ CreateCast(CreateCastStmt *stmt)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* indicates binary compatibility */
|
/* indicates binary coercibility */
|
||||||
funcid = InvalidOid;
|
funcid = InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* convert CoercionContext enum to char value for castcontext */
|
||||||
|
switch (stmt->context)
|
||||||
|
{
|
||||||
|
case COERCION_IMPLICIT:
|
||||||
|
castcontext = COERCION_CODE_IMPLICIT;
|
||||||
|
break;
|
||||||
|
case COERCION_ASSIGNMENT:
|
||||||
|
castcontext = COERCION_CODE_ASSIGNMENT;
|
||||||
|
break;
|
||||||
|
case COERCION_EXPLICIT:
|
||||||
|
castcontext = COERCION_CODE_EXPLICIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "CreateCast: bogus CoercionContext %c", stmt->context);
|
||||||
|
castcontext = 0; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
relation = heap_openr(CastRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for duplicate. This is just to give a friendly error message,
|
||||||
|
* the unique index would catch it anyway (so no need to sweat about
|
||||||
|
* race conditions).
|
||||||
|
*/
|
||||||
|
tuple = SearchSysCache(CASTSOURCETARGET,
|
||||||
|
ObjectIdGetDatum(sourcetypeid),
|
||||||
|
ObjectIdGetDatum(targettypeid),
|
||||||
|
0, 0);
|
||||||
|
if (HeapTupleIsValid(tuple))
|
||||||
|
elog(ERROR, "cast from data type %s to data type %s already exists",
|
||||||
|
TypeNameToString(stmt->sourcetype),
|
||||||
|
TypeNameToString(stmt->targettype));
|
||||||
|
|
||||||
/* ready to go */
|
/* ready to go */
|
||||||
values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
|
values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
|
||||||
values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
|
values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
|
||||||
values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
|
values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
|
||||||
values[Anum_pg_cast_castimplicit - 1] = BoolGetDatum(stmt->implicit);
|
values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
|
||||||
|
|
||||||
for (i = 0; i < Natts_pg_cast; ++i)
|
MemSet(nulls, ' ', Natts_pg_cast);
|
||||||
nulls[i] = ' ';
|
|
||||||
|
|
||||||
tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
|
tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
|
||||||
|
|
||||||
@ -706,6 +729,7 @@ CreateCast(CreateCastStmt *stmt)
|
|||||||
|
|
||||||
CatalogUpdateIndexes(relation, tuple);
|
CatalogUpdateIndexes(relation, tuple);
|
||||||
|
|
||||||
|
/* make dependency entries */
|
||||||
myself.classId = RelationGetRelid(relation);
|
myself.classId = RelationGetRelid(relation);
|
||||||
myself.objectId = HeapTupleGetOid(tuple);
|
myself.objectId = HeapTupleGetOid(tuple);
|
||||||
myself.objectSubId = 0;
|
myself.objectSubId = 0;
|
||||||
@ -732,6 +756,7 @@ CreateCast(CreateCastStmt *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
|
|
||||||
heap_close(relation, RowExclusiveLock);
|
heap_close(relation, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.87 2002/09/04 20:31:15 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.88 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -335,8 +335,8 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
|||||||
|
|
||||||
for (i = 0; i < nargs; i++)
|
for (i = 0; i < nargs; i++)
|
||||||
{
|
{
|
||||||
if (!IsBinaryCompatible(argTypes[i], true_typeids[i]))
|
if (!IsBinaryCoercible(argTypes[i], true_typeids[i]))
|
||||||
func_error("DefineIndex", funcIndex->funcname, nargs, argTypes,
|
func_error("DefineIndex", funcIndex->funcname, nargs, true_typeids,
|
||||||
"Index function must be binary-compatible with table datatype");
|
"Index function must be binary-compatible with table datatype");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +464,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
|||||||
opClassId = HeapTupleGetOid(tuple);
|
opClassId = HeapTupleGetOid(tuple);
|
||||||
opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
|
opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
|
||||||
|
|
||||||
if (!IsBinaryCompatible(attrType, opInputType))
|
if (!IsBinaryCoercible(attrType, opInputType))
|
||||||
elog(ERROR, "operator class \"%s\" does not accept data type %s",
|
elog(ERROR, "operator class \"%s\" does not accept data type %s",
|
||||||
NameListToString(attribute->opclass), format_type_be(attrType));
|
NameListToString(attribute->opclass), format_type_be(attrType));
|
||||||
|
|
||||||
@ -508,7 +508,7 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
|
|||||||
nexact++;
|
nexact++;
|
||||||
exactOid = opclass->oid;
|
exactOid = opclass->oid;
|
||||||
}
|
}
|
||||||
else if (IsBinaryCompatible(opclass->opcintype, attrType))
|
else if (IsBinaryCoercible(attrType, opclass->opcintype))
|
||||||
{
|
{
|
||||||
ncompatible++;
|
ncompatible++;
|
||||||
compatibleOid = opclass->oid;
|
compatibleOid = opclass->oid;
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.86 2002/09/04 20:31:18 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.87 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -913,7 +913,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||||||
*/
|
*/
|
||||||
Oid inputType = exprType(aggref->target);
|
Oid inputType = exprType(aggref->target);
|
||||||
|
|
||||||
if (!IsBinaryCompatible(inputType, aggform->aggtranstype))
|
if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
|
||||||
elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
|
elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
|
||||||
aggref->aggfnoid);
|
aggref->aggfnoid);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.211 2002/09/04 20:31:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.212 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -850,6 +850,7 @@ _copyFunc(Func *from)
|
|||||||
newnode->funcid = from->funcid;
|
newnode->funcid = from->funcid;
|
||||||
newnode->funcresulttype = from->funcresulttype;
|
newnode->funcresulttype = from->funcresulttype;
|
||||||
newnode->funcretset = from->funcretset;
|
newnode->funcretset = from->funcretset;
|
||||||
|
newnode->funcformat = from->funcformat;
|
||||||
/* Do not copy the run-time state, if any */
|
/* Do not copy the run-time state, if any */
|
||||||
newnode->func_fcache = NULL;
|
newnode->func_fcache = NULL;
|
||||||
|
|
||||||
@ -931,6 +932,7 @@ _copyRelabelType(RelabelType *from)
|
|||||||
Node_Copy(from, newnode, arg);
|
Node_Copy(from, newnode, arg);
|
||||||
newnode->resulttype = from->resulttype;
|
newnode->resulttype = from->resulttype;
|
||||||
newnode->resulttypmod = from->resulttypmod;
|
newnode->resulttypmod = from->resulttypmod;
|
||||||
|
newnode->relabelformat = from->relabelformat;
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
@ -2634,7 +2636,7 @@ _copyCreateCastStmt(CreateCastStmt *from)
|
|||||||
Node_Copy(from, newnode, sourcetype);
|
Node_Copy(from, newnode, sourcetype);
|
||||||
Node_Copy(from, newnode, targettype);
|
Node_Copy(from, newnode, targettype);
|
||||||
Node_Copy(from, newnode, func);
|
Node_Copy(from, newnode, func);
|
||||||
newnode->implicit = from->implicit;
|
newnode->context = from->context;
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.158 2002/09/02 02:13:01 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.159 2002/09/18 21:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -217,6 +217,15 @@ _equalFunc(Func *a, Func *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->funcretset != b->funcretset)
|
if (a->funcretset != b->funcretset)
|
||||||
return false;
|
return false;
|
||||||
|
/*
|
||||||
|
* Special-case COERCE_DONTCARE, so that pathkeys can build coercion
|
||||||
|
* nodes that are equal() to both explicit and implicit coercions.
|
||||||
|
*/
|
||||||
|
if (a->funcformat != b->funcformat &&
|
||||||
|
a->funcformat != COERCE_DONTCARE &&
|
||||||
|
b->funcformat != COERCE_DONTCARE)
|
||||||
|
return false;
|
||||||
|
|
||||||
/* Note we do not look at func_fcache; see notes for _equalOper */
|
/* Note we do not look at func_fcache; see notes for _equalOper */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -302,6 +311,14 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->resulttypmod != b->resulttypmod)
|
if (a->resulttypmod != b->resulttypmod)
|
||||||
return false;
|
return false;
|
||||||
|
/*
|
||||||
|
* Special-case COERCE_DONTCARE, so that pathkeys can build coercion
|
||||||
|
* nodes that are equal() to both explicit and implicit coercions.
|
||||||
|
*/
|
||||||
|
if (a->relabelformat != b->relabelformat &&
|
||||||
|
a->relabelformat != COERCE_DONTCARE &&
|
||||||
|
b->relabelformat != COERCE_DONTCARE)
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1475,7 +1492,7 @@ _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
|
|||||||
return false;
|
return false;
|
||||||
if (!equal(a->func, b->func))
|
if (!equal(a->func, b->func))
|
||||||
return false;
|
return false;
|
||||||
if (a->implicit != b->implicit)
|
if (a->context != b->context)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.34 2002/09/04 20:31:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.35 2002/09/18 21:35:21 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -215,13 +215,14 @@ makeAlias(const char *aliasname, List *colnames)
|
|||||||
* creates a RelabelType node
|
* creates a RelabelType node
|
||||||
*/
|
*/
|
||||||
RelabelType *
|
RelabelType *
|
||||||
makeRelabelType(Node *arg, Oid rtype, int32 rtypmod)
|
makeRelabelType(Node *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
|
||||||
{
|
{
|
||||||
RelabelType *r = makeNode(RelabelType);
|
RelabelType *r = makeNode(RelabelType);
|
||||||
|
|
||||||
r->arg = arg;
|
r->arg = arg;
|
||||||
r->resulttype = rtype;
|
r->resulttype = rtype;
|
||||||
r->resulttypmod = rtypmod;
|
r->resulttypmod = rtypmod;
|
||||||
|
r->relabelformat = rformat;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.173 2002/09/04 20:31:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.174 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||||
@ -860,10 +860,11 @@ static void
|
|||||||
_outFunc(StringInfo str, Func *node)
|
_outFunc(StringInfo str, Func *node)
|
||||||
{
|
{
|
||||||
appendStringInfo(str,
|
appendStringInfo(str,
|
||||||
" FUNC :funcid %u :funcresulttype %u :funcretset %s ",
|
" FUNC :funcid %u :funcresulttype %u :funcretset %s :funcformat %d ",
|
||||||
node->funcid,
|
node->funcid,
|
||||||
node->funcresulttype,
|
node->funcresulttype,
|
||||||
booltostr(node->funcretset));
|
booltostr(node->funcretset),
|
||||||
|
(int) node->funcformat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -914,9 +915,11 @@ _outRelabelType(StringInfo str, RelabelType *node)
|
|||||||
{
|
{
|
||||||
appendStringInfo(str, " RELABELTYPE :arg ");
|
appendStringInfo(str, " RELABELTYPE :arg ");
|
||||||
_outNode(str, node->arg);
|
_outNode(str, node->arg);
|
||||||
|
appendStringInfo(str,
|
||||||
appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
|
" :resulttype %u :resulttypmod %d :relabelformat %d ",
|
||||||
node->resulttype, node->resulttypmod);
|
node->resulttype,
|
||||||
|
node->resulttypmod,
|
||||||
|
(int) node->relabelformat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.132 2002/09/04 20:31:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.133 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Most of the read functions for plan nodes are tested. (In fact, they
|
* Most of the read functions for plan nodes are tested. (In fact, they
|
||||||
@ -1129,6 +1129,10 @@ _readFunc(void)
|
|||||||
token = pg_strtok(&length); /* now read it */
|
token = pg_strtok(&length); /* now read it */
|
||||||
local_node->funcretset = strtobool(token);
|
local_node->funcretset = strtobool(token);
|
||||||
|
|
||||||
|
token = pg_strtok(&length); /* get :funcformat */
|
||||||
|
token = pg_strtok(&length); /* now read it */
|
||||||
|
local_node->funcformat = (CoercionForm) atoi(token);
|
||||||
|
|
||||||
local_node->func_fcache = NULL;
|
local_node->func_fcache = NULL;
|
||||||
|
|
||||||
return local_node;
|
return local_node;
|
||||||
@ -1335,6 +1339,10 @@ _readRelabelType(void)
|
|||||||
token = pg_strtok(&length); /* get resulttypmod */
|
token = pg_strtok(&length); /* get resulttypmod */
|
||||||
local_node->resulttypmod = atoi(token);
|
local_node->resulttypmod = atoi(token);
|
||||||
|
|
||||||
|
token = pg_strtok(&length); /* eat :relabelformat */
|
||||||
|
token = pg_strtok(&length); /* get relabelformat */
|
||||||
|
local_node->relabelformat = (CoercionForm) atoi(token);
|
||||||
|
|
||||||
return local_node;
|
return local_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.122 2002/09/04 20:31:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.123 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -825,32 +825,15 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
|||||||
* is whether the operator has a commutator operator that matches
|
* is whether the operator has a commutator operator that matches
|
||||||
* the index's opclass.
|
* the index's opclass.
|
||||||
*
|
*
|
||||||
* We try both the straightforward match and matches that rely on
|
|
||||||
* recognizing binary-compatible datatypes. For example, if we have
|
|
||||||
* an expression like "oid = 123", the operator will be oideqint4,
|
|
||||||
* which we need to replace with oideq in order to recognize it as
|
|
||||||
* matching an oid_ops index on the oid field. A variant case is where
|
|
||||||
* the expression is like "oid::int4 = 123", where the given operator
|
|
||||||
* will be int4eq and again we need to intuit that we want to use oideq.
|
|
||||||
*
|
|
||||||
* Returns the OID of the matching operator, or InvalidOid if no match.
|
* Returns the OID of the matching operator, or InvalidOid if no match.
|
||||||
* Note that the returned OID will be different from the one in the given
|
* (Formerly, this routine might return a binary-compatible operator
|
||||||
* expression if we used a binary-compatible substitution. Also note that
|
* rather than the original one, but that kluge is history.)
|
||||||
* if indexkey_on_left is FALSE (meaning we need to commute), the returned
|
|
||||||
* OID is *not* commuted; it can be plugged directly into the given clause.
|
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
|
indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
|
||||||
{
|
{
|
||||||
Oid expr_op = ((Oper *) clause->oper)->opno;
|
Oid expr_op = ((Oper *) clause->oper)->opno;
|
||||||
Oid commuted_op,
|
Oid commuted_op;
|
||||||
new_op;
|
|
||||||
Operator oldoptup;
|
|
||||||
Form_pg_operator oldopform;
|
|
||||||
char *opname;
|
|
||||||
Oid ltype,
|
|
||||||
rtype,
|
|
||||||
indexkeytype;
|
|
||||||
|
|
||||||
/* Get the commuted operator if necessary */
|
/* Get the commuted operator if necessary */
|
||||||
if (indexkey_on_left)
|
if (indexkey_on_left)
|
||||||
@ -860,83 +843,10 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
|
|||||||
if (commuted_op == InvalidOid)
|
if (commuted_op == InvalidOid)
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
|
|
||||||
/* Done if the (commuted) operator is a member of the index's opclass */
|
/* OK if the (commuted) operator is a member of the index's opclass */
|
||||||
if (op_in_opclass(commuted_op, opclass))
|
if (op_in_opclass(commuted_op, opclass))
|
||||||
return expr_op;
|
return expr_op;
|
||||||
|
|
||||||
/*
|
|
||||||
* Maybe the index uses a binary-compatible operator set.
|
|
||||||
*
|
|
||||||
* Get the nominal input types of the given operator and the actual type
|
|
||||||
* (before binary-compatible relabeling) of the index key.
|
|
||||||
*/
|
|
||||||
oldoptup = SearchSysCache(OPEROID,
|
|
||||||
ObjectIdGetDatum(expr_op),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!HeapTupleIsValid(oldoptup))
|
|
||||||
return InvalidOid; /* probably can't happen */
|
|
||||||
oldopform = (Form_pg_operator) GETSTRUCT(oldoptup);
|
|
||||||
opname = pstrdup(NameStr(oldopform->oprname));
|
|
||||||
ltype = oldopform->oprleft;
|
|
||||||
rtype = oldopform->oprright;
|
|
||||||
ReleaseSysCache(oldoptup);
|
|
||||||
|
|
||||||
if (indexkey_on_left)
|
|
||||||
{
|
|
||||||
Node *leftop = (Node *) get_leftop(clause);
|
|
||||||
|
|
||||||
if (leftop && IsA(leftop, RelabelType))
|
|
||||||
leftop = ((RelabelType *) leftop)->arg;
|
|
||||||
indexkeytype = exprType(leftop);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Node *rightop = (Node *) get_rightop(clause);
|
|
||||||
|
|
||||||
if (rightop && IsA(rightop, RelabelType))
|
|
||||||
rightop = ((RelabelType *) rightop)->arg;
|
|
||||||
indexkeytype = exprType(rightop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure we have different but binary-compatible types.
|
|
||||||
*/
|
|
||||||
if (ltype == indexkeytype && rtype == indexkeytype)
|
|
||||||
return InvalidOid; /* no chance for a different operator */
|
|
||||||
if (!IsBinaryCompatible(ltype, indexkeytype))
|
|
||||||
return InvalidOid;
|
|
||||||
if (!IsBinaryCompatible(rtype, indexkeytype))
|
|
||||||
return InvalidOid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OK, look for operator of the same name with the indexkey's data
|
|
||||||
* type. (In theory this might find a non-semantically-comparable
|
|
||||||
* operator, but in practice that seems pretty unlikely for
|
|
||||||
* binary-compatible types.)
|
|
||||||
*/
|
|
||||||
new_op = compatible_oper_opid(makeList1(makeString(opname)),
|
|
||||||
indexkeytype, indexkeytype, true);
|
|
||||||
|
|
||||||
if (OidIsValid(new_op))
|
|
||||||
{
|
|
||||||
if (new_op != expr_op)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* OK, we found a binary-compatible operator of the same name;
|
|
||||||
* now does it match the index?
|
|
||||||
*/
|
|
||||||
if (indexkey_on_left)
|
|
||||||
commuted_op = new_op;
|
|
||||||
else
|
|
||||||
commuted_op = get_commutator(new_op);
|
|
||||||
if (commuted_op == InvalidOid)
|
|
||||||
return InvalidOid;
|
|
||||||
|
|
||||||
if (op_in_opclass(commuted_op, opclass))
|
|
||||||
return new_op;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.40 2002/09/04 20:31:20 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.41 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -520,6 +520,7 @@ build_index_pathkeys(Query *root,
|
|||||||
funcnode->funcid = index->indproc;
|
funcnode->funcid = index->indproc;
|
||||||
funcnode->funcresulttype = get_func_rettype(index->indproc);
|
funcnode->funcresulttype = get_func_rettype(index->indproc);
|
||||||
funcnode->funcretset = false; /* can never be a set */
|
funcnode->funcretset = false; /* can never be a set */
|
||||||
|
funcnode->funcformat = COERCE_DONTCARE; /* to match any user expr */
|
||||||
funcnode->func_fcache = NULL;
|
funcnode->func_fcache = NULL;
|
||||||
|
|
||||||
while (*indexkeys != 0)
|
while (*indexkeys != 0)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.118 2002/09/04 20:31:21 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.119 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1027,8 +1027,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
|
|||||||
Expr *clause = (Expr *) lfirst(i);
|
Expr *clause = (Expr *) lfirst(i);
|
||||||
Expr *newclause;
|
Expr *newclause;
|
||||||
List *leftvarnos;
|
List *leftvarnos;
|
||||||
Oid opclass,
|
Oid opclass;
|
||||||
newopno;
|
|
||||||
|
|
||||||
if (!is_opclause((Node *) clause) || length(clause->args) != 2)
|
if (!is_opclause((Node *) clause) || length(clause->args) != 2)
|
||||||
elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
|
elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
|
||||||
@ -1061,23 +1060,13 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
|
|||||||
index,
|
index,
|
||||||
&opclass);
|
&opclass);
|
||||||
|
|
||||||
/*
|
|
||||||
* Substitute the appropriate operator if the expression operator
|
|
||||||
* is merely binary-compatible with the index. This shouldn't
|
|
||||||
* fail, since indxpath.c found it before...
|
|
||||||
*/
|
|
||||||
newopno = indexable_operator(newclause, opclass, true);
|
|
||||||
if (newopno == InvalidOid)
|
|
||||||
elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
|
|
||||||
((Oper *) newclause->oper)->opno = newopno;
|
|
||||||
|
|
||||||
fixed_qual = lappend(fixed_qual, newclause);
|
fixed_qual = lappend(fixed_qual, newclause);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, check to see if index is lossy for this operator. If
|
* Finally, check to see if index is lossy for this operator. If
|
||||||
* so, add (a copy of) original form of clause to recheck list.
|
* so, add (a copy of) original form of clause to recheck list.
|
||||||
*/
|
*/
|
||||||
if (op_requires_recheck(newopno, opclass))
|
if (op_requires_recheck(((Oper *) newclause->oper)->opno, opclass))
|
||||||
recheck_qual = lappend(recheck_qual,
|
recheck_qual = lappend(recheck_qual,
|
||||||
copyObject((Node *) clause));
|
copyObject((Node *) clause));
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.56 2002/09/04 20:31:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -187,8 +187,9 @@ expand_targetlist(List *tlist, int command_type,
|
|||||||
false, /* not a set */
|
false, /* not a set */
|
||||||
false);
|
false);
|
||||||
if (!att_tup->attisdropped)
|
if (!att_tup->attisdropped)
|
||||||
new_expr = coerce_type_constraints(NULL, new_expr,
|
new_expr = coerce_type_constraints(new_expr,
|
||||||
atttype, false);
|
atttype,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
break;
|
break;
|
||||||
case CMD_UPDATE:
|
case CMD_UPDATE:
|
||||||
/* Insert NULLs for dropped columns */
|
/* Insert NULLs for dropped columns */
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.79 2002/09/11 14:48:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.80 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -420,8 +420,7 @@ generate_setop_tlist(List *colTypes, int flag,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
expr = coerce_to_common_type(NULL,
|
expr = coerce_to_common_type(expr,
|
||||||
expr,
|
|
||||||
colType,
|
colType,
|
||||||
"UNION/INTERSECT/EXCEPT");
|
"UNION/INTERSECT/EXCEPT");
|
||||||
colTypmod = -1;
|
colTypmod = -1;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.248 2002/09/04 20:31:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.249 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2565,24 +2565,20 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
|
|||||||
given_type_id = exprType(expr);
|
given_type_id = exprType(expr);
|
||||||
expected_type_id = (Oid) lfirsti(paramtypes);
|
expected_type_id = (Oid) lfirsti(paramtypes);
|
||||||
|
|
||||||
if (given_type_id != expected_type_id)
|
expr = coerce_to_target_type(expr, given_type_id,
|
||||||
{
|
expected_type_id, -1,
|
||||||
expr = CoerceTargetExpr(pstate,
|
COERCION_ASSIGNMENT,
|
||||||
expr,
|
COERCE_IMPLICIT_CAST);
|
||||||
given_type_id,
|
|
||||||
expected_type_id,
|
|
||||||
-1,
|
|
||||||
false);
|
|
||||||
|
|
||||||
if (!expr)
|
if (expr == NULL)
|
||||||
elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s"
|
elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s"
|
||||||
"\n\tYou will need to rewrite or cast the expression",
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
i,
|
i,
|
||||||
format_type_be(given_type_id),
|
format_type_be(given_type_id),
|
||||||
format_type_be(expected_type_id));
|
format_type_be(expected_type_id));
|
||||||
}
|
|
||||||
|
|
||||||
fix_opids(expr);
|
fix_opids(expr);
|
||||||
|
|
||||||
lfirst(l) = expr;
|
lfirst(l) = expr;
|
||||||
|
|
||||||
paramtypes = lnext(paramtypes);
|
paramtypes = lnext(paramtypes);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.366 2002/09/05 22:52:48 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.367 2002/09/18 21:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -161,8 +161,8 @@ static void doNegateFloat(Value *v);
|
|||||||
%type <list> createdb_opt_list, copy_opt_list
|
%type <list> createdb_opt_list, copy_opt_list
|
||||||
%type <defelt> createdb_opt_item, copy_opt_item
|
%type <defelt> createdb_opt_item, copy_opt_item
|
||||||
|
|
||||||
%type <ival> opt_lock, lock_type
|
%type <ival> opt_lock, lock_type, cast_context
|
||||||
%type <boolean> opt_force, opt_or_replace, opt_assignment
|
%type <boolean> opt_force, opt_or_replace
|
||||||
|
|
||||||
%type <list> user_list
|
%type <list> user_list
|
||||||
|
|
||||||
@ -349,7 +349,7 @@ static void doNegateFloat(Value *v);
|
|||||||
|
|
||||||
HANDLER, HAVING, HOUR_P,
|
HANDLER, HAVING, HOUR_P,
|
||||||
|
|
||||||
ILIKE, IMMEDIATE, IMMUTABLE, IN_P, INCREMENT,
|
ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT_P, IN_P, INCREMENT,
|
||||||
INDEX, INHERITS, INITIALLY, INNER_P, INOUT, INPUT,
|
INDEX, INHERITS, INITIALLY, INNER_P, INOUT, INPUT,
|
||||||
INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
|
INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
|
||||||
INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
|
INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
|
||||||
@ -3230,29 +3230,30 @@ any_operator:
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
|
CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
|
||||||
WITH FUNCTION function_with_argtypes opt_assignment
|
WITH FUNCTION function_with_argtypes cast_context
|
||||||
{
|
{
|
||||||
CreateCastStmt *n = makeNode(CreateCastStmt);
|
CreateCastStmt *n = makeNode(CreateCastStmt);
|
||||||
n->sourcetype = $4;
|
n->sourcetype = $4;
|
||||||
n->targettype = $6;
|
n->targettype = $6;
|
||||||
n->func = (FuncWithArgs *) $10;
|
n->func = (FuncWithArgs *) $10;
|
||||||
n->implicit = $11;
|
n->context = (CoercionContext) $11;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| CREATE CAST '(' ConstTypename AS ConstTypename ')'
|
| CREATE CAST '(' ConstTypename AS ConstTypename ')'
|
||||||
WITHOUT FUNCTION opt_assignment
|
WITHOUT FUNCTION cast_context
|
||||||
{
|
{
|
||||||
CreateCastStmt *n = makeNode(CreateCastStmt);
|
CreateCastStmt *n = makeNode(CreateCastStmt);
|
||||||
n->sourcetype = $4;
|
n->sourcetype = $4;
|
||||||
n->targettype = $6;
|
n->targettype = $6;
|
||||||
n->func = NULL;
|
n->func = NULL;
|
||||||
n->implicit = $10;
|
n->context = (CoercionContext) $10;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_assignment: AS ASSIGNMENT { $$ = TRUE; }
|
cast_context: AS IMPLICIT_P { $$ = COERCION_IMPLICIT; }
|
||||||
| /*EMPTY*/ { $$ = FALSE; }
|
| AS ASSIGNMENT { $$ = COERCION_ASSIGNMENT; }
|
||||||
|
| /*EMPTY*/ { $$ = COERCION_EXPLICIT; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
@ -7061,6 +7062,7 @@ unreserved_keyword:
|
|||||||
| HOUR_P
|
| HOUR_P
|
||||||
| IMMEDIATE
|
| IMMEDIATE
|
||||||
| IMMUTABLE
|
| IMMUTABLE
|
||||||
|
| IMPLICIT_P
|
||||||
| INCREMENT
|
| INCREMENT
|
||||||
| INDEX
|
| INDEX
|
||||||
| INHERITS
|
| INHERITS
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.126 2002/08/27 04:55:09 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.127 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -147,6 +147,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"ilike", ILIKE},
|
{"ilike", ILIKE},
|
||||||
{"immediate", IMMEDIATE},
|
{"immediate", IMMEDIATE},
|
||||||
{"immutable", IMMUTABLE},
|
{"immutable", IMMUTABLE},
|
||||||
|
{"implicit", IMPLICIT_P},
|
||||||
{"in", IN_P},
|
{"in", IN_P},
|
||||||
{"increment", INCREMENT},
|
{"increment", INCREMENT},
|
||||||
{"index", INDEX},
|
{"index", INDEX},
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.97 2002/09/04 20:31:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -872,20 +872,24 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar)
|
|||||||
* typmod is not same as input.
|
* typmod is not same as input.
|
||||||
*/
|
*/
|
||||||
if (l_colvar->vartype != outcoltype)
|
if (l_colvar->vartype != outcoltype)
|
||||||
l_node = coerce_type(NULL, (Node *) l_colvar, l_colvar->vartype,
|
l_node = coerce_type((Node *) l_colvar, l_colvar->vartype,
|
||||||
outcoltype, outcoltypmod, false);
|
outcoltype,
|
||||||
|
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
|
||||||
else if (l_colvar->vartypmod != outcoltypmod)
|
else if (l_colvar->vartypmod != outcoltypmod)
|
||||||
l_node = (Node *) makeRelabelType((Node *) l_colvar,
|
l_node = (Node *) makeRelabelType((Node *) l_colvar,
|
||||||
outcoltype, outcoltypmod);
|
outcoltype, outcoltypmod,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
else
|
else
|
||||||
l_node = (Node *) l_colvar;
|
l_node = (Node *) l_colvar;
|
||||||
|
|
||||||
if (r_colvar->vartype != outcoltype)
|
if (r_colvar->vartype != outcoltype)
|
||||||
r_node = coerce_type(NULL, (Node *) r_colvar, r_colvar->vartype,
|
r_node = coerce_type((Node *) r_colvar, r_colvar->vartype,
|
||||||
outcoltype, outcoltypmod, false);
|
outcoltype,
|
||||||
|
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
|
||||||
else if (r_colvar->vartypmod != outcoltypmod)
|
else if (r_colvar->vartypmod != outcoltypmod)
|
||||||
r_node = (Node *) makeRelabelType((Node *) r_colvar,
|
r_node = (Node *) makeRelabelType((Node *) r_colvar,
|
||||||
outcoltype, outcoltypmod);
|
outcoltype, outcoltypmod,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
else
|
else
|
||||||
r_node = (Node *) r_colvar;
|
r_node = (Node *) r_colvar;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.83 2002/09/04 20:31:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.84 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -23,28 +23,104 @@
|
|||||||
#include "parser/parse_func.h"
|
#include "parser/parse_func.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
|
static Node *coerce_type_typmod(Node *node,
|
||||||
|
Oid targetTypeId, int32 targetTypMod,
|
||||||
|
CoercionForm cformat);
|
||||||
static Oid PreferredType(CATEGORY category, Oid type);
|
static Oid PreferredType(CATEGORY category, Oid type);
|
||||||
static bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
|
static bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
|
||||||
bool isExplicit,
|
CoercionContext ccontext,
|
||||||
Oid *funcid);
|
Oid *funcid);
|
||||||
static Oid find_typmod_coercion_function(Oid typeId);
|
static Node *build_func_call(Oid funcid, Oid rettype, List *args,
|
||||||
static Node *build_func_call(Oid funcid, Oid rettype, List *args);
|
CoercionForm fformat);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* coerce_to_target_type()
|
||||||
|
* Convert an expression to a target type and typmod.
|
||||||
|
*
|
||||||
|
* This is the general-purpose entry point for arbitrary type coercion
|
||||||
|
* operations. Direct use of the component operations can_coerce_type,
|
||||||
|
* coerce_type, and coerce_type_typmod should be restricted to special
|
||||||
|
* cases (eg, when the conversion is expected to succeed).
|
||||||
|
*
|
||||||
|
* Returns the possibly-transformed expression tree, or NULL if the type
|
||||||
|
* conversion is not possible. (We do this, rather than elog'ing directly,
|
||||||
|
* so that callers can generate custom error messages indicating context.)
|
||||||
|
*
|
||||||
|
* expr - input expression tree (already transformed by transformExpr)
|
||||||
|
* exprtype - result type of expr
|
||||||
|
* targettype - desired result type
|
||||||
|
* targettypmod - desired result typmod
|
||||||
|
* ccontext, cformat - context indicators to control coercions
|
||||||
|
*/
|
||||||
|
Node *
|
||||||
|
coerce_to_target_type(Node *expr, Oid exprtype,
|
||||||
|
Oid targettype, int32 targettypmod,
|
||||||
|
CoercionContext ccontext,
|
||||||
|
CoercionForm cformat)
|
||||||
|
{
|
||||||
|
if (can_coerce_type(1, &exprtype, &targettype, ccontext))
|
||||||
|
expr = coerce_type(expr, exprtype, targettype,
|
||||||
|
ccontext, cformat);
|
||||||
|
/*
|
||||||
|
* String hacks to get transparent conversions for char and varchar:
|
||||||
|
* if a coercion to text is available, use it for forced coercions to
|
||||||
|
* char(n) or varchar(n).
|
||||||
|
*
|
||||||
|
* This is pretty grotty, but seems easier to maintain than providing
|
||||||
|
* entries in pg_cast that parallel all the ones for text.
|
||||||
|
*/
|
||||||
|
else if (ccontext >= COERCION_ASSIGNMENT &&
|
||||||
|
(targettype == BPCHAROID || targettype == VARCHAROID))
|
||||||
|
{
|
||||||
|
Oid text_id = TEXTOID;
|
||||||
|
|
||||||
|
if (can_coerce_type(1, &exprtype, &text_id, ccontext))
|
||||||
|
{
|
||||||
|
expr = coerce_type(expr, exprtype, text_id,
|
||||||
|
ccontext, cformat);
|
||||||
|
/* Need a RelabelType if no typmod coercion is performed */
|
||||||
|
if (targettypmod < 0)
|
||||||
|
expr = (Node *) makeRelabelType(expr, targettype, -1,
|
||||||
|
cformat);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
expr = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
expr = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the target is a fixed-length type, it may need a length coercion
|
||||||
|
* as well as a type coercion.
|
||||||
|
*/
|
||||||
|
if (expr != NULL)
|
||||||
|
expr = coerce_type_typmod(expr, targettype, targettypmod, cformat);
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* coerce_type()
|
* coerce_type()
|
||||||
* Convert a function argument to a different type.
|
* Convert an expression to a different type.
|
||||||
*
|
*
|
||||||
* The caller should already have determined that the coercion is possible;
|
* The caller should already have determined that the coercion is possible;
|
||||||
* see can_coerce_type.
|
* see can_coerce_type.
|
||||||
|
*
|
||||||
|
* No coercion to a typmod (length) is performed here. The caller must
|
||||||
|
* call coerce_type_typmod as well, if a typmod constraint is wanted.
|
||||||
|
* (But if the target type is a domain, it may internally contain a
|
||||||
|
* typmod constraint, which will be applied inside coerce_type_constraints.)
|
||||||
*/
|
*/
|
||||||
Node *
|
Node *
|
||||||
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||||
Oid targetTypeId, int32 atttypmod, bool isExplicit)
|
CoercionContext ccontext, CoercionForm cformat)
|
||||||
{
|
{
|
||||||
Node *result;
|
Node *result;
|
||||||
Oid funcId;
|
Oid funcId;
|
||||||
@ -68,7 +144,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
* example, int4's typinput function will reject "1.2", whereas
|
* example, int4's typinput function will reject "1.2", whereas
|
||||||
* float-to-int type conversion will round to integer.
|
* float-to-int type conversion will round to integer.
|
||||||
*
|
*
|
||||||
* XXX if the typinput function is not cachable, we really ought to
|
* XXX if the typinput function is not immutable, we really ought to
|
||||||
* postpone evaluation of the function call until runtime. But
|
* postpone evaluation of the function call until runtime. But
|
||||||
* there is no way to represent a typinput function call as an
|
* there is no way to represent a typinput function call as an
|
||||||
* expression tree, because C-string values are not Datums. (XXX
|
* expression tree, because C-string values are not Datums. (XXX
|
||||||
@ -91,28 +167,31 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
con->constvalue));
|
con->constvalue));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If target is a domain, use the typmod it applies to the
|
* We pass typmod -1 to the input routine, primarily because
|
||||||
* base type. Note that we call stringTypeDatum using the
|
* existing input routines follow implicit-coercion semantics
|
||||||
* domain's pg_type row, though. This works because the
|
* for length checks, which is not always what we want here.
|
||||||
* domain row has the same typinput and typelem as the base
|
* Any length constraint will be applied later by our caller.
|
||||||
* type --- ugly...
|
*
|
||||||
|
* Note that we call stringTypeDatum using the domain's pg_type
|
||||||
|
* row, if it's a domain. This works because the domain row has
|
||||||
|
* the same typinput and typelem as the base type --- ugly...
|
||||||
*/
|
*/
|
||||||
if (targetTyptype == 'd')
|
newcon->constvalue = stringTypeDatum(targetType, val, -1);
|
||||||
atttypmod = getBaseTypeMod(targetTypeId, atttypmod);
|
|
||||||
|
|
||||||
newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
|
|
||||||
pfree(val);
|
pfree(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (Node *) newcon;
|
result = (Node *) newcon;
|
||||||
|
|
||||||
/*
|
/* If target is a domain, apply constraints. */
|
||||||
* If target is a domain, apply constraints (except for typmod,
|
|
||||||
* which we assume the input routine took care of).
|
|
||||||
*/
|
|
||||||
if (targetTyptype == 'd')
|
if (targetTyptype == 'd')
|
||||||
result = coerce_type_constraints(pstate, result, targetTypeId,
|
{
|
||||||
false);
|
result = coerce_type_constraints(result, targetTypeId,
|
||||||
|
cformat);
|
||||||
|
/* We might now need a RelabelType. */
|
||||||
|
if (exprType(result) != targetTypeId)
|
||||||
|
result = (Node *) makeRelabelType(result, targetTypeId, -1,
|
||||||
|
cformat);
|
||||||
|
}
|
||||||
|
|
||||||
ReleaseSysCache(targetType);
|
ReleaseSysCache(targetType);
|
||||||
}
|
}
|
||||||
@ -120,9 +199,10 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
targetTypeId == ANYARRAYOID)
|
targetTypeId == ANYARRAYOID)
|
||||||
{
|
{
|
||||||
/* assume can_coerce_type verified that implicit coercion is okay */
|
/* assume can_coerce_type verified that implicit coercion is okay */
|
||||||
|
/* NB: we do NOT want a RelabelType here */
|
||||||
result = node;
|
result = node;
|
||||||
}
|
}
|
||||||
else if (find_coercion_pathway(targetTypeId, inputTypeId, isExplicit,
|
else if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
|
||||||
&funcId))
|
&funcId))
|
||||||
{
|
{
|
||||||
if (OidIsValid(funcId))
|
if (OidIsValid(funcId))
|
||||||
@ -135,7 +215,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
*/
|
*/
|
||||||
Oid baseTypeId = getBaseType(targetTypeId);
|
Oid baseTypeId = getBaseType(targetTypeId);
|
||||||
|
|
||||||
result = build_func_call(funcId, baseTypeId, makeList1(node));
|
result = build_func_call(funcId, baseTypeId, makeList1(node),
|
||||||
|
cformat);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If domain, test against domain constraints and relabel with
|
* If domain, test against domain constraints and relabel with
|
||||||
@ -143,9 +224,10 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
*/
|
*/
|
||||||
if (targetTypeId != baseTypeId)
|
if (targetTypeId != baseTypeId)
|
||||||
{
|
{
|
||||||
result = coerce_type_constraints(pstate, result,
|
result = coerce_type_constraints(result, targetTypeId,
|
||||||
targetTypeId, true);
|
cformat);
|
||||||
result = (Node *) makeRelabelType(result, targetTypeId, -1);
|
result = (Node *) makeRelabelType(result, targetTypeId, -1,
|
||||||
|
cformat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -179,8 +261,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
* Also, domains may have value restrictions beyond the base type
|
* Also, domains may have value restrictions beyond the base type
|
||||||
* that must be accounted for.
|
* that must be accounted for.
|
||||||
*/
|
*/
|
||||||
result = coerce_type_constraints(pstate, node,
|
result = coerce_type_constraints(node, targetTypeId,
|
||||||
targetTypeId, true);
|
cformat);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX could we label result with exprTypmod(node) instead of
|
* XXX could we label result with exprTypmod(node) instead of
|
||||||
@ -189,7 +271,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
* typmod, which is likely but not certain (wrong if target is
|
* typmod, which is likely but not certain (wrong if target is
|
||||||
* a domain, in any case).
|
* a domain, in any case).
|
||||||
*/
|
*/
|
||||||
result = (Node *) makeRelabelType(result, targetTypeId, -1);
|
result = (Node *) makeRelabelType(result, targetTypeId, -1,
|
||||||
|
cformat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (typeInheritsFrom(inputTypeId, targetTypeId))
|
else if (typeInheritsFrom(inputTypeId, targetTypeId))
|
||||||
@ -199,7 +282,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
* except relabel the type. This is binary compatibility for
|
* except relabel the type. This is binary compatibility for
|
||||||
* complex types.
|
* complex types.
|
||||||
*/
|
*/
|
||||||
result = (Node *) makeRelabelType(node, targetTypeId, -1);
|
result = (Node *) makeRelabelType(node, targetTypeId, -1,
|
||||||
|
cformat);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -215,15 +299,14 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* can_coerce_type()
|
* can_coerce_type()
|
||||||
* Can input_typeids be coerced to func_typeids?
|
* Can input_typeids be coerced to target_typeids?
|
||||||
*
|
*
|
||||||
* We must be told whether this is an implicit or explicit coercion
|
* We must be told the context (CAST construct, assignment, implicit coercion)
|
||||||
* (explicit being a CAST construct, explicit function call, etc).
|
* as this determines the set of available casts.
|
||||||
* We will accept a wider set of coercion cases for an explicit coercion.
|
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
|
||||||
bool isExplicit)
|
CoercionContext ccontext)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -231,7 +314,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
|||||||
for (i = 0; i < nargs; i++)
|
for (i = 0; i < nargs; i++)
|
||||||
{
|
{
|
||||||
Oid inputTypeId = input_typeids[i];
|
Oid inputTypeId = input_typeids[i];
|
||||||
Oid targetTypeId = func_typeids[i];
|
Oid targetTypeId = target_typeids[i];
|
||||||
Oid funcId;
|
Oid funcId;
|
||||||
|
|
||||||
/* no problem if same type */
|
/* no problem if same type */
|
||||||
@ -278,7 +361,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise reject; this assumes there are no explicit
|
* Otherwise reject; this assumes there are no explicit
|
||||||
* coercions to ANYARRAY. If we don't reject then
|
* coercion paths to ANYARRAY. If we don't reject then
|
||||||
* parse_coerce would have to repeat the above test.
|
* parse_coerce would have to repeat the above test.
|
||||||
*/
|
*/
|
||||||
return false;
|
return false;
|
||||||
@ -288,7 +371,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
|||||||
* If pg_cast shows that we can coerce, accept. This test now
|
* If pg_cast shows that we can coerce, accept. This test now
|
||||||
* covers both binary-compatible and coercion-function cases.
|
* covers both binary-compatible and coercion-function cases.
|
||||||
*/
|
*/
|
||||||
if (find_coercion_pathway(targetTypeId, inputTypeId, isExplicit,
|
if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
|
||||||
&funcId))
|
&funcId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -312,10 +395,12 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
|||||||
* Create an expression tree to enforce the constraints (if any)
|
* Create an expression tree to enforce the constraints (if any)
|
||||||
* that should be applied by the type. Currently this is only
|
* that should be applied by the type. Currently this is only
|
||||||
* interesting for domain types.
|
* interesting for domain types.
|
||||||
|
*
|
||||||
|
* NOTE: result tree is not guaranteed to show the correct exprType() for
|
||||||
|
* the domain; it may show the base type. Caller must relabel if needed.
|
||||||
*/
|
*/
|
||||||
Node *
|
Node *
|
||||||
coerce_type_constraints(ParseState *pstate, Node *arg,
|
coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
|
||||||
Oid typeId, bool applyTypmod)
|
|
||||||
{
|
{
|
||||||
char *notNull = NULL;
|
char *notNull = NULL;
|
||||||
int32 typmod = -1;
|
int32 typmod = -1;
|
||||||
@ -356,8 +441,8 @@ coerce_type_constraints(ParseState *pstate, Node *arg,
|
|||||||
/*
|
/*
|
||||||
* If domain applies a typmod to its base type, do length coercion.
|
* If domain applies a typmod to its base type, do length coercion.
|
||||||
*/
|
*/
|
||||||
if (applyTypmod && typmod >= 0)
|
if (typmod >= 0)
|
||||||
arg = coerce_type_typmod(pstate, arg, typeId, typmod);
|
arg = coerce_type_typmod(arg, typeId, typmod, cformat);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only need to add one NOT NULL check regardless of how many domains
|
* Only need to add one NOT NULL check regardless of how many domains
|
||||||
@ -380,8 +465,9 @@ coerce_type_constraints(ParseState *pstate, Node *arg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* coerce_type_typmod()
|
/*
|
||||||
* Force a value to a particular typmod, if meaningful and possible.
|
* coerce_type_typmod()
|
||||||
|
* Force a value to a particular typmod, if meaningful and possible.
|
||||||
*
|
*
|
||||||
* This is applied to values that are going to be stored in a relation
|
* This is applied to values that are going to be stored in a relation
|
||||||
* (where we have an atttypmod for the column) as well as values being
|
* (where we have an atttypmod for the column) as well as values being
|
||||||
@ -394,33 +480,65 @@ coerce_type_constraints(ParseState *pstate, Node *arg,
|
|||||||
* coercion for a domain is considered to be part of the type coercion
|
* coercion for a domain is considered to be part of the type coercion
|
||||||
* needed to produce the domain value in the first place. So, no getBaseType.
|
* needed to produce the domain value in the first place. So, no getBaseType.
|
||||||
*/
|
*/
|
||||||
Node *
|
static Node *
|
||||||
coerce_type_typmod(ParseState *pstate, Node *node,
|
coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
|
||||||
Oid targetTypeId, int32 atttypmod)
|
CoercionForm cformat)
|
||||||
{
|
{
|
||||||
Oid funcId;
|
Oid funcId;
|
||||||
|
int nargs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A negative typmod is assumed to mean that no coercion is wanted.
|
* A negative typmod is assumed to mean that no coercion is wanted.
|
||||||
*/
|
*/
|
||||||
if (atttypmod < 0 || atttypmod == exprTypmod(node))
|
if (targetTypMod < 0 || targetTypMod == exprTypmod(node))
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
funcId = find_typmod_coercion_function(targetTypeId);
|
funcId = find_typmod_coercion_function(targetTypeId, &nargs);
|
||||||
|
|
||||||
if (OidIsValid(funcId))
|
if (OidIsValid(funcId))
|
||||||
{
|
{
|
||||||
|
List *args;
|
||||||
Const *cons;
|
Const *cons;
|
||||||
|
Node *fcall;
|
||||||
|
|
||||||
|
/* Pass given value, plus target typmod as an int4 constant */
|
||||||
cons = makeConst(INT4OID,
|
cons = makeConst(INT4OID,
|
||||||
sizeof(int32),
|
sizeof(int32),
|
||||||
Int32GetDatum(atttypmod),
|
Int32GetDatum(targetTypMod),
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
node = build_func_call(funcId, targetTypeId, makeList2(node, cons));
|
args = makeList2(node, cons);
|
||||||
|
|
||||||
|
if (nargs == 3)
|
||||||
|
{
|
||||||
|
/* Pass it a boolean isExplicit parameter, too */
|
||||||
|
cons = makeConst(BOOLOID,
|
||||||
|
sizeof(bool),
|
||||||
|
BoolGetDatum(cformat != COERCE_IMPLICIT_CAST),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false);
|
||||||
|
|
||||||
|
args = lappend(args, cons);
|
||||||
|
}
|
||||||
|
|
||||||
|
fcall = build_func_call(funcId, targetTypeId, args, cformat);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the input is a constant, apply the length coercion
|
||||||
|
* function now instead of delaying to runtime.
|
||||||
|
*
|
||||||
|
* See the comments for the similar case in coerce_type.
|
||||||
|
*/
|
||||||
|
if (node && IsA(node, Const) &&
|
||||||
|
!((Const *) node)->constisnull)
|
||||||
|
node = eval_const_expressions(fcall);
|
||||||
|
else
|
||||||
|
node = fcall;
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -437,19 +555,19 @@ Node *
|
|||||||
coerce_to_boolean(Node *node, const char *constructName)
|
coerce_to_boolean(Node *node, const char *constructName)
|
||||||
{
|
{
|
||||||
Oid inputTypeId = exprType(node);
|
Oid inputTypeId = exprType(node);
|
||||||
Oid targetTypeId;
|
|
||||||
|
|
||||||
if (inputTypeId != BOOLOID)
|
if (inputTypeId != BOOLOID)
|
||||||
{
|
{
|
||||||
targetTypeId = BOOLOID;
|
node = coerce_to_target_type(node, inputTypeId,
|
||||||
if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false))
|
BOOLOID, -1,
|
||||||
|
COERCION_ASSIGNMENT,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
|
if (node == NULL)
|
||||||
{
|
{
|
||||||
/* translator: first %s is name of a SQL construct, eg WHERE */
|
/* translator: first %s is name of a SQL construct, eg WHERE */
|
||||||
elog(ERROR, "Argument of %s must be type boolean, not type %s",
|
elog(ERROR, "Argument of %s must be type boolean, not type %s",
|
||||||
constructName, format_type_be(inputTypeId));
|
constructName, format_type_be(inputTypeId));
|
||||||
}
|
}
|
||||||
node = coerce_type(NULL, node, inputTypeId, targetTypeId, -1,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression_returns_set(node))
|
if (expression_returns_set(node))
|
||||||
@ -472,12 +590,6 @@ coerce_to_boolean(Node *node, const char *constructName)
|
|||||||
* in the list will be preferred if there is doubt.
|
* in the list will be preferred if there is doubt.
|
||||||
* 'context' is a phrase to use in the error message if we fail to select
|
* 'context' is a phrase to use in the error message if we fail to select
|
||||||
* a usable type.
|
* a usable type.
|
||||||
*
|
|
||||||
* XXX this code is WRONG, since (for example) given the input (int4,int8)
|
|
||||||
* it will select int4, whereas according to SQL92 clause 9.3 the correct
|
|
||||||
* answer is clearly int8. To fix this we need a notion of a promotion
|
|
||||||
* hierarchy within type categories --- something more complete than
|
|
||||||
* just a single preferred type.
|
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
select_common_type(List *typeids, const char *context)
|
select_common_type(List *typeids, const char *context)
|
||||||
@ -511,12 +623,13 @@ select_common_type(List *typeids, const char *context)
|
|||||||
elog(ERROR, "%s types '%s' and '%s' not matched",
|
elog(ERROR, "%s types '%s' and '%s' not matched",
|
||||||
context, format_type_be(ptype), format_type_be(ntype));
|
context, format_type_be(ptype), format_type_be(ntype));
|
||||||
}
|
}
|
||||||
else if (IsPreferredType(pcategory, ntype)
|
else if (!IsPreferredType(pcategory, ptype) &&
|
||||||
&& !IsPreferredType(pcategory, ptype)
|
can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
|
||||||
&& can_coerce_type(1, &ptype, &ntype, false))
|
!can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* new one is preferred and can convert? then take it...
|
* take new type if can coerce to it implicitly but not the
|
||||||
|
* other way; but if we have a preferred type, stay on it.
|
||||||
*/
|
*/
|
||||||
ptype = ntype;
|
ptype = ntype;
|
||||||
pcategory = TypeCategory(ptype);
|
pcategory = TypeCategory(ptype);
|
||||||
@ -547,26 +660,20 @@ select_common_type(List *typeids, const char *context)
|
|||||||
* This is used following select_common_type() to coerce the individual
|
* This is used following select_common_type() to coerce the individual
|
||||||
* expressions to the desired type. 'context' is a phrase to use in the
|
* expressions to the desired type. 'context' is a phrase to use in the
|
||||||
* error message if we fail to coerce.
|
* error message if we fail to coerce.
|
||||||
*
|
|
||||||
* NOTE: pstate may be NULL.
|
|
||||||
*/
|
*/
|
||||||
Node *
|
Node *
|
||||||
coerce_to_common_type(ParseState *pstate, Node *node,
|
coerce_to_common_type(Node *node, Oid targetTypeId, const char *context)
|
||||||
Oid targetTypeId,
|
|
||||||
const char *context)
|
|
||||||
{
|
{
|
||||||
Oid inputTypeId = exprType(node);
|
Oid inputTypeId = exprType(node);
|
||||||
|
|
||||||
if (inputTypeId == targetTypeId)
|
if (inputTypeId == targetTypeId)
|
||||||
return node; /* no work */
|
return node; /* no work */
|
||||||
if (can_coerce_type(1, &inputTypeId, &targetTypeId, false))
|
if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
|
||||||
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
|
node = coerce_type(node, inputTypeId, targetTypeId,
|
||||||
false);
|
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
elog(ERROR, "%s unable to convert to type %s",
|
elog(ERROR, "%s unable to convert to type %s",
|
||||||
context, format_type_be(targetTypeId));
|
context, format_type_be(targetTypeId));
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,8 +815,6 @@ PreferredType(CATEGORY category, Oid type)
|
|||||||
type == REGCLASSOID ||
|
type == REGCLASSOID ||
|
||||||
type == REGTYPEOID)
|
type == REGTYPEOID)
|
||||||
result = OIDOID;
|
result = OIDOID;
|
||||||
else if (type == NUMERICOID)
|
|
||||||
result = NUMERICOID;
|
|
||||||
else
|
else
|
||||||
result = FLOAT8OID;
|
result = FLOAT8OID;
|
||||||
break;
|
break;
|
||||||
@ -742,49 +847,52 @@ PreferredType(CATEGORY category, Oid type)
|
|||||||
} /* PreferredType() */
|
} /* PreferredType() */
|
||||||
|
|
||||||
|
|
||||||
/* IsBinaryCompatible()
|
/* IsBinaryCoercible()
|
||||||
* Check if two types are binary-compatible.
|
* Check if srctype is binary-coercible to targettype.
|
||||||
*
|
*
|
||||||
* This notion allows us to cheat and directly exchange values without
|
* This notion allows us to cheat and directly exchange values without
|
||||||
* going through the trouble of calling a conversion function.
|
* going through the trouble of calling a conversion function.
|
||||||
*
|
*
|
||||||
* As of 7.3, binary compatibility isn't hardwired into the code anymore.
|
* As of 7.3, binary coercibility isn't hardwired into the code anymore.
|
||||||
* We consider two types binary-compatible if there is an implicit,
|
* We consider two types binary-coercible if there is an implicitly
|
||||||
* no-function-needed pg_cast entry. NOTE that we assume that such
|
* invokable, no-function-needed pg_cast entry.
|
||||||
* entries are symmetric, ie, it doesn't matter which type we consider
|
*
|
||||||
* source and which target. (cf. checks in opr_sanity regression test)
|
* This function replaces IsBinaryCompatible(), which was an inherently
|
||||||
|
* symmetric test. Since the pg_cast entries aren't necessarily symmetric,
|
||||||
|
* the order of the operands is now significant.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
IsBinaryCompatible(Oid type1, Oid type2)
|
IsBinaryCoercible(Oid srctype, Oid targettype)
|
||||||
{
|
{
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Form_pg_cast castForm;
|
Form_pg_cast castForm;
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
/* Fast path if same type */
|
/* Fast path if same type */
|
||||||
if (type1 == type2)
|
if (srctype == targettype)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Perhaps the types are domains; if so, look at their base types */
|
/* Perhaps the types are domains; if so, look at their base types */
|
||||||
if (OidIsValid(type1))
|
if (OidIsValid(srctype))
|
||||||
type1 = getBaseType(type1);
|
srctype = getBaseType(srctype);
|
||||||
if (OidIsValid(type2))
|
if (OidIsValid(targettype))
|
||||||
type2 = getBaseType(type2);
|
targettype = getBaseType(targettype);
|
||||||
|
|
||||||
/* Somewhat-fast path if same base type */
|
/* Somewhat-fast path if same base type */
|
||||||
if (type1 == type2)
|
if (srctype == targettype)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Else look in pg_cast */
|
/* Else look in pg_cast */
|
||||||
tuple = SearchSysCache(CASTSOURCETARGET,
|
tuple = SearchSysCache(CASTSOURCETARGET,
|
||||||
ObjectIdGetDatum(type1),
|
ObjectIdGetDatum(srctype),
|
||||||
ObjectIdGetDatum(type2),
|
ObjectIdGetDatum(targettype),
|
||||||
0, 0);
|
0, 0);
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
return false; /* no cast */
|
return false; /* no cast */
|
||||||
castForm = (Form_pg_cast) GETSTRUCT(tuple);
|
castForm = (Form_pg_cast) GETSTRUCT(tuple);
|
||||||
|
|
||||||
result = (castForm->castfunc == InvalidOid) && castForm->castimplicit;
|
result = (castForm->castfunc == InvalidOid &&
|
||||||
|
castForm->castcontext == COERCION_CODE_IMPLICIT);
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
@ -796,12 +904,15 @@ IsBinaryCompatible(Oid type1, Oid type2)
|
|||||||
* find_coercion_pathway
|
* find_coercion_pathway
|
||||||
* Look for a coercion pathway between two types.
|
* Look for a coercion pathway between two types.
|
||||||
*
|
*
|
||||||
* If we find a matching entry in pg_cast, return TRUE, and set *funcid
|
* ccontext determines the set of available casts.
|
||||||
|
*
|
||||||
|
* If we find a suitable entry in pg_cast, return TRUE, and set *funcid
|
||||||
* to the castfunc value (which may be InvalidOid for a binary-compatible
|
* to the castfunc value (which may be InvalidOid for a binary-compatible
|
||||||
* coercion).
|
* coercion).
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
|
find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
|
||||||
|
CoercionContext ccontext,
|
||||||
Oid *funcid)
|
Oid *funcid)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
@ -828,8 +939,29 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
|
|||||||
if (HeapTupleIsValid(tuple))
|
if (HeapTupleIsValid(tuple))
|
||||||
{
|
{
|
||||||
Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
|
Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
|
||||||
|
CoercionContext castcontext;
|
||||||
|
|
||||||
if (isExplicit || castForm->castimplicit)
|
/* convert char value for castcontext to CoercionContext enum */
|
||||||
|
switch (castForm->castcontext)
|
||||||
|
{
|
||||||
|
case COERCION_CODE_IMPLICIT:
|
||||||
|
castcontext = COERCION_IMPLICIT;
|
||||||
|
break;
|
||||||
|
case COERCION_CODE_ASSIGNMENT:
|
||||||
|
castcontext = COERCION_ASSIGNMENT;
|
||||||
|
break;
|
||||||
|
case COERCION_CODE_EXPLICIT:
|
||||||
|
castcontext = COERCION_EXPLICIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "find_coercion_pathway: bogus castcontext %c",
|
||||||
|
castForm->castcontext);
|
||||||
|
castcontext = 0; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rely on ordering of enum for correct behavior here */
|
||||||
|
if (ccontext >= castcontext)
|
||||||
{
|
{
|
||||||
*funcid = castForm->castfunc;
|
*funcid = castForm->castfunc;
|
||||||
result = true;
|
result = true;
|
||||||
@ -850,30 +982,59 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
|
|||||||
* the type requires coercion to its own length and that the said
|
* the type requires coercion to its own length and that the said
|
||||||
* function should be invoked to do that.
|
* function should be invoked to do that.
|
||||||
*
|
*
|
||||||
|
* Alternatively, the length-coercing function may have the signature
|
||||||
|
* (targettype, int4, bool). On success, *nargs is set to report which
|
||||||
|
* signature we found.
|
||||||
|
*
|
||||||
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
|
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
|
||||||
*
|
*
|
||||||
|
* If the given type is a varlena array type, we do not look for a coercion
|
||||||
|
* function associated directly with the array type, but instead look for
|
||||||
|
* one associated with the element type. If one exists, we report
|
||||||
|
* array_length_coerce() as the coercion function to use.
|
||||||
|
*
|
||||||
* This mechanism may seem pretty grotty and in need of replacement by
|
* This mechanism may seem pretty grotty and in need of replacement by
|
||||||
* something in pg_cast, but since typmod is only interesting for datatypes
|
* something in pg_cast, but since typmod is only interesting for datatypes
|
||||||
* that have special handling in the grammar, there's not really much
|
* that have special handling in the grammar, there's not really much
|
||||||
* percentage in making it any easier to apply such coercions ...
|
* percentage in making it any easier to apply such coercions ...
|
||||||
*/
|
*/
|
||||||
static Oid
|
Oid
|
||||||
find_typmod_coercion_function(Oid typeId)
|
find_typmod_coercion_function(Oid typeId, int *nargs)
|
||||||
{
|
{
|
||||||
Oid funcid = InvalidOid;
|
Oid funcid = InvalidOid;
|
||||||
|
bool isArray = false;
|
||||||
Type targetType;
|
Type targetType;
|
||||||
|
Form_pg_type typeForm;
|
||||||
char *typname;
|
char *typname;
|
||||||
Oid typnamespace;
|
Oid typnamespace;
|
||||||
Oid oid_array[FUNC_MAX_ARGS];
|
Oid oid_array[FUNC_MAX_ARGS];
|
||||||
HeapTuple ftup;
|
HeapTuple ftup;
|
||||||
|
|
||||||
targetType = typeidType(typeId);
|
targetType = typeidType(typeId);
|
||||||
typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
|
typeForm = (Form_pg_type) GETSTRUCT(targetType);
|
||||||
typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace;
|
|
||||||
|
|
||||||
|
/* Check for a varlena array type (and not a domain) */
|
||||||
|
if (typeForm->typelem != InvalidOid &&
|
||||||
|
typeForm->typlen == -1 &&
|
||||||
|
typeForm->typtype != 'd')
|
||||||
|
{
|
||||||
|
/* Yes, switch our attention to the element type */
|
||||||
|
typeId = typeForm->typelem;
|
||||||
|
ReleaseSysCache(targetType);
|
||||||
|
targetType = typeidType(typeId);
|
||||||
|
typeForm = (Form_pg_type) GETSTRUCT(targetType);
|
||||||
|
isArray = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function name is same as type internal name, and in same namespace */
|
||||||
|
typname = NameStr(typeForm->typname);
|
||||||
|
typnamespace = typeForm->typnamespace;
|
||||||
|
|
||||||
|
/* First look for parameters (type, int4) */
|
||||||
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||||
oid_array[0] = typeId;
|
oid_array[0] = typeId;
|
||||||
oid_array[1] = INT4OID;
|
oid_array[1] = INT4OID;
|
||||||
|
*nargs = 2;
|
||||||
|
|
||||||
ftup = SearchSysCache(PROCNAMENSP,
|
ftup = SearchSysCache(PROCNAMENSP,
|
||||||
CStringGetDatum(typname),
|
CStringGetDatum(typname),
|
||||||
@ -894,8 +1055,45 @@ find_typmod_coercion_function(Oid typeId)
|
|||||||
ReleaseSysCache(ftup);
|
ReleaseSysCache(ftup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!OidIsValid(funcid))
|
||||||
|
{
|
||||||
|
/* Didn't find a function, so now try (type, int4, bool) */
|
||||||
|
oid_array[2] = BOOLOID;
|
||||||
|
*nargs = 3;
|
||||||
|
|
||||||
|
ftup = SearchSysCache(PROCNAMENSP,
|
||||||
|
CStringGetDatum(typname),
|
||||||
|
Int16GetDatum(3),
|
||||||
|
PointerGetDatum(oid_array),
|
||||||
|
ObjectIdGetDatum(typnamespace));
|
||||||
|
if (HeapTupleIsValid(ftup))
|
||||||
|
{
|
||||||
|
Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
|
||||||
|
|
||||||
|
/* Make sure the function's result type is as expected */
|
||||||
|
if (pform->prorettype == typeId && !pform->proretset &&
|
||||||
|
!pform->proisagg)
|
||||||
|
{
|
||||||
|
/* Okay to use it */
|
||||||
|
funcid = HeapTupleGetOid(ftup);
|
||||||
|
}
|
||||||
|
ReleaseSysCache(ftup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ReleaseSysCache(targetType);
|
ReleaseSysCache(targetType);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, if we did find a coercion function for an array element type,
|
||||||
|
* report array_length_coerce() as the function to use. We know it
|
||||||
|
* takes three arguments always.
|
||||||
|
*/
|
||||||
|
if (isArray && OidIsValid(funcid))
|
||||||
|
{
|
||||||
|
funcid = F_ARRAY_LENGTH_COERCE;
|
||||||
|
*nargs = 3;
|
||||||
|
}
|
||||||
|
|
||||||
return funcid;
|
return funcid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,7 +1103,7 @@ find_typmod_coercion_function(Oid typeId)
|
|||||||
* The argument expressions must have been transformed already.
|
* The argument expressions must have been transformed already.
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
build_func_call(Oid funcid, Oid rettype, List *args)
|
build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
|
||||||
{
|
{
|
||||||
Func *funcnode;
|
Func *funcnode;
|
||||||
Expr *expr;
|
Expr *expr;
|
||||||
@ -914,6 +1112,7 @@ build_func_call(Oid funcid, Oid rettype, List *args)
|
|||||||
funcnode->funcid = funcid;
|
funcnode->funcid = funcid;
|
||||||
funcnode->funcresulttype = rettype;
|
funcnode->funcresulttype = rettype;
|
||||||
funcnode->funcretset = false; /* only possible case here */
|
funcnode->funcretset = false; /* only possible case here */
|
||||||
|
funcnode->funcformat = fformat;
|
||||||
funcnode->func_fcache = NULL;
|
funcnode->func_fcache = NULL;
|
||||||
|
|
||||||
expr = makeNode(Expr);
|
expr = makeNode(Expr);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.128 2002/09/04 20:31:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.129 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -28,7 +28,6 @@
|
|||||||
#include "parser/parse_func.h"
|
#include "parser/parse_func.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "parser/parse_target.h"
|
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
@ -40,9 +39,7 @@ static int expr_depth_counter = 0;
|
|||||||
|
|
||||||
bool Transform_null_equals = false;
|
bool Transform_null_equals = false;
|
||||||
|
|
||||||
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
|
static Node *typecast_expression(Node *expr, TypeName *typename);
|
||||||
static Node *parser_typecast_expression(ParseState *pstate,
|
|
||||||
Node *expr, TypeName *typename);
|
|
||||||
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
|
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
|
||||||
static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
||||||
List *indirection);
|
List *indirection);
|
||||||
@ -145,10 +142,9 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
A_Const *con = (A_Const *) expr;
|
A_Const *con = (A_Const *) expr;
|
||||||
Value *val = &con->val;
|
Value *val = &con->val;
|
||||||
|
|
||||||
|
result = (Node *) make_const(val);
|
||||||
if (con->typename != NULL)
|
if (con->typename != NULL)
|
||||||
result = parser_typecast_constant(val, con->typename);
|
result = typecast_expression(result, con->typename);
|
||||||
else
|
|
||||||
result = (Node *) make_const(val);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_ExprFieldSelect:
|
case T_ExprFieldSelect:
|
||||||
@ -175,7 +171,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
TypeCast *tc = (TypeCast *) expr;
|
TypeCast *tc = (TypeCast *) expr;
|
||||||
Node *arg = transformExpr(pstate, tc->arg);
|
Node *arg = transformExpr(pstate, tc->arg);
|
||||||
|
|
||||||
result = parser_typecast_expression(pstate, arg, tc->typename);
|
result = typecast_expression(arg, tc->typename);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_A_Expr:
|
case T_A_Expr:
|
||||||
@ -562,8 +558,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
newc->casetype = ptype;
|
newc->casetype = ptype;
|
||||||
|
|
||||||
/* Convert default result clause, if necessary */
|
/* Convert default result clause, if necessary */
|
||||||
newc->defresult = coerce_to_common_type(pstate,
|
newc->defresult = coerce_to_common_type(newc->defresult,
|
||||||
newc->defresult,
|
|
||||||
ptype,
|
ptype,
|
||||||
"CASE/ELSE");
|
"CASE/ELSE");
|
||||||
|
|
||||||
@ -572,8 +567,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
{
|
{
|
||||||
CaseWhen *w = (CaseWhen *) lfirst(args);
|
CaseWhen *w = (CaseWhen *) lfirst(args);
|
||||||
|
|
||||||
w->result = coerce_to_common_type(pstate,
|
w->result = coerce_to_common_type(w->result,
|
||||||
w->result,
|
|
||||||
ptype,
|
ptype,
|
||||||
"CASE/WHEN");
|
"CASE/WHEN");
|
||||||
}
|
}
|
||||||
@ -671,8 +665,12 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
|
|||||||
if (indirection == NIL)
|
if (indirection == NIL)
|
||||||
return basenode;
|
return basenode;
|
||||||
return (Node *) transformArraySubscripts(pstate,
|
return (Node *) transformArraySubscripts(pstate,
|
||||||
basenode, exprType(basenode),
|
basenode,
|
||||||
indirection, false, NULL);
|
exprType(basenode),
|
||||||
|
exprTypmod(basenode),
|
||||||
|
indirection,
|
||||||
|
false,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Node *
|
static Node *
|
||||||
@ -1037,23 +1035,13 @@ exprTypmod(Node *expr)
|
|||||||
*
|
*
|
||||||
* If coercedTypmod is not NULL, the typmod is stored there if the expression
|
* If coercedTypmod is not NULL, the typmod is stored there if the expression
|
||||||
* is a length-coercion function, else -1 is stored there.
|
* is a length-coercion function, else -1 is stored there.
|
||||||
*
|
|
||||||
* We assume that a two-argument function named for a datatype, whose
|
|
||||||
* output and first argument types are that datatype, and whose second
|
|
||||||
* input is an int32 constant, represents a forced length coercion.
|
|
||||||
*
|
|
||||||
* XXX It'd be better if the parsetree retained some explicit indication
|
|
||||||
* of the coercion, so we didn't need these heuristics.
|
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
||||||
{
|
{
|
||||||
Func *func;
|
Func *func;
|
||||||
|
int nargs;
|
||||||
Const *second_arg;
|
Const *second_arg;
|
||||||
HeapTuple procTuple;
|
|
||||||
HeapTuple typeTuple;
|
|
||||||
Form_pg_proc procStruct;
|
|
||||||
Form_pg_type typeStruct;
|
|
||||||
|
|
||||||
if (coercedTypmod != NULL)
|
if (coercedTypmod != NULL)
|
||||||
*coercedTypmod = -1; /* default result on failure */
|
*coercedTypmod = -1; /* default result on failure */
|
||||||
@ -1067,142 +1055,44 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
|||||||
Assert(IsA(func, Func));
|
Assert(IsA(func, Func));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's not a two-argument function with the second argument being
|
* If it didn't come from a coercion context, reject.
|
||||||
* an int4 constant, it can't have been created from a length
|
|
||||||
* coercion.
|
|
||||||
*/
|
*/
|
||||||
if (length(((Expr *) expr)->args) != 2)
|
if (func->funcformat != COERCE_EXPLICIT_CAST &&
|
||||||
|
func->funcformat != COERCE_IMPLICIT_CAST)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's not a two-argument or three-argument function with the second
|
||||||
|
* argument being an int4 constant, it can't have been created from a
|
||||||
|
* length coercion (it must be a type coercion, instead).
|
||||||
|
*/
|
||||||
|
nargs = length(((Expr *) expr)->args);
|
||||||
|
if (nargs < 2 || nargs > 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
second_arg = (Const *) lsecond(((Expr *) expr)->args);
|
second_arg = (Const *) lsecond(((Expr *) expr)->args);
|
||||||
if (!IsA(second_arg, Const) ||
|
if (!IsA(second_arg, Const) ||
|
||||||
second_arg->consttype != INT4OID ||
|
second_arg->consttype != INT4OID ||
|
||||||
second_arg->constisnull)
|
second_arg->constisnull)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
|
||||||
* Lookup the function in pg_proc
|
|
||||||
*/
|
|
||||||
procTuple = SearchSysCache(PROCOID,
|
|
||||||
ObjectIdGetDatum(func->funcid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!HeapTupleIsValid(procTuple))
|
|
||||||
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
|
|
||||||
procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It must be a function with two arguments where the first is of the
|
|
||||||
* same type as the return value and the second is an int4. Also, just
|
|
||||||
* to be sure, check return type agrees with expr node.
|
|
||||||
*/
|
|
||||||
if (procStruct->pronargs != 2 ||
|
|
||||||
procStruct->prorettype != procStruct->proargtypes[0] ||
|
|
||||||
procStruct->proargtypes[1] != INT4OID ||
|
|
||||||
procStruct->prorettype != ((Expr *) expr)->typeOid)
|
|
||||||
{
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Furthermore, the name and namespace of the function must be the
|
|
||||||
* same as its result type's name/namespace (cf.
|
|
||||||
* find_coercion_function).
|
|
||||||
*/
|
|
||||||
typeTuple = SearchSysCache(TYPEOID,
|
|
||||||
ObjectIdGetDatum(procStruct->prorettype),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!HeapTupleIsValid(typeTuple))
|
|
||||||
elog(ERROR, "cache lookup for type %u failed",
|
|
||||||
procStruct->prorettype);
|
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
|
|
||||||
if (strcmp(NameStr(procStruct->proname),
|
|
||||||
NameStr(typeStruct->typname)) != 0 ||
|
|
||||||
procStruct->pronamespace != typeStruct->typnamespace)
|
|
||||||
{
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
ReleaseSysCache(typeTuple);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, it is indeed a length-coercion function.
|
* OK, it is indeed a length-coercion function.
|
||||||
*/
|
*/
|
||||||
if (coercedTypmod != NULL)
|
if (coercedTypmod != NULL)
|
||||||
*coercedTypmod = DatumGetInt32(second_arg->constvalue);
|
*coercedTypmod = DatumGetInt32(second_arg->constvalue);
|
||||||
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
ReleaseSysCache(typeTuple);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Produce an appropriate Const node from a constant value produced
|
* Handle an explicit CAST construct.
|
||||||
* by the parser and an explicit type name to cast to.
|
|
||||||
*/
|
|
||||||
static Node *
|
|
||||||
parser_typecast_constant(Value *expr, TypeName *typename)
|
|
||||||
{
|
|
||||||
Type tp;
|
|
||||||
Datum datum;
|
|
||||||
Const *con;
|
|
||||||
char *const_string = NULL;
|
|
||||||
bool string_palloced = false;
|
|
||||||
bool isNull = false;
|
|
||||||
|
|
||||||
tp = typenameType(typename);
|
|
||||||
|
|
||||||
switch (nodeTag(expr))
|
|
||||||
{
|
|
||||||
case T_Integer:
|
|
||||||
const_string = DatumGetCString(DirectFunctionCall1(int4out,
|
|
||||||
Int32GetDatum(expr->val.ival)));
|
|
||||||
string_palloced = true;
|
|
||||||
break;
|
|
||||||
case T_Float:
|
|
||||||
case T_String:
|
|
||||||
case T_BitString:
|
|
||||||
const_string = expr->val.str;
|
|
||||||
break;
|
|
||||||
case T_Null:
|
|
||||||
isNull = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
elog(ERROR, "Cannot cast this expression to type '%s'",
|
|
||||||
typeTypeName(tp));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNull)
|
|
||||||
datum = (Datum) NULL;
|
|
||||||
else
|
|
||||||
datum = stringTypeDatum(tp, const_string, typename->typmod);
|
|
||||||
|
|
||||||
con = makeConst(typeTypeId(tp),
|
|
||||||
typeLen(tp),
|
|
||||||
datum,
|
|
||||||
isNull,
|
|
||||||
typeByVal(tp),
|
|
||||||
false, /* not a set */
|
|
||||||
true /* is cast */ );
|
|
||||||
|
|
||||||
if (string_palloced)
|
|
||||||
pfree(const_string);
|
|
||||||
|
|
||||||
ReleaseSysCache(tp);
|
|
||||||
|
|
||||||
return (Node *) con;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle an explicit CAST applied to a non-constant expression.
|
|
||||||
* (Actually, this works for constants too, but gram.y won't generate
|
|
||||||
* a TypeCast node if the argument is just a constant.)
|
|
||||||
*
|
*
|
||||||
* The given expr has already been transformed, but we need to lookup
|
* The given expr has already been transformed, but we need to lookup
|
||||||
* the type name and then apply any necessary coercion function(s).
|
* the type name and then apply any necessary coercion function(s).
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
parser_typecast_expression(ParseState *pstate,
|
typecast_expression(Node *expr, TypeName *typename)
|
||||||
Node *expr, TypeName *typename)
|
|
||||||
{
|
{
|
||||||
Oid inputType = exprType(expr);
|
Oid inputType = exprType(expr);
|
||||||
Oid targetType;
|
Oid targetType;
|
||||||
@ -1212,23 +1102,14 @@ parser_typecast_expression(ParseState *pstate,
|
|||||||
if (inputType == InvalidOid)
|
if (inputType == InvalidOid)
|
||||||
return expr; /* do nothing if NULL input */
|
return expr; /* do nothing if NULL input */
|
||||||
|
|
||||||
if (inputType != targetType)
|
expr = coerce_to_target_type(expr, inputType,
|
||||||
{
|
targetType, typename->typmod,
|
||||||
expr = CoerceTargetExpr(pstate, expr, inputType,
|
COERCION_EXPLICIT,
|
||||||
targetType, typename->typmod,
|
COERCE_EXPLICIT_CAST);
|
||||||
true); /* explicit coercion */
|
if (expr == NULL)
|
||||||
if (expr == NULL)
|
elog(ERROR, "Cannot cast type %s to %s",
|
||||||
elog(ERROR, "Cannot cast type '%s' to '%s'",
|
format_type_be(inputType),
|
||||||
format_type_be(inputType),
|
format_type_be(targetType));
|
||||||
format_type_be(targetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the target is a fixed-length type, it may need a length coercion
|
|
||||||
* as well as a type coercion.
|
|
||||||
*/
|
|
||||||
expr = coerce_type_typmod(pstate, expr,
|
|
||||||
targetType, typename->typmod);
|
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.136 2002/09/04 20:31:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.137 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -32,15 +32,12 @@
|
|||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
static Node *ParseComplexProjection(ParseState *pstate,
|
static Node *ParseComplexProjection(char *funcname, Node *first_arg);
|
||||||
char *funcname,
|
|
||||||
Node *first_arg);
|
|
||||||
static Oid **argtype_inherit(int nargs, Oid *argtypes);
|
static Oid **argtype_inherit(int nargs, Oid *argtypes);
|
||||||
|
|
||||||
static int find_inheritors(Oid relid, Oid **supervec);
|
static int find_inheritors(Oid relid, Oid **supervec);
|
||||||
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
|
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
|
||||||
static void make_arguments(ParseState *pstate,
|
static void make_arguments(int nargs,
|
||||||
int nargs,
|
|
||||||
List *fargs,
|
List *fargs,
|
||||||
Oid *input_typeids,
|
Oid *input_typeids,
|
||||||
Oid *function_typeids);
|
Oid *function_typeids);
|
||||||
@ -137,7 +134,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||||||
* ParseComplexProjection can't handle the projection, we have
|
* ParseComplexProjection can't handle the projection, we have
|
||||||
* to keep going.
|
* to keep going.
|
||||||
*/
|
*/
|
||||||
retval = ParseComplexProjection(pstate, cname, first_arg);
|
retval = ParseComplexProjection(cname, first_arg);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -243,8 +240,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||||||
* We can do it as a trivial coercion. coerce_type can handle
|
* We can do it as a trivial coercion. coerce_type can handle
|
||||||
* these cases, so why duplicate code...
|
* these cases, so why duplicate code...
|
||||||
*/
|
*/
|
||||||
return coerce_type(pstate, lfirst(fargs),
|
return coerce_type(lfirst(fargs), oid_array[0], rettype,
|
||||||
oid_array[0], rettype, -1, true);
|
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
|
||||||
}
|
}
|
||||||
else if (fdresult == FUNCDETAIL_NORMAL)
|
else if (fdresult == FUNCDETAIL_NORMAL)
|
||||||
{
|
{
|
||||||
@ -296,7 +293,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* perform the necessary typecasting of arguments */
|
/* perform the necessary typecasting of arguments */
|
||||||
make_arguments(pstate, nargs, fargs, oid_array, true_oid_array);
|
make_arguments(nargs, fargs, oid_array, true_oid_array);
|
||||||
|
|
||||||
/* build the appropriate output structure */
|
/* build the appropriate output structure */
|
||||||
if (fdresult == FUNCDETAIL_NORMAL)
|
if (fdresult == FUNCDETAIL_NORMAL)
|
||||||
@ -307,6 +304,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||||||
funcnode->funcid = funcid;
|
funcnode->funcid = funcid;
|
||||||
funcnode->funcresulttype = rettype;
|
funcnode->funcresulttype = rettype;
|
||||||
funcnode->funcretset = retset;
|
funcnode->funcretset = retset;
|
||||||
|
funcnode->funcformat = COERCE_EXPLICIT_CALL;
|
||||||
funcnode->func_fcache = NULL;
|
funcnode->func_fcache = NULL;
|
||||||
|
|
||||||
expr->typeOid = rettype;
|
expr->typeOid = rettype;
|
||||||
@ -367,7 +365,7 @@ match_argtypes(int nargs,
|
|||||||
{
|
{
|
||||||
next_candidate = current_candidate->next;
|
next_candidate = current_candidate->next;
|
||||||
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
|
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
|
||||||
false))
|
COERCION_IMPLICIT))
|
||||||
{
|
{
|
||||||
current_candidate->next = *candidates;
|
current_candidate->next = *candidates;
|
||||||
*candidates = current_candidate;
|
*candidates = current_candidate;
|
||||||
@ -470,7 +468,7 @@ func_select_candidate(int nargs,
|
|||||||
{
|
{
|
||||||
if (input_typeids[i] != UNKNOWNOID)
|
if (input_typeids[i] != UNKNOWNOID)
|
||||||
{
|
{
|
||||||
if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
|
if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
|
||||||
nmatch++;
|
nmatch++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -776,7 +774,7 @@ func_get_detail(List *funcname,
|
|||||||
Node *arg1 = lfirst(fargs);
|
Node *arg1 = lfirst(fargs);
|
||||||
|
|
||||||
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
|
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
|
||||||
IsBinaryCompatible(sourceType, targetType))
|
IsBinaryCoercible(sourceType, targetType))
|
||||||
{
|
{
|
||||||
/* Yup, it's a type coercion */
|
/* Yup, it's a type coercion */
|
||||||
*funcid = InvalidOid;
|
*funcid = InvalidOid;
|
||||||
@ -1120,8 +1118,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
|||||||
* actual arguments and argument types, do the necessary typecasting.
|
* actual arguments and argument types, do the necessary typecasting.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
make_arguments(ParseState *pstate,
|
make_arguments(int nargs,
|
||||||
int nargs,
|
|
||||||
List *fargs,
|
List *fargs,
|
||||||
Oid *input_typeids,
|
Oid *input_typeids,
|
||||||
Oid *function_typeids)
|
Oid *function_typeids)
|
||||||
@ -1136,11 +1133,11 @@ make_arguments(ParseState *pstate,
|
|||||||
/* types don't match? then force coercion using a function call... */
|
/* types don't match? then force coercion using a function call... */
|
||||||
if (input_typeids[i] != function_typeids[i])
|
if (input_typeids[i] != function_typeids[i])
|
||||||
{
|
{
|
||||||
lfirst(current_fargs) = coerce_type(pstate,
|
lfirst(current_fargs) = coerce_type(lfirst(current_fargs),
|
||||||
lfirst(current_fargs),
|
|
||||||
input_typeids[i],
|
input_typeids[i],
|
||||||
function_typeids[i], -1,
|
function_typeids[i],
|
||||||
false);
|
COERCION_IMPLICIT,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1179,9 +1176,7 @@ setup_field_select(Node *input, char *attname, Oid relid)
|
|||||||
* NB: argument is expected to be transformed already, ie, not a RangeVar.
|
* NB: argument is expected to be transformed already, ie, not a RangeVar.
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
ParseComplexProjection(ParseState *pstate,
|
ParseComplexProjection(char *funcname, Node *first_arg)
|
||||||
char *funcname,
|
|
||||||
Node *first_arg)
|
|
||||||
{
|
{
|
||||||
Oid argtype = exprType(first_arg);
|
Oid argtype = exprType(first_arg);
|
||||||
Oid argrelid;
|
Oid argrelid;
|
||||||
|
@ -1,27 +1,22 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* parse_node.c
|
* parse_node.c
|
||||||
* various routines that make nodes for query plans
|
* various routines that make nodes for querytrees
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.68 2002/09/04 20:31:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.69 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <float.h>
|
|
||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "fmgr.h"
|
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
@ -29,14 +24,11 @@
|
|||||||
#include "parser/parse_node.h"
|
#include "parser/parse_node.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "parser/parse_target.h"
|
|
||||||
#include "parser/parse_type.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/varbit.h"
|
#include "utils/int8.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
#include "utils/varbit.h"
|
||||||
static bool fitsInFloat(Value *value);
|
|
||||||
|
|
||||||
|
|
||||||
/* make_parsestate()
|
/* make_parsestate()
|
||||||
@ -70,8 +62,8 @@ make_operand(Node *tree, Oid orig_typeId, Oid target_typeId)
|
|||||||
{
|
{
|
||||||
/* must coerce? */
|
/* must coerce? */
|
||||||
if (target_typeId != orig_typeId)
|
if (target_typeId != orig_typeId)
|
||||||
result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1,
|
result = coerce_type(tree, orig_typeId, target_typeId,
|
||||||
false);
|
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
|
||||||
else
|
else
|
||||||
result = tree;
|
result = tree;
|
||||||
}
|
}
|
||||||
@ -191,6 +183,7 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
|
|||||||
* arrayBase Already-transformed expression for the array as a whole
|
* arrayBase Already-transformed expression for the array as a whole
|
||||||
* (may be NULL if we are handling an INSERT)
|
* (may be NULL if we are handling an INSERT)
|
||||||
* arrayType OID of array's datatype
|
* arrayType OID of array's datatype
|
||||||
|
* arrayTypMod typmod to be applied to array elements
|
||||||
* indirection Untransformed list of subscripts (must not be NIL)
|
* indirection Untransformed list of subscripts (must not be NIL)
|
||||||
* forceSlice If true, treat subscript as array slice in all cases
|
* forceSlice If true, treat subscript as array slice in all cases
|
||||||
* assignFrom NULL for array fetch, else transformed expression for source.
|
* assignFrom NULL for array fetch, else transformed expression for source.
|
||||||
@ -199,6 +192,7 @@ ArrayRef *
|
|||||||
transformArraySubscripts(ParseState *pstate,
|
transformArraySubscripts(ParseState *pstate,
|
||||||
Node *arrayBase,
|
Node *arrayBase,
|
||||||
Oid arrayType,
|
Oid arrayType,
|
||||||
|
int32 arrayTypMod,
|
||||||
List *indirection,
|
List *indirection,
|
||||||
bool forceSlice,
|
bool forceSlice,
|
||||||
Node *assignFrom)
|
Node *assignFrom)
|
||||||
@ -286,8 +280,10 @@ transformArraySubscripts(ParseState *pstate,
|
|||||||
{
|
{
|
||||||
subexpr = transformExpr(pstate, ai->lidx);
|
subexpr = transformExpr(pstate, ai->lidx);
|
||||||
/* If it's not int4 already, try to coerce */
|
/* If it's not int4 already, try to coerce */
|
||||||
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
|
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
|
||||||
INT4OID, -1, false);
|
INT4OID, -1,
|
||||||
|
COERCION_ASSIGNMENT,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
if (subexpr == NULL)
|
if (subexpr == NULL)
|
||||||
elog(ERROR, "array index expressions must be integers");
|
elog(ERROR, "array index expressions must be integers");
|
||||||
}
|
}
|
||||||
@ -306,8 +302,10 @@ transformArraySubscripts(ParseState *pstate,
|
|||||||
}
|
}
|
||||||
subexpr = transformExpr(pstate, ai->uidx);
|
subexpr = transformExpr(pstate, ai->uidx);
|
||||||
/* If it's not int4 already, try to coerce */
|
/* If it's not int4 already, try to coerce */
|
||||||
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
|
subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
|
||||||
INT4OID, -1, false);
|
INT4OID, -1,
|
||||||
|
COERCION_ASSIGNMENT,
|
||||||
|
COERCE_IMPLICIT_CAST);
|
||||||
if (subexpr == NULL)
|
if (subexpr == NULL)
|
||||||
elog(ERROR, "array index expressions must be integers");
|
elog(ERROR, "array index expressions must be integers");
|
||||||
upperIndexpr = lappend(upperIndexpr, subexpr);
|
upperIndexpr = lappend(upperIndexpr, subexpr);
|
||||||
@ -323,19 +321,16 @@ transformArraySubscripts(ParseState *pstate,
|
|||||||
|
|
||||||
if (typesource != InvalidOid)
|
if (typesource != InvalidOid)
|
||||||
{
|
{
|
||||||
if (typesource != typeneeded)
|
assignFrom = coerce_to_target_type(assignFrom, typesource,
|
||||||
{
|
typeneeded, arrayTypMod,
|
||||||
/* XXX fixme: need to get the array's atttypmod? */
|
COERCION_ASSIGNMENT,
|
||||||
assignFrom = CoerceTargetExpr(pstate, assignFrom,
|
COERCE_IMPLICIT_CAST);
|
||||||
typesource, typeneeded,
|
if (assignFrom == NULL)
|
||||||
-1, false);
|
elog(ERROR, "Array assignment requires type %s"
|
||||||
if (assignFrom == NULL)
|
" but expression is of type %s"
|
||||||
elog(ERROR, "Array assignment requires type '%s'"
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
" but expression is of type '%s'"
|
format_type_be(typeneeded),
|
||||||
"\n\tYou will need to rewrite or cast the expression",
|
format_type_be(typesource));
|
||||||
format_type_be(typeneeded),
|
|
||||||
format_type_be(typesource));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +339,7 @@ transformArraySubscripts(ParseState *pstate,
|
|||||||
*/
|
*/
|
||||||
aref = makeNode(ArrayRef);
|
aref = makeNode(ArrayRef);
|
||||||
aref->refrestype = resultType; /* XXX should save element type
|
aref->refrestype = resultType; /* XXX should save element type
|
||||||
* too */
|
* OID too */
|
||||||
aref->refattrlength = type_struct_array->typlen;
|
aref->refattrlength = type_struct_array->typlen;
|
||||||
aref->refelemlength = type_struct_element->typlen;
|
aref->refelemlength = type_struct_element->typlen;
|
||||||
aref->refelembyval = type_struct_element->typbyval;
|
aref->refelembyval = type_struct_element->typbyval;
|
||||||
@ -373,21 +368,16 @@ transformArraySubscripts(ParseState *pstate,
|
|||||||
* resolution that we're not sure that it should be considered text.
|
* resolution that we're not sure that it should be considered text.
|
||||||
* Explicit "NULL" constants are also typed as UNKNOWN.
|
* Explicit "NULL" constants are also typed as UNKNOWN.
|
||||||
*
|
*
|
||||||
* For integers and floats we produce int4, float8, or numeric depending
|
* For integers and floats we produce int4, int8, or numeric depending
|
||||||
* on the value of the number. XXX In some cases it would be nice to take
|
* on the value of the number. XXX This should include int2 as well,
|
||||||
* context into account when determining the type to convert to, but in
|
* but additional cleanup is needed before we can do that; else cases
|
||||||
* other cases we can't delay the type choice. One possibility is to invent
|
* like "WHERE int4var = 42" will fail to be indexable.
|
||||||
* a dummy type "UNKNOWNNUMERIC" that's treated similarly to UNKNOWN;
|
|
||||||
* that would allow us to do the right thing in examples like a simple
|
|
||||||
* INSERT INTO table (numericcolumn) VALUES (1.234), since we wouldn't
|
|
||||||
* have to resolve the unknown type until we knew the destination column
|
|
||||||
* type. On the other hand UNKNOWN has considerable problems of its own.
|
|
||||||
* We would not like "SELECT 1.2 + 3.4" to claim it can't choose a type.
|
|
||||||
*/
|
*/
|
||||||
Const *
|
Const *
|
||||||
make_const(Value *value)
|
make_const(Value *value)
|
||||||
{
|
{
|
||||||
Datum val;
|
Datum val;
|
||||||
|
int64 val64;
|
||||||
Oid typeid;
|
Oid typeid;
|
||||||
int typelen;
|
int typelen;
|
||||||
bool typebyval;
|
bool typebyval;
|
||||||
@ -404,12 +394,13 @@ make_const(Value *value)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Float:
|
case T_Float:
|
||||||
if (fitsInFloat(value))
|
/* could be an oversize integer as well as a float ... */
|
||||||
|
if (scanint8(strVal(value), true, &val64))
|
||||||
{
|
{
|
||||||
val = Float8GetDatum(floatVal(value));
|
val = Int64GetDatum(val64);
|
||||||
|
|
||||||
typeid = FLOAT8OID;
|
typeid = INT8OID;
|
||||||
typelen = sizeof(float8);
|
typelen = sizeof(int64);
|
||||||
typebyval = false; /* XXX might change someday */
|
typebyval = false; /* XXX might change someday */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -470,46 +461,3 @@ make_const(Value *value)
|
|||||||
|
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Decide whether a T_Float value fits in float8, or must be treated as
|
|
||||||
* type "numeric". We check the number of digits and check for overflow/
|
|
||||||
* underflow. (With standard compilation options, Postgres' NUMERIC type
|
|
||||||
* can handle decimal exponents up to 1000, considerably more than most
|
|
||||||
* implementations of float8, so this is a sensible test.)
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
fitsInFloat(Value *value)
|
|
||||||
{
|
|
||||||
const char *ptr;
|
|
||||||
int ndigits;
|
|
||||||
char *endptr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Count digits, ignoring leading zeroes (but not trailing zeroes).
|
|
||||||
* DBL_DIG is the maximum safe number of digits for "double".
|
|
||||||
*/
|
|
||||||
ptr = strVal(value);
|
|
||||||
while (*ptr == '+' || *ptr == '-' || *ptr == '0' || *ptr == '.')
|
|
||||||
ptr++;
|
|
||||||
ndigits = 0;
|
|
||||||
for (; *ptr; ptr++)
|
|
||||||
{
|
|
||||||
if (isdigit((unsigned char) *ptr))
|
|
||||||
ndigits++;
|
|
||||||
else if (*ptr == 'e' || *ptr == 'E')
|
|
||||||
break; /* don't count digits in exponent */
|
|
||||||
}
|
|
||||||
if (ndigits > DBL_DIG)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use strtod() to check for overflow/underflow.
|
|
||||||
*/
|
|
||||||
errno = 0;
|
|
||||||
(void) strtod(strVal(value), &endptr);
|
|
||||||
if (*endptr != '\0' || errno != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.59 2002/09/04 20:31:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.60 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -273,7 +273,7 @@ oper_select_candidate(int nargs,
|
|||||||
current_candidate = current_candidate->next)
|
current_candidate = current_candidate->next)
|
||||||
{
|
{
|
||||||
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
|
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
|
||||||
false))
|
COERCION_IMPLICIT))
|
||||||
{
|
{
|
||||||
if (last_candidate == NULL)
|
if (last_candidate == NULL)
|
||||||
{
|
{
|
||||||
@ -362,7 +362,7 @@ oper_select_candidate(int nargs,
|
|||||||
{
|
{
|
||||||
if (input_typeids[i] != UNKNOWNOID)
|
if (input_typeids[i] != UNKNOWNOID)
|
||||||
{
|
{
|
||||||
if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
|
if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
|
||||||
nmatch++;
|
nmatch++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,8 +696,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
|
|||||||
|
|
||||||
/* but is it good enough? */
|
/* but is it good enough? */
|
||||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||||
if (IsBinaryCompatible(opform->oprleft, arg1) &&
|
if (IsBinaryCoercible(arg1, opform->oprleft) &&
|
||||||
IsBinaryCompatible(opform->oprright, arg2))
|
IsBinaryCoercible(arg2, opform->oprright))
|
||||||
return optup;
|
return optup;
|
||||||
|
|
||||||
/* nope... */
|
/* nope... */
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.89 2002/09/04 20:31:24 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.90 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -274,6 +274,7 @@ updateTargetListEntry(ParseState *pstate,
|
|||||||
aref = transformArraySubscripts(pstate,
|
aref = transformArraySubscripts(pstate,
|
||||||
arrayBase,
|
arrayBase,
|
||||||
attrtype,
|
attrtype,
|
||||||
|
attrtypmod,
|
||||||
indirection,
|
indirection,
|
||||||
pstate->p_is_insert,
|
pstate->p_is_insert,
|
||||||
tle->expr);
|
tle->expr);
|
||||||
@ -284,30 +285,21 @@ updateTargetListEntry(ParseState *pstate,
|
|||||||
/*
|
/*
|
||||||
* For normal non-subscripted target column, do type checking and
|
* For normal non-subscripted target column, do type checking and
|
||||||
* coercion. But accept InvalidOid, which indicates the source is
|
* coercion. But accept InvalidOid, which indicates the source is
|
||||||
* a NULL constant.
|
* a NULL constant. (XXX is that still true?)
|
||||||
*/
|
*/
|
||||||
if (type_id != InvalidOid)
|
if (type_id != InvalidOid)
|
||||||
{
|
{
|
||||||
if (type_id != attrtype)
|
tle->expr = coerce_to_target_type(tle->expr, type_id,
|
||||||
{
|
attrtype, attrtypmod,
|
||||||
tle->expr = CoerceTargetExpr(pstate, tle->expr, type_id,
|
COERCION_ASSIGNMENT,
|
||||||
attrtype, attrtypmod,
|
COERCE_IMPLICIT_CAST);
|
||||||
false);
|
if (tle->expr == NULL)
|
||||||
if (tle->expr == NULL)
|
elog(ERROR, "column \"%s\" is of type %s"
|
||||||
elog(ERROR, "column \"%s\" is of type '%s'"
|
" but expression is of type %s"
|
||||||
" but expression is of type '%s'"
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
"\n\tYou will need to rewrite or cast the expression",
|
colname,
|
||||||
colname,
|
format_type_be(attrtype),
|
||||||
format_type_be(attrtype),
|
format_type_be(type_id));
|
||||||
format_type_be(type_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the target is a fixed-length type, it may need a length
|
|
||||||
* coercion as well as a type coercion.
|
|
||||||
*/
|
|
||||||
tle->expr = coerce_type_typmod(pstate, tle->expr,
|
|
||||||
attrtype, attrtypmod);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,46 +316,6 @@ updateTargetListEntry(ParseState *pstate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node *
|
|
||||||
CoerceTargetExpr(ParseState *pstate,
|
|
||||||
Node *expr,
|
|
||||||
Oid type_id,
|
|
||||||
Oid attrtype,
|
|
||||||
int32 attrtypmod,
|
|
||||||
bool isExplicit)
|
|
||||||
{
|
|
||||||
if (can_coerce_type(1, &type_id, &attrtype, isExplicit))
|
|
||||||
expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod,
|
|
||||||
isExplicit);
|
|
||||||
|
|
||||||
#ifndef DISABLE_STRING_HACKS
|
|
||||||
|
|
||||||
/*
|
|
||||||
* string hacks to get transparent conversions w/o explicit
|
|
||||||
* conversions
|
|
||||||
*/
|
|
||||||
else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
|
|
||||||
{
|
|
||||||
Oid text_id = TEXTOID;
|
|
||||||
|
|
||||||
if (type_id == TEXTOID)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (can_coerce_type(1, &type_id, &text_id, isExplicit))
|
|
||||||
expr = coerce_type(pstate, expr, type_id, text_id, attrtypmod,
|
|
||||||
isExplicit);
|
|
||||||
else
|
|
||||||
expr = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
else
|
|
||||||
expr = NULL;
|
|
||||||
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* checkInsertTargets -
|
* checkInsertTargets -
|
||||||
* generate a list of INSERT column targets if not supplied, or
|
* generate a list of INSERT column targets if not supplied, or
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.109 2002/09/11 14:48:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.110 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -25,7 +25,6 @@
|
|||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parse_target.h"
|
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
@ -474,29 +473,21 @@ build_column_default(Relation rel, int attrno)
|
|||||||
*/
|
*/
|
||||||
exprtype = exprType(expr);
|
exprtype = exprType(expr);
|
||||||
|
|
||||||
if (exprtype != atttype)
|
expr = coerce_to_target_type(expr, exprtype,
|
||||||
{
|
atttype, atttypmod,
|
||||||
expr = CoerceTargetExpr(NULL, expr, exprtype,
|
COERCION_ASSIGNMENT,
|
||||||
atttype, atttypmod, false);
|
COERCE_IMPLICIT_CAST);
|
||||||
|
|
||||||
/*
|
|
||||||
* This really shouldn't fail; should have checked the default's
|
|
||||||
* type when it was created ...
|
|
||||||
*/
|
|
||||||
if (expr == NULL)
|
|
||||||
elog(ERROR, "Column \"%s\" is of type %s"
|
|
||||||
" but default expression is of type %s"
|
|
||||||
"\n\tYou will need to rewrite or cast the expression",
|
|
||||||
NameStr(att_tup->attname),
|
|
||||||
format_type_be(atttype),
|
|
||||||
format_type_be(exprtype));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the column is a fixed-length type, it may need a length coercion
|
* This really shouldn't fail; should have checked the default's
|
||||||
* as well as a type coercion.
|
* type when it was created ...
|
||||||
*/
|
*/
|
||||||
expr = coerce_type_typmod(NULL, expr, atttype, atttypmod);
|
if (expr == NULL)
|
||||||
|
elog(ERROR, "Column \"%s\" is of type %s"
|
||||||
|
" but default expression is of type %s"
|
||||||
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
|
NameStr(att_tup->attname),
|
||||||
|
format_type_be(atttype),
|
||||||
|
format_type_be(exprtype));
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.80 2002/09/04 20:31:27 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.81 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include "access/tupmacs.h"
|
#include "access/tupmacs.h"
|
||||||
#include "catalog/catalog.h"
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "parser/parse_coerce.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
@ -755,6 +756,72 @@ array_out(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_CSTRING(retval);
|
PG_RETURN_CSTRING(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* array_length_coerce :
|
||||||
|
* Apply the element type's length-coercion routine to each element
|
||||||
|
* of the given array.
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
array_length_coerce(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
||||||
|
int32 len = PG_GETARG_INT32(1);
|
||||||
|
bool isExplicit = PG_GETARG_BOOL(2);
|
||||||
|
FmgrInfo *fmgr_info = fcinfo->flinfo;
|
||||||
|
FmgrInfo *element_finfo;
|
||||||
|
FunctionCallInfoData locfcinfo;
|
||||||
|
|
||||||
|
/* If no typmod is provided, shortcircuit the whole thing */
|
||||||
|
if (len < 0)
|
||||||
|
PG_RETURN_ARRAYTYPE_P(v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We arrange to look up the element type's coercion function only
|
||||||
|
* once per series of calls.
|
||||||
|
*/
|
||||||
|
if (fmgr_info->fn_extra == NULL)
|
||||||
|
{
|
||||||
|
Oid funcId;
|
||||||
|
int nargs;
|
||||||
|
|
||||||
|
fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,
|
||||||
|
sizeof(FmgrInfo));
|
||||||
|
element_finfo = (FmgrInfo *) fmgr_info->fn_extra;
|
||||||
|
|
||||||
|
funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs);
|
||||||
|
|
||||||
|
if (OidIsValid(funcId))
|
||||||
|
fmgr_info_cxt(funcId, element_finfo, fmgr_info->fn_mcxt);
|
||||||
|
else
|
||||||
|
element_finfo->fn_oid = InvalidOid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
element_finfo = (FmgrInfo *) fmgr_info->fn_extra;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we didn't find a coercion function, return the array unmodified
|
||||||
|
* (this should not happen in the normal course of things, but might
|
||||||
|
* happen if this function is called manually).
|
||||||
|
*/
|
||||||
|
if (element_finfo->fn_oid == InvalidOid)
|
||||||
|
PG_RETURN_ARRAYTYPE_P(v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use array_map to apply the function to each array element.
|
||||||
|
*
|
||||||
|
* Note: we pass isExplicit whether or not the function wants it ...
|
||||||
|
*/
|
||||||
|
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
||||||
|
locfcinfo.flinfo = element_finfo;
|
||||||
|
locfcinfo.nargs = 3;
|
||||||
|
locfcinfo.arg[0] = PointerGetDatum(v);
|
||||||
|
locfcinfo.arg[1] = Int32GetDatum(len);
|
||||||
|
locfcinfo.arg[2] = BoolGetDatum(isExplicit);
|
||||||
|
|
||||||
|
return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v));
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* array_dims :
|
* array_dims :
|
||||||
* returns the dimensions of the array pointed to by "v", as a "text"
|
* returns the dimensions of the array pointed to by "v", as a "text"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.41 2002/09/04 20:31:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.42 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -48,14 +48,16 @@
|
|||||||
* Formatting and conversion routines.
|
* Formatting and conversion routines.
|
||||||
*---------------------------------------------------------*/
|
*---------------------------------------------------------*/
|
||||||
|
|
||||||
/* int8in()
|
/*
|
||||||
|
* scanint8 --- try to parse a string into an int8.
|
||||||
|
*
|
||||||
|
* If errorOK is false, elog a useful error message if the string is bad.
|
||||||
|
* If errorOK is true, just return "false" for bad input.
|
||||||
*/
|
*/
|
||||||
Datum
|
bool
|
||||||
int8in(PG_FUNCTION_ARGS)
|
scanint8(const char *str, bool errorOK, int64 *result)
|
||||||
{
|
{
|
||||||
char *str = PG_GETARG_CSTRING(0);
|
const char *ptr = str;
|
||||||
int64 result;
|
|
||||||
char *ptr = str;
|
|
||||||
int64 tmp = 0;
|
int64 tmp = 0;
|
||||||
int sign = 1;
|
int sign = 1;
|
||||||
|
|
||||||
@ -63,8 +65,11 @@ int8in(PG_FUNCTION_ARGS)
|
|||||||
* Do our own scan, rather than relying on sscanf which might be
|
* Do our own scan, rather than relying on sscanf which might be
|
||||||
* broken for long long.
|
* broken for long long.
|
||||||
*/
|
*/
|
||||||
while (*ptr && isspace((unsigned char) *ptr)) /* skip leading spaces */
|
|
||||||
|
/* skip leading spaces */
|
||||||
|
while (*ptr && isspace((unsigned char) *ptr))
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
||||||
/* handle sign */
|
/* handle sign */
|
||||||
if (*ptr == '-')
|
if (*ptr == '-')
|
||||||
{
|
{
|
||||||
@ -79,28 +84,61 @@ int8in(PG_FUNCTION_ARGS)
|
|||||||
#ifndef INT64_IS_BUSTED
|
#ifndef INT64_IS_BUSTED
|
||||||
if (strcmp(ptr, "9223372036854775808") == 0)
|
if (strcmp(ptr, "9223372036854775808") == 0)
|
||||||
{
|
{
|
||||||
result = -INT64CONST(0x7fffffffffffffff) - 1;
|
*result = -INT64CONST(0x7fffffffffffffff) - 1;
|
||||||
PG_RETURN_INT64(result);
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (*ptr == '+')
|
else if (*ptr == '+')
|
||||||
ptr++;
|
ptr++;
|
||||||
if (!isdigit((unsigned char) *ptr)) /* require at least one digit */
|
|
||||||
elog(ERROR, "Bad int8 external representation \"%s\"", str);
|
/* require at least one digit */
|
||||||
while (*ptr && isdigit((unsigned char) *ptr)) /* process digits */
|
if (!isdigit((unsigned char) *ptr))
|
||||||
|
{
|
||||||
|
if (errorOK)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
elog(ERROR, "Bad int8 external representation \"%s\"", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process digits */
|
||||||
|
while (*ptr && isdigit((unsigned char) *ptr))
|
||||||
{
|
{
|
||||||
int64 newtmp = tmp * 10 + (*ptr++ - '0');
|
int64 newtmp = tmp * 10 + (*ptr++ - '0');
|
||||||
|
|
||||||
if ((newtmp / 10) != tmp) /* overflow? */
|
if ((newtmp / 10) != tmp) /* overflow? */
|
||||||
elog(ERROR, "int8 value out of range: \"%s\"", str);
|
{
|
||||||
|
if (errorOK)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
elog(ERROR, "int8 value out of range: \"%s\"", str);
|
||||||
|
}
|
||||||
tmp = newtmp;
|
tmp = newtmp;
|
||||||
}
|
}
|
||||||
if (*ptr) /* trailing junk? */
|
|
||||||
elog(ERROR, "Bad int8 external representation \"%s\"", str);
|
|
||||||
|
|
||||||
result = (sign < 0) ? -tmp : tmp;
|
/* trailing junk? */
|
||||||
|
if (*ptr)
|
||||||
|
{
|
||||||
|
if (errorOK)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
elog(ERROR, "Bad int8 external representation \"%s\"", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = (sign < 0) ? -tmp : tmp;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* int8in()
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
int8in(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
char *str = PG_GETARG_CSTRING(0);
|
||||||
|
int64 result;
|
||||||
|
|
||||||
|
(void) scanint8(str, false, &result);
|
||||||
PG_RETURN_INT64(result);
|
PG_RETURN_INT64(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +785,7 @@ i8tod(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* dtoi8()
|
/* dtoi8()
|
||||||
* Convert double float to 8-byte integer.
|
* Convert float8 to 8-byte integer.
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
dtoi8(PG_FUNCTION_ARGS)
|
dtoi8(PG_FUNCTION_ARGS)
|
||||||
@ -771,8 +809,66 @@ dtoi8(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_INT64(result);
|
PG_RETURN_INT64(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* text_int8()
|
Datum
|
||||||
|
i8tof(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
int64 val = PG_GETARG_INT64(0);
|
||||||
|
float4 result;
|
||||||
|
|
||||||
|
result = val;
|
||||||
|
|
||||||
|
PG_RETURN_FLOAT4(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ftoi8()
|
||||||
|
* Convert float4 to 8-byte integer.
|
||||||
*/
|
*/
|
||||||
|
Datum
|
||||||
|
ftoi8(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
float4 val = PG_GETARG_FLOAT4(0);
|
||||||
|
int64 result;
|
||||||
|
float8 dval;
|
||||||
|
|
||||||
|
/* Round val to nearest integer (but it's still in float form) */
|
||||||
|
dval = rint(val);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Does it fit in an int64? Avoid assuming that we have handy
|
||||||
|
* constants defined for the range boundaries, instead test for
|
||||||
|
* overflow by reverse-conversion.
|
||||||
|
*/
|
||||||
|
result = (int64) dval;
|
||||||
|
|
||||||
|
if ((float8) result != dval)
|
||||||
|
elog(ERROR, "Floating point conversion to int8 is out of range");
|
||||||
|
|
||||||
|
PG_RETURN_INT64(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
i8tooid(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
int64 val = PG_GETARG_INT64(0);
|
||||||
|
Oid result;
|
||||||
|
|
||||||
|
result = (Oid) val;
|
||||||
|
|
||||||
|
/* Test for overflow by reverse-conversion. */
|
||||||
|
if ((int64) result != val)
|
||||||
|
elog(ERROR, "int8 conversion to OID is out of range");
|
||||||
|
|
||||||
|
PG_RETURN_OID(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
oidtoi8(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid val = PG_GETARG_OID(0);
|
||||||
|
|
||||||
|
PG_RETURN_INT64((int64) val);
|
||||||
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
text_int8(PG_FUNCTION_ARGS)
|
text_int8(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -793,9 +889,6 @@ text_int8(PG_FUNCTION_ARGS)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* int8_text()
|
|
||||||
*/
|
|
||||||
Datum
|
Datum
|
||||||
int8_text(PG_FUNCTION_ARGS)
|
int8_text(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* 1998 Jan Wieck
|
* 1998 Jan Wieck
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.53 2002/09/04 20:31:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.54 2002/09/18 21:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
@ -1709,6 +1709,50 @@ numeric_float4(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Datum
|
||||||
|
text_numeric(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
text *str = PG_GETARG_TEXT_P(0);
|
||||||
|
int len;
|
||||||
|
char *s;
|
||||||
|
Datum result;
|
||||||
|
|
||||||
|
len = (VARSIZE(str) - VARHDRSZ);
|
||||||
|
s = palloc(len + 1);
|
||||||
|
memcpy(s, VARDATA(str), len);
|
||||||
|
*(s + len) = '\0';
|
||||||
|
|
||||||
|
result = DirectFunctionCall3(numeric_in, CStringGetDatum(s),
|
||||||
|
ObjectIdGetDatum(0), Int32GetDatum(-1));
|
||||||
|
|
||||||
|
pfree(s);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_text(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
/* val is numeric, but easier to leave it as Datum */
|
||||||
|
Datum val = PG_GETARG_DATUM(0);
|
||||||
|
char *s;
|
||||||
|
int len;
|
||||||
|
text *result;
|
||||||
|
|
||||||
|
s = DatumGetCString(DirectFunctionCall1(numeric_out, val));
|
||||||
|
len = strlen(s);
|
||||||
|
|
||||||
|
result = (text *) palloc(VARHDRSZ + len);
|
||||||
|
|
||||||
|
VARATT_SIZEP(result) = len + VARHDRSZ;
|
||||||
|
memcpy(VARDATA(result), s, len);
|
||||||
|
|
||||||
|
pfree(s);
|
||||||
|
|
||||||
|
PG_RETURN_TEXT_P(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Aggregate functions
|
* Aggregate functions
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.75 2002/09/04 20:31:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.76 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -49,7 +49,7 @@ static void parseNameAndArgTypes(const char *string, const char *caller,
|
|||||||
/*
|
/*
|
||||||
* regprocin - converts "proname" to proc OID
|
* regprocin - converts "proname" to proc OID
|
||||||
*
|
*
|
||||||
* We also accept a numeric OID, mostly for historical reasons.
|
* We also accept a numeric OID, for symmetry with the output routine.
|
||||||
*
|
*
|
||||||
* '-' signifies unknown (OID 0). In all other cases, the input must
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
||||||
* match an existing pg_proc entry.
|
* match an existing pg_proc entry.
|
||||||
@ -71,15 +71,8 @@ regprocin(PG_FUNCTION_ARGS)
|
|||||||
pro_name_or_oid[0] <= '9' &&
|
pro_name_or_oid[0] <= '9' &&
|
||||||
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
|
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
|
||||||
{
|
{
|
||||||
Oid searchOid;
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||||
|
|
||||||
searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
||||||
CStringGetDatum(pro_name_or_oid)));
|
CStringGetDatum(pro_name_or_oid)));
|
||||||
result = (RegProcedure) GetSysCacheOid(PROCOID,
|
|
||||||
ObjectIdGetDatum(searchOid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!RegProcedureIsValid(result))
|
|
||||||
elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
|
|
||||||
PG_RETURN_OID(result);
|
PG_RETURN_OID(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +204,7 @@ regprocout(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* regprocedurein - converts "proname(args)" to proc OID
|
* regprocedurein - converts "proname(args)" to proc OID
|
||||||
*
|
*
|
||||||
* We also accept a numeric OID, mostly for historical reasons.
|
* We also accept a numeric OID, for symmetry with the output routine.
|
||||||
*
|
*
|
||||||
* '-' signifies unknown (OID 0). In all other cases, the input must
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
||||||
* match an existing pg_proc entry.
|
* match an existing pg_proc entry.
|
||||||
@ -235,15 +228,8 @@ regprocedurein(PG_FUNCTION_ARGS)
|
|||||||
pro_name_or_oid[0] <= '9' &&
|
pro_name_or_oid[0] <= '9' &&
|
||||||
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
|
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
|
||||||
{
|
{
|
||||||
Oid searchOid;
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||||
|
|
||||||
searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
||||||
CStringGetDatum(pro_name_or_oid)));
|
CStringGetDatum(pro_name_or_oid)));
|
||||||
result = (RegProcedure) GetSysCacheOid(PROCOID,
|
|
||||||
ObjectIdGetDatum(searchOid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!RegProcedureIsValid(result))
|
|
||||||
elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
|
|
||||||
PG_RETURN_OID(result);
|
PG_RETURN_OID(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +347,7 @@ regprocedureout(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* regoperin - converts "oprname" to operator OID
|
* regoperin - converts "oprname" to operator OID
|
||||||
*
|
*
|
||||||
* We also accept a numeric OID, mostly for historical reasons.
|
* We also accept a numeric OID, for symmetry with the output routine.
|
||||||
*
|
*
|
||||||
* '0' signifies unknown (OID 0). In all other cases, the input must
|
* '0' signifies unknown (OID 0). In all other cases, the input must
|
||||||
* match an existing pg_operator entry.
|
* match an existing pg_operator entry.
|
||||||
@ -383,15 +369,8 @@ regoperin(PG_FUNCTION_ARGS)
|
|||||||
opr_name_or_oid[0] <= '9' &&
|
opr_name_or_oid[0] <= '9' &&
|
||||||
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
|
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
|
||||||
{
|
{
|
||||||
Oid searchOid;
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||||
|
|
||||||
searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
||||||
CStringGetDatum(opr_name_or_oid)));
|
CStringGetDatum(opr_name_or_oid)));
|
||||||
result = GetSysCacheOid(OPEROID,
|
|
||||||
ObjectIdGetDatum(searchOid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!OidIsValid(result))
|
|
||||||
elog(ERROR, "No operator with oid %s", opr_name_or_oid);
|
|
||||||
PG_RETURN_OID(result);
|
PG_RETURN_OID(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,7 +510,7 @@ regoperout(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* regoperatorin - converts "oprname(args)" to operator OID
|
* regoperatorin - converts "oprname(args)" to operator OID
|
||||||
*
|
*
|
||||||
* We also accept a numeric OID, mostly for historical reasons.
|
* We also accept a numeric OID, for symmetry with the output routine.
|
||||||
*
|
*
|
||||||
* '0' signifies unknown (OID 0). In all other cases, the input must
|
* '0' signifies unknown (OID 0). In all other cases, the input must
|
||||||
* match an existing pg_operator entry.
|
* match an existing pg_operator entry.
|
||||||
@ -556,15 +535,8 @@ regoperatorin(PG_FUNCTION_ARGS)
|
|||||||
opr_name_or_oid[0] <= '9' &&
|
opr_name_or_oid[0] <= '9' &&
|
||||||
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
|
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
|
||||||
{
|
{
|
||||||
Oid searchOid;
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||||
|
|
||||||
searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
||||||
CStringGetDatum(opr_name_or_oid)));
|
CStringGetDatum(opr_name_or_oid)));
|
||||||
result = GetSysCacheOid(OPEROID,
|
|
||||||
ObjectIdGetDatum(searchOid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!OidIsValid(result))
|
|
||||||
elog(ERROR, "No operator with oid %s", opr_name_or_oid);
|
|
||||||
PG_RETURN_OID(result);
|
PG_RETURN_OID(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +670,7 @@ regoperatorout(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* regclassin - converts "classname" to class OID
|
* regclassin - converts "classname" to class OID
|
||||||
*
|
*
|
||||||
* We also accept a numeric OID, mostly for historical reasons.
|
* We also accept a numeric OID, for symmetry with the output routine.
|
||||||
*
|
*
|
||||||
* '-' signifies unknown (OID 0). In all other cases, the input must
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
||||||
* match an existing pg_class entry.
|
* match an existing pg_class entry.
|
||||||
@ -719,15 +691,8 @@ regclassin(PG_FUNCTION_ARGS)
|
|||||||
class_name_or_oid[0] <= '9' &&
|
class_name_or_oid[0] <= '9' &&
|
||||||
strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
|
strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
|
||||||
{
|
{
|
||||||
Oid searchOid;
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||||
|
|
||||||
searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
||||||
CStringGetDatum(class_name_or_oid)));
|
CStringGetDatum(class_name_or_oid)));
|
||||||
result = GetSysCacheOid(RELOID,
|
|
||||||
ObjectIdGetDatum(searchOid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!OidIsValid(result))
|
|
||||||
elog(ERROR, "No class with oid %s", class_name_or_oid);
|
|
||||||
PG_RETURN_OID(result);
|
PG_RETURN_OID(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,7 +808,7 @@ regclassout(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* regtypein - converts "typename" to type OID
|
* regtypein - converts "typename" to type OID
|
||||||
*
|
*
|
||||||
* We also accept a numeric OID, mostly for historical reasons.
|
* We also accept a numeric OID, for symmetry with the output routine.
|
||||||
*
|
*
|
||||||
* '-' signifies unknown (OID 0). In all other cases, the input must
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
||||||
* match an existing pg_type entry.
|
* match an existing pg_type entry.
|
||||||
@ -870,15 +835,8 @@ regtypein(PG_FUNCTION_ARGS)
|
|||||||
typ_name_or_oid[0] <= '9' &&
|
typ_name_or_oid[0] <= '9' &&
|
||||||
strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
|
strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
|
||||||
{
|
{
|
||||||
Oid searchOid;
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||||
|
|
||||||
searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
||||||
CStringGetDatum(typ_name_or_oid)));
|
CStringGetDatum(typ_name_or_oid)));
|
||||||
result = GetSysCacheOid(TYPEOID,
|
|
||||||
ObjectIdGetDatum(searchOid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!OidIsValid(result))
|
|
||||||
elog(ERROR, "No type with oid %s", typ_name_or_oid);
|
|
||||||
PG_RETURN_OID(result);
|
PG_RETURN_OID(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* back to source text
|
* back to source text
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.121 2002/09/04 20:31:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.122 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -152,7 +152,6 @@ static void get_oper_expr(Expr *expr, deparse_context *context);
|
|||||||
static void get_func_expr(Expr *expr, deparse_context *context);
|
static void get_func_expr(Expr *expr, deparse_context *context);
|
||||||
static void get_agg_expr(Aggref *aggref, deparse_context *context);
|
static void get_agg_expr(Aggref *aggref, deparse_context *context);
|
||||||
static Node *strip_type_coercion(Node *expr, Oid resultType);
|
static Node *strip_type_coercion(Node *expr, Oid resultType);
|
||||||
static void get_tle_expr(TargetEntry *tle, deparse_context *context);
|
|
||||||
static void get_const_expr(Const *constval, deparse_context *context);
|
static void get_const_expr(Const *constval, deparse_context *context);
|
||||||
static void get_sublink_expr(Node *node, deparse_context *context);
|
static void get_sublink_expr(Node *node, deparse_context *context);
|
||||||
static void get_from_clause(Query *query, deparse_context *context);
|
static void get_from_clause(Query *query, deparse_context *context);
|
||||||
@ -1430,7 +1429,6 @@ get_basic_select_query(Query *query, deparse_context *context,
|
|||||||
sep = ", ";
|
sep = ", ";
|
||||||
colno++;
|
colno++;
|
||||||
|
|
||||||
/* Do NOT use get_tle_expr here; see its comments! */
|
|
||||||
get_rule_expr(tle->expr, context);
|
get_rule_expr(tle->expr, context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1644,7 +1642,7 @@ get_insert_query_def(Query *query, deparse_context *context)
|
|||||||
|
|
||||||
appendStringInfo(buf, sep);
|
appendStringInfo(buf, sep);
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
get_tle_expr(tle, context);
|
get_rule_expr(tle->expr, context);
|
||||||
}
|
}
|
||||||
appendStringInfoChar(buf, ')');
|
appendStringInfoChar(buf, ')');
|
||||||
}
|
}
|
||||||
@ -1694,7 +1692,7 @@ get_update_query_def(Query *query, deparse_context *context)
|
|||||||
if (!tleIsArrayAssign(tle))
|
if (!tleIsArrayAssign(tle))
|
||||||
appendStringInfo(buf, "%s = ",
|
appendStringInfo(buf, "%s = ",
|
||||||
quote_identifier(tle->resdom->resname));
|
quote_identifier(tle->resdom->resname));
|
||||||
get_tle_expr(tle, context);
|
get_rule_expr(tle->expr, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the FROM clause if needed */
|
/* Add the FROM clause if needed */
|
||||||
@ -2106,12 +2104,29 @@ get_rule_expr(Node *node, deparse_context *context)
|
|||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
{
|
{
|
||||||
RelabelType *relabel = (RelabelType *) node;
|
RelabelType *relabel = (RelabelType *) node;
|
||||||
|
Node *arg = relabel->arg;
|
||||||
|
|
||||||
appendStringInfoChar(buf, '(');
|
if (relabel->relabelformat == COERCE_IMPLICIT_CAST)
|
||||||
get_rule_expr(relabel->arg, context);
|
{
|
||||||
appendStringInfo(buf, ")::%s",
|
/* don't show an implicit cast */
|
||||||
|
get_rule_expr(arg, context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Strip off any type coercions on the input, so we don't
|
||||||
|
* print redundancies like x::bpchar::character(8).
|
||||||
|
*
|
||||||
|
* XXX Are there any cases where this is a bad idea?
|
||||||
|
*/
|
||||||
|
arg = strip_type_coercion(arg, relabel->resulttype);
|
||||||
|
|
||||||
|
appendStringInfoChar(buf, '(');
|
||||||
|
get_rule_expr(arg, context);
|
||||||
|
appendStringInfo(buf, ")::%s",
|
||||||
format_type_with_typemod(relabel->resulttype,
|
format_type_with_typemod(relabel->resulttype,
|
||||||
relabel->resulttypmod));
|
relabel->resulttypmod));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2305,21 +2320,33 @@ get_func_expr(Expr *expr, deparse_context *context)
|
|||||||
StringInfo buf = context->buf;
|
StringInfo buf = context->buf;
|
||||||
Func *func = (Func *) (expr->oper);
|
Func *func = (Func *) (expr->oper);
|
||||||
Oid funcoid = func->funcid;
|
Oid funcoid = func->funcid;
|
||||||
int32 coercedTypmod;
|
|
||||||
Oid argtypes[FUNC_MAX_ARGS];
|
Oid argtypes[FUNC_MAX_ARGS];
|
||||||
int nargs;
|
int nargs;
|
||||||
List *l;
|
List *l;
|
||||||
char *sep;
|
char *sep;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if function is a length-coercion function for some
|
* If the function call came from an implicit coercion, then just show
|
||||||
* datatype. If so, display the operation as a type cast.
|
* the first argument.
|
||||||
*/
|
*/
|
||||||
if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
|
if (func->funcformat == COERCE_IMPLICIT_CAST)
|
||||||
|
{
|
||||||
|
get_rule_expr((Node *) lfirst(expr->args), context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the function call came from an explicit cast, then show
|
||||||
|
* the first argument plus an explicit cast operation.
|
||||||
|
*/
|
||||||
|
if (func->funcformat == COERCE_EXPLICIT_CAST)
|
||||||
{
|
{
|
||||||
Node *arg = lfirst(expr->args);
|
Node *arg = lfirst(expr->args);
|
||||||
Oid rettype = get_func_rettype(funcoid);
|
Oid rettype = expr->typeOid;
|
||||||
char *typdesc;
|
int32 coercedTypmod;
|
||||||
|
|
||||||
|
/* Get the typmod if this is a length-coercion function */
|
||||||
|
(void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Strip off any type coercions on the input, so we don't print
|
* Strip off any type coercions on the input, so we don't print
|
||||||
@ -2331,17 +2358,8 @@ get_func_expr(Expr *expr, deparse_context *context)
|
|||||||
|
|
||||||
appendStringInfoChar(buf, '(');
|
appendStringInfoChar(buf, '(');
|
||||||
get_rule_expr(arg, context);
|
get_rule_expr(arg, context);
|
||||||
|
appendStringInfo(buf, ")::%s",
|
||||||
/*
|
format_type_with_typemod(rettype, coercedTypmod));
|
||||||
* Show typename with appropriate length decoration. Note that
|
|
||||||
* since exprIsLengthCoercion succeeded, the function's output
|
|
||||||
* type is the right thing to report. Also note we don't need to
|
|
||||||
* quote the result of format_type_with_typemod: it takes care of
|
|
||||||
* double-quoting any identifier that needs it.
|
|
||||||
*/
|
|
||||||
typdesc = format_type_with_typemod(rettype, coercedTypmod);
|
|
||||||
appendStringInfo(buf, ")::%s", typdesc);
|
|
||||||
pfree(typdesc);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2393,15 +2411,14 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* strip_type_coercion
|
* strip_type_coercion
|
||||||
* Strip any type coercions at the top of the given expression tree,
|
* Strip any type coercion at the top of the given expression tree,
|
||||||
* as long as they are coercions to the given datatype.
|
* if it is a coercion to the given datatype.
|
||||||
*
|
*
|
||||||
* A RelabelType node is always a type coercion. A function call is
|
* We use this to avoid printing two levels of coercion in situations where
|
||||||
* also considered a type coercion if it has one argument and there is
|
* the expression tree has a length-coercion node atop a type-coercion node.
|
||||||
* a cast declared that uses it.
|
|
||||||
*
|
*
|
||||||
* XXX It'd be better if the parsetree retained some explicit indication
|
* Note: avoid stripping a length-coercion node, since two successive
|
||||||
* of the coercion, so we didn't need these heuristics.
|
* coercions to different lengths aren't a no-op.
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
strip_type_coercion(Node *expr, Oid resultType)
|
strip_type_coercion(Node *expr, Oid resultType)
|
||||||
@ -2409,101 +2426,30 @@ strip_type_coercion(Node *expr, Oid resultType)
|
|||||||
if (expr == NULL || exprType(expr) != resultType)
|
if (expr == NULL || exprType(expr) != resultType)
|
||||||
return expr;
|
return expr;
|
||||||
|
|
||||||
if (IsA(expr, RelabelType))
|
if (IsA(expr, RelabelType) &&
|
||||||
return strip_type_coercion(((RelabelType *) expr)->arg, resultType);
|
((RelabelType *) expr)->resulttypmod == -1)
|
||||||
|
return ((RelabelType *) expr)->arg;
|
||||||
|
|
||||||
if (IsA(expr, Expr) &&
|
if (IsA(expr, Expr) &&
|
||||||
((Expr *) expr)->opType == FUNC_EXPR)
|
((Expr *) expr)->opType == FUNC_EXPR)
|
||||||
{
|
{
|
||||||
Func *func;
|
Func *func = (Func *) (((Expr *) expr)->oper);
|
||||||
HeapTuple procTuple;
|
|
||||||
HeapTuple castTuple;
|
|
||||||
Form_pg_proc procStruct;
|
|
||||||
Form_pg_cast castStruct;
|
|
||||||
|
|
||||||
func = (Func *) (((Expr *) expr)->oper);
|
|
||||||
Assert(IsA(func, Func));
|
Assert(IsA(func, Func));
|
||||||
if (length(((Expr *) expr)->args) != 1)
|
if (func->funcformat != COERCE_EXPLICIT_CAST &&
|
||||||
|
func->funcformat != COERCE_IMPLICIT_CAST)
|
||||||
|
return expr; /* don't absorb into upper coercion */
|
||||||
|
|
||||||
|
if (exprIsLengthCoercion(expr, NULL))
|
||||||
return expr;
|
return expr;
|
||||||
/* Lookup the function in pg_proc */
|
|
||||||
procTuple = SearchSysCache(PROCOID,
|
return (Node *) lfirst(((Expr *) expr)->args);
|
||||||
ObjectIdGetDatum(func->funcid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!HeapTupleIsValid(procTuple))
|
|
||||||
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
|
|
||||||
procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
|
|
||||||
/* Double-check func has one arg and correct result type */
|
|
||||||
if (procStruct->pronargs != 1 ||
|
|
||||||
procStruct->prorettype != resultType)
|
|
||||||
{
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
/* See if function has is actually declared as a cast */
|
|
||||||
castTuple = SearchSysCache(CASTSOURCETARGET,
|
|
||||||
ObjectIdGetDatum(procStruct->proargtypes[0]),
|
|
||||||
ObjectIdGetDatum(procStruct->prorettype),
|
|
||||||
0, 0);
|
|
||||||
if (!HeapTupleIsValid(castTuple))
|
|
||||||
{
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
/* It must also be an implicit cast. */
|
|
||||||
castStruct = (Form_pg_cast) GETSTRUCT(castTuple);
|
|
||||||
if (!castStruct->castimplicit)
|
|
||||||
{
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
ReleaseSysCache(castTuple);
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
/* Okay, it is indeed a type-coercion function */
|
|
||||||
ReleaseSysCache(procTuple);
|
|
||||||
ReleaseSysCache(castTuple);
|
|
||||||
return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
|
||||||
* get_tle_expr
|
|
||||||
*
|
|
||||||
* In an INSERT or UPDATE targetlist item, the parser may have inserted
|
|
||||||
* a length-coercion function call to coerce the value to the right
|
|
||||||
* length for the target column. We want to suppress the output of
|
|
||||||
* that function call, otherwise dump/reload/dump... would blow up the
|
|
||||||
* expression by adding more and more layers of length-coercion calls.
|
|
||||||
*
|
|
||||||
* As of 7.0, this hack is no longer absolutely essential, because the parser
|
|
||||||
* is now smart enough not to add a redundant length coercion function call.
|
|
||||||
* But we still suppress the function call just for neatness of displayed
|
|
||||||
* rules.
|
|
||||||
*
|
|
||||||
* Note that this hack must NOT be applied to SELECT targetlist items;
|
|
||||||
* any length coercion appearing there is something the user actually wrote.
|
|
||||||
* ----------
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
get_tle_expr(TargetEntry *tle, deparse_context *context)
|
|
||||||
{
|
|
||||||
Expr *expr = (Expr *) (tle->expr);
|
|
||||||
int32 coercedTypmod;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If top level is a length coercion to the correct length, suppress
|
|
||||||
* it; else dump the expression normally.
|
|
||||||
*/
|
|
||||||
if (tle->resdom->restypmod >= 0 &&
|
|
||||||
exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
|
|
||||||
coercedTypmod == tle->resdom->restypmod)
|
|
||||||
get_rule_expr((Node *) lfirst(expr->args), context);
|
|
||||||
else
|
|
||||||
get_rule_expr(tle->expr, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* get_const_expr
|
* get_const_expr
|
||||||
*
|
*
|
||||||
@ -2518,6 +2464,8 @@ get_const_expr(Const *constval, deparse_context *context)
|
|||||||
Form_pg_type typeStruct;
|
Form_pg_type typeStruct;
|
||||||
char *extval;
|
char *extval;
|
||||||
char *valptr;
|
char *valptr;
|
||||||
|
bool isfloat = false;
|
||||||
|
bool needlabel;
|
||||||
|
|
||||||
if (constval->constisnull)
|
if (constval->constisnull)
|
||||||
{
|
{
|
||||||
@ -2563,8 +2511,12 @@ get_const_expr(Const *constval, deparse_context *context)
|
|||||||
* NaN, so we need not get too crazy about pattern
|
* NaN, so we need not get too crazy about pattern
|
||||||
* matching here.
|
* matching here.
|
||||||
*/
|
*/
|
||||||
if (strspn(extval, "0123456789 +-eE.") == strlen(extval))
|
if (strspn(extval, "0123456789+-eE.") == strlen(extval))
|
||||||
|
{
|
||||||
appendStringInfo(buf, extval);
|
appendStringInfo(buf, extval);
|
||||||
|
if (strcspn(extval, "eE.") != strlen(extval))
|
||||||
|
isfloat = true; /* it looks like a float */
|
||||||
|
}
|
||||||
else
|
else
|
||||||
appendStringInfo(buf, "'%s'", extval);
|
appendStringInfo(buf, "'%s'", extval);
|
||||||
}
|
}
|
||||||
@ -2609,20 +2561,30 @@ get_const_expr(Const *constval, deparse_context *context)
|
|||||||
|
|
||||||
pfree(extval);
|
pfree(extval);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append ::typename unless the constant will be implicitly typed as
|
||||||
|
* the right type when it is read in. XXX this code has to be kept
|
||||||
|
* in sync with the behavior of the parser, especially make_const.
|
||||||
|
*/
|
||||||
switch (constval->consttype)
|
switch (constval->consttype)
|
||||||
{
|
{
|
||||||
case BOOLOID:
|
case BOOLOID:
|
||||||
case INT4OID:
|
case INT4OID:
|
||||||
case FLOAT8OID:
|
|
||||||
case UNKNOWNOID:
|
case UNKNOWNOID:
|
||||||
/* These types can be left unlabeled */
|
/* These types can be left unlabeled */
|
||||||
|
needlabel = false;
|
||||||
|
break;
|
||||||
|
case NUMERICOID:
|
||||||
|
/* Float-looking constants will be typed as numeric */
|
||||||
|
needlabel = !isfloat;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
appendStringInfo(buf, "::%s",
|
needlabel = true;
|
||||||
format_type_with_typemod(constval->consttype,
|
|
||||||
-1));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (needlabel)
|
||||||
|
appendStringInfo(buf, "::%s",
|
||||||
|
format_type_with_typemod(constval->consttype, -1));
|
||||||
|
|
||||||
ReleaseSysCache(typetup);
|
ReleaseSysCache(typetup);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.25 2002/09/04 20:31:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.26 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,11 @@
|
|||||||
* data section -- private data section for the bits data structures
|
* data section -- private data section for the bits data structures
|
||||||
* bitlength -- length of the bit string in bits
|
* bitlength -- length of the bit string in bits
|
||||||
* bitdata -- bit string, most significant byte first
|
* bitdata -- bit string, most significant byte first
|
||||||
|
*
|
||||||
|
* The length of the bitdata vector should always be exactly as many
|
||||||
|
* bytes as are needed for the given bitlength. If the bitlength is
|
||||||
|
* not a multiple of 8, the extra low-order padding bits of the last
|
||||||
|
* byte must be zeroes.
|
||||||
*----------
|
*----------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -104,7 +109,7 @@ bit_in(PG_FUNCTION_ARGS)
|
|||||||
len = VARBITTOTALLEN(atttypmod);
|
len = VARBITTOTALLEN(atttypmod);
|
||||||
result = (VarBit *) palloc(len);
|
result = (VarBit *) palloc(len);
|
||||||
/* set to 0 so that *r is always initialised and string is zero-padded */
|
/* set to 0 so that *r is always initialised and string is zero-padded */
|
||||||
memset(result, 0, len);
|
MemSet(result, 0, len);
|
||||||
VARATT_SIZEP(result) = len;
|
VARATT_SIZEP(result) = len;
|
||||||
VARBITLEN(result) = atttypmod;
|
VARBITLEN(result) = atttypmod;
|
||||||
|
|
||||||
@ -203,50 +208,52 @@ bit_out(PG_FUNCTION_ARGS)
|
|||||||
/* bit()
|
/* bit()
|
||||||
* Converts a bit() type to a specific internal length.
|
* Converts a bit() type to a specific internal length.
|
||||||
* len is the bitlength specified in the column definition.
|
* len is the bitlength specified in the column definition.
|
||||||
|
*
|
||||||
|
* If doing implicit cast, raise error when source data is wrong length.
|
||||||
|
* If doing explicit cast, silently truncate or zero-pad to specified length.
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
bit(PG_FUNCTION_ARGS)
|
bit(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
||||||
int32 len = PG_GETARG_INT32(1);
|
int32 len = PG_GETARG_INT32(1);
|
||||||
|
bool isExplicit = PG_GETARG_BOOL(2);
|
||||||
|
VarBit *result;
|
||||||
|
int rlen;
|
||||||
|
int ipad;
|
||||||
|
bits8 mask;
|
||||||
|
|
||||||
/* No work if typmod is invalid or supplied data matches it already */
|
/* No work if typmod is invalid or supplied data matches it already */
|
||||||
if (len <= 0 || len == VARBITLEN(arg))
|
if (len <= 0 || len == VARBITLEN(arg))
|
||||||
PG_RETURN_VARBIT_P(arg);
|
PG_RETURN_VARBIT_P(arg);
|
||||||
else
|
|
||||||
|
if (!isExplicit)
|
||||||
elog(ERROR, "Bit string length %d does not match type BIT(%d)",
|
elog(ERROR, "Bit string length %d does not match type BIT(%d)",
|
||||||
VARBITLEN(arg), len);
|
VARBITLEN(arg), len);
|
||||||
return 0; /* quiet compiler */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* _bit()
|
rlen = VARBITTOTALLEN(len);
|
||||||
* Converts an array of bit() elements to a specific internal length.
|
result = (VarBit *) palloc(rlen);
|
||||||
* len is the bitlength specified in the column definition.
|
/* set to 0 so that string is zero-padded */
|
||||||
*/
|
MemSet(result, 0, rlen);
|
||||||
Datum
|
VARATT_SIZEP(result) = rlen;
|
||||||
_bit(PG_FUNCTION_ARGS)
|
VARBITLEN(result) = len;
|
||||||
{
|
|
||||||
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
memcpy(VARBITS(result), VARBITS(arg),
|
||||||
int32 len = PG_GETARG_INT32(1);
|
Min(VARBITBYTES(result), VARBITBYTES(arg)));
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since bit() is a built-in function, we should only need to look it
|
* Make sure last byte is zero-padded if needed. This is useless but
|
||||||
* up once per run.
|
* safe if source data was shorter than target length (we assume the
|
||||||
|
* last byte of the source data was itself correctly zero-padded).
|
||||||
*/
|
*/
|
||||||
static FmgrInfo bit_finfo;
|
ipad = VARBITPAD(result);
|
||||||
|
if (ipad > 0)
|
||||||
|
{
|
||||||
|
mask = BITMASK << ipad;
|
||||||
|
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
||||||
|
}
|
||||||
|
|
||||||
if (bit_finfo.fn_oid == InvalidOid)
|
PG_RETURN_VARBIT_P(result);
|
||||||
fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext);
|
|
||||||
|
|
||||||
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
|
||||||
locfcinfo.flinfo = &bit_finfo;
|
|
||||||
locfcinfo.nargs = 2;
|
|
||||||
/* We assume we are "strict" and need not worry about null inputs */
|
|
||||||
locfcinfo.arg[0] = PointerGetDatum(v);
|
|
||||||
locfcinfo.arg[1] = Int32GetDatum(len);
|
|
||||||
|
|
||||||
return array_map(&locfcinfo, BITOID, BITOID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -311,7 +318,7 @@ varbit_in(PG_FUNCTION_ARGS)
|
|||||||
len = VARBITTOTALLEN(bitlen);
|
len = VARBITTOTALLEN(bitlen);
|
||||||
result = (VarBit *) palloc(len);
|
result = (VarBit *) palloc(len);
|
||||||
/* set to 0 so that *r is always initialised and string is zero-padded */
|
/* set to 0 so that *r is always initialised and string is zero-padded */
|
||||||
memset(result, 0, len);
|
MemSet(result, 0, len);
|
||||||
VARATT_SIZEP(result) = len;
|
VARATT_SIZEP(result) = len;
|
||||||
VARBITLEN(result) = Min(bitlen, atttypmod);
|
VARBITLEN(result) = Min(bitlen, atttypmod);
|
||||||
|
|
||||||
@ -406,20 +413,26 @@ varbit_out(PG_FUNCTION_ARGS)
|
|||||||
/* varbit()
|
/* varbit()
|
||||||
* Converts a varbit() type to a specific internal length.
|
* Converts a varbit() type to a specific internal length.
|
||||||
* len is the maximum bitlength specified in the column definition.
|
* len is the maximum bitlength specified in the column definition.
|
||||||
|
*
|
||||||
|
* If doing implicit cast, raise error when source data is too long.
|
||||||
|
* If doing explicit cast, silently truncate to max length.
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
varbit(PG_FUNCTION_ARGS)
|
varbit(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
VarBit *arg = PG_GETARG_VARBIT_P(0);
|
||||||
int32 len = PG_GETARG_INT32(1);
|
int32 len = PG_GETARG_INT32(1);
|
||||||
|
bool isExplicit = PG_GETARG_BOOL(2);
|
||||||
VarBit *result;
|
VarBit *result;
|
||||||
int rlen;
|
int rlen;
|
||||||
|
int ipad;
|
||||||
|
bits8 mask;
|
||||||
|
|
||||||
/* No work if typmod is invalid or supplied data matches it already */
|
/* No work if typmod is invalid or supplied data matches it already */
|
||||||
if (len <= 0 || len >= VARBITLEN(arg))
|
if (len <= 0 || len >= VARBITLEN(arg))
|
||||||
PG_RETURN_VARBIT_P(arg);
|
PG_RETURN_VARBIT_P(arg);
|
||||||
|
|
||||||
if (len < VARBITLEN(arg))
|
if (!isExplicit)
|
||||||
elog(ERROR, "Bit string too long for type BIT VARYING(%d)", len);
|
elog(ERROR, "Bit string too long for type BIT VARYING(%d)", len);
|
||||||
|
|
||||||
rlen = VARBITTOTALLEN(len);
|
rlen = VARBITTOTALLEN(len);
|
||||||
@ -429,39 +442,17 @@ varbit(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
|
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
|
||||||
|
|
||||||
|
/* Make sure last byte is zero-padded if needed */
|
||||||
|
ipad = VARBITPAD(result);
|
||||||
|
if (ipad > 0)
|
||||||
|
{
|
||||||
|
mask = BITMASK << ipad;
|
||||||
|
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
||||||
|
}
|
||||||
|
|
||||||
PG_RETURN_VARBIT_P(result);
|
PG_RETURN_VARBIT_P(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _varbit()
|
|
||||||
* Converts an array of bit() elements to a specific internal length.
|
|
||||||
* len is the maximum bitlength specified in the column definition.
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
_varbit(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
|
||||||
int32 len = PG_GETARG_INT32(1);
|
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since varbit() is a built-in function, we should only need to look
|
|
||||||
* it up once per run.
|
|
||||||
*/
|
|
||||||
static FmgrInfo varbit_finfo;
|
|
||||||
|
|
||||||
if (varbit_finfo.fn_oid == InvalidOid)
|
|
||||||
fmgr_info_cxt(F_VARBIT, &varbit_finfo, TopMemoryContext);
|
|
||||||
|
|
||||||
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
|
||||||
locfcinfo.flinfo = &varbit_finfo;
|
|
||||||
locfcinfo.nargs = 2;
|
|
||||||
/* We assume we are "strict" and need not worry about null inputs */
|
|
||||||
locfcinfo.arg[0] = PointerGetDatum(v);
|
|
||||||
locfcinfo.arg[1] = Int32GetDatum(len);
|
|
||||||
|
|
||||||
return array_map(&locfcinfo, VARBITOID, VARBITOID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Comparison operators
|
* Comparison operators
|
||||||
@ -978,7 +969,7 @@ bitshiftleft(PG_FUNCTION_ARGS)
|
|||||||
/* If we shifted all the bits out, return an all-zero string */
|
/* If we shifted all the bits out, return an all-zero string */
|
||||||
if (shft >= VARBITLEN(arg))
|
if (shft >= VARBITLEN(arg))
|
||||||
{
|
{
|
||||||
memset(r, 0, VARBITBYTES(arg));
|
MemSet(r, 0, VARBITBYTES(arg));
|
||||||
PG_RETURN_VARBIT_P(result);
|
PG_RETURN_VARBIT_P(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,7 +982,7 @@ bitshiftleft(PG_FUNCTION_ARGS)
|
|||||||
/* Special case: we can do a memcpy */
|
/* Special case: we can do a memcpy */
|
||||||
len = VARBITBYTES(arg) - byte_shift;
|
len = VARBITBYTES(arg) - byte_shift;
|
||||||
memcpy(r, p, len);
|
memcpy(r, p, len);
|
||||||
memset(r + len, 0, byte_shift);
|
MemSet(r + len, 0, byte_shift);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1037,7 +1028,7 @@ bitshiftright(PG_FUNCTION_ARGS)
|
|||||||
/* If we shifted all the bits out, return an all-zero string */
|
/* If we shifted all the bits out, return an all-zero string */
|
||||||
if (shft >= VARBITLEN(arg))
|
if (shft >= VARBITLEN(arg))
|
||||||
{
|
{
|
||||||
memset(r, 0, VARBITBYTES(arg));
|
MemSet(r, 0, VARBITBYTES(arg));
|
||||||
PG_RETURN_VARBIT_P(result);
|
PG_RETURN_VARBIT_P(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1046,7 +1037,7 @@ bitshiftright(PG_FUNCTION_ARGS)
|
|||||||
p = VARBITS(arg);
|
p = VARBITS(arg);
|
||||||
|
|
||||||
/* Set the first part of the result to 0 */
|
/* Set the first part of the result to 0 */
|
||||||
memset(r, 0, byte_shift);
|
MemSet(r, 0, byte_shift);
|
||||||
r += byte_shift;
|
r += byte_shift;
|
||||||
|
|
||||||
if (ishift == 0)
|
if (ishift == 0)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.94 2002/09/04 20:31:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.95 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -165,21 +165,28 @@ bpcharout(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts a CHARACTER type to the specified size. maxlen is the new
|
* Converts a CHARACTER type to the specified size.
|
||||||
* declared length plus VARHDRSZ bytes. Truncation
|
*
|
||||||
* rules see bpcharin() above.
|
* maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
|
||||||
|
* isExplicit is true if this is for an explicit cast to char(N).
|
||||||
|
*
|
||||||
|
* Truncation rules: for an explicit cast, silently truncate to the given
|
||||||
|
* length; for an implicit cast, raise error unless extra characters are
|
||||||
|
* all spaces. (This is sort-of per SQL: the spec would actually have us
|
||||||
|
* raise a "completion condition" for the explicit cast case, but Postgres
|
||||||
|
* hasn't got such a concept.)
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
bpchar(PG_FUNCTION_ARGS)
|
bpchar(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
BpChar *source = PG_GETARG_BPCHAR_P(0);
|
BpChar *source = PG_GETARG_BPCHAR_P(0);
|
||||||
int32 maxlen = PG_GETARG_INT32(1);
|
int32 maxlen = PG_GETARG_INT32(1);
|
||||||
|
bool isExplicit = PG_GETARG_BOOL(2);
|
||||||
BpChar *result;
|
BpChar *result;
|
||||||
int32 len;
|
int32 len;
|
||||||
char *r;
|
char *r;
|
||||||
char *s;
|
char *s;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
int charlen; /* number of charcters in the input string
|
int charlen; /* number of charcters in the input string
|
||||||
* + VARHDRSZ */
|
* + VARHDRSZ */
|
||||||
|
|
||||||
@ -188,7 +195,7 @@ bpchar(PG_FUNCTION_ARGS)
|
|||||||
charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ;
|
charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ;
|
||||||
|
|
||||||
/* No work if typmod is invalid or supplied data matches it already */
|
/* No work if typmod is invalid or supplied data matches it already */
|
||||||
if (maxlen < (int32) VARHDRSZ || len == maxlen)
|
if (maxlen < (int32) VARHDRSZ || charlen == maxlen)
|
||||||
PG_RETURN_BPCHAR_P(source);
|
PG_RETURN_BPCHAR_P(source);
|
||||||
|
|
||||||
if (charlen > maxlen)
|
if (charlen > maxlen)
|
||||||
@ -199,10 +206,13 @@ bpchar(PG_FUNCTION_ARGS)
|
|||||||
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
|
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
|
||||||
maxlen - VARHDRSZ) + VARHDRSZ;
|
maxlen - VARHDRSZ) + VARHDRSZ;
|
||||||
|
|
||||||
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
|
if (!isExplicit)
|
||||||
if (*(VARDATA(source) + i) != ' ')
|
{
|
||||||
elog(ERROR, "value too long for type character(%d)",
|
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
|
||||||
maxlen - VARHDRSZ);
|
if (*(VARDATA(source) + i) != ' ')
|
||||||
|
elog(ERROR, "value too long for type character(%d)",
|
||||||
|
maxlen - VARHDRSZ);
|
||||||
|
}
|
||||||
|
|
||||||
len = maxmblen;
|
len = maxmblen;
|
||||||
|
|
||||||
@ -238,37 +248,6 @@ bpchar(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* _bpchar()
|
|
||||||
* Converts an array of char() elements to a specific internal length.
|
|
||||||
* len is the length specified in () plus VARHDRSZ bytes.
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
_bpchar(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
|
||||||
int32 len = PG_GETARG_INT32(1);
|
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since bpchar() is a built-in function, we should only need to look
|
|
||||||
* it up once per run.
|
|
||||||
*/
|
|
||||||
static FmgrInfo bpchar_finfo;
|
|
||||||
|
|
||||||
if (bpchar_finfo.fn_oid == InvalidOid)
|
|
||||||
fmgr_info_cxt(F_BPCHAR, &bpchar_finfo, TopMemoryContext);
|
|
||||||
|
|
||||||
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
|
||||||
locfcinfo.flinfo = &bpchar_finfo;
|
|
||||||
locfcinfo.nargs = 2;
|
|
||||||
/* We assume we are "strict" and need not worry about null inputs */
|
|
||||||
locfcinfo.arg[0] = PointerGetDatum(v);
|
|
||||||
locfcinfo.arg[1] = Int32GetDatum(len);
|
|
||||||
|
|
||||||
return array_map(&locfcinfo, BPCHAROID, BPCHAROID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* char_bpchar()
|
/* char_bpchar()
|
||||||
* Convert char to bpchar(1).
|
* Convert char to bpchar(1).
|
||||||
*/
|
*/
|
||||||
@ -354,9 +333,9 @@ name_bpchar(PG_FUNCTION_ARGS)
|
|||||||
* Note that atttypmod is regarded as the number of characters, which
|
* Note that atttypmod is regarded as the number of characters, which
|
||||||
* is not necessarily the same as the number of bytes.
|
* is not necessarily the same as the number of bytes.
|
||||||
*
|
*
|
||||||
* If the C string is too long,
|
* If the C string is too long, raise an error, unless the extra characters
|
||||||
* raise an error, unless the extra characters are spaces, in which
|
* are spaces, in which case they're truncated. (per SQL)
|
||||||
* case they're truncated. (per SQL) */
|
*/
|
||||||
Datum
|
Datum
|
||||||
varcharin(PG_FUNCTION_ARGS)
|
varcharin(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -428,17 +407,26 @@ varcharout(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts a VARCHAR type to the specified size. maxlen is the new
|
* Converts a VARCHAR type to the specified size.
|
||||||
* declared length plus VARHDRSZ bytes. Truncation
|
*
|
||||||
* rules see varcharin() above.
|
* maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
|
||||||
|
* isExplicit is true if this is for an explicit cast to varchar(N).
|
||||||
|
*
|
||||||
|
* Truncation rules: for an explicit cast, silently truncate to the given
|
||||||
|
* length; for an implicit cast, raise error unless extra characters are
|
||||||
|
* all spaces. (This is sort-of per SQL: the spec would actually have us
|
||||||
|
* raise a "completion condition" for the explicit cast case, but Postgres
|
||||||
|
* hasn't got such a concept.)
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
varchar(PG_FUNCTION_ARGS)
|
varchar(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
VarChar *source = PG_GETARG_VARCHAR_P(0);
|
VarChar *source = PG_GETARG_VARCHAR_P(0);
|
||||||
int32 maxlen = PG_GETARG_INT32(1);
|
int32 maxlen = PG_GETARG_INT32(1);
|
||||||
|
bool isExplicit = PG_GETARG_BOOL(2);
|
||||||
VarChar *result;
|
VarChar *result;
|
||||||
int32 len;
|
int32 len;
|
||||||
|
size_t maxmblen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
len = VARSIZE(source);
|
len = VARSIZE(source);
|
||||||
@ -448,21 +436,19 @@ varchar(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* only reach here if string is too long... */
|
/* only reach here if string is too long... */
|
||||||
|
|
||||||
|
/* truncate multibyte string preserving multibyte boundary */
|
||||||
|
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
|
||||||
|
maxlen - VARHDRSZ);
|
||||||
|
|
||||||
|
if (!isExplicit)
|
||||||
{
|
{
|
||||||
size_t maxmblen;
|
for (i = maxmblen; i < len - VARHDRSZ; i++)
|
||||||
|
|
||||||
/* truncate multibyte string preserving multibyte boundary */
|
|
||||||
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
|
|
||||||
maxlen - VARHDRSZ) + VARHDRSZ;
|
|
||||||
|
|
||||||
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
|
|
||||||
if (*(VARDATA(source) + i) != ' ')
|
if (*(VARDATA(source) + i) != ' ')
|
||||||
elog(ERROR, "value too long for type character varying(%d)",
|
elog(ERROR, "value too long for type character varying(%d)",
|
||||||
maxlen - VARHDRSZ);
|
maxlen - VARHDRSZ);
|
||||||
|
|
||||||
len = maxmblen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
len = maxmblen + VARHDRSZ;
|
||||||
result = palloc(len);
|
result = palloc(len);
|
||||||
VARATT_SIZEP(result) = len;
|
VARATT_SIZEP(result) = len;
|
||||||
memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ);
|
memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ);
|
||||||
@ -471,38 +457,6 @@ varchar(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* _varchar()
|
|
||||||
* Converts an array of varchar() elements to the specified size.
|
|
||||||
* len is the length specified in () plus VARHDRSZ bytes.
|
|
||||||
*/
|
|
||||||
Datum
|
|
||||||
_varchar(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
|
||||||
int32 len = PG_GETARG_INT32(1);
|
|
||||||
FunctionCallInfoData locfcinfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since varchar() is a built-in function, we should only need to look
|
|
||||||
* it up once per run.
|
|
||||||
*/
|
|
||||||
static FmgrInfo varchar_finfo;
|
|
||||||
|
|
||||||
if (varchar_finfo.fn_oid == InvalidOid)
|
|
||||||
fmgr_info_cxt(F_VARCHAR, &varchar_finfo, TopMemoryContext);
|
|
||||||
|
|
||||||
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
|
||||||
locfcinfo.flinfo = &varchar_finfo;
|
|
||||||
locfcinfo.nargs = 2;
|
|
||||||
/* We assume we are "strict" and need not worry about null inputs */
|
|
||||||
locfcinfo.arg[0] = PointerGetDatum(v);
|
|
||||||
locfcinfo.arg[1] = Int32GetDatum(len);
|
|
||||||
|
|
||||||
return array_map(&locfcinfo, VARCHAROID, VARCHAROID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Exported functions
|
* Exported functions
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
47
src/backend/utils/cache/lsyscache.c
vendored
47
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.83 2002/09/04 20:31:30 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.84 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Eventually, the index information should go through here, too.
|
* Eventually, the index information should go through here, too.
|
||||||
@ -1073,51 +1073,6 @@ getBaseType(Oid typid)
|
|||||||
return typid;
|
return typid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* getBaseTypeMod
|
|
||||||
* If the given type is a domain, return the typmod it applies to
|
|
||||||
* its base type; otherwise return the specified original typmod.
|
|
||||||
*/
|
|
||||||
int32
|
|
||||||
getBaseTypeMod(Oid typid, int32 typmod)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We loop to find the bottom base type in a stack of domains.
|
|
||||||
*/
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
HeapTuple tup;
|
|
||||||
Form_pg_type typTup;
|
|
||||||
|
|
||||||
tup = SearchSysCache(TYPEOID,
|
|
||||||
ObjectIdGetDatum(typid),
|
|
||||||
0, 0, 0);
|
|
||||||
if (!HeapTupleIsValid(tup))
|
|
||||||
elog(ERROR, "getBaseTypeMod: failed to lookup type %u", typid);
|
|
||||||
typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
||||||
if (typTup->typtype != 'd')
|
|
||||||
{
|
|
||||||
/* Not a domain, so done */
|
|
||||||
ReleaseSysCache(tup);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The typmod applied to a domain should always be -1.
|
|
||||||
*
|
|
||||||
* We substitute the domain's typmod as we switch attention to the
|
|
||||||
* base type.
|
|
||||||
*/
|
|
||||||
Assert(typmod < 0);
|
|
||||||
|
|
||||||
typid = typTup->typbasetype;
|
|
||||||
typmod = typTup->typtypmod;
|
|
||||||
ReleaseSysCache(tup);
|
|
||||||
}
|
|
||||||
|
|
||||||
return typmod;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_typavgwidth
|
* get_typavgwidth
|
||||||
*
|
*
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
# Portions Copyright (c) 1994, Regents of the University of California
|
# Portions Copyright (c) 1994, Regents of the University of California
|
||||||
#
|
#
|
||||||
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.173 2002/09/05 19:56:57 tgl Exp $
|
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.174 2002/09/18 21:35:23 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -1018,7 +1018,7 @@ echo "ok"
|
|||||||
|
|
||||||
# Create pg_conversion and support functions
|
# Create pg_conversion and support functions
|
||||||
$ECHO_N "creating conversions... "$ECHO_C
|
$ECHO_N "creating conversions... "$ECHO_C
|
||||||
cat $datadir/conversion_create.sql | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
|
grep -v '^DROP CONVERSION' $datadir/conversion_create.sql | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
|
||||||
echo "ok"
|
echo "ok"
|
||||||
|
|
||||||
# Set most system catalogs and built-in functions as world-accessible.
|
# Set most system catalogs and built-in functions as world-accessible.
|
||||||
@ -1063,7 +1063,7 @@ UPDATE pg_database SET \
|
|||||||
-- We use the OID of template0 to determine lastsysoid
|
-- We use the OID of template0 to determine lastsysoid
|
||||||
|
|
||||||
UPDATE pg_database SET datlastsysoid = \
|
UPDATE pg_database SET datlastsysoid = \
|
||||||
(SELECT oid - 1 FROM pg_database WHERE datname = 'template0');
|
(SELECT oid::int4 - 1 FROM pg_database WHERE datname = 'template0');
|
||||||
|
|
||||||
-- Explicitly revoke public create-schema and create-temp-table privileges
|
-- Explicitly revoke public create-schema and create-temp-table privileges
|
||||||
-- in template1 and template0; else the latter would be on by default
|
-- in template1 and template0; else the latter would be on by default
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.298 2002/09/07 16:14:33 petere Exp $
|
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.299 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -3797,7 +3797,7 @@ dumpCasts(Archive *fout,
|
|||||||
selectSourceSchema("pg_catalog");
|
selectSourceSchema("pg_catalog");
|
||||||
|
|
||||||
if (fout->remoteVersion >= 70300)
|
if (fout->remoteVersion >= 70300)
|
||||||
appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castimplicit FROM pg_cast ORDER BY 1,2,3;");
|
appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castcontext FROM pg_cast ORDER BY 1,2,3;");
|
||||||
else
|
else
|
||||||
appendPQExpBuffer(query, "SELECT p.oid, t1.oid, t2.oid, p.oid, true FROM pg_type t1, pg_type t2, pg_proc p WHERE p.pronargs = 1 AND p.proargtypes[0] = t1.oid AND p.prorettype = t2.oid AND p.proname = t2.typname ORDER BY 1,2,3;");
|
appendPQExpBuffer(query, "SELECT p.oid, t1.oid, t2.oid, p.oid, true FROM pg_type t1, pg_type t2, pg_proc p WHERE p.pronargs = 1 AND p.proargtypes[0] = t1.oid AND p.prorettype = t2.oid AND p.proname = t2.typname ORDER BY 1,2,3;");
|
||||||
|
|
||||||
@ -3816,7 +3816,7 @@ dumpCasts(Archive *fout,
|
|||||||
char *castsource = PQgetvalue(res, i, 1);
|
char *castsource = PQgetvalue(res, i, 1);
|
||||||
char *casttarget = PQgetvalue(res, i, 2);
|
char *casttarget = PQgetvalue(res, i, 2);
|
||||||
char *castfunc = PQgetvalue(res, i, 3);
|
char *castfunc = PQgetvalue(res, i, 3);
|
||||||
char *castimplicit = PQgetvalue(res, i, 4);
|
char *castcontext = PQgetvalue(res, i, 4);
|
||||||
int fidx = -1;
|
int fidx = -1;
|
||||||
const char *((*deps)[]);
|
const char *((*deps)[]);
|
||||||
|
|
||||||
@ -3859,8 +3859,10 @@ dumpCasts(Archive *fout,
|
|||||||
appendPQExpBuffer(defqry, "WITH FUNCTION %s",
|
appendPQExpBuffer(defqry, "WITH FUNCTION %s",
|
||||||
format_function_signature(&finfo[fidx], true));
|
format_function_signature(&finfo[fidx], true));
|
||||||
|
|
||||||
if (strcmp(castimplicit, "t") == 0)
|
if (strcmp(castcontext, "a") == 0)
|
||||||
appendPQExpBuffer(defqry, " AS ASSIGNMENT");
|
appendPQExpBuffer(defqry, " AS ASSIGNMENT");
|
||||||
|
else if (strcmp(castcontext, "i") == 0)
|
||||||
|
appendPQExpBuffer(defqry, " AS IMPLICIT");
|
||||||
appendPQExpBuffer(defqry, ";\n");
|
appendPQExpBuffer(defqry, ";\n");
|
||||||
|
|
||||||
ArchiveEntry(fout, castoid,
|
ArchiveEntry(fout, castoid,
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: catversion.h,v 1.158 2002/09/02 06:24:15 momjian Exp $
|
* $Id: catversion.h,v 1.159 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200209021
|
#define CATALOG_VERSION_NO 200209181
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2002, PostgreSQL Global Development Group
|
* Copyright (c) 2002, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $Id: pg_cast.h,v 1.3 2002/09/04 20:31:37 momjian Exp $
|
* $Id: pg_cast.h,v 1.4 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -22,17 +22,38 @@ CATALOG(pg_cast)
|
|||||||
{
|
{
|
||||||
Oid castsource; /* source datatype for cast */
|
Oid castsource; /* source datatype for cast */
|
||||||
Oid casttarget; /* destination datatype for cast */
|
Oid casttarget; /* destination datatype for cast */
|
||||||
Oid castfunc; /* 0 = binary compatible */
|
Oid castfunc; /* cast function; 0 = binary coercible */
|
||||||
bool castimplicit; /* allow implicit casting? */
|
char castcontext; /* contexts in which cast can be used */
|
||||||
} FormData_pg_cast;
|
} FormData_pg_cast;
|
||||||
|
|
||||||
typedef FormData_pg_cast *Form_pg_cast;
|
typedef FormData_pg_cast *Form_pg_cast;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The allowable values for pg_cast.castcontext are specified by this enum.
|
||||||
|
* Since castcontext is stored as a "char", we use ASCII codes for human
|
||||||
|
* convenience in reading the table. Note that internally to the backend,
|
||||||
|
* these values are converted to the CoercionContext enum (see primnodes.h),
|
||||||
|
* which is defined to sort in a convenient order; the ASCII codes don't
|
||||||
|
* have to sort in any special order.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum CoercionCodes
|
||||||
|
{
|
||||||
|
COERCION_CODE_IMPLICIT = 'i', /* coercion in context of expression */
|
||||||
|
COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */
|
||||||
|
COERCION_CODE_EXPLICIT = 'e' /* explicit cast operation */
|
||||||
|
} CoercionCodes;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* compiler constants for pg_cast
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
#define Natts_pg_cast 4
|
#define Natts_pg_cast 4
|
||||||
#define Anum_pg_cast_castsource 1
|
#define Anum_pg_cast_castsource 1
|
||||||
#define Anum_pg_cast_casttarget 2
|
#define Anum_pg_cast_casttarget 2
|
||||||
#define Anum_pg_cast_castfunc 3
|
#define Anum_pg_cast_castfunc 3
|
||||||
#define Anum_pg_cast_castimplicit 4
|
#define Anum_pg_cast_castcontext 4
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initial contents of pg_cast
|
* initial contents of pg_cast
|
||||||
@ -40,197 +61,216 @@ typedef FormData_pg_cast *Form_pg_cast;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* binary compatible casts
|
* Numeric category: implicit casts are allowed in the direction
|
||||||
|
* int2->int4->int8->numeric->float4->float8, while casts in the
|
||||||
|
* reverse direction are assignment-only.
|
||||||
*/
|
*/
|
||||||
DATA(insert ( 25 1042 0 t ));
|
DATA(insert ( 20 21 714 a ));
|
||||||
DATA(insert ( 25 1043 0 t ));
|
DATA(insert ( 20 23 480 a ));
|
||||||
DATA(insert ( 1042 25 0 t ));
|
DATA(insert ( 20 700 652 i ));
|
||||||
DATA(insert ( 1042 1043 0 t ));
|
DATA(insert ( 20 701 482 i ));
|
||||||
DATA(insert ( 1043 25 0 t ));
|
DATA(insert ( 20 1700 1781 i ));
|
||||||
DATA(insert ( 1043 1042 0 t ));
|
DATA(insert ( 21 20 754 i ));
|
||||||
|
DATA(insert ( 21 23 313 i ));
|
||||||
DATA(insert ( 23 24 0 t ));
|
DATA(insert ( 21 700 236 i ));
|
||||||
DATA(insert ( 23 26 0 t ));
|
DATA(insert ( 21 701 235 i ));
|
||||||
DATA(insert ( 23 2202 0 t ));
|
DATA(insert ( 21 1700 1782 i ));
|
||||||
DATA(insert ( 23 2203 0 t ));
|
DATA(insert ( 23 20 481 i ));
|
||||||
DATA(insert ( 23 2204 0 t ));
|
DATA(insert ( 23 21 314 a ));
|
||||||
DATA(insert ( 23 2205 0 t ));
|
DATA(insert ( 23 700 318 i ));
|
||||||
DATA(insert ( 23 2206 0 t ));
|
DATA(insert ( 23 701 316 i ));
|
||||||
DATA(insert ( 24 23 0 t ));
|
DATA(insert ( 23 1700 1740 i ));
|
||||||
DATA(insert ( 24 26 0 t ));
|
DATA(insert ( 700 20 653 a ));
|
||||||
DATA(insert ( 24 2202 0 t ));
|
DATA(insert ( 700 21 238 a ));
|
||||||
DATA(insert ( 24 2203 0 t ));
|
DATA(insert ( 700 23 319 a ));
|
||||||
DATA(insert ( 24 2204 0 t ));
|
DATA(insert ( 700 701 311 i ));
|
||||||
DATA(insert ( 24 2205 0 t ));
|
DATA(insert ( 700 1700 1742 a ));
|
||||||
DATA(insert ( 24 2206 0 t ));
|
DATA(insert ( 701 20 483 a ));
|
||||||
DATA(insert ( 26 23 0 t ));
|
DATA(insert ( 701 21 237 a ));
|
||||||
DATA(insert ( 26 24 0 t ));
|
DATA(insert ( 701 23 317 a ));
|
||||||
DATA(insert ( 26 2202 0 t ));
|
DATA(insert ( 701 700 312 a ));
|
||||||
DATA(insert ( 26 2203 0 t ));
|
DATA(insert ( 701 1700 1743 a ));
|
||||||
DATA(insert ( 26 2204 0 t ));
|
DATA(insert ( 1700 20 1779 a ));
|
||||||
DATA(insert ( 26 2205 0 t ));
|
DATA(insert ( 1700 21 1783 a ));
|
||||||
DATA(insert ( 26 2206 0 t ));
|
DATA(insert ( 1700 23 1744 a ));
|
||||||
DATA(insert ( 2202 23 0 t ));
|
DATA(insert ( 1700 700 1745 i ));
|
||||||
DATA(insert ( 2202 24 0 t ));
|
DATA(insert ( 1700 701 1746 i ));
|
||||||
DATA(insert ( 2202 26 0 t ));
|
|
||||||
DATA(insert ( 2202 2203 0 t ));
|
|
||||||
DATA(insert ( 2202 2204 0 t ));
|
|
||||||
DATA(insert ( 2202 2205 0 t ));
|
|
||||||
DATA(insert ( 2202 2206 0 t ));
|
|
||||||
DATA(insert ( 2203 23 0 t ));
|
|
||||||
DATA(insert ( 2203 24 0 t ));
|
|
||||||
DATA(insert ( 2203 26 0 t ));
|
|
||||||
DATA(insert ( 2203 2202 0 t ));
|
|
||||||
DATA(insert ( 2203 2204 0 t ));
|
|
||||||
DATA(insert ( 2203 2205 0 t ));
|
|
||||||
DATA(insert ( 2203 2206 0 t ));
|
|
||||||
DATA(insert ( 2204 23 0 t ));
|
|
||||||
DATA(insert ( 2204 24 0 t ));
|
|
||||||
DATA(insert ( 2204 26 0 t ));
|
|
||||||
DATA(insert ( 2204 2202 0 t ));
|
|
||||||
DATA(insert ( 2204 2203 0 t ));
|
|
||||||
DATA(insert ( 2204 2205 0 t ));
|
|
||||||
DATA(insert ( 2204 2206 0 t ));
|
|
||||||
DATA(insert ( 2205 23 0 t ));
|
|
||||||
DATA(insert ( 2205 24 0 t ));
|
|
||||||
DATA(insert ( 2205 26 0 t ));
|
|
||||||
DATA(insert ( 2205 2202 0 t ));
|
|
||||||
DATA(insert ( 2205 2203 0 t ));
|
|
||||||
DATA(insert ( 2205 2204 0 t ));
|
|
||||||
DATA(insert ( 2205 2206 0 t ));
|
|
||||||
DATA(insert ( 2206 23 0 t ));
|
|
||||||
DATA(insert ( 2206 24 0 t ));
|
|
||||||
DATA(insert ( 2206 26 0 t ));
|
|
||||||
DATA(insert ( 2206 2202 0 t ));
|
|
||||||
DATA(insert ( 2206 2203 0 t ));
|
|
||||||
DATA(insert ( 2206 2204 0 t ));
|
|
||||||
DATA(insert ( 2206 2205 0 t ));
|
|
||||||
|
|
||||||
DATA(insert ( 23 702 0 t ));
|
|
||||||
DATA(insert ( 702 23 0 t ));
|
|
||||||
|
|
||||||
DATA(insert ( 23 703 0 t ));
|
|
||||||
DATA(insert ( 703 23 0 t ));
|
|
||||||
|
|
||||||
DATA(insert ( 650 869 0 t ));
|
|
||||||
DATA(insert ( 869 650 0 t ));
|
|
||||||
|
|
||||||
DATA(insert ( 1560 1562 0 t ));
|
|
||||||
DATA(insert ( 1562 1560 0 t ));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* regular casts through a function
|
* OID category: allow implicit conversion from any integral type (including
|
||||||
*
|
* int8, to support OID literals > 2G) to OID, as well as assignment coercion
|
||||||
* This list can be obtained from the following query as long as the
|
* from OID to int4 or int8. Similarly for each OID-alias type. Also allow
|
||||||
* naming convention of the cast functions remains the same:
|
* implicit coercions between OID and each OID-alias type, as well as
|
||||||
*
|
* regproc<->regprocedure and regoper<->regoperator. (Other coercions
|
||||||
* select p.proargtypes[0] as source, p.prorettype as target, p.oid as func,
|
* between alias types must pass through OID.)
|
||||||
* p.proimplicit as implicit
|
|
||||||
* from pg_proc p, pg_type t where p.pronargs=1 and p.proname = t.typname
|
|
||||||
* and p.prorettype = t.oid order by 1, 2;
|
|
||||||
*/
|
*/
|
||||||
DATA(insert ( 18 25 946 t ));
|
DATA(insert ( 20 26 1287 i ));
|
||||||
DATA(insert ( 18 1042 860 t ));
|
DATA(insert ( 21 26 313 i ));
|
||||||
DATA(insert ( 19 25 406 t ));
|
DATA(insert ( 23 26 0 i ));
|
||||||
DATA(insert ( 19 1042 408 t ));
|
DATA(insert ( 26 20 1288 a ));
|
||||||
DATA(insert ( 19 1043 1401 t ));
|
DATA(insert ( 26 23 0 a ));
|
||||||
DATA(insert ( 20 21 714 t ));
|
DATA(insert ( 26 24 0 i ));
|
||||||
DATA(insert ( 20 23 480 t ));
|
DATA(insert ( 24 26 0 i ));
|
||||||
DATA(insert ( 20 25 1288 t ));
|
DATA(insert ( 20 24 1287 i ));
|
||||||
DATA(insert ( 20 701 482 t ));
|
DATA(insert ( 21 24 313 i ));
|
||||||
DATA(insert ( 20 1043 1623 f ));
|
DATA(insert ( 23 24 0 i ));
|
||||||
DATA(insert ( 20 1700 1781 t ));
|
DATA(insert ( 24 20 1288 a ));
|
||||||
DATA(insert ( 21 20 754 t ));
|
DATA(insert ( 24 23 0 a ));
|
||||||
DATA(insert ( 21 23 313 t ));
|
DATA(insert ( 24 2202 0 i ));
|
||||||
DATA(insert ( 21 25 113 t ));
|
DATA(insert ( 2202 24 0 i ));
|
||||||
DATA(insert ( 21 700 236 t ));
|
DATA(insert ( 26 2202 0 i ));
|
||||||
DATA(insert ( 21 701 235 t ));
|
DATA(insert ( 2202 26 0 i ));
|
||||||
DATA(insert ( 21 1700 1782 t ));
|
DATA(insert ( 20 2202 1287 i ));
|
||||||
DATA(insert ( 23 20 481 t ));
|
DATA(insert ( 21 2202 313 i ));
|
||||||
DATA(insert ( 23 21 314 t ));
|
DATA(insert ( 23 2202 0 i ));
|
||||||
DATA(insert ( 23 25 112 t ));
|
DATA(insert ( 2202 20 1288 a ));
|
||||||
DATA(insert ( 23 700 318 t ));
|
DATA(insert ( 2202 23 0 a ));
|
||||||
DATA(insert ( 23 701 316 t ));
|
DATA(insert ( 26 2203 0 i ));
|
||||||
DATA(insert ( 23 1043 1619 f ));
|
DATA(insert ( 2203 26 0 i ));
|
||||||
DATA(insert ( 23 1700 1740 t ));
|
DATA(insert ( 20 2203 1287 i ));
|
||||||
DATA(insert ( 25 18 944 t ));
|
DATA(insert ( 21 2203 313 i ));
|
||||||
DATA(insert ( 25 19 407 t ));
|
DATA(insert ( 23 2203 0 i ));
|
||||||
DATA(insert ( 25 20 1289 f ));
|
DATA(insert ( 2203 20 1288 a ));
|
||||||
DATA(insert ( 25 21 818 f ));
|
DATA(insert ( 2203 23 0 a ));
|
||||||
DATA(insert ( 25 23 819 f ));
|
DATA(insert ( 2203 2204 0 i ));
|
||||||
DATA(insert ( 25 26 817 f ));
|
DATA(insert ( 2204 2203 0 i ));
|
||||||
DATA(insert ( 25 650 1714 f ));
|
DATA(insert ( 26 2204 0 i ));
|
||||||
DATA(insert ( 25 700 839 f ));
|
DATA(insert ( 2204 26 0 i ));
|
||||||
DATA(insert ( 25 701 838 f ));
|
DATA(insert ( 20 2204 1287 i ));
|
||||||
DATA(insert ( 25 829 767 f ));
|
DATA(insert ( 21 2204 313 i ));
|
||||||
DATA(insert ( 25 869 1713 f ));
|
DATA(insert ( 23 2204 0 i ));
|
||||||
DATA(insert ( 25 1082 748 f ));
|
DATA(insert ( 2204 20 1288 a ));
|
||||||
DATA(insert ( 25 1083 837 f ));
|
DATA(insert ( 2204 23 0 a ));
|
||||||
DATA(insert ( 25 1114 2022 f ));
|
DATA(insert ( 26 2205 0 i ));
|
||||||
DATA(insert ( 25 1184 1191 f ));
|
DATA(insert ( 2205 26 0 i ));
|
||||||
DATA(insert ( 25 1186 1263 f ));
|
DATA(insert ( 20 2205 1287 i ));
|
||||||
DATA(insert ( 25 1266 938 f ));
|
DATA(insert ( 21 2205 313 i ));
|
||||||
DATA(insert ( 26 25 114 t ));
|
DATA(insert ( 23 2205 0 i ));
|
||||||
DATA(insert ( 601 600 1532 f ));
|
DATA(insert ( 2205 20 1288 a ));
|
||||||
DATA(insert ( 602 600 1533 f ));
|
DATA(insert ( 2205 23 0 a ));
|
||||||
DATA(insert ( 602 604 1449 f ));
|
DATA(insert ( 26 2206 0 i ));
|
||||||
DATA(insert ( 603 600 1534 f ));
|
DATA(insert ( 2206 26 0 i ));
|
||||||
DATA(insert ( 603 601 1541 f ));
|
DATA(insert ( 20 2206 1287 i ));
|
||||||
DATA(insert ( 603 604 1448 f ));
|
DATA(insert ( 21 2206 313 i ));
|
||||||
DATA(insert ( 603 718 1479 f ));
|
DATA(insert ( 23 2206 0 i ));
|
||||||
DATA(insert ( 604 600 1540 f ));
|
DATA(insert ( 2206 20 1288 a ));
|
||||||
DATA(insert ( 604 602 1447 f ));
|
DATA(insert ( 2206 23 0 a ));
|
||||||
DATA(insert ( 604 603 1446 f ));
|
|
||||||
DATA(insert ( 604 718 1474 f ));
|
/*
|
||||||
DATA(insert ( 700 21 238 f ));
|
* String category: this needs to be tightened up
|
||||||
DATA(insert ( 700 23 319 f ));
|
*/
|
||||||
DATA(insert ( 700 25 841 t ));
|
DATA(insert ( 25 1042 0 i ));
|
||||||
DATA(insert ( 700 701 311 t ));
|
DATA(insert ( 25 1043 0 i ));
|
||||||
DATA(insert ( 700 1700 1742 t ));
|
DATA(insert ( 1042 25 0 i ));
|
||||||
DATA(insert ( 701 20 483 t ));
|
DATA(insert ( 1042 1043 0 i ));
|
||||||
DATA(insert ( 701 21 237 f ));
|
DATA(insert ( 1043 25 0 i ));
|
||||||
DATA(insert ( 701 23 317 f ));
|
DATA(insert ( 1043 1042 0 i ));
|
||||||
DATA(insert ( 701 25 840 t ));
|
DATA(insert ( 18 25 946 i ));
|
||||||
DATA(insert ( 701 700 312 t ));
|
DATA(insert ( 18 1042 860 i ));
|
||||||
DATA(insert ( 701 1700 1743 t ));
|
DATA(insert ( 19 25 406 i ));
|
||||||
DATA(insert ( 702 1082 1179 f ));
|
DATA(insert ( 19 1042 408 i ));
|
||||||
DATA(insert ( 702 1083 1364 f ));
|
DATA(insert ( 19 1043 1401 i ));
|
||||||
DATA(insert ( 702 1114 2023 t ));
|
DATA(insert ( 25 18 944 a ));
|
||||||
DATA(insert ( 702 1184 1173 t ));
|
DATA(insert ( 25 19 407 i ));
|
||||||
DATA(insert ( 703 1186 1177 t ));
|
DATA(insert ( 1042 19 409 i ));
|
||||||
DATA(insert ( 718 600 1416 f ));
|
DATA(insert ( 1043 19 1400 i ));
|
||||||
DATA(insert ( 718 603 1480 f ));
|
|
||||||
DATA(insert ( 718 604 1544 f ));
|
/*
|
||||||
DATA(insert ( 829 25 752 f ));
|
* Datetime category
|
||||||
DATA(insert ( 869 25 730 f ));
|
*/
|
||||||
DATA(insert ( 1042 19 409 t ));
|
DATA(insert ( 702 1082 1179 a ));
|
||||||
DATA(insert ( 1043 19 1400 t ));
|
DATA(insert ( 702 1083 1364 a ));
|
||||||
DATA(insert ( 1082 25 749 t ));
|
DATA(insert ( 702 1114 2023 i ));
|
||||||
DATA(insert ( 1082 1114 2024 t ));
|
DATA(insert ( 702 1184 1173 i ));
|
||||||
DATA(insert ( 1082 1184 1174 t ));
|
DATA(insert ( 703 1186 1177 i ));
|
||||||
DATA(insert ( 1083 25 948 t ));
|
DATA(insert ( 1082 1114 2024 i ));
|
||||||
DATA(insert ( 1083 1186 1370 t ));
|
DATA(insert ( 1082 1184 1174 i ));
|
||||||
DATA(insert ( 1083 1266 2047 t ));
|
DATA(insert ( 1083 1186 1370 i ));
|
||||||
DATA(insert ( 1114 25 2034 t ));
|
DATA(insert ( 1083 1266 2047 i ));
|
||||||
DATA(insert ( 1114 702 2030 f ));
|
DATA(insert ( 1114 702 2030 a ));
|
||||||
DATA(insert ( 1114 1082 2029 f ));
|
DATA(insert ( 1114 1082 2029 a ));
|
||||||
DATA(insert ( 1114 1083 1316 f ));
|
DATA(insert ( 1114 1083 1316 a ));
|
||||||
DATA(insert ( 1114 1184 2028 t ));
|
DATA(insert ( 1114 1184 2028 i ));
|
||||||
DATA(insert ( 1184 25 1192 t ));
|
DATA(insert ( 1184 702 1180 a ));
|
||||||
DATA(insert ( 1184 702 1180 f ));
|
DATA(insert ( 1184 1082 1178 a ));
|
||||||
DATA(insert ( 1184 1082 1178 f ));
|
DATA(insert ( 1184 1083 2019 a ));
|
||||||
DATA(insert ( 1184 1083 2019 f ));
|
DATA(insert ( 1184 1114 2027 a ));
|
||||||
DATA(insert ( 1184 1114 2027 t ));
|
DATA(insert ( 1184 1266 1388 a ));
|
||||||
DATA(insert ( 1184 1266 1388 f ));
|
DATA(insert ( 1186 703 1194 a ));
|
||||||
DATA(insert ( 1186 25 1193 t ));
|
DATA(insert ( 1186 1083 1419 a ));
|
||||||
DATA(insert ( 1186 703 1194 f ));
|
DATA(insert ( 1266 1083 2046 a ));
|
||||||
DATA(insert ( 1186 1083 1419 f ));
|
/* Cross-category casts between int4 and abstime, reltime */
|
||||||
DATA(insert ( 1266 25 939 t ));
|
DATA(insert ( 23 702 0 e ));
|
||||||
DATA(insert ( 1266 1083 2046 t ));
|
DATA(insert ( 702 23 0 e ));
|
||||||
DATA(insert ( 1700 20 1779 f ));
|
DATA(insert ( 23 703 0 e ));
|
||||||
DATA(insert ( 1700 21 1783 f ));
|
DATA(insert ( 703 23 0 e ));
|
||||||
DATA(insert ( 1700 23 1744 f ));
|
|
||||||
DATA(insert ( 1700 700 1745 f ));
|
/*
|
||||||
DATA(insert ( 1700 701 1746 f ));
|
* Geometric category
|
||||||
|
*/
|
||||||
|
DATA(insert ( 601 600 1532 e ));
|
||||||
|
DATA(insert ( 602 600 1533 e ));
|
||||||
|
DATA(insert ( 602 604 1449 a ));
|
||||||
|
DATA(insert ( 603 600 1534 e ));
|
||||||
|
DATA(insert ( 603 601 1541 e ));
|
||||||
|
DATA(insert ( 603 604 1448 a ));
|
||||||
|
DATA(insert ( 603 718 1479 e ));
|
||||||
|
DATA(insert ( 604 600 1540 e ));
|
||||||
|
DATA(insert ( 604 602 1447 a ));
|
||||||
|
DATA(insert ( 604 603 1446 e ));
|
||||||
|
DATA(insert ( 604 718 1474 e ));
|
||||||
|
DATA(insert ( 718 600 1416 e ));
|
||||||
|
DATA(insert ( 718 603 1480 e ));
|
||||||
|
DATA(insert ( 718 604 1544 e ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INET category
|
||||||
|
*/
|
||||||
|
DATA(insert ( 650 869 0 i ));
|
||||||
|
DATA(insert ( 869 650 0 i ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BitString category
|
||||||
|
*/
|
||||||
|
DATA(insert ( 1560 1562 0 i ));
|
||||||
|
DATA(insert ( 1562 1560 0 i ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cross-category casts to and from TEXT
|
||||||
|
*
|
||||||
|
* For historical reasons, most casts to TEXT are implicit. This is BAD
|
||||||
|
* and should be reined in.
|
||||||
|
*/
|
||||||
|
DATA(insert ( 20 25 1289 i ));
|
||||||
|
DATA(insert ( 25 20 1290 e ));
|
||||||
|
DATA(insert ( 21 25 113 i ));
|
||||||
|
DATA(insert ( 25 21 818 e ));
|
||||||
|
DATA(insert ( 23 25 112 i ));
|
||||||
|
DATA(insert ( 25 23 819 e ));
|
||||||
|
DATA(insert ( 26 25 114 i ));
|
||||||
|
DATA(insert ( 25 26 817 e ));
|
||||||
|
DATA(insert ( 25 650 1714 e ));
|
||||||
|
DATA(insert ( 700 25 841 i ));
|
||||||
|
DATA(insert ( 25 700 839 e ));
|
||||||
|
DATA(insert ( 701 25 840 i ));
|
||||||
|
DATA(insert ( 25 701 838 e ));
|
||||||
|
DATA(insert ( 829 25 752 e ));
|
||||||
|
DATA(insert ( 25 829 767 e ));
|
||||||
|
DATA(insert ( 869 25 730 e ));
|
||||||
|
DATA(insert ( 25 869 1713 e ));
|
||||||
|
DATA(insert ( 1082 25 749 i ));
|
||||||
|
DATA(insert ( 25 1082 748 e ));
|
||||||
|
DATA(insert ( 1083 25 948 i ));
|
||||||
|
DATA(insert ( 25 1083 837 e ));
|
||||||
|
DATA(insert ( 1114 25 2034 i ));
|
||||||
|
DATA(insert ( 25 1114 2022 e ));
|
||||||
|
DATA(insert ( 1184 25 1192 i ));
|
||||||
|
DATA(insert ( 25 1184 1191 e ));
|
||||||
|
DATA(insert ( 1186 25 1193 i ));
|
||||||
|
DATA(insert ( 25 1186 1263 e ));
|
||||||
|
DATA(insert ( 1266 25 939 i ));
|
||||||
|
DATA(insert ( 25 1266 938 e ));
|
||||||
|
DATA(insert ( 1700 25 1688 i ));
|
||||||
|
DATA(insert ( 25 1700 1686 e ));
|
||||||
|
|
||||||
#endif /* PG_CAST_H */
|
#endif /* PG_CAST_H */
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: pg_operator.h,v 1.109 2002/09/04 20:31:37 momjian Exp $
|
* $Id: pg_operator.h,v 1.110 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -526,10 +526,6 @@ DATA(insert OID = 1133 ( ">" PGNSP PGUID b f 701 700 16 1122 1134 0 0 0 0 f
|
|||||||
DATA(insert OID = 1134 ( "<=" PGNSP PGUID b f 701 700 16 1125 1133 0 0 0 0 float84le scalarltsel scalarltjoinsel ));
|
DATA(insert OID = 1134 ( "<=" PGNSP PGUID b f 701 700 16 1125 1133 0 0 0 0 float84le scalarltsel scalarltjoinsel ));
|
||||||
DATA(insert OID = 1135 ( ">=" PGNSP PGUID b f 701 700 16 1124 1132 0 0 0 0 float84ge scalargtsel scalargtjoinsel ));
|
DATA(insert OID = 1135 ( ">=" PGNSP PGUID b f 701 700 16 1124 1132 0 0 0 0 float84ge scalargtsel scalargtjoinsel ));
|
||||||
|
|
||||||
/* int4 vs oid equality --- use oid (unsigned) comparison */
|
|
||||||
DATA(insert OID = 1136 ( "=" PGNSP PGUID b t 23 26 16 1137 1656 0 0 0 0 oideq eqsel eqjoinsel ));
|
|
||||||
DATA(insert OID = 1137 ( "=" PGNSP PGUID b t 26 23 16 1136 1661 0 0 0 0 oideq eqsel eqjoinsel ));
|
|
||||||
|
|
||||||
DATA(insert OID = 1158 ( "!" PGNSP PGUID r f 21 0 23 0 0 0 0 0 0 int2fac - - ));
|
DATA(insert OID = 1158 ( "!" PGNSP PGUID r f 21 0 23 0 0 0 0 0 0 int2fac - - ));
|
||||||
DATA(insert OID = 1175 ( "!!" PGNSP PGUID l f 0 21 23 0 0 0 0 0 0 int2fac - - ));
|
DATA(insert OID = 1175 ( "!!" PGNSP PGUID l f 0 21 23 0 0 0 0 0 0 int2fac - - ));
|
||||||
|
|
||||||
@ -723,17 +719,13 @@ DATA(insert OID = 1631 ( "~~*" PGNSP PGUID b f 1043 25 16 0 1632 0 0 0 0 tex
|
|||||||
#define OID_VARCHAR_ICLIKE_OP 1631
|
#define OID_VARCHAR_ICLIKE_OP 1631
|
||||||
DATA(insert OID = 1632 ( "!~~*" PGNSP PGUID b f 1043 25 16 0 1631 0 0 0 0 texticnlike icnlikesel icnlikejoinsel ));
|
DATA(insert OID = 1632 ( "!~~*" PGNSP PGUID b f 1043 25 16 0 1631 0 0 0 0 texticnlike icnlikesel icnlikejoinsel ));
|
||||||
|
|
||||||
/* int4 vs oid comparisons --- use oid (unsigned) comparison */
|
/* regproc comparisons --- use oid (unsigned) comparison */
|
||||||
DATA(insert OID = 1656 ( "<>" PGNSP PGUID b f 23 26 16 1661 1136 0 0 0 0 oidne neqsel neqjoinsel ));
|
DATA(insert OID = 1656 ( "=" PGNSP PGUID b t 24 24 16 1656 1657 1658 1658 1658 1659 oideq eqsel eqjoinsel ));
|
||||||
DATA(insert OID = 1657 ( "<" PGNSP PGUID b f 23 26 16 1663 1660 0 0 0 0 oidlt scalarltsel scalarltjoinsel ));
|
DATA(insert OID = 1657 ( "<>" PGNSP PGUID b f 24 24 16 1657 1656 0 0 0 0 oidne neqsel neqjoinsel ));
|
||||||
DATA(insert OID = 1658 ( ">" PGNSP PGUID b f 23 26 16 1662 1659 0 0 0 0 oidgt scalargtsel scalargtjoinsel ));
|
DATA(insert OID = 1658 ( "<" PGNSP PGUID b f 24 24 16 1659 1661 0 0 0 0 oidlt scalarltsel scalarltjoinsel ));
|
||||||
DATA(insert OID = 1659 ( "<=" PGNSP PGUID b f 23 26 16 1665 1658 0 0 0 0 oidle scalarltsel scalarltjoinsel ));
|
DATA(insert OID = 1659 ( ">" PGNSP PGUID b f 24 24 16 1658 1660 0 0 0 0 oidgt scalargtsel scalargtjoinsel ));
|
||||||
DATA(insert OID = 1660 ( ">=" PGNSP PGUID b f 23 26 16 1664 1657 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
|
DATA(insert OID = 1660 ( "<=" PGNSP PGUID b f 24 24 16 1661 1659 0 0 0 0 oidle scalarltsel scalarltjoinsel ));
|
||||||
DATA(insert OID = 1661 ( "<>" PGNSP PGUID b f 26 23 16 1656 1137 0 0 0 0 oidne neqsel neqjoinsel ));
|
DATA(insert OID = 1661 ( ">=" PGNSP PGUID b f 24 24 16 1660 1658 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
|
||||||
DATA(insert OID = 1662 ( "<" PGNSP PGUID b f 26 23 16 1658 1665 0 0 0 0 oidlt scalarltsel scalarltjoinsel ));
|
|
||||||
DATA(insert OID = 1663 ( ">" PGNSP PGUID b f 26 23 16 1657 1664 0 0 0 0 oidgt scalargtsel scalargtjoinsel ));
|
|
||||||
DATA(insert OID = 1664 ( "<=" PGNSP PGUID b f 26 23 16 1660 1663 0 0 0 0 oidle scalarltsel scalarltjoinsel ));
|
|
||||||
DATA(insert OID = 1665 ( ">=" PGNSP PGUID b f 26 23 16 1659 1662 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
|
|
||||||
|
|
||||||
/* NUMERIC type - OID's 1700-1799 */
|
/* NUMERIC type - OID's 1700-1799 */
|
||||||
DATA(insert OID = 1751 ( "-" PGNSP PGUID l f 0 1700 1700 0 0 0 0 0 0 numeric_uminus - - ));
|
DATA(insert OID = 1751 ( "-" PGNSP PGUID l f 0 1700 1700 0 0 0 0 0 0 numeric_uminus - - ));
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: pg_proc.h,v 1.271 2002/09/12 00:21:24 momjian Exp $
|
* $Id: pg_proc.h,v 1.272 2002/09/18 21:35:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
@ -886,15 +886,20 @@ DESCR("convert int8 to float8");
|
|||||||
DATA(insert OID = 483 ( int8 PGNSP PGUID 12 f f t f i 1 20 "701" dtoi8 - _null_ ));
|
DATA(insert OID = 483 ( int8 PGNSP PGUID 12 f f t f i 1 20 "701" dtoi8 - _null_ ));
|
||||||
DESCR("convert float8 to int8");
|
DESCR("convert float8 to int8");
|
||||||
|
|
||||||
|
/* OIDS 500 - 599 */
|
||||||
|
|
||||||
|
/* OIDS 600 - 699 */
|
||||||
|
|
||||||
|
DATA(insert OID = 652 ( float4 PGNSP PGUID 12 f f t f i 1 700 "20" i8tof - _null_ ));
|
||||||
|
DESCR("convert int8 to float4");
|
||||||
|
DATA(insert OID = 653 ( int8 PGNSP PGUID 12 f f t f i 1 20 "700" ftoi8 - _null_ ));
|
||||||
|
DESCR("convert float4 to int8");
|
||||||
|
|
||||||
DATA(insert OID = 714 ( int2 PGNSP PGUID 12 f f t f i 1 21 "20" int82 - _null_ ));
|
DATA(insert OID = 714 ( int2 PGNSP PGUID 12 f f t f i 1 21 "20" int82 - _null_ ));
|
||||||
DESCR("convert int8 to int2");
|
DESCR("convert int8 to int2");
|
||||||
DATA(insert OID = 754 ( int8 PGNSP PGUID 12 f f t f i 1 20 "21" int28 - _null_ ));
|
DATA(insert OID = 754 ( int8 PGNSP PGUID 12 f f t f i 1 20 "21" int28 - _null_ ));
|
||||||
DESCR("convert int2 to int8");
|
DESCR("convert int2 to int8");
|
||||||
|
|
||||||
/* OIDS 500 - 599 */
|
|
||||||
|
|
||||||
/* OIDS 600 - 699 */
|
|
||||||
|
|
||||||
DATA(insert OID = 1285 ( int4notin PGNSP PGUID 12 f f t f s 2 16 "23 25" int4notin - _null_ ));
|
DATA(insert OID = 1285 ( int4notin PGNSP PGUID 12 f f t f s 2 16 "23 25" int4notin - _null_ ));
|
||||||
DESCR("not in");
|
DESCR("not in");
|
||||||
DATA(insert OID = 1286 ( oidnotin PGNSP PGUID 12 f f t f s 2 16 "26 25" oidnotin - _null_ ));
|
DATA(insert OID = 1286 ( oidnotin PGNSP PGUID 12 f f t f s 2 16 "26 25" oidnotin - _null_ ));
|
||||||
@ -910,9 +915,9 @@ DESCR("greater-than-or-equal");
|
|||||||
DATA(insert OID = 659 ( namene PGNSP PGUID 12 f f t f i 2 16 "19 19" namene - _null_ ));
|
DATA(insert OID = 659 ( namene PGNSP PGUID 12 f f t f i 2 16 "19 19" namene - _null_ ));
|
||||||
DESCR("not equal");
|
DESCR("not equal");
|
||||||
|
|
||||||
DATA(insert OID = 668 ( bpchar PGNSP PGUID 12 f f t f i 2 1042 "1042 23" bpchar - _null_ ));
|
DATA(insert OID = 668 ( bpchar PGNSP PGUID 12 f f t f i 3 1042 "1042 23 16" bpchar - _null_ ));
|
||||||
DESCR("adjust char() to typmod length");
|
DESCR("adjust char() to typmod length");
|
||||||
DATA(insert OID = 669 ( varchar PGNSP PGUID 12 f f t f i 2 1043 "1043 23" varchar - _null_ ));
|
DATA(insert OID = 669 ( varchar PGNSP PGUID 12 f f t f i 3 1043 "1043 23 16" varchar - _null_ ));
|
||||||
DESCR("adjust varchar() to typmod length");
|
DESCR("adjust varchar() to typmod length");
|
||||||
|
|
||||||
DATA(insert OID = 676 ( mktinterval PGNSP PGUID 12 f f t f i 2 704 "702 702" mktinterval - _null_ ));
|
DATA(insert OID = 676 ( mktinterval PGNSP PGUID 12 f f t f i 2 704 "702 702" mktinterval - _null_ ));
|
||||||
@ -1374,7 +1379,7 @@ DATA(insert OID = 1141 ( date_pli PGNSP PGUID 12 f f t f i 2 1082 "1082 23"
|
|||||||
DESCR("add");
|
DESCR("add");
|
||||||
DATA(insert OID = 1142 ( date_mii PGNSP PGUID 12 f f t f i 2 1082 "1082 23" date_mii - _null_ ));
|
DATA(insert OID = 1142 ( date_mii PGNSP PGUID 12 f f t f i 2 1082 "1082 23" date_mii - _null_ ));
|
||||||
DESCR("subtract");
|
DESCR("subtract");
|
||||||
DATA(insert OID = 1143 ( time_in PGNSP PGUID 12 f f t f s 1 1083 "2275" time_in - _null_ ));
|
DATA(insert OID = 1143 ( time_in PGNSP PGUID 12 f f t f s 3 1083 "2275 26 23" time_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1144 ( time_out PGNSP PGUID 12 f f t f i 1 2275 "1083" time_out - _null_ ));
|
DATA(insert OID = 1144 ( time_out PGNSP PGUID 12 f f t f i 1 2275 "1083" time_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -1390,7 +1395,7 @@ DESCR("multiply");
|
|||||||
DATA(insert OID = 1149 ( circle_div_pt PGNSP PGUID 12 f f t f i 2 718 "718 600" circle_div_pt - _null_ ));
|
DATA(insert OID = 1149 ( circle_div_pt PGNSP PGUID 12 f f t f i 2 718 "718 600" circle_div_pt - _null_ ));
|
||||||
DESCR("divide");
|
DESCR("divide");
|
||||||
|
|
||||||
DATA(insert OID = 1150 ( timestamptz_in PGNSP PGUID 12 f f t f s 1 1184 "2275" timestamptz_in - _null_ ));
|
DATA(insert OID = 1150 ( timestamptz_in PGNSP PGUID 12 f f t f s 3 1184 "2275 26 23" timestamptz_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1151 ( timestamptz_out PGNSP PGUID 12 f f t f s 1 2275 "1184" timestamptz_out - _null_ ));
|
DATA(insert OID = 1151 ( timestamptz_out PGNSP PGUID 12 f f t f s 1 2275 "1184" timestamptz_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -1409,7 +1414,7 @@ DESCR("greater-than");
|
|||||||
DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f f t f s 2 1114 "25 1184" timestamptz_zone - _null_ ));
|
DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f f t f s 2 1114 "25 1184" timestamptz_zone - _null_ ));
|
||||||
DESCR("timestamp at a specified time zone");
|
DESCR("timestamp at a specified time zone");
|
||||||
|
|
||||||
DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f f t f s 1 1186 "2275" interval_in - _null_ ));
|
DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f f t f s 3 1186 "2275 26 23" interval_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1161 ( interval_out PGNSP PGUID 12 f f t f i 1 2275 "1186" interval_out - _null_ ));
|
DATA(insert OID = 1161 ( interval_out PGNSP PGUID 12 f f t f i 1 2275 "1186" interval_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -1539,15 +1544,18 @@ DESCR("multiply");
|
|||||||
DATA(insert OID = 1281 ( int48div PGNSP PGUID 12 f f t f i 2 20 "23 20" int48div - _null_ ));
|
DATA(insert OID = 1281 ( int48div PGNSP PGUID 12 f f t f i 2 20 "23 20" int48div - _null_ ));
|
||||||
DESCR("divide");
|
DESCR("divide");
|
||||||
|
|
||||||
DATA(insert OID = 1288 ( text PGNSP PGUID 12 f f t f i 1 25 "20" int8_text - _null_ ));
|
DATA(insert OID = 1287 ( oid PGNSP PGUID 12 f f t f i 1 26 "20" i8tooid - _null_ ));
|
||||||
|
DESCR("convert int8 to oid");
|
||||||
|
DATA(insert OID = 1288 ( int8 PGNSP PGUID 12 f f t f i 1 20 "26" oidtoi8 - _null_ ));
|
||||||
|
DESCR("convert oid to int8");
|
||||||
|
|
||||||
|
DATA(insert OID = 1289 ( text PGNSP PGUID 12 f f t f i 1 25 "20" int8_text - _null_ ));
|
||||||
DESCR("convert int8 to text");
|
DESCR("convert int8 to text");
|
||||||
DATA(insert OID = 1289 ( int8 PGNSP PGUID 12 f f t f i 1 20 "25" text_int8 - _null_ ));
|
DATA(insert OID = 1290 ( int8 PGNSP PGUID 12 f f t f i 1 20 "25" text_int8 - _null_ ));
|
||||||
DESCR("convert text to int8");
|
DESCR("convert text to int8");
|
||||||
|
|
||||||
DATA(insert OID = 1290 ( _bpchar PGNSP PGUID 12 f f t f i 2 1014 "1014 23" _bpchar - _null_ ));
|
DATA(insert OID = 1291 ( array_length_coerce PGNSP PGUID 12 f f t f i 3 2277 "2277 23 16" array_length_coerce - _null_ ));
|
||||||
DESCR("adjust char()[] to typmod length");
|
DESCR("adjust any array to element typmod length");
|
||||||
DATA(insert OID = 1291 ( _varchar PGNSP PGUID 12 f f t f i 2 1015 "1015 23" _varchar - _null_ ));
|
|
||||||
DESCR("adjust varchar()[] to typmod length");
|
|
||||||
|
|
||||||
DATA(insert OID = 1292 ( tideq PGNSP PGUID 12 f f t f i 2 16 "27 27" tideq - _null_ ));
|
DATA(insert OID = 1292 ( tideq PGNSP PGUID 12 f f t f i 2 16 "27 27" tideq - _null_ ));
|
||||||
DESCR("equal");
|
DESCR("equal");
|
||||||
@ -1594,7 +1602,7 @@ DESCR("SQL92 interval comparison");
|
|||||||
DATA(insert OID = 1311 ( overlaps PGNSP PGUID 14 f f f f i 4 16 "1083 1186 1083 1083" "select ($1, ($1 + $2)) overlaps ($3, $4)" - _null_ ));
|
DATA(insert OID = 1311 ( overlaps PGNSP PGUID 14 f f f f i 4 16 "1083 1186 1083 1083" "select ($1, ($1 + $2)) overlaps ($3, $4)" - _null_ ));
|
||||||
DESCR("SQL92 interval comparison");
|
DESCR("SQL92 interval comparison");
|
||||||
|
|
||||||
DATA(insert OID = 1312 ( timestamp_in PGNSP PGUID 12 f f t f s 1 1114 "2275" timestamp_in - _null_ ));
|
DATA(insert OID = 1312 ( timestamp_in PGNSP PGUID 12 f f t f s 3 1114 "2275 26 23" timestamp_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1313 ( timestamp_out PGNSP PGUID 12 f f t f s 1 2275 "1114" timestamp_out - _null_ ));
|
DATA(insert OID = 1313 ( timestamp_out PGNSP PGUID 12 f f t f s 1 2275 "1114" timestamp_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -1644,7 +1652,7 @@ DATA(insert OID = 1349 ( oidvectortypes PGNSP PGUID 12 f f t f s 1 25 "30" oi
|
|||||||
DESCR("print type names of oidvector field");
|
DESCR("print type names of oidvector field");
|
||||||
|
|
||||||
|
|
||||||
DATA(insert OID = 1350 ( timetz_in PGNSP PGUID 12 f f t f s 1 1266 "2275" timetz_in - _null_ ));
|
DATA(insert OID = 1350 ( timetz_in PGNSP PGUID 12 f f t f s 3 1266 "2275 26 23" timetz_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1351 ( timetz_out PGNSP PGUID 12 f f t f i 1 2275 "1266" timetz_out - _null_ ));
|
DATA(insert OID = 1351 ( timetz_out PGNSP PGUID 12 f f t f i 1 2275 "1266" timetz_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -1983,7 +1991,7 @@ DESCR("# points in path");
|
|||||||
DATA(insert OID = 1556 ( npoints PGNSP PGUID 12 f f t f i 1 23 "604" poly_npoints - _null_ ));
|
DATA(insert OID = 1556 ( npoints PGNSP PGUID 12 f f t f i 1 23 "604" poly_npoints - _null_ ));
|
||||||
DESCR("number of points in polygon");
|
DESCR("number of points in polygon");
|
||||||
|
|
||||||
DATA(insert OID = 1564 ( bit_in PGNSP PGUID 12 f f t f i 1 1560 "2275" bit_in - _null_ ));
|
DATA(insert OID = 1564 ( bit_in PGNSP PGUID 12 f f t f i 3 1560 "2275 26 23" bit_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1565 ( bit_out PGNSP PGUID 12 f f t f i 1 2275 "1560" bit_out - _null_ ));
|
DATA(insert OID = 1565 ( bit_out PGNSP PGUID 12 f f t f i 1 2275 "1560" bit_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -2008,7 +2016,7 @@ DESCR("set sequence value");
|
|||||||
DATA(insert OID = 1765 ( setval PGNSP PGUID 12 f f t f v 3 20 "25 20 16" setval_and_iscalled - _null_ ));
|
DATA(insert OID = 1765 ( setval PGNSP PGUID 12 f f t f v 3 20 "25 20 16" setval_and_iscalled - _null_ ));
|
||||||
DESCR("set sequence value and iscalled status");
|
DESCR("set sequence value and iscalled status");
|
||||||
|
|
||||||
DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 f f t f i 1 1562 "2275" varbit_in - _null_ ));
|
DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 f f t f i 3 1562 "2275 26 23" varbit_in - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
DATA(insert OID = 1580 ( varbit_out PGNSP PGUID 12 f f t f i 1 2275 "1562" varbit_out - _null_ ));
|
DATA(insert OID = 1580 ( varbit_out PGNSP PGUID 12 f f t f i 1 2275 "1562" varbit_out - _null_ ));
|
||||||
DESCR("(internal)");
|
DESCR("(internal)");
|
||||||
@ -2060,8 +2068,6 @@ DESCR("PI");
|
|||||||
|
|
||||||
DATA(insert OID = 1618 ( interval_mul PGNSP PGUID 12 f f t f i 2 1186 "1186 701" interval_mul - _null_ ));
|
DATA(insert OID = 1618 ( interval_mul PGNSP PGUID 12 f f t f i 2 1186 "1186 701" interval_mul - _null_ ));
|
||||||
DESCR("multiply interval");
|
DESCR("multiply interval");
|
||||||
DATA(insert OID = 1619 ( varchar PGNSP PGUID 12 f f t f i 1 1043 "23" int4_text - _null_ ));
|
|
||||||
DESCR("convert int4 to varchar");
|
|
||||||
|
|
||||||
DATA(insert OID = 1620 ( ascii PGNSP PGUID 12 f f t f i 1 23 "25" ascii - _null_ ));
|
DATA(insert OID = 1620 ( ascii PGNSP PGUID 12 f f t f i 1 23 "25" ascii - _null_ ));
|
||||||
DESCR("convert first char to int4");
|
DESCR("convert first char to int4");
|
||||||
@ -2070,8 +2076,6 @@ DESCR("convert int4 to char");
|
|||||||
DATA(insert OID = 1622 ( repeat PGNSP PGUID 12 f f t f i 2 25 "25 23" repeat - _null_ ));
|
DATA(insert OID = 1622 ( repeat PGNSP PGUID 12 f f t f i 2 25 "25 23" repeat - _null_ ));
|
||||||
DESCR("replicate string int4 times");
|
DESCR("replicate string int4 times");
|
||||||
|
|
||||||
DATA(insert OID = 1623 ( varchar PGNSP PGUID 12 f f t f i 1 1043 "20" int8_text - _null_ ));
|
|
||||||
DESCR("convert int8 to varchar");
|
|
||||||
DATA(insert OID = 1624 ( mul_d_interval PGNSP PGUID 12 f f t f i 2 1186 "701 1186" mul_d_interval - _null_ ));
|
DATA(insert OID = 1624 ( mul_d_interval PGNSP PGUID 12 f f t f i 2 1186 "701 1186" mul_d_interval - _null_ ));
|
||||||
|
|
||||||
DATA(insert OID = 1633 ( texticlike PGNSP PGUID 12 f f t f i 2 16 "25 25" texticlike - _null_ ));
|
DATA(insert OID = 1633 ( texticlike PGNSP PGUID 12 f f t f i 2 16 "25 25" texticlike - _null_ ));
|
||||||
@ -2133,9 +2137,9 @@ DESCR("replace all occurrences of old_substr with new_substr in string");
|
|||||||
DATA(insert OID = 2088 ( split_part PGNSP PGUID 12 f f t f i 3 25 "25 25 23" split_text - _null_ ));
|
DATA(insert OID = 2088 ( split_part PGNSP PGUID 12 f f t f i 3 25 "25 25 23" split_text - _null_ ));
|
||||||
DESCR("split string by field_sep and return field_num");
|
DESCR("split string by field_sep and return field_num");
|
||||||
DATA(insert OID = 2089 ( to_hex PGNSP PGUID 12 f f t f i 1 25 "23" to_hex32 - _null_ ));
|
DATA(insert OID = 2089 ( to_hex PGNSP PGUID 12 f f t f i 1 25 "23" to_hex32 - _null_ ));
|
||||||
DESCR("convert int32 number to hex");
|
DESCR("convert int4 number to hex");
|
||||||
DATA(insert OID = 2090 ( to_hex PGNSP PGUID 12 f f t f i 1 25 "20" to_hex64 - _null_ ));
|
DATA(insert OID = 2090 ( to_hex PGNSP PGUID 12 f f t f i 1 25 "20" to_hex64 - _null_ ));
|
||||||
DESCR("convert int64 number to hex");
|
DESCR("convert int8 number to hex");
|
||||||
|
|
||||||
/* for character set encoding support */
|
/* for character set encoding support */
|
||||||
|
|
||||||
@ -2250,14 +2254,10 @@ DESCR("int4 to bitstring");
|
|||||||
DATA(insert OID = 1684 ( int4 PGNSP PGUID 12 f f t f i 1 23 "1560" bittoint4 - _null_ ));
|
DATA(insert OID = 1684 ( int4 PGNSP PGUID 12 f f t f i 1 23 "1560" bittoint4 - _null_ ));
|
||||||
DESCR("bitstring to int4");
|
DESCR("bitstring to int4");
|
||||||
|
|
||||||
DATA(insert OID = 1685 ( bit PGNSP PGUID 12 f f t f i 2 1560 "1560 23" bit - _null_ ));
|
DATA(insert OID = 1685 ( bit PGNSP PGUID 12 f f t f i 3 1560 "1560 23 16" bit - _null_ ));
|
||||||
DESCR("adjust bit() to typmod length");
|
DESCR("adjust bit() to typmod length");
|
||||||
DATA(insert OID = 1686 ( _bit PGNSP PGUID 12 f f t f i 2 1561 "1561 23" _bit - _null_ ));
|
DATA(insert OID = 1687 ( varbit PGNSP PGUID 12 f f t f i 3 1562 "1562 23 16" varbit - _null_ ));
|
||||||
DESCR("adjust bit()[] to typmod length");
|
|
||||||
DATA(insert OID = 1687 ( varbit PGNSP PGUID 12 f f t f i 2 1562 "1562 23" varbit - _null_ ));
|
|
||||||
DESCR("adjust varbit() to typmod length");
|
DESCR("adjust varbit() to typmod length");
|
||||||
DATA(insert OID = 1688 ( _varbit PGNSP PGUID 12 f f t f i 2 1563 "1563 23" _varbit - _null_ ));
|
|
||||||
DESCR("adjust varbit()[] to typmod length");
|
|
||||||
|
|
||||||
DATA(insert OID = 1698 ( position PGNSP PGUID 12 f f t f i 2 23 "1560 1560" bitposition - _null_ ));
|
DATA(insert OID = 1698 ( position PGNSP PGUID 12 f f t f i 2 23 "1560 1560" bitposition - _null_ ));
|
||||||
DESCR("return position of sub-bitstring");
|
DESCR("return position of sub-bitstring");
|
||||||
@ -2351,6 +2351,11 @@ DESCR("text to cidr");
|
|||||||
DATA(insert OID = 1715 ( set_masklen PGNSP PGUID 12 f f t f i 2 869 "869 23" inet_set_masklen - _null_ ));
|
DATA(insert OID = 1715 ( set_masklen PGNSP PGUID 12 f f t f i 2 869 "869 23" inet_set_masklen - _null_ ));
|
||||||
DESCR("change the netmask of an inet");
|
DESCR("change the netmask of an inet");
|
||||||
|
|
||||||
|
DATA(insert OID = 1686 ( numeric PGNSP PGUID 12 f f t f i 1 1700 "25" text_numeric - _null_ ));
|
||||||
|
DESCR("(internal)");
|
||||||
|
DATA(insert OID = 1688 ( text PGNSP PGUID 12 f f t f i 1 25 "1700" numeric_text - _null_ ));
|
||||||
|
DESCR("(internal)");
|
||||||
|
|
||||||
DATA(insert OID = 1690 ( time_mi_time PGNSP PGUID 12 f f t f i 2 1186 "1083 1083" time_mi_time - _null_ ));
|
DATA(insert OID = 1690 ( time_mi_time PGNSP PGUID 12 f f t f i 2 1186 "1083 1083" time_mi_time - _null_ ));
|
||||||
DESCR("minus");
|
DESCR("minus");
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: makefuncs.h,v 1.40 2002/09/04 20:31:43 momjian Exp $
|
* $Id: makefuncs.h,v 1.41 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
|
|
||||||
extern A_Expr *makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr);
|
extern A_Expr *makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr);
|
||||||
|
|
||||||
extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
|
extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
|
||||||
@ -52,7 +53,8 @@ extern Const *makeNullConst(Oid consttype);
|
|||||||
|
|
||||||
extern Alias *makeAlias(const char *aliasname, List *colnames);
|
extern Alias *makeAlias(const char *aliasname, List *colnames);
|
||||||
|
|
||||||
extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod);
|
extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod,
|
||||||
|
CoercionForm rformat);
|
||||||
|
|
||||||
extern RangeVar *makeRangeVar(char *schemaname, char *relname);
|
extern RangeVar *makeRangeVar(char *schemaname, char *relname);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.206 2002/09/04 20:31:43 momjian Exp $
|
* $Id: parsenodes.h,v 1.207 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1632,7 +1632,7 @@ typedef struct CreateCastStmt
|
|||||||
TypeName *sourcetype;
|
TypeName *sourcetype;
|
||||||
TypeName *targettype;
|
TypeName *targettype;
|
||||||
FuncWithArgs *func;
|
FuncWithArgs *func;
|
||||||
bool implicit;
|
CoercionContext context;
|
||||||
} CreateCastStmt;
|
} CreateCastStmt;
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: primnodes.h,v 1.67 2002/09/04 20:31:44 momjian Exp $
|
* $Id: primnodes.h,v 1.68 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -139,6 +139,30 @@ typedef struct RangeVar
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CoercionContext - distinguishes the allowed set of type casts
|
||||||
|
*
|
||||||
|
* NB: ordering of the alternatives is significant; later (larger) values
|
||||||
|
* allow more casts than earlier ones.
|
||||||
|
*/
|
||||||
|
typedef enum CoercionContext
|
||||||
|
{
|
||||||
|
COERCION_IMPLICIT, /* coercion in context of expression */
|
||||||
|
COERCION_ASSIGNMENT, /* coercion in context of assignment */
|
||||||
|
COERCION_EXPLICIT /* explicit cast operation */
|
||||||
|
} CoercionContext;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CoercionForm - information showing how to display a function-call node
|
||||||
|
*/
|
||||||
|
typedef enum CoercionForm
|
||||||
|
{
|
||||||
|
COERCE_EXPLICIT_CALL, /* display as a function call */
|
||||||
|
COERCE_EXPLICIT_CAST, /* display as an explicit cast */
|
||||||
|
COERCE_IMPLICIT_CAST, /* implicit cast, so hide it */
|
||||||
|
COERCE_DONTCARE /* special case for pathkeys */
|
||||||
|
} CoercionForm;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expr
|
* Expr
|
||||||
*/
|
*/
|
||||||
@ -194,6 +218,7 @@ typedef struct Func
|
|||||||
Oid funcid; /* PG_PROC OID of the function */
|
Oid funcid; /* PG_PROC OID of the function */
|
||||||
Oid funcresulttype; /* PG_TYPE OID of result value */
|
Oid funcresulttype; /* PG_TYPE OID of result value */
|
||||||
bool funcretset; /* true if function returns set */
|
bool funcretset; /* true if function returns set */
|
||||||
|
CoercionForm funcformat; /* how to display this function call */
|
||||||
FunctionCachePtr func_fcache; /* runtime state, or NULL */
|
FunctionCachePtr func_fcache; /* runtime state, or NULL */
|
||||||
} Func;
|
} Func;
|
||||||
|
|
||||||
@ -460,6 +485,7 @@ typedef struct RelabelType
|
|||||||
Node *arg; /* input expression */
|
Node *arg; /* input expression */
|
||||||
Oid resulttype; /* output type of coercion expression */
|
Oid resulttype; /* output type of coercion expression */
|
||||||
int32 resulttypmod; /* output typmod (usually -1) */
|
int32 resulttypmod; /* output typmod (usually -1) */
|
||||||
|
CoercionForm relabelformat; /* how to display this node */
|
||||||
} RelabelType;
|
} RelabelType;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* parse_coerce.h
|
* parse_coerce.h
|
||||||
*
|
|
||||||
* Routines for type coercion.
|
* Routines for type coercion.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parse_coerce.h,v 1.46 2002/09/04 20:31:45 momjian Exp $
|
* $Id: parse_coerce.h,v 1.47 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,29 +29,31 @@ typedef enum CATEGORY
|
|||||||
TIMESPAN_TYPE,
|
TIMESPAN_TYPE,
|
||||||
GEOMETRIC_TYPE,
|
GEOMETRIC_TYPE,
|
||||||
NETWORK_TYPE,
|
NETWORK_TYPE,
|
||||||
USER_TYPE,
|
USER_TYPE
|
||||||
MIXED_TYPE
|
|
||||||
} CATEGORY;
|
} CATEGORY;
|
||||||
|
|
||||||
|
|
||||||
extern bool IsBinaryCompatible(Oid type1, Oid type2);
|
extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
|
||||||
extern bool IsPreferredType(CATEGORY category, Oid type);
|
extern bool IsPreferredType(CATEGORY category, Oid type);
|
||||||
extern CATEGORY TypeCategory(Oid type);
|
extern CATEGORY TypeCategory(Oid type);
|
||||||
|
|
||||||
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
extern Node *coerce_to_target_type(Node *expr, Oid exprtype,
|
||||||
bool isExplicit);
|
Oid targettype, int32 targettypmod,
|
||||||
extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
CoercionContext ccontext,
|
||||||
Oid targetTypeId, int32 atttypmod, bool isExplicit);
|
CoercionForm cformat);
|
||||||
extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
|
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
|
||||||
Oid targetTypeId, int32 atttypmod);
|
CoercionContext ccontext);
|
||||||
extern Node *coerce_type_constraints(ParseState *pstate, Node *arg,
|
extern Node *coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||||
Oid typeId, bool applyTypmod);
|
CoercionContext ccontext, CoercionForm cformat);
|
||||||
|
extern Node *coerce_type_constraints(Node *arg, Oid typeId,
|
||||||
|
CoercionForm cformat);
|
||||||
|
|
||||||
extern Node *coerce_to_boolean(Node *node, const char *constructName);
|
extern Node *coerce_to_boolean(Node *node, const char *constructName);
|
||||||
|
|
||||||
extern Oid select_common_type(List *typeids, const char *context);
|
extern Oid select_common_type(List *typeids, const char *context);
|
||||||
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
|
extern Node *coerce_to_common_type(Node *node, Oid targetTypeId,
|
||||||
Oid targetTypeId,
|
|
||||||
const char *context);
|
const char *context);
|
||||||
|
|
||||||
|
extern Oid find_typmod_coercion_function(Oid typeId, int *nargs);
|
||||||
|
|
||||||
#endif /* PARSE_COERCE_H */
|
#endif /* PARSE_COERCE_H */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parse_node.h,v 1.31 2002/06/20 20:29:51 momjian Exp $
|
* $Id: parse_node.h,v 1.32 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -57,6 +57,7 @@ extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
|
|||||||
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
|
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
|
||||||
Node *arrayBase,
|
Node *arrayBase,
|
||||||
Oid arrayType,
|
Oid arrayType,
|
||||||
|
int32 arrayTypMod,
|
||||||
List *indirection,
|
List *indirection,
|
||||||
bool forceSlice,
|
bool forceSlice,
|
||||||
Node *assignFrom);
|
Node *assignFrom);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* parse_target.h
|
* parse_target.h
|
||||||
*
|
* handle target lists
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parse_target.h,v 1.26 2002/09/04 20:31:45 momjian Exp $
|
* $Id: parse_target.h,v 1.27 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "parser/parse_node.h"
|
#include "parser/parse_node.h"
|
||||||
|
|
||||||
|
|
||||||
extern List *transformTargetList(ParseState *pstate, List *targetlist);
|
extern List *transformTargetList(ParseState *pstate, List *targetlist);
|
||||||
extern TargetEntry *transformTargetEntry(ParseState *pstate,
|
extern TargetEntry *transformTargetEntry(ParseState *pstate,
|
||||||
Node *node, Node *expr,
|
Node *node, Node *expr,
|
||||||
@ -23,9 +24,6 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
|
|||||||
extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
|
extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
|
||||||
char *colname, int attrno,
|
char *colname, int attrno,
|
||||||
List *indirection);
|
List *indirection);
|
||||||
extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr,
|
|
||||||
Oid type_id, Oid attrtype, int32 attrtypmod,
|
|
||||||
bool isExplicit);
|
|
||||||
extern List *checkInsertTargets(ParseState *pstate, List *cols,
|
extern List *checkInsertTargets(ParseState *pstate, List *cols,
|
||||||
List **attrnos);
|
List **attrnos);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: array.h,v 1.34 2002/09/04 20:31:45 momjian Exp $
|
* $Id: array.h,v 1.35 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -82,6 +82,7 @@ typedef struct
|
|||||||
*/
|
*/
|
||||||
extern Datum array_in(PG_FUNCTION_ARGS);
|
extern Datum array_in(PG_FUNCTION_ARGS);
|
||||||
extern Datum array_out(PG_FUNCTION_ARGS);
|
extern Datum array_out(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum array_length_coerce(PG_FUNCTION_ARGS);
|
||||||
extern Datum array_eq(PG_FUNCTION_ARGS);
|
extern Datum array_eq(PG_FUNCTION_ARGS);
|
||||||
extern Datum array_dims(PG_FUNCTION_ARGS);
|
extern Datum array_dims(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: builtins.h,v 1.199 2002/09/04 20:31:45 momjian Exp $
|
* $Id: builtins.h,v 1.200 2002/09/18 21:35:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -422,7 +422,6 @@ extern Datum currtid_byrelname(PG_FUNCTION_ARGS);
|
|||||||
extern Datum bpcharin(PG_FUNCTION_ARGS);
|
extern Datum bpcharin(PG_FUNCTION_ARGS);
|
||||||
extern Datum bpcharout(PG_FUNCTION_ARGS);
|
extern Datum bpcharout(PG_FUNCTION_ARGS);
|
||||||
extern Datum bpchar(PG_FUNCTION_ARGS);
|
extern Datum bpchar(PG_FUNCTION_ARGS);
|
||||||
extern Datum _bpchar(PG_FUNCTION_ARGS);
|
|
||||||
extern Datum char_bpchar(PG_FUNCTION_ARGS);
|
extern Datum char_bpchar(PG_FUNCTION_ARGS);
|
||||||
extern Datum name_bpchar(PG_FUNCTION_ARGS);
|
extern Datum name_bpchar(PG_FUNCTION_ARGS);
|
||||||
extern Datum bpchar_name(PG_FUNCTION_ARGS);
|
extern Datum bpchar_name(PG_FUNCTION_ARGS);
|
||||||
@ -440,7 +439,6 @@ extern Datum hashbpchar(PG_FUNCTION_ARGS);
|
|||||||
extern Datum varcharin(PG_FUNCTION_ARGS);
|
extern Datum varcharin(PG_FUNCTION_ARGS);
|
||||||
extern Datum varcharout(PG_FUNCTION_ARGS);
|
extern Datum varcharout(PG_FUNCTION_ARGS);
|
||||||
extern Datum varchar(PG_FUNCTION_ARGS);
|
extern Datum varchar(PG_FUNCTION_ARGS);
|
||||||
extern Datum _varchar(PG_FUNCTION_ARGS);
|
|
||||||
extern Datum varchareq(PG_FUNCTION_ARGS);
|
extern Datum varchareq(PG_FUNCTION_ARGS);
|
||||||
extern Datum varcharne(PG_FUNCTION_ARGS);
|
extern Datum varcharne(PG_FUNCTION_ARGS);
|
||||||
extern Datum varcharlt(PG_FUNCTION_ARGS);
|
extern Datum varcharlt(PG_FUNCTION_ARGS);
|
||||||
@ -633,6 +631,8 @@ extern Datum numeric_float8(PG_FUNCTION_ARGS);
|
|||||||
extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS);
|
extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS);
|
||||||
extern Datum float4_numeric(PG_FUNCTION_ARGS);
|
extern Datum float4_numeric(PG_FUNCTION_ARGS);
|
||||||
extern Datum numeric_float4(PG_FUNCTION_ARGS);
|
extern Datum numeric_float4(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum text_numeric(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum numeric_text(PG_FUNCTION_ARGS);
|
||||||
extern Datum numeric_accum(PG_FUNCTION_ARGS);
|
extern Datum numeric_accum(PG_FUNCTION_ARGS);
|
||||||
extern Datum int2_accum(PG_FUNCTION_ARGS);
|
extern Datum int2_accum(PG_FUNCTION_ARGS);
|
||||||
extern Datum int4_accum(PG_FUNCTION_ARGS);
|
extern Datum int4_accum(PG_FUNCTION_ARGS);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: int8.h,v 1.34 2002/06/20 20:29:53 momjian Exp $
|
* $Id: int8.h,v 1.35 2002/09/18 21:35:25 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These data types are supported on all 64-bit architectures, and may
|
* These data types are supported on all 64-bit architectures, and may
|
||||||
@ -29,6 +29,8 @@
|
|||||||
#define INT64_FORMAT "%ld"
|
#define INT64_FORMAT "%ld"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern bool scanint8(const char *str, bool errorOK, int64 *result);
|
||||||
|
|
||||||
extern Datum int8in(PG_FUNCTION_ARGS);
|
extern Datum int8in(PG_FUNCTION_ARGS);
|
||||||
extern Datum int8out(PG_FUNCTION_ARGS);
|
extern Datum int8out(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
@ -106,6 +108,12 @@ extern Datum int82(PG_FUNCTION_ARGS);
|
|||||||
extern Datum i8tod(PG_FUNCTION_ARGS);
|
extern Datum i8tod(PG_FUNCTION_ARGS);
|
||||||
extern Datum dtoi8(PG_FUNCTION_ARGS);
|
extern Datum dtoi8(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
extern Datum i8tof(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum ftoi8(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
extern Datum i8tooid(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum oidtoi8(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
extern Datum int8_text(PG_FUNCTION_ARGS);
|
extern Datum int8_text(PG_FUNCTION_ARGS);
|
||||||
extern Datum text_int8(PG_FUNCTION_ARGS);
|
extern Datum text_int8(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: lsyscache.h,v 1.62 2002/09/04 20:31:45 momjian Exp $
|
* $Id: lsyscache.h,v 1.63 2002/09/18 21:35:25 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -58,7 +58,6 @@ extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem);
|
|||||||
extern bool getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
|
extern bool getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
|
||||||
bool *typIsVarlena);
|
bool *typIsVarlena);
|
||||||
extern Oid getBaseType(Oid typid);
|
extern Oid getBaseType(Oid typid);
|
||||||
extern int32 getBaseTypeMod(Oid typid, int32 typmod);
|
|
||||||
extern int32 get_typavgwidth(Oid typid, int32 typmod);
|
extern int32 get_typavgwidth(Oid typid, int32 typmod);
|
||||||
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
|
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
|
||||||
extern bool get_attstatsslot(HeapTuple statstuple,
|
extern bool get_attstatsslot(HeapTuple statstuple,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: varbit.h,v 1.15 2002/08/04 06:33:56 thomas Exp $
|
* $Id: varbit.h,v 1.16 2002/09/18 21:35:25 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -66,9 +66,7 @@ extern Datum bit_out(PG_FUNCTION_ARGS);
|
|||||||
extern Datum varbit_in(PG_FUNCTION_ARGS);
|
extern Datum varbit_in(PG_FUNCTION_ARGS);
|
||||||
extern Datum varbit_out(PG_FUNCTION_ARGS);
|
extern Datum varbit_out(PG_FUNCTION_ARGS);
|
||||||
extern Datum bit(PG_FUNCTION_ARGS);
|
extern Datum bit(PG_FUNCTION_ARGS);
|
||||||
extern Datum _bit(PG_FUNCTION_ARGS);
|
|
||||||
extern Datum varbit(PG_FUNCTION_ARGS);
|
extern Datum varbit(PG_FUNCTION_ARGS);
|
||||||
extern Datum _varbit(PG_FUNCTION_ARGS);
|
|
||||||
extern Datum biteq(PG_FUNCTION_ARGS);
|
extern Datum biteq(PG_FUNCTION_ARGS);
|
||||||
extern Datum bitne(PG_FUNCTION_ARGS);
|
extern Datum bitne(PG_FUNCTION_ARGS);
|
||||||
extern Datum bitlt(PG_FUNCTION_ARGS);
|
extern Datum bitlt(PG_FUNCTION_ARGS);
|
||||||
|
@ -13,10 +13,14 @@ create domain domainvarchar varchar(5);
|
|||||||
create domain domainnumeric numeric(8,2);
|
create domain domainnumeric numeric(8,2);
|
||||||
create domain domainint4 int4;
|
create domain domainint4 int4;
|
||||||
create domain domaintext text;
|
create domain domaintext text;
|
||||||
-- Test coercions
|
-- Test explicit coercions --- these should succeed (and truncate)
|
||||||
SELECT cast('123456' as domainvarchar); -- fail
|
SELECT cast('123456' as domainvarchar);
|
||||||
ERROR: value too long for type character varying(5)
|
domainvarchar
|
||||||
SELECT cast('12345' as domainvarchar); -- pass
|
---------------
|
||||||
|
12345
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cast('12345' as domainvarchar);
|
||||||
domainvarchar
|
domainvarchar
|
||||||
---------------
|
---------------
|
||||||
12345
|
12345
|
||||||
|
@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
|
|||||||
Sat Jan 01 10:00:00 1994
|
Sat Jan 01 10:00:00 1994
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
|
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
|
||||||
ERROR: Bad time external representation '11:00-5'
|
Jan_01_1994_8am
|
||||||
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
|
------------------------------
|
||||||
Jan_01_1994_11am
|
Sat Jan 01 08:00:00 1994 PST
|
||||||
--------------------------
|
(1 row)
|
||||||
Sat Jan 01 11:00:00 1994
|
|
||||||
|
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
|
||||||
|
Jan_01_1994_8am
|
||||||
|
------------------------------
|
||||||
|
Sat Jan 01 08:00:00 1994 PST
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
||||||
@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
|
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
|
||||||
ERROR: Cannot cast type 'time with time zone' to 'interval'
|
ERROR: Cannot cast type time with time zone to interval
|
||||||
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
|
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'
|
ERROR: Cannot cast type interval to time with time zone
|
||||||
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
|
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
|
||||||
23:29:00-08
|
23:29:00-08
|
||||||
-------------
|
-------------
|
||||||
|
@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
|
|||||||
Sat Jan 01 10:00:00 1994
|
Sat Jan 01 10:00:00 1994
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
|
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
|
||||||
ERROR: Bad time external representation '11:00-5'
|
Jan_01_1994_8am
|
||||||
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
|
------------------------------
|
||||||
Jan_01_1994_11am
|
Sat Jan 01 08:00:00 1994 PST
|
||||||
--------------------------
|
(1 row)
|
||||||
Sat Jan 01 11:00:00 1994
|
|
||||||
|
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
|
||||||
|
Jan_01_1994_8am
|
||||||
|
------------------------------
|
||||||
|
Sat Jan 01 08:00:00 1994 PST
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
||||||
@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
|
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
|
||||||
ERROR: Cannot cast type 'time with time zone' to 'interval'
|
ERROR: Cannot cast type time with time zone to interval
|
||||||
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
|
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'
|
ERROR: Cannot cast type interval to time with time zone
|
||||||
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
|
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
|
||||||
23:29:00-08
|
23:29:00-08
|
||||||
-------------
|
-------------
|
||||||
|
@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
|
|||||||
Sat Jan 01 10:00:00 1994
|
Sat Jan 01 10:00:00 1994
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
|
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
|
||||||
ERROR: Bad time external representation '11:00-5'
|
Jan_01_1994_8am
|
||||||
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
|
------------------------------
|
||||||
Jan_01_1994_11am
|
Sat Jan 01 08:00:00 1994 PST
|
||||||
--------------------------
|
(1 row)
|
||||||
Sat Jan 01 11:00:00 1994
|
|
||||||
|
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
|
||||||
|
Jan_01_1994_8am
|
||||||
|
------------------------------
|
||||||
|
Sat Jan 01 08:00:00 1994 PST
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
||||||
@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
|
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
|
||||||
ERROR: Cannot cast type 'time with time zone' to 'interval'
|
ERROR: Cannot cast type time with time zone to interval
|
||||||
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
|
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'
|
ERROR: Cannot cast type interval to time with time zone
|
||||||
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
|
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
|
||||||
23:29:00-08
|
23:29:00-08
|
||||||
-------------
|
-------------
|
||||||
|
@ -202,33 +202,35 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
|
|||||||
|
|
||||||
-- **************** pg_cast ****************
|
-- **************** pg_cast ****************
|
||||||
-- Look for casts from and to the same type. This is not harmful, but
|
-- Look for casts from and to the same type. This is not harmful, but
|
||||||
-- useless.
|
-- useless. Also catch bogus values in pg_cast columns (other than
|
||||||
|
-- cases detected by oidjoins test).
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM pg_cast c
|
FROM pg_cast c
|
||||||
WHERE c.castsource = c.casttarget;
|
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
|
||||||
castsource | casttarget | castfunc | castimplicit
|
OR castcontext NOT IN ('e', 'a', 'i');
|
||||||
------------+------------+----------+--------------
|
castsource | casttarget | castfunc | castcontext
|
||||||
|
------------+------------+----------+-------------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Look for cast functions with incorrect number or type of argument
|
-- Look for cast functions that don't have the right signature. The
|
||||||
-- or return value.
|
-- argument and result types in pg_proc must be the same as, or binary
|
||||||
|
-- compatible with, what it says in pg_cast.
|
||||||
SELECT c.*
|
SELECT c.*
|
||||||
FROM pg_cast c, pg_proc p
|
FROM pg_cast c, pg_proc p
|
||||||
WHERE c.castfunc = p.oid AND
|
WHERE c.castfunc = p.oid AND
|
||||||
(p.pronargs <> 1 OR
|
(p.pronargs <> 1
|
||||||
p.proargtypes[0] <> c.castsource OR
|
OR NOT (c.castsource = p.proargtypes[0] OR
|
||||||
p.prorettype <> c.casttarget);
|
EXISTS (SELECT 1 FROM pg_cast k
|
||||||
castsource | casttarget | castfunc | castimplicit
|
WHERE k.castfunc = 0 AND
|
||||||
------------+------------+----------+--------------
|
k.castsource = c.castsource AND
|
||||||
(0 rows)
|
k.casttarget = p.proargtypes[0]))
|
||||||
|
OR NOT (p.prorettype = c.casttarget OR
|
||||||
-- Look for binary compatible casts that are not implicit. This is
|
EXISTS (SELECT 1 FROM pg_cast k
|
||||||
-- legal, but probably not intended.
|
WHERE k.castfunc = 0 AND
|
||||||
SELECT *
|
k.castsource = p.prorettype AND
|
||||||
FROM pg_cast c
|
k.casttarget = c.casttarget)));
|
||||||
WHERE c.castfunc = 0 AND NOT c.castimplicit;
|
castsource | casttarget | castfunc | castcontext
|
||||||
castsource | casttarget | castfunc | castimplicit
|
------------+------------+----------+-------------
|
||||||
------------+------------+----------+--------------
|
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Look for binary compatible casts that do not have the reverse
|
-- Look for binary compatible casts that do not have the reverse
|
||||||
@ -241,8 +243,8 @@ WHERE c.castfunc = 0 AND
|
|||||||
WHERE k.castfunc = 0 AND
|
WHERE k.castfunc = 0 AND
|
||||||
k.castsource = c.casttarget AND
|
k.castsource = c.casttarget AND
|
||||||
k.casttarget = c.castsource);
|
k.casttarget = c.castsource);
|
||||||
castsource | casttarget | castfunc | castimplicit
|
castsource | casttarget | castfunc | castcontext
|
||||||
------------+------------+----------+--------------
|
------------+------------+----------+-------------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- **************** pg_operator ****************
|
-- **************** pg_operator ****************
|
||||||
@ -414,20 +416,18 @@ WHERE p1.oprlsortop != p1.oprrsortop AND
|
|||||||
-- Hashing only works on simple equality operators "type = sametype",
|
-- Hashing only works on simple equality operators "type = sametype",
|
||||||
-- since the hash itself depends on the bitwise representation of the type.
|
-- since the hash itself depends on the bitwise representation of the type.
|
||||||
-- Check that allegedly hashable operators look like they might be "=".
|
-- Check that allegedly hashable operators look like they might be "=".
|
||||||
-- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
|
-- NOTE: in 7.3, this search finds xideqint4.
|
||||||
-- Until we have some cleaner way of dealing with binary-equivalent types,
|
-- Until we have some cleaner way of dealing with binary-equivalent types,
|
||||||
-- just leave those three tuples in the expected output.
|
-- just leave that tuple in the expected output.
|
||||||
SELECT p1.oid, p1.oprname
|
SELECT p1.oid, p1.oprname
|
||||||
FROM pg_operator AS p1
|
FROM pg_operator AS p1
|
||||||
WHERE p1.oprcanhash AND NOT
|
WHERE p1.oprcanhash AND NOT
|
||||||
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
|
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
|
||||||
p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
|
p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
|
||||||
oid | oprname
|
oid | oprname
|
||||||
------+---------
|
-----+---------
|
||||||
353 | =
|
353 | =
|
||||||
1136 | =
|
(1 row)
|
||||||
1137 | =
|
|
||||||
(3 rows)
|
|
||||||
|
|
||||||
-- In 6.5 we accepted hashable array equality operators when the array element
|
-- In 6.5 we accepted hashable array equality operators when the array element
|
||||||
-- type is hashable. However, what we actually need to make hashjoin work on
|
-- type is hashable. However, what we actually need to make hashjoin work on
|
||||||
|
@ -75,7 +75,7 @@ EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true);
|
|||||||
ERROR: Wrong number of parameters, expected 6 but got 7
|
ERROR: Wrong number of parameters, expected 6 but got 7
|
||||||
-- wrong param types
|
-- wrong param types
|
||||||
EXECUTE q3(5::smallint, 10.5::float, false, 500::oid, 4::bigint, 'bytea');
|
EXECUTE q3(5::smallint, 10.5::float, false, 500::oid, 4::bigint, 'bytea');
|
||||||
ERROR: Parameter $2 of type double precision cannot be coerced into the expected type integer
|
ERROR: Parameter $3 of type boolean cannot be coerced into the expected type double precision
|
||||||
You will need to rewrite or cast the expression
|
You will need to rewrite or cast the expression
|
||||||
-- invalid type
|
-- invalid type
|
||||||
PREPARE q4(nonexistenttype) AS SELECT $1;
|
PREPARE q4(nonexistenttype) AS SELECT $1;
|
||||||
|
@ -1321,10 +1321,10 @@ SELECT tablename, rulename, definition FROM pg_rules
|
|||||||
rtest_nothn1 | rtest_nothn_r2 | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
|
rtest_nothn1 | rtest_nothn_r2 | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
|
||||||
rtest_nothn2 | rtest_nothn_r3 | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);
|
rtest_nothn2 | rtest_nothn_r3 | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);
|
||||||
rtest_nothn2 | rtest_nothn_r4 | CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2 DO INSTEAD NOTHING;
|
rtest_nothn2 | rtest_nothn_r4 | CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2 DO INSTEAD NOTHING;
|
||||||
rtest_order1 | rtest_order_r1 | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 1 - this should run 3rd or 4th'::text);
|
rtest_order1 | rtest_order_r1 | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 1 - this should run 3rd or 4th'::text);
|
||||||
rtest_order1 | rtest_order_r2 | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 2 - this should run 1st'::text);
|
rtest_order1 | rtest_order_r2 | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 2 - this should run 1st'::text);
|
||||||
rtest_order1 | rtest_order_r3 | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 3 - this should run 3rd or 4th'::text);
|
rtest_order1 | rtest_order_r3 | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 3 - this should run 3rd or 4th'::text);
|
||||||
rtest_order1 | rtest_order_r4 | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 4 - this should run 2nd'::text);
|
rtest_order1 | rtest_order_r4 | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 4 - this should run 2nd'::text);
|
||||||
rtest_person | rtest_pers_del | CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person DO DELETE FROM rtest_admin WHERE (rtest_admin.pname = old.pname);
|
rtest_person | rtest_pers_del | CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person DO DELETE FROM rtest_admin WHERE (rtest_admin.pname = old.pname);
|
||||||
rtest_person | rtest_pers_upd | CREATE RULE rtest_pers_upd AS ON UPDATE TO rtest_person DO UPDATE rtest_admin SET pname = new.pname WHERE (rtest_admin.pname = old.pname);
|
rtest_person | rtest_pers_upd | CREATE RULE rtest_pers_upd AS ON UPDATE TO rtest_person DO UPDATE rtest_admin SET pname = new.pname WHERE (rtest_admin.pname = old.pname);
|
||||||
rtest_system | rtest_sys_del | CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system DO (DELETE FROM rtest_interface WHERE (rtest_interface.sysname = old.sysname); DELETE FROM rtest_admin WHERE (rtest_admin.sysname = old.sysname); );
|
rtest_system | rtest_sys_del | CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system DO (DELETE FROM rtest_interface WHERE (rtest_interface.sysname = old.sysname); DELETE FROM rtest_admin WHERE (rtest_admin.sysname = old.sysname); );
|
||||||
|
@ -47,8 +47,15 @@ SELECT CAST(name 'namefield' AS text) AS "text(name)";
|
|||||||
namefield
|
namefield
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
|
-- since this is an explicit cast, it should truncate w/o error:
|
||||||
ERROR: value too long for type character(10)
|
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
|
||||||
|
char(text)
|
||||||
|
------------
|
||||||
|
doh!
|
||||||
|
hi de ho n
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- note: implicit-cast case is tested in char.sql
|
||||||
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
|
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
|
||||||
char(text)
|
char(text)
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -90,7 +90,7 @@ SELECT 1.1 AS two UNION ALL SELECT 2;
|
|||||||
SELECT 1.0 AS two UNION ALL SELECT 1;
|
SELECT 1.0 AS two UNION ALL SELECT 1;
|
||||||
two
|
two
|
||||||
-----
|
-----
|
||||||
1
|
1.0
|
||||||
1
|
1
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@ create domain domainnumeric numeric(8,2);
|
|||||||
create domain domainint4 int4;
|
create domain domainint4 int4;
|
||||||
create domain domaintext text;
|
create domain domaintext text;
|
||||||
|
|
||||||
-- Test coercions
|
-- Test explicit coercions --- these should succeed (and truncate)
|
||||||
SELECT cast('123456' as domainvarchar); -- fail
|
SELECT cast('123456' as domainvarchar);
|
||||||
SELECT cast('12345' as domainvarchar); -- pass
|
SELECT cast('12345' as domainvarchar);
|
||||||
|
|
||||||
-- Test tables using domains
|
-- Test tables using domains
|
||||||
create table basictest
|
create table basictest
|
||||||
|
@ -90,8 +90,8 @@ SELECT (timestamp without time zone 'tomorrow' > 'now') as "True";
|
|||||||
-- to enable support for SQL99 timestamp type syntax.
|
-- to enable support for SQL99 timestamp type syntax.
|
||||||
SELECT date '1994-01-01' + time '11:00' AS "Jan_01_1994_11am";
|
SELECT date '1994-01-01' + time '11:00' AS "Jan_01_1994_11am";
|
||||||
SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
|
SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
|
||||||
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
|
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
|
||||||
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
|
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
|
||||||
|
|
||||||
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
||||||
SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
||||||
|
@ -162,28 +162,32 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
|
|||||||
-- **************** pg_cast ****************
|
-- **************** pg_cast ****************
|
||||||
|
|
||||||
-- Look for casts from and to the same type. This is not harmful, but
|
-- Look for casts from and to the same type. This is not harmful, but
|
||||||
-- useless.
|
-- useless. Also catch bogus values in pg_cast columns (other than
|
||||||
|
-- cases detected by oidjoins test).
|
||||||
|
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM pg_cast c
|
FROM pg_cast c
|
||||||
WHERE c.castsource = c.casttarget;
|
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
|
||||||
|
OR castcontext NOT IN ('e', 'a', 'i');
|
||||||
|
|
||||||
-- Look for cast functions with incorrect number or type of argument
|
-- Look for cast functions that don't have the right signature. The
|
||||||
-- or return value.
|
-- argument and result types in pg_proc must be the same as, or binary
|
||||||
|
-- compatible with, what it says in pg_cast.
|
||||||
|
|
||||||
SELECT c.*
|
SELECT c.*
|
||||||
FROM pg_cast c, pg_proc p
|
FROM pg_cast c, pg_proc p
|
||||||
WHERE c.castfunc = p.oid AND
|
WHERE c.castfunc = p.oid AND
|
||||||
(p.pronargs <> 1 OR
|
(p.pronargs <> 1
|
||||||
p.proargtypes[0] <> c.castsource OR
|
OR NOT (c.castsource = p.proargtypes[0] OR
|
||||||
p.prorettype <> c.casttarget);
|
EXISTS (SELECT 1 FROM pg_cast k
|
||||||
|
WHERE k.castfunc = 0 AND
|
||||||
-- Look for binary compatible casts that are not implicit. This is
|
k.castsource = c.castsource AND
|
||||||
-- legal, but probably not intended.
|
k.casttarget = p.proargtypes[0]))
|
||||||
|
OR NOT (p.prorettype = c.casttarget OR
|
||||||
SELECT *
|
EXISTS (SELECT 1 FROM pg_cast k
|
||||||
FROM pg_cast c
|
WHERE k.castfunc = 0 AND
|
||||||
WHERE c.castfunc = 0 AND NOT c.castimplicit;
|
k.castsource = p.prorettype AND
|
||||||
|
k.casttarget = c.casttarget)));
|
||||||
|
|
||||||
-- Look for binary compatible casts that do not have the reverse
|
-- Look for binary compatible casts that do not have the reverse
|
||||||
-- direction registered as well, or where the reverse direction is not
|
-- direction registered as well, or where the reverse direction is not
|
||||||
@ -341,9 +345,9 @@ WHERE p1.oprlsortop != p1.oprrsortop AND
|
|||||||
-- Hashing only works on simple equality operators "type = sametype",
|
-- Hashing only works on simple equality operators "type = sametype",
|
||||||
-- since the hash itself depends on the bitwise representation of the type.
|
-- since the hash itself depends on the bitwise representation of the type.
|
||||||
-- Check that allegedly hashable operators look like they might be "=".
|
-- Check that allegedly hashable operators look like they might be "=".
|
||||||
-- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
|
-- NOTE: in 7.3, this search finds xideqint4.
|
||||||
-- Until we have some cleaner way of dealing with binary-equivalent types,
|
-- Until we have some cleaner way of dealing with binary-equivalent types,
|
||||||
-- just leave those three tuples in the expected output.
|
-- just leave that tuple in the expected output.
|
||||||
|
|
||||||
SELECT p1.oid, p1.oprname
|
SELECT p1.oid, p1.oprname
|
||||||
FROM pg_operator AS p1
|
FROM pg_operator AS p1
|
||||||
|
@ -27,7 +27,9 @@ SELECT CAST(f1 AS text) AS "text(varchar)" FROM VARCHAR_TBL;
|
|||||||
|
|
||||||
SELECT CAST(name 'namefield' AS text) AS "text(name)";
|
SELECT CAST(name 'namefield' AS text) AS "text(name)";
|
||||||
|
|
||||||
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
|
-- since this is an explicit cast, it should truncate w/o error:
|
||||||
|
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
|
||||||
|
-- note: implicit-cast case is tested in char.sql
|
||||||
|
|
||||||
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
|
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user