diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index a8fd81e19c948bf285e9ae82d1d5135264c04785..01dfe6ad73b3c8697b30b6a2981a3b525b46d4dd 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -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">
@@ -841,9 +841,8 @@
   <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>
@@ -879,17 +878,25 @@
       <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>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 41ca3c00e53669a2f05ec6aa74782ac2591dc223..28d3fcb7edeb88303ff341300d740ac775a5f06d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -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>
 
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
index bc9f71e566ea78e38b3eff460497bacdcc2800d5..e64d696f81afc9ee11d966e627d54dae1e90318f 100644
--- a/doc/src/sgml/ref/create_cast.sgml
+++ b/doc/src/sgml/ref/create_cast.sgml
@@ -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>
@@ -15,11 +15,11 @@
 <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>
 
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index b7f2b4be71b57b181a4deb8baae6b1fdc5db3cf8..f373cc6e25df86c8c80408365a96fd3406acae44 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -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
diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml
index 0bfc40b1edf16c8c90867c41b488f9d0fbc26cb7..e6ff564be969ace3e8bd0b9e0c3d85661e0342e1 100644
--- a/doc/src/sgml/typeconv.sgml
+++ b/doc/src/sgml/typeconv.sgml
@@ -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>
 
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index f09d1fc1debb902f5db1b6b202f0364091f620d9..6bc15b8060a3694ec20103945ffdd27941bfa9de 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -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));
 	}
 
 	/*
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 7b83cf960d97e0e8cb87612854e21f3bd9121fbf..37794645ee58d4f9d9a15c5831fd59f42cb34335 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -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);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index ba667a26542525903cb51443ca323a23b2c27fc9..b915a02c310ac4b619fccce47ce87e98b97037d5 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -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),
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index a935dae7e6e7f07f9dc09b6ec9cafbc86821736b..f67538625ac6fa62ce547458fe1face42bb4f396 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -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);
 }
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 6f0c8438a894519a9464c177ea21fcbd8bae3f56..9660cb61b83e468d5ddb5dab0d0e183f73fbb5ca 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -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;
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 1a9239c57b94c7f24aa1f9cc8cca8e868ec71fc9..898ca62a6005495b8c0e438e5f2332fa667762ab 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -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);
 		}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2964085e0aa2958a8d8545f3dd7c552d53e68b10..73e240aca7c2dd24af21f7fb8bc75e3ff85643f8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7f677c0837c09359fe50fcb09bda91917a46737f..8c5d6a0337ab3ce671043e4887e81438523604e3 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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;
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 8363fccfa6e40fc33b0e0f3aef6e9058ca5feee6..b92011445e3467f40a56c3d2ad74f98ed9bde8ae 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -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;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 8873c4e3d2c998c52e5c700220ec6fd258407670..fde42291691cd8d0acb8270b2cd12f1bafddbe3b 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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);
 }
 
 /*
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 14edd8e3d13eb6a2d04ff6fcf908a68bb13f33b1..a4f0c81fa1eeec7e2e2f90f8467fc50fbd77a505 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -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;
 }
 
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 5595e1aec9929897d8ecb83fb9a4be2d82b83204..cfd20e8f488f91b9170c1b712ac49ae643a846e1 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -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;
 }
 
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index fc33d5296ad7fdffc317711b0560ec23e11d62d0..350c761165b4ff65505676f03591ac2d232c7f2e 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -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)
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index da3568bbd7d8deffbe9eba454016825e477a7b0a..9cdbcc2e5e548206392263f54ef63d5a87341902 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -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));
 	}
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 5b930e2b5e62ed819a6e008778672f890ce94664..95687cb0d0d0d09eed4ce197f0223888e4d2926c 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -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 */
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 414e26c54cbeef538205d4ef7e31f1171f8f3b98..914b0eee618cd1d4bbde35d194f8912c80d08e92 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -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;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 97b242b9b6bc46d3d773c918459eb040f3d4d818..663ae22d9429c0990743e8df57f98ff3ebab1b89 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d038cdd46e7b7486f8fa460b2f3c37896e5eeffd..43597306d4410a67c520a26a2e02af25e2f579f1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 9a3064ad661596bea9b1ce1287679dc4117f6dab..305ed8601812e1b5ad4e619baeccebd9136d1fec 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -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},
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index a46ff5e2fcd76958fdfc600d9768a9351f89a113..245c0ba422bab57987c85830876c8158c9947898 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -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;
 
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index d57e18f2324e500a7f60adcd81e8ba87a85f4af0..c0081133eb3a5116650ffa0421e4ffcabec263d1 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,28 +23,104 @@
 #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);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 7be413f6b5bd2b1f34289a1c4c7a6000e11a0295..3873fd37f0de436dd1669b0a7602f9c862724480 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -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;
 }
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 648ddfbaf0ca4391176ad0e4dab1e7c89ffc42b7..9a54a900aeaf4db2c52fd3734e79f786d6d4496f 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,15 +32,12 @@
 #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;
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 391694fa198523d8607684d6d67e2ecdb9fc4a4f..408fb4f11f6c1c310f35a8651db813590903b3f3 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -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"
@@ -29,14 +24,11 @@
 #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;
-}
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index ecf1a2abece4241a6fa36e4ce41d9c9f25635f39..776acc78bfae1729354e14cf15e8a75454f5f3b6 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -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... */
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index b9c5b6cb137da86a3b8875b63a83162711718c67..18d11cc7f5ac55c5f0ba87eab9a63f66389b66ce 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -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
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 95fc726227f802bb7619bf81e11465b6c0f2f0a8..0b2d839eb3f9570a21c7187f659ff1c1b896f228 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -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;
 }
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 5d53eca999fdea5f0fc2cc7599cbd0f90896110f..f864338897037c3a63e6bcebb4cf496b5ac79da8 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -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"
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 267ad821037d10b89cc26c46b4f767edce8d7a34..8a346cd8b838be5520de718356ed2d6dbf59b6e6 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,14 +48,16 @@
  * 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)
 {
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 228c43c6c4644f1f31fa3c9e7ab83cff29fadd0c..4ea0fec1c1a13e71ae41bfbffc06caffe2b765d3 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -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
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 22c93c431a068e37decdd61b8d25020de9d173d3..638f5293ed2d7a3f2f2b1e8c298dae8f3193d7e6 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -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);
 	}
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 740dde36dd49ac7670f2299e7da9dafd0c38dedf..9f21a609f3dfc179d87e9da46ce9e127690b99f7 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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);
 }
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index f0c31a3961b4a45f529bb36befd941508a0c62ab..715a99863fda2a1deb3a7aa4f97c69c3940ce48c 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,11 @@
  *	  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)
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 780daf756555dcb3b2271f228265ce8c5c7a8c67..03579f437b62b15ba79ad1382d3efdc934d2df90 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -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
  *****************************************************************************/
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 2672ed3aada445c14854bc01796a21e006933481..c8a038d8a7d752fd63bbf9df5c049e17d20d2fd5 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -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
  *
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
index a3fad0d6834cb6f4ae099ce1b62c2442afab8323..830263bb03c1c18f31d76c3d860d29f1d9ce997a 100644
--- a/src/bin/initdb/initdb.sh
+++ b/src/bin/initdb/initdb.sh
@@ -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
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 3945c3e600585b29626889353740b05cc46f4aa7..d19fcf461c8c26282f40214262657a5d64775fcc 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -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,
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 817ef79bcafd2bf2811fcf35d655cbb3113221b1..21a7732c5fb028ddca3636b16f3bacee4202b682 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -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
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 31763358d1c8925698153e1edd6011b5243afc63..48ff930bafb770b7fd5ca34ed95f4bfee1ed0a18 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -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 */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index c770150f7346ece1d4dbb49ebb8cbde0d40ef1c6..c97003cf43150fd585d3218663511ac387ccf9fe 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -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 - - ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ff2200d2cc000dd6bef096b659416a2ae4f0a391..eb44f283b9197812b80de05070fb6692b66c3657 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -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");
 
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index f4e69d3d15886377e8a7d53ce206ad0f2d19ef52..e7c9c29413cbd78b19bafa82fb5c4ccfa5cb4984 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -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);
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 0f703e27eccc612e36c6ff2bdacf57478dadb5b3..56e3922ea9f453f0c7fa19c627cd10bd01f0141a 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -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;
 
 /* ----------------------
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 111ed7f8ce8474c6639a74d828dd58476557a909..1d7c5115b64a44fa2057144335cdd2aed09f9e70 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -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;
 
 
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index 152ade0e9bd5f92e6eb1bfdfa028bb6b4dd87ebf..61a63cafeb49f414757d8c20bede7bb6694a1086 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -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 */
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 8fac035fcc62cc6080ee74fdcd703f7d2eb72c22..beb16e2cc8e916cd452a49548014b7af4f5e1448 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -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);
diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h
index acca0f05690fa35a625fb829b3162f6b5851f76e..b8c495484bfd1ac13f184905b8f6073291d2e985 100644
--- a/src/include/parser/parse_target.h
+++ b/src/include/parser/parse_target.h
@@ -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);
 
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index 5c1276467c083df01643421318c218b30c2baead..639d9dc31535b0eb16473cdb185815d3acc433ee 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -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);
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index e97982215d84df14bd42524083315186d88603ea..d9f611bcfd8dc9ee9b14bb94c095147ccf657899 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -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);
diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h
index 4ffa3bca50485a464d6ffc56ff3371c7db3de570..f8b337e3c0c31626873025110daf2adf61e91a1d 100644
--- a/src/include/utils/int8.h
+++ b/src/include/utils/int8.h
@@ -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);
 
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 029fdcdc8638ea6b1e071cd66dc453fc55bfd8e6..5dee7bc0cbb8bdd3b0e2f96c00894ffa58edc117 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -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,
diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h
index 8dff3166d566b48c56f7441b363e66279fd1e6bb..9e5505624b6aea837fcef87d51900110bb140fb9 100644
--- a/src/include/utils/varbit.h
+++ b/src/include/utils/varbit.h
@@ -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);
diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out
index 522c28121ff27ef071895d5b017394ac133732f8..8bbed8c431ddf2e48aaf7fec82988f9004c09ce1 100644
--- a/src/test/regress/expected/domain.out
+++ b/src/test/regress/expected/domain.out
@@ -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
diff --git a/src/test/regress/expected/horology-no-DST-before-1970.out b/src/test/regress/expected/horology-no-DST-before-1970.out
index 3561fac04bf1fec0496d3392114f0b079e3f8c45..b8b7423ec520f01c286b2f5a72b5758255e2279f 100644
--- a/src/test/regress/expected/horology-no-DST-before-1970.out
+++ b/src/test/regress/expected/horology-no-DST-before-1970.out
@@ -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 
 -------------
diff --git a/src/test/regress/expected/horology-solaris-1947.out b/src/test/regress/expected/horology-solaris-1947.out
index 22d335c6c2c19eb60b6d9ee6d905c048d9ce3675..1601a346f01612f152b18e3568be3f10fcf7fd0e 100644
--- a/src/test/regress/expected/horology-solaris-1947.out
+++ b/src/test/regress/expected/horology-solaris-1947.out
@@ -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 
 -------------
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index 83d92182d085726ba638f8f5990c92e1c9b0f678..294b7854106ba88388d0c70a8f92e559e4406447 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -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 
 -------------
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index c4d26254d4ab2a9721a20132641b1842652fd8b1..3decbdb7991dfa01557f019eb5cbb413d80adc46 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -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 | castimplicit 
-------------+------------+----------+--------------
+ castsource | casttarget | castfunc | castcontext 
+------------+------------+----------+-------------
 (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
diff --git a/src/test/regress/expected/prepare.out b/src/test/regress/expected/prepare.out
index 166be86eefd4a40562bbb494f7e645866ff5889e..629e444fb7b7fbce78823dc9ac5865dfb78744dd 100644
--- a/src/test/regress/expected/prepare.out
+++ b/src/test/regress/expected/prepare.out
@@ -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;
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 6ffa0c3dcd7770511aeec91b3fa21c8fbd2bf769..a4dfd78cac364ba93ca489b86cea2ae96dc22706 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -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); );
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index ce81969936c5e1a9355e50d0dbc9ba653200e3b0..576fafb7729493308ae297abe0b2f7254d75868f 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -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)      
 ----------------------
diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out
index 0adad8c119d314a4572789ba47287651fdade9ee..a46a44becab4b2a76792d5871373fe02aeea051e 100644
--- a/src/test/regress/expected/union.out
+++ b/src/test/regress/expected/union.out
@@ -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)
 
diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql
index 9627870934fe16e533adb5c3f7d3bc86288e551c..a5690694cad3cb431e4f33642a2eaaa0778f3d16 100644
--- a/src/test/regress/sql/domain.sql
+++ b/src/test/regress/sql/domain.sql
@@ -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
diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql
index 136e6c6c6517c046afe3b27bec4d9660b4084593..6d767d23760a57816e29d1bd4bbeb7a01082078a 100644
--- a/src/test/regress/sql/horology.sql
+++ b/src/test/regress/sql/horology.sql
@@ -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;
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 9c3a93e30bea871dc8e9c898d727a4cc20f7bdc0..faacc83850e8c7f673e054387d3ea811c2abab28 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -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
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index 692233793dc74c7996601d8ac14149b6e3ac9b32..e5c15bc528fdfd516d12dea5821a4703cb2ed081 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -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;