Re: User defined I/O conversion casts

Поиск
Список
Период
Сортировка
От Heikki Linnakangas
Тема Re: User defined I/O conversion casts
Дата
Msg-id 490A138E.80100@enterprisedb.com
обсуждение исходный текст
Ответ на Re: User defined I/O conversion casts  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: User defined I/O conversion casts  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
Tom Lane wrote:
> Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:
>> Yeah, a magical OID clearly has some issues. A new field in pg_cast is
>> the obvious alternative. How about adding a "castmethod" char field,
>> with values:
>> b = binary-compatible cast (CREATE CAST ... WITHOUT FUNCTION)
>> i = I/O coercion cast (the new beast, CREATE CAST ... WITH INOUT)
>> f = use cast function specified in castfunc field.
>> castfunc is 0 for methods b and i.
>
> Seems sane to me.  If you do that, please add a check in the opr_sanity
> regression test that castfunc is nonzero if and only if castmethod is f.

Here's a patch. It seems pretty straightforward, I'll apply this
tomorrow, barring objections. Note to self: bump the catalog version.

BTW, it looks like we don't have any test cases for the CREATE CAST
command. I think I'll add one.

--
   Heikki Linnakangas
   EnterpriseDB   http://www.enterprisedb.com
*** doc/src/sgml/catalogs.sgml
--- doc/src/sgml/catalogs.sgml
***************
*** 1415,1423 ****
     cannot be deduced from some generic rule.  For example, casting between a
     domain and its base type is not explicitly represented in
     <structname>pg_cast</structname>.  Another important exception is that
!    <quote>I/O conversion casts</>, those performed using a data type's own
!    I/O functions to convert to or from <type>text</> or other string types,
!    are not explicitly represented in <structname>pg_cast</structname>.
    </para>

    <table>
--- 1415,1424 ----
     cannot be deduced from some generic rule.  For example, casting between a
     domain and its base type is not explicitly represented in
     <structname>pg_cast</structname>.  Another important exception is that
!    <quote>automatic I/O conversion casts</>, those performed using a data
!    type's own I/O functions to convert to or from <type>text</> or other
!    string types, are not explicitly represented in
!    <structname>pg_cast</structname>.
    </para>

    <table>
***************
*** 1454,1461 ****
        <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
        <entry>
         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>

--- 1455,1461 ----
        <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
        <entry>
         The OID of the function to use to perform this cast.  Zero is
!        stored if the cast method doesn't require a function.
        </entry>
       </row>

***************
*** 1473,1478 ****
--- 1473,1489 ----
         other cases
        </entry>
       </row>
+      <row>
+       <entry><structfield>castmethod</structfield></entry>
+       <entry><type>char</type></entry>
+       <entry></entry>
+       <entry>
+        Indicates how the cast is performed.
+        <literal>f</> means that the function specified in the <structfield>castfunc</> field is used.
+        <literal>i</> means that the input/output functions are used.
+        <literal>b</> means that the types are binary-coercible, thus no conversion is required
+       </entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
*** doc/src/sgml/ref/create_cast.sgml
--- doc/src/sgml/ref/create_cast.sgml
***************
*** 24,29 **** CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r
--- 24,33 ----
  CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
      WITHOUT FUNCTION
      [ AS ASSIGNMENT | AS IMPLICIT ]
+
+ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
+     WITH INOUT
+     [ AS ASSIGNMENT | AS IMPLICIT ]
  </synopsis>
   </refsynopsisdiv>

***************
*** 59,64 **** SELECT CAST(42 AS float8);
--- 63,75 ----
    </para>

    <para>
+    You can define a cast as an <firstterm>I/O conversion cast</> using
+    the <literal>WITH INOUT</literal> syntax. An I/O conversion cast is
+    performed by invoking the output function of the source data type, and
+    passing the result to the input function of the target data type.
+   </para>
+
+   <para>
     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> or
***************
*** 200,205 **** SELECT CAST ( 2 AS numeric ) + 4.0;
--- 211,228 ----
      </varlistentry>

      <varlistentry>
+      <term><literal>WITH INOUT</literal></term>
+
+      <listitem>
+       <para>
+        Indicates that the cast is an I/O conversion cast, performed by
+        invoking the output function of the source data type, and passing the
+        result to the input function of the target data type.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><literal>AS ASSIGNMENT</literal></term>

       <listitem>
***************
*** 284,296 **** SELECT CAST ( 2 AS numeric ) + 4.0;
     It is normally not necessary to create casts between user-defined types
     and the standard string types (<type>text</>, <type>varchar</>, and
     <type>char(<replaceable>n</>)</type>, as well as user-defined types that
!    are defined to be in the string category).  <productname>PostgreSQL</> will
!    automatically handle a cast to a string type by invoking the other
!    type's output function, or conversely handle a cast from a string type
!    by invoking the other type's input function.  These
!    automatically-provided casts are known as <firstterm>I/O conversion
!    casts</>.  I/O conversion casts to string types are treated as
!    assignment casts, while I/O conversion casts from string types are
     explicit-only.  You can override this behavior by declaring your own
     cast to replace an I/O conversion cast, but usually the only reason to
     do so is if you want the conversion to be more easily invokable than the
--- 307,316 ----
     It is normally not necessary to create casts between user-defined types
     and the standard string types (<type>text</>, <type>varchar</>, and
     <type>char(<replaceable>n</>)</type>, as well as user-defined types that
!    are defined to be in the string category).  <productname>PostgreSQL</>
!    provides automatic I/O conversion casts for that. The automatic casts to
!    string types are treated as assignment casts, while the automatic casts
!    from string types are
     explicit-only.  You can override this behavior by declaring your own
     cast to replace an I/O conversion cast, but usually the only reason to
     do so is if you want the conversion to be more easily invokable than the
*** src/backend/commands/functioncmds.c
--- src/backend/commands/functioncmds.c
***************
*** 1383,1388 **** CreateCast(CreateCastStmt *stmt)
--- 1383,1389 ----
      Oid            funcid;
      int            nargs;
      char        castcontext;
+     char        castmethod;
      Relation    relation;
      HeapTuple    tuple;
      Datum        values[Natts_pg_cast];
***************
*** 1415,1421 **** CreateCast(CreateCastStmt *stmt)
--- 1416,1430 ----
                          format_type_be(sourcetypeid),
                          format_type_be(targettypeid))));

+     /* Detemine the cast method */
      if (stmt->func != NULL)
+         castmethod = COERCION_METHOD_FUNCTION;
+     else if(stmt->inout)
+         castmethod = COERCION_METHOD_INOUT;
+     else
+         castmethod = COERCION_METHOD_BINARY;
+
+     if (castmethod == COERCION_METHOD_FUNCTION)
      {
          Form_pg_proc procstruct;

***************
*** 1476,1481 **** CreateCast(CreateCastStmt *stmt)
--- 1485,1496 ----
      }
      else
      {
+         funcid = InvalidOid;
+         nargs = 0;
+     }
+
+     if (castmethod == COERCION_METHOD_BINARY)
+     {
          int16        typ1len;
          int16        typ2len;
          bool        typ1byval;
***************
*** 1483,1492 **** CreateCast(CreateCastStmt *stmt)
          char        typ1align;
          char        typ2align;

-         /* indicates binary coercibility */
-         funcid = InvalidOid;
-         nargs = 0;
-
          /*
           * Must be superuser to create binary-compatible casts, since
           * erroneous casts can easily crash the backend.
--- 1498,1503 ----
***************
*** 1562,1567 **** CreateCast(CreateCastStmt *stmt)
--- 1573,1579 ----
      values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
      values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
      values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
+     values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);

      MemSet(nulls, ' ', Natts_pg_cast);

*** src/backend/nodes/copyfuncs.c
--- src/backend/nodes/copyfuncs.c
***************
*** 3042,3047 **** _copyCreateCastStmt(CreateCastStmt *from)
--- 3042,3048 ----
      COPY_NODE_FIELD(targettype);
      COPY_NODE_FIELD(func);
      COPY_SCALAR_FIELD(context);
+     COPY_SCALAR_FIELD(inout);

      return newnode;
  }
*** src/backend/nodes/equalfuncs.c
--- src/backend/nodes/equalfuncs.c
***************
*** 1666,1671 **** _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
--- 1666,1672 ----
      COMPARE_NODE_FIELD(targettype);
      COMPARE_NODE_FIELD(func);
      COMPARE_SCALAR_FIELD(context);
+     COMPARE_SCALAR_FIELD(inout);

      return true;
  }
*** src/backend/parser/gram.y
--- src/backend/parser/gram.y
***************
*** 4590,4595 **** CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
--- 4590,4596 ----
                      n->targettype = $6;
                      n->func = $10;
                      n->context = (CoercionContext) $11;
+                     n->inout = false;
                      $$ = (Node *)n;
                  }
              | CREATE CAST '(' Typename AS Typename ')'
***************
*** 4600,4605 **** CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
--- 4601,4618 ----
                      n->targettype = $6;
                      n->func = NULL;
                      n->context = (CoercionContext) $10;
+                     n->inout = false;
+                     $$ = (Node *)n;
+                 }
+             | CREATE CAST '(' Typename AS Typename ')'
+                     WITH INOUT cast_context
+                 {
+                     CreateCastStmt *n = makeNode(CreateCastStmt);
+                     n->sourcetype = $4;
+                     n->targettype = $6;
+                     n->func = NULL;
+                     n->context = (CoercionContext) $10;
+                     n->inout = true;
                      $$ = (Node *)n;
                  }
          ;
*** src/backend/parser/parse_coerce.c
--- src/backend/parser/parse_coerce.c
***************
*** 1909,1919 **** find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
          /* Rely on ordering of enum for correct behavior here */
          if (ccontext >= castcontext)
          {
!             *funcid = castForm->castfunc;
!             if (OidIsValid(*funcid))
!                 result = COERCION_PATH_FUNC;
!             else
!                 result = COERCION_PATH_RELABELTYPE;
          }

          ReleaseSysCache(tuple);
--- 1909,1931 ----
          /* Rely on ordering of enum for correct behavior here */
          if (ccontext >= castcontext)
          {
!             switch (castForm->castmethod)
!             {
!                 case COERCION_METHOD_FUNCTION:
!                     result = COERCION_PATH_FUNC;
!                     *funcid = castForm->castfunc;
!                     break;
!                 case COERCION_METHOD_INOUT:
!                     result = COERCION_PATH_COERCEVIAIO;
!                     break;
!                 case COERCION_METHOD_BINARY:
!                     result = COERCION_PATH_RELABELTYPE;
!                     break;
!                 default:
!                     elog(ERROR, "unrecognized castmethod: %d",
!                          (int) castForm->castmethod);
!                     break;
!             }
          }

          ReleaseSysCache(tuple);
*** src/bin/pg_dump/pg_dump.c
--- src/bin/pg_dump/pg_dump.c
***************
*** 36,41 **** int            optreset;
--- 36,42 ----

  #include "access/attnum.h"
  #include "access/sysattr.h"
+ #include "catalog/pg_cast.h"
  #include "catalog/pg_class.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_trigger.h"
***************
*** 4410,4430 **** getCasts(int *numCasts)
      int            i_casttarget;
      int            i_castfunc;
      int            i_castcontext;

      /* Make sure we are in proper schema */
      selectSourceSchema("pg_catalog");

!     if (g_fout->remoteVersion >= 70300)
      {
          appendPQExpBuffer(query, "SELECT tableoid, oid, "
!                           "castsource, casttarget, castfunc, castcontext "
                            "FROM pg_cast ORDER BY 3,4");
      }
      else
      {
          appendPQExpBuffer(query, "SELECT 0 as tableoid, p.oid, "
                            "t1.oid as castsource, t2.oid as casttarget, "
!                           "p.oid as castfunc, 'e' as castcontext "
                            "FROM pg_type t1, pg_type t2, pg_proc p "
                            "WHERE p.pronargs = 1 AND "
                            "p.proargtypes[0] = t1.oid AND "
--- 4411,4441 ----
      int            i_casttarget;
      int            i_castfunc;
      int            i_castcontext;
+     int            i_castmethod;

      /* Make sure we are in proper schema */
      selectSourceSchema("pg_catalog");

!     if (g_fout->remoteVersion >= 80400)
!     {
!         appendPQExpBuffer(query, "SELECT tableoid, oid, "
!                           "castsource, casttarget, castfunc, castcontext, "
!                           "castmethod "
!                           "FROM pg_cast ORDER BY 3,4");
!     }
!     else if (g_fout->remoteVersion >= 70300)
      {
          appendPQExpBuffer(query, "SELECT tableoid, oid, "
!                           "castsource, casttarget, castfunc, castcontext, "
!                           "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END "
                            "FROM pg_cast ORDER BY 3,4");
      }
      else
      {
          appendPQExpBuffer(query, "SELECT 0 as tableoid, p.oid, "
                            "t1.oid as castsource, t2.oid as casttarget, "
!                           "p.oid as castfunc, 'e' as castcontext, "
!                           "'f' as castmethod "
                            "FROM pg_type t1, pg_type t2, pg_proc p "
                            "WHERE p.pronargs = 1 AND "
                            "p.proargtypes[0] = t1.oid AND "
***************
*** 4447,4452 **** getCasts(int *numCasts)
--- 4458,4464 ----
      i_casttarget = PQfnumber(res, "casttarget");
      i_castfunc = PQfnumber(res, "castfunc");
      i_castcontext = PQfnumber(res, "castcontext");
+     i_castmethod = PQfnumber(res, "castmethod");

      for (i = 0; i < ntups; i++)
      {
***************
*** 4462,4467 **** getCasts(int *numCasts)
--- 4474,4480 ----
          castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
          castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
          castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
+         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));

          /*
           * Try to name cast as concatenation of typnames.  This is only used
***************
*** 7188,7205 **** dumpCast(Archive *fout, CastInfo *cast)
                        getFormattedTypeName(cast->castsource, zeroAsNone),
                        getFormattedTypeName(cast->casttarget, zeroAsNone));

!     if (!OidIsValid(cast->castfunc))
!         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
!     else
      {
!         /*
!          * Always qualify the function name, in case it is not in pg_catalog
!          * schema (format_function_signature won't qualify it).
!          */
!         appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
!                           fmtId(funcInfo->dobj.namespace->dobj.name));
!         appendPQExpBuffer(defqry, "%s",
!                           format_function_signature(funcInfo, true));
      }

      if (cast->castcontext == 'a')
--- 7201,7226 ----
                        getFormattedTypeName(cast->castsource, zeroAsNone),
                        getFormattedTypeName(cast->casttarget, zeroAsNone));

!     switch(cast->castmethod)
      {
!         case COERCION_METHOD_BINARY:
!             appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
!             break;
!         case COERCION_METHOD_INOUT:
!             appendPQExpBuffer(defqry, "WITH INOUT");
!             break;
!         case COERCION_METHOD_FUNCTION:
!             /*
!              * Always qualify the function name, in case it is not in
!              * pg_catalog schema (format_function_signature won't qualify it).
!              */
!             appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
!                               fmtId(funcInfo->dobj.namespace->dobj.name));
!             appendPQExpBuffer(defqry, "%s",
!                               format_function_signature(funcInfo, true));
!             break;
!         default:
!             write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
      }

      if (cast->castcontext == 'a')
*** src/bin/pg_dump/pg_dump.h
--- src/bin/pg_dump/pg_dump.h
***************
*** 376,381 **** typedef struct _castInfo
--- 376,382 ----
      Oid            casttarget;
      Oid            castfunc;
      char        castcontext;
+     char        castmethod;
  } CastInfo;

  /* InhInfo isn't a DumpableObject, just temporary state */
*** src/include/catalog/pg_cast.h
--- src/include/catalog/pg_cast.h
***************
*** 36,41 **** CATALOG(pg_cast,2605)
--- 36,42 ----
      Oid            casttarget;        /* destination datatype for cast */
      Oid            castfunc;        /* cast function; 0 = binary coercible */
      char        castcontext;    /* contexts in which cast can be used */
+     char        castmethod;        /* cast method */
  } FormData_pg_cast;

  typedef FormData_pg_cast *Form_pg_cast;
***************
*** 56,71 **** typedef enum CoercionCodes
      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_castcontext    4

  /* ----------------
   *        initial contents of pg_cast
--- 57,85 ----
      COERCION_CODE_EXPLICIT = 'e'    /* explicit cast operation */
  } CoercionCodes;

+ /*
+  * The allowable values for pg_cast.castmethod are specified by this enum.
+  * Since castcontext is stored as a "char", we use ASCII codes for human
+  * convenience in reading the table.
+  */
+ typedef enum CoercionMethod
+ {
+     COERCION_METHOD_FUNCTION = 'f',        /* use a function */
+     COERCION_METHOD_BINARY = 'b',        /* types are binary-compatible */
+     COERCION_METHOD_INOUT = 'i'            /* use input/output functions */
+ } CoercionMethod;
+

  /* ----------------
   *        compiler constants for pg_cast
   * ----------------
   */
! #define Natts_pg_cast                5
  #define Anum_pg_cast_castsource        1
  #define Anum_pg_cast_casttarget        2
  #define Anum_pg_cast_castfunc        3
  #define Anum_pg_cast_castcontext    4
+ #define Anum_pg_cast_castmethod        5

  /* ----------------
   *        initial contents of pg_cast
***************
*** 80,119 **** typedef enum CoercionCodes
   * int2->int4->int8->numeric->float4->float8, while casts in the
   * reverse direction are assignment-only.
   */
! 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 ));

  /* Allow explicit coercions between int4 and bool */
! DATA(insert (    23    16    2557 e ));
! DATA(insert (    16    23    2558 e ));

  /*
   * OID category: allow implicit conversion from any integral type (including
--- 94,133 ----
   * int2->int4->int8->numeric->float4->float8, while casts in the
   * reverse direction are assignment-only.
   */
! DATA(insert (    20     21  714 a f ));
! DATA(insert (    20     23  480 a f ));
! DATA(insert (    20    700  652 i f ));
! DATA(insert (    20    701  482 i f ));
! DATA(insert (    20 1700 1781 i f ));
! DATA(insert (    21     20  754 i f ));
! DATA(insert (    21     23  313 i f ));
! DATA(insert (    21    700  236 i f ));
! DATA(insert (    21    701  235 i f ));
! DATA(insert (    21 1700 1782 i f ));
! DATA(insert (    23     20  481 i f ));
! DATA(insert (    23     21  314 a f ));
! DATA(insert (    23    700  318 i f ));
! DATA(insert (    23    701  316 i f ));
! DATA(insert (    23 1700 1740 i f ));
! DATA(insert (  700     20  653 a f ));
! DATA(insert (  700     21  238 a f ));
! DATA(insert (  700     23  319 a f ));
! DATA(insert (  700    701  311 i f ));
! DATA(insert (  700 1700 1742 a f ));
! DATA(insert (  701     20  483 a f ));
! DATA(insert (  701     21  237 a f ));
! DATA(insert (  701     23  317 a f ));
! DATA(insert (  701    700  312 a f ));
! DATA(insert (  701 1700 1743 a f ));
! DATA(insert ( 1700     20 1779 a f ));
! DATA(insert ( 1700     21 1783 a f ));
! DATA(insert ( 1700     23 1744 a f ));
! DATA(insert ( 1700    700 1745 i f ));
! DATA(insert ( 1700    701 1746 i f ));

  /* Allow explicit coercions between int4 and bool */
! DATA(insert (    23    16    2557 e f ));
! DATA(insert (    16    23    2558 e f ));

  /*
   * OID category: allow implicit conversion from any integral type (including
***************
*** 125,288 **** DATA(insert (    16    23    2558 e ));
   * casts from text and varchar to regclass, which exist mainly to support
   * legacy forms of nextval() and related functions.
   */
! 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 ));
! DATA(insert (    26 3734    0 i ));
! DATA(insert ( 3734     26    0 i ));
! DATA(insert (    20 3734 1287 i ));
! DATA(insert (    21 3734  313 i ));
! DATA(insert (    23 3734    0 i ));
! DATA(insert ( 3734     20 1288 a ));
! DATA(insert ( 3734     23    0 a ));
! DATA(insert (    26 3769    0 i ));
! DATA(insert ( 3769     26    0 i ));
! DATA(insert (    20 3769 1287 i ));
! DATA(insert (    21 3769  313 i ));
! DATA(insert (    23 3769    0 i ));
! DATA(insert ( 3769     20 1288 a ));
! DATA(insert ( 3769     23    0 a ));
! DATA(insert (    25 2205 1079 i ));
! DATA(insert ( 1043 2205 1079 i ));

  /*
   * String category
   */
! DATA(insert (    25 1042    0 i ));
! DATA(insert (    25 1043    0 i ));
! DATA(insert ( 1042     25  401 i ));
! DATA(insert ( 1042 1043  401 i ));
! DATA(insert ( 1043     25    0 i ));
! DATA(insert ( 1043 1042    0 i ));
! DATA(insert (    18     25  946 i ));
! DATA(insert (    18 1042  860 a ));
! DATA(insert (    18 1043  946 a ));
! DATA(insert (    19     25  406 i ));
! DATA(insert (    19 1042  408 a ));
! DATA(insert (    19 1043 1401 a ));
! DATA(insert (    25     18  944 a ));
! DATA(insert ( 1042     18  944 a ));
! DATA(insert ( 1043     18  944 a ));
! DATA(insert (    25     19  407 i ));
! DATA(insert ( 1042     19  409 i ));
! DATA(insert ( 1043     19 1400 i ));

  /* Allow explicit coercions between int4 and "char" */
! DATA(insert (    18     23   77 e ));
! DATA(insert (    23     18   78 e ));

  /*
   * 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 1715 a ));

  /*
   * BitString category
   */
! DATA(insert ( 1560 1562    0 i ));
! DATA(insert ( 1562 1560    0 i ));
  /* Cross-category casts between bit and int4, int8 */
! DATA(insert (    20 1560 2075 e ));
! DATA(insert (    23 1560 1683 e ));
! DATA(insert ( 1560     20 2076 e ));
! DATA(insert ( 1560     23 1684 e ));

  /*
   * Cross-category casts to and from TEXT
--- 139,302 ----
   * casts from text and varchar to regclass, which exist mainly to support
   * legacy forms of nextval() and related functions.
   */
! DATA(insert (    20     26 1287 i f ));
! DATA(insert (    21     26  313 i f ));
! DATA(insert (    23     26    0 i b ));
! DATA(insert (    26     20 1288 a f ));
! DATA(insert (    26     23    0 a b ));
! DATA(insert (    26     24    0 i b ));
! DATA(insert (    24     26    0 i b ));
! DATA(insert (    20     24 1287 i f ));
! DATA(insert (    21     24  313 i f ));
! DATA(insert (    23     24    0 i b ));
! DATA(insert (    24     20 1288 a f ));
! DATA(insert (    24     23    0 a b ));
! DATA(insert (    24 2202    0 i b ));
! DATA(insert ( 2202     24    0 i b ));
! DATA(insert (    26 2202    0 i b ));
! DATA(insert ( 2202     26    0 i b ));
! DATA(insert (    20 2202 1287 i f ));
! DATA(insert (    21 2202  313 i f ));
! DATA(insert (    23 2202    0 i b ));
! DATA(insert ( 2202     20 1288 a f ));
! DATA(insert ( 2202     23    0 a b ));
! DATA(insert (    26 2203    0 i b ));
! DATA(insert ( 2203     26    0 i b ));
! DATA(insert (    20 2203 1287 i f ));
! DATA(insert (    21 2203  313 i f ));
! DATA(insert (    23 2203    0 i b ));
! DATA(insert ( 2203     20 1288 a f ));
! DATA(insert ( 2203     23    0 a b ));
! DATA(insert ( 2203 2204    0 i b ));
! DATA(insert ( 2204 2203    0 i b ));
! DATA(insert (    26 2204    0 i b ));
! DATA(insert ( 2204     26    0 i b ));
! DATA(insert (    20 2204 1287 i f ));
! DATA(insert (    21 2204  313 i f ));
! DATA(insert (    23 2204    0 i b ));
! DATA(insert ( 2204     20 1288 a f ));
! DATA(insert ( 2204     23    0 a b ));
! DATA(insert (    26 2205    0 i b ));
! DATA(insert ( 2205     26    0 i b ));
! DATA(insert (    20 2205 1287 i f ));
! DATA(insert (    21 2205  313 i f ));
! DATA(insert (    23 2205    0 i b ));
! DATA(insert ( 2205     20 1288 a f ));
! DATA(insert ( 2205     23    0 a b ));
! DATA(insert (    26 2206    0 i b ));
! DATA(insert ( 2206     26    0 i b ));
! DATA(insert (    20 2206 1287 i f ));
! DATA(insert (    21 2206  313 i f ));
! DATA(insert (    23 2206    0 i b ));
! DATA(insert ( 2206     20 1288 a f ));
! DATA(insert ( 2206     23    0 a b ));
! DATA(insert (    26 3734    0 i b ));
! DATA(insert ( 3734     26    0 i b ));
! DATA(insert (    20 3734 1287 i f ));
! DATA(insert (    21 3734  313 i f ));
! DATA(insert (    23 3734    0 i b ));
! DATA(insert ( 3734     20 1288 a f ));
! DATA(insert ( 3734     23    0 a b ));
! DATA(insert (    26 3769    0 i b ));
! DATA(insert ( 3769     26    0 i b ));
! DATA(insert (    20 3769 1287 i f ));
! DATA(insert (    21 3769  313 i f ));
! DATA(insert (    23 3769    0 i b ));
! DATA(insert ( 3769     20 1288 a f ));
! DATA(insert ( 3769     23    0 a b ));
! DATA(insert (    25 2205 1079 i f ));
! DATA(insert ( 1043 2205 1079 i f ));

  /*
   * String category
   */
! DATA(insert (    25 1042    0 i b ));
! DATA(insert (    25 1043    0 i b ));
! DATA(insert ( 1042     25  401 i f ));
! DATA(insert ( 1042 1043  401 i f ));
! DATA(insert ( 1043     25    0 i b ));
! DATA(insert ( 1043 1042    0 i b ));
! DATA(insert (    18     25  946 i f ));
! DATA(insert (    18 1042  860 a f ));
! DATA(insert (    18 1043  946 a f ));
! DATA(insert (    19     25  406 i f ));
! DATA(insert (    19 1042  408 a f ));
! DATA(insert (    19 1043 1401 a f ));
! DATA(insert (    25     18  944 a f ));
! DATA(insert ( 1042     18  944 a f ));
! DATA(insert ( 1043     18  944 a f ));
! DATA(insert (    25     19  407 i f ));
! DATA(insert ( 1042     19  409 i f ));
! DATA(insert ( 1043     19 1400 i f ));

  /* Allow explicit coercions between int4 and "char" */
! DATA(insert (    18     23   77 e f ));
! DATA(insert (    23     18   78 e f ));

  /*
   * Datetime category
   */
! DATA(insert (  702 1082 1179 a f ));
! DATA(insert (  702 1083 1364 a f ));
! DATA(insert (  702 1114 2023 i f ));
! DATA(insert (  702 1184 1173 i f ));
! DATA(insert (  703 1186 1177 i f ));
! DATA(insert ( 1082 1114 2024 i f ));
! DATA(insert ( 1082 1184 1174 i f ));
! DATA(insert ( 1083 1186 1370 i f ));
! DATA(insert ( 1083 1266 2047 i f ));
! DATA(insert ( 1114    702 2030 a f ));
! DATA(insert ( 1114 1082 2029 a f ));
! DATA(insert ( 1114 1083 1316 a f ));
! DATA(insert ( 1114 1184 2028 i f ));
! DATA(insert ( 1184    702 1180 a f ));
! DATA(insert ( 1184 1082 1178 a f ));
! DATA(insert ( 1184 1083 2019 a f ));
! DATA(insert ( 1184 1114 2027 a f ));
! DATA(insert ( 1184 1266 1388 a f ));
! DATA(insert ( 1186    703 1194 a f ));
! DATA(insert ( 1186 1083 1419 a f ));
! DATA(insert ( 1266 1083 2046 a f ));
  /* Cross-category casts between int4 and abstime, reltime */
! DATA(insert (    23    702    0 e b ));
! DATA(insert (  702     23    0 e b ));
! DATA(insert (    23    703    0 e b ));
! DATA(insert (  703     23    0 e b ));

  /*
   * Geometric category
   */
! DATA(insert (  601    600 1532 e f ));
! DATA(insert (  602    600 1533 e f ));
! DATA(insert (  602    604 1449 a f ));
! DATA(insert (  603    600 1534 e f ));
! DATA(insert (  603    601 1541 e f ));
! DATA(insert (  603    604 1448 a f ));
! DATA(insert (  603    718 1479 e f ));
! DATA(insert (  604    600 1540 e f ));
! DATA(insert (  604    602 1447 a f ));
! DATA(insert (  604    603 1446 e f ));
! DATA(insert (  604    718 1474 e f ));
! DATA(insert (  718    600 1416 e f ));
! DATA(insert (  718    603 1480 e f ));
! DATA(insert (  718    604 1544 e f ));

  /*
   * INET category
   */
! DATA(insert (  650    869    0 i b ));
! DATA(insert (  869    650 1715 a f ));

  /*
   * BitString category
   */
! DATA(insert ( 1560 1562    0 i b ));
! DATA(insert ( 1562 1560    0 i b ));
  /* Cross-category casts between bit and int4, int8 */
! DATA(insert (    20 1560 2075 e f ));
! DATA(insert (    23 1560 1683 e f ));
! DATA(insert ( 1560     20 2076 e f ));
! DATA(insert ( 1560     23 1684 e f ));

  /*
   * Cross-category casts to and from TEXT
***************
*** 296,341 **** DATA(insert ( 1560     23 1684 e ));
   * behavior will ensue when the automatic cast is applied instead of the
   * pg_cast entry!
   */
! DATA(insert (  650     25  730 a ));
! DATA(insert (  869     25  730 a ));
! DATA(insert (    16     25 2971 a ));
! DATA(insert (  142     25    0 a ));
! DATA(insert (    25    142 2896 e ));

  /*
   * Cross-category casts to and from VARCHAR
   *
   * We support all the same casts as for TEXT.
   */
! DATA(insert (  650 1043  730 a ));
! DATA(insert (  869 1043  730 a ));
! DATA(insert (    16 1043 2971 a ));
! DATA(insert (  142 1043    0 a ));
! DATA(insert ( 1043    142 2896 e ));

  /*
   * Cross-category casts to and from BPCHAR
   *
   * We support all the same casts as for TEXT.
   */
! DATA(insert (  650 1042  730 a ));
! DATA(insert (  869 1042  730 a ));
! DATA(insert (    16 1042 2971 a ));
! DATA(insert (  142 1042    0 a ));
! DATA(insert ( 1042    142 2896 e ));

  /*
   * Length-coercion functions
   */
! DATA(insert ( 1042 1042  668 i ));
! DATA(insert ( 1043 1043  669 i ));
! DATA(insert ( 1083 1083 1968 i ));
! DATA(insert ( 1114 1114 1961 i ));
! DATA(insert ( 1184 1184 1967 i ));
! DATA(insert ( 1186 1186 1200 i ));
! DATA(insert ( 1266 1266 1969 i ));
! DATA(insert ( 1560 1560 1685 i ));
! DATA(insert ( 1562 1562 1687 i ));
! DATA(insert ( 1700 1700 1703 i ));

  #endif   /* PG_CAST_H */
--- 310,355 ----
   * behavior will ensue when the automatic cast is applied instead of the
   * pg_cast entry!
   */
! DATA(insert (  650     25  730 a f ));
! DATA(insert (  869     25  730 a f ));
! DATA(insert (    16     25 2971 a f ));
! DATA(insert (  142     25    0 a b ));
! DATA(insert (    25    142 2896 e f ));

  /*
   * Cross-category casts to and from VARCHAR
   *
   * We support all the same casts as for TEXT.
   */
! DATA(insert (  650 1043  730 a f ));
! DATA(insert (  869 1043  730 a f ));
! DATA(insert (    16 1043 2971 a f ));
! DATA(insert (  142 1043    0 a b ));
! DATA(insert ( 1043    142 2896 e f ));

  /*
   * Cross-category casts to and from BPCHAR
   *
   * We support all the same casts as for TEXT.
   */
! DATA(insert (  650 1042  730 a f ));
! DATA(insert (  869 1042  730 a f ));
! DATA(insert (    16 1042 2971 a f ));
! DATA(insert (  142 1042    0 a b ));
! DATA(insert ( 1042    142 2896 e f ));

  /*
   * Length-coercion functions
   */
! DATA(insert ( 1042 1042  668 i f ));
! DATA(insert ( 1043 1043  669 i f ));
! DATA(insert ( 1083 1083 1968 i f ));
! DATA(insert ( 1114 1114 1961 i f ));
! DATA(insert ( 1184 1184 1967 i f ));
! DATA(insert ( 1186 1186 1200 i f ));
! DATA(insert ( 1266 1266 1969 i f ));
! DATA(insert ( 1560 1560 1685 i f ));
! DATA(insert ( 1562 1562 1687 i f ));
! DATA(insert ( 1700 1700 1703 i f ));

  #endif   /* PG_CAST_H */
*** src/include/nodes/parsenodes.h
--- src/include/nodes/parsenodes.h
***************
*** 2062,2067 **** typedef struct CreateCastStmt
--- 2062,2068 ----
      TypeName   *targettype;
      FuncWithArgs *func;
      CoercionContext context;
+     bool        inout;
  } CreateCastStmt;

  /* ----------------------
*** src/test/regress/expected/opr_sanity.out
--- src/test/regress/expected/opr_sanity.out
***************
*** 22,28 **** create function binary_coercible(oid, oid) returns bool as $$
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castfunc = 0 and castcontext = 'i') OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
--- 22,28 ----
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castmethod = 'b' and castcontext = 'i') OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
***************
*** 33,39 **** create function physically_coercible(oid, oid) returns bool as $$
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castfunc = 0) OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
--- 33,39 ----
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castmethod = 'b') OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
***************
*** 262,270 **** WHERE p1.prorettype = 'internal'::regtype AND NOT
  -- oidjoins test).
  SELECT *
  FROM pg_cast c
! WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i');
!  castsource | casttarget | castfunc | castcontext
! ------------+------------+----------+-------------
  (0 rows)

  -- Look for casts to/from the same type that aren't length coercion functions.
--- 262,281 ----
  -- oidjoins test).
  SELECT *
  FROM pg_cast c
! WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i')
!     OR castmethod NOT IN ('f', 'b' ,'i');
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
! (0 rows)
!
! -- Check that castfunc is nonzero only for cast methods that need a function,
! -- and zero otherwise
! SELECT *
! FROM pg_cast c
! WHERE (castmethod = 'f' AND castfunc = 0)
!    OR (castmethod IN ('b', 'i') AND castfunc <> 0);
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
  (0 rows)

  -- Look for casts to/from the same type that aren't length coercion functions.
***************
*** 273,287 **** WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i');
  SELECT *
  FROM pg_cast c
  WHERE castsource = casttarget AND castfunc = 0;
!  castsource | casttarget | castfunc | castcontext
! ------------+------------+----------+-------------
  (0 rows)

  SELECT c.*
  FROM pg_cast c, pg_proc p
  WHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget;
!  castsource | casttarget | castfunc | castcontext
! ------------+------------+----------+-------------
  (0 rows)

  -- Look for cast functions that don't have the right signature.  The
--- 284,298 ----
  SELECT *
  FROM pg_cast c
  WHERE castsource = casttarget AND castfunc = 0;
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
  (0 rows)

  SELECT c.*
  FROM pg_cast c, pg_proc p
  WHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget;
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
  (0 rows)

  -- Look for cast functions that don't have the right signature.  The
***************
*** 299,306 **** WHERE c.castfunc = p.oid AND
               OR (c.castsource = 'character'::regtype AND
                   p.proargtypes[0] = 'text'::regtype))
       OR NOT binary_coercible(p.prorettype, c.casttarget));
!  castsource | casttarget | castfunc | castcontext
! ------------+------------+----------+-------------
  (0 rows)

  SELECT c.*
--- 310,317 ----
               OR (c.castsource = 'character'::regtype AND
                   p.proargtypes[0] = 'text'::regtype))
       OR NOT binary_coercible(p.prorettype, c.casttarget));
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
  (0 rows)

  SELECT c.*
***************
*** 308,315 **** FROM pg_cast c, pg_proc p
  WHERE c.castfunc = p.oid AND
      ((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR
       (p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype));
!  castsource | casttarget | castfunc | castcontext
! ------------+------------+----------+-------------
  (0 rows)

  -- Look for binary compatible casts that do not have the reverse
--- 319,326 ----
  WHERE c.castfunc = p.oid AND
      ((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR
       (p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype));
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
  (0 rows)

  -- Look for binary compatible casts that do not have the reverse
***************
*** 324,342 **** WHERE c.castfunc = p.oid AND
  -- texttoxml(), which does an XML syntax check.
  SELECT *
  FROM pg_cast c
! WHERE c.castfunc = 0 AND
      NOT EXISTS (SELECT 1 FROM pg_cast k
!                 WHERE k.castfunc = 0 AND
                      k.castsource = c.casttarget AND
                      k.casttarget = c.castsource);
!  castsource | casttarget | castfunc | castcontext
! ------------+------------+----------+-------------
!          25 |       1042 |        0 | i
!        1043 |       1042 |        0 | i
!         650 |        869 |        0 | i
!         142 |         25 |        0 | a
!         142 |       1043 |        0 | a
!         142 |       1042 |        0 | a
  (6 rows)

  -- **************** pg_operator ****************
--- 335,353 ----
  -- texttoxml(), which does an XML syntax check.
  SELECT *
  FROM pg_cast c
! WHERE c.castmethod = 'b' AND
      NOT EXISTS (SELECT 1 FROM pg_cast k
!                 WHERE k.castmethod = 'b' AND
                      k.castsource = c.casttarget AND
                      k.casttarget = c.castsource);
!  castsource | casttarget | castfunc | castcontext | castmethod
! ------------+------------+----------+-------------+------------
!          25 |       1042 |        0 | i           | b
!        1043 |       1042 |        0 | i           | b
!         650 |        869 |        0 | i           | b
!         142 |         25 |        0 | a           | b
!         142 |       1043 |        0 | a           | b
!         142 |       1042 |        0 | a           | b
  (6 rows)

  -- **************** pg_operator ****************
*** src/test/regress/sql/opr_sanity.sql
--- src/test/regress/sql/opr_sanity.sql
***************
*** 25,31 **** create function binary_coercible(oid, oid) returns bool as $$
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castfunc = 0 and castcontext = 'i') OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
--- 25,31 ----
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castmethod = 'b' and castcontext = 'i') OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
***************
*** 37,43 **** create function physically_coercible(oid, oid) returns bool as $$
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castfunc = 0) OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
--- 37,43 ----
  SELECT ($1 = $2) OR
   EXISTS(select 1 from pg_catalog.pg_cast where
          castsource = $1 and casttarget = $2 and
!         castmethod = 'b') OR
   ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
    EXISTS(select 1 from pg_catalog.pg_type where
           oid = $1 and typelem != 0 and typlen = -1))
***************
*** 214,220 **** WHERE p1.prorettype = 'internal'::regtype AND NOT

  SELECT *
  FROM pg_cast c
! WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i');

  -- Look for casts to/from the same type that aren't length coercion functions.
  -- (We assume they are length coercions if they take multiple arguments.)
--- 214,229 ----

  SELECT *
  FROM pg_cast c
! WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i')
!     OR castmethod NOT IN ('f', 'b' ,'i');
!
! -- Check that castfunc is nonzero only for cast methods that need a function,
! -- and zero otherwise
!
! SELECT *
! FROM pg_cast c
! WHERE (castmethod = 'f' AND castfunc = 0)
!    OR (castmethod IN ('b', 'i') AND castfunc <> 0);

  -- Look for casts to/from the same type that aren't length coercion functions.
  -- (We assume they are length coercions if they take multiple arguments.)
***************
*** 267,275 **** WHERE c.castfunc = p.oid AND

  SELECT *
  FROM pg_cast c
! WHERE c.castfunc = 0 AND
      NOT EXISTS (SELECT 1 FROM pg_cast k
!                 WHERE k.castfunc = 0 AND
                      k.castsource = c.casttarget AND
                      k.casttarget = c.castsource);

--- 276,284 ----

  SELECT *
  FROM pg_cast c
! WHERE c.castmethod = 'b' AND
      NOT EXISTS (SELECT 1 FROM pg_cast k
!                 WHERE k.castmethod = 'b' AND
                      k.castsource = c.casttarget AND
                      k.casttarget = c.castsource);


В списке pgsql-hackers по дате отправления:

Предыдущее
От: Gregory Stark
Дата:
Сообщение: Updated posix fadvise patch v19
Следующее
От: Gregory Stark
Дата:
Сообщение: Re: PG_PAGE_LAYOUT_VERSION 5 - time for change