pg_cast table, and standards-compliant CREATE/DROP CAST commands, plus
authorPeter Eisentraut
Thu, 18 Jul 2002 23:11:32 +0000 (23:11 +0000)
committerPeter Eisentraut
Thu, 18 Jul 2002 23:11:32 +0000 (23:11 +0000)
extension to create binary compatible casts.  Includes dependency tracking
as well.

pg_proc.proimplicit is now defunct, but will be removed in a separate
commit.

pg_dump provides a migration path from the previous scheme to declare
casts.  Dumping binary compatible casts is currently impossible, though.

36 files changed:
doc/src/sgml/ref/allfiles.sgml
doc/src/sgml/ref/create_cast.sgml [new file with mode: 0644]
doc/src/sgml/ref/create_function.sgml
doc/src/sgml/ref/drop_cast.sgml [new file with mode: 0644]
doc/src/sgml/reference.sgml
doc/src/sgml/release.sgml
src/backend/catalog/Makefile
src/backend/catalog/dependency.c
src/backend/catalog/indexing.c
src/backend/catalog/pg_aggregate.c
src/backend/catalog/pg_proc.c
src/backend/commands/functioncmds.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_coerce.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/sets.c
src/backend/utils/cache/syscache.c
src/bin/initdb/initdb.sh
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/include/catalog/catname.h
src/include/catalog/catversion.h
src/include/catalog/indexing.h
src/include/catalog/pg_cast.h [new file with mode: 0644]
src/include/catalog/pg_proc.h
src/include/commands/defrem.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/utils/syscache.h
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/sanity_check.out
src/test/regress/sql/opr_sanity.sql

index c9ece5af561b559127569f474f1db22de4416842..55b4fc5c9f096c2703c7b941a33f3007a13ee775 100644 (file)
@@ -1,5 +1,5 @@
 
@@ -51,6 +51,7 @@ Complete list of usable sgml source files in this directory.
 
 
 
+
 
 
 
@@ -71,6 +72,7 @@ Complete list of usable sgml source files in this directory.
 
 
 
+
 
 
 
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml
new file mode 100644 (file)
index 0000000..8125994
--- /dev/null
@@ -0,0 +1,232 @@
+
+
+
+  CREATE CAST
+  SQL - Language Statements
+
+  CREATE CAST
+  define a user-defined cast
+
+
+CREATE CAST (sourcetype AS targettype)
+    WITH FUNCTION funcname (argtype)
+    [AS ASSIGNMENT]
+
+CREATE CAST (sourcetype AS targettype)
+    WITHOUT FUNCTION
+    [AS ASSIGNMENT]
+
+  
+  Description
+
+  
+   CREATE CAST defines a new cast.  A cast
+   specifies which function can be invoked when a conversion between
+   two data types is requested.  For example,
+
+SELECT CAST(42 AS text);
+
+   converts the integer constant 42 to type text by
+   invoking a previously specified function, in this case
+   text(int4). (If no suitable cast has been defined, the
+   conversion fails.)
+  
+
+  
+   Two types may be binary compatible, which
+   means that they can be converted into one another for
+   free without invoking any function.  This requires that
+   corresponding values use the same internal representation.  For
+   instance, the types text and varchar are
+   binary compatible.
+  
+
+  
+   A cast can marked 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 CAST,
+   x::typename, or
+   typename(x) constructs.  For
+   example, supposing that foo.f1 is a column of
+   type text, then
+
+INSERT INTO foo(f1) VALUES(42);
+
+   will be allowed if the cast from type integer to type
+   text is marked AS ASSIGNMENT, otherwise
+   not. (We generally use the term implicit
+   cast to describe this kind of cast.)
+  
+
+  
+   It is wise to be conservative about marking casts as implicit.  An
+   overabundance of implicit casting paths can cause
+   PostgreSQL to choose surprising
+   interpretations of commands, or to be unable to resolve commands at
+   all because there are multiple possible interpretations.  A good
+   rule of thumb is to make cast implicitly invokable only for
+   information-preserving transformations between types in the same
+   general type category.  For example, int2 to
+   int4 casts can reasonably be implicit, but be wary of
+   marking int4 to text or
+   float8 to int4 as implicit casts.
+  
+
+  
+   To be able to create a cast, you must own the underlying function.
+   To be able to create a binary compatible cast, you must own both
+   the source and the target data type.
+  
+
+   
+    Parameters
+
+    
+     sourcetype
+
+     
+      
+       The name of the source data type of the cast.
+      
+     
+    
+
+    
+     targettype
+
+     
+      
+       The name of the target data type of the cast.
+      
+     
+    
+
+    
+     funcname(argtype)
+
+     
+      
+       The function used to perform the cast.  The function name may
+       be schema-qualified.  If it is not, the function will be looked
+       up in the path.  The argument type must be identical to the
+       source type, the result data type must match the target type of
+       the cast.  Cast functions must be marked immutable.
+      
+     
+    
+
+    
+     WITHOUT FUNCTION
+
+     
+      
+       Indicates that the source type and the target type are binary
+       compatible, so no function is required to perform the cast.
+      
+     
+    
+
+    
+     AS ASSIGNMENT
+
+     
+      
+       Indicates that the cast may be invoked implicitly.
+      
+     
+    
+   
+
+
+  Notes
+
+  
+   Use DROP CAST to remove user-defined casts.
+  
+
+  
+   The privileges required to create a cast may be changed in a future
+   release.
+  
+
+  
+   Remember that if you want to be able to convert types both ways you
+   need to declare casts both ways explicitly.
+  
+
+  
+   Prior to PostgreSQL 7.3, every function that had the same name as a
+   data type, returned that data type, and took one argument of a
+   different type was automatically a cast function.  This system has
+   been abandoned in face of the introduction of schemas and to be
+   able to store binary compatible casts.  The built-in cast functions
+   still follow this naming scheme, but they have to be declared as
+   casts explicitly now.
+  
+
+
+  Examples
+
+  
+   To create a cast from type text to type
+   int using the function int4(text):
+
+CREATE CAST (text AS int4) WITH FUNCTION int4(text);
+
+   (This cast is already predefined in the system.)
+  
+
+  Compatibility
+
+  
+   The CREATE CAST command conforms to SQL99,
+   except that SQL99 does not make provisions for binary compatible
+   types.
+  
+
+
+  See Also
+
+  
+   ,
+   ,
+   ,
+   PostgreSQL Programmer's Guide
+  
+
+
+
+
index b2d2314a7332383232be2854f116507664c666a9..e2170dcc45d252a5a55dd9fc36cbc1b8d1bc417d 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -20,7 +20,6 @@ CREATE [ OR REPLACE ] FUNCTION name
   { LANGUAGE langname
     | IMMUTABLE | STABLE | VOLATILE
     | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
-    | IMPLICIT CAST
     | [EXTERNAL] SECURITY INVOKER | [EXTERNAL] SECURITY DEFINER
     | AS 'definition'
     | AS 'obj_file', 'link_symbol'
@@ -188,18 +187,6 @@ CREATE [ OR REPLACE ] FUNCTION name
      
     
 
-    
-     IMPLICIT CAST
-
-     
-      
-       Indicates that the function may be used for implicit type
-       conversions.  See 
-       endterm="sql-createfunction-cast-functions-title"> for more detail.
-      
-     
-    
-
    
     EXTERNAL SECURITY INVOKER
     EXTERNAL SECURITY DEFINER
@@ -285,14 +272,6 @@ CREATE [ OR REPLACE ] FUNCTION name
         
        
 
-       
-        implicitCoercion
-        
-         
-          Same as IMPLICIT CAST
-         
-        
-       
       
 
       Attribute names are not case-sensitive.
@@ -394,55 +373,6 @@ CREATE [ OR REPLACE ] FUNCTION name
   
  
 
-  
-   Type Cast Functions
-  
-  
-   A function that has one argument and is named the same as its return
-   data type (including the schema name) is considered to be a type
-   casting function: it can be invoked to convert a value of its input
-   data type into a value 
-   of its output datatype.  For example,
-
-SELECT CAST(42 AS text);
-
-   converts the integer constant 42 to text by invoking a function
-   text(int4), if such a function exists and returns type
-   text.  (If no suitable conversion function can be found, the cast fails.)
-  
-
-  
-   If a potential cast function is marked IMPLICIT CAST,
-   then 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 CAST,
-   x::typename, or
-   typename(x) constructs.  For
-   example, supposing that foo.f1 is a column of
-   type text, then
-
-INSERT INTO foo(f1) VALUES(42);
-
-   will be allowed if text(int4) is marked
-   IMPLICIT CAST, otherwise not.
-  
-
-  
-   It is wise to be conservative about marking cast functions as
-   implicit casts.  An overabundance of implicit casting paths can
-   cause PostgreSQL to choose surprising
-   interpretations of commands, or to be unable to resolve commands at
-   all because there are multiple possible interpretations.  A good
-   rule of thumb is to make cast implicitly invokable only for
-   information-preserving transformations between types in the same
-   general type category.  For example, int2 to
-   int4 casts can reasonably be implicit, but be wary of
-   marking int4 to text or
-   float8 to int4 as implicit casts.
-  
-  
  
   Examples
 
diff --git a/doc/src/sgml/ref/drop_cast.sgml b/doc/src/sgml/ref/drop_cast.sgml
new file mode 100644 (file)
index 0000000..3715211
--- /dev/null
@@ -0,0 +1,133 @@
+
+
+
+  DROP CAST
+  SQL - Language Statements
+
+  DROP CAST
+  remove a user-defined cast
+
+
+DROP CAST (sourcetype AS targettype)
+    [ CASCADE | RESTRICT ]
+
+  
+  Description
+
+  
+   DROP CAST removes a previously defined cast.
+  
+
+  
+   To be able to drop a cast, you must own the underlying function.
+   To be able to drop a binary compatible cast, you must own both the
+   source and the target data type.  These are the same privileges
+   that are required to create a cast.
+  
+
+   
+    Parameters
+
+    
+     sourcetype
+
+     
+      
+       The name of the source data type of the cast.
+      
+     
+    
+
+    
+     targettype
+
+     
+      
+       The name of the target data type of the cast.
+      
+     
+    
+
+    
+     CASCADE
+     RESTRICT
+
+     
+      
+       These key words do not have any effect, since there are no
+       dependencies on casts.
+      
+     
+    
+   
+
+
+  Notes
+
+  
+   Use CREATE CAST to create user-defined casts.
+  
+
+  
+   The privileges required to drop a cast may be changed in a future
+   release.
+  
+
+
+  Examples
+
+  
+   To drop the cast from type text to type int:
+
+DROP CAST (text AS int4);
+
+  
+
+  Compatibility
+
+  
+   The DROP CAST command conforms to SQL99.
+  
+
+
+  See Also
+
+  
+   
+  
+
+
+
+
index 8249039826ced554fb9356f5812e61a6bdb700a4..39fec262dd06223f2c047f960af3921fcad287ca 100644 (file)
@@ -1,5 +1,5 @@
 
@@ -60,6 +60,7 @@ PostgreSQL Reference Manual
    &commit;
    ©Table;
    &createAggregate;
+   &createCast;
    &createConstraint;
    &createDatabase;
    &createDomain;
@@ -80,6 +81,7 @@ PostgreSQL Reference Manual
    &declare;
    &delete;
    &dropAggregate;
+   &dropCast;
    &dropDatabase;
    &dropDomain;
    &dropFunction;
index f215c84b93e0c0c73808f36020b071b6302ba95f..4f7911ff4e1dc543487b836663d10ae9556d9f9e 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 
+CREATE CAST/DROP CAST
 Sequences created by SERIAL column definitions now auto-drop with the column
 Most forms of DROP now support RESTRICT and CASCADE options
 Recursive SQL functions can be defined
index 22e033524eeffe232e104533bac37837056026c1..37681565ecff6e93ccf315d71937b3c0bf51354d 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.41 2002/07/12 18:43:13 tgl Exp $
+# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.42 2002/07/18 23:11:27 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -30,7 +30,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
    pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
    pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
    pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
-   pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h \
+   pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
    pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
    pg_depend.h indexing.h \
     )
index d2dc8b3795ade3c2f83f5db66e8a19a7982a248c..638843c3e0795f8c94d7861131bf6f64a7c9eff1 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.4 2002/07/18 16:47:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.5 2002/07/18 23:11:27 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,7 @@
 /* This enum covers all system catalogs whose OIDs can appear in classid. */
 typedef enum ObjectClasses
 {
+   OCLASS_CAST,                /* pg_cast */
    OCLASS_CLASS,               /* pg_class */
    OCLASS_PROC,                /* pg_proc */
    OCLASS_TYPE,                /* pg_type */
@@ -604,6 +605,10 @@ doDeletion(const ObjectAddress *object)
            RemoveSchemaById(object->objectId);
            break;
 
+       case OCLASS_CAST:
+           DropCastById(object->objectId);
+           break;
+
        default:
            elog(ERROR, "doDeletion: Unsupported object class %u",
                 object->classId);
@@ -979,6 +984,7 @@ term_object_addresses(ObjectAddresses *addrs)
 static void
 init_object_classes(void)
 {
+   object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
    object_classes[OCLASS_CLASS] = RelOid_pg_class;
    object_classes[OCLASS_PROC] = RelOid_pg_proc;
    object_classes[OCLASS_TYPE] = RelOid_pg_type;
@@ -1023,6 +1029,11 @@ getObjectClass(const ObjectAddress *object)
    if (!object_classes_initialized)
        init_object_classes();
 
+   if (object->classId == object_classes[OCLASS_CAST])
+   {
+       Assert(object->objectSubId == 0);
+       return OCLASS_CAST;
+   }
    if (object->classId == object_classes[OCLASS_CONSTRAINT])
    {
        Assert(object->objectSubId == 0);
@@ -1078,6 +1089,10 @@ getObjectDescription(const ObjectAddress *object)
 
    switch (getObjectClass(object))
    {
+       case OCLASS_CAST:
+           appendStringInfo(&buffer, "cast");
+           break;
+
        case OCLASS_CLASS:
            getRelationDescription(&buffer, object->objectId);
            if (object->objectSubId != 0)
index 9f16b4d4cc18ea3cd89a2ddb94509c6a0776436d..80e3a15cf57a75295f2ffabe4d41f232b98cd8d2 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.97 2002/07/15 16:33:31 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.98 2002/07/18 23:11:27 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,6 +43,8 @@ char     *Name_pg_attr_indices[Num_pg_attr_indices] =
 {AttributeRelidNameIndex, AttributeRelidNumIndex};
 char      *Name_pg_attrdef_indices[Num_pg_attrdef_indices] =
 {AttrDefaultIndex, AttrDefaultOidIndex};
+char      *Name_pg_cast_indices[Num_pg_cast_indices] =
+{CastSourceTargetIndex};
 char      *Name_pg_class_indices[Num_pg_class_indices] =
 {ClassNameNspIndex, ClassOidIndex};
 char      *Name_pg_constraint_indices[Num_pg_constraint_indices] =
index 28d7e83f575e8026e191ec2304fd3ebf678ffb5c..189db5d77da89204653d6fa3a9ec9759e5034e74 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.50 2002/07/16 22:12:18 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.51 2002/07/18 23:11:27 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -144,7 +144,6 @@ AggregateCreate(const char *aggName,
                              "-",          /* probin */
                              true,         /* isAgg */
                              false,        /* security invoker (currently not definable for agg) */
-                             false,        /* isImplicit */
                              false,        /* isStrict (not needed for agg) */
                              PROVOLATILE_IMMUTABLE,    /* volatility (not needed for agg) */
                              BYTE_PCT,     /* default cost values */
index f8693fa7fece1ca54a79e970f70b1e6b61ea2b21..29cfbb9b46e4312148314b4b4fcfea2e69848ce0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.78 2002/07/18 16:47:23 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.79 2002/07/18 23:11:27 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,7 +55,6 @@ ProcedureCreate(const char *procedureName,
                const char *probin,
                bool isAgg,
                bool security_definer,
-               bool isImplicit,
                bool isStrict,
                char volatility,
                int32 byte_pct,
@@ -163,7 +162,7 @@ ProcedureCreate(const char *procedureName,
    values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */
    values[i++] = BoolGetDatum(isAgg);          /* proisagg */
    values[i++] = BoolGetDatum(security_definer); /* prosecdef */
-   values[i++] = BoolGetDatum(isImplicit);     /* proimplicit */
+   values[i++] = BoolGetDatum(false);          /* proimplicit */
    values[i++] = BoolGetDatum(isStrict);       /* proisstrict */
    values[i++] = BoolGetDatum(returnsSet);     /* proretset */
    values[i++] = CharGetDatum(volatility);     /* provolatile */
index 9a33810b07351dac3d2c2281b3d41efb78bf2955..2ed9581b665d7c0c2fbf22f6ffe84b986e40d7bb 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.8 2002/07/12 18:43:16 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.9 2002/07/18 23:11:27 petere Exp $
  *
  * DESCRIPTION
  *   These routines take the parse tree and pick out the
@@ -34,7 +34,9 @@
 #include "access/heapam.h"
 #include "catalog/catname.h"
 #include "catalog/dependency.h"
+#include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_cast.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
@@ -44,6 +46,7 @@
 #include "parser/parse_func.h"
 #include "parser/parse_type.h"
 #include "utils/acl.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
@@ -171,8 +174,7 @@ compute_attributes_sql_style(const List *options,
                             char **language,
                             char *volatility_p,
                             bool *strict_p,
-                            bool *security_definer,
-                            bool *implicit_cast)
+                            bool *security_definer)
 {
    const List *option;
    DefElem *as_item = NULL;
@@ -180,7 +182,6 @@ compute_attributes_sql_style(const List *options,
    DefElem *volatility_item = NULL;
    DefElem *strict_item = NULL;
    DefElem *security_item = NULL;
-   DefElem *implicit_item = NULL;
 
    foreach(option, options)
    {
@@ -216,12 +217,6 @@ compute_attributes_sql_style(const List *options,
                elog(ERROR, "conflicting or redundant options");
            security_item = defel;
        }
-       else if (strcmp(defel->defname, "implicit")==0)
-       {
-           if (implicit_item)
-               elog(ERROR, "conflicting or redundant options");
-           implicit_item = defel;
-       }
        else
            elog(ERROR, "invalid CREATE FUNCTION option");
    }
@@ -252,8 +247,6 @@ compute_attributes_sql_style(const List *options,
        *strict_p = intVal(strict_item->arg);
    if (security_item)
        *security_definer = intVal(security_item->arg);
-   if (implicit_item)
-       *implicit_cast = intVal(implicit_item->arg);
 }
 
 
@@ -264,10 +257,7 @@ compute_attributes_sql_style(const List *options,
  * These parameters supply optional information about a function.
  * All have defaults if not specified.
  *
- * Note: currently, only three of these parameters actually do anything:
- *
- *  * isImplicit means the function may be used as an implicit type
- *    coercion.
+ * Note: currently, only two of these parameters actually do anything:
  *
  *  * isStrict means the function should not be called when any NULL
  *    inputs are present; instead a NULL result value should be assumed.
@@ -284,7 +274,7 @@ static void
 compute_attributes_with_style(List *parameters,
                              int32 *byte_pct_p, int32 *perbyte_cpu_p,
                              int32 *percall_cpu_p, int32 *outin_ratio_p,
-                             bool *isImplicit_p, bool *isStrict_p,
+                             bool *isStrict_p,
                              char *volatility_p)
 {
    List       *pl;
@@ -293,9 +283,7 @@ compute_attributes_with_style(List *parameters,
    {
        DefElem    *param = (DefElem *) lfirst(pl);
 
-       if (strcasecmp(param->defname, "implicitcoercion") == 0)
-           *isImplicit_p = true;
-       else if (strcasecmp(param->defname, "isstrict") == 0)
+       if (strcasecmp(param->defname, "isstrict") == 0)
            *isStrict_p = true;
        else if (strcasecmp(param->defname, "isimmutable") == 0)
            *volatility_p = PROVOLATILE_IMMUTABLE;
@@ -398,8 +386,7 @@ CreateFunction(CreateFunctionStmt *stmt)
                perbyte_cpu,
                percall_cpu,
                outin_ratio;
-   bool        isImplicit,
-               isStrict,
+   bool        isStrict,
                security;
    char        volatility;
    HeapTuple   languageTuple;
@@ -420,14 +407,13 @@ CreateFunction(CreateFunctionStmt *stmt)
    perbyte_cpu = PERBYTE_CPU;
    percall_cpu = PERCALL_CPU;
    outin_ratio = OUTIN_RATIO;
-   isImplicit = false;
    isStrict = false;
    security = false;
    volatility = PROVOLATILE_VOLATILE;
 
    /* override attributes from explicit list */
    compute_attributes_sql_style(stmt->options,
-                                &as_clause, &language, &volatility, &isStrict, &security, &isImplicit);
+                                &as_clause, &language, &volatility, &isStrict, &security);
 
    /* Convert language name to canonical case */
    case_translate_language_name(language, languageName);
@@ -474,8 +460,7 @@ CreateFunction(CreateFunctionStmt *stmt)
 
    compute_attributes_with_style(stmt->withClause,
                                  &byte_pct, &perbyte_cpu, &percall_cpu,
-                                 &outin_ratio, &isImplicit, &isStrict,
-                                 &volatility);
+                                 &outin_ratio, &isStrict, &volatility);
 
    interpret_AS_clause(languageOid, languageName, as_clause,
                        &prosrc_str, &probin_str);
@@ -517,7 +502,6 @@ CreateFunction(CreateFunctionStmt *stmt)
                    probin_str, /* converted to text later */
                    false,      /* not an aggregate */
                    security,
-                   isImplicit,
                    isStrict,
                    volatility,
                    byte_pct,
@@ -639,3 +623,217 @@ RemoveFunctionById(Oid funcOid)
        heap_close(relation, RowExclusiveLock);
    }
 }
+
+
+
+/*
+ * CREATE CAST
+ */
+void
+CreateCast(CreateCastStmt *stmt)
+{
+   Oid         sourcetypeid;
+   Oid         targettypeid;
+   Oid         funcid;
+   HeapTuple   tuple;
+   Relation    relation;
+   Form_pg_proc procstruct;
+
+   Datum       values[Natts_pg_proc];
+   char        nulls[Natts_pg_proc];
+   int         i;
+
+   ObjectAddress myself,
+       referenced;
+
+   sourcetypeid = LookupTypeName(stmt->sourcetype);
+   if (!OidIsValid(sourcetypeid))
+       elog(ERROR, "source data type %s does not exist",
+            TypeNameToString(stmt->sourcetype));
+
+   targettypeid = LookupTypeName(stmt->targettype);
+   if (!OidIsValid(targettypeid))
+       elog(ERROR, "target data type %s does not exist",
+            TypeNameToString(stmt->targettype));
+
+   if (sourcetypeid == targettypeid)
+       elog(ERROR, "source data type and target data type are the same");
+
+   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)
+   {
+       funcid = LookupFuncNameTypeNames(stmt->func->funcname, stmt->func->funcargs, false, "CreateCast");
+
+       if(!pg_proc_ownercheck(funcid, GetUserId()))
+           elog(ERROR, "permission denied");
+
+       tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+           elog(ERROR, "cache lookup of function %u failed", funcid);
+
+       procstruct = (Form_pg_proc) GETSTRUCT(tuple);
+       if (procstruct->pronargs != 1)
+           elog(ERROR, "cast function must take 1 argument");
+       if (procstruct->proargtypes[0] != sourcetypeid)
+           elog(ERROR, "argument of cast function must match source data type");
+       if (procstruct->prorettype != targettypeid)
+           elog(ERROR, "return data type of cast function must match target data type");
+       if (procstruct->provolatile != PROVOLATILE_IMMUTABLE)
+           elog(ERROR, "cast function must be immutable");
+       if (procstruct->proisagg)
+           elog(ERROR, "cast function must not be an aggregate function");
+       if (procstruct->proretset)
+           elog(ERROR, "cast function must be not return a set");
+
+       ReleaseSysCache(tuple);
+   }
+   else
+   {
+       /* indicates binary compatibility */
+       if (!pg_type_ownercheck(sourcetypeid, GetUserId())
+           || !pg_type_ownercheck(targettypeid, GetUserId()))
+           elog(ERROR, "permission denied");
+       funcid = 0;
+   }
+
+   /* 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);
+
+   for (i = 0; i < Natts_pg_cast; ++i)
+       nulls[i] = ' ';
+
+   tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
+   simple_heap_insert(relation, tuple);
+
+   if (RelationGetForm(relation)->relhasindex)
+   {
+       Relation    idescs[Num_pg_cast_indices];
+
+       CatalogOpenIndices(Num_pg_cast_indices, Name_pg_cast_indices, idescs);
+       CatalogIndexInsert(idescs, Num_pg_cast_indices, relation, tuple);
+       CatalogCloseIndices(Num_pg_cast_indices, idescs);
+   }
+
+   myself.classId = get_system_catalog_relid(CastRelationName);
+   myself.objectId = tuple->t_data->t_oid;
+   myself.objectSubId = 0;
+
+   /* dependency on source type */
+   referenced.classId = RelOid_pg_type;
+   referenced.objectId = sourcetypeid;
+   referenced.objectSubId = 0;
+   recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+   /* dependency on target type */
+   referenced.classId = RelOid_pg_type;
+   referenced.objectId = targettypeid;
+   referenced.objectSubId = 0;
+   recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+   /* dependency on function */
+   if (OidIsValid(funcid))
+   {
+       referenced.classId = RelOid_pg_proc;
+       referenced.objectId = funcid;
+       referenced.objectSubId = 0;
+       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+   }
+
+   heap_freetuple(tuple);
+   heap_close(relation, RowExclusiveLock);
+}
+
+
+
+/*
+ * DROP CAST
+ */
+void
+DropCast(DropCastStmt *stmt)
+{
+   Oid         sourcetypeid;
+   Oid         targettypeid;
+   HeapTuple   tuple;
+   Form_pg_cast caststruct;
+   ObjectAddress object;
+
+   sourcetypeid = LookupTypeName(stmt->sourcetype);
+   if (!OidIsValid(sourcetypeid))
+       elog(ERROR, "source data type %s does not exist",
+            TypeNameToString(stmt->sourcetype));
+
+   targettypeid = LookupTypeName(stmt->targettype);
+   if (!OidIsValid(targettypeid))
+       elog(ERROR, "target data type %s does not exist",
+            TypeNameToString(stmt->targettype));
+
+   tuple = SearchSysCache(CASTSOURCETARGET,
+                        ObjectIdGetDatum(sourcetypeid),
+                        ObjectIdGetDatum(targettypeid),
+                        0, 0);
+   if (!HeapTupleIsValid(tuple))
+       elog(ERROR, "cast from type %s to type %s does not exist",
+            TypeNameToString(stmt->sourcetype),
+            TypeNameToString(stmt->targettype));
+
+   /* Permission check */
+   caststruct = (Form_pg_cast) GETSTRUCT(tuple);
+   if (caststruct->castfunc != InvalidOid)
+   {
+       if(!pg_proc_ownercheck(caststruct->castfunc, GetUserId()))
+           elog(ERROR, "permission denied");
+   }
+   else
+   {
+       if (!pg_type_ownercheck(sourcetypeid, GetUserId())
+           || !pg_type_ownercheck(targettypeid, GetUserId()))
+           elog(ERROR, "permission denied");
+   }
+
+   ReleaseSysCache(tuple);
+
+   /*
+    * Do the deletion
+    */
+   object.classId = get_system_catalog_relid(CastRelationName);
+   object.objectId = tuple->t_data->t_oid;
+   object.objectSubId = 0;
+
+   performDeletion(&object, stmt->behavior);
+}
+
+
+void
+DropCastById(Oid castOid)
+{
+   Relation    relation;
+   ScanKeyData scankey;
+   HeapScanDesc scan;
+   HeapTuple   tuple;
+
+   relation = heap_openr(CastRelationName, RowExclusiveLock);
+   ScanKeyEntryInitialize(&scankey, 0x0,
+                          ObjectIdAttributeNumber, F_OIDEQ,
+                          ObjectIdGetDatum(castOid));
+   scan = heap_beginscan(relation, SnapshotNow, 1, &scankey);
+   tuple = heap_getnext(scan, ForwardScanDirection);
+   if (HeapTupleIsValid(tuple))
+       simple_heap_delete(relation, &tuple->t_self);
+   else
+       elog(ERROR, "could not find tuple for cast %u", castOid);
+   heap_endscan(scan);
+   heap_close(relation, RowExclusiveLock);
+}
index bece9e0f1848cd00a0e69c49b295d5c3fcc4d890..4bc561f96ab54edb17ae1b67cce52f7f85373e5e 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.346 2002/07/18 17:14:19 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.347 2002/07/18 23:11:27 petere Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -135,13 +135,13 @@ static void doNegateFloat(Value *v);
        AlterDatabaseSetStmt, AlterGroupStmt,
        AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
        AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
-       ConstraintsSetStmt, CopyStmt, CreateAsStmt,
+       ConstraintsSetStmt, CopyStmt, CreateAsStmt, CreateCastStmt,
        CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
        CreateSchemaStmt, CreateSeqStmt, CreateStmt,
        CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
        CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
        DropGroupStmt, DropPLangStmt, DropStmt,
-       DropAssertStmt, DropTrigStmt, DropRuleStmt,
+       DropAssertStmt, DropTrigStmt, DropRuleStmt, DropCastStmt,
        DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
        GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
        LockStmt, NotifyStmt, OptimizableStmt,
@@ -165,7 +165,7 @@ static void doNegateFloat(Value *v);
 %type  createdb_opt_item, copy_opt_item
 
 %type    opt_lock, lock_type
-%type     opt_force, opt_or_replace
+%type     opt_force, opt_or_replace, opt_assignment
 
 %type    user_list
 
@@ -346,7 +346,7 @@ static void doNegateFloat(Value *v);
 
    HANDLER, HAVING, HOUR_P,
 
-   ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT, IN_P, INCREMENT,
+   ILIKE, IMMEDIATE, IMMUTABLE, IN_P, INCREMENT,
    INDEX, INHERITS, INITIALLY, INNER_P, INOUT, INPUT,
    INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
    INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
@@ -475,6 +475,7 @@ stmt :
            | CopyStmt
            | CreateStmt
            | CreateAsStmt
+           | CreateCastStmt
            | CreateDomainStmt
            | CreateFunctionStmt
            | CreateSchemaStmt
@@ -489,6 +490,7 @@ stmt :
            | DropStmt
            | TruncateStmt
            | CommentStmt
+           | DropCastStmt
            | DropGroupStmt
            | DropPLangStmt
            | DropAssertStmt
@@ -2886,15 +2888,6 @@ RecipeStmt:  EXECUTE RECIPE recipe_name
  *                     as 
  *                     language  [with parameters]
  *
- * CAST() form allowing all options from the CREATE FUNCTION form:
- *             create [or replace] cast ( as )
- *                     as 
- *                     language  [with parameters]
- *
- * SQL99 CAST() form (requires a function to be previously defined):
- *             create [or replace] cast ( as )
- *                     with function fname () [as assignment]
- *
  *****************************************************************************/
 
 CreateFunctionStmt:
@@ -2910,63 +2903,6 @@ CreateFunctionStmt:
                    n->withClause = $9;
                    $$ = (Node *)n;
                }
-       /* CREATE CAST SQL99 standard form */
-       | CREATE opt_or_replace CAST '(' func_type AS func_type ')'
-           WITH FUNCTION func_name func_args opt_assignment opt_definition
-               {
-                   CreateFunctionStmt *n;
-                   char buf[256];
-                   n = makeNode(CreateFunctionStmt);
-                   n->replace = $2;
-                   n->funcname = $7->names;
-                   n->argTypes = makeList1($5);
-                   n->returnType = $7;
-                   /* expand this into a string of SQL language */
-                   strcpy(buf, "select ");
-                   strcat(buf, ((Value *)lfirst($11))->val.str);
-                   strcat(buf, "($1)");
-                   n->options = lappend($14, makeDefElem("as", (Node *)makeList1(makeString(pstrdup(buf)))));
-                   /* make sure that this will allow implicit casting */
-                   n->options = lappend(n->options,
-                                        makeDefElem("implicit", (Node *)makeInteger(TRUE)));
-                   /* and mention that this is SQL language */
-                   n->options = lappend(n->options,
-                                        makeDefElem("language", (Node *)makeString(pstrdup("sql"))));
-                   $$ = (Node *)n;
-               }
-       /* CREATE CAST SQL99 minimally variant form */
-       | CREATE opt_or_replace CAST '(' func_type AS func_type ')'
-           WITH FUNCTION func_name func_args AS Sconst opt_definition
-               {
-                   CreateFunctionStmt *n;
-                   n = makeNode(CreateFunctionStmt);
-                   n->replace = $2;
-                   n->funcname = $7->names;
-                   n->argTypes = makeList1($5);
-                   n->returnType = $7;
-                   n->options = lappend($15, makeDefElem("as", (Node *)lcons(makeList1(makeString($14)), $11)));
-                   /* make sure that this will allow implicit casting */
-                   n->options = lappend(n->options,
-                                        makeDefElem("implicit", (Node *)makeInteger(TRUE)));
-                   n->options = lappend(n->options,
-                                        makeDefElem("language", (Node *)makeString(pstrdup("c"))));
-                   $$ = (Node *)n;
-               }
-       /* CREATE CAST with mostly CREATE FUNCTION clauses */
-       | CREATE opt_or_replace CAST '(' func_type AS func_type ')'
-           createfunc_opt_list opt_definition
-               {
-                   CreateFunctionStmt *n;
-                   n = makeNode(CreateFunctionStmt);
-                   n->replace = $2;
-                   n->funcname = $7->names;
-                   n->argTypes = makeList1($5);
-                   n->returnType = $7;
-                   /* make sure that this will allow implicit casting */
-                   n->options = lappend($9, makeDefElem("implicit", (Node *)makeInteger(TRUE)));
-                   n->withClause = $10;
-                   $$ = (Node *)n;
-               }
        ;
 
 opt_or_replace:
@@ -3090,10 +3026,6 @@ createfunc_opt_item:
                {
                    $$ = makeDefElem("security", (Node *)makeInteger(FALSE));
                }
-           | IMPLICIT CAST
-               {
-                   $$ = makeDefElem("implicit", (Node *)makeInteger(TRUE));
-               }
        ;
 
 func_as:   Sconst                      { $$ = makeList1(makeString($1)); }
@@ -3108,10 +3040,6 @@ opt_definition:
            | /*EMPTY*/                             { $$ = NIL; }
        ;
 
-opt_assignment:  AS ASSIGNMENT                 {}
-       | /*EMPTY*/                             {}
-       ;
-
 
 /*****************************************************************************
  *
@@ -3132,14 +3060,6 @@ RemoveFuncStmt:
                    n->behavior = $5;
                    $$ = (Node *)n;
                }
-       | DROP CAST '(' func_type AS func_type ')' opt_drop_behavior
-               {
-                   RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
-                   n->funcname = $6->names;
-                   n->args = makeList1($4);
-                   n->behavior = $8;
-                   $$ = (Node *)n;
-               }
        ;
 
 RemoveAggrStmt:
@@ -3190,6 +3110,49 @@ any_operator:
        ;
 
 
+/*****************************************************************************
+ *
+ *     CREATE CAST / DROP CAST
+ *
+ *****************************************************************************/
+
+CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
+                   WITH FUNCTION function_with_argtypes opt_assignment
+               {
+                   CreateCastStmt *n = makeNode(CreateCastStmt);
+                   n->sourcetype = $4;
+                   n->targettype = $6;
+                   n->func = (FuncWithArgs *) $10;
+                   n->implicit = $11;
+                   $$ = (Node *)n;
+               }
+           | CREATE CAST '(' ConstTypename AS ConstTypename ')'
+                   WITHOUT FUNCTION opt_assignment
+               {
+                   CreateCastStmt *n = makeNode(CreateCastStmt);
+                   n->sourcetype = $4;
+                   n->targettype = $6;
+                   n->func = NULL;
+                   n->implicit = $10;
+                   $$ = (Node *)n;
+               }
+
+opt_assignment:  AS ASSIGNMENT                 { $$ = TRUE; }
+       | /*EMPTY*/                             { $$ = FALSE; }
+       ;
+
+
+DropCastStmt: DROP CAST '(' ConstTypename AS ConstTypename ')' opt_drop_behavior
+               {
+                   DropCastStmt *n = makeNode(DropCastStmt);
+                   n->sourcetype = $4;
+                   n->targettype = $6;
+                   n->behavior = $8;
+                   $$ = (Node *)n;
+               }
+
+
+
 /*****************************************************************************
  *
  *     QUERY:
@@ -6701,7 +6664,6 @@ unreserved_keyword:
            | HOUR_P
            | IMMEDIATE
            | IMMUTABLE
-           | IMPLICIT
            | INCREMENT
            | INDEX
            | INHERITS
index f007092f668ba1339c3e15557f7ef67232976482..02c9fcdda93e2594c73dd92060880443b64d7752 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.121 2002/07/18 17:14:19 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.122 2002/07/18 23:11:28 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -142,7 +142,6 @@ static const ScanKeyword ScanKeywords[] = {
    {"ilike", ILIKE},
    {"immediate", IMMEDIATE},
    {"immutable", IMMUTABLE},
-   {"implicit", IMPLICIT},
    {"in", IN_P},
    {"increment", INCREMENT},
    {"index", INDEX},
index fda9100d67d67dfda8528ea684d88c5e6082c350..15896a37d78be2e85c838b56b8948fe1a0b3b2c2 100644 (file)
@@ -8,12 +8,13 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.77 2002/07/09 13:52:14 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.78 2002/07/18 23:11:28 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "catalog/pg_cast.h"
 #include "catalog/pg_proc.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
@@ -31,8 +32,9 @@ Oid           PromoteTypeToNext(Oid inType);
 
 static Oid PreferredType(CATEGORY category, Oid type);
 static Node *build_func_call(Oid funcid, Oid rettype, List *args);
-static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId,
-                                  Oid secondArgType, bool isExplicit);
+static Oid find_coercion_function(Oid targetTypeId, Oid sourceTypeId,
+                                  bool isExplicit);
+static Oid find_typmod_coercion_function(Oid typeId);
 static Node    *TypeConstraints(Node *arg, Oid typeId);
 
 /* coerce_type()
@@ -142,7 +144,6 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 
        funcId = find_coercion_function(baseTypeId,
                                        getBaseType(inputTypeId),
-                                       InvalidOid,
                                        isExplicit);
        if (!OidIsValid(funcId))
            elog(ERROR, "coerce_type: no conversion function from '%s' to '%s'",
@@ -258,7 +259,6 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
         */
        funcId = find_coercion_function(getBaseType(targetTypeId),
                                        getBaseType(inputTypeId),
-                                       InvalidOid,
                                        isExplicit);
        if (!OidIsValid(funcId))
            return false;
@@ -312,8 +312,7 @@ coerce_type_typmod(ParseState *pstate, Node *node,
    if (atttypmod < 0 || atttypmod == exprTypmod(node))
        return node;
 
-   /* Note this is always implicit coercion */
-   funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
+   funcId = find_typmod_coercion_function(baseTypeId);
    if (OidIsValid(funcId))
    {
        Const      *cons;
@@ -621,21 +620,25 @@ TypeCategory(Oid inType)
 static bool
 DirectlyBinaryCompatible(Oid type1, Oid type2)
 {
+   HeapTuple   tuple;
+   bool        result;
+
    if (type1 == type2)
        return true;
-   if (TypeIsTextGroup(type1) && TypeIsTextGroup(type2))
-       return true;
-   if (TypeIsInt4GroupA(type1) && TypeIsInt4GroupA(type2))
-       return true;
-   if (TypeIsInt4GroupB(type1) && TypeIsInt4GroupB(type2))
-       return true;
-   if (TypeIsInt4GroupC(type1) && TypeIsInt4GroupC(type2))
-       return true;
-   if (TypeIsInetGroup(type1) && TypeIsInetGroup(type2))
-       return true;
-   if (TypeIsBitGroup(type1) && TypeIsBitGroup(type2))
-       return true;
-   return false;
+
+   tuple = SearchSysCache(CASTSOURCETARGET, type1, type2, 0, 0);
+   if (HeapTupleIsValid(tuple))
+   {
+       Form_pg_cast caststruct;
+
+       caststruct = (Form_pg_cast) GETSTRUCT(tuple);
+       result = caststruct->castfunc == InvalidOid && caststruct->castimplicit;
+       ReleaseSysCache(tuple);
+   }
+   else
+       result = false;
+
+   return result;
 }
 
 
@@ -750,34 +753,51 @@ PreferredType(CATEGORY category, Oid type)
  * If a function is found, return its pg_proc OID; else return InvalidOid.
  */
 static Oid
-find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
-                      bool isExplicit)
+find_coercion_function(Oid targetTypeId, Oid sourceTypeId, bool isExplicit)
+{
+   Oid         funcid = InvalidOid;
+   HeapTuple   tuple;
+
+   tuple = SearchSysCache(CASTSOURCETARGET,
+                          ObjectIdGetDatum(sourceTypeId),
+                          ObjectIdGetDatum(targetTypeId),
+                          0, 0);
+
+   if (HeapTupleIsValid(tuple))
+   {
+       Form_pg_cast cform = (Form_pg_cast) GETSTRUCT(tuple);
+
+       if (isExplicit || cform->castimplicit)
+           funcid = cform->castfunc;
+
+       ReleaseSysCache(tuple);
+   }
+
+   return funcid;
+}
+
+
+static Oid
+find_typmod_coercion_function(Oid typeId)
 {
    Oid         funcid = InvalidOid;
    Type        targetType;
    char       *typname;
    Oid         typnamespace;
    Oid         oid_array[FUNC_MAX_ARGS];
-   int         nargs;
    HeapTuple   ftup;
 
-   targetType = typeidType(targetTypeId);
+   targetType = typeidType(typeId);
    typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
    typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace;
 
    MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
-   oid_array[0] = inputTypeId;
-   if (OidIsValid(secondArgType))
-   {
-       oid_array[1] = secondArgType;
-       nargs = 2;
-   }
-   else
-       nargs = 1;
+   oid_array[0] = typeId;
+   oid_array[1] = INT4OID;
 
    ftup = SearchSysCache(PROCNAMENSP,
                          CStringGetDatum(typname),
-                         Int16GetDatum(nargs),
+                         Int16GetDatum(2),
                          PointerGetDatum(oid_array),
                          ObjectIdGetDatum(typnamespace));
    if (HeapTupleIsValid(ftup))
@@ -785,15 +805,11 @@ find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
        Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
 
        /* Make sure the function's result type is as expected */
-       if (pform->prorettype == targetTypeId && !pform->proretset &&
+       if (pform->prorettype == typeId && !pform->proretset &&
            !pform->proisagg)
        {
-           /* If needed, make sure it can be invoked implicitly */
-           if (isExplicit || pform->proimplicit)
-           {
-               /* Okay to use it */
-               funcid = ftup->t_data->t_oid;
-           }
+           /* Okay to use it */
+           funcid = ftup->t_data->t_oid;
        }
        ReleaseSysCache(ftup);
    }
index 862faf34cae8b9b735592f6ecdc954e4b455e6ec..d9137368335d3b5cd7abb6fd233db48789019a75 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.271 2002/07/18 16:47:25 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.272 2002/07/18 23:11:28 petere Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.271 $ $Date: 2002/07/18 16:47:25 $\n");
+       puts("$Revision: 1.272 $ $Date: 2002/07/18 23:11:28 $\n");
    }
 
    /*
@@ -2444,6 +2444,14 @@ CreateCommandTag(Node *parsetree)
            tag = "CREATE CONVERSION";
            break;
 
+       case T_CreateCastStmt:
+           tag = "CREATE CAST";
+           break;
+
+       case T_DropCastStmt:
+           tag = "DROP CAST";
+           break;
+
        default:
            elog(LOG, "CreateCommandTag: unknown parse node type %d",
                 nodeTag(parsetree));
index 8ba7466ee286b663b4ead170fe06e8ca231df270..54eeab77cd1c404b542751a9555a9869249d6781 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.163 2002/07/18 16:47:25 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.164 2002/07/18 23:11:28 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -829,6 +829,14 @@ ProcessUtility(Node *parsetree,
            }
            break;
 
+       case T_CreateCastStmt:
+           CreateCast((CreateCastStmt *) parsetree);
+           break;
+
+       case T_DropCastStmt:
+           DropCast((DropCastStmt *) parsetree);
+           break;
+
        default:
            elog(ERROR, "ProcessUtility: command #%d unsupported",
                 nodeTag(parsetree));
index 2772b668738409a9ffb35b2a69e8822f62ffacef..5999ad96285c2b0e5235e8f577015ef01048e7d9 100644 (file)
@@ -3,7 +3,7 @@
  *             back to source text
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.111 2002/07/18 17:14:20 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.112 2002/07/18 23:11:28 petere Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -43,6 +43,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_cast.h"
 #include "catalog/pg_index.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
@@ -2048,9 +2049,9 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
  *     Strip any type coercions at the top of the given expression tree,
  *     as long as they are coercions 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 the function name
- * is the same as the (internal) name of its result type.
+ * 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.
  *
  * XXX It'd be better if the parsetree retained some explicit indication
  * of the coercion, so we didn't need these heuristics.
@@ -2069,9 +2070,9 @@ strip_type_coercion(Node *expr, Oid resultType)
    {
        Func       *func;
        HeapTuple   procTuple;
-       HeapTuple   typeTuple;
+       HeapTuple   castTuple;
        Form_pg_proc procStruct;
-       Form_pg_type typeStruct;
+       Form_pg_cast castStruct;
 
        func = (Func *) (((Expr *) expr)->oper);
        Assert(IsA(func, Func));
@@ -2085,33 +2086,33 @@ strip_type_coercion(Node *expr, Oid resultType)
            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 */
-       /* Also, it must be an implicit coercion function */
        if (procStruct->pronargs != 1 ||
-           procStruct->prorettype != resultType ||
-           !procStruct->proimplicit)
+           procStruct->prorettype != resultType)
        {
            ReleaseSysCache(procTuple);
            return expr;
        }
-       /* See if function has same name/namespace as its result type */
-       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)
+       /* 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(typeTuple);
+           ReleaseSysCache(castTuple);
            return expr;
        }
        /* Okay, it is indeed a type-coercion function */
        ReleaseSysCache(procTuple);
-       ReleaseSysCache(typeTuple);
+       ReleaseSysCache(castTuple);
        return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
    }
 
index 52763d29e43f8de0e3cd98a1b3ba95bf7384b805..d03fd88e4df0c8fd26c26975f960491cc77a5fe9 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.46 2002/06/20 20:29:38 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.47 2002/07/18 23:11:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,7 +63,6 @@ SetDefine(char *querystr, Oid elemType)
                             fileName,  /* probin */
                             false,     /* not aggregate */
                             false,     /* security invoker */
-                            false,     /* not implicit coercion */
                             false,     /* isStrict (irrelevant, no args) */
                             PROVOLATILE_VOLATILE,  /* assume unsafe */
                             100,       /* byte_pct */
index a724a0874eec35050497b54161ed2d5cb62cd7b1..5f0be16b75a8f20f50d8ee6887d36fe7f0489b2c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.81 2002/07/11 07:39:27 ishii Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.82 2002/07/18 23:11:29 petere Exp $
  *
  * NOTES
  *   These routines allow the parser/planner/executor to perform
@@ -28,6 +28,7 @@
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_amop.h"
 #include "catalog/pg_amproc.h"
+#include "catalog/pg_cast.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_group.h"
 #include "catalog/pg_index.h"
@@ -174,6 +175,17 @@ static const struct cachedesc cacheinfo[] = {
            0,
            0
    }},
+   {
+       CastRelationName,           /* CASTSOURCETARGET */
+       CastSourceTargetIndex,
+       0,
+       2,
+       {
+           Anum_pg_cast_castsource,
+           Anum_pg_cast_casttarget,
+           0,
+           0
+   }},
    {OperatorClassRelationName, /* CLAAMNAMENSP */
        OpclassAmNameNspIndex,
        0,
index 9902a24fc4f498b5206b44c403a26ab363b4c81b..f582da72c39ec938e26892e964d2ef0f3cc4d9d1 100644 (file)
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.160 2002/07/18 16:47:25 tgl Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.161 2002/07/18 23:11:29 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -708,6 +708,7 @@ $ECHO_N "initializing pg_depend... "$ECHO_C
 -- First delete any already-made entries; PINs override all else, and must
 -- be the only entries for their objects.
 DELETE FROM pg_depend;
+INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_class;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_proc;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_type;
index 827459b4db4ea98cdfd5bf5aafa2ac155d8a2c68..123ef3df056dcbb41c19330567dced91436383a8 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.65 2002/06/20 20:29:41 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.66 2002/07/18 23:11:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -170,6 +170,13 @@ dumpSchema(Archive *fout,
        dumpOprs(fout, oprinfo, numOperators);
    }
 
+   if (!dataOnly)
+   {
+       if (g_verbose)
+           write_msg(NULL, "dumping out user-defined casts\n");
+       dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
+   }
+
    *numTablesPtr = numTables;
    return tblinfo;
 }
@@ -386,6 +393,23 @@ findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
    return -1;
 }
 
+/*
+ * Finds the index (in tinfo) of the type with the given OID.  Returns
+ * -1 if not found.
+ */
+int
+findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid)
+{
+   int         i;
+
+   for (i = 0; i < numTypes; i++)
+   {
+       if (strcmp(tinfo[i].oid, oid) == 0)
+           return i;
+   }
+   return -1;
+}
+
 /*
  * findOprByOid
  *   given the oid of an operator, return the name of the operator
index 1aefb9801aafa5b1e1928b2bdb553c130bc22549..a173839b4d4ca20d2b85350c6c90af4edf1f5ca9 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.273 2002/07/18 04:50:51 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.274 2002/07/18 23:11:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3398,7 +3398,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
    char       *prosrc;
    char       *probin;
    char       *provolatile;
-   char       *proimplicit;
    char       *proisstrict;
    char       *prosecdef;
    char       *lanname;
@@ -3417,7 +3416,7 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
    {
        appendPQExpBuffer(query,
                          "SELECT proretset, prosrc, probin, "
-                         "provolatile, proimplicit, proisstrict, prosecdef, "
+                         "provolatile, proisstrict, prosecdef, "
                          "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
                          "FROM pg_catalog.pg_proc "
                          "WHERE oid = '%s'::pg_catalog.oid",
@@ -3428,7 +3427,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
        appendPQExpBuffer(query,
                          "SELECT proretset, prosrc, probin, "
                          "case when proiscachable then 'i' else 'v' end as provolatile, "
-                         "'f'::boolean as proimplicit, "
                          "proisstrict, "
                          "'f'::boolean as prosecdef, "
                          "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
@@ -3441,7 +3439,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
        appendPQExpBuffer(query,
                          "SELECT proretset, prosrc, probin, "
                          "case when proiscachable then 'i' else 'v' end as provolatile, "
-                         "'f'::boolean as proimplicit, "
                          "'f'::boolean as proisstrict, "
                          "'f'::boolean as prosecdef, "
                          "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
@@ -3472,7 +3469,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
    prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
    probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
    provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
-   proimplicit = PQgetvalue(res, 0, PQfnumber(res, "proimplicit"));
    proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
    prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
    lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
@@ -3533,9 +3529,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
        }
    }
 
-   if (proimplicit[0] == 't')
-       appendPQExpBuffer(q, " IMPLICIT CAST");
-
    if (proisstrict[0] == 't')
        appendPQExpBuffer(q, " STRICT");
 
@@ -3569,6 +3562,108 @@ done:
    free(funcsig_tag);
 }
 
+
+/*
+ * Dump all casts
+ */
+void
+dumpCasts(Archive *fout,
+         FuncInfo *finfo, int numFuncs,
+         TypeInfo *tinfo, int numTypes)
+{
+   PGresult   *res;
+   PQExpBuffer query = createPQExpBuffer();
+   PQExpBuffer defqry = createPQExpBuffer();
+   PQExpBuffer delqry = createPQExpBuffer();
+   int         ntups;
+   int         i;
+
+   /* Make sure we are in proper schema */
+   selectSourceSchema("pg_catalog");
+
+   if (fout->remoteVersion >= 70300)
+       appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castimplicit 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;");
+
+   res = PQexec(g_conn, query->data);
+   if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
+   {
+       write_msg(NULL, "query to obtain list of casts failed: %s",
+                 PQerrorMessage(g_conn));
+       exit_nicely();
+   }
+   ntups = PQntuples(res);
+
+   for (i = 0; i < ntups; i++)
+   {
+       char * castoid = PQgetvalue(res, i, 0);
+       char * castsource = PQgetvalue(res, i, 1);
+       char * casttarget = PQgetvalue(res, i, 2);
+       char * castfunc = PQgetvalue(res, i, 3);
+       char * castimplicit = PQgetvalue(res, i, 4);
+       int fidx = -1;
+       const char *((*deps)[]);
+
+       if (strcmp(castfunc, "0") != 0)
+           fidx = findFuncByOid(finfo, numFuncs, castfunc);
+
+       /*
+        * We treat the cast as being in the namespace of the
+        * underlying function.  This doesn't handle binary compatible
+        * casts.  Where should those go?
+        */
+       if (fidx < 0 || !finfo[fidx].pronamespace->dump)
+           continue;
+
+       /* Make a dependency to ensure function is dumped first */
+       if (fidx >= 0)
+       {
+           deps = malloc(sizeof(char *) * 2);
+
+           (*deps)[0] = strdup(castfunc);
+           (*deps)[1] = NULL;  /* End of List */
+       }
+       else
+           deps = NULL;
+
+       resetPQExpBuffer(defqry);
+       resetPQExpBuffer(delqry);
+
+       appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
+                         getFormattedTypeName(castsource, zeroAsNone),
+                         getFormattedTypeName(casttarget, zeroAsNone));
+
+       appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
+                         getFormattedTypeName(castsource, zeroAsNone),
+                         getFormattedTypeName(casttarget, zeroAsNone));
+
+       if (strcmp(castfunc, "0")==0)
+           appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
+       else
+           appendPQExpBuffer(defqry, "WITH FUNCTION %s",
+                             format_function_signature(&finfo[fidx], true));
+
+       if (strcmp(castimplicit, "t")==0)
+           appendPQExpBuffer(defqry, " AS ASSIGNMENT");
+       appendPQExpBuffer(defqry, ";\n");
+
+       ArchiveEntry(fout, castoid,
+                    format_function_signature(&finfo[fidx], false),
+                    finfo[fidx].pronamespace->nspname, "",
+                    "CAST", deps,
+                    defqry->data, delqry->data,
+                    NULL, NULL, NULL);
+   }
+
+   PQclear(res);
+
+   destroyPQExpBuffer(query);
+   destroyPQExpBuffer(defqry);
+   destroyPQExpBuffer(delqry);
+}
+
+
 /*
  * dumpOprs
  *   writes out to fout the queries to recreate all the user-defined operators
index 17491b027e57d0cdacc114585b9b356e80c85055..732fdfb74e411aa2ee6d611e955481827032ddf5 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.90 2002/07/06 20:12:30 momjian Exp $
+ * $Id: pg_dump.h,v 1.91 2002/07/18 23:11:29 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -177,6 +177,7 @@ typedef enum _OidOptions
 extern int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
 extern char *findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid);
 extern int findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid);
+extern int findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid);
 
 extern void check_conn_and_db(void);
 extern void exit_nicely(void);
@@ -202,6 +203,8 @@ extern void dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
          TypeInfo *tinfo, int numTypes);
 extern void dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs);
 extern void dumpFuncs(Archive *fout, FuncInfo finfo[], int numFuncs);
+extern void dumpCasts(Archive *fout, FuncInfo *finfo, int numFuncs,
+                     TypeInfo *tinfo, int numTypes);
 extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates);
 extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
 extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
index 0e452a9ca3e7c3f27fac9ac3e96b5487fd74158d..dc1fedae9e1db6b349b7df3260114af2ecfec0f6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catname.h,v 1.28 2002/07/12 18:43:19 tgl Exp $
+ * $Id: catname.h,v 1.29 2002/07/18 23:11:30 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #define  AccessMethodOperatorRelationName "pg_amop"
 #define  AccessMethodProcedureRelationName "pg_amproc"
 #define  AttributeRelationName "pg_attribute"
+#define  CastRelationName "pg_cast"
 #define  ConstraintRelationName "pg_constraint"
 #define  ConversionRelationName "pg_conversion"
 #define  DatabaseRelationName "pg_database"
index 5fd581b254870a82320ff205d5b0944d2e526674..077da864a418d4577e6b032e9c65db57a1b80d05 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.140 2002/07/15 16:33:31 tgl Exp $
+ * $Id: catversion.h,v 1.141 2002/07/18 23:11:30 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200207141
+#define CATALOG_VERSION_NO 200207191
 
 #endif
index 91e35934470387e668f8cf8d4d409db5dee0f367..777a4031dd79b14f52682588642b1eb6684c379d 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: indexing.h,v 1.70 2002/07/15 16:33:31 tgl Exp $
+ * $Id: indexing.h,v 1.71 2002/07/18 23:11:30 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@
 #define Num_pg_amproc_indices      1
 #define Num_pg_attr_indices            2
 #define Num_pg_attrdef_indices     2
+#define Num_pg_cast_indices            1
 #define Num_pg_class_indices       2
 #define Num_pg_constraint_indices  3
 #define Num_pg_conversion_indices  3
@@ -60,6 +61,7 @@
 #define AttrDefaultOidIndex            "pg_attrdef_oid_index"
 #define AttributeRelidNameIndex        "pg_attribute_relid_attnam_index"
 #define AttributeRelidNumIndex     "pg_attribute_relid_attnum_index"
+#define CastSourceTargetIndex      "pg_cast_source_target_index"
 #define ClassNameNspIndex          "pg_class_relname_nsp_index"
 #define ClassOidIndex              "pg_class_oid_index"
 #define ConstraintNameNspIndex     "pg_constraint_conname_nsp_index"
@@ -108,6 +110,7 @@ extern char *Name_pg_amop_indices[];
 extern char *Name_pg_amproc_indices[];
 extern char *Name_pg_attr_indices[];
 extern char *Name_pg_attrdef_indices[];
+extern char *Name_pg_cast_indices[];
 extern char *Name_pg_class_indices[];
 extern char *Name_pg_constraint_indices[];
 extern char *Name_pg_conversion_indices[];
@@ -166,6 +169,7 @@ DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index on pg_attrdef using btree(ad
 DECLARE_UNIQUE_INDEX(pg_attrdef_oid_index on pg_attrdef using btree(oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnam_index on pg_attribute using btree(attrelid oid_ops, attname name_ops));
 DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnum_index on pg_attribute using btree(attrelid oid_ops, attnum int2_ops));
+DECLARE_UNIQUE_INDEX(pg_cast_source_target_index on pg_cast using btree(castsource oid_ops, casttarget oid_ops));
 DECLARE_UNIQUE_INDEX(pg_class_oid_index on pg_class using btree(oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index on pg_class using btree(relname name_ops, relnamespace oid_ops));
 /* This following index is not used for a cache and is not unique */
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
new file mode 100644 (file)
index 0000000..4e042a3
--- /dev/null
@@ -0,0 +1,225 @@
+/*-------------------------------------------------------------------------
+ *
+ * $Header: /cvsroot/pgsql/src/include/catalog/pg_cast.h,v 1.1 2002/07/18 23:11:30 petere Exp $
+ *
+ * Copyright (c) 2002, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_CAST_H
+#define PG_CAST_H
+
+CATALOG(pg_cast)
+{
+   Oid         castsource;
+   Oid         casttarget;
+   Oid         castfunc;       /* 0 = binary compatible */
+   bool        castimplicit;
+} FormData_pg_cast;
+
+typedef FormData_pg_cast *Form_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
+
+/* ----------------
+ *     initial contents of pg_cast
+ * ----------------
+ */
+
+/*
+ * binary compatible casts
+ */
+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 ));
+
+/*
+ * 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:
+ *
+ * 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;
+ */
+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 ));
+/*xDATA(insert (   23  703 1200 f ));*/
+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 f ));
+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 f ));
+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 ));
+
+#endif   /* PG_CAST_H */
index 0bb719a55ab72decaeb87ff862e79125551f3cd8..c84ac13a9591d7e9c11f4933d767eb28bf264c2b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.243 2002/06/20 20:29:44 momjian Exp $
+ * $Id: pg_proc.h,v 1.244 2002/07/18 23:11:30 petere Exp $
  *
  * NOTES
  *   The script catalog/genbki.sh reads this file and generates .bki
@@ -45,7 +45,7 @@ CATALOG(pg_proc) BOOTSTRAP
    Oid         prolang;        /* OID of pg_language entry */
    bool        proisagg;       /* is it an aggregate? */
    bool        prosecdef;      /* security definer */
-   bool        proimplicit;    /* can be invoked as implicit coercion? */
+   bool        proimplicit;    /* unused */
    bool        proisstrict;    /* strict with respect to NULLs? */
    bool        proretset;      /* returns a set? */
    char        provolatile;    /* see PROVOLATILE_ categories below */
@@ -3007,7 +3007,6 @@ extern Oid ProcedureCreate(const char *procedureName,
                const char *probin,
                bool isAgg,
                bool security_definer,
-               bool isImplicit,
                bool isStrict,
                char volatility,
                int32 byte_pct,
index 169ec3f3dff1dc132428a0600ac5ceaa750c32c1..707ba1d1b819f6dd9707e4a9288e10695558b81e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: defrem.h,v 1.41 2002/07/12 18:43:19 tgl Exp $
+ * $Id: defrem.h,v 1.42 2002/07/18 23:11:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,9 @@ extern void ReindexDatabase(const char *databaseName, bool force, bool all);
 extern void CreateFunction(CreateFunctionStmt *stmt);
 extern void RemoveFunction(RemoveFuncStmt *stmt);
 extern void RemoveFunctionById(Oid funcOid);
+extern void CreateCast(CreateCastStmt *stmt);
+extern void DropCast(DropCastStmt *stmt);
+extern void DropCastById(Oid castOid);
 
 extern void DefineOperator(List *names, List *parameters);
 extern void RemoveOperator(RemoveOperStmt *stmt);
index 308bf95877d462c25020b23b0e75ae290d2f0e4d..3583315a274a24f3a527877ef41c8a3d048adbaf 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.112 2002/07/18 17:14:20 momjian Exp $
+ * $Id: nodes.h,v 1.113 2002/07/18 23:11:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -199,6 +199,8 @@ typedef enum NodeTag
    T_AlterDatabaseSetStmt,
    T_AlterUserSetStmt,
    T_CreateConversionStmt,
+   T_CreateCastStmt,
+   T_DropCastStmt,
 
    T_A_Expr = 700,
    T_ColumnRef,
index b2e42ab71648b88ae48cfb215a06df54a5175253..e4c6b625d11f0ce5d3f6d130e4e939c732e27296 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.192 2002/07/18 17:14:20 momjian Exp $
+ * $Id: parsenodes.h,v 1.193 2002/07/18 23:11:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1555,4 +1555,30 @@ typedef struct CreateConversionStmt
    bool        def;                /* is this a default conversion? */
 } CreateConversionStmt;
 
+/* ----------------------
+ * CREATE CAST Statement
+ * ----------------------
+ */
+typedef struct CreateCastStmt
+{
+   NodeTag     type;
+   TypeName   *sourcetype;
+   TypeName   *targettype;
+   FuncWithArgs *func;
+   bool        implicit;
+} CreateCastStmt;
+
+/* ----------------------
+ * DROP CAST Statement
+ * ----------------------
+ */
+typedef struct DropCastStmt
+{
+   NodeTag     type;
+   TypeName   *sourcetype;
+   TypeName   *targettype;
+   DropBehavior behavior;
+} DropCastStmt;
+
+
 #endif   /* PARSENODES_H */
index f40471d7948754c01e645dce11330dbe905eb172..5d964bb5668815c1c977af3272085c4741574b66 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: syscache.h,v 1.49 2002/07/11 07:39:28 ishii Exp $
+ * $Id: syscache.h,v 1.50 2002/07/18 23:11:32 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 #define AMPROCNUM      5
 #define ATTNAME            6
 #define ATTNUM         7
-#define CLAAMNAMENSP   8
-#define CLAOID         9
-#define CONNAMESP      10
-#define GRONAME            11
-#define GROSYSID       12
-#define INDEXRELID     13
-#define INHRELID       14
-#define LANGNAME       15
-#define LANGOID            16
-#define NAMESPACENAME  17
-#define NAMESPACEOID   18
-#define OPERNAMENSP        19
-#define OPEROID            20
-#define PROCNAMENSP        21
-#define PROCOID            22
-#define RELNAMENSP     23
-#define RELOID         24
-#define RULERELNAME        25
-#define SHADOWNAME     26
-#define SHADOWSYSID        27
-#define STATRELATT     28
-#define TYPENAMENSP        29
-#define TYPEOID            30
+#define CASTSOURCETARGET 8
+#define CLAAMNAMENSP   9
+#define CLAOID         10
+#define CONNAMESP      11
+#define GRONAME            12
+#define GROSYSID       13
+#define INDEXRELID     14
+#define INHRELID       15
+#define LANGNAME       16
+#define LANGOID            17
+#define NAMESPACENAME  18
+#define NAMESPACEOID   19
+#define OPERNAMENSP        20
+#define OPEROID            21
+#define PROCNAMENSP        22
+#define PROCOID            23
+#define RELNAMENSP     24
+#define RELOID         25
+#define RULERELNAME        26
+#define SHADOWNAME     27
+#define SHADOWSYSID        28
+#define STATRELATT     29
+#define TYPENAMENSP        30
+#define TYPEOID            31
 
 extern void InitCatalogCache(void);
 extern void InitCatalogCachePhase2(void);
index 98ac26c0c20788ebf8892ff2d950312e130c796d..cb1193b0407eb9365024747b864e7cac47d58c60 100644 (file)
@@ -1,7 +1,7 @@
 --
 -- OPR_SANITY
 -- Sanity checks for common errors in making operator/procedure system tables:
--- pg_operator, pg_proc, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
+-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
 --
 -- None of the SELECTs here should ever find any matching entries,
 -- so the expected output is easy to maintain ;-).
@@ -180,20 +180,49 @@ WHERE p1.oid != p2.oid AND
 -------------+-------------
 (0 rows)
 
--- If a proc is marked as an implicit cast, then it should be something that
--- the system might actually use as a cast function: name same as the name
--- of its output type, and either one arg that's a different type, or two
--- args where the first is the same as the output type and the second is int4.
-SELECT p1.oid, p1.proname
-FROM pg_proc as p1
-WHERE p1.proimplicit AND
-    (NOT EXISTS (SELECT 1 FROM pg_type t WHERE t.oid = p1.prorettype AND
-                 t.typname = p1.proname) OR
-     NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
-          (p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
-           p1.proargtypes[1] = 'int4'::regtype)));
- oid | proname 
------+---------
+-- **************** pg_cast ****************
+-- Look for casts from and to the same type.  This is not harmful, but
+-- useless.
+SELECT *
+FROM pg_cast c
+WHERE c.castsource = c.casttarget;
+ castsource | casttarget | castfunc | castimplicit 
+------------+------------+----------+--------------
+(0 rows)
+
+-- Look for cast functions with incorrect number or type of argument
+-- or return value.
+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 
+------------+------------+----------+--------------
+(0 rows)
+
+-- Look for binary compatible casts that do not have the reverse
+-- direction registered as well, or where the reverse direction is not
+-- also binary compatible.  This is legal, but probably not intended.
+SELECT *
+FROM pg_cast c
+WHERE c.castfunc = 0 AND
+    NOT EXISTS (SELECT * FROM pg_cast k
+                WHERE k.castfunc = 0 AND
+                    k.castsource = c.casttarget AND
+                    k.casttarget = c.castsource);
+ castsource | casttarget | castfunc | castimplicit 
+------------+------------+----------+--------------
 (0 rows)
 
 -- **************** pg_operator ****************
index 2e0cf3a03300daa482a2aba217aa99510c74f103..25e7b091c22e0b8a9313927f7177915ffe253668 100644 (file)
@@ -37,6 +37,7 @@ SELECT relname, relhasindex
  pg_amproc           | t
  pg_attrdef          | t
  pg_attribute        | t
+ pg_cast             | t
  pg_class            | t
  pg_constraint       | t
  pg_conversion       | t
@@ -62,5 +63,5 @@ SELECT relname, relhasindex
  shighway            | t
  tenk1               | t
  tenk2               | t
-(52 rows)
+(53 rows)
 
index 270c275b87a4907225fa9149501eb1f04ab442a6..9d08dbd5bb37f2a780b47c6034e6243a38e91966 100644 (file)
@@ -1,7 +1,7 @@
 --
 -- OPR_SANITY
 -- Sanity checks for common errors in making operator/procedure system tables:
--- pg_operator, pg_proc, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
+-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
 --
 -- None of the SELECTs here should ever find any matching entries,
 -- so the expected output is easy to maintain ;-).
@@ -141,19 +141,43 @@ WHERE p1.oid != p2.oid AND
     NOT p1.proisagg AND NOT p2.proisagg AND
     (p1.proargtypes[7] < p2.proargtypes[7]);
 
--- If a proc is marked as an implicit cast, then it should be something that
--- the system might actually use as a cast function: name same as the name
--- of its output type, and either one arg that's a different type, or two
--- args where the first is the same as the output type and the second is int4.
+-- **************** pg_cast ****************
 
-SELECT p1.oid, p1.proname
-FROM pg_proc as p1
-WHERE p1.proimplicit AND
-    (NOT EXISTS (SELECT 1 FROM pg_type t WHERE t.oid = p1.prorettype AND
-                 t.typname = p1.proname) OR
-     NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
-          (p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
-           p1.proargtypes[1] = 'int4'::regtype)));
+-- Look for casts from and to the same type.  This is not harmful, but
+-- useless.
+
+SELECT *
+FROM pg_cast c
+WHERE c.castsource = c.casttarget;
+
+-- Look for cast functions with incorrect number or type of argument
+-- or return value.
+
+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;
+
+-- Look for binary compatible casts that do not have the reverse
+-- direction registered as well, or where the reverse direction is not
+-- also binary compatible.  This is legal, but probably not intended.
+
+SELECT *
+FROM pg_cast c
+WHERE c.castfunc = 0 AND
+    NOT EXISTS (SELECT * FROM pg_cast k
+                WHERE k.castfunc = 0 AND
+                    k.castsource = c.casttarget AND
+                    k.casttarget = c.castsource);
 
 -- **************** pg_operator ****************