]> granicus.if.org Git - postgresql/commitdiff
Extend pg_cast castimplicit column to a three-way value; this allows us
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 18 Sep 2002 21:35:25 +0000 (21:35 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 18 Sep 2002 21:35:25 +0000 (21:35 +0000)
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.

70 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/datatype.sgml
doc/src/sgml/ref/create_cast.sgml
doc/src/sgml/release.sgml
doc/src/sgml/typeconv.sgml
src/backend/catalog/heap.c
src/backend/catalog/pg_aggregate.c
src/backend/catalog/pg_proc.c
src/backend/commands/functioncmds.c
src/backend/commands/indexcmds.c
src/backend/executor/nodeAgg.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/pathkeys.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/prep/preptlist.c
src/backend/optimizer/prep/prepunion.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_node.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_target.c
src/backend/rewrite/rewriteHandler.c
src/backend/utils/adt/arrayfuncs.c
src/backend/utils/adt/int8.c
src/backend/utils/adt/numeric.c
src/backend/utils/adt/regproc.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/varbit.c
src/backend/utils/adt/varchar.c
src/backend/utils/cache/lsyscache.c
src/bin/initdb/initdb.sh
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/nodes/makefuncs.h
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h
src/include/parser/parse_coerce.h
src/include/parser/parse_node.h
src/include/parser/parse_target.h
src/include/utils/array.h
src/include/utils/builtins.h
src/include/utils/int8.h
src/include/utils/lsyscache.h
src/include/utils/varbit.h
src/test/regress/expected/domain.out
src/test/regress/expected/horology-no-DST-before-1970.out
src/test/regress/expected/horology-solaris-1947.out
src/test/regress/expected/horology.out
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/prepare.out
src/test/regress/expected/rules.out
src/test/regress/expected/strings.out
src/test/regress/expected/union.out
src/test/regress/sql/domain.sql
src/test/regress/sql/horology.sql
src/test/regress/sql/opr_sanity.sql
src/test/regress/sql/strings.sql

index a8fd81e19c948bf285e9ae82d1d5135264c04785..01dfe6ad73b3c8697b30b6a2981a3b525b46d4dd 100644 (file)
@@ -1,6 +1,6 @@
 <!--
  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">
   <title>pg_cast</title>
 
   <para>
-   <structname>pg_cast</structname> stores data type conversion paths
-   defined with <command>CREATE CAST</command> plus the built-in
-   conversions.
+   <structname>pg_cast</structname> stores data type conversion paths,
+   both built-in paths and those defined with <command>CREATE CAST</command>.
   </para>
 
   <table>
       <entry><type>oid</type></entry>
       <entry>pg_proc.oid</entry>
       <entry>
-       The OID of the function to use to perform this cast.  A 0 is
-       stored if the data types are binary compatible (that is, no
-       function is needed to perform the cast).
+       The OID of the function to use to perform this cast.  Zero is
+       stored if the data types are binary coercible (that is, no
+       run-time operation is needed to perform the cast).
       </entry>
      </row>
 
      <row>
-      <entry>castimplicit</entry>
-      <entry><type>bool</type></entry>
+      <entry>castcontext</entry>
+      <entry><type>char</type></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>
     </tbody>
    </tgroup>
index 41ca3c00e53669a2f05ec6aa74782ac2591dc223..28d3fcb7edeb88303ff341300d740ac775a5f06d 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.102 2002/08/23 02:54:18 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.103 2002/09/18 21:35:20 tgl Exp $
 -->
 
  <chapter id="datatype">
@@ -823,8 +823,19 @@ CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
 
    <note>
     <para>
-     Prior to <productname>PostgreSQL</> 7.2, strings that were too long were silently
-     truncated, no error was raised.
+     If one explicitly casts a value to
+     <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>
    </note>
 
@@ -897,12 +908,14 @@ INSERT INTO test2 VALUES ('ok');
 INSERT INTO test2 VALUES ('good      ');
 INSERT INTO test2 VALUES ('too long');
 <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;
 <computeroutput>
    b   | char_length
 -------+-------------
  ok    |           2
  good  |           5
+ too l |           5
 </computeroutput>
 </programlisting>
     <calloutlist>
@@ -932,7 +945,7 @@ SELECT b, char_length(b) FROM test2;
    </para>
 
     <table tocentry="1">
-     <title>Specialty Character Type</title>
+     <title>Specialty Character Types</title>
      <tgroup cols="3">
       <thead>
        <row>
@@ -2832,29 +2845,39 @@ SELECT * FROM test1 WHERE a;
    <para>
     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:
-    <type>BIT(<replaceable>x</replaceable>)</type> and <type>BIT
-    VARYING(<replaceable>x</replaceable>)</type>; where
-    <replaceable>x</replaceable> is a positive integer.
+    <type>BIT(<replaceable>n</replaceable>)</type> and <type>BIT
+    VARYING(<replaceable>n</replaceable>)</type>, where
+    <replaceable>n</replaceable> is a positive integer.
    </para>
 
    <para>
     <type>BIT</type> type data must match the length
-    <replaceable>x</replaceable> exactly; it is an error to attempt to
-    store shorter or longer bit strings.  <type>BIT VARYING</type> is
+    <replaceable>n</replaceable> exactly; it is an error to attempt to
+    store shorter or longer bit strings.  <type>BIT VARYING</type> data is
     of variable length up to the maximum length
-    <replaceable>x</replaceable>; longer strings will be rejected.
-    <type>BIT</type> without length is equivalent to
-    <literal>BIT(1)</literal>, <type>BIT VARYING</type> without length
+    <replaceable>n</replaceable>; longer strings will be rejected.
+    Writing <type>BIT</type> without a length is equivalent to
+    <literal>BIT(1)</literal>, while <type>BIT VARYING</type> without a length
     specification means unlimited length.
    </para>
 
    <note>
     <para>
-     Prior to <productname>PostgreSQL</> 7.2, <type>BIT</type> type data was
-     zero-padded on the right.  This was changed to comply with the
-     SQL standard.  To implement zero-padded bit strings, a
-     combination of the concatenation operator and the
-     <function>substring</function> function can be used.
+     If one explicitly casts a bit-string value to
+     <type>BIT(<replaceable>n</>)</type>, it will be truncated or
+     zero-padded on the right to be exactly <replaceable>n</> bits,
+     without raising an error.  Similarly,
+     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>
    </note>
 
@@ -2874,9 +2897,16 @@ CREATE TABLE test (a BIT(3), b BIT VARYING(5));
 INSERT INTO test VALUES (B'101', B'00');
 INSERT INTO test VALUES (B'10', B'101');
 <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>
-SELECT SUBSTRING(b FROM 1 FOR 2) FROM test;
 </programlisting>
    </example>
 
index bc9f71e566ea78e38b3eff460497bacdcc2800d5..e64d696f81afc9ee11d966e627d54dae1e90318f 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.4 2002/09/15 13:04:16 petere Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.5 2002/09/18 21:35:20 tgl Exp $ -->
 
 <refentry id="SQL-CREATECAST">
  <refmeta>
 <synopsis>
 CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
     WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtype</replaceable>)
-    [AS ASSIGNMENT]
+    [ AS ASSIGNMENT | AS IMPLICIT ]
 
 CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
     WITHOUT FUNCTION
-    [AS ASSIGNMENT]
+    [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
  </refsynopsisdiv>
   
@@ -49,20 +49,44 @@ SELECT CAST(42 AS text);
   </para>
 
   <para>
-   A cast can be marked <literal>AS ASSIGNMENT</>, which means that it
-   can be invoked implicitly in any context where the conversion it
-   defines is required.  Cast functions not so marked can be invoked
-   only by explicit <literal>CAST</>,
+   By default, a cast can be invoked only by an explicit cast request,
+   that is an explicit <literal>CAST(<replaceable>x</> AS
+   <replaceable>typename</>)</literal>,
    <replaceable>x</><literal>::</><replaceable>typename</>, or
-   <replaceable>typename</>(<replaceable>x</>) constructs.  For
-   example, supposing that <literal>foo.f1</literal> is a column of
+   <replaceable>typename</>(<replaceable>x</>) construct.
+  </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
 <programlisting>
 INSERT INTO foo(f1) VALUES(42);
 </programlisting>
    will be allowed if the cast from type <type>integer</type> to type
    <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.)
   </para>
 
@@ -74,10 +98,11 @@ INSERT INTO foo(f1) VALUES(42);
    all because there are multiple possible interpretations.  A good
    rule of thumb is to make a cast implicitly invokable only for
    information-preserving transformations between types in the same
-   general type category.  For example, <type>int2</type> to
-   <type>int4</type> casts can reasonably be implicit, but be wary of
-   marking <type>int4</type> to <type>text</type> or
-   <type>float8</type> to <type>int4</type> as implicit casts.
+   general type category.  For example, the cast from <type>int2</type> to
+   <type>int4</type> can reasonably be implicit, but the cast from
+   <type>float8</type> to <type>int4</type> should probably be
+   assignment-only.  Cross-type-category casts, such as <type>text</>
+   to <type>int4</>, are best made explicit-only.
   </para>
 
   <para>
@@ -138,7 +163,18 @@ INSERT INTO foo(f1) VALUES(42);
 
      <listitem>
       <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>
      </listitem>
     </varlistentry>
@@ -163,10 +199,10 @@ INSERT INTO foo(f1) VALUES(42);
    data type, returned that data type, and took one argument of a
    different type was automatically a cast function.  This convention has
    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
-   still follow this naming scheme, but they have to be declared as
-   casts explicitly now.
+   still follow this naming scheme, but they have to be shown as
+   casts in <literal>pg_cast</> now.)
   </para>
  </refsect1>
 
@@ -191,7 +227,8 @@ CREATE CAST (text AS int4) WITH FUNCTION int4(text);
   <para>
    The <command>CREATE CAST</command> command conforms to SQL99,
    except that SQL99 does not make provisions for binary compatible
-   types.
+   types.  <literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname>
+   extension, too.
   </para>
  </refsect1>
 
index b7f2b4be71b57b181a4deb8baae6b1fdc5db3cf8..f373cc6e25df86c8c80408365a96fd3406acae44 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.158 2002/09/04 07:16:32 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.159 2002/09/18 21:35:20 tgl Exp $
 -->
 
 <appendix id="release">
@@ -24,6 +24,8 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 <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
 No-autocommit mode is available (set autocommit to off)
 Substantial improvements in functionality for functions returning sets
index 0bfc40b1edf16c8c90867c41b488f9d0fbc26cb7..e6ff564be969ace3e8bd0b9e0c3d85661e0342e1 100644 (file)
@@ -804,13 +804,9 @@ If the non-unknown inputs are not all of the same type category, fail.
 
 <step performance="required">
 <para>
-If one or more non-unknown inputs are of a preferred type in that category,
-resolve as that type.
-</para></step>
-
-<step performance="required">
-<para>
-Otherwise, resolve as the type of the first non-unknown input.
+Choose the first non-unknown input type which is a preferred type in
+that category or allows all the non-unknown inputs to be implicitly
+coerced to it.
 </para></step>
 
 <step performance="required">
@@ -842,15 +838,16 @@ Here, the unknown-type literal <literal>'b'</literal> will be resolved as type t
 
 <para>
 <screen>
-tgl=> SELECT 1.2 AS "Double" UNION SELECT 1;
- Double
---------
-      1
-    1.2
+tgl=> SELECT 1.2 AS "Numeric" UNION SELECT 1;
+ Numeric
+---------
+       1
+     1.2
 (2 rows)
 </screen>
-The literal <literal>1.2</> is of type <type>double precision</>,
-the preferred type in the numeric category, so that type is used.
+The literal <literal>1.2</> is of type <type>numeric</>,
+and the integer value <literal>1</> can be cast implicitly to
+<type>numeric</>, so that type is used.
 </para>
 </example>
 
@@ -858,27 +855,18 @@ the preferred type in the numeric category, so that type is used.
 <title>Type Conversion in a Transposed Union</title>
 
 <para>
-Here the output type of the union is forced to match the type of
-the first clause in the union:
-
 <screen>
-tgl=> SELECT 1 AS "All integers"
+tgl=> SELECT 1 AS "Real"
 tgl-> UNION SELECT CAST('2.2' AS REAL);
- All integers
---------------
-            1
-            2
+ Real
+------
+    1
+  2.2
 (2 rows)
 </screen>
-</para>
-<para>
-Since <type>REAL</type> is not a preferred type, the parser sees no reason
-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.
+Here, since type <type>real</> cannot be implicitly cast to <type>integer</>,
+but <type>integer</> can be implicitly cast to <type>real</>, the union
+result type is resolved as <type>real</>.
 </para>
 </example>
 
index f09d1fc1debb902f5db1b6b202f0364091f620d9..6bc15b8060a3694ec20103945ffdd27941bfa9de 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -51,7 +51,6 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
-#include "parser/parse_target.h"
 #include "rewrite/rewriteRemove.h"
 #include "storage/smgr.h"
 #include "utils/builtins.h"
@@ -1705,17 +1704,16 @@ cookDefault(ParseState *pstate,
        {
                Oid                     type_id = exprType(expr);
 
-               if (type_id != atttypid)
-               {
-                       if (CoerceTargetExpr(pstate, expr, type_id,
-                                                                atttypid, atttypmod, false) == NULL)
-                               elog(ERROR, "Column \"%s\" is of type %s"
-                                        " but default expression is of type %s"
-                                  "\n\tYou will need to rewrite or cast the expression",
-                                        attname,
-                                        format_type_be(atttypid),
-                                        format_type_be(type_id));
-               }
+               if (coerce_to_target_type(expr, type_id,
+                                                                 atttypid, atttypmod,
+                                                                 COERCION_ASSIGNMENT,
+                                                                 COERCE_IMPLICIT_CAST) == NULL)
+                       elog(ERROR, "Column \"%s\" is of type %s"
+                                " but default expression is of type %s"
+                                "\n\tYou will need to rewrite or cast the expression",
+                                attname,
+                                format_type_be(atttypid),
+                                format_type_be(type_id));
        }
 
        /*
index 7b83cf960d97e0e8cb87612854e21f3bd9121fbf..37794645ee58d4f9d9a15c5831fd59f42cb34335 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.55 2002/09/04 20:31:14 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.56 2002/09/18 21:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -95,7 +95,7 @@ AggregateCreate(const char *aggName,
         */
        if (proc->proisstrict && agginitval == NULL)
        {
-               if (!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");
        }
        ReleaseSysCache(tup);
index ba667a26542525903cb51443ca323a23b2c27fc9..b915a02c310ac4b619fccce47ce87e98b97037d5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.93 2002/09/04 20:31:14 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.94 2002/09/18 21:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -369,7 +369,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
                                 format_type_be(rettype));
 
                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",
                                 format_type_be(rettype), format_type_be(restype));
        }
@@ -388,7 +388,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
                if (tlistlen == 1)
                {
                        restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
-                       if (IsBinaryCompatible(restype, rettype))
+                       if (IsBinaryCoercible(restype, rettype))
                                return;
                }
 
@@ -426,7 +426,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
 
                        tletype = exprType(tle->expr);
                        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",
                                         format_type_be(rettype),
                                         format_type_be(tletype),
index a935dae7e6e7f07f9dc09b6ec9cafbc86821736b..f67538625ac6fa62ce547458fe1face42bb4f396 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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
  *       These routines take the parse tree and pick out the
@@ -601,14 +601,11 @@ CreateCast(CreateCastStmt *stmt)
        Oid                     sourcetypeid;
        Oid                     targettypeid;
        Oid                     funcid;
-       HeapTuple       tuple;
+       char            castcontext;
        Relation        relation;
-       Form_pg_proc procstruct;
-
-       Datum           values[Natts_pg_proc];
-       char            nulls[Natts_pg_proc];
-       int                     i;
-
+       HeapTuple       tuple;
+       Datum           values[Natts_pg_cast];
+       char            nulls[Natts_pg_cast];
        ObjectAddress myself,
                                referenced;
 
@@ -648,24 +645,17 @@ CreateCast(CreateCastStmt *stmt)
                         TypeNameToString(stmt->sourcetype),
                         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)
        {
+               Form_pg_proc procstruct;
+
                funcid = LookupFuncNameTypeNames(stmt->func->funcname,
                                                                                 stmt->func->funcargs,
                                                                                 "CreateCast");
 
-               tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+               tuple = SearchSysCache(PROCOID,
+                                                          ObjectIdGetDatum(funcid),
+                                                          0, 0, 0);
                if (!HeapTupleIsValid(tuple))
                        elog(ERROR, "cache lookup of function %u failed", funcid);
 
@@ -687,18 +677,51 @@ CreateCast(CreateCastStmt *stmt)
        }
        else
        {
-               /* indicates binary compatibility */
+               /* indicates binary coercibility */
                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 */
        values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
        values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
        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)
-               nulls[i] = ' ';
+       MemSet(nulls, ' ', Natts_pg_cast);
 
        tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
 
@@ -706,6 +729,7 @@ CreateCast(CreateCastStmt *stmt)
 
        CatalogUpdateIndexes(relation, tuple);
 
+       /* make dependency entries */
        myself.classId = RelationGetRelid(relation);
        myself.objectId = HeapTupleGetOid(tuple);
        myself.objectSubId = 0;
@@ -732,6 +756,7 @@ CreateCast(CreateCastStmt *stmt)
        }
 
        heap_freetuple(tuple);
+
        heap_close(relation, RowExclusiveLock);
 }
 
index 6f0c8438a894519a9464c177ea21fcbd8bae3f56..9660cb61b83e468d5ddb5dab0d0e183f73fbb5ca 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.87 2002/09/04 20:31:15 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.88 2002/09/18 21:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -335,8 +335,8 @@ FuncIndexArgs(IndexInfo *indexInfo,
 
        for (i = 0; i < nargs; i++)
        {
-               if (!IsBinaryCompatible(argTypes[i], true_typeids[i]))
-                       func_error("DefineIndex", funcIndex->funcname, nargs, argTypes,
+               if (!IsBinaryCoercible(argTypes[i], true_typeids[i]))
+                       func_error("DefineIndex", funcIndex->funcname, nargs, true_typeids,
                                           "Index function must be binary-compatible with table datatype");
        }
 
@@ -464,7 +464,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
        opClassId = HeapTupleGetOid(tuple);
        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",
                 NameListToString(attribute->opclass), format_type_be(attrType));
 
@@ -508,7 +508,7 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
                                nexact++;
                                exactOid = opclass->oid;
                        }
-                       else if (IsBinaryCompatible(opclass->opcintype, attrType))
+                       else if (IsBinaryCoercible(attrType, opclass->opcintype))
                        {
                                ncompatible++;
                                compatibleOid = opclass->oid;
index 1a9239c57b94c7f24aa1f9cc8cca8e868ec71fc9..898ca62a6005495b8c0e438e5f2332fa667762ab 100644 (file)
@@ -46,7 +46,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.86 2002/09/04 20:31:18 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.87 2002/09/18 21:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -913,7 +913,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
                         */
                        Oid                     inputType = exprType(aggref->target);
 
-                       if (!IsBinaryCompatible(inputType, aggform->aggtranstype))
+                       if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
                                elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
                                         aggref->aggfnoid);
                }
index 2964085e0aa2958a8d8545f3dd7c552d53e68b10..73e240aca7c2dd24af21f7fb8bc75e3ff85643f8 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.211 2002/09/04 20:31:19 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.212 2002/09/18 21:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -850,6 +850,7 @@ _copyFunc(Func *from)
        newnode->funcid = from->funcid;
        newnode->funcresulttype = from->funcresulttype;
        newnode->funcretset = from->funcretset;
+       newnode->funcformat = from->funcformat;
        /* Do not copy the run-time state, if any */
        newnode->func_fcache = NULL;
 
@@ -931,6 +932,7 @@ _copyRelabelType(RelabelType *from)
        Node_Copy(from, newnode, arg);
        newnode->resulttype = from->resulttype;
        newnode->resulttypmod = from->resulttypmod;
+       newnode->relabelformat = from->relabelformat;
 
        return newnode;
 }
@@ -2634,7 +2636,7 @@ _copyCreateCastStmt(CreateCastStmt *from)
        Node_Copy(from, newnode, sourcetype);
        Node_Copy(from, newnode, targettype);
        Node_Copy(from, newnode, func);
-       newnode->implicit = from->implicit;
+       newnode->context = from->context;
 
        return newnode;
 }
index 7f677c0837c09359fe50fcb09bda91917a46737f..8c5d6a0337ab3ce671043e4887e81438523604e3 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.158 2002/09/02 02:13:01 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.159 2002/09/18 21:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -217,6 +217,15 @@ _equalFunc(Func *a, Func *b)
                return false;
        if (a->funcretset != b->funcretset)
                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 */
 
        return true;
@@ -302,6 +311,14 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
                return false;
        if (a->resulttypmod != b->resulttypmod)
                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;
 }
 
@@ -1475,7 +1492,7 @@ _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
                return false;
        if (!equal(a->func, b->func))
                return false;
-       if (a->implicit != b->implicit)
+       if (a->context != b->context)
                return false;
 
        return true;
index 8363fccfa6e40fc33b0e0f3aef6e9058ca5feee6..b92011445e3467f40a56c3d2ad74f98ed9bde8ae 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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"
 
@@ -215,13 +215,14 @@ makeAlias(const char *aliasname, List *colnames)
  *       creates a RelabelType node
  */
 RelabelType *
-makeRelabelType(Node *arg, Oid rtype, int32 rtypmod)
+makeRelabelType(Node *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
 {
        RelabelType *r = makeNode(RelabelType);
 
        r->arg = arg;
        r->resulttype = rtype;
        r->resulttypmod = rtypmod;
+       r->relabelformat = rformat;
 
        return r;
 }
index 8873c4e3d2c998c52e5c700220ec6fd258407670..fde42291691cd8d0acb8270b2cd12f1bafddbe3b 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -860,10 +860,11 @@ static void
 _outFunc(StringInfo str, Func *node)
 {
        appendStringInfo(str,
-                                  " FUNC :funcid %u :funcresulttype %u :funcretset %s ",
+               " FUNC :funcid %u :funcresulttype %u :funcretset %s :funcformat %d ",
                                         node->funcid,
                                         node->funcresulttype,
-                                        booltostr(node->funcretset));
+                                        booltostr(node->funcretset),
+                                        (int) node->funcformat);
 }
 
 /*
@@ -914,9 +915,11 @@ _outRelabelType(StringInfo str, RelabelType *node)
 {
        appendStringInfo(str, " RELABELTYPE :arg ");
        _outNode(str, node->arg);
-
-       appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
-                                        node->resulttype, node->resulttypmod);
+       appendStringInfo(str,
+                                        " :resulttype %u :resulttypmod %d :relabelformat %d ",
+                                        node->resulttype,
+                                        node->resulttypmod,
+                                        (int) node->relabelformat);
 }
 
 /*
index 14edd8e3d13eb6a2d04ff6fcf908a68bb13f33b1..a4f0c81fa1eeec7e2e2f90f8467fc50fbd77a505 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -1129,6 +1129,10 @@ _readFunc(void)
        token = pg_strtok(&length); /* now read it */
        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;
 
        return local_node;
@@ -1335,6 +1339,10 @@ _readRelabelType(void)
        token = pg_strtok(&length); /* get resulttypmod */
        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;
 }
 
index 5595e1aec9929897d8ecb83fb9a4be2d82b83204..cfd20e8f488f91b9170c1b712ac49ae643a846e1 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.122 2002/09/04 20:31:20 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.123 2002/09/18 21:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -825,32 +825,15 @@ match_clause_to_indexkey(RelOptInfo *rel,
  * is whether the operator has a commutator operator that matches
  * 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.
- * Note that the returned OID will be different from the one in the given
- * expression if we used a binary-compatible substitution.     Also note that
- * 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.
+ * (Formerly, this routine might return a binary-compatible operator
+ * rather than the original one, but that kluge is history.)
  */
 Oid
 indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
 {
        Oid                     expr_op = ((Oper *) clause->oper)->opno;
-       Oid                     commuted_op,
-                               new_op;
-       Operator        oldoptup;
-       Form_pg_operator oldopform;
-       char       *opname;
-       Oid                     ltype,
-                               rtype,
-                               indexkeytype;
+       Oid                     commuted_op;
 
        /* Get the commuted operator if necessary */
        if (indexkey_on_left)
@@ -860,83 +843,10 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
        if (commuted_op == 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))
                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;
 }
 
index fc33d5296ad7fdffc317711b0560ec23e11d62d0..350c761165b4ff65505676f03591ac2d232c7f2e 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.40 2002/09/04 20:31:20 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.41 2002/09/18 21:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -520,6 +520,7 @@ build_index_pathkeys(Query *root,
                funcnode->funcid = index->indproc;
                funcnode->funcresulttype = get_func_rettype(index->indproc);
                funcnode->funcretset = false;   /* can never be a set */
+               funcnode->funcformat = COERCE_DONTCARE; /* to match any user expr */
                funcnode->func_fcache = NULL;
 
                while (*indexkeys != 0)
index da3568bbd7d8deffbe9eba454016825e477a7b0a..9cdbcc2e5e548206392263f54ef63d5a87341902 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.118 2002/09/04 20:31:21 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.119 2002/09/18 21:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1027,8 +1027,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
                Expr       *clause = (Expr *) lfirst(i);
                Expr       *newclause;
                List       *leftvarnos;
-               Oid                     opclass,
-                                       newopno;
+               Oid                     opclass;
 
                if (!is_opclause((Node *) clause) || length(clause->args) != 2)
                        elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
@@ -1061,23 +1060,13 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
                                                                                                           index,
                                                                                                           &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);
 
                /*
                 * Finally, check to see if index is lossy for this operator. If
                 * 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,
                                                                   copyObject((Node *) clause));
        }
index 5b930e2b5e62ed819a6e008778672f890ce94664..95687cb0d0d0d09eed4ce197f0223888e4d2926c 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.56 2002/09/04 20:31:22 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57 2002/09/18 21:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -187,8 +187,9 @@ expand_targetlist(List *tlist, int command_type,
                                                                                                  false,                /* not a set */
                                                                                                  false);
                                        if (!att_tup->attisdropped)
-                                               new_expr = coerce_type_constraints(NULL, new_expr,
-                                                                                                                atttype, false);
+                                               new_expr = coerce_type_constraints(new_expr,
+                                                                                                                  atttype,
+                                                                                                                  COERCE_IMPLICIT_CAST);
                                        break;
                                case CMD_UPDATE:
                                        /* Insert NULLs for dropped columns */
index 414e26c54cbeef538205d4ef7e31f1171f8f3b98..914b0eee618cd1d4bbde35d194f8912c80d08e92 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.79 2002/09/11 14:48:55 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.80 2002/09/18 21:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -420,8 +420,7 @@ generate_setop_tlist(List *colTypes, int flag,
                }
                else
                {
-                       expr = coerce_to_common_type(NULL,
-                                                                                expr,
+                       expr = coerce_to_common_type(expr,
                                                                                 colType,
                                                                                 "UNION/INTERSECT/EXCEPT");
                        colTypmod = -1;
index 97b242b9b6bc46d3d773c918459eb040f3d4d818..663ae22d9429c0990743e8df57f98ff3ebab1b89 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.248 2002/09/04 20:31:22 momjian Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.249 2002/09/18 21:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2565,24 +2565,20 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
                        given_type_id = exprType(expr);
                        expected_type_id = (Oid) lfirsti(paramtypes);
 
-                       if (given_type_id != expected_type_id)
-                       {
-                               expr = CoerceTargetExpr(pstate,
-                                                                               expr,
-                                                                               given_type_id,
-                                                                               expected_type_id,
-                                                                               -1,
-                                                                               false);
-
-                               if (!expr)
-                                       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",
-                                                i,
-                                                format_type_be(given_type_id),
-                                                format_type_be(expected_type_id));
-                       }
+                       expr = coerce_to_target_type(expr, given_type_id,
+                                                                                expected_type_id, -1,
+                                                                                COERCION_ASSIGNMENT,
+                                                                                COERCE_IMPLICIT_CAST);
+
+                       if (expr == NULL)
+                               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",
+                                        i,
+                                        format_type_be(given_type_id),
+                                        format_type_be(expected_type_id));
 
                        fix_opids(expr);
+
                        lfirst(l) = expr;
 
                        paramtypes = lnext(paramtypes);
index d038cdd46e7b7486f8fa460b2f3c37896e5eeffd..43597306d4410a67c520a26a2e02af25e2f579f1 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -161,8 +161,8 @@ static void doNegateFloat(Value *v);
 %type <list>   createdb_opt_list, copy_opt_list
 %type <defelt> createdb_opt_item, copy_opt_item
 
-%type <ival>   opt_lock, lock_type
-%type <boolean>        opt_force, opt_or_replace, opt_assignment
+%type <ival>   opt_lock, lock_type, cast_context
+%type <boolean>        opt_force, opt_or_replace
 
 %type <list>   user_list
 
@@ -349,7 +349,7 @@ static void doNegateFloat(Value *v);
 
        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,
        INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
        INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
@@ -3230,29 +3230,30 @@ any_operator:
  *****************************************************************************/
 
 CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
-                                       WITH FUNCTION function_with_argtypes opt_assignment
+                                       WITH FUNCTION function_with_argtypes cast_context
                                {
                                        CreateCastStmt *n = makeNode(CreateCastStmt);
                                        n->sourcetype = $4;
                                        n->targettype = $6;
                                        n->func = (FuncWithArgs *) $10;
-                                       n->implicit = $11;
+                                       n->context = (CoercionContext) $11;
                                        $$ = (Node *)n;
                                }
                        | CREATE CAST '(' ConstTypename AS ConstTypename ')'
-                                       WITHOUT FUNCTION opt_assignment
+                                       WITHOUT FUNCTION cast_context
                                {
                                        CreateCastStmt *n = makeNode(CreateCastStmt);
                                        n->sourcetype = $4;
                                        n->targettype = $6;
                                        n->func = NULL;
-                                       n->implicit = $10;
+                                       n->context = (CoercionContext) $10;
                                        $$ = (Node *)n;
                                }
                ;
 
-opt_assignment:  AS ASSIGNMENT                                 { $$ = TRUE; }
-               | /*EMPTY*/                                                             { $$ = FALSE; }
+cast_context:  AS IMPLICIT_P                                   { $$ = COERCION_IMPLICIT; }
+               | AS ASSIGNMENT                                                 { $$ = COERCION_ASSIGNMENT; }
+               | /*EMPTY*/                                                             { $$ = COERCION_EXPLICIT; }
                ;
 
 
@@ -7061,6 +7062,7 @@ unreserved_keyword:
                        | HOUR_P
                        | IMMEDIATE
                        | IMMUTABLE
+                       | IMPLICIT_P
                        | INCREMENT
                        | INDEX
                        | INHERITS
index 9a3064ad661596bea9b1ce1287679dc4117f6dab..305ed8601812e1b5ad4e619baeccebd9136d1fec 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.126 2002/08/27 04:55:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.127 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -147,6 +147,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"ilike", ILIKE},
        {"immediate", IMMEDIATE},
        {"immutable", IMMUTABLE},
+       {"implicit", IMPLICIT_P},
        {"in", IN_P},
        {"increment", INCREMENT},
        {"index", INDEX},
index a46ff5e2fcd76958fdfc600d9768a9351f89a113..245c0ba422bab57987c85830876c8158c9947898 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.97 2002/09/04 20:31:23 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -872,20 +872,24 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar)
         * typmod is not same as input.
         */
        if (l_colvar->vartype != outcoltype)
-               l_node = coerce_type(NULL, (Node *) l_colvar, l_colvar->vartype,
-                                                        outcoltype, outcoltypmod, false);
+               l_node = coerce_type((Node *) l_colvar, l_colvar->vartype,
+                                                        outcoltype,
+                                                        COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
        else if (l_colvar->vartypmod != outcoltypmod)
                l_node = (Node *) makeRelabelType((Node *) l_colvar,
-                                                                                 outcoltype, outcoltypmod);
+                                                                                 outcoltype, outcoltypmod,
+                                                                                 COERCE_IMPLICIT_CAST);
        else
                l_node = (Node *) l_colvar;
 
        if (r_colvar->vartype != outcoltype)
-               r_node = coerce_type(NULL, (Node *) r_colvar, r_colvar->vartype,
-                                                        outcoltype, outcoltypmod, false);
+               r_node = coerce_type((Node *) r_colvar, r_colvar->vartype,
+                                                        outcoltype,
+                                                        COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
        else if (r_colvar->vartypmod != outcoltypmod)
                r_node = (Node *) makeRelabelType((Node *) r_colvar,
-                                                                                 outcoltype, outcoltypmod);
+                                                                                 outcoltype, outcoltypmod,
+                                                                                 COERCE_IMPLICIT_CAST);
        else
                r_node = (Node *) r_colvar;
 
index d57e18f2324e500a7f60adcd81e8ba87a85f4af0..c0081133eb3a5116650ffa0421e4ffcabec263d1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.83 2002/09/04 20:31:23 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.84 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "parser/parse_func.h"
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
+static Node *coerce_type_typmod(Node *node,
+                                                               Oid targetTypeId, int32 targetTypMod,
+                                                               CoercionForm cformat);
 static Oid     PreferredType(CATEGORY category, Oid type);
 static bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
-                                         bool isExplicit,
-                                         Oid *funcid);
-static Oid     find_typmod_coercion_function(Oid typeId);
-static Node *build_func_call(Oid funcid, Oid rettype, List *args);
+                                                                 CoercionContext ccontext,
+                                                                 Oid *funcid);
+static Node *build_func_call(Oid funcid, Oid rettype, List *args,
+                                                        CoercionForm fformat);
+
+
+/*
+ * coerce_to_target_type()
+ *             Convert an expression to a target type and typmod.
+ *
+ * This is the general-purpose entry point for arbitrary type coercion
+ * operations.  Direct use of the component operations can_coerce_type,
+ * coerce_type, and coerce_type_typmod should be restricted to special
+ * cases (eg, when the conversion is expected to succeed).
+ *
+ * Returns the possibly-transformed expression tree, or NULL if the type
+ * conversion is not possible.  (We do this, rather than elog'ing directly,
+ * so that callers can generate custom error messages indicating context.)
+ *
+ * expr - input expression tree (already transformed by transformExpr)
+ * exprtype - result type of expr
+ * targettype - desired result type
+ * targettypmod - desired result typmod
+ * ccontext, cformat - context indicators to control coercions
+ */
+Node *
+coerce_to_target_type(Node *expr, Oid exprtype,
+                                         Oid targettype, int32 targettypmod,
+                                         CoercionContext ccontext,
+                                         CoercionForm cformat)
+{
+       if (can_coerce_type(1, &exprtype, &targettype, ccontext))
+               expr = coerce_type(expr, exprtype, targettype,
+                                                  ccontext, cformat);
+       /*
+        * String hacks to get transparent conversions for char and varchar:
+        * if a coercion to text is available, use it for forced coercions to
+        * char(n) or varchar(n).
+        *
+        * This is pretty grotty, but seems easier to maintain than providing
+        * entries in pg_cast that parallel all the ones for text.
+        */
+       else if (ccontext >= COERCION_ASSIGNMENT &&
+                        (targettype == BPCHAROID || targettype == VARCHAROID))
+       {
+               Oid                     text_id = TEXTOID;
+
+               if (can_coerce_type(1, &exprtype, &text_id, ccontext))
+               {
+                       expr = coerce_type(expr, exprtype, text_id,
+                                                          ccontext, cformat);
+                       /* Need a RelabelType if no typmod coercion is performed */
+                       if (targettypmod < 0)
+                               expr = (Node *) makeRelabelType(expr, targettype, -1,
+                                                                                               cformat);
+               }
+               else
+                       expr = NULL;
+       }
+       else
+               expr = NULL;
+
+       /*
+        * If the target is a fixed-length type, it may need a length coercion
+        * as well as a type coercion.
+        */
+       if (expr != NULL)
+               expr = coerce_type_typmod(expr, targettype, targettypmod, cformat);
+
+       return expr;
+}
 
 
 /*
  * coerce_type()
- *             Convert a function argument to a different type.
+ *             Convert an expression to a different type.
  *
  * The caller should already have determined that the coercion is possible;
  * see can_coerce_type.
+ *
+ * No coercion to a typmod (length) is performed here.  The caller must
+ * call coerce_type_typmod as well, if a typmod constraint is wanted.
+ * (But if the target type is a domain, it may internally contain a
+ * typmod constraint, which will be applied inside coerce_type_constraints.)
  */
 Node *
-coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
-                       Oid targetTypeId, int32 atttypmod, bool isExplicit)
+coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
+                       CoercionContext ccontext, CoercionForm cformat)
 {
        Node       *result;
        Oid                     funcId;
@@ -68,7 +144,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                 * example, int4's typinput function will reject "1.2", whereas
                 * float-to-int type conversion will round to integer.
                 *
-                * XXX if the typinput function is not cachable, we really ought to
+                * XXX if the typinput function is not immutable, we really ought to
                 * postpone evaluation of the function call until runtime. But
                 * there is no way to represent a typinput function call as an
                 * expression tree, because C-string values are not Datums. (XXX
@@ -91,28 +167,31 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                                                                                                           con->constvalue));
 
                        /*
-                        * If target is a domain, use the typmod it applies to the
-                        * base type.  Note that we call stringTypeDatum using the
-                        * domain's pg_type row, though.  This works because the
-                        * domain row has the same typinput and typelem as the base
-                        * type --- ugly...
+                        * We pass typmod -1 to the input routine, primarily because
+                        * existing input routines follow implicit-coercion semantics
+                        * for length checks, which is not always what we want here.
+                        * Any length constraint will be applied later by our caller.
+                        *
+                        * Note that we call stringTypeDatum using the domain's pg_type
+                        * row, if it's a domain.  This works because the domain row has
+                        * the same typinput and typelem as the base type --- ugly...
                         */
-                       if (targetTyptype == 'd')
-                               atttypmod = getBaseTypeMod(targetTypeId, atttypmod);
-
-                       newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
+                       newcon->constvalue = stringTypeDatum(targetType, val, -1);
                        pfree(val);
                }
 
                result = (Node *) newcon;
 
-               /*
-                * If target is a domain, apply constraints (except for typmod,
-                * which we assume the input routine took care of).
-                */
+               /* If target is a domain, apply constraints. */
                if (targetTyptype == 'd')
-                       result = coerce_type_constraints(pstate, result, targetTypeId,
-                                                                                        false);
+               {
+                       result = coerce_type_constraints(result, targetTypeId,
+                                                                                        cformat);
+                       /* We might now need a RelabelType. */
+                       if (exprType(result) != targetTypeId)
+                               result = (Node *) makeRelabelType(result, targetTypeId, -1,
+                                                                                                 cformat);
+               }
 
                ReleaseSysCache(targetType);
        }
@@ -120,9 +199,10 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                         targetTypeId == ANYARRAYOID)
        {
                /* assume can_coerce_type verified that implicit coercion is okay */
+               /* NB: we do NOT want a RelabelType here */
                result = node;
        }
-       else if (find_coercion_pathway(targetTypeId, inputTypeId, isExplicit,
+       else if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
                                                                   &funcId))
        {
                if (OidIsValid(funcId))
@@ -135,7 +215,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                         */
                        Oid                     baseTypeId = getBaseType(targetTypeId);
 
-                       result = build_func_call(funcId, baseTypeId, makeList1(node));
+                       result = build_func_call(funcId, baseTypeId, makeList1(node),
+                                                                        cformat);
 
                        /*
                         * If domain, test against domain constraints and relabel with
@@ -143,9 +224,10 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                         */
                        if (targetTypeId != baseTypeId)
                        {
-                               result = coerce_type_constraints(pstate, result,
-                                                                                                targetTypeId, true);
-                               result = (Node *) makeRelabelType(result, targetTypeId, -1);
+                               result = coerce_type_constraints(result, targetTypeId,
+                                                                                                cformat);
+                               result = (Node *) makeRelabelType(result, targetTypeId, -1,
+                                                                                                 cformat);
                        }
 
                        /*
@@ -179,8 +261,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                         * Also, domains may have value restrictions beyond the base type
                         * that must be accounted for.
                         */
-                       result = coerce_type_constraints(pstate, node,
-                                                                                        targetTypeId, true);
+                       result = coerce_type_constraints(node, targetTypeId,
+                                                                                        cformat);
 
                        /*
                         * XXX could we label result with exprTypmod(node) instead of
@@ -189,7 +271,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                         * typmod, which is likely but not certain (wrong if target is
                         * a domain, in any case).
                         */
-                       result = (Node *) makeRelabelType(result, targetTypeId, -1);
+                       result = (Node *) makeRelabelType(result, targetTypeId, -1,
+                                                                                         cformat);
                }
        }
        else if (typeInheritsFrom(inputTypeId, targetTypeId))
@@ -199,7 +282,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
                 * except relabel the type.  This is binary compatibility for
                 * complex types.
                 */
-               result = (Node *) makeRelabelType(node, targetTypeId, -1);
+               result = (Node *) makeRelabelType(node, targetTypeId, -1,
+                                                                                 cformat);
        }
        else
        {
@@ -215,15 +299,14 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 
 /*
  * can_coerce_type()
- *             Can input_typeids be coerced to func_typeids?
+ *             Can input_typeids be coerced to target_typeids?
  *
- * We must be told whether this is an implicit or explicit coercion
- * (explicit being a CAST construct, explicit function call, etc).
- * We will accept a wider set of coercion cases for an explicit coercion.
+ * We must be told the context (CAST construct, assignment, implicit coercion)
+ * as this determines the set of available casts.
  */
 bool
-can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
-                               bool isExplicit)
+can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
+                               CoercionContext ccontext)
 {
        int                     i;
 
@@ -231,7 +314,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
        for (i = 0; i < nargs; i++)
        {
                Oid                     inputTypeId = input_typeids[i];
-               Oid                     targetTypeId = func_typeids[i];
+               Oid                     targetTypeId = target_typeids[i];
                Oid                     funcId;
 
                /* no problem if same type */
@@ -278,7 +361,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
 
                        /*
                         * Otherwise reject; this assumes there are no explicit
-                        * coercions to ANYARRAY.  If we don't reject then
+                        * coercion paths to ANYARRAY.  If we don't reject then
                         * parse_coerce would have to repeat the above test.
                         */
                        return false;
@@ -288,7 +371,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
                 * If pg_cast shows that we can coerce, accept.  This test now
                 * covers both binary-compatible and coercion-function cases.
                 */
-               if (find_coercion_pathway(targetTypeId, inputTypeId, isExplicit,
+               if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
                                                                  &funcId))
                        continue;
 
@@ -312,10 +395,12 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
  * Create an expression tree to enforce the constraints (if any)
  * that should be applied by the type. Currently this is only
  * interesting for domain types.
+ *
+ * NOTE: result tree is not guaranteed to show the correct exprType() for
+ * the domain; it may show the base type.  Caller must relabel if needed.
  */
 Node *
-coerce_type_constraints(ParseState *pstate, Node *arg,
-                                               Oid typeId, bool applyTypmod)
+coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
 {
        char       *notNull = NULL;
        int32           typmod = -1;
@@ -356,8 +441,8 @@ coerce_type_constraints(ParseState *pstate, Node *arg,
        /*
         * If domain applies a typmod to its base type, do length coercion.
         */
-       if (applyTypmod && typmod >= 0)
-               arg = coerce_type_typmod(pstate, arg, typeId, typmod);
+       if (typmod >= 0)
+               arg = coerce_type_typmod(arg, typeId, typmod, cformat);
 
        /*
         * Only need to add one NOT NULL check regardless of how many domains
@@ -380,8 +465,9 @@ coerce_type_constraints(ParseState *pstate, Node *arg,
 }
 
 
-/* coerce_type_typmod()
- * Force a value to a particular typmod, if meaningful and possible.
+/*
+ * coerce_type_typmod()
+ *             Force a value to a particular typmod, if meaningful and possible.
  *
  * This is applied to values that are going to be stored in a relation
  * (where we have an atttypmod for the column) as well as values being
@@ -394,33 +480,65 @@ coerce_type_constraints(ParseState *pstate, Node *arg,
  * coercion for a domain is considered to be part of the type coercion
  * needed to produce the domain value in the first place.  So, no getBaseType.
  */
-Node *
-coerce_type_typmod(ParseState *pstate, Node *node,
-                                  Oid targetTypeId, int32 atttypmod)
+static Node *
+coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
+                                  CoercionForm cformat)
 {
        Oid                     funcId;
+       int                     nargs;
 
        /*
         * A negative typmod is assumed to mean that no coercion is wanted.
         */
-       if (atttypmod < 0 || atttypmod == exprTypmod(node))
+       if (targetTypMod < 0 || targetTypMod == exprTypmod(node))
                return node;
 
-       funcId = find_typmod_coercion_function(targetTypeId);
+       funcId = find_typmod_coercion_function(targetTypeId, &nargs);
 
        if (OidIsValid(funcId))
        {
+               List       *args;
                Const      *cons;
+               Node       *fcall;
 
+               /* Pass given value, plus target typmod as an int4 constant */
                cons = makeConst(INT4OID,
                                                 sizeof(int32),
-                                                Int32GetDatum(atttypmod),
+                                                Int32GetDatum(targetTypMod),
                                                 false,
                                                 true,
                                                 false,
                                                 false);
 
-               node = build_func_call(funcId, targetTypeId, makeList2(node, cons));
+               args = makeList2(node, cons);
+
+               if (nargs == 3)
+               {
+                       /* Pass it a boolean isExplicit parameter, too */
+                       cons = makeConst(BOOLOID,
+                                                        sizeof(bool),
+                                                        BoolGetDatum(cformat != COERCE_IMPLICIT_CAST),
+                                                        false,
+                                                        true,
+                                                        false,
+                                                        false);
+
+                       args = lappend(args, cons);
+               }
+
+               fcall = build_func_call(funcId, targetTypeId, args, cformat);
+
+               /*
+                * If the input is a constant, apply the length coercion
+                * function now instead of delaying to runtime.
+                *
+                * See the comments for the similar case in coerce_type.
+                */
+               if (node && IsA(node, Const) &&
+                       !((Const *) node)->constisnull)
+                       node = eval_const_expressions(fcall);
+               else
+                       node = fcall;
        }
 
        return node;
@@ -437,19 +555,19 @@ Node *
 coerce_to_boolean(Node *node, const char *constructName)
 {
        Oid                     inputTypeId = exprType(node);
-       Oid                     targetTypeId;
 
        if (inputTypeId != BOOLOID)
        {
-               targetTypeId = BOOLOID;
-               if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false))
+               node = coerce_to_target_type(node, inputTypeId,
+                                                                        BOOLOID, -1,
+                                                                        COERCION_ASSIGNMENT,
+                                                                        COERCE_IMPLICIT_CAST);
+               if (node == NULL)
                {
                        /* translator: first %s is name of a SQL construct, eg WHERE */
                        elog(ERROR, "Argument of %s must be type boolean, not type %s",
                                 constructName, format_type_be(inputTypeId));
                }
-               node = coerce_type(NULL, node, inputTypeId, targetTypeId, -1,
-                                                  false);
        }
 
        if (expression_returns_set(node))
@@ -472,12 +590,6 @@ coerce_to_boolean(Node *node, const char *constructName)
  * in the list will be preferred if there is doubt.
  * 'context' is a phrase to use in the error message if we fail to select
  * a usable type.
- *
- * XXX this code is WRONG, since (for example) given the input (int4,int8)
- * it will select int4, whereas according to SQL92 clause 9.3 the correct
- * answer is clearly int8.     To fix this we need a notion of a promotion
- * hierarchy within type categories --- something more complete than
- * just a single preferred type.
  */
 Oid
 select_common_type(List *typeids, const char *context)
@@ -511,12 +623,13 @@ select_common_type(List *typeids, const char *context)
                                elog(ERROR, "%s types '%s' and '%s' not matched",
                                  context, format_type_be(ptype), format_type_be(ntype));
                        }
-                       else if (IsPreferredType(pcategory, ntype)
-                                        && !IsPreferredType(pcategory, ptype)
-                                        && can_coerce_type(1, &ptype, &ntype, false))
+                       else if (!IsPreferredType(pcategory, ptype) &&
+                                        can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
+                                        !can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT))
                        {
                                /*
-                                * new one is preferred and can convert? then take it...
+                                * take new type if can coerce to it implicitly but not the
+                                * other way; but if we have a preferred type, stay on it.
                                 */
                                ptype = ntype;
                                pcategory = TypeCategory(ptype);
@@ -547,26 +660,20 @@ select_common_type(List *typeids, const char *context)
  * This is used following select_common_type() to coerce the individual
  * expressions to the desired type.  'context' is a phrase to use in the
  * error message if we fail to coerce.
- *
- * NOTE: pstate may be NULL.
  */
 Node *
-coerce_to_common_type(ParseState *pstate, Node *node,
-                                         Oid targetTypeId,
-                                         const char *context)
+coerce_to_common_type(Node *node, Oid targetTypeId, const char *context)
 {
        Oid                     inputTypeId = exprType(node);
 
        if (inputTypeId == targetTypeId)
                return node;                    /* no work */
-       if (can_coerce_type(1, &inputTypeId, &targetTypeId, false))
-               node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
-                                                  false);
+       if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
+               node = coerce_type(node, inputTypeId, targetTypeId,
+                                                  COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
        else
-       {
                elog(ERROR, "%s unable to convert to type %s",
                         context, format_type_be(targetTypeId));
-       }
        return node;
 }
 
@@ -708,8 +815,6 @@ PreferredType(CATEGORY category, Oid type)
                                type == REGCLASSOID ||
                                type == REGTYPEOID)
                                result = OIDOID;
-                       else if (type == NUMERICOID)
-                               result = NUMERICOID;
                        else
                                result = FLOAT8OID;
                        break;
@@ -742,49 +847,52 @@ PreferredType(CATEGORY category, Oid type)
 }      /* PreferredType() */
 
 
-/* IsBinaryCompatible()
- *             Check if two types are binary-compatible.
+/* IsBinaryCoercible()
+ *             Check if srctype is binary-coercible to targettype.
  *
  * This notion allows us to cheat and directly exchange values without
  * going through the trouble of calling a conversion function.
  *
- * As of 7.3, binary compatibility isn't hardwired into the code anymore.
- * We consider two types binary-compatible if there is an implicit,
- * no-function-needed pg_cast entry.  NOTE that we assume that such
- * entries are symmetric, ie, it doesn't matter which type we consider
- * source and which target.  (cf. checks in opr_sanity regression test)
+ * As of 7.3, binary coercibility isn't hardwired into the code anymore.
+ * We consider two types binary-coercible if there is an implicitly
+ * invokable, no-function-needed pg_cast entry.
+ *
+ * This function replaces IsBinaryCompatible(), which was an inherently
+ * symmetric test.  Since the pg_cast entries aren't necessarily symmetric,
+ * the order of the operands is now significant.
  */
 bool
-IsBinaryCompatible(Oid type1, Oid type2)
+IsBinaryCoercible(Oid srctype, Oid targettype)
 {
        HeapTuple       tuple;
        Form_pg_cast castForm;
        bool            result;
 
        /* Fast path if same type */
-       if (type1 == type2)
+       if (srctype == targettype)
                return true;
 
        /* Perhaps the types are domains; if so, look at their base types */
-       if (OidIsValid(type1))
-               type1 = getBaseType(type1);
-       if (OidIsValid(type2))
-               type2 = getBaseType(type2);
+       if (OidIsValid(srctype))
+               srctype = getBaseType(srctype);
+       if (OidIsValid(targettype))
+               targettype = getBaseType(targettype);
 
        /* Somewhat-fast path if same base type */
-       if (type1 == type2)
+       if (srctype == targettype)
                return true;
 
        /* Else look in pg_cast */
        tuple = SearchSysCache(CASTSOURCETARGET,
-                                                  ObjectIdGetDatum(type1),
-                                                  ObjectIdGetDatum(type2),
+                                                  ObjectIdGetDatum(srctype),
+                                                  ObjectIdGetDatum(targettype),
                                                   0, 0);
        if (!HeapTupleIsValid(tuple))
                return false;                   /* no cast */
        castForm = (Form_pg_cast) GETSTRUCT(tuple);
 
-       result = (castForm->castfunc == InvalidOid) && castForm->castimplicit;
+       result = (castForm->castfunc == InvalidOid &&
+                         castForm->castcontext == COERCION_CODE_IMPLICIT);
 
        ReleaseSysCache(tuple);
 
@@ -796,12 +904,15 @@ IsBinaryCompatible(Oid type1, Oid type2)
  * find_coercion_pathway
  *             Look for a coercion pathway between two types.
  *
- * If we find a matching entry in pg_cast, return TRUE, and set *funcid
+ * ccontext determines the set of available casts.
+ *
+ * If we find a suitable entry in pg_cast, return TRUE, and set *funcid
  * to the castfunc value (which may be InvalidOid for a binary-compatible
  * coercion).
  */
 static bool
-find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
+find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
+                                         CoercionContext ccontext,
                                          Oid *funcid)
 {
        bool            result = false;
@@ -828,8 +939,29 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
        if (HeapTupleIsValid(tuple))
        {
                Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
+               CoercionContext castcontext;
+
+               /* convert char value for castcontext to CoercionContext enum */
+               switch (castForm->castcontext)
+               {
+                       case COERCION_CODE_IMPLICIT:
+                               castcontext = COERCION_IMPLICIT;
+                               break;
+                       case COERCION_CODE_ASSIGNMENT:
+                               castcontext = COERCION_ASSIGNMENT;
+                               break;
+                       case COERCION_CODE_EXPLICIT:
+                               castcontext = COERCION_EXPLICIT;
+                               break;
+                       default:
+                               elog(ERROR, "find_coercion_pathway: bogus castcontext %c",
+                                        castForm->castcontext);
+                               castcontext = 0;        /* keep compiler quiet */
+                               break;
+               }
 
-               if (isExplicit || castForm->castimplicit)
+               /* Rely on ordering of enum for correct behavior here */
+               if (ccontext >= castcontext)
                {
                        *funcid = castForm->castfunc;
                        result = true;
@@ -850,30 +982,59 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
  * the type requires coercion to its own length and that the said
  * function should be invoked to do that.
  *
+ * Alternatively, the length-coercing function may have the signature
+ * (targettype, int4, bool).  On success, *nargs is set to report which
+ * signature we found.
+ *
  * "bpchar" (ie, char(N)) and "numeric" are examples of such types.
  *
+ * If the given type is a varlena array type, we do not look for a coercion
+ * function associated directly with the array type, but instead look for
+ * one associated with the element type.  If one exists, we report
+ * array_length_coerce() as the coercion function to use.
+ *
  * This mechanism may seem pretty grotty and in need of replacement by
  * something in pg_cast, but since typmod is only interesting for datatypes
  * that have special handling in the grammar, there's not really much
  * percentage in making it any easier to apply such coercions ...
  */
-static Oid
-find_typmod_coercion_function(Oid typeId)
+Oid
+find_typmod_coercion_function(Oid typeId, int *nargs)
 {
        Oid                     funcid = InvalidOid;
+       bool            isArray = false;
        Type            targetType;
+       Form_pg_type typeForm;
        char       *typname;
        Oid                     typnamespace;
        Oid                     oid_array[FUNC_MAX_ARGS];
        HeapTuple       ftup;
 
        targetType = typeidType(typeId);
-       typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
-       typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace;
+       typeForm = (Form_pg_type) GETSTRUCT(targetType);
 
+       /* Check for a varlena array type (and not a domain) */
+       if (typeForm->typelem != InvalidOid &&
+               typeForm->typlen == -1 &&
+               typeForm->typtype != 'd')
+       {
+               /* Yes, switch our attention to the element type */
+               typeId = typeForm->typelem;
+               ReleaseSysCache(targetType);
+               targetType = typeidType(typeId);
+               typeForm = (Form_pg_type) GETSTRUCT(targetType);
+               isArray = true;
+       }
+
+       /* Function name is same as type internal name, and in same namespace */
+       typname = NameStr(typeForm->typname);
+       typnamespace = typeForm->typnamespace;
+
+       /* First look for parameters (type, int4) */
        MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
        oid_array[0] = typeId;
        oid_array[1] = INT4OID;
+       *nargs = 2;
 
        ftup = SearchSysCache(PROCNAMENSP,
                                                  CStringGetDatum(typname),
@@ -894,8 +1055,45 @@ find_typmod_coercion_function(Oid typeId)
                ReleaseSysCache(ftup);
        }
 
+       if (!OidIsValid(funcid))
+       {
+               /* Didn't find a function, so now try (type, int4, bool) */
+               oid_array[2] = BOOLOID;
+               *nargs = 3;
+
+               ftup = SearchSysCache(PROCNAMENSP,
+                                                         CStringGetDatum(typname),
+                                                         Int16GetDatum(3),
+                                                         PointerGetDatum(oid_array),
+                                                         ObjectIdGetDatum(typnamespace));
+               if (HeapTupleIsValid(ftup))
+               {
+                       Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
+
+                       /* Make sure the function's result type is as expected */
+                       if (pform->prorettype == typeId && !pform->proretset &&
+                               !pform->proisagg)
+                       {
+                               /* Okay to use it */
+                               funcid = HeapTupleGetOid(ftup);
+                       }
+                       ReleaseSysCache(ftup);
+               }
+       }
+
        ReleaseSysCache(targetType);
 
+       /*
+        * Now, if we did find a coercion function for an array element type,
+        * report array_length_coerce() as the function to use.  We know it
+        * takes three arguments always.
+        */
+       if (isArray && OidIsValid(funcid))
+       {
+               funcid = F_ARRAY_LENGTH_COERCE;
+               *nargs = 3;
+       }
+
        return funcid;
 }
 
@@ -905,7 +1103,7 @@ find_typmod_coercion_function(Oid typeId)
  * The argument expressions must have been transformed already.
  */
 static Node *
-build_func_call(Oid funcid, Oid rettype, List *args)
+build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
 {
        Func       *funcnode;
        Expr       *expr;
@@ -914,6 +1112,7 @@ build_func_call(Oid funcid, Oid rettype, List *args)
        funcnode->funcid = funcid;
        funcnode->funcresulttype = rettype;
        funcnode->funcretset = false;           /* only possible case here */
+       funcnode->funcformat = fformat;
        funcnode->func_fcache = NULL;
 
        expr = makeNode(Expr);
index 7be413f6b5bd2b1f34289a1c4c7a6000e11a0295..3873fd37f0de436dd1669b0a7602f9c862724480 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.128 2002/09/04 20:31:23 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.129 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,7 +28,6 @@
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
-#include "parser/parse_target.h"
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -40,9 +39,7 @@ static int    expr_depth_counter = 0;
 
 bool           Transform_null_equals = false;
 
-static Node *parser_typecast_constant(Value *expr, TypeName *typename);
-static Node *parser_typecast_expression(ParseState *pstate,
-                                                  Node *expr, TypeName *typename);
+static Node *typecast_expression(Node *expr, TypeName *typename);
 static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
 static Node *transformIndirection(ParseState *pstate, Node *basenode,
                                         List *indirection);
@@ -145,10 +142,9 @@ transformExpr(ParseState *pstate, Node *expr)
                                A_Const    *con = (A_Const *) expr;
                                Value      *val = &con->val;
 
+                               result = (Node *) make_const(val);
                                if (con->typename != NULL)
-                                       result = parser_typecast_constant(val, con->typename);
-                               else
-                                       result = (Node *) make_const(val);
+                                       result = typecast_expression(result, con->typename);
                                break;
                        }
                case T_ExprFieldSelect:
@@ -175,7 +171,7 @@ transformExpr(ParseState *pstate, Node *expr)
                                TypeCast   *tc = (TypeCast *) expr;
                                Node       *arg = transformExpr(pstate, tc->arg);
 
-                               result = parser_typecast_expression(pstate, arg, tc->typename);
+                               result = typecast_expression(arg, tc->typename);
                                break;
                        }
                case T_A_Expr:
@@ -562,8 +558,7 @@ transformExpr(ParseState *pstate, Node *expr)
                                newc->casetype = ptype;
 
                                /* Convert default result clause, if necessary */
-                               newc->defresult = coerce_to_common_type(pstate,
-                                                                                                               newc->defresult,
+                               newc->defresult = coerce_to_common_type(newc->defresult,
                                                                                                                ptype,
                                                                                                                "CASE/ELSE");
 
@@ -572,8 +567,7 @@ transformExpr(ParseState *pstate, Node *expr)
                                {
                                        CaseWhen   *w = (CaseWhen *) lfirst(args);
 
-                                       w->result = coerce_to_common_type(pstate,
-                                                                                                         w->result,
+                                       w->result = coerce_to_common_type(w->result,
                                                                                                          ptype,
                                                                                                          "CASE/WHEN");
                                }
@@ -671,8 +665,12 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
        if (indirection == NIL)
                return basenode;
        return (Node *) transformArraySubscripts(pstate,
-                                                                                        basenode, exprType(basenode),
-                                                                                        indirection, false, NULL);
+                                                                                        basenode,
+                                                                                        exprType(basenode),
+                                                                                        exprTypmod(basenode),
+                                                                                        indirection,
+                                                                                        false,
+                                                                                        NULL);
 }
 
 static Node *
@@ -1037,23 +1035,13 @@ exprTypmod(Node *expr)
  *
  * If coercedTypmod is not NULL, the typmod is stored there if the expression
  * 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
 exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
 {
        Func       *func;
+       int                     nargs;
        Const      *second_arg;
-       HeapTuple       procTuple;
-       HeapTuple       typeTuple;
-       Form_pg_proc procStruct;
-       Form_pg_type typeStruct;
 
        if (coercedTypmod != NULL)
                *coercedTypmod = -1;    /* default result on failure */
@@ -1067,62 +1055,26 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
        Assert(IsA(func, Func));
 
        /*
-        * If it's not a two-argument function with the second argument being
-        * an int4 constant, it can't have been created from a length
-        * coercion.
+        * If it didn't come from a coercion context, reject.
         */
-       if (length(((Expr *) expr)->args) != 2)
-               return false;
-       second_arg = (Const *) lsecond(((Expr *) expr)->args);
-       if (!IsA(second_arg, Const) ||
-               second_arg->consttype != INT4OID ||
-               second_arg->constisnull)
+       if (func->funcformat != COERCE_EXPLICIT_CAST &&
+               func->funcformat != COERCE_IMPLICIT_CAST)
                return false;
 
        /*
-        * Lookup the function in pg_proc
-        */
-       procTuple = SearchSysCache(PROCOID,
-                                                          ObjectIdGetDatum(func->funcid),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(procTuple))
-               elog(ERROR, "cache lookup for proc %u failed", func->funcid);
-       procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
-
-       /*
-        * It must be a function with two arguments where the first is of the
-        * same type as the return value and the second is an int4. Also, just
-        * to be sure, check return type agrees with expr node.
+        * If it's not a two-argument or three-argument function with the second
+        * argument being an int4 constant, it can't have been created from a
+        * length coercion (it must be a type coercion, instead).
         */
-       if (procStruct->pronargs != 2 ||
-               procStruct->prorettype != procStruct->proargtypes[0] ||
-               procStruct->proargtypes[1] != INT4OID ||
-               procStruct->prorettype != ((Expr *) expr)->typeOid)
-       {
-               ReleaseSysCache(procTuple);
+       nargs = length(((Expr *) expr)->args);
+       if (nargs < 2 || nargs > 3)
                return false;
-       }
 
-       /*
-        * Furthermore, the name and namespace of the function must be the
-        * same as its result type's name/namespace (cf.
-        * find_coercion_function).
-        */
-       typeTuple = SearchSysCache(TYPEOID,
-                                                          ObjectIdGetDatum(procStruct->prorettype),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(typeTuple))
-               elog(ERROR, "cache lookup for type %u failed",
-                        procStruct->prorettype);
-       typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
-       if (strcmp(NameStr(procStruct->proname),
-                          NameStr(typeStruct->typname)) != 0 ||
-               procStruct->pronamespace != typeStruct->typnamespace)
-       {
-               ReleaseSysCache(procTuple);
-               ReleaseSysCache(typeTuple);
+       second_arg = (Const *) lsecond(((Expr *) expr)->args);
+       if (!IsA(second_arg, Const) ||
+               second_arg->consttype != INT4OID ||
+               second_arg->constisnull)
                return false;
-       }
 
        /*
         * OK, it is indeed a length-coercion function.
@@ -1130,79 +1082,17 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
        if (coercedTypmod != NULL)
                *coercedTypmod = DatumGetInt32(second_arg->constvalue);
 
-       ReleaseSysCache(procTuple);
-       ReleaseSysCache(typeTuple);
        return true;
 }
 
 /*
- * Produce an appropriate Const node from a constant value produced
- * 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.)
+ * Handle an explicit CAST construct.
  *
  * The given expr has already been transformed, but we need to lookup
  * the type name and then apply any necessary coercion function(s).
  */
 static Node *
-parser_typecast_expression(ParseState *pstate,
-                                                  Node *expr, TypeName *typename)
+typecast_expression(Node *expr, TypeName *typename)
 {
        Oid                     inputType = exprType(expr);
        Oid                     targetType;
@@ -1212,23 +1102,14 @@ parser_typecast_expression(ParseState *pstate,
        if (inputType == InvalidOid)
                return expr;                    /* do nothing if NULL input */
 
-       if (inputType != targetType)
-       {
-               expr = CoerceTargetExpr(pstate, expr, inputType,
-                                                               targetType, typename->typmod,
-                                                               true);  /* explicit coercion */
-               if (expr == NULL)
-                       elog(ERROR, "Cannot cast type '%s' to '%s'",
-                                format_type_be(inputType),
-                                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);
+       expr = coerce_to_target_type(expr, inputType,
+                                                                targetType, typename->typmod,
+                                                                COERCION_EXPLICIT,
+                                                                COERCE_EXPLICIT_CAST);
+       if (expr == NULL)
+               elog(ERROR, "Cannot cast type %s to %s",
+                        format_type_be(inputType),
+                        format_type_be(targetType));
 
        return expr;
 }
index 648ddfbaf0ca4391176ad0e4dab1e7c89ffc42b7..9a54a900aeaf4db2c52fd3734e79f786d6d4496f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/syscache.h"
 
 
-static Node *ParseComplexProjection(ParseState *pstate,
-                                          char *funcname,
-                                          Node *first_arg);
+static Node *ParseComplexProjection(char *funcname, Node *first_arg);
 static Oid **argtype_inherit(int nargs, Oid *argtypes);
 
 static int     find_inheritors(Oid relid, Oid **supervec);
 static Oid **gen_cross_product(InhPaths *arginh, int nargs);
-static void make_arguments(ParseState *pstate,
-                          int nargs,
+static void make_arguments(int nargs,
                           List *fargs,
                           Oid *input_typeids,
                           Oid *function_typeids);
@@ -137,7 +134,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                         * ParseComplexProjection can't handle the projection, we have
                         * to keep going.
                         */
-                       retval = ParseComplexProjection(pstate, cname, first_arg);
+                       retval = ParseComplexProjection(cname, first_arg);
                        if (retval)
                                return retval;
                }
@@ -243,8 +240,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                 * We can do it as a trivial coercion. coerce_type can handle
                 * these cases, so why duplicate code...
                 */
-               return coerce_type(pstate, lfirst(fargs),
-                                                  oid_array[0], rettype, -1, true);
+               return coerce_type(lfirst(fargs), oid_array[0], rettype,
+                                                  COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
        }
        else if (fdresult == FUNCDETAIL_NORMAL)
        {
@@ -296,7 +293,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
        }
 
        /* 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 */
        if (fdresult == FUNCDETAIL_NORMAL)
@@ -307,6 +304,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                funcnode->funcid = funcid;
                funcnode->funcresulttype = rettype;
                funcnode->funcretset = retset;
+               funcnode->funcformat = COERCE_EXPLICIT_CALL;
                funcnode->func_fcache = NULL;
 
                expr->typeOid = rettype;
@@ -367,7 +365,7 @@ match_argtypes(int nargs,
        {
                next_candidate = current_candidate->next;
                if (can_coerce_type(nargs, input_typeids, current_candidate->args,
-                                                       false))
+                                                       COERCION_IMPLICIT))
                {
                        current_candidate->next = *candidates;
                        *candidates = current_candidate;
@@ -470,7 +468,7 @@ func_select_candidate(int nargs,
                {
                        if (input_typeids[i] != UNKNOWNOID)
                        {
-                               if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
+                               if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
                                        nmatch++;
                        }
                }
@@ -776,7 +774,7 @@ func_get_detail(List *funcname,
                                Node       *arg1 = lfirst(fargs);
 
                                if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
-                                       IsBinaryCompatible(sourceType, targetType))
+                                       IsBinaryCoercible(sourceType, targetType))
                                {
                                        /* Yup, it's a type coercion */
                                        *funcid = InvalidOid;
@@ -1120,8 +1118,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
  *     actual arguments and argument types, do the necessary typecasting.
  */
 static void
-make_arguments(ParseState *pstate,
-                          int nargs,
+make_arguments(int nargs,
                           List *fargs,
                           Oid *input_typeids,
                           Oid *function_typeids)
@@ -1136,11 +1133,11 @@ make_arguments(ParseState *pstate,
                /* types don't match? then force coercion using a function call... */
                if (input_typeids[i] != function_typeids[i])
                {
-                       lfirst(current_fargs) = coerce_type(pstate,
-                                                                                               lfirst(current_fargs),
+                       lfirst(current_fargs) = coerce_type(lfirst(current_fargs),
                                                                                                input_typeids[i],
-                                                                                               function_typeids[i], -1,
-                                                                                               false);
+                                                                                               function_typeids[i],
+                                                                                               COERCION_IMPLICIT,
+                                                                                               COERCE_IMPLICIT_CAST);
                }
        }
 }
@@ -1179,9 +1176,7 @@ setup_field_select(Node *input, char *attname, Oid relid)
  * NB: argument is expected to be transformed already, ie, not a RangeVar.
  */
 static Node *
-ParseComplexProjection(ParseState *pstate,
-                                          char *funcname,
-                                          Node *first_arg)
+ParseComplexProjection(char *funcname, Node *first_arg)
 {
        Oid                     argtype = exprType(first_arg);
        Oid                     argrelid;
index 391694fa198523d8607684d6d67e2ecdb9fc4a4f..408fb4f11f6c1c310f35a8651db813590903b3f3 100644 (file)
@@ -1,27 +1,22 @@
 /*-------------------------------------------------------------------------
  *
  * 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) 1994, Regents of the University of California
  *
  *
  * 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 <ctype.h>
-#include <errno.h>
-#include <float.h>
-
 #include "access/heapam.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
-#include "fmgr.h"
 #include "nodes/makefuncs.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_node.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
-#include "parser/parse_target.h"
-#include "parser/parse_type.h"
 #include "utils/builtins.h"
-#include "utils/varbit.h"
+#include "utils/int8.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
-
-static bool fitsInFloat(Value *value);
+#include "utils/varbit.h"
 
 
 /* make_parsestate()
@@ -70,8 +62,8 @@ make_operand(Node *tree, Oid orig_typeId, Oid target_typeId)
        {
                /* must coerce? */
                if (target_typeId != orig_typeId)
-                       result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1,
-                                                                false);
+                       result = coerce_type(tree, orig_typeId, target_typeId,
+                                                                COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
                else
                        result = tree;
        }
@@ -191,6 +183,7 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
  * arrayBase   Already-transformed expression for the array as a whole
  *                             (may be NULL if we are handling an INSERT)
  * arrayType   OID of array's datatype
+ * arrayTypMod typmod to be applied to array elements
  * indirection Untransformed list of subscripts (must not be NIL)
  * forceSlice  If true, treat subscript as array slice in all cases
  * assignFrom  NULL for array fetch, else transformed expression for source.
@@ -199,6 +192,7 @@ ArrayRef *
 transformArraySubscripts(ParseState *pstate,
                                                 Node *arrayBase,
                                                 Oid arrayType,
+                                                int32 arrayTypMod,
                                                 List *indirection,
                                                 bool forceSlice,
                                                 Node *assignFrom)
@@ -286,8 +280,10 @@ transformArraySubscripts(ParseState *pstate,
                        {
                                subexpr = transformExpr(pstate, ai->lidx);
                                /* If it's not int4 already, try to coerce */
-                               subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
-                                                                                  INT4OID, -1, false);
+                               subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
+                                                                                               INT4OID, -1,
+                                                                                               COERCION_ASSIGNMENT,
+                                                                                               COERCE_IMPLICIT_CAST);
                                if (subexpr == NULL)
                                        elog(ERROR, "array index expressions must be integers");
                        }
@@ -306,8 +302,10 @@ transformArraySubscripts(ParseState *pstate,
                }
                subexpr = transformExpr(pstate, ai->uidx);
                /* If it's not int4 already, try to coerce */
-               subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
-                                                                  INT4OID, -1, false);
+               subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
+                                                                               INT4OID, -1,
+                                                                               COERCION_ASSIGNMENT,
+                                                                               COERCE_IMPLICIT_CAST);
                if (subexpr == NULL)
                        elog(ERROR, "array index expressions must be integers");
                upperIndexpr = lappend(upperIndexpr, subexpr);
@@ -323,19 +321,16 @@ transformArraySubscripts(ParseState *pstate,
 
                if (typesource != InvalidOid)
                {
-                       if (typesource != typeneeded)
-                       {
-                               /* XXX fixme: need to get the array's atttypmod? */
-                               assignFrom = CoerceTargetExpr(pstate, assignFrom,
-                                                                                         typesource, typeneeded,
-                                                                                         -1, false);
-                               if (assignFrom == NULL)
-                                       elog(ERROR, "Array assignment requires type '%s'"
-                                                " but expression is of type '%s'"
-                                       "\n\tYou will need to rewrite or cast the expression",
-                                                format_type_be(typeneeded),
-                                                format_type_be(typesource));
-                       }
+                       assignFrom = coerce_to_target_type(assignFrom, typesource,
+                                                                                          typeneeded, arrayTypMod,
+                                                                                          COERCION_ASSIGNMENT,
+                                                                                          COERCE_IMPLICIT_CAST);
+                       if (assignFrom == NULL)
+                               elog(ERROR, "Array assignment requires type %s"
+                                        " but expression is of type %s"
+                                        "\n\tYou will need to rewrite or cast the expression",
+                                        format_type_be(typeneeded),
+                                        format_type_be(typesource));
                }
        }
 
@@ -344,7 +339,7 @@ transformArraySubscripts(ParseState *pstate,
         */
        aref = makeNode(ArrayRef);
        aref->refrestype = resultType;          /* XXX should save element type
-                                                                                * too */
+                                                                                * OID too */
        aref->refattrlength = type_struct_array->typlen;
        aref->refelemlength = type_struct_element->typlen;
        aref->refelembyval = type_struct_element->typbyval;
@@ -373,21 +368,16 @@ transformArraySubscripts(ParseState *pstate,
  *     resolution that we're not sure that it should be considered text.
  *     Explicit "NULL" constants are also typed as UNKNOWN.
  *
- *     For integers and floats we produce int4, float8, or numeric depending
- *     on the value of the number.  XXX In some cases it would be nice to take
- *     context into account when determining the type to convert to, but in
- *     other cases we can't delay the type choice.  One possibility is to invent
- *     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.
+ *     For integers and floats we produce int4, int8, or numeric depending
+ *     on the value of the number.  XXX This should include int2 as well,
+ *     but additional cleanup is needed before we can do that; else cases
+ *     like "WHERE int4var = 42" will fail to be indexable.
  */
 Const *
 make_const(Value *value)
 {
        Datum           val;
+       int64           val64;
        Oid                     typeid;
        int                     typelen;
        bool            typebyval;
@@ -404,12 +394,13 @@ make_const(Value *value)
                        break;
 
                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;
-                               typelen = sizeof(float8);
+                               typeid = INT8OID;
+                               typelen = sizeof(int64);
                                typebyval = false;              /* XXX might change someday */
                        }
                        else
@@ -470,46 +461,3 @@ make_const(Value *value)
 
        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;
-}
index ecf1a2abece4241a6fa36e4ce41d9c9f25635f39..776acc78bfae1729354e14cf15e8a75454f5f3b6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.59 2002/09/04 20:31:24 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.60 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -273,7 +273,7 @@ oper_select_candidate(int nargs,
                 current_candidate = current_candidate->next)
        {
                if (can_coerce_type(nargs, input_typeids, current_candidate->args,
-                                                       false))
+                                                       COERCION_IMPLICIT))
                {
                        if (last_candidate == NULL)
                        {
@@ -362,7 +362,7 @@ oper_select_candidate(int nargs,
                {
                        if (input_typeids[i] != UNKNOWNOID)
                        {
-                               if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
+                               if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
                                        nmatch++;
                        }
                }
@@ -696,8 +696,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
 
        /* but is it good enough? */
        opform = (Form_pg_operator) GETSTRUCT(optup);
-       if (IsBinaryCompatible(opform->oprleft, arg1) &&
-               IsBinaryCompatible(opform->oprright, arg2))
+       if (IsBinaryCoercible(arg1, opform->oprleft) &&
+               IsBinaryCoercible(arg2, opform->oprright))
                return optup;
 
        /* nope... */
index b9c5b6cb137da86a3b8875b63a83162711718c67..18d11cc7f5ac55c5f0ba87eab9a63f66389b66ce 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.89 2002/09/04 20:31:24 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.90 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -274,6 +274,7 @@ updateTargetListEntry(ParseState *pstate,
                aref = transformArraySubscripts(pstate,
                                                                                arrayBase,
                                                                                attrtype,
+                                                                               attrtypmod,
                                                                                indirection,
                                                                                pstate->p_is_insert,
                                                                                tle->expr);
@@ -284,30 +285,21 @@ updateTargetListEntry(ParseState *pstate,
                /*
                 * For normal non-subscripted target column, do type checking and
                 * 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 != attrtype)
-                       {
-                               tle->expr = CoerceTargetExpr(pstate, tle->expr, type_id,
-                                                                                        attrtype, attrtypmod,
-                                                                                        false);
-                               if (tle->expr == NULL)
-                                       elog(ERROR, "column \"%s\" is of type '%s'"
-                                                " but expression is of type '%s'"
-                                       "\n\tYou will need to rewrite or cast the expression",
-                                                colname,
-                                                format_type_be(attrtype),
-                                                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);
+                       tle->expr = coerce_to_target_type(tle->expr, type_id,
+                                                                                         attrtype, attrtypmod,
+                                                                                         COERCION_ASSIGNMENT,
+                                                                                         COERCE_IMPLICIT_CAST);
+                       if (tle->expr == NULL)
+                               elog(ERROR, "column \"%s\" is of type %s"
+                                        " but expression is of type %s"
+                                        "\n\tYou will need to rewrite or cast the expression",
+                                        colname,
+                                        format_type_be(attrtype),
+                                        format_type_be(type_id));
                }
        }
 
@@ -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 -
  *       generate a list of INSERT column targets if not supplied, or
index 95fc726227f802bb7619bf81e11465b6c0f2f0a8..0b2d839eb3f9570a21c7187f659ff1c1b896f228 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.109 2002/09/11 14:48:54 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.110 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,7 +25,6 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
-#include "parser/parse_target.h"
 #include "parser/parse_type.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteHandler.h"
@@ -474,29 +473,21 @@ build_column_default(Relation rel, int attrno)
         */
        exprtype = exprType(expr);
 
-       if (exprtype != atttype)
-       {
-               expr = CoerceTargetExpr(NULL, expr, exprtype,
-                                                               atttype, atttypmod, false);
-
-               /*
-                * This really shouldn't fail; should have checked the default's
-                * type when it was created ...
-                */
-               if (expr == NULL)
-                       elog(ERROR, "Column \"%s\" is of type %s"
-                                " but default expression is of type %s"
-                                "\n\tYou will need to rewrite or cast the expression",
-                                NameStr(att_tup->attname),
-                                format_type_be(atttype),
-                                format_type_be(exprtype));
-       }
-
+       expr = coerce_to_target_type(expr, exprtype,
+                                                                atttype, atttypmod,
+                                                                COERCION_ASSIGNMENT,
+                                                                COERCE_IMPLICIT_CAST);
        /*
-        * If the column is a fixed-length type, it may need a length coercion
-        * as well as a type coercion.
+        * This really shouldn't fail; should have checked the default's
+        * type when it was created ...
         */
-       expr = coerce_type_typmod(NULL, expr, atttype, atttypmod);
+       if (expr == NULL)
+               elog(ERROR, "Column \"%s\" is of type %s"
+                        " but default expression is of type %s"
+                        "\n\tYou will need to rewrite or cast the expression",
+                        NameStr(att_tup->attname),
+                        format_type_be(atttype),
+                        format_type_be(exprtype));
 
        return expr;
 }
index 5d53eca999fdea5f0fc2cc7599cbd0f90896110f..f864338897037c3a63e6bcebb4cf496b5ac79da8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.80 2002/09/04 20:31:27 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.81 2002/09/18 21:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 #include "access/tupmacs.h"
 #include "catalog/catalog.h"
 #include "catalog/pg_type.h"
+#include "parser/parse_coerce.h"
 #include "utils/array.h"
 #include "utils/memutils.h"
 #include "utils/syscache.h"
@@ -755,6 +756,72 @@ array_out(PG_FUNCTION_ARGS)
        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 :
  *               returns the dimensions of the array pointed to by "v", as a "text"
index 267ad821037d10b89cc26c46b4f767edce8d7a34..8a346cd8b838be5520de718356ed2d6dbf59b6e6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  * 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
-int8in(PG_FUNCTION_ARGS)
+bool
+scanint8(const char *str, bool errorOK, int64 *result)
 {
-       char       *str = PG_GETARG_CSTRING(0);
-       int64           result;
-       char       *ptr = str;
+       const char *ptr = str;
        int64           tmp = 0;
        int                     sign = 1;
 
@@ -63,8 +65,11 @@ int8in(PG_FUNCTION_ARGS)
         * Do our own scan, rather than relying on sscanf which might be
         * broken for long long.
         */
-       while (*ptr && isspace((unsigned char) *ptr))           /* skip leading spaces */
+
+       /* skip leading spaces */
+       while (*ptr && isspace((unsigned char) *ptr))
                ptr++;
+
        /* handle sign */
        if (*ptr == '-')
        {
@@ -79,28 +84,61 @@ int8in(PG_FUNCTION_ARGS)
 #ifndef INT64_IS_BUSTED
                if (strcmp(ptr, "9223372036854775808") == 0)
                {
-                       result = -INT64CONST(0x7fffffffffffffff) - 1;
-                       PG_RETURN_INT64(result);
+                       *result = -INT64CONST(0x7fffffffffffffff) - 1;
+                       return true;
                }
 #endif
        }
        else if (*ptr == '+')
                ptr++;
-       if (!isdigit((unsigned char) *ptr)) /* require at least one digit */
-               elog(ERROR, "Bad int8 external representation \"%s\"", str);
-       while (*ptr && isdigit((unsigned char) *ptr))           /* process digits */
+
+       /* require at least one digit */
+       if (!isdigit((unsigned char) *ptr))
+       {
+               if (errorOK)
+                       return false;
+               else
+                       elog(ERROR, "Bad int8 external representation \"%s\"", str);
+       }
+
+       /* process digits */
+       while (*ptr && isdigit((unsigned char) *ptr))
        {
                int64           newtmp = tmp * 10 + (*ptr++ - '0');
 
                if ((newtmp / 10) != tmp)               /* overflow? */
-                       elog(ERROR, "int8 value out of range: \"%s\"", str);
+               {
+                       if (errorOK)
+                               return false;
+                       else
+                               elog(ERROR, "int8 value out of range: \"%s\"", str);
+               }
                tmp = newtmp;
        }
-       if (*ptr)                                       /* trailing junk? */
-               elog(ERROR, "Bad int8 external representation \"%s\"", str);
 
-       result = (sign < 0) ? -tmp : tmp;
+       /* trailing junk? */
+       if (*ptr)
+       {
+               if (errorOK)
+                       return false;
+               else
+                       elog(ERROR, "Bad int8 external representation \"%s\"", str);
+       }
 
+       *result = (sign < 0) ? -tmp : tmp;
+
+       return true;
+}
+
+/* int8in()
+ */
+Datum
+int8in(PG_FUNCTION_ARGS)
+{
+       char       *str = PG_GETARG_CSTRING(0);
+       int64           result;
+
+       (void) scanint8(str, false, &result);
        PG_RETURN_INT64(result);
 }
 
@@ -747,7 +785,7 @@ i8tod(PG_FUNCTION_ARGS)
 }
 
 /* dtoi8()
- * Convert double float to 8-byte integer.
+ * Convert float8 to 8-byte integer.
  */
 Datum
 dtoi8(PG_FUNCTION_ARGS)
@@ -771,8 +809,66 @@ dtoi8(PG_FUNCTION_ARGS)
        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
 text_int8(PG_FUNCTION_ARGS)
 {
@@ -793,9 +889,6 @@ text_int8(PG_FUNCTION_ARGS)
        return result;
 }
 
-
-/* int8_text()
- */
 Datum
 int8_text(PG_FUNCTION_ARGS)
 {
index 228c43c6c4644f1f31fa3c9e7ab83cff29fadd0c..4ea0fec1c1a13e71ae41bfbffc06caffe2b765d3 100644 (file)
@@ -5,7 +5,7 @@
  *
  *     1998 Jan Wieck
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.53 2002/09/04 20:31:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.54 2002/09/18 21:35:22 tgl Exp $
  *
  * ----------
  */
@@ -1709,6 +1709,50 @@ numeric_float4(PG_FUNCTION_ARGS)
 }
 
 
+Datum
+text_numeric(PG_FUNCTION_ARGS)
+{
+       text       *str = PG_GETARG_TEXT_P(0);
+       int                     len;
+       char       *s;
+       Datum           result;
+
+       len = (VARSIZE(str) - VARHDRSZ);
+       s = palloc(len + 1);
+       memcpy(s, VARDATA(str), len);
+       *(s + len) = '\0';
+
+       result = DirectFunctionCall3(numeric_in, CStringGetDatum(s),
+                                                                ObjectIdGetDatum(0), Int32GetDatum(-1));
+
+       pfree(s);
+
+       return result;
+}
+
+Datum
+numeric_text(PG_FUNCTION_ARGS)
+{
+       /* val is numeric, but easier to leave it as Datum */
+       Datum           val = PG_GETARG_DATUM(0);
+       char       *s;
+       int                     len;
+       text       *result;
+
+       s = DatumGetCString(DirectFunctionCall1(numeric_out, val));
+       len = strlen(s);
+
+       result = (text *) palloc(VARHDRSZ + len);
+
+       VARATT_SIZEP(result) = len + VARHDRSZ;
+       memcpy(VARDATA(result), s, len);
+
+       pfree(s);
+
+       PG_RETURN_TEXT_P(result);
+}
+
+
 /* ----------------------------------------------------------------------
  *
  * Aggregate functions
index 22c93c431a068e37decdd61b8d25020de9d173d3..638f5293ed2d7a3f2f2b1e8c298dae8f3193d7e6 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.75 2002/09/04 20:31:28 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.76 2002/09/18 21:35:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,7 +49,7 @@ static void parseNameAndArgTypes(const char *string, const char *caller,
 /*
  * regprocin           - converts "proname" to proc OID
  *
- * 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
  * match an existing pg_proc entry.
@@ -71,15 +71,8 @@ regprocin(PG_FUNCTION_ARGS)
                pro_name_or_oid[0] <= '9' &&
                strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
        {
-               Oid                     searchOid;
-
-               searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+               result = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                                          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);
        }
 
@@ -211,7 +204,7 @@ regprocout(PG_FUNCTION_ARGS)
 /*
  * 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
  * match an existing pg_proc entry.
@@ -235,15 +228,8 @@ regprocedurein(PG_FUNCTION_ARGS)
                pro_name_or_oid[0] <= '9' &&
                strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
        {
-               Oid                     searchOid;
-
-               searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+               result = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                                          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);
        }
 
@@ -361,7 +347,7 @@ regprocedureout(PG_FUNCTION_ARGS)
 /*
  * 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
  * match an existing pg_operator entry.
@@ -383,15 +369,8 @@ regoperin(PG_FUNCTION_ARGS)
                opr_name_or_oid[0] <= '9' &&
                strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
        {
-               Oid                     searchOid;
-
-               searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+               result = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                                          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);
        }
 
@@ -531,7 +510,7 @@ regoperout(PG_FUNCTION_ARGS)
 /*
  * 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
  * match an existing pg_operator entry.
@@ -556,15 +535,8 @@ regoperatorin(PG_FUNCTION_ARGS)
                opr_name_or_oid[0] <= '9' &&
                strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
        {
-               Oid                     searchOid;
-
-               searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+               result = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                                          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);
        }
 
@@ -698,7 +670,7 @@ regoperatorout(PG_FUNCTION_ARGS)
 /*
  * 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
  * match an existing pg_class entry.
@@ -719,15 +691,8 @@ regclassin(PG_FUNCTION_ARGS)
                class_name_or_oid[0] <= '9' &&
        strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
        {
-               Oid                     searchOid;
-
-               searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+               result = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                                        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);
        }
 
@@ -843,7 +808,7 @@ regclassout(PG_FUNCTION_ARGS)
 /*
  * 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
  * match an existing pg_type entry.
@@ -870,15 +835,8 @@ regtypein(PG_FUNCTION_ARGS)
                typ_name_or_oid[0] <= '9' &&
                strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
        {
-               Oid                     searchOid;
-
-               searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+               result = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                                          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);
        }
 
index 740dde36dd49ac7670f2299e7da9dafd0c38dedf..9f21a609f3dfc179d87e9da46ce9e127690b99f7 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.121 2002/09/04 20:31:28 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.122 2002/09/18 21:35:23 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -152,7 +152,6 @@ static void get_oper_expr(Expr *expr, deparse_context *context);
 static void get_func_expr(Expr *expr, deparse_context *context);
 static void get_agg_expr(Aggref *aggref, deparse_context *context);
 static Node *strip_type_coercion(Node *expr, Oid resultType);
-static void get_tle_expr(TargetEntry *tle, deparse_context *context);
 static void get_const_expr(Const *constval, deparse_context *context);
 static void get_sublink_expr(Node *node, deparse_context *context);
 static void get_from_clause(Query *query, deparse_context *context);
@@ -1430,7 +1429,6 @@ get_basic_select_query(Query *query, deparse_context *context,
                sep = ", ";
                colno++;
 
-               /* Do NOT use get_tle_expr here; see its comments! */
                get_rule_expr(tle->expr, context);
 
                /*
@@ -1644,7 +1642,7 @@ get_insert_query_def(Query *query, deparse_context *context)
 
                        appendStringInfo(buf, sep);
                        sep = ", ";
-                       get_tle_expr(tle, context);
+                       get_rule_expr(tle->expr, context);
                }
                appendStringInfoChar(buf, ')');
        }
@@ -1694,7 +1692,7 @@ get_update_query_def(Query *query, deparse_context *context)
                if (!tleIsArrayAssign(tle))
                        appendStringInfo(buf, "%s = ",
                                                         quote_identifier(tle->resdom->resname));
-               get_tle_expr(tle, context);
+               get_rule_expr(tle->expr, context);
        }
 
        /* Add the FROM clause if needed */
@@ -2106,12 +2104,29 @@ get_rule_expr(Node *node, deparse_context *context)
                case T_RelabelType:
                        {
                                RelabelType *relabel = (RelabelType *) node;
+                               Node   *arg = relabel->arg;
 
-                               appendStringInfoChar(buf, '(');
-                               get_rule_expr(relabel->arg, context);
-                               appendStringInfo(buf, ")::%s",
+                               if (relabel->relabelformat == COERCE_IMPLICIT_CAST)
+                               {
+                                       /* don't show an implicit cast */
+                                       get_rule_expr(arg, context);
+                               }
+                               else
+                               {
+                                       /*
+                                        * Strip off any type coercions on the input, so we don't
+                                        * print redundancies like x::bpchar::character(8).
+                                        *
+                                        * XXX Are there any cases where this is a bad idea?
+                                        */
+                                       arg = strip_type_coercion(arg, relabel->resulttype);
+
+                                       appendStringInfoChar(buf, '(');
+                                       get_rule_expr(arg, context);
+                                       appendStringInfo(buf, ")::%s",
                                                        format_type_with_typemod(relabel->resulttype,
-                                                                                                relabel->resulttypmod));
+                                                                                                        relabel->resulttypmod));
+                               }
                        }
                        break;
 
@@ -2305,21 +2320,33 @@ get_func_expr(Expr *expr, deparse_context *context)
        StringInfo      buf = context->buf;
        Func       *func = (Func *) (expr->oper);
        Oid                     funcoid = func->funcid;
-       int32           coercedTypmod;
        Oid                     argtypes[FUNC_MAX_ARGS];
        int                     nargs;
        List       *l;
        char       *sep;
 
        /*
-        * Check to see if function is a length-coercion function for some
-        * datatype.  If so, display the operation as a type cast.
+        * If the function call came from an implicit coercion, then just show
+        * the first argument.
+        */
+       if (func->funcformat == COERCE_IMPLICIT_CAST)
+       {
+               get_rule_expr((Node *) lfirst(expr->args), context);
+               return;
+       }
+
+       /*
+        * If the function call came from an explicit cast, then show
+        * the first argument plus an explicit cast operation.
         */
-       if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
+       if (func->funcformat == COERCE_EXPLICIT_CAST)
        {
                Node       *arg = lfirst(expr->args);
-               Oid                     rettype = get_func_rettype(funcoid);
-               char       *typdesc;
+               Oid                     rettype = expr->typeOid;
+               int32           coercedTypmod;
+
+               /* Get the typmod if this is a length-coercion function */
+               (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
 
                /*
                 * Strip off any type coercions on the input, so we don't print
@@ -2331,17 +2358,8 @@ get_func_expr(Expr *expr, deparse_context *context)
 
                appendStringInfoChar(buf, '(');
                get_rule_expr(arg, context);
-
-               /*
-                * Show typename with appropriate length decoration. Note that
-                * since exprIsLengthCoercion succeeded, the function's output
-                * type is the right thing to report.  Also note we don't need to
-                * quote the result of format_type_with_typemod: it takes care of
-                * double-quoting any identifier that needs it.
-                */
-               typdesc = format_type_with_typemod(rettype, coercedTypmod);
-               appendStringInfo(buf, ")::%s", typdesc);
-               pfree(typdesc);
+               appendStringInfo(buf, ")::%s",
+                                                format_type_with_typemod(rettype, coercedTypmod));
 
                return;
        }
@@ -2393,15 +2411,14 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
 
 /*
  * strip_type_coercion
- *             Strip any type coercions at the top of the given expression tree,
- *             as long as they are coercions to the given datatype.
+ *             Strip any type coercion at the top of the given expression tree,
+ *             if it is a coercion to the given datatype.
  *
- * A RelabelType node is always a type coercion.  A function call is
- * also considered a type coercion if it has one argument and there is
- * a cast declared that uses it.
+ * We use this to avoid printing two levels of coercion in situations where
+ * the expression tree has a length-coercion node atop a type-coercion node.
  *
- * XXX It'd be better if the parsetree retained some explicit indication
- * of the coercion, so we didn't need these heuristics.
+ * Note: avoid stripping a length-coercion node, since two successive
+ * coercions to different lengths aren't a no-op.
  */
 static Node *
 strip_type_coercion(Node *expr, Oid resultType)
@@ -2409,101 +2426,30 @@ strip_type_coercion(Node *expr, Oid resultType)
        if (expr == NULL || exprType(expr) != resultType)
                return expr;
 
-       if (IsA(expr, RelabelType))
-               return strip_type_coercion(((RelabelType *) expr)->arg, resultType);
+       if (IsA(expr, RelabelType) &&
+               ((RelabelType *) expr)->resulttypmod == -1)
+               return ((RelabelType *) expr)->arg;
 
        if (IsA(expr, Expr) &&
                ((Expr *) expr)->opType == FUNC_EXPR)
        {
-               Func       *func;
-               HeapTuple       procTuple;
-               HeapTuple       castTuple;
-               Form_pg_proc procStruct;
-               Form_pg_cast castStruct;
+               Func       *func = (Func *) (((Expr *) expr)->oper);
 
-               func = (Func *) (((Expr *) expr)->oper);
                Assert(IsA(func, Func));
-               if (length(((Expr *) expr)->args) != 1)
-                       return expr;
-               /* 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);
-               /* Double-check func has one arg and correct result type */
-               if (procStruct->pronargs != 1 ||
-                       procStruct->prorettype != resultType)
-               {
-                       ReleaseSysCache(procTuple);
-                       return expr;
-               }
-               /* See if function has is actually declared as a cast */
-               castTuple = SearchSysCache(CASTSOURCETARGET,
-                                                       ObjectIdGetDatum(procStruct->proargtypes[0]),
-                                                               ObjectIdGetDatum(procStruct->prorettype),
-                                                                  0, 0);
-               if (!HeapTupleIsValid(castTuple))
-               {
-                       ReleaseSysCache(procTuple);
-                       return expr;
-               }
-               /* It must also be an implicit cast. */
-               castStruct = (Form_pg_cast) GETSTRUCT(castTuple);
-               if (!castStruct->castimplicit)
-               {
-                       ReleaseSysCache(procTuple);
-                       ReleaseSysCache(castTuple);
+               if (func->funcformat != COERCE_EXPLICIT_CAST &&
+                       func->funcformat != COERCE_IMPLICIT_CAST)
+                       return expr;            /* don't absorb into upper coercion */
+
+               if (exprIsLengthCoercion(expr, NULL))
                        return expr;
-               }
-               /* Okay, it is indeed a type-coercion function */
-               ReleaseSysCache(procTuple);
-               ReleaseSysCache(castTuple);
-               return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
+
+               return (Node *) lfirst(((Expr *) expr)->args);
        }
 
        return expr;
 }
 
 
-/* ----------
- * get_tle_expr
- *
- *             In an INSERT or UPDATE targetlist item, the parser may have inserted
- *             a length-coercion function call to coerce the value to the right
- *             length for the target column.  We want to suppress the output of
- *             that function call, otherwise dump/reload/dump... would blow up the
- *             expression by adding more and more layers of length-coercion calls.
- *
- * As of 7.0, this hack is no longer absolutely essential, because the parser
- * is now smart enough not to add a redundant length coercion function call.
- * But we still suppress the function call just for neatness of displayed
- * rules.
- *
- * Note that this hack must NOT be applied to SELECT targetlist items;
- * any length coercion appearing there is something the user actually wrote.
- * ----------
- */
-static void
-get_tle_expr(TargetEntry *tle, deparse_context *context)
-{
-       Expr       *expr = (Expr *) (tle->expr);
-       int32           coercedTypmod;
-
-       /*
-        * If top level is a length coercion to the correct length, suppress
-        * it; else dump the expression normally.
-        */
-       if (tle->resdom->restypmod >= 0 &&
-               exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
-               coercedTypmod == tle->resdom->restypmod)
-               get_rule_expr((Node *) lfirst(expr->args), context);
-       else
-               get_rule_expr(tle->expr, context);
-}
-
-
 /* ----------
  * get_const_expr
  *
@@ -2518,6 +2464,8 @@ get_const_expr(Const *constval, deparse_context *context)
        Form_pg_type typeStruct;
        char       *extval;
        char       *valptr;
+       bool            isfloat = false;
+       bool            needlabel;
 
        if (constval->constisnull)
        {
@@ -2563,8 +2511,12 @@ get_const_expr(Const *constval, deparse_context *context)
                                 * NaN, so we need not get too crazy about pattern
                                 * matching here.
                                 */
-                               if (strspn(extval, "0123456789 +-eE.") == strlen(extval))
+                               if (strspn(extval, "0123456789+-eE.") == strlen(extval))
+                               {
                                        appendStringInfo(buf, extval);
+                                       if (strcspn(extval, "eE.") != strlen(extval))
+                                               isfloat = true; /* it looks like a float */
+                               }
                                else
                                        appendStringInfo(buf, "'%s'", extval);
                        }
@@ -2609,20 +2561,30 @@ get_const_expr(Const *constval, deparse_context *context)
 
        pfree(extval);
 
+       /*
+        * Append ::typename unless the constant will be implicitly typed as
+        * the right type when it is read in.  XXX this code has to be kept
+        * in sync with the behavior of the parser, especially make_const.
+        */
        switch (constval->consttype)
        {
                case BOOLOID:
                case INT4OID:
-               case FLOAT8OID:
                case UNKNOWNOID:
                        /* These types can be left unlabeled */
+                       needlabel = false;
+                       break;
+               case NUMERICOID:
+                       /* Float-looking constants will be typed as numeric */
+                       needlabel = !isfloat;
                        break;
                default:
-                       appendStringInfo(buf, "::%s",
-                                                        format_type_with_typemod(constval->consttype,
-                                                                                                         -1));
+                       needlabel = true;
                        break;
        }
+       if (needlabel)
+               appendStringInfo(buf, "::%s",
+                                                format_type_with_typemod(constval->consttype, -1));
 
        ReleaseSysCache(typetup);
 }
index f0c31a3961b4a45f529bb36befd941508a0c62ab..715a99863fda2a1deb3a7aa4f97c69c3940ce48c 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *       data section -- private data section for the bits data structures
  *             bitlength -- length of the bit string in bits
  *             bitdata   -- bit string, most significant byte first
+ *
+ *     The length of the bitdata vector should always be exactly as many
+ *     bytes as are needed for the given bitlength.  If the bitlength is
+ *     not a multiple of 8, the extra low-order padding bits of the last
+ *     byte must be zeroes.
  *----------
  */
 
@@ -104,7 +109,7 @@ bit_in(PG_FUNCTION_ARGS)
        len = VARBITTOTALLEN(atttypmod);
        result = (VarBit *) palloc(len);
        /* 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;
        VARBITLEN(result) = atttypmod;
 
@@ -203,50 +208,52 @@ bit_out(PG_FUNCTION_ARGS)
 /* bit()
  * Converts a bit() type to a specific internal length.
  * 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
 bit(PG_FUNCTION_ARGS)
 {
        VarBit     *arg = PG_GETARG_VARBIT_P(0);
        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 */
        if (len <= 0 || len == VARBITLEN(arg))
                PG_RETURN_VARBIT_P(arg);
-       else
+
+       if (!isExplicit)
                elog(ERROR, "Bit string length %d does not match type BIT(%d)",
                         VARBITLEN(arg), len);
-       return 0;                                       /* quiet compiler */
-}
 
-/* _bit()
- * Converts an array of bit() elements to a specific internal length.
- * len is the bitlength specified in the column definition.
- */
-Datum
-_bit(PG_FUNCTION_ARGS)
-{
-       ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
-       int32           len = PG_GETARG_INT32(1);
-       FunctionCallInfoData locfcinfo;
+       rlen = VARBITTOTALLEN(len);
+       result = (VarBit *) palloc(rlen);
+       /* set to 0 so that string is zero-padded */
+       MemSet(result, 0, rlen);
+       VARATT_SIZEP(result) = rlen;
+       VARBITLEN(result) = len;
+
+       memcpy(VARBITS(result), VARBITS(arg),
+                  Min(VARBITBYTES(result), VARBITBYTES(arg)));
 
        /*
-        * Since bit() is a built-in function, we should only need to look it
-        * up once per run.
+        * Make sure last byte is zero-padded if needed.  This is useless but
+        * 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;
-
-       if (bit_finfo.fn_oid == InvalidOid)
-               fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext);
-
-       MemSet(&locfcinfo, 0, sizeof(locfcinfo));
-       locfcinfo.flinfo = &bit_finfo;
-       locfcinfo.nargs = 2;
-       /* We assume we are "strict" and need not worry about null inputs */
-       locfcinfo.arg[0] = PointerGetDatum(v);
-       locfcinfo.arg[1] = Int32GetDatum(len);
+       ipad = VARBITPAD(result);
+       if (ipad > 0)
+       {
+               mask = BITMASK << ipad;
+               *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
+       }
 
-       return array_map(&locfcinfo, BITOID, BITOID);
+       PG_RETURN_VARBIT_P(result);
 }
 
 /*
@@ -311,7 +318,7 @@ varbit_in(PG_FUNCTION_ARGS)
        len = VARBITTOTALLEN(bitlen);
        result = (VarBit *) palloc(len);
        /* 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;
        VARBITLEN(result) = Min(bitlen, atttypmod);
 
@@ -406,20 +413,26 @@ varbit_out(PG_FUNCTION_ARGS)
 /* varbit()
  * Converts a varbit() type to a specific internal length.
  * 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
 varbit(PG_FUNCTION_ARGS)
 {
        VarBit     *arg = PG_GETARG_VARBIT_P(0);
        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 */
        if (len <= 0 || len >= VARBITLEN(arg))
                PG_RETURN_VARBIT_P(arg);
 
-       if (len < VARBITLEN(arg))
+       if (!isExplicit)
                elog(ERROR, "Bit string too long for type BIT VARYING(%d)", len);
 
        rlen = VARBITTOTALLEN(len);
@@ -429,37 +442,15 @@ varbit(PG_FUNCTION_ARGS)
 
        memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
 
-       PG_RETURN_VARBIT_P(result);
-}
-
-/* _varbit()
- * Converts an array of bit() elements to a specific internal length.
- * len is the maximum bitlength specified in the column definition.
- */
-Datum
-_varbit(PG_FUNCTION_ARGS)
-{
-       ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
-       int32           len = PG_GETARG_INT32(1);
-       FunctionCallInfoData locfcinfo;
-
-       /*
-        * Since varbit() is a built-in function, we should only need to look
-        * it up once per run.
-        */
-       static FmgrInfo varbit_finfo;
-
-       if (varbit_finfo.fn_oid == InvalidOid)
-               fmgr_info_cxt(F_VARBIT, &varbit_finfo, TopMemoryContext);
-
-       MemSet(&locfcinfo, 0, sizeof(locfcinfo));
-       locfcinfo.flinfo = &varbit_finfo;
-       locfcinfo.nargs = 2;
-       /* We assume we are "strict" and need not worry about null inputs */
-       locfcinfo.arg[0] = PointerGetDatum(v);
-       locfcinfo.arg[1] = Int32GetDatum(len);
+       /* Make sure last byte is zero-padded if needed */
+       ipad = VARBITPAD(result);
+       if (ipad > 0)
+       {
+               mask = BITMASK << ipad;
+               *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
+       }
 
-       return array_map(&locfcinfo, VARBITOID, VARBITOID);
+       PG_RETURN_VARBIT_P(result);
 }
 
 
@@ -978,7 +969,7 @@ bitshiftleft(PG_FUNCTION_ARGS)
        /* If we shifted all the bits out, return an all-zero string */
        if (shft >= VARBITLEN(arg))
        {
-               memset(r, 0, VARBITBYTES(arg));
+               MemSet(r, 0, VARBITBYTES(arg));
                PG_RETURN_VARBIT_P(result);
        }
 
@@ -991,7 +982,7 @@ bitshiftleft(PG_FUNCTION_ARGS)
                /* Special case: we can do a memcpy */
                len = VARBITBYTES(arg) - byte_shift;
                memcpy(r, p, len);
-               memset(r + len, 0, byte_shift);
+               MemSet(r + len, 0, byte_shift);
        }
        else
        {
@@ -1037,7 +1028,7 @@ bitshiftright(PG_FUNCTION_ARGS)
        /* If we shifted all the bits out, return an all-zero string */
        if (shft >= VARBITLEN(arg))
        {
-               memset(r, 0, VARBITBYTES(arg));
+               MemSet(r, 0, VARBITBYTES(arg));
                PG_RETURN_VARBIT_P(result);
        }
 
@@ -1046,7 +1037,7 @@ bitshiftright(PG_FUNCTION_ARGS)
        p = VARBITS(arg);
 
        /* Set the first part of the result to 0 */
-       memset(r, 0, byte_shift);
+       MemSet(r, 0, byte_shift);
        r += byte_shift;
 
        if (ishift == 0)
index 780daf756555dcb3b2271f228265ce8c5c7a8c67..03579f437b62b15ba79ad1382d3efdc934d2df90 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.94 2002/09/04 20:31:29 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.95 2002/09/18 21:35:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -165,21 +165,28 @@ bpcharout(PG_FUNCTION_ARGS)
 
 
 /*
- * Converts a CHARACTER type to the specified size.  maxlen is the new
- * declared length plus VARHDRSZ bytes.  Truncation
- * rules see bpcharin() above.
+ * Converts a CHARACTER type to the specified size.
+ *
+ * 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
 bpchar(PG_FUNCTION_ARGS)
 {
        BpChar     *source = PG_GETARG_BPCHAR_P(0);
        int32           maxlen = PG_GETARG_INT32(1);
+       bool            isExplicit = PG_GETARG_BOOL(2);
        BpChar     *result;
        int32           len;
        char       *r;
        char       *s;
        int                     i;
-
        int                     charlen;                /* number of charcters in the input string
                                                                 * + VARHDRSZ */
 
@@ -188,7 +195,7 @@ bpchar(PG_FUNCTION_ARGS)
        charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ;
 
        /* 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);
 
        if (charlen > maxlen)
@@ -199,10 +206,13 @@ bpchar(PG_FUNCTION_ARGS)
                maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
                                                                        maxlen - VARHDRSZ) + VARHDRSZ;
 
-               for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
-                       if (*(VARDATA(source) + i) != ' ')
-                               elog(ERROR, "value too long for type character(%d)",
-                                        maxlen - VARHDRSZ);
+               if (!isExplicit)
+               {
+                       for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
+                               if (*(VARDATA(source) + i) != ' ')
+                                       elog(ERROR, "value too long for type character(%d)",
+                                                maxlen - VARHDRSZ);
+               }
 
                len = maxmblen;
 
@@ -238,37 +248,6 @@ bpchar(PG_FUNCTION_ARGS)
 }
 
 
-/* _bpchar()
- * Converts an array of char() elements to a specific internal length.
- * len is the length specified in () plus VARHDRSZ bytes.
- */
-Datum
-_bpchar(PG_FUNCTION_ARGS)
-{
-       ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
-       int32           len = PG_GETARG_INT32(1);
-       FunctionCallInfoData locfcinfo;
-
-       /*
-        * Since bpchar() is a built-in function, we should only need to look
-        * it up once per run.
-        */
-       static FmgrInfo bpchar_finfo;
-
-       if (bpchar_finfo.fn_oid == InvalidOid)
-               fmgr_info_cxt(F_BPCHAR, &bpchar_finfo, TopMemoryContext);
-
-       MemSet(&locfcinfo, 0, sizeof(locfcinfo));
-       locfcinfo.flinfo = &bpchar_finfo;
-       locfcinfo.nargs = 2;
-       /* We assume we are "strict" and need not worry about null inputs */
-       locfcinfo.arg[0] = PointerGetDatum(v);
-       locfcinfo.arg[1] = Int32GetDatum(len);
-
-       return array_map(&locfcinfo, BPCHAROID, BPCHAROID);
-}
-
-
 /* char_bpchar()
  * Convert char to bpchar(1).
  */
@@ -354,9 +333,9 @@ name_bpchar(PG_FUNCTION_ARGS)
  * Note that atttypmod is regarded as the number of characters, which
  * is not necessarily the same as the number of bytes.
  *
- * If the C string is too long,
- * raise an error, unless the extra characters are spaces, in which
- * case they're truncated.  (per SQL) */
+ * If the C string is too long, raise an error, unless the extra characters
+ * are spaces, in which case they're truncated.  (per SQL)
+ */
 Datum
 varcharin(PG_FUNCTION_ARGS)
 {
@@ -428,17 +407,26 @@ varcharout(PG_FUNCTION_ARGS)
 
 
 /*
- * Converts a VARCHAR type to the specified size.  maxlen is the new
- * declared length plus VARHDRSZ bytes.  Truncation
- * rules see varcharin() above.
+ * Converts a VARCHAR type to the specified size.
+ *
+ * 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
 varchar(PG_FUNCTION_ARGS)
 {
        VarChar    *source = PG_GETARG_VARCHAR_P(0);
        int32           maxlen = PG_GETARG_INT32(1);
+       bool            isExplicit = PG_GETARG_BOOL(2);
        VarChar    *result;
        int32           len;
+       size_t          maxmblen;
        int                     i;
 
        len = VARSIZE(source);
@@ -448,21 +436,19 @@ varchar(PG_FUNCTION_ARGS)
 
        /* only reach here if string is too long... */
 
-       {
-               size_t          maxmblen;
-
-               /* truncate multibyte string preserving multibyte boundary */
-               maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
-                                                                       maxlen - VARHDRSZ) + VARHDRSZ;
+       /* truncate multibyte string preserving multibyte boundary */
+       maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
+                                                               maxlen - VARHDRSZ);
 
-               for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
+       if (!isExplicit)
+       {
+               for (i = maxmblen; i < len - VARHDRSZ; i++)
                        if (*(VARDATA(source) + i) != ' ')
                                elog(ERROR, "value too long for type character varying(%d)",
                                         maxlen - VARHDRSZ);
-
-               len = maxmblen;
        }
 
+       len = maxmblen + VARHDRSZ;
        result = palloc(len);
        VARATT_SIZEP(result) = len;
        memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ);
@@ -471,38 +457,6 @@ varchar(PG_FUNCTION_ARGS)
 }
 
 
-/* _varchar()
- * Converts an array of varchar() elements to the specified size.
- * len is the length specified in () plus VARHDRSZ bytes.
- */
-Datum
-_varchar(PG_FUNCTION_ARGS)
-{
-       ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
-       int32           len = PG_GETARG_INT32(1);
-       FunctionCallInfoData locfcinfo;
-
-       /*
-        * Since varchar() is a built-in function, we should only need to look
-        * it up once per run.
-        */
-       static FmgrInfo varchar_finfo;
-
-       if (varchar_finfo.fn_oid == InvalidOid)
-               fmgr_info_cxt(F_VARCHAR, &varchar_finfo, TopMemoryContext);
-
-       MemSet(&locfcinfo, 0, sizeof(locfcinfo));
-       locfcinfo.flinfo = &varchar_finfo;
-       locfcinfo.nargs = 2;
-       /* We assume we are "strict" and need not worry about null inputs */
-       locfcinfo.arg[0] = PointerGetDatum(v);
-       locfcinfo.arg[1] = Int32GetDatum(len);
-
-       return array_map(&locfcinfo, VARCHAROID, VARCHAROID);
-}
-
-
-
 /*****************************************************************************
  * Exported functions
  *****************************************************************************/
index 2672ed3aada445c14854bc01796a21e006933481..c8a038d8a7d752fd63bbf9df5c049e17d20d2fd5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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
  *       Eventually, the index information should go through here, too.
@@ -1073,51 +1073,6 @@ getBaseType(Oid 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
  *
index a3fad0d6834cb6f4ae099ce1b62c2442afab8323..830263bb03c1c18f31d76c3d860d29f1d9ce997a 100644 (file)
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.173 2002/09/05 19:56:57 tgl Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.174 2002/09/18 21:35:23 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -1018,7 +1018,7 @@ echo "ok"
 
 # Create pg_conversion and support functions
 $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"
 
 # Set most system catalogs and built-in functions as world-accessible.
@@ -1063,7 +1063,7 @@ UPDATE pg_database SET \
 -- We use the OID of template0 to determine lastsysoid
 
 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
 -- in template1 and template0; else the latter would be on by default
index 3945c3e600585b29626889353740b05cc46f4aa7..d19fcf461c8c26282f40214262657a5d64775fcc 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.298 2002/09/07 16:14:33 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.299 2002/09/18 21:35:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3797,7 +3797,7 @@ dumpCasts(Archive *fout,
        selectSourceSchema("pg_catalog");
 
        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
                appendPQExpBuffer(query, "SELECT p.oid, t1.oid, t2.oid, p.oid, true FROM pg_type t1, pg_type t2, pg_proc p WHERE p.pronargs = 1 AND p.proargtypes[0] = t1.oid AND p.prorettype = t2.oid AND p.proname = t2.typname ORDER BY 1,2,3;");
 
@@ -3816,7 +3816,7 @@ dumpCasts(Archive *fout,
                char       *castsource = PQgetvalue(res, i, 1);
                char       *casttarget = PQgetvalue(res, i, 2);
                char       *castfunc = PQgetvalue(res, i, 3);
-               char       *castimplicit = PQgetvalue(res, i, 4);
+               char       *castcontext = PQgetvalue(res, i, 4);
                int                     fidx = -1;
                const char *((*deps)[]);
 
@@ -3859,8 +3859,10 @@ dumpCasts(Archive *fout,
                        appendPQExpBuffer(defqry, "WITH FUNCTION %s",
                                                  format_function_signature(&finfo[fidx], true));
 
-               if (strcmp(castimplicit, "t") == 0)
+               if (strcmp(castcontext, "a") == 0)
                        appendPQExpBuffer(defqry, " AS ASSIGNMENT");
+               else if (strcmp(castcontext, "i") == 0)
+                       appendPQExpBuffer(defqry, " AS IMPLICIT");
                appendPQExpBuffer(defqry, ";\n");
 
                ArchiveEntry(fout, castoid,
index 817ef79bcafd2bf2811fcf35d655cbb3113221b1..21a7732c5fb028ddca3636b16f3bacee4202b682 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.158 2002/09/02 06:24:15 momjian Exp $
+ * $Id: catversion.h,v 1.159 2002/09/18 21:35:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200209021
+#define CATALOG_VERSION_NO     200209181
 
 #endif
index 31763358d1c8925698153e1edd6011b5243afc63..48ff930bafb770b7fd5ca34ed95f4bfee1ed0a18 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
- * $Id: pg_cast.h,v 1.3 2002/09/04 20:31:37 momjian Exp $
+ * $Id: pg_cast.h,v 1.4 2002/09/18 21:35:23 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -22,17 +22,38 @@ CATALOG(pg_cast)
 {
        Oid                     castsource;             /* source datatype for cast */
        Oid                     casttarget;             /* destination datatype for cast */
-       Oid                     castfunc;               /* 0 = binary compatible */
-       bool            castimplicit;   /* allow implicit casting? */
+       Oid                     castfunc;               /* cast function; 0 = binary coercible */
+       char            castcontext;    /* contexts in which cast can be used */
 } FormData_pg_cast;
 
 typedef FormData_pg_cast *Form_pg_cast;
 
+/*
+ * The allowable values for pg_cast.castcontext are specified by this enum.
+ * Since castcontext is stored as a "char", we use ASCII codes for human
+ * convenience in reading the table.  Note that internally to the backend,
+ * these values are converted to the CoercionContext enum (see primnodes.h),
+ * which is defined to sort in a convenient order; the ASCII codes don't
+ * have to sort in any special order.
+ */
+
+typedef enum CoercionCodes
+{
+       COERCION_CODE_IMPLICIT = 'i',   /* coercion in context of expression */
+       COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */
+       COERCION_CODE_EXPLICIT = 'e'    /* explicit cast operation */
+} CoercionCodes;
+
+
+/* ----------------
+ *             compiler constants for pg_cast
+ * ----------------
+ */
 #define Natts_pg_cast                          4
 #define Anum_pg_cast_castsource                1
 #define Anum_pg_cast_casttarget                2
 #define Anum_pg_cast_castfunc          3
-#define Anum_pg_cast_castimplicit      4
+#define Anum_pg_cast_castcontext       4
 
 /* ----------------
  *             initial contents of pg_cast
@@ -40,197 +61,216 @@ typedef FormData_pg_cast *Form_pg_cast;
  */
 
 /*
- * binary compatible casts
+ * Numeric category: implicit casts are allowed in the direction
+ * int2->int4->int8->numeric->float4->float8, while casts in the
+ * reverse direction are assignment-only.
  */
-DATA(insert (  25 1042    0 t ));
-DATA(insert (  25 1043    0 t ));
-DATA(insert ( 1042      25    0 t ));
-DATA(insert ( 1042 1043    0 t ));
-DATA(insert ( 1043      25    0 t ));
-DATA(insert ( 1043 1042    0 t ));
-
-DATA(insert (  23       24    0 t ));
-DATA(insert (  23       26    0 t ));
-DATA(insert (  23 2202    0 t ));
-DATA(insert (  23 2203    0 t ));
-DATA(insert (  23 2204    0 t ));
-DATA(insert (  23 2205    0 t ));
-DATA(insert (  23 2206    0 t ));
-DATA(insert (  24       23    0 t ));
-DATA(insert (  24       26    0 t ));
-DATA(insert (  24 2202    0 t ));
-DATA(insert (  24 2203    0 t ));
-DATA(insert (  24 2204    0 t ));
-DATA(insert (  24 2205    0 t ));
-DATA(insert (  24 2206    0 t ));
-DATA(insert (  26       23    0 t ));
-DATA(insert (  26       24    0 t ));
-DATA(insert (  26 2202    0 t ));
-DATA(insert (  26 2203    0 t ));
-DATA(insert (  26 2204    0 t ));
-DATA(insert (  26 2205    0 t ));
-DATA(insert (  26 2206    0 t ));
-DATA(insert ( 2202      23    0 t ));
-DATA(insert ( 2202      24    0 t ));
-DATA(insert ( 2202      26    0 t ));
-DATA(insert ( 2202 2203    0 t ));
-DATA(insert ( 2202 2204    0 t ));
-DATA(insert ( 2202 2205    0 t ));
-DATA(insert ( 2202 2206    0 t ));
-DATA(insert ( 2203      23    0 t ));
-DATA(insert ( 2203      24    0 t ));
-DATA(insert ( 2203      26    0 t ));
-DATA(insert ( 2203 2202    0 t ));
-DATA(insert ( 2203 2204    0 t ));
-DATA(insert ( 2203 2205    0 t ));
-DATA(insert ( 2203 2206    0 t ));
-DATA(insert ( 2204      23    0 t ));
-DATA(insert ( 2204      24    0 t ));
-DATA(insert ( 2204      26    0 t ));
-DATA(insert ( 2204 2202    0 t ));
-DATA(insert ( 2204 2203    0 t ));
-DATA(insert ( 2204 2205    0 t ));
-DATA(insert ( 2204 2206    0 t ));
-DATA(insert ( 2205      23    0 t ));
-DATA(insert ( 2205      24    0 t ));
-DATA(insert ( 2205      26    0 t ));
-DATA(insert ( 2205 2202    0 t ));
-DATA(insert ( 2205 2203    0 t ));
-DATA(insert ( 2205 2204    0 t ));
-DATA(insert ( 2205 2206    0 t ));
-DATA(insert ( 2206      23    0 t ));
-DATA(insert ( 2206      24    0 t ));
-DATA(insert ( 2206      26    0 t ));
-DATA(insert ( 2206 2202    0 t ));
-DATA(insert ( 2206 2203    0 t ));
-DATA(insert ( 2206 2204    0 t ));
-DATA(insert ( 2206 2205    0 t ));
-
-DATA(insert (  23      702    0 t ));
-DATA(insert (  702      23    0 t ));
-
-DATA(insert (  23      703    0 t ));
-DATA(insert (  703      23    0 t ));
-
-DATA(insert (  650     869    0 t ));
-DATA(insert (  869     650    0 t ));
-
-DATA(insert ( 1560 1562    0 t ));
-DATA(insert ( 1562 1560    0 t ));
+DATA(insert (  20       21  714 a ));
+DATA(insert (  20       23  480 a ));
+DATA(insert (  20  700  652 i ));
+DATA(insert (  20      701  482 i ));
+DATA(insert (  20 1700 1781 i ));
+DATA(insert (  21       20  754 i ));
+DATA(insert (  21       23  313 i ));
+DATA(insert (  21      700  236 i ));
+DATA(insert (  21      701  235 i ));
+DATA(insert (  21 1700 1782 i ));
+DATA(insert (  23       20  481 i ));
+DATA(insert (  23       21  314 a ));
+DATA(insert (  23      700  318 i ));
+DATA(insert (  23      701  316 i ));
+DATA(insert (  23 1700 1740 i ));
+DATA(insert (  700      20  653 a ));
+DATA(insert (  700      21  238 a ));
+DATA(insert (  700      23  319 a ));
+DATA(insert (  700     701  311 i ));
+DATA(insert (  700 1700 1742 a ));
+DATA(insert (  701      20  483 a ));
+DATA(insert (  701      21  237 a ));
+DATA(insert (  701      23  317 a ));
+DATA(insert (  701     700  312 a ));
+DATA(insert (  701 1700 1743 a ));
+DATA(insert ( 1700      20 1779 a ));
+DATA(insert ( 1700      21 1783 a ));
+DATA(insert ( 1700      23 1744 a ));
+DATA(insert ( 1700     700 1745 i ));
+DATA(insert ( 1700     701 1746 i ));
 
 /*
- * regular casts through a function
- *
- * This list can be obtained from the following query as long as the
- * naming convention of the cast functions remains the same:
+ * OID category: allow implicit conversion from any integral type (including
+ * int8, to support OID literals > 2G) to OID, as well as assignment coercion
+ * from OID to int4 or int8.  Similarly for each OID-alias type.  Also allow
+ * implicit coercions between OID and each OID-alias type, as well as
+ * regproc<->regprocedure and regoper<->regoperator.  (Other coercions
+ * between alias types must pass through OID.)
+ */
+DATA(insert (  20       26 1287 i ));
+DATA(insert (  21       26  313 i ));
+DATA(insert (  23       26    0 i ));
+DATA(insert (  26       20 1288 a ));
+DATA(insert (  26       23    0 a ));
+DATA(insert (  26       24    0 i ));
+DATA(insert (  24       26    0 i ));
+DATA(insert (  20       24 1287 i ));
+DATA(insert (  21       24  313 i ));
+DATA(insert (  23       24    0 i ));
+DATA(insert (  24       20 1288 a ));
+DATA(insert (  24       23    0 a ));
+DATA(insert (  24 2202    0 i ));
+DATA(insert ( 2202      24    0 i ));
+DATA(insert (  26 2202    0 i ));
+DATA(insert ( 2202      26    0 i ));
+DATA(insert (  20 2202 1287 i ));
+DATA(insert (  21 2202  313 i ));
+DATA(insert (  23 2202    0 i ));
+DATA(insert ( 2202      20 1288 a ));
+DATA(insert ( 2202      23    0 a ));
+DATA(insert (  26 2203    0 i ));
+DATA(insert ( 2203      26    0 i ));
+DATA(insert (  20 2203 1287 i ));
+DATA(insert (  21 2203  313 i ));
+DATA(insert (  23 2203    0 i ));
+DATA(insert ( 2203      20 1288 a ));
+DATA(insert ( 2203      23    0 a ));
+DATA(insert ( 2203 2204    0 i ));
+DATA(insert ( 2204 2203    0 i ));
+DATA(insert (  26 2204    0 i ));
+DATA(insert ( 2204      26    0 i ));
+DATA(insert (  20 2204 1287 i ));
+DATA(insert (  21 2204  313 i ));
+DATA(insert (  23 2204    0 i ));
+DATA(insert ( 2204      20 1288 a ));
+DATA(insert ( 2204      23    0 a ));
+DATA(insert (  26 2205    0 i ));
+DATA(insert ( 2205      26    0 i ));
+DATA(insert (  20 2205 1287 i ));
+DATA(insert (  21 2205  313 i ));
+DATA(insert (  23 2205    0 i ));
+DATA(insert ( 2205      20 1288 a ));
+DATA(insert ( 2205      23    0 a ));
+DATA(insert (  26 2206    0 i ));
+DATA(insert ( 2206      26    0 i ));
+DATA(insert (  20 2206 1287 i ));
+DATA(insert (  21 2206  313 i ));
+DATA(insert (  23 2206    0 i ));
+DATA(insert ( 2206      20 1288 a ));
+DATA(insert ( 2206      23    0 a ));
+
+/*
+ * String category: this needs to be tightened up
+ */
+DATA(insert (  25 1042    0 i ));
+DATA(insert (  25 1043    0 i ));
+DATA(insert ( 1042      25    0 i ));
+DATA(insert ( 1042 1043    0 i ));
+DATA(insert ( 1043      25    0 i ));
+DATA(insert ( 1043 1042    0 i ));
+DATA(insert (  18       25  946 i ));
+DATA(insert (  18 1042  860 i ));
+DATA(insert (  19       25  406 i ));
+DATA(insert (  19 1042  408 i ));
+DATA(insert (  19 1043 1401 i ));
+DATA(insert (  25       18  944 a ));
+DATA(insert (  25       19  407 i ));
+DATA(insert ( 1042      19  409 i ));
+DATA(insert ( 1043      19 1400 i ));
+
+/*
+ * Datetime category
+ */
+DATA(insert (  702 1082 1179 a ));
+DATA(insert (  702 1083 1364 a ));
+DATA(insert (  702 1114 2023 i ));
+DATA(insert (  702 1184 1173 i ));
+DATA(insert (  703 1186 1177 i ));
+DATA(insert ( 1082 1114 2024 i ));
+DATA(insert ( 1082 1184 1174 i ));
+DATA(insert ( 1083 1186 1370 i ));
+DATA(insert ( 1083 1266 2047 i ));
+DATA(insert ( 1114     702 2030 a ));
+DATA(insert ( 1114 1082 2029 a ));
+DATA(insert ( 1114 1083 1316 a ));
+DATA(insert ( 1114 1184 2028 i ));
+DATA(insert ( 1184     702 1180 a ));
+DATA(insert ( 1184 1082 1178 a ));
+DATA(insert ( 1184 1083 2019 a ));
+DATA(insert ( 1184 1114 2027 a ));
+DATA(insert ( 1184 1266 1388 a ));
+DATA(insert ( 1186     703 1194 a ));
+DATA(insert ( 1186 1083 1419 a ));
+DATA(insert ( 1266 1083 2046 a ));
+/* Cross-category casts between int4 and abstime, reltime */
+DATA(insert (  23      702    0 e ));
+DATA(insert (  702      23    0 e ));
+DATA(insert (  23      703    0 e ));
+DATA(insert (  703      23    0 e ));
+
+/*
+ * Geometric category
+ */
+DATA(insert (  601     600 1532 e ));
+DATA(insert (  602     600 1533 e ));
+DATA(insert (  602     604 1449 a ));
+DATA(insert (  603     600 1534 e ));
+DATA(insert (  603     601 1541 e ));
+DATA(insert (  603     604 1448 a ));
+DATA(insert (  603     718 1479 e ));
+DATA(insert (  604     600 1540 e ));
+DATA(insert (  604     602 1447 a ));
+DATA(insert (  604     603 1446 e ));
+DATA(insert (  604     718 1474 e ));
+DATA(insert (  718     600 1416 e ));
+DATA(insert (  718     603 1480 e ));
+DATA(insert (  718     604 1544 e ));
+
+/*
+ * INET category
+ */
+DATA(insert (  650     869    0 i ));
+DATA(insert (  869     650    0 i ));
+
+/*
+ * BitString category
+ */
+DATA(insert ( 1560 1562    0 i ));
+DATA(insert ( 1562 1560    0 i ));
+
+/*
+ * Cross-category casts to and from TEXT
  *
- * select p.proargtypes[0] as source, p.prorettype as target, p.oid as func,
- * p.proimplicit as implicit
- * from pg_proc p, pg_type t where p.pronargs=1 and p.proname = t.typname
- * and p.prorettype = t.oid order by 1, 2;
+ * For historical reasons, most casts to TEXT are implicit.  This is BAD
+ * and should be reined in.
  */
-DATA(insert (  18       25  946 t ));
-DATA(insert (  18 1042  860 t ));
-DATA(insert (  19       25  406 t ));
-DATA(insert (  19 1042  408 t ));
-DATA(insert (  19 1043 1401 t ));
-DATA(insert (  20       21  714 t ));
-DATA(insert (  20       23  480 t ));
-DATA(insert (  20       25 1288 t ));
-DATA(insert (  20      701  482 t ));
-DATA(insert (  20 1043 1623 f ));
-DATA(insert (  20 1700 1781 t ));
-DATA(insert (  21       20  754 t ));
-DATA(insert (  21       23  313 t ));
-DATA(insert (  21       25  113 t ));
-DATA(insert (  21      700  236 t ));
-DATA(insert (  21      701  235 t ));
-DATA(insert (  21 1700 1782 t ));
-DATA(insert (  23       20  481 t ));
-DATA(insert (  23       21  314 t ));
-DATA(insert (  23       25  112 t ));
-DATA(insert (  23      700  318 t ));
-DATA(insert (  23      701  316 t ));
-DATA(insert (  23 1043 1619 f ));
-DATA(insert (  23 1700 1740 t ));
-DATA(insert (  25       18  944 t ));
-DATA(insert (  25       19  407 t ));
-DATA(insert (  25       20 1289 f ));
-DATA(insert (  25       21  818 f ));
-DATA(insert (  25       23  819 f ));
-DATA(insert (  25       26  817 f ));
-DATA(insert (  25      650 1714 f ));
-DATA(insert (  25      700  839 f ));
-DATA(insert (  25      701  838 f ));
-DATA(insert (  25      829  767 f ));
-DATA(insert (  25      869 1713 f ));
-DATA(insert (  25 1082  748 f ));
-DATA(insert (  25 1083  837 f ));
-DATA(insert (  25 1114 2022 f ));
-DATA(insert (  25 1184 1191 f ));
-DATA(insert (  25 1186 1263 f ));
-DATA(insert (  25 1266  938 f ));
-DATA(insert (  26       25  114 t ));
-DATA(insert (  601     600 1532 f ));
-DATA(insert (  602     600 1533 f ));
-DATA(insert (  602     604 1449 f ));
-DATA(insert (  603     600 1534 f ));
-DATA(insert (  603     601 1541 f ));
-DATA(insert (  603     604 1448 f ));
-DATA(insert (  603     718 1479 f ));
-DATA(insert (  604     600 1540 f ));
-DATA(insert (  604     602 1447 f ));
-DATA(insert (  604     603 1446 f ));
-DATA(insert (  604     718 1474 f ));
-DATA(insert (  700      21  238 f ));
-DATA(insert (  700      23  319 f ));
-DATA(insert (  700      25  841 t ));
-DATA(insert (  700     701  311 t ));
-DATA(insert (  700 1700 1742 t ));
-DATA(insert (  701      20  483 t ));
-DATA(insert (  701      21  237 f ));
-DATA(insert (  701      23  317 f ));
-DATA(insert (  701      25  840 t ));
-DATA(insert (  701     700  312 t ));
-DATA(insert (  701 1700 1743 t ));
-DATA(insert (  702 1082 1179 f ));
-DATA(insert (  702 1083 1364 f ));
-DATA(insert (  702 1114 2023 t ));
-DATA(insert (  702 1184 1173 t ));
-DATA(insert (  703 1186 1177 t ));
-DATA(insert (  718     600 1416 f ));
-DATA(insert (  718     603 1480 f ));
-DATA(insert (  718     604 1544 f ));
-DATA(insert (  829      25  752 f ));
-DATA(insert (  869      25  730 f ));
-DATA(insert ( 1042      19  409 t ));
-DATA(insert ( 1043      19 1400 t ));
-DATA(insert ( 1082      25  749 t ));
-DATA(insert ( 1082 1114 2024 t ));
-DATA(insert ( 1082 1184 1174 t ));
-DATA(insert ( 1083      25  948 t ));
-DATA(insert ( 1083 1186 1370 t ));
-DATA(insert ( 1083 1266 2047 t ));
-DATA(insert ( 1114      25 2034 t ));
-DATA(insert ( 1114     702 2030 f ));
-DATA(insert ( 1114 1082 2029 f ));
-DATA(insert ( 1114 1083 1316 f ));
-DATA(insert ( 1114 1184 2028 t ));
-DATA(insert ( 1184      25 1192 t ));
-DATA(insert ( 1184     702 1180 f ));
-DATA(insert ( 1184 1082 1178 f ));
-DATA(insert ( 1184 1083 2019 f ));
-DATA(insert ( 1184 1114 2027 t ));
-DATA(insert ( 1184 1266 1388 f ));
-DATA(insert ( 1186      25 1193 t ));
-DATA(insert ( 1186     703 1194 f ));
-DATA(insert ( 1186 1083 1419 f ));
-DATA(insert ( 1266      25  939 t ));
-DATA(insert ( 1266 1083 2046 t ));
-DATA(insert ( 1700      20 1779 f ));
-DATA(insert ( 1700      21 1783 f ));
-DATA(insert ( 1700      23 1744 f ));
-DATA(insert ( 1700     700 1745 f ));
-DATA(insert ( 1700     701 1746 f ));
+DATA(insert (  20       25 1289 i ));
+DATA(insert (  25       20 1290 e ));
+DATA(insert (  21       25  113 i ));
+DATA(insert (  25       21  818 e ));
+DATA(insert (  23       25  112 i ));
+DATA(insert (  25       23  819 e ));
+DATA(insert (  26       25  114 i ));
+DATA(insert (  25       26  817 e ));
+DATA(insert (  25      650 1714 e ));
+DATA(insert (  700      25  841 i ));
+DATA(insert (  25      700  839 e ));
+DATA(insert (  701      25  840 i ));
+DATA(insert (  25      701  838 e ));
+DATA(insert (  829      25  752 e ));
+DATA(insert (  25      829  767 e ));
+DATA(insert (  869      25  730 e ));
+DATA(insert (  25      869 1713 e ));
+DATA(insert ( 1082      25  749 i ));
+DATA(insert (  25 1082  748 e ));
+DATA(insert ( 1083      25  948 i ));
+DATA(insert (  25 1083  837 e ));
+DATA(insert ( 1114      25 2034 i ));
+DATA(insert (  25 1114 2022 e ));
+DATA(insert ( 1184      25 1192 i ));
+DATA(insert (  25 1184 1191 e ));
+DATA(insert ( 1186      25 1193 i ));
+DATA(insert (  25 1186 1263 e ));
+DATA(insert ( 1266      25  939 i ));
+DATA(insert (  25 1266  938 e ));
+DATA(insert ( 1700      25 1688 i ));
+DATA(insert (  25 1700 1686 e ));
 
 #endif   /* PG_CAST_H */
index c770150f7346ece1d4dbb49ebb8cbde0d40ef1c6..c97003cf43150fd585d3218663511ac387ccf9fe 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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
  *       the genbki.sh script reads this file and generates .bki
@@ -526,10 +526,6 @@ DATA(insert OID = 1133 (  ">"              PGNSP PGUID b f  701    700  16 1122 1134  0 0 0 0 f
 DATA(insert OID = 1134 (  "<="         PGNSP PGUID b f  701    700  16 1125 1133  0 0 0 0 float84le scalarltsel scalarltjoinsel ));
 DATA(insert OID = 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 = 1175 (  "!!"         PGNSP PGUID l f  0       21   23 0 0 0 0 0 0 int2fac - - ));
 
@@ -723,17 +719,13 @@ DATA(insert OID = 1631 (  "~~*"   PGNSP PGUID b f  1043 25        16 0 1632 0 0 0 0 tex
 #define OID_VARCHAR_ICLIKE_OP  1631
 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 */
-DATA(insert OID = 1656 (  "<>"    PGNSP PGUID b f      23      26      16 1661 1136    0  0   0   0 oidne neqsel neqjoinsel ));
-DATA(insert OID = 1657 (  "<"     PGNSP PGUID b f      23      26      16 1663 1660    0  0   0   0 oidlt scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1658 (  ">"     PGNSP PGUID b f      23      26      16 1662 1659    0  0   0   0 oidgt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 1659 (  "<="    PGNSP PGUID b f      23      26      16 1665 1658    0  0   0   0 oidle scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1660 (  ">="    PGNSP PGUID b f      23      26      16 1664 1657    0  0   0   0 oidge scalargtsel scalargtjoinsel ));
-DATA(insert OID = 1661 (  "<>"    PGNSP PGUID b f      26      23      16 1656 1137    0  0   0   0 oidne neqsel neqjoinsel ));
-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 ));
+/* regproc comparisons --- use oid (unsigned) comparison */
+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      24      24      16 1657 1656 0 0 0 0 oidne neqsel neqjoinsel ));
+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      24      24      16 1658 1660 0 0 0 0 oidgt 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      24      24      16 1660 1658 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
 
 /* 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 - - ));
index ff2200d2cc000dd6bef096b659416a2ae4f0a391..eb44f283b9197812b80de05070fb6692b66c3657 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.271 2002/09/12 00:21:24 momjian Exp $
+ * $Id: pg_proc.h,v 1.272 2002/09/18 21:35:23 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -886,15 +886,20 @@ DESCR("convert int8 to float8");
 DATA(insert OID = 483 (  int8                     PGNSP PGUID 12 f f t f i 1  20 "701"  dtoi8 - _null_ ));
 DESCR("convert float8 to int8");
 
+/* OIDS 500 - 599 */
+
+/* OIDS 600 - 699 */
+
+DATA(insert OID = 652 (  float4                           PGNSP PGUID 12 f f t f i 1 700 "20"  i8tof - _null_ ));
+DESCR("convert int8 to float4");
+DATA(insert OID = 653 (  int8                     PGNSP PGUID 12 f f t f i 1  20 "700"  ftoi8 - _null_ ));
+DESCR("convert float4 to int8");
+
 DATA(insert OID = 714 (  int2                     PGNSP PGUID 12 f f t f i 1  21 "20"  int82 - _null_ ));
 DESCR("convert int8 to int2");
 DATA(insert OID = 754 (  int8                     PGNSP PGUID 12 f f t f i 1  20 "21"  int28 - _null_ ));
 DESCR("convert int2 to int8");
 
-/* OIDS 500 - 599 */
-
-/* OIDS 600 - 699 */
-
 DATA(insert OID = 1285 (  int4notin               PGNSP PGUID 12 f f t f s 2 16 "23 25"        int4notin - _null_ ));
 DESCR("not in");
 DATA(insert OID = 1286 (  oidnotin                PGNSP PGUID 12 f f t f s 2 16 "26 25"        oidnotin - _null_ ));
@@ -910,9 +915,9 @@ DESCR("greater-than-or-equal");
 DATA(insert OID = 659 (  namene                           PGNSP PGUID 12 f f t f i 2 16 "19 19"        namene - _null_ ));
 DESCR("not equal");
 
-DATA(insert OID = 668 (  bpchar                           PGNSP PGUID 12 f f t f i 2 1042 "1042 23"    bpchar - _null_ ));
+DATA(insert OID = 668 (  bpchar                           PGNSP PGUID 12 f f t f i 3 1042 "1042 23 16" bpchar - _null_ ));
 DESCR("adjust char() to typmod length");
-DATA(insert OID = 669 (  varchar                  PGNSP PGUID 12 f f t f i 2 1043 "1043 23"    varchar - _null_ ));
+DATA(insert OID = 669 (  varchar                  PGNSP PGUID 12 f f t f i 3 1043 "1043 23 16" varchar - _null_ ));
 DESCR("adjust varchar() to typmod length");
 
 DATA(insert OID = 676 (  mktinterval      PGNSP PGUID 12 f f t f i 2 704 "702 702" mktinterval - _null_ ));
@@ -1374,7 +1379,7 @@ DATA(insert OID = 1141 (  date_pli                   PGNSP PGUID 12 f f t f i 2 1082 "1082 23"
 DESCR("add");
 DATA(insert OID = 1142 (  date_mii                PGNSP PGUID 12 f f t f i 2 1082 "1082 23"    date_mii - _null_ ));
 DESCR("subtract");
-DATA(insert OID = 1143 (  time_in                 PGNSP PGUID 12 f f t f s 1 1083 "2275"       time_in - _null_ ));
+DATA(insert OID = 1143 (  time_in                 PGNSP PGUID 12 f f t f s 3 1083 "2275 26 23" time_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1144 (  time_out                PGNSP PGUID 12 f f t f i 1 2275 "1083"       time_out - _null_ ));
 DESCR("(internal)");
@@ -1390,7 +1395,7 @@ DESCR("multiply");
 DATA(insert OID = 1149 (  circle_div_pt    PGNSP PGUID 12 f f t f i 2 718 "718 600"  circle_div_pt - _null_ ));
 DESCR("divide");
 
-DATA(insert OID = 1150 (  timestamptz_in   PGNSP PGUID 12 f f t f s 1 1184 "2275"      timestamptz_in - _null_ ));
+DATA(insert OID = 1150 (  timestamptz_in   PGNSP PGUID 12 f f t f s 3 1184 "2275 26 23"        timestamptz_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1151 (  timestamptz_out  PGNSP PGUID 12 f f t f s 1 2275 "1184"      timestamptz_out - _null_ ));
 DESCR("(internal)");
@@ -1409,7 +1414,7 @@ DESCR("greater-than");
 DATA(insert OID = 1159 (  timezone                PGNSP PGUID 12 f f t f s 2 1114 "25 1184"  timestamptz_zone - _null_ ));
 DESCR("timestamp at a specified time zone");
 
-DATA(insert OID = 1160 (  interval_in     PGNSP PGUID 12 f f t f s 1 1186 "2275"       interval_in - _null_ ));
+DATA(insert OID = 1160 (  interval_in     PGNSP PGUID 12 f f t f s 3 1186 "2275 26 23" interval_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1161 (  interval_out    PGNSP PGUID 12 f f t f i 1 2275 "1186"       interval_out - _null_ ));
 DESCR("(internal)");
@@ -1539,15 +1544,18 @@ DESCR("multiply");
 DATA(insert OID = 1281 (  int48div                PGNSP PGUID 12 f f t f i 2 20 "23 20"        int48div - _null_ ));
 DESCR("divide");
 
-DATA(insert OID = 1288 (  text                    PGNSP PGUID 12 f f t f i 1 25 "20"  int8_text - _null_ ));
+DATA(insert OID = 1287 (  oid                     PGNSP PGUID 12 f f t f i 1 26 "20"  i8tooid - _null_ ));
+DESCR("convert int8 to oid");
+DATA(insert OID = 1288 (  int8                    PGNSP PGUID 12 f f t f i 1 20 "26"  oidtoi8 - _null_ ));
+DESCR("convert oid to int8");
+
+DATA(insert OID = 1289 (  text                    PGNSP PGUID 12 f f t f i 1 25 "20"  int8_text - _null_ ));
 DESCR("convert int8 to text");
-DATA(insert OID = 1289 (  int8                    PGNSP PGUID 12 f f t f i 1 20 "25"  text_int8 - _null_ ));
+DATA(insert OID = 1290 (  int8                    PGNSP PGUID 12 f f t f i 1 20 "25"  text_int8 - _null_ ));
 DESCR("convert text to int8");
 
-DATA(insert OID = 1290 (  _bpchar                 PGNSP PGUID 12 f f t f i 2 1014 "1014 23"    _bpchar - _null_ ));
-DESCR("adjust char()[] to typmod length");
-DATA(insert OID = 1291 (  _varchar                PGNSP PGUID 12 f f t f i 2 1015 "1015 23"    _varchar - _null_ ));
-DESCR("adjust varchar()[] to typmod length");
+DATA(insert OID = 1291 (  array_length_coerce  PGNSP PGUID 12 f f t f i 3 2277 "2277 23 16"    array_length_coerce - _null_ ));
+DESCR("adjust any array to element typmod length");
 
 DATA(insert OID = 1292 ( tideq                    PGNSP PGUID 12 f f t f i 2 16 "27 27"        tideq - _null_ ));
 DESCR("equal");
@@ -1594,7 +1602,7 @@ DESCR("SQL92 interval comparison");
 DATA(insert OID = 1311 ( overlaps                       PGNSP PGUID 14 f f f f i 4 16 "1083 1186 1083 1083"    "select ($1, ($1 + $2)) overlaps ($3, $4)" - _null_ ));
 DESCR("SQL92 interval comparison");
 
-DATA(insert OID = 1312 (  timestamp_in          PGNSP PGUID 12 f f t f s 1 1114 "2275" timestamp_in - _null_ ));
+DATA(insert OID = 1312 (  timestamp_in          PGNSP PGUID 12 f f t f s 3 1114 "2275 26 23" timestamp_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1313 (  timestamp_out                 PGNSP PGUID 12 f f t f s 1 2275 "1114" timestamp_out - _null_ ));
 DESCR("(internal)");
@@ -1644,7 +1652,7 @@ DATA(insert OID = 1349 (  oidvectortypes   PGNSP PGUID 12 f f t f s 1 25 "30"  oi
 DESCR("print type names of oidvector field");
 
 
-DATA(insert OID = 1350 (  timetz_in               PGNSP PGUID 12 f f t f s 1 1266 "2275"       timetz_in - _null_ ));
+DATA(insert OID = 1350 (  timetz_in               PGNSP PGUID 12 f f t f s 3 1266 "2275 26 23" timetz_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1351 (  timetz_out      PGNSP PGUID 12 f f t f i 1 2275 "1266"       timetz_out - _null_ ));
 DESCR("(internal)");
@@ -1983,7 +1991,7 @@ DESCR("# points in path");
 DATA(insert OID = 1556 (  npoints                      PGNSP PGUID 12 f f t f i 1      23 "604"  poly_npoints - _null_ ));
 DESCR("number of points in polygon");
 
-DATA(insert OID = 1564 (  bit_in                       PGNSP PGUID 12 f f t f i 1 1560 "2275"  bit_in - _null_ ));
+DATA(insert OID = 1564 (  bit_in                       PGNSP PGUID 12 f f t f i 3 1560 "2275 26 23"    bit_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1565 (  bit_out                      PGNSP PGUID 12 f f t f i 1 2275 "1560"  bit_out - _null_ ));
 DESCR("(internal)");
@@ -2008,7 +2016,7 @@ DESCR("set sequence value");
 DATA(insert OID = 1765 (  setval                       PGNSP PGUID 12 f f t f v 3 20 "25 20 16"        setval_and_iscalled - _null_ ));
 DESCR("set sequence value and iscalled status");
 
-DATA(insert OID = 1579 (  varbit_in                    PGNSP PGUID 12 f f t f i 1 1562 "2275"  varbit_in - _null_ ));
+DATA(insert OID = 1579 (  varbit_in                    PGNSP PGUID 12 f f t f i 3 1562 "2275 26 23"    varbit_in - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1580 (  varbit_out           PGNSP PGUID 12 f f t f i 1 2275 "1562"  varbit_out - _null_ ));
 DESCR("(internal)");
@@ -2060,8 +2068,6 @@ DESCR("PI");
 
 DATA(insert OID = 1618 (  interval_mul         PGNSP PGUID 12 f f t f i 2 1186 "1186 701"      interval_mul - _null_ ));
 DESCR("multiply interval");
-DATA(insert OID = 1619 (  varchar                      PGNSP PGUID 12 f f t f i 1 1043 "23"    int4_text - _null_ ));
-DESCR("convert int4 to varchar");
 
 DATA(insert OID = 1620 (  ascii                                PGNSP PGUID 12 f f t f i 1 23 "25"      ascii - _null_ ));
 DESCR("convert first char to int4");
@@ -2070,8 +2076,6 @@ DESCR("convert int4 to char");
 DATA(insert OID = 1622 (  repeat                       PGNSP PGUID 12 f f t f i 2 25 "25 23"  repeat - _null_ ));
 DESCR("replicate string int4 times");
 
-DATA(insert OID = 1623 (  varchar                      PGNSP PGUID 12 f f t f i 1 1043 "20"    int8_text - _null_ ));
-DESCR("convert int8 to varchar");
 DATA(insert OID = 1624 (  mul_d_interval       PGNSP PGUID 12 f f t f i 2 1186 "701 1186"      mul_d_interval - _null_ ));
 
 DATA(insert OID = 1633 (  texticlike           PGNSP PGUID 12 f f t f i 2 16 "25 25" texticlike - _null_ ));
@@ -2133,9 +2137,9 @@ DESCR("replace all occurrences of old_substr with new_substr in string");
 DATA(insert OID =  2088 ( split_part   PGNSP PGUID 12 f f t f i 3 25 "25 25 23"  split_text - _null_ ));
 DESCR("split string by field_sep and return field_num");
 DATA(insert OID =  2089 ( to_hex          PGNSP PGUID 12 f f t f i 1 25 "23"  to_hex32 - _null_ ));
-DESCR("convert int32 number to hex");
+DESCR("convert int4 number to hex");
 DATA(insert OID =  2090 ( to_hex          PGNSP PGUID 12 f f t f i 1 25 "20"  to_hex64 - _null_ ));
-DESCR("convert int64 number to hex");
+DESCR("convert int8 number to hex");
 
 /* for character set encoding support */
 
@@ -2250,14 +2254,10 @@ DESCR("int4 to bitstring");
 DATA(insert OID = 1684 (  int4                         PGNSP PGUID 12 f f t f i 1 23 "1560"    bittoint4 - _null_ ));
 DESCR("bitstring to int4");
 
-DATA(insert OID = 1685 (  bit                     PGNSP PGUID 12 f f t f i 2 1560 "1560 23"    bit - _null_ ));
+DATA(insert OID = 1685 (  bit                     PGNSP PGUID 12 f f t f i 3 1560 "1560 23 16" bit - _null_ ));
 DESCR("adjust bit() to typmod length");
-DATA(insert OID = 1686 (  _bit                    PGNSP PGUID 12 f f t f i 2 1561 "1561 23"    _bit - _null_ ));
-DESCR("adjust bit()[] to typmod length");
-DATA(insert OID = 1687 (  varbit                  PGNSP PGUID 12 f f t f i 2 1562 "1562 23"    varbit - _null_ ));
+DATA(insert OID = 1687 (  varbit                  PGNSP PGUID 12 f f t f i 3 1562 "1562 23 16" varbit - _null_ ));
 DESCR("adjust varbit() to typmod length");
-DATA(insert OID = 1688 (  _varbit                 PGNSP PGUID 12 f f t f i 2 1563 "1563 23"    _varbit - _null_ ));
-DESCR("adjust varbit()[] to typmod length");
 
 DATA(insert OID = 1698 (  position                PGNSP PGUID 12 f f t f i 2 23 "1560 1560" bitposition - _null_ ));
 DESCR("return position of sub-bitstring");
@@ -2351,6 +2351,11 @@ DESCR("text to cidr");
 DATA(insert OID = 1715 (  set_masklen          PGNSP PGUID 12 f f t f i 2 869 "869 23"  inet_set_masklen - _null_ ));
 DESCR("change the netmask of an inet");
 
+DATA(insert OID = 1686 ( numeric                       PGNSP PGUID 12 f f t f i 1 1700 "25"    text_numeric - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 1688 ( text                          PGNSP PGUID 12 f f t f i 1 25 "1700"    numeric_text - _null_ ));
+DESCR("(internal)");
+
 DATA(insert OID = 1690 ( time_mi_time          PGNSP PGUID 12 f f t f i 2 1186 "1083 1083"  time_mi_time - _null_ ));
 DESCR("minus");
 
index f4e69d3d15886377e8a7d53ce206ad0f2d19ef52..e7c9c29413cbd78b19bafa82fb5c4ccfa5cb4984 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: makefuncs.h,v 1.40 2002/09/04 20:31:43 momjian Exp $
+ * $Id: makefuncs.h,v 1.41 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "nodes/parsenodes.h"
 
+
 extern A_Expr *makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr);
 
 extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
@@ -52,7 +53,8 @@ extern Const *makeNullConst(Oid consttype);
 
 extern Alias *makeAlias(const char *aliasname, List *colnames);
 
-extern 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);
 
index 0f703e27eccc612e36c6ff2bdacf57478dadb5b3..56e3922ea9f453f0c7fa19c627cd10bd01f0141a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.206 2002/09/04 20:31:43 momjian Exp $
+ * $Id: parsenodes.h,v 1.207 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1632,7 +1632,7 @@ typedef struct CreateCastStmt
        TypeName   *sourcetype;
        TypeName   *targettype;
        FuncWithArgs *func;
-       bool            implicit;
+       CoercionContext context;
 } CreateCastStmt;
 
 /* ----------------------
index 111ed7f8ce8474c6639a74d828dd58476557a909..1d7c5115b64a44fa2057144335cdd2aed09f9e70 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.67 2002/09/04 20:31:44 momjian Exp $
+ * $Id: primnodes.h,v 1.68 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -139,6 +139,30 @@ typedef struct RangeVar
  * ----------------------------------------------------------------
  */
 
+/*
+ * CoercionContext - distinguishes the allowed set of type casts
+ *
+ * NB: ordering of the alternatives is significant; later (larger) values
+ * allow more casts than earlier ones.
+ */
+typedef enum CoercionContext
+{
+       COERCION_IMPLICIT,                      /* coercion in context of expression */
+       COERCION_ASSIGNMENT,            /* coercion in context of assignment */
+       COERCION_EXPLICIT                       /* explicit cast operation */
+} CoercionContext;
+
+/*
+ * CoercionForm - information showing how to display a function-call node
+ */
+typedef enum CoercionForm
+{
+       COERCE_EXPLICIT_CALL,           /* display as a function call */
+       COERCE_EXPLICIT_CAST,           /* display as an explicit cast */
+       COERCE_IMPLICIT_CAST,           /* implicit cast, so hide it */
+       COERCE_DONTCARE                         /* special case for pathkeys */
+} CoercionForm;
+
 /*
  * Expr
  */
@@ -194,6 +218,7 @@ typedef struct Func
        Oid                     funcid;                 /* PG_PROC OID of the function */
        Oid                     funcresulttype; /* PG_TYPE OID of result value */
        bool            funcretset;             /* true if function returns set */
+       CoercionForm funcformat;        /* how to display this function call */
        FunctionCachePtr func_fcache;           /* runtime state, or NULL */
 } Func;
 
@@ -460,6 +485,7 @@ typedef struct RelabelType
        Node       *arg;                        /* input expression */
        Oid                     resulttype;             /* output type of coercion expression */
        int32           resulttypmod;   /* output typmod (usually -1) */
+       CoercionForm relabelformat;     /* how to display this node */
 } RelabelType;
 
 
index 152ade0e9bd5f92e6eb1bfdfa028bb6b4dd87ebf..61a63cafeb49f414757d8c20bede7bb6694a1086 100644 (file)
@@ -1,13 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * parse_coerce.h
- *
  *     Routines for type coercion.
  *
+ *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_coerce.h,v 1.46 2002/09/04 20:31:45 momjian Exp $
+ * $Id: parse_coerce.h,v 1.47 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,29 +29,31 @@ typedef enum CATEGORY
        TIMESPAN_TYPE,
        GEOMETRIC_TYPE,
        NETWORK_TYPE,
-       USER_TYPE,
-       MIXED_TYPE
+       USER_TYPE
 } CATEGORY;
 
 
-extern bool IsBinaryCompatible(Oid type1, Oid type2);
+extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
 extern bool IsPreferredType(CATEGORY category, Oid type);
 extern CATEGORY TypeCategory(Oid type);
 
-extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
-                               bool isExplicit);
-extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
-                       Oid targetTypeId, int32 atttypmod, bool isExplicit);
-extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
-                                  Oid targetTypeId, int32 atttypmod);
-extern Node *coerce_type_constraints(ParseState *pstate, Node *arg,
-                                               Oid typeId, bool applyTypmod);
+extern Node *coerce_to_target_type(Node *expr, Oid exprtype,
+                                                                  Oid targettype, int32 targettypmod,
+                                                                  CoercionContext ccontext,
+                                                                  CoercionForm cformat);
+extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
+                                                       CoercionContext ccontext);
+extern Node *coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
+                                                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 Oid     select_common_type(List *typeids, const char *context);
-extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
-                                         Oid targetTypeId,
+extern Node *coerce_to_common_type(Node *node, Oid targetTypeId,
                                          const char *context);
 
+extern Oid     find_typmod_coercion_function(Oid typeId, int *nargs);
+
 #endif   /* PARSE_COERCE_H */
index 8fac035fcc62cc6080ee74fdcd703f7d2eb72c22..beb16e2cc8e916cd452a49548014b7af4f5e1448 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_node.h,v 1.31 2002/06/20 20:29:51 momjian Exp $
+ * $Id: parse_node.h,v 1.32 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,7 @@ extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
 extern ArrayRef *transformArraySubscripts(ParseState *pstate,
                                                 Node *arrayBase,
                                                 Oid arrayType,
+                                                int32 arrayTypMod,
                                                 List *indirection,
                                                 bool forceSlice,
                                                 Node *assignFrom);
index acca0f05690fa35a625fb829b3162f6b5851f76e..b8c495484bfd1ac13f184905b8f6073291d2e985 100644 (file)
@@ -1,13 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * parse_target.h
- *
+ *       handle target lists
  *
  *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_target.h,v 1.26 2002/09/04 20:31:45 momjian Exp $
+ * $Id: parse_target.h,v 1.27 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "parser/parse_node.h"
 
+
 extern List *transformTargetList(ParseState *pstate, List *targetlist);
 extern TargetEntry *transformTargetEntry(ParseState *pstate,
                                         Node *node, Node *expr,
@@ -23,9 +24,6 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
 extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
                                          char *colname, int attrno,
                                          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,
                                   List **attrnos);
 
index 5c1276467c083df01643421318c218b30c2baead..639d9dc31535b0eb16473cdb185815d3acc433ee 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: array.h,v 1.34 2002/09/04 20:31:45 momjian Exp $
+ * $Id: array.h,v 1.35 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,6 +82,7 @@ typedef struct
  */
 extern Datum array_in(PG_FUNCTION_ARGS);
 extern Datum array_out(PG_FUNCTION_ARGS);
+extern Datum array_length_coerce(PG_FUNCTION_ARGS);
 extern Datum array_eq(PG_FUNCTION_ARGS);
 extern Datum array_dims(PG_FUNCTION_ARGS);
 
index e97982215d84df14bd42524083315186d88603ea..d9f611bcfd8dc9ee9b14bb94c095147ccf657899 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.199 2002/09/04 20:31:45 momjian Exp $
+ * $Id: builtins.h,v 1.200 2002/09/18 21:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -422,7 +422,6 @@ extern Datum currtid_byrelname(PG_FUNCTION_ARGS);
 extern Datum bpcharin(PG_FUNCTION_ARGS);
 extern Datum bpcharout(PG_FUNCTION_ARGS);
 extern Datum bpchar(PG_FUNCTION_ARGS);
-extern Datum _bpchar(PG_FUNCTION_ARGS);
 extern Datum char_bpchar(PG_FUNCTION_ARGS);
 extern Datum name_bpchar(PG_FUNCTION_ARGS);
 extern Datum bpchar_name(PG_FUNCTION_ARGS);
@@ -440,7 +439,6 @@ extern Datum hashbpchar(PG_FUNCTION_ARGS);
 extern Datum varcharin(PG_FUNCTION_ARGS);
 extern Datum varcharout(PG_FUNCTION_ARGS);
 extern Datum varchar(PG_FUNCTION_ARGS);
-extern Datum _varchar(PG_FUNCTION_ARGS);
 extern Datum varchareq(PG_FUNCTION_ARGS);
 extern Datum varcharne(PG_FUNCTION_ARGS);
 extern Datum varcharlt(PG_FUNCTION_ARGS);
@@ -633,6 +631,8 @@ extern Datum numeric_float8(PG_FUNCTION_ARGS);
 extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS);
 extern Datum float4_numeric(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 int2_accum(PG_FUNCTION_ARGS);
 extern Datum int4_accum(PG_FUNCTION_ARGS);
index 4ffa3bca50485a464d6ffc56ff3371c7db3de570..f8b337e3c0c31626873025110daf2adf61e91a1d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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
  * These data types are supported on all 64-bit architectures, and may
@@ -29,6 +29,8 @@
 #define INT64_FORMAT "%ld"
 #endif
 
+extern bool scanint8(const char *str, bool errorOK, int64 *result);
+
 extern Datum int8in(PG_FUNCTION_ARGS);
 extern Datum int8out(PG_FUNCTION_ARGS);
 
@@ -106,6 +108,12 @@ extern Datum int82(PG_FUNCTION_ARGS);
 extern Datum i8tod(PG_FUNCTION_ARGS);
 extern Datum 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 text_int8(PG_FUNCTION_ARGS);
 
index 029fdcdc8638ea6b1e071cd66dc453fc55bfd8e6..5dee7bc0cbb8bdd3b0e2f96c00894ffa58edc117 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.62 2002/09/04 20:31:45 momjian Exp $
+ * $Id: lsyscache.h,v 1.63 2002/09/18 21:35:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,7 +58,6 @@ extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem);
 extern bool getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
                                  bool *typIsVarlena);
 extern Oid     getBaseType(Oid typid);
-extern int32 getBaseTypeMod(Oid typid, int32 typmod);
 extern int32 get_typavgwidth(Oid typid, int32 typmod);
 extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
 extern bool get_attstatsslot(HeapTuple statstuple,
index 8dff3166d566b48c56f7441b363e66279fd1e6bb..9e5505624b6aea837fcef87d51900110bb140fb9 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: varbit.h,v 1.15 2002/08/04 06:33:56 thomas Exp $
+ * $Id: varbit.h,v 1.16 2002/09/18 21:35:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,9 +66,7 @@ extern Datum bit_out(PG_FUNCTION_ARGS);
 extern Datum varbit_in(PG_FUNCTION_ARGS);
 extern Datum varbit_out(PG_FUNCTION_ARGS);
 extern Datum bit(PG_FUNCTION_ARGS);
-extern Datum _bit(PG_FUNCTION_ARGS);
 extern Datum varbit(PG_FUNCTION_ARGS);
-extern Datum _varbit(PG_FUNCTION_ARGS);
 extern Datum biteq(PG_FUNCTION_ARGS);
 extern Datum bitne(PG_FUNCTION_ARGS);
 extern Datum bitlt(PG_FUNCTION_ARGS);
index 522c28121ff27ef071895d5b017394ac133732f8..8bbed8c431ddf2e48aaf7fec82988f9004c09ce1 100644 (file)
@@ -13,10 +13,14 @@ create domain domainvarchar varchar(5);
 create domain domainnumeric numeric(8,2);
 create domain domainint4 int4;
 create domain domaintext text;
--- Test coercions
-SELECT cast('123456' as domainvarchar); -- fail
-ERROR:  value too long for type character varying(5)
-SELECT cast('12345' as domainvarchar); -- pass
+-- Test explicit coercions --- these should succeed (and truncate)
+SELECT cast('123456' as domainvarchar);
+ domainvarchar 
+---------------
+ 12345
+(1 row)
+
+SELECT cast('12345' as domainvarchar);
  domainvarchar 
 ---------------
  12345
index 3561fac04bf1fec0496d3392114f0b079e3f8c45..b8b7423ec520f01c286b2f5a72b5758255e2279f 100644 (file)
@@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
  Sat Jan 01 10:00:00 1994
 (1 row)
 
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-ERROR:  Bad time external representation '11:00-5'
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
-     Jan_01_1994_11am     
---------------------------
- Sat Jan 01 11:00:00 1994
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+       Jan_01_1994_8am        
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
+(1 row)
+
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
+       Jan_01_1994_8am        
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
 (1 row)
 
 SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
@@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
 (1 row)
 
 SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
-ERROR:  Cannot cast type 'time with time zone' to 'interval'
+ERROR:  Cannot cast type time with time zone to interval
 SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
-ERROR:  Cannot cast type 'interval' to 'time with time zone'
+ERROR:  Cannot cast type interval to time with time zone
 SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
  23:29:00-08 
 -------------
index 22d335c6c2c19eb60b6d9ee6d905c048d9ce3675..1601a346f01612f152b18e3568be3f10fcf7fd0e 100644 (file)
@@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
  Sat Jan 01 10:00:00 1994
 (1 row)
 
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-ERROR:  Bad time external representation '11:00-5'
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
-     Jan_01_1994_11am     
---------------------------
- Sat Jan 01 11:00:00 1994
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+       Jan_01_1994_8am        
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
+(1 row)
+
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
+       Jan_01_1994_8am        
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
 (1 row)
 
 SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
@@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
 (1 row)
 
 SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
-ERROR:  Cannot cast type 'time with time zone' to 'interval'
+ERROR:  Cannot cast type time with time zone to interval
 SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
-ERROR:  Cannot cast type 'interval' to 'time with time zone'
+ERROR:  Cannot cast type interval to time with time zone
 SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
  23:29:00-08 
 -------------
index 83d92182d085726ba638f8f5990c92e1c9b0f678..294b7854106ba88388d0c70a8f92e559e4406447 100644 (file)
@@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
  Sat Jan 01 10:00:00 1994
 (1 row)
 
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-ERROR:  Bad time external representation '11:00-5'
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
-     Jan_01_1994_11am     
---------------------------
- Sat Jan 01 11:00:00 1994
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+       Jan_01_1994_8am        
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
+(1 row)
+
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
+       Jan_01_1994_8am        
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
 (1 row)
 
 SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
@@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
 (1 row)
 
 SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
-ERROR:  Cannot cast type 'time with time zone' to 'interval'
+ERROR:  Cannot cast type time with time zone to interval
 SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
-ERROR:  Cannot cast type 'interval' to 'time with time zone'
+ERROR:  Cannot cast type interval to time with time zone
 SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
  23:29:00-08 
 -------------
index c4d26254d4ab2a9721a20132641b1842652fd8b1..3decbdb7991dfa01557f019eb5cbb413d80adc46 100644 (file)
@@ -202,33 +202,35 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
 
 -- **************** pg_cast ****************
 -- Look for casts from and to the same type.  This is not harmful, but
--- useless.
+-- useless.  Also catch bogus values in pg_cast columns (other than
+-- cases detected by oidjoins test).
 SELECT *
 FROM pg_cast c
-WHERE c.castsource = c.casttarget;
- castsource | casttarget | castfunc | castimplicit 
-------------+------------+----------+--------------
+WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
+    OR castcontext NOT IN ('e', 'a', 'i');
+ castsource | casttarget | castfunc | castcontext 
+------------+------------+----------+-------------
 (0 rows)
 
--- Look for cast functions with incorrect number or type of argument
--- or return value.
+-- Look for cast functions that don't have the right signature.  The
+-- argument and result types in pg_proc must be the same as, or binary
+-- compatible with, what it says in pg_cast.
 SELECT c.*
 FROM pg_cast c, pg_proc p
 WHERE c.castfunc = p.oid AND
-    (p.pronargs <> 1 OR
-     p.proargtypes[0] <> c.castsource OR
-     p.prorettype <> c.casttarget);
- castsource | casttarget | castfunc | castimplicit 
-------------+------------+----------+--------------
-(0 rows)
-
--- Look for binary compatible casts that are not implicit.  This is
--- legal, but probably not intended.
-SELECT *
-FROM pg_cast c
-WHERE c.castfunc = 0 AND NOT c.castimplicit;
- castsource | casttarget | castfunc | castimplicit 
-------------+------------+----------+--------------
+    (p.pronargs <> 1
+     OR NOT (c.castsource = p.proargtypes[0] OR
+             EXISTS (SELECT 1 FROM pg_cast k
+                     WHERE k.castfunc = 0 AND
+                       k.castsource = c.castsource AND
+                       k.casttarget = p.proargtypes[0]))
+     OR NOT (p.prorettype = c.casttarget OR
+             EXISTS (SELECT 1 FROM pg_cast k
+                     WHERE k.castfunc = 0 AND
+                       k.castsource = p.prorettype AND
+                       k.casttarget = c.casttarget)));
+ castsource | casttarget | castfunc | castcontext 
+------------+------------+----------+-------------
 (0 rows)
 
 -- Look for binary compatible casts that do not have the reverse
@@ -241,8 +243,8 @@ WHERE c.castfunc = 0 AND
                 WHERE k.castfunc = 0 AND
                     k.castsource = c.casttarget AND
                     k.casttarget = c.castsource);
- castsource | casttarget | castfunc | castimplici
-------------+------------+----------+--------------
+ castsource | casttarget | castfunc | castcontex
+------------+------------+----------+-------------
 (0 rows)
 
 -- **************** pg_operator ****************
@@ -414,20 +416,18 @@ WHERE p1.oprlsortop != p1.oprrsortop AND
 -- Hashing only works on simple equality operators "type = sametype",
 -- since the hash itself depends on the bitwise representation of the type.
 -- Check that allegedly hashable operators look like they might be "=".
--- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
+-- NOTE: in 7.3, this search finds xideqint4.
 -- Until we have some cleaner way of dealing with binary-equivalent types,
--- just leave those three tuples in the expected output.
+-- just leave that tuple in the expected output.
 SELECT p1.oid, p1.oprname
 FROM pg_operator AS p1
 WHERE p1.oprcanhash AND NOT
     (p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
      p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
- oid  | oprname 
-------+---------
-  353 | =
- 1136 | =
- 1137 | =
-(3 rows)
+ oid | oprname 
+-----+---------
+ 353 | =
+(1 row)
 
 -- In 6.5 we accepted hashable array equality operators when the array element
 -- type is hashable.  However, what we actually need to make hashjoin work on
index 166be86eefd4a40562bbb494f7e645866ff5889e..629e444fb7b7fbce78823dc9ac5865dfb78744dd 100644 (file)
@@ -75,7 +75,7 @@ EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true);
 ERROR:  Wrong number of parameters, expected 6 but got 7
 -- wrong param types
 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
 -- invalid type
 PREPARE q4(nonexistenttype) AS SELECT $1;
index 6ffa0c3dcd7770511aeec91b3fa21c8fbd2bf769..a4dfd78cac364ba93ca489b86cea2ae96dc22706 100644 (file)
@@ -1321,10 +1321,10 @@ SELECT tablename, rulename, definition FROM pg_rules
  rtest_nothn1  | rtest_nothn_r2  | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
  rtest_nothn2  | rtest_nothn_r3  | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);
  rtest_nothn2  | rtest_nothn_r4  | CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2 DO INSTEAD NOTHING;
- rtest_order1  | rtest_order_r1  | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 1 - this should run 3rd or 4th'::text);
- rtest_order1  | rtest_order_r2  | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 2 - this should run 1st'::text);
- rtest_order1  | rtest_order_r3  | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 3 - this should run 3rd or 4th'::text);
- rtest_order1  | rtest_order_r4  | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 4 - this should run 2nd'::text);
+ rtest_order1  | rtest_order_r1  | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 1 - this should run 3rd or 4th'::text);
+ rtest_order1  | rtest_order_r2  | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 2 - this should run 1st'::text);
+ rtest_order1  | rtest_order_r3  | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 3 - this should run 3rd or 4th'::text);
+ rtest_order1  | rtest_order_r4  | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 4 - this should run 2nd'::text);
  rtest_person  | rtest_pers_del  | CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person DO DELETE FROM rtest_admin WHERE (rtest_admin.pname = old.pname);
  rtest_person  | rtest_pers_upd  | CREATE RULE rtest_pers_upd AS ON UPDATE TO rtest_person DO UPDATE rtest_admin SET pname = new.pname WHERE (rtest_admin.pname = old.pname);
  rtest_system  | rtest_sys_del   | CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system DO (DELETE FROM rtest_interface WHERE (rtest_interface.sysname = old.sysname); DELETE FROM rtest_admin WHERE (rtest_admin.sysname = old.sysname); );
index ce81969936c5e1a9355e50d0dbc9ba653200e3b0..576fafb7729493308ae297abe0b2f7254d75868f 100644 (file)
@@ -47,8 +47,15 @@ SELECT CAST(name 'namefield' AS text) AS "text(name)";
  namefield
 (1 row)
 
-SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
-ERROR:  value too long for type character(10)
+-- since this is an explicit cast, it should truncate w/o error:
+SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
+ char(text) 
+------------
+ doh!      
+ hi de ho n
+(2 rows)
+
+-- note: implicit-cast case is tested in char.sql
 SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
       char(text)      
 ----------------------
index 0adad8c119d314a4572789ba47287651fdade9ee..a46a44becab4b2a76792d5871373fe02aeea051e 100644 (file)
@@ -90,7 +90,7 @@ SELECT 1.1 AS two UNION ALL SELECT 2;
 SELECT 1.0 AS two UNION ALL SELECT 1;
  two 
 -----
-   1
+ 1.0
    1
 (2 rows)
 
index 9627870934fe16e533adb5c3f7d3bc86288e551c..a5690694cad3cb431e4f33642a2eaaa0778f3d16 100644 (file)
@@ -20,9 +20,9 @@ create domain domainnumeric numeric(8,2);
 create domain domainint4 int4;
 create domain domaintext text;
 
--- Test coercions
-SELECT cast('123456' as domainvarchar); -- fail
-SELECT cast('12345' as domainvarchar); -- pass
+-- Test explicit coercions --- these should succeed (and truncate)
+SELECT cast('123456' as domainvarchar);
+SELECT cast('12345' as domainvarchar);
 
 -- Test tables using domains
 create table basictest
index 136e6c6c6517c046afe3b27bec4d9660b4084593..6d767d23760a57816e29d1bd4bbeb7a01082078a 100644 (file)
@@ -90,8 +90,8 @@ SELECT (timestamp without time zone 'tomorrow' > 'now') as "True";
 -- to enable support for SQL99 timestamp type syntax.
 SELECT date '1994-01-01' + time '11:00' AS "Jan_01_1994_11am";
 SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
 
 SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
 SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;
index 9c3a93e30bea871dc8e9c898d727a4cc20f7bdc0..faacc83850e8c7f673e054387d3ea811c2abab28 100644 (file)
@@ -162,28 +162,32 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
 -- **************** pg_cast ****************
 
 -- Look for casts from and to the same type.  This is not harmful, but
--- useless.
+-- useless.  Also catch bogus values in pg_cast columns (other than
+-- cases detected by oidjoins test).
 
 SELECT *
 FROM pg_cast c
-WHERE c.castsource = c.casttarget;
+WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
+    OR castcontext NOT IN ('e', 'a', 'i');
 
--- Look for cast functions with incorrect number or type of argument
--- or return value.
+-- Look for cast functions that don't have the right signature.  The
+-- argument and result types in pg_proc must be the same as, or binary
+-- compatible with, what it says in pg_cast.
 
 SELECT c.*
 FROM pg_cast c, pg_proc p
 WHERE c.castfunc = p.oid AND
-    (p.pronargs <> 1 OR
-     p.proargtypes[0] <> c.castsource OR
-     p.prorettype <> c.casttarget);
-
--- Look for binary compatible casts that are not implicit.  This is
--- legal, but probably not intended.
-
-SELECT *
-FROM pg_cast c
-WHERE c.castfunc = 0 AND NOT c.castimplicit;
+    (p.pronargs <> 1
+     OR NOT (c.castsource = p.proargtypes[0] OR
+             EXISTS (SELECT 1 FROM pg_cast k
+                     WHERE k.castfunc = 0 AND
+                       k.castsource = c.castsource AND
+                       k.casttarget = p.proargtypes[0]))
+     OR NOT (p.prorettype = c.casttarget OR
+             EXISTS (SELECT 1 FROM pg_cast k
+                     WHERE k.castfunc = 0 AND
+                       k.castsource = p.prorettype AND
+                       k.casttarget = c.casttarget)));
 
 -- Look for binary compatible casts that do not have the reverse
 -- direction registered as well, or where the reverse direction is not
@@ -341,9 +345,9 @@ WHERE p1.oprlsortop != p1.oprrsortop AND
 -- Hashing only works on simple equality operators "type = sametype",
 -- since the hash itself depends on the bitwise representation of the type.
 -- Check that allegedly hashable operators look like they might be "=".
--- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
+-- NOTE: in 7.3, this search finds xideqint4.
 -- Until we have some cleaner way of dealing with binary-equivalent types,
--- just leave those three tuples in the expected output.
+-- just leave that tuple in the expected output.
 
 SELECT p1.oid, p1.oprname
 FROM pg_operator AS p1
index 692233793dc74c7996601d8ac14149b6e3ac9b32..e5c15bc528fdfd516d12dea5821a4703cb2ed081 100644 (file)
@@ -27,7 +27,9 @@ SELECT CAST(f1 AS text) AS "text(varchar)" FROM VARCHAR_TBL;
 
 SELECT CAST(name 'namefield' AS text) AS "text(name)";
 
-SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
+-- since this is an explicit cast, it should truncate w/o error:
+SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
+-- note: implicit-cast case is tested in char.sql
 
 SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;