]> granicus.if.org Git - postgresql/commitdiff
Allow I/O conversion casts to be applied to or from any type that is a member
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 30 Jul 2008 21:23:17 +0000 (21:23 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 30 Jul 2008 21:23:17 +0000 (21:23 +0000)
of the STRING type category, thereby opening up the mechanism for user-defined
types.  This is mainly for the benefit of citext, though; there aren't likely
to be a lot of types that are all general-purpose character strings.
Per discussion with David Wheeler.

contrib/citext/expected/citext.out
contrib/citext/sql/citext.sql
doc/src/sgml/ref/create_cast.sgml
src/backend/parser/parse_coerce.c

index 7c207f4e9cf8b9fe535da562fde097aff15375e5..9a60b93490c7db109453eed61931766e0f616b5a 100644 (file)
@@ -1141,13 +1141,16 @@ SELECT like_escape( name::text, ''::citext ) =like_escape( name::text, '' ) AS t
  t
 (5 rows)
 
---- TODO: Get citext working with magic cast functions?
-SELECT cidr( '192.168.1.2'::citext ) = cidr( '192.168.1.2'::text ) AS "t TODO";
-ERROR:  function cidr(citext) does not exist
-LINE 1: SELECT cidr( '192.168.1.2'::citext ) = cidr( '192.168.1.2'::...
-               ^
-HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
-SELECT '192.168.1.2'::cidr::citext = '192.168.1.2'::cidr::text AS "t TODO";
-ERROR:  cannot cast type cidr to citext
-LINE 1: SELECT '192.168.1.2'::cidr::citext = '192.168.1.2'::cidr::te...
-                                    ^
+--- citext should work as source or destination of I/O conversion casts
+SELECT cidr( '192.168.1.2'::citext ) = cidr( '192.168.1.2'::text ) AS "t";
+ t 
+---
+ t
+(1 row)
+
+SELECT '192.168.1.2'::cidr::citext = '192.168.1.2'::cidr::text AS "t";
+ t 
+---
+ t
+(1 row)
+
index 04a297da026f249aedb4090e5b5bfa4155e277f2..8df3e93219cc56567226bb290a7e0fed05039b3f 100644 (file)
@@ -323,6 +323,6 @@ SELECT COUNT(*) = 19::bigint AS t FROM try;
 SELECT like_escape( name, '' ) = like_escape( name::text, '' ) AS t FROM srt;
 SELECT like_escape( name::text, ''::citext ) =like_escape( name::text, '' ) AS t FROM srt;
 
---- TODO: Get citext working with magic cast functions?
-SELECT cidr( '192.168.1.2'::citext ) = cidr( '192.168.1.2'::text ) AS "t TODO";
-SELECT '192.168.1.2'::cidr::citext = '192.168.1.2'::cidr::text AS "t TODO";
+--- citext should work as source or destination of I/O conversion casts
+SELECT cidr( '192.168.1.2'::citext ) = cidr( '192.168.1.2'::text ) AS "t";
+SELECT '192.168.1.2'::cidr::citext = '192.168.1.2'::cidr::text AS "t";
index ea56f66857b35186cc8f10a054fb74eee082d42f..080f31832d2e92d9d1cfbd731565dae95f7146b4 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.28 2008/07/12 16:20:06 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.29 2008/07/30 21:23:17 tgl Exp $ -->
 
 <refentry id="SQL-CREATECAST">
  <refmeta>
@@ -26,7 +26,7 @@ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r
     [ AS ASSIGNMENT | AS IMPLICIT ]
 </synopsis>
  </refsynopsisdiv>
-  
+
  <refsect1 id="sql-createcast-description">
   <title>Description</title>
 
@@ -131,6 +131,18 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
    to <type>int4</>, are best made explicit-only.
   </para>
 
+  <note>
+   <para>
+    Sometimes it is necessary for usability or standards-compliance reasons
+    to provide multiple implicit casts among a set of types, resulting in
+    ambiguity that cannot be avoided as above.  The parser has a fallback
+    heuristic based on <firstterm>type categories</> and <firstterm>preferred
+    types</> that can help to provide desired behavior in such cases.  See
+    <xref linkend="sql-createtype" endterm="sql-createtype-title"> for
+    more information.
+   </para>
+  </note>
+
   <para>
    To be able to create a cast, you must own the source or the target
    data type.  To create a binary-coercible cast, you must be superuser.
@@ -181,8 +193,8 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
 
      <listitem>
       <para>
-       Indicates that the source type and the target type are binary
-       coercible, so no function is required to perform the cast.
+       Indicates that the source type is binary-coercible to the target type,
+       so no function is required to perform the cast.
       </para>
      </listitem>
     </varlistentry>
@@ -218,7 +230,7 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
    if there is none.  The third argument,
    if present, must be type <type>boolean</>; it receives <literal>true</>
    if the cast is an explicit cast, <literal>false</> otherwise.
-   (Bizarrely, the SQL spec demands different behaviors for explicit and
+   (Bizarrely, the SQL standard demands different behaviors for explicit and
    implicit casts in some cases.  This argument is supplied for functions
    that must implement such casts.  It is not recommended that you design
    your own data types so that this matters.)
@@ -271,7 +283,8 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <para>
    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>).  <productname>PostgreSQL</> will
+   <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
@@ -340,16 +353,15 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
   <title>Examples</title>
 
   <para>
-   To create a cast from type <type>bigint</type> to type
+   To create an assignment cast from type <type>bigint</type> to type
    <type>int4</type> using the function <literal>int4(bigint)</literal>:
 <programlisting>
-CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint);
+CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
 </programlisting>
    (This cast is already predefined in the system.)
   </para>
  </refsect1>
 
  <refsect1 id="sql-createcast-compat">
   <title>Compatibility</title>
 
@@ -358,7 +370,7 @@ CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint);
    <acronym>SQL</acronym> standard,
    except that SQL does not make provisions for binary-coercible
    types or extra arguments to implementation functions.
-   <literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname> 
+   <literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname>
    extension, too.
   </para>
  </refsect1>
index df5ad09bae18fdcc2c1a947f8a50536e0068692b..df1fb8526de55b46e33507b9d66b9e58fb96ffeb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.162 2008/07/30 17:05:04 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.163 2008/07/30 21:23:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1796,8 +1796,8 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
 
                /*
                 * If we still haven't found a possibility, consider automatic casting
-                * using I/O functions.  We allow assignment casts to textual types
-                * and explicit casts from textual types to be handled this way. (The
+                * using I/O functions.  We allow assignment casts to string types
+                * and explicit casts from string types to be handled this way. (The
                 * CoerceViaIO mechanism is a lot more general than that, but this is
                 * all we want to allow in the absence of a pg_cast entry.) It would
                 * probably be better to insist on explicit casts in both directions,
@@ -1807,14 +1807,10 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
                if (result == COERCION_PATH_NONE)
                {
                        if (ccontext >= COERCION_ASSIGNMENT &&
-                               (targetTypeId == TEXTOID ||
-                                targetTypeId == VARCHAROID ||
-                                targetTypeId == BPCHAROID))
+                               TypeCategory(targetTypeId) == TYPCATEGORY_STRING)
                                result = COERCION_PATH_COERCEVIAIO;
                        else if (ccontext >= COERCION_EXPLICIT &&
-                                        (sourceTypeId == TEXTOID ||
-                                         sourceTypeId == VARCHAROID ||
-                                         sourceTypeId == BPCHAROID))
+                                        TypeCategory(sourceTypeId) == TYPCATEGORY_STRING)
                                result = COERCION_PATH_COERCEVIAIO;
                }
        }