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:
Tom Lane 2002-09-18 21:35:25 +00:00
parent cc70ba2e4d
commit b26dfb9522
70 changed files with 1642 additions and 1528 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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));
}
} }
/* /*

View File

@ -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);

View File

@ -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),

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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);
} }
/* /*

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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)

View File

@ -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));
} }

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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},

View File

@ -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;

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;
}

View File

@ -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... */

View File

@ -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

View File

@ -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;
} }

View File

@ -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"

View File

@ -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)
{ {

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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)

View File

@ -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
*****************************************************************************/ *****************************************************************************/

View File

@ -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
* *

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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 - - ));

View File

@ -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");

View File

@ -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);

View File

@ -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;
/* ---------------------- /* ----------------------

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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
------------- -------------

View File

@ -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
------------- -------------

View File

@ -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
------------- -------------

View File

@ -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

View File

@ -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;

View File

@ -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); );

View File

@ -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)
---------------------- ----------------------

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;