Commit b26dfb95 authored by Tom Lane's avatar Tom Lane

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.
parent cc70ba2e
<!-- <!--
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 @@ ...@@ -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 @@ ...@@ -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>
......
<!-- <!--
$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> ( ...@@ -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'); ...@@ -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; ...@@ -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; ...@@ -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)); ...@@ -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>
......
<!-- $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 @@ ...@@ -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); ...@@ -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); ...@@ -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); ...@@ -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); ...@@ -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); ...@@ -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>
......
<!-- <!--
$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 ...@@ -24,6 +24,8 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters. worries about funny characters.
--> -->
<literallayout><![CDATA[ <literallayout><![CDATA[
Mixed numeric-and-float expressions are evaluated as float, per SQL spec
Explicit casts to char, varchar, bit, varbit will truncate or pad without error
CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE are available CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE are available
No-autocommit mode is available (set autocommit to off) No-autocommit mode is available (set autocommit to off)
Substantial improvements in functionality for functions returning sets Substantial improvements in functionality for functions returning sets
......
...@@ -804,13 +804,9 @@ If the non-unknown inputs are not all of the same type category, fail. ...@@ -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 ...@@ -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. ...@@ -858,27 +855,18 @@ the preferred type in the numeric category, so that type is used.
<title>Type Conversion in a Transposed Union</title> <title>Type Conversion in a Transposed Union</title>
<para> <para>
Here the output type of the union is forced to match the type of
the first clause in the union:
<screen> <screen>
tgl=> SELECT 1 AS "All integers" tgl=> SELECT 1 AS "Real"
tgl-> UNION SELECT CAST('2.2' AS REAL); tgl-> UNION SELECT CAST('2.2' AS REAL);
All integers Real
-------------- ------
1 1
2 2.2
(2 rows) (2 rows)
</screen> </screen>
</para> Here, since type <type>real</> cannot be implicitly cast to <type>integer</>,
<para> but <type>integer</> can be implicitly cast to <type>real</>, the union
Since <type>REAL</type> is not a preferred type, the parser sees no reason result type is resolved as <type>real</>.
to select it over <type>INTEGER</type> (which is what the 1 is), and instead
falls back on the use-the-first-alternative rule.
This example demonstrates that the preferred-type mechanism doesn't encode
as much information as we'd like. Future versions of
<productname>PostgreSQL</productname> may support a more general notion of
type preferences.
</para> </para>
</example> </example>
......
...@@ -8,7 +8,7 @@ ...@@ -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 @@ ...@@ -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,10 +1704,10 @@ cookDefault(ParseState *pstate, ...@@ -1705,10 +1704,10 @@ 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",
...@@ -1716,7 +1715,6 @@ cookDefault(ParseState *pstate, ...@@ -1716,7 +1715,6 @@ cookDefault(ParseState *pstate,
format_type_be(atttypid), format_type_be(atttypid),
format_type_be(type_id)); format_type_be(type_id));
} }
}
/* /*
* Might as well try to reduce any constant expressions. * Might as well try to reduce any constant expressions.
......
...@@ -8,7 +8,7 @@ ...@@ -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, ...@@ -95,7 +95,7 @@ AggregateCreate(const char *aggName,
*/ */
if (proc->proisstrict && agginitval == NULL) if (proc->proisstrict && agginitval == NULL)
{ {
if (!IsBinaryCompatible(aggBaseType, aggTransType)) if (!IsBinaryCoercible(aggBaseType, aggTransType))
elog(ERROR, "must not omit initval when transfn is strict and transtype is not compatible with input type"); elog(ERROR, "must not omit initval when transfn is strict and transtype is not compatible with input type");
} }
ReleaseSysCache(tup); ReleaseSysCache(tup);
......
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -426,7 +426,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
tletype = exprType(tle->expr); tletype = exprType(tle->expr);
atttype = attr->atttypid; atttype = attr->atttypid;
if (!IsBinaryCompatible(tletype, atttype)) if (!IsBinaryCoercible(tletype, atttype))
elog(ERROR, "function declared to return %s returns %s instead of %s at column %d", elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
format_type_be(rettype), format_type_be(rettype),
format_type_be(tletype), format_type_be(tletype),
......
...@@ -9,7 +9,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -732,6 +756,7 @@ CreateCast(CreateCastStmt *stmt)
} }
heap_freetuple(tuple); heap_freetuple(tuple);
heap_close(relation, RowExclusiveLock); heap_close(relation, RowExclusiveLock);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -508,7 +508,7 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
nexact++; nexact++;
exactOid = opclass->oid; exactOid = opclass->oid;
} }
else if (IsBinaryCompatible(opclass->opcintype, attrType)) else if (IsBinaryCoercible(attrType, opclass->opcintype))
{ {
ncompatible++; ncompatible++;
compatibleOid = opclass->oid; compatibleOid = opclass->oid;
......
...@@ -46,7 +46,7 @@ ...@@ -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) ...@@ -913,7 +913,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
*/ */
Oid inputType = exprType(aggref->target); Oid inputType = exprType(aggref->target);
if (!IsBinaryCompatible(inputType, aggform->aggtranstype)) if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
elog(ERROR, "Aggregate %u needs to have compatible input type and transition type", elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
aggref->aggfnoid); aggref->aggfnoid);
} }
......
...@@ -15,7 +15,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -2634,7 +2636,7 @@ _copyCreateCastStmt(CreateCastStmt *from)
Node_Copy(from, newnode, sourcetype); Node_Copy(from, newnode, sourcetype);
Node_Copy(from, newnode, targettype); Node_Copy(from, newnode, targettype);
Node_Copy(from, newnode, func); Node_Copy(from, newnode, func);
newnode->implicit = from->implicit; newnode->context = from->context;
return newnode; return newnode;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -1475,7 +1492,7 @@ _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
return false; return false;
if (!equal(a->func, b->func)) if (!equal(a->func, b->func))
return false; return false;
if (a->implicit != b->implicit) if (a->context != b->context)
return false; return false;
return true; return true;
......
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -215,13 +215,14 @@ makeAlias(const char *aliasname, List *colnames)
* creates a RelabelType node * creates a RelabelType node
*/ */
RelabelType * RelabelType *
makeRelabelType(Node *arg, Oid rtype, int32 rtypmod) makeRelabelType(Node *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
{ {
RelabelType *r = makeNode(RelabelType); RelabelType *r = makeNode(RelabelType);
r->arg = arg; r->arg = arg;
r->resulttype = rtype; r->resulttype = rtype;
r->resulttypmod = rtypmod; r->resulttypmod = rtypmod;
r->relabelformat = rformat;
return r; return r;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -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 ...@@ -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) ...@@ -914,9 +915,11 @@ _outRelabelType(StringInfo str, RelabelType *node)
{ {
appendStringInfo(str, " RELABELTYPE :arg "); appendStringInfo(str, " RELABELTYPE :arg ");
_outNode(str, node->arg); _outNode(str, node->arg);
appendStringInfo(str,
appendStringInfo(str, " :resulttype %u :resulttypmod %d ", " :resulttype %u :resulttypmod %d :relabelformat %d ",
node->resulttype, node->resulttypmod); node->resulttype,
node->resulttypmod,
(int) node->relabelformat);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -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) ...@@ -1335,6 +1339,10 @@ _readRelabelType(void)
token = pg_strtok(&length); /* get resulttypmod */ token = pg_strtok(&length); /* get resulttypmod */
local_node->resulttypmod = atoi(token); local_node->resulttypmod = atoi(token);
token = pg_strtok(&length); /* eat :relabelformat */
token = pg_strtok(&length); /* get relabelformat */
local_node->relabelformat = (CoercionForm) atoi(token);
return local_node; return local_node;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -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, ...@@ -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) ...@@ -860,83 +843,10 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
if (commuted_op == InvalidOid) if (commuted_op == InvalidOid)
return InvalidOid; return InvalidOid;
/* Done if the (commuted) operator is a member of the index's opclass */ /* OK if the (commuted) operator is a member of the index's opclass */
if (op_in_opclass(commuted_op, opclass)) if (op_in_opclass(commuted_op, opclass))
return expr_op; return expr_op;
/*
* Maybe the index uses a binary-compatible operator set.
*
* Get the nominal input types of the given operator and the actual type
* (before binary-compatible relabeling) of the index key.
*/
oldoptup = SearchSysCache(OPEROID,
ObjectIdGetDatum(expr_op),
0, 0, 0);
if (!HeapTupleIsValid(oldoptup))
return InvalidOid; /* probably can't happen */
oldopform = (Form_pg_operator) GETSTRUCT(oldoptup);
opname = pstrdup(NameStr(oldopform->oprname));
ltype = oldopform->oprleft;
rtype = oldopform->oprright;
ReleaseSysCache(oldoptup);
if (indexkey_on_left)
{
Node *leftop = (Node *) get_leftop(clause);
if (leftop && IsA(leftop, RelabelType))
leftop = ((RelabelType *) leftop)->arg;
indexkeytype = exprType(leftop);
}
else
{
Node *rightop = (Node *) get_rightop(clause);
if (rightop && IsA(rightop, RelabelType))
rightop = ((RelabelType *) rightop)->arg;
indexkeytype = exprType(rightop);
}
/*
* Make sure we have different but binary-compatible types.
*/
if (ltype == indexkeytype && rtype == indexkeytype)
return InvalidOid; /* no chance for a different operator */
if (!IsBinaryCompatible(ltype, indexkeytype))
return InvalidOid;
if (!IsBinaryCompatible(rtype, indexkeytype))
return InvalidOid;
/*
* OK, look for operator of the same name with the indexkey's data
* type. (In theory this might find a non-semantically-comparable
* operator, but in practice that seems pretty unlikely for
* binary-compatible types.)
*/
new_op = compatible_oper_opid(makeList1(makeString(opname)),
indexkeytype, indexkeytype, true);
if (OidIsValid(new_op))
{
if (new_op != expr_op)
{
/*
* OK, we found a binary-compatible operator of the same name;
* now does it match the index?
*/
if (indexkey_on_left)
commuted_op = new_op;
else
commuted_op = get_commutator(new_op);
if (commuted_op == InvalidOid)
return InvalidOid;
if (op_in_opclass(commuted_op, opclass))
return new_op;
}
}
return InvalidOid; return InvalidOid;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -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, ...@@ -520,6 +520,7 @@ build_index_pathkeys(Query *root,
funcnode->funcid = index->indproc; funcnode->funcid = index->indproc;
funcnode->funcresulttype = get_func_rettype(index->indproc); funcnode->funcresulttype = get_func_rettype(index->indproc);
funcnode->funcretset = false; /* can never be a set */ funcnode->funcretset = false; /* can never be a set */
funcnode->funcformat = COERCE_DONTCARE; /* to match any user expr */
funcnode->func_fcache = NULL; funcnode->func_fcache = NULL;
while (*indexkeys != 0) while (*indexkeys != 0)
......
...@@ -10,7 +10,7 @@ ...@@ -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, ...@@ -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, ...@@ -1061,23 +1060,13 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
index, index,
&opclass); &opclass);
/*
* Substitute the appropriate operator if the expression operator
* is merely binary-compatible with the index. This shouldn't
* fail, since indxpath.c found it before...
*/
newopno = indexable_operator(newclause, opclass, true);
if (newopno == InvalidOid)
elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
((Oper *) newclause->oper)->opno = newopno;
fixed_qual = lappend(fixed_qual, newclause); fixed_qual = lappend(fixed_qual, newclause);
/* /*
* Finally, check to see if index is lossy for this operator. If * Finally, check to see if index is lossy for this operator. If
* so, add (a copy of) original form of clause to recheck list. * so, add (a copy of) original form of clause to recheck list.
*/ */
if (op_requires_recheck(newopno, opclass)) if (op_requires_recheck(((Oper *) newclause->oper)->opno, opclass))
recheck_qual = lappend(recheck_qual, recheck_qual = lappend(recheck_qual,
copyObject((Node *) clause)); copyObject((Node *) clause));
} }
......
...@@ -15,7 +15,7 @@ ...@@ -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, ...@@ -187,8 +187,9 @@ expand_targetlist(List *tlist, int command_type,
false, /* not a set */ false, /* not a set */
false); false);
if (!att_tup->attisdropped) if (!att_tup->attisdropped)
new_expr = coerce_type_constraints(NULL, new_expr, new_expr = coerce_type_constraints(new_expr,
atttype, false); atttype,
COERCE_IMPLICIT_CAST);
break; break;
case CMD_UPDATE: case CMD_UPDATE:
/* Insert NULLs for dropped columns */ /* Insert NULLs for dropped columns */
......
...@@ -14,7 +14,7 @@ ...@@ -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, ...@@ -420,8 +420,7 @@ generate_setop_tlist(List *colTypes, int flag,
} }
else else
{ {
expr = coerce_to_common_type(NULL, expr = coerce_to_common_type(expr,
expr,
colType, colType,
"UNION/INTERSECT/EXCEPT"); "UNION/INTERSECT/EXCEPT");
colTypmod = -1; colTypmod = -1;
......
...@@ -6,7 +6,7 @@ ...@@ -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) ...@@ -2565,24 +2565,20 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
given_type_id = exprType(expr); given_type_id = exprType(expr);
expected_type_id = (Oid) lfirsti(paramtypes); expected_type_id = (Oid) lfirsti(paramtypes);
if (given_type_id != expected_type_id) expr = coerce_to_target_type(expr, given_type_id,
{ expected_type_id, -1,
expr = CoerceTargetExpr(pstate, COERCION_ASSIGNMENT,
expr, COERCE_IMPLICIT_CAST);
given_type_id,
expected_type_id,
-1,
false);
if (!expr) if (expr == NULL)
elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s" elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s"
"\n\tYou will need to rewrite or cast the expression", "\n\tYou will need to rewrite or cast the expression",
i, i,
format_type_be(given_type_id), format_type_be(given_type_id),
format_type_be(expected_type_id)); format_type_be(expected_type_id));
}
fix_opids(expr); fix_opids(expr);
lfirst(l) = expr; lfirst(l) = expr;
paramtypes = lnext(paramtypes); paramtypes = lnext(paramtypes);
......
...@@ -11,7 +11,7 @@ ...@@ -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); ...@@ -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); ...@@ -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: ...@@ -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: ...@@ -7061,6 +7062,7 @@ unreserved_keyword:
| HOUR_P | HOUR_P
| IMMEDIATE | IMMEDIATE
| IMMUTABLE | IMMUTABLE
| IMPLICIT_P
| INCREMENT | INCREMENT
| INDEX | INDEX
| INHERITS | INHERITS
......
...@@ -8,7 +8,7 @@ ...@@ -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[] = { ...@@ -147,6 +147,7 @@ static const ScanKeyword ScanKeywords[] = {
{"ilike", ILIKE}, {"ilike", ILIKE},
{"immediate", IMMEDIATE}, {"immediate", IMMEDIATE},
{"immutable", IMMUTABLE}, {"immutable", IMMUTABLE},
{"implicit", IMPLICIT_P},
{"in", IN_P}, {"in", IN_P},
{"increment", INCREMENT}, {"increment", INCREMENT},
{"index", INDEX}, {"index", INDEX},
......
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -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;
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -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 @@ ...@@ -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; ...@@ -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) ...@@ -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;
if (con->typename != NULL)
result = parser_typecast_constant(val, con->typename);
else
result = (Node *) make_const(val); result = (Node *) make_const(val);
if (con->typename != NULL)
result = typecast_expression(result, con->typename);
break; break;
} }
case T_ExprFieldSelect: case T_ExprFieldSelect:
...@@ -175,7 +171,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,62 +1055,26 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod) ...@@ -1067,62 +1055,26 @@ 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;
second_arg = (Const *) lsecond(((Expr *) expr)->args);
if (!IsA(second_arg, Const) ||
second_arg->consttype != INT4OID ||
second_arg->constisnull)
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 * If it's not a two-argument or three-argument function with the second
* same type as the return value and the second is an int4. Also, just * argument being an int4 constant, it can't have been created from a
* to be sure, check return type agrees with expr node. * length coercion (it must be a type coercion, instead).
*/ */
if (procStruct->pronargs != 2 || nargs = length(((Expr *) expr)->args);
procStruct->prorettype != procStruct->proargtypes[0] || if (nargs < 2 || nargs > 3)
procStruct->proargtypes[1] != INT4OID ||
procStruct->prorettype != ((Expr *) expr)->typeOid)
{
ReleaseSysCache(procTuple);
return false; return false;
}
/* second_arg = (Const *) lsecond(((Expr *) expr)->args);
* Furthermore, the name and namespace of the function must be the if (!IsA(second_arg, Const) ||
* same as its result type's name/namespace (cf. second_arg->consttype != INT4OID ||
* find_coercion_function). second_arg->constisnull)
*/
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; return false;
}
/* /*
* OK, it is indeed a length-coercion function. * OK, it is indeed a length-coercion function.
...@@ -1130,79 +1082,17 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod) ...@@ -1130,79 +1082,17 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
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, ...@@ -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,
{
expr = CoerceTargetExpr(pstate, expr, inputType,
targetType, typename->typmod, targetType, typename->typmod,
true); /* explicit coercion */ COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST);
if (expr == NULL) if (expr == NULL)
elog(ERROR, "Cannot cast type '%s' to '%s'", elog(ERROR, "Cannot cast type %s to %s",
format_type_be(inputType), format_type_be(inputType),
format_type_be(targetType)); format_type_be(targetType));
}
/*
* If the target is a fixed-length type, it may need a length coercion
* as well as a type coercion.
*/
expr = coerce_type_typmod(pstate, expr,
targetType, typename->typmod);
return expr; return expr;
} }
...@@ -8,7 +8,7 @@ ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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;
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* 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 @@ ...@@ -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) ...@@ -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) ...@@ -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 * ...@@ -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, ...@@ -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, ...@@ -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,28 +321,25 @@ transformArraySubscripts(ParseState *pstate, ...@@ -323,28 +321,25 @@ 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,
-1, false);
if (assignFrom == NULL) if (assignFrom == NULL)
elog(ERROR, "Array assignment requires type '%s'" elog(ERROR, "Array assignment requires 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",
format_type_be(typeneeded), format_type_be(typeneeded),
format_type_be(typesource)); format_type_be(typesource));
} }
} }
}
/* /*
* Ready to build the ArrayRef node. * Ready to build the ArrayRef node.
*/ */
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, ...@@ -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) ...@@ -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) ...@@ -470,46 +461,3 @@ make_const(Value *value)
return con; return con;
} }
/*
* Decide whether a T_Float value fits in float8, or must be treated as
* type "numeric". We check the number of digits and check for overflow/
* underflow. (With standard compilation options, Postgres' NUMERIC type
* can handle decimal exponents up to 1000, considerably more than most
* implementations of float8, so this is a sensible test.)
*/
static bool
fitsInFloat(Value *value)
{
const char *ptr;
int ndigits;
char *endptr;
/*
* Count digits, ignoring leading zeroes (but not trailing zeroes).
* DBL_DIG is the maximum safe number of digits for "double".
*/
ptr = strVal(value);
while (*ptr == '+' || *ptr == '-' || *ptr == '0' || *ptr == '.')
ptr++;
ndigits = 0;
for (; *ptr; ptr++)
{
if (isdigit((unsigned char) *ptr))
ndigits++;
else if (*ptr == 'e' || *ptr == 'E')
break; /* don't count digits in exponent */
}
if (ndigits > DBL_DIG)
return false;
/*
* Use strtod() to check for overflow/underflow.
*/
errno = 0;
(void) strtod(strVal(value), &endptr);
if (*endptr != '\0' || errno != 0)
return false;
return true;
}
...@@ -8,7 +8,7 @@ ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -696,8 +696,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
/* but is it good enough? */ /* but is it good enough? */
opform = (Form_pg_operator) GETSTRUCT(optup); opform = (Form_pg_operator) GETSTRUCT(optup);
if (IsBinaryCompatible(opform->oprleft, arg1) && if (IsBinaryCoercible(arg1, opform->oprleft) &&
IsBinaryCompatible(opform->oprright, arg2)) IsBinaryCoercible(arg2, opform->oprright))
return optup; return optup;
/* nope... */ /* nope... */
......
...@@ -8,7 +8,7 @@ ...@@ -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, ...@@ -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,31 +285,22 @@ updateTargetListEntry(ParseState *pstate, ...@@ -284,31 +285,22 @@ 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,
{
tle->expr = CoerceTargetExpr(pstate, tle->expr, type_id,
attrtype, attrtypmod, attrtype, attrtypmod,
false); COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
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, ...@@ -324,46 +316,6 @@ updateTargetListEntry(ParseState *pstate,
} }
Node *
CoerceTargetExpr(ParseState *pstate,
Node *expr,
Oid type_id,
Oid attrtype,
int32 attrtypmod,
bool isExplicit)
{
if (can_coerce_type(1, &type_id, &attrtype, isExplicit))
expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod,
isExplicit);
#ifndef DISABLE_STRING_HACKS
/*
* string hacks to get transparent conversions w/o explicit
* conversions
*/
else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
{
Oid text_id = TEXTOID;
if (type_id == TEXTOID)
{
}
else if (can_coerce_type(1, &type_id, &text_id, isExplicit))
expr = coerce_type(pstate, expr, type_id, text_id, attrtypmod,
isExplicit);
else
expr = NULL;
}
#endif
else
expr = NULL;
return expr;
}
/* /*
* checkInsertTargets - * checkInsertTargets -
* generate a list of INSERT column targets if not supplied, or * generate a list of INSERT column targets if not supplied, or
......
...@@ -7,7 +7,7 @@ ...@@ -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 @@ ...@@ -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,11 +473,10 @@ build_column_default(Relation rel, int attrno) ...@@ -474,11 +473,10 @@ 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 * This really shouldn't fail; should have checked the default's
* type when it was created ... * type when it was created ...
...@@ -490,13 +488,6 @@ build_column_default(Relation rel, int attrno) ...@@ -490,13 +488,6 @@ build_column_default(Relation rel, int attrno)
NameStr(att_tup->attname), NameStr(att_tup->attname),
format_type_be(atttype), format_type_be(atttype),
format_type_be(exprtype)); format_type_be(exprtype));
}
/*
* If the column is a fixed-length type, it may need a length coercion
* as well as a type coercion.
*/
expr = coerce_type_typmod(NULL, expr, atttype, atttypmod);
return expr; return expr;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -755,6 +756,72 @@ array_out(PG_FUNCTION_ARGS)
PG_RETURN_CSTRING(retval); PG_RETURN_CSTRING(retval);
} }
/*-------------------------------------------------------------------------
* array_length_coerce :
* Apply the element type's length-coercion routine to each element
* of the given array.
*-------------------------------------------------------------------------
*/
Datum
array_length_coerce(PG_FUNCTION_ARGS)
{
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
int32 len = PG_GETARG_INT32(1);
bool isExplicit = PG_GETARG_BOOL(2);
FmgrInfo *fmgr_info = fcinfo->flinfo;
FmgrInfo *element_finfo;
FunctionCallInfoData locfcinfo;
/* If no typmod is provided, shortcircuit the whole thing */
if (len < 0)
PG_RETURN_ARRAYTYPE_P(v);
/*
* We arrange to look up the element type's coercion function only
* once per series of calls.
*/
if (fmgr_info->fn_extra == NULL)
{
Oid funcId;
int nargs;
fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,
sizeof(FmgrInfo));
element_finfo = (FmgrInfo *) fmgr_info->fn_extra;
funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs);
if (OidIsValid(funcId))
fmgr_info_cxt(funcId, element_finfo, fmgr_info->fn_mcxt);
else
element_finfo->fn_oid = InvalidOid;
}
else
element_finfo = (FmgrInfo *) fmgr_info->fn_extra;
/*
* If we didn't find a coercion function, return the array unmodified
* (this should not happen in the normal course of things, but might
* happen if this function is called manually).
*/
if (element_finfo->fn_oid == InvalidOid)
PG_RETURN_ARRAYTYPE_P(v);
/*
* Use array_map to apply the function to each array element.
*
* Note: we pass isExplicit whether or not the function wants it ...
*/
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
locfcinfo.flinfo = element_finfo;
locfcinfo.nargs = 3;
locfcinfo.arg[0] = PointerGetDatum(v);
locfcinfo.arg[1] = Int32GetDatum(len);
locfcinfo.arg[2] = BoolGetDatum(isExplicit);
return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v));
}
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* array_dims : * array_dims :
* returns the dimensions of the array pointed to by "v", as a "text" * returns the dimensions of the array pointed to by "v", as a "text"
......
...@@ -7,7 +7,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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 */
/* require at least one digit */
if (!isdigit((unsigned char) *ptr))
{
if (errorOK)
return false;
else
elog(ERROR, "Bad int8 external representation \"%s\"", str); elog(ERROR, "Bad int8 external representation \"%s\"", str);
while (*ptr && isdigit((unsigned char) *ptr)) /* process digits */ }
/* 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? */
{
if (errorOK)
return false;
else
elog(ERROR, "int8 value out of range: \"%s\"", str); elog(ERROR, "int8 value out of range: \"%s\"", str);
}
tmp = newtmp; tmp = newtmp;
} }
if (*ptr) /* trailing junk? */
/* trailing junk? */
if (*ptr)
{
if (errorOK)
return false;
else
elog(ERROR, "Bad int8 external representation \"%s\"", str); elog(ERROR, "Bad int8 external representation \"%s\"", str);
}
*result = (sign < 0) ? -tmp : tmp;
return true;
}
result = (sign < 0) ? -tmp : tmp; /* 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) ...@@ -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) ...@@ -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) ...@@ -793,9 +889,6 @@ text_int8(PG_FUNCTION_ARGS)
return result; return result;
} }
/* int8_text()
*/
Datum Datum
int8_text(PG_FUNCTION_ARGS) int8_text(PG_FUNCTION_ARGS)
{ {
......
...@@ -5,7 +5,7 @@ ...@@ -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) ...@@ -1709,6 +1709,50 @@ numeric_float4(PG_FUNCTION_ARGS)
} }
Datum
text_numeric(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int len;
char *s;
Datum result;
len = (VARSIZE(str) - VARHDRSZ);
s = palloc(len + 1);
memcpy(s, VARDATA(str), len);
*(s + len) = '\0';
result = DirectFunctionCall3(numeric_in, CStringGetDatum(s),
ObjectIdGetDatum(0), Int32GetDatum(-1));
pfree(s);
return result;
}
Datum
numeric_text(PG_FUNCTION_ARGS)
{
/* val is numeric, but easier to leave it as Datum */
Datum val = PG_GETARG_DATUM(0);
char *s;
int len;
text *result;
s = DatumGetCString(DirectFunctionCall1(numeric_out, val));
len = strlen(s);
result = (text *) palloc(VARHDRSZ + len);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), s, len);
pfree(s);
PG_RETURN_TEXT_P(result);
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* *
* Aggregate functions * Aggregate functions
......
...@@ -13,7 +13,7 @@ ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
This diff is collapsed.
...@@ -9,7 +9,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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)
if (bit_finfo.fn_oid == InvalidOid) {
fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext); mask = BITMASK << ipad;
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
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); PG_RETURN_VARBIT_P(result);
} }
/* /*
...@@ -311,7 +318,7 @@ varbit_in(PG_FUNCTION_ARGS) ...@@ -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) ...@@ -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,37 +442,15 @@ varbit(PG_FUNCTION_ARGS) ...@@ -429,37 +442,15 @@ varbit(PG_FUNCTION_ARGS)
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result)); memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
PG_RETURN_VARBIT_P(result); /* Make sure last byte is zero-padded if needed */
} ipad = VARBITPAD(result);
if (ipad > 0)
/* _varbit() {
* Converts an array of bit() elements to a specific internal length. mask = BITMASK << ipad;
* len is the maximum bitlength specified in the column definition. *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
*/ }
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); PG_RETURN_VARBIT_P(result);
} }
...@@ -978,7 +969,7 @@ bitshiftleft(PG_FUNCTION_ARGS) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -1046,7 +1037,7 @@ bitshiftright(PG_FUNCTION_ARGS)
p = VARBITS(arg); p = VARBITS(arg);
/* Set the first part of the result to 0 */ /* Set the first part of the result to 0 */
memset(r, 0, byte_shift); MemSet(r, 0, byte_shift);
r += byte_shift; r += byte_shift;
if (ishift == 0) if (ishift == 0)
......
...@@ -8,7 +8,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
if (!isExplicit)
{
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++) for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ') if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character(%d)", elog(ERROR, "value too long for type character(%d)",
maxlen - VARHDRSZ); maxlen - VARHDRSZ);
}
len = maxmblen; len = maxmblen;
...@@ -238,37 +248,6 @@ bpchar(PG_FUNCTION_ARGS) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -448,21 +436,19 @@ varchar(PG_FUNCTION_ARGS)
/* only reach here if string is too long... */ /* only reach here if string is too long... */
{
size_t maxmblen;
/* truncate multibyte string preserving multibyte boundary */ /* truncate multibyte string preserving multibyte boundary */
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ, maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
maxlen - VARHDRSZ) + VARHDRSZ; maxlen - VARHDRSZ);
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++) if (!isExplicit)
{
for (i = maxmblen; 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) ...@@ -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
*****************************************************************************/ *****************************************************************************/
......
...@@ -7,7 +7,7 @@ ...@@ -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) ...@@ -1073,51 +1073,6 @@ getBaseType(Oid typid)
return typid; return typid;
} }
/*
* getBaseTypeMod
* If the given type is a domain, return the typmod it applies to
* its base type; otherwise return the specified original typmod.
*/
int32
getBaseTypeMod(Oid typid, int32 typmod)
{
/*
* We loop to find the bottom base type in a stack of domains.
*/
for (;;)
{
HeapTuple tup;
Form_pg_type typTup;
tup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "getBaseTypeMod: failed to lookup type %u", typid);
typTup = (Form_pg_type) GETSTRUCT(tup);
if (typTup->typtype != 'd')
{
/* Not a domain, so done */
ReleaseSysCache(tup);
break;
}
/*
* The typmod applied to a domain should always be -1.
*
* We substitute the domain's typmod as we switch attention to the
* base type.
*/
Assert(typmod < 0);
typid = typTup->typbasetype;
typmod = typTup->typtypmod;
ReleaseSysCache(tup);
}
return typmod;
}
/* /*
* get_typavgwidth * get_typavgwidth
* *
......
...@@ -27,7 +27,7 @@ ...@@ -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" ...@@ -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 \ ...@@ -1063,7 +1063,7 @@ UPDATE pg_database SET \
-- We use the OID of template0 to determine lastsysoid -- We use the OID of template0 to determine lastsysoid
UPDATE pg_database SET datlastsysoid = \ UPDATE pg_database SET datlastsysoid = \
(SELECT oid - 1 FROM pg_database WHERE datname = 'template0'); (SELECT oid::int4 - 1 FROM pg_database WHERE datname = 'template0');
-- Explicitly revoke public create-schema and create-temp-table privileges -- Explicitly revoke public create-schema and create-temp-table privileges
-- in template1 and template0; else the latter would be on by default -- in template1 and template0; else the latter would be on by default
......
...@@ -22,7 +22,7 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -3859,8 +3859,10 @@ dumpCasts(Archive *fout,
appendPQExpBuffer(defqry, "WITH FUNCTION %s", appendPQExpBuffer(defqry, "WITH FUNCTION %s",
format_function_signature(&finfo[fidx], true)); format_function_signature(&finfo[fidx], true));
if (strcmp(castimplicit, "t") == 0) if (strcmp(castcontext, "a") == 0)
appendPQExpBuffer(defqry, " AS ASSIGNMENT"); appendPQExpBuffer(defqry, " AS ASSIGNMENT");
else if (strcmp(castcontext, "i") == 0)
appendPQExpBuffer(defqry, " AS IMPLICIT");
appendPQExpBuffer(defqry, ";\n"); appendPQExpBuffer(defqry, ";\n");
ArchiveEntry(fout, castoid, ArchiveEntry(fout, castoid,
......
...@@ -37,7 +37,7 @@ ...@@ -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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200209021 #define CATALOG_VERSION_NO 200209181
#endif #endif
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -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 ...@@ -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 ...@@ -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 - - ));
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -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 @@ ...@@ -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); ...@@ -52,7 +53,8 @@ extern Const *makeNullConst(Oid consttype);
extern Alias *makeAlias(const char *aliasname, List *colnames); extern Alias *makeAlias(const char *aliasname, List *colnames);
extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod); extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod,
CoercionForm rformat);
extern RangeVar *makeRangeVar(char *schemaname, char *relname); extern RangeVar *makeRangeVar(char *schemaname, char *relname);
......
...@@ -7,7 +7,7 @@ ...@@ -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 ...@@ -1632,7 +1632,7 @@ typedef struct CreateCastStmt
TypeName *sourcetype; TypeName *sourcetype;
TypeName *targettype; TypeName *targettype;
FuncWithArgs *func; FuncWithArgs *func;
bool implicit; CoercionContext context;
} CreateCastStmt; } CreateCastStmt;
/* ---------------------- /* ----------------------
......
...@@ -10,7 +10,7 @@ ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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;
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* 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 ...@@ -29,29 +29,31 @@ typedef enum CATEGORY
TIMESPAN_TYPE, TIMESPAN_TYPE,
GEOMETRIC_TYPE, GEOMETRIC_TYPE,
NETWORK_TYPE, NETWORK_TYPE,
USER_TYPE, USER_TYPE
MIXED_TYPE
} CATEGORY; } CATEGORY;
extern bool IsBinaryCompatible(Oid type1, Oid type2); extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
extern bool IsPreferredType(CATEGORY category, Oid type); extern bool IsPreferredType(CATEGORY category, Oid type);
extern CATEGORY TypeCategory(Oid type); extern CATEGORY TypeCategory(Oid type);
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids, extern Node *coerce_to_target_type(Node *expr, Oid exprtype,
bool isExplicit); Oid targettype, int32 targettypmod,
extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, CoercionContext ccontext,
Oid targetTypeId, int32 atttypmod, bool isExplicit); CoercionForm cformat);
extern Node *coerce_type_typmod(ParseState *pstate, Node *node, extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
Oid targetTypeId, int32 atttypmod); CoercionContext ccontext);
extern Node *coerce_type_constraints(ParseState *pstate, Node *arg, extern Node *coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
Oid typeId, bool applyTypmod); CoercionContext ccontext, CoercionForm cformat);
extern Node *coerce_type_constraints(Node *arg, Oid typeId,
CoercionForm cformat);
extern Node *coerce_to_boolean(Node *node, const char *constructName); extern Node *coerce_to_boolean(Node *node, const char *constructName);
extern Oid select_common_type(List *typeids, const char *context); extern Oid select_common_type(List *typeids, const char *context);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node, extern Node *coerce_to_common_type(Node *node, Oid targetTypeId,
Oid targetTypeId,
const char *context); const char *context);
extern Oid find_typmod_coercion_function(Oid typeId, int *nargs);
#endif /* PARSE_COERCE_H */ #endif /* PARSE_COERCE_H */
...@@ -6,7 +6,7 @@ ...@@ -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); ...@@ -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);
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* 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 @@ ...@@ -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, ...@@ -23,9 +24,6 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle, extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
char *colname, int attrno, char *colname, int attrno,
List *indirection); List *indirection);
extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr,
Oid type_id, Oid attrtype, int32 attrtypmod,
bool isExplicit);
extern List *checkInsertTargets(ParseState *pstate, List *cols, extern List *checkInsertTargets(ParseState *pstate, List *cols,
List **attrnos); List **attrnos);
......
...@@ -10,7 +10,7 @@ ...@@ -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 ...@@ -82,6 +82,7 @@ typedef struct
*/ */
extern Datum array_in(PG_FUNCTION_ARGS); extern Datum array_in(PG_FUNCTION_ARGS);
extern Datum array_out(PG_FUNCTION_ARGS); extern Datum array_out(PG_FUNCTION_ARGS);
extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_eq(PG_FUNCTION_ARGS); extern Datum array_eq(PG_FUNCTION_ARGS);
extern Datum array_dims(PG_FUNCTION_ARGS); extern Datum array_dims(PG_FUNCTION_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -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); ...@@ -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); ...@@ -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); ...@@ -633,6 +631,8 @@ extern Datum numeric_float8(PG_FUNCTION_ARGS);
extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS);
extern Datum float4_numeric(PG_FUNCTION_ARGS); extern Datum float4_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_float4(PG_FUNCTION_ARGS); extern Datum numeric_float4(PG_FUNCTION_ARGS);
extern Datum text_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_text(PG_FUNCTION_ARGS);
extern Datum numeric_accum(PG_FUNCTION_ARGS); extern Datum numeric_accum(PG_FUNCTION_ARGS);
extern Datum int2_accum(PG_FUNCTION_ARGS); extern Datum int2_accum(PG_FUNCTION_ARGS);
extern Datum int4_accum(PG_FUNCTION_ARGS); extern Datum int4_accum(PG_FUNCTION_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -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 @@ ...@@ -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); ...@@ -106,6 +108,12 @@ extern Datum int82(PG_FUNCTION_ARGS);
extern Datum i8tod(PG_FUNCTION_ARGS); extern Datum i8tod(PG_FUNCTION_ARGS);
extern Datum dtoi8(PG_FUNCTION_ARGS); extern Datum dtoi8(PG_FUNCTION_ARGS);
extern Datum i8tof(PG_FUNCTION_ARGS);
extern Datum ftoi8(PG_FUNCTION_ARGS);
extern Datum i8tooid(PG_FUNCTION_ARGS);
extern Datum oidtoi8(PG_FUNCTION_ARGS);
extern Datum int8_text(PG_FUNCTION_ARGS); extern Datum int8_text(PG_FUNCTION_ARGS);
extern Datum text_int8(PG_FUNCTION_ARGS); extern Datum text_int8(PG_FUNCTION_ARGS);
......
...@@ -6,7 +6,7 @@ ...@@ -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); ...@@ -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,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -75,7 +75,7 @@ EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true); ...@@ -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;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment