From 395e47aa40b3e34794702ef67e0cb7948a2a7bb3 Mon Sep 17 00:00:00 2001 From: heikki Date: Fri, 31 Oct 2008 08:39:22 +0000 Subject: [PATCH] Add support for user-defined I/O conversion casts. --- doc/src/sgml/catalogs.sgml | 21 +- doc/src/sgml/ref/create_cast.sgml | 36 +- src/backend/commands/functioncmds.c | 20 +- src/backend/nodes/copyfuncs.c | 1 + src/backend/nodes/equalfuncs.c | 1 + src/backend/parser/gram.y | 13 + src/backend/parser/parse_coerce.c | 22 +- src/bin/pg_dump/pg_dump.c | 49 ++- src/bin/pg_dump/pg_dump.h | 1 + src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_cast.h | 696 ++++++++++++++++--------------- src/include/nodes/parsenodes.h | 1 + src/test/regress/expected/opr_sanity.out | 57 ++- src/test/regress/sql/opr_sanity.sql | 19 +- 14 files changed, 533 insertions(+), 406 deletions(-) rewrite src/include/catalog/pg_cast.h (60%) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index c660874cdd..66f74f4a4e 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1415,9 +1415,10 @@ cannot be deduced from some generic rule. For example, casting between a domain and its base type is not explicitly represented in pg_cast. Another important exception is that - I/O conversion casts, those performed using a data type's own - I/O functions to convert to or from text or other string types, - are not explicitly represented in pg_cast. + automatic I/O conversion casts, those performed using a data + type's own I/O functions to convert to or from text or other + string types, are not explicitly represented in + pg_cast. @@ -1454,8 +1455,7 @@ pg_proc.oid The OID of the function to use to perform this cast. Zero is - stored if the data types are binary coercible (that is, no - run-time operation is needed to perform the cast) + stored if the cast method doesn't require a function. @@ -1473,6 +1473,17 @@ other cases + + castmethod + char + + + Indicates how the cast is performed. + f means that the function specified in the castfunc field is used. + i means that the input/output functions are used. + b means that the types are binary-coercible, thus no conversion is required + +
diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml index f6fb1a2e39..028a0d024c 100644 --- a/doc/src/sgml/ref/create_cast.sgml +++ b/doc/src/sgml/ref/create_cast.sgml @@ -24,6 +24,10 @@ CREATE CAST (sourcetype AS targettypesourcetype AS targettype) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] + +CREATE CAST (sourcetype AS targettype) + WITH INOUT + [ AS ASSIGNMENT | AS IMPLICIT ] @@ -59,6 +63,13 @@ SELECT CAST(42 AS float8); + You can define a cast as an I/O conversion cast using + the WITH INOUT syntax. An I/O conversion cast is + performed by invoking the output function of the source data type, and + passing the result to the input function of the target data type. + + + By default, a cast can be invoked only by an explicit cast request, that is an explicit CAST(x AS typename) or @@ -200,6 +211,18 @@ SELECT CAST ( 2 AS numeric ) + 4.0; + WITH INOUT + + + + Indicates that the cast is an I/O conversion cast, performed by + invoking the output function of the source data type, and passing the + result to the input function of the target data type. + + + + + AS ASSIGNMENT @@ -284,15 +307,12 @@ SELECT CAST ( 2 AS numeric ) + 4.0; It is normally not necessary to create casts between user-defined types and the standard string types (text, varchar, and char(n), as well as user-defined types that - are defined to be in the string category). PostgreSQL will - automatically handle a cast to a string type by invoking the other - type's output function, or conversely handle a cast from a string type - by invoking the other type's input function. These - automatically-provided casts are known as I/O conversion - casts. I/O conversion casts to string types are treated as - assignment casts, while I/O conversion casts from string types are + are defined to be in the string category). PostgreSQL + provides automatic I/O conversion casts for that. The automatic casts to + string types are treated as assignment casts, while the automatic casts + from string types are explicit-only. You can override this behavior by declaring your own - cast to replace an I/O conversion cast, but usually the only reason to + cast to replace an automatic cast, but usually the only reason to do so is if you want the conversion to be more easily invokable than the standard assignment-only or explicit-only setting. Another possible reason is that you want the conversion to behave differently from the diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index fe6d547cd2..5e8e788186 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1383,6 +1383,7 @@ CreateCast(CreateCastStmt *stmt) Oid funcid; int nargs; char castcontext; + char castmethod; Relation relation; HeapTuple tuple; Datum values[Natts_pg_cast]; @@ -1415,7 +1416,15 @@ CreateCast(CreateCastStmt *stmt) format_type_be(sourcetypeid), format_type_be(targettypeid)))); + /* Detemine the cast method */ if (stmt->func != NULL) + castmethod = COERCION_METHOD_FUNCTION; + else if(stmt->inout) + castmethod = COERCION_METHOD_INOUT; + else + castmethod = COERCION_METHOD_BINARY; + + if (castmethod == COERCION_METHOD_FUNCTION) { Form_pg_proc procstruct; @@ -1476,6 +1485,12 @@ CreateCast(CreateCastStmt *stmt) } else { + funcid = InvalidOid; + nargs = 0; + } + + if (castmethod == COERCION_METHOD_BINARY) + { int16 typ1len; int16 typ2len; bool typ1byval; @@ -1483,10 +1498,6 @@ CreateCast(CreateCastStmt *stmt) char typ1align; char typ2align; - /* indicates binary coercibility */ - funcid = InvalidOid; - nargs = 0; - /* * Must be superuser to create binary-compatible casts, since * erroneous casts can easily crash the backend. @@ -1562,6 +1573,7 @@ CreateCast(CreateCastStmt *stmt) values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid); values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid); values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext); + values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod); MemSet(nulls, ' ', Natts_pg_cast); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7d3dbe260c..4273ef18a5 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3042,6 +3042,7 @@ _copyCreateCastStmt(CreateCastStmt *from) COPY_NODE_FIELD(targettype); COPY_NODE_FIELD(func); COPY_SCALAR_FIELD(context); + COPY_SCALAR_FIELD(inout); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 77d0f534b0..ed902734f9 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1666,6 +1666,7 @@ _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b) COMPARE_NODE_FIELD(targettype); COMPARE_NODE_FIELD(func); COMPARE_SCALAR_FIELD(context); + COMPARE_SCALAR_FIELD(inout); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 94a91afe75..de760b5d57 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -4590,6 +4590,7 @@ CreateCastStmt: CREATE CAST '(' Typename AS Typename ')' n->targettype = $6; n->func = $10; n->context = (CoercionContext) $11; + n->inout = false; $$ = (Node *)n; } | CREATE CAST '(' Typename AS Typename ')' @@ -4600,6 +4601,18 @@ CreateCastStmt: CREATE CAST '(' Typename AS Typename ')' n->targettype = $6; n->func = NULL; n->context = (CoercionContext) $10; + n->inout = false; + $$ = (Node *)n; + } + | CREATE CAST '(' Typename AS Typename ')' + WITH INOUT cast_context + { + CreateCastStmt *n = makeNode(CreateCastStmt); + n->sourcetype = $4; + n->targettype = $6; + n->func = NULL; + n->context = (CoercionContext) $10; + n->inout = true; $$ = (Node *)n; } ; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index f939dd8b2f..227247d404 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -1909,11 +1909,23 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, /* Rely on ordering of enum for correct behavior here */ if (ccontext >= castcontext) { - *funcid = castForm->castfunc; - if (OidIsValid(*funcid)) - result = COERCION_PATH_FUNC; - else - result = COERCION_PATH_RELABELTYPE; + switch (castForm->castmethod) + { + case COERCION_METHOD_FUNCTION: + result = COERCION_PATH_FUNC; + *funcid = castForm->castfunc; + break; + case COERCION_METHOD_INOUT: + result = COERCION_PATH_COERCEVIAIO; + break; + case COERCION_METHOD_BINARY: + result = COERCION_PATH_RELABELTYPE; + break; + default: + elog(ERROR, "unrecognized castmethod: %d", + (int) castForm->castmethod); + break; + } } ReleaseSysCache(tuple); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 6c0f8278f9..4f6a08861e 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -36,6 +36,7 @@ int optreset; #include "access/attnum.h" #include "access/sysattr.h" +#include "catalog/pg_cast.h" #include "catalog/pg_class.h" #include "catalog/pg_proc.h" #include "catalog/pg_trigger.h" @@ -4410,21 +4411,31 @@ getCasts(int *numCasts) int i_casttarget; int i_castfunc; int i_castcontext; + int i_castmethod; /* Make sure we are in proper schema */ selectSourceSchema("pg_catalog"); - if (g_fout->remoteVersion >= 70300) + if (g_fout->remoteVersion >= 80400) + { + appendPQExpBuffer(query, "SELECT tableoid, oid, " + "castsource, casttarget, castfunc, castcontext, " + "castmethod " + "FROM pg_cast ORDER BY 3,4"); + } + else if (g_fout->remoteVersion >= 70300) { appendPQExpBuffer(query, "SELECT tableoid, oid, " - "castsource, casttarget, castfunc, castcontext " + "castsource, casttarget, castfunc, castcontext, " + "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod " "FROM pg_cast ORDER BY 3,4"); } else { appendPQExpBuffer(query, "SELECT 0 as tableoid, p.oid, " "t1.oid as castsource, t2.oid as casttarget, " - "p.oid as castfunc, 'e' as castcontext " + "p.oid as castfunc, 'e' as castcontext, " + "'f' as castmethod " "FROM pg_type t1, pg_type t2, pg_proc p " "WHERE p.pronargs = 1 AND " "p.proargtypes[0] = t1.oid AND " @@ -4447,6 +4458,7 @@ getCasts(int *numCasts) i_casttarget = PQfnumber(res, "casttarget"); i_castfunc = PQfnumber(res, "castfunc"); i_castcontext = PQfnumber(res, "castcontext"); + i_castmethod = PQfnumber(res, "castmethod"); for (i = 0; i < ntups; i++) { @@ -4462,6 +4474,7 @@ getCasts(int *numCasts) castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget)); castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc)); castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext)); + castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod)); /* * Try to name cast as concatenation of typnames. This is only used @@ -7188,18 +7201,26 @@ dumpCast(Archive *fout, CastInfo *cast) getFormattedTypeName(cast->castsource, zeroAsNone), getFormattedTypeName(cast->casttarget, zeroAsNone)); - if (!OidIsValid(cast->castfunc)) - appendPQExpBuffer(defqry, "WITHOUT FUNCTION"); - else + switch(cast->castmethod) { - /* - * Always qualify the function name, in case it is not in pg_catalog - * schema (format_function_signature won't qualify it). - */ - appendPQExpBuffer(defqry, "WITH FUNCTION %s.", - fmtId(funcInfo->dobj.namespace->dobj.name)); - appendPQExpBuffer(defqry, "%s", - format_function_signature(funcInfo, true)); + case COERCION_METHOD_BINARY: + appendPQExpBuffer(defqry, "WITHOUT FUNCTION"); + break; + case COERCION_METHOD_INOUT: + appendPQExpBuffer(defqry, "WITH INOUT"); + break; + case COERCION_METHOD_FUNCTION: + /* + * Always qualify the function name, in case it is not in + * pg_catalog schema (format_function_signature won't qualify it). + */ + appendPQExpBuffer(defqry, "WITH FUNCTION %s.", + fmtId(funcInfo->dobj.namespace->dobj.name)); + appendPQExpBuffer(defqry, "%s", + format_function_signature(funcInfo, true)); + break; + default: + write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n"); } if (cast->castcontext == 'a') diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 74cc147ab4..2d66b32c63 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -376,6 +376,7 @@ typedef struct _castInfo Oid casttarget; Oid castfunc; char castcontext; + char castmethod; } CastInfo; /* InhInfo isn't a DumpableObject, just temporary state */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 85fe684e25..56f98f655f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200810171 +#define CATALOG_VERSION_NO 200810311 #endif diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h dissimilarity index 60% index 44e92b3482..534b560aca 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -1,341 +1,355 @@ -/*------------------------------------------------------------------------- - * - * pg_cast.h - * definition of the system "type casts" relation (pg_cast) - * along with the relation's initial contents. - * - * As of Postgres 8.0, pg_cast describes not only type coercion functions - * but also length coercion functions. - * - * - * Copyright (c) 2002-2008, PostgreSQL Global Development Group - * - * $PostgreSQL$ - * - * NOTES - * the genbki.sh script reads this file and generates .bki - * information from the DATA() statements. - * - *------------------------------------------------------------------------- - */ -#ifndef PG_CAST_H -#define PG_CAST_H - -#include "catalog/genbki.h" - -/* ---------------- - * pg_cast definition. cpp turns this into - * typedef struct FormData_pg_cast - * ---------------- - */ -#define CastRelationId 2605 - -CATALOG(pg_cast,2605) -{ - Oid castsource; /* source datatype for cast */ - Oid casttarget; /* destination datatype for cast */ - Oid castfunc; /* cast function; 0 = binary coercible */ - char castcontext; /* contexts in which cast can be used */ -} FormData_pg_cast; - -typedef FormData_pg_cast *Form_pg_cast; - -/* - * The allowable values for pg_cast.castcontext are specified by this enum. - * Since castcontext is stored as a "char", we use ASCII codes for human - * convenience in reading the table. Note that internally to the backend, - * these values are converted to the CoercionContext enum (see primnodes.h), - * which is defined to sort in a convenient order; the ASCII codes don't - * have to sort in any special order. - */ - -typedef enum CoercionCodes -{ - COERCION_CODE_IMPLICIT = 'i', /* coercion in context of expression */ - COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */ - COERCION_CODE_EXPLICIT = 'e' /* explicit cast operation */ -} CoercionCodes; - - -/* ---------------- - * compiler constants for pg_cast - * ---------------- - */ -#define Natts_pg_cast 4 -#define Anum_pg_cast_castsource 1 -#define Anum_pg_cast_casttarget 2 -#define Anum_pg_cast_castfunc 3 -#define Anum_pg_cast_castcontext 4 - -/* ---------------- - * initial contents of pg_cast - * - * Note: this table has OIDs, but we don't bother to assign them manually, - * since nothing needs to know the specific OID of any built-in cast. - * ---------------- - */ - -/* - * Numeric category: implicit casts are allowed in the direction - * int2->int4->int8->numeric->float4->float8, while casts in the - * reverse direction are assignment-only. - */ -DATA(insert ( 20 21 714 a )); -DATA(insert ( 20 23 480 a )); -DATA(insert ( 20 700 652 i )); -DATA(insert ( 20 701 482 i )); -DATA(insert ( 20 1700 1781 i )); -DATA(insert ( 21 20 754 i )); -DATA(insert ( 21 23 313 i )); -DATA(insert ( 21 700 236 i )); -DATA(insert ( 21 701 235 i )); -DATA(insert ( 21 1700 1782 i )); -DATA(insert ( 23 20 481 i )); -DATA(insert ( 23 21 314 a )); -DATA(insert ( 23 700 318 i )); -DATA(insert ( 23 701 316 i )); -DATA(insert ( 23 1700 1740 i )); -DATA(insert ( 700 20 653 a )); -DATA(insert ( 700 21 238 a )); -DATA(insert ( 700 23 319 a )); -DATA(insert ( 700 701 311 i )); -DATA(insert ( 700 1700 1742 a )); -DATA(insert ( 701 20 483 a )); -DATA(insert ( 701 21 237 a )); -DATA(insert ( 701 23 317 a )); -DATA(insert ( 701 700 312 a )); -DATA(insert ( 701 1700 1743 a )); -DATA(insert ( 1700 20 1779 a )); -DATA(insert ( 1700 21 1783 a )); -DATA(insert ( 1700 23 1744 a )); -DATA(insert ( 1700 700 1745 i )); -DATA(insert ( 1700 701 1746 i )); - -/* Allow explicit coercions between int4 and bool */ -DATA(insert ( 23 16 2557 e )); -DATA(insert ( 16 23 2558 e )); - -/* - * OID category: allow implicit conversion from any integral type (including - * int8, to support OID literals > 2G) to OID, as well as assignment coercion - * from OID to int4 or int8. Similarly for each OID-alias type. Also allow - * implicit coercions between OID and each OID-alias type, as well as - * regproc<->regprocedure and regoper<->regoperator. (Other coercions - * between alias types must pass through OID.) Lastly, there are implicit - * casts from text and varchar to regclass, which exist mainly to support - * legacy forms of nextval() and related functions. - */ -DATA(insert ( 20 26 1287 i )); -DATA(insert ( 21 26 313 i )); -DATA(insert ( 23 26 0 i )); -DATA(insert ( 26 20 1288 a )); -DATA(insert ( 26 23 0 a )); -DATA(insert ( 26 24 0 i )); -DATA(insert ( 24 26 0 i )); -DATA(insert ( 20 24 1287 i )); -DATA(insert ( 21 24 313 i )); -DATA(insert ( 23 24 0 i )); -DATA(insert ( 24 20 1288 a )); -DATA(insert ( 24 23 0 a )); -DATA(insert ( 24 2202 0 i )); -DATA(insert ( 2202 24 0 i )); -DATA(insert ( 26 2202 0 i )); -DATA(insert ( 2202 26 0 i )); -DATA(insert ( 20 2202 1287 i )); -DATA(insert ( 21 2202 313 i )); -DATA(insert ( 23 2202 0 i )); -DATA(insert ( 2202 20 1288 a )); -DATA(insert ( 2202 23 0 a )); -DATA(insert ( 26 2203 0 i )); -DATA(insert ( 2203 26 0 i )); -DATA(insert ( 20 2203 1287 i )); -DATA(insert ( 21 2203 313 i )); -DATA(insert ( 23 2203 0 i )); -DATA(insert ( 2203 20 1288 a )); -DATA(insert ( 2203 23 0 a )); -DATA(insert ( 2203 2204 0 i )); -DATA(insert ( 2204 2203 0 i )); -DATA(insert ( 26 2204 0 i )); -DATA(insert ( 2204 26 0 i )); -DATA(insert ( 20 2204 1287 i )); -DATA(insert ( 21 2204 313 i )); -DATA(insert ( 23 2204 0 i )); -DATA(insert ( 2204 20 1288 a )); -DATA(insert ( 2204 23 0 a )); -DATA(insert ( 26 2205 0 i )); -DATA(insert ( 2205 26 0 i )); -DATA(insert ( 20 2205 1287 i )); -DATA(insert ( 21 2205 313 i )); -DATA(insert ( 23 2205 0 i )); -DATA(insert ( 2205 20 1288 a )); -DATA(insert ( 2205 23 0 a )); -DATA(insert ( 26 2206 0 i )); -DATA(insert ( 2206 26 0 i )); -DATA(insert ( 20 2206 1287 i )); -DATA(insert ( 21 2206 313 i )); -DATA(insert ( 23 2206 0 i )); -DATA(insert ( 2206 20 1288 a )); -DATA(insert ( 2206 23 0 a )); -DATA(insert ( 26 3734 0 i )); -DATA(insert ( 3734 26 0 i )); -DATA(insert ( 20 3734 1287 i )); -DATA(insert ( 21 3734 313 i )); -DATA(insert ( 23 3734 0 i )); -DATA(insert ( 3734 20 1288 a )); -DATA(insert ( 3734 23 0 a )); -DATA(insert ( 26 3769 0 i )); -DATA(insert ( 3769 26 0 i )); -DATA(insert ( 20 3769 1287 i )); -DATA(insert ( 21 3769 313 i )); -DATA(insert ( 23 3769 0 i )); -DATA(insert ( 3769 20 1288 a )); -DATA(insert ( 3769 23 0 a )); -DATA(insert ( 25 2205 1079 i )); -DATA(insert ( 1043 2205 1079 i )); - -/* - * String category - */ -DATA(insert ( 25 1042 0 i )); -DATA(insert ( 25 1043 0 i )); -DATA(insert ( 1042 25 401 i )); -DATA(insert ( 1042 1043 401 i )); -DATA(insert ( 1043 25 0 i )); -DATA(insert ( 1043 1042 0 i )); -DATA(insert ( 18 25 946 i )); -DATA(insert ( 18 1042 860 a )); -DATA(insert ( 18 1043 946 a )); -DATA(insert ( 19 25 406 i )); -DATA(insert ( 19 1042 408 a )); -DATA(insert ( 19 1043 1401 a )); -DATA(insert ( 25 18 944 a )); -DATA(insert ( 1042 18 944 a )); -DATA(insert ( 1043 18 944 a )); -DATA(insert ( 25 19 407 i )); -DATA(insert ( 1042 19 409 i )); -DATA(insert ( 1043 19 1400 i )); - -/* Allow explicit coercions between int4 and "char" */ -DATA(insert ( 18 23 77 e )); -DATA(insert ( 23 18 78 e )); - -/* - * Datetime category - */ -DATA(insert ( 702 1082 1179 a )); -DATA(insert ( 702 1083 1364 a )); -DATA(insert ( 702 1114 2023 i )); -DATA(insert ( 702 1184 1173 i )); -DATA(insert ( 703 1186 1177 i )); -DATA(insert ( 1082 1114 2024 i )); -DATA(insert ( 1082 1184 1174 i )); -DATA(insert ( 1083 1186 1370 i )); -DATA(insert ( 1083 1266 2047 i )); -DATA(insert ( 1114 702 2030 a )); -DATA(insert ( 1114 1082 2029 a )); -DATA(insert ( 1114 1083 1316 a )); -DATA(insert ( 1114 1184 2028 i )); -DATA(insert ( 1184 702 1180 a )); -DATA(insert ( 1184 1082 1178 a )); -DATA(insert ( 1184 1083 2019 a )); -DATA(insert ( 1184 1114 2027 a )); -DATA(insert ( 1184 1266 1388 a )); -DATA(insert ( 1186 703 1194 a )); -DATA(insert ( 1186 1083 1419 a )); -DATA(insert ( 1266 1083 2046 a )); -/* Cross-category casts between int4 and abstime, reltime */ -DATA(insert ( 23 702 0 e )); -DATA(insert ( 702 23 0 e )); -DATA(insert ( 23 703 0 e )); -DATA(insert ( 703 23 0 e )); - -/* - * Geometric category - */ -DATA(insert ( 601 600 1532 e )); -DATA(insert ( 602 600 1533 e )); -DATA(insert ( 602 604 1449 a )); -DATA(insert ( 603 600 1534 e )); -DATA(insert ( 603 601 1541 e )); -DATA(insert ( 603 604 1448 a )); -DATA(insert ( 603 718 1479 e )); -DATA(insert ( 604 600 1540 e )); -DATA(insert ( 604 602 1447 a )); -DATA(insert ( 604 603 1446 e )); -DATA(insert ( 604 718 1474 e )); -DATA(insert ( 718 600 1416 e )); -DATA(insert ( 718 603 1480 e )); -DATA(insert ( 718 604 1544 e )); - -/* - * INET category - */ -DATA(insert ( 650 869 0 i )); -DATA(insert ( 869 650 1715 a )); - -/* - * BitString category - */ -DATA(insert ( 1560 1562 0 i )); -DATA(insert ( 1562 1560 0 i )); -/* Cross-category casts between bit and int4, int8 */ -DATA(insert ( 20 1560 2075 e )); -DATA(insert ( 23 1560 1683 e )); -DATA(insert ( 1560 20 2076 e )); -DATA(insert ( 1560 23 1684 e )); - -/* - * Cross-category casts to and from TEXT - * - * We need entries here only for a few specialized cases where the behavior - * of the cast function differs from the datatype's I/O functions. Otherwise, - * parse_coerce.c will generate CoerceViaIO operations without any prompting. - * - * Note that the castcontext values specified here should be no stronger than - * parse_coerce.c's automatic casts ('a' to text, 'e' from text) else odd - * behavior will ensue when the automatic cast is applied instead of the - * pg_cast entry! - */ -DATA(insert ( 650 25 730 a )); -DATA(insert ( 869 25 730 a )); -DATA(insert ( 16 25 2971 a )); -DATA(insert ( 142 25 0 a )); -DATA(insert ( 25 142 2896 e )); - -/* - * Cross-category casts to and from VARCHAR - * - * We support all the same casts as for TEXT. - */ -DATA(insert ( 650 1043 730 a )); -DATA(insert ( 869 1043 730 a )); -DATA(insert ( 16 1043 2971 a )); -DATA(insert ( 142 1043 0 a )); -DATA(insert ( 1043 142 2896 e )); - -/* - * Cross-category casts to and from BPCHAR - * - * We support all the same casts as for TEXT. - */ -DATA(insert ( 650 1042 730 a )); -DATA(insert ( 869 1042 730 a )); -DATA(insert ( 16 1042 2971 a )); -DATA(insert ( 142 1042 0 a )); -DATA(insert ( 1042 142 2896 e )); - -/* - * Length-coercion functions - */ -DATA(insert ( 1042 1042 668 i )); -DATA(insert ( 1043 1043 669 i )); -DATA(insert ( 1083 1083 1968 i )); -DATA(insert ( 1114 1114 1961 i )); -DATA(insert ( 1184 1184 1967 i )); -DATA(insert ( 1186 1186 1200 i )); -DATA(insert ( 1266 1266 1969 i )); -DATA(insert ( 1560 1560 1685 i )); -DATA(insert ( 1562 1562 1687 i )); -DATA(insert ( 1700 1700 1703 i )); - -#endif /* PG_CAST_H */ +/*------------------------------------------------------------------------- + * + * pg_cast.h + * definition of the system "type casts" relation (pg_cast) + * along with the relation's initial contents. + * + * As of Postgres 8.0, pg_cast describes not only type coercion functions + * but also length coercion functions. + * + * + * Copyright (c) 2002-2008, PostgreSQL Global Development Group + * + * $PostgreSQL$ + * + * NOTES + * the genbki.sh script reads this file and generates .bki + * information from the DATA() statements. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CAST_H +#define PG_CAST_H + +#include "catalog/genbki.h" + +/* ---------------- + * pg_cast definition. cpp turns this into + * typedef struct FormData_pg_cast + * ---------------- + */ +#define CastRelationId 2605 + +CATALOG(pg_cast,2605) +{ + Oid castsource; /* source datatype for cast */ + Oid casttarget; /* destination datatype for cast */ + Oid castfunc; /* cast function; 0 = binary coercible */ + char castcontext; /* contexts in which cast can be used */ + char castmethod; /* cast method */ +} FormData_pg_cast; + +typedef FormData_pg_cast *Form_pg_cast; + +/* + * The allowable values for pg_cast.castcontext are specified by this enum. + * Since castcontext is stored as a "char", we use ASCII codes for human + * convenience in reading the table. Note that internally to the backend, + * these values are converted to the CoercionContext enum (see primnodes.h), + * which is defined to sort in a convenient order; the ASCII codes don't + * have to sort in any special order. + */ + +typedef enum CoercionCodes +{ + COERCION_CODE_IMPLICIT = 'i', /* coercion in context of expression */ + COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */ + COERCION_CODE_EXPLICIT = 'e' /* explicit cast operation */ +} CoercionCodes; + +/* + * The allowable values for pg_cast.castmethod are specified by this enum. + * Since castcontext is stored as a "char", we use ASCII codes for human + * convenience in reading the table. + */ +typedef enum CoercionMethod +{ + COERCION_METHOD_FUNCTION = 'f', /* use a function */ + COERCION_METHOD_BINARY = 'b', /* types are binary-compatible */ + COERCION_METHOD_INOUT = 'i' /* use input/output functions */ +} CoercionMethod; + + +/* ---------------- + * compiler constants for pg_cast + * ---------------- + */ +#define Natts_pg_cast 5 +#define Anum_pg_cast_castsource 1 +#define Anum_pg_cast_casttarget 2 +#define Anum_pg_cast_castfunc 3 +#define Anum_pg_cast_castcontext 4 +#define Anum_pg_cast_castmethod 5 + +/* ---------------- + * initial contents of pg_cast + * + * Note: this table has OIDs, but we don't bother to assign them manually, + * since nothing needs to know the specific OID of any built-in cast. + * ---------------- + */ + +/* + * Numeric category: implicit casts are allowed in the direction + * int2->int4->int8->numeric->float4->float8, while casts in the + * reverse direction are assignment-only. + */ +DATA(insert ( 20 21 714 a f )); +DATA(insert ( 20 23 480 a f )); +DATA(insert ( 20 700 652 i f )); +DATA(insert ( 20 701 482 i f )); +DATA(insert ( 20 1700 1781 i f )); +DATA(insert ( 21 20 754 i f )); +DATA(insert ( 21 23 313 i f )); +DATA(insert ( 21 700 236 i f )); +DATA(insert ( 21 701 235 i f )); +DATA(insert ( 21 1700 1782 i f )); +DATA(insert ( 23 20 481 i f )); +DATA(insert ( 23 21 314 a f )); +DATA(insert ( 23 700 318 i f )); +DATA(insert ( 23 701 316 i f )); +DATA(insert ( 23 1700 1740 i f )); +DATA(insert ( 700 20 653 a f )); +DATA(insert ( 700 21 238 a f )); +DATA(insert ( 700 23 319 a f )); +DATA(insert ( 700 701 311 i f )); +DATA(insert ( 700 1700 1742 a f )); +DATA(insert ( 701 20 483 a f )); +DATA(insert ( 701 21 237 a f )); +DATA(insert ( 701 23 317 a f )); +DATA(insert ( 701 700 312 a f )); +DATA(insert ( 701 1700 1743 a f )); +DATA(insert ( 1700 20 1779 a f )); +DATA(insert ( 1700 21 1783 a f )); +DATA(insert ( 1700 23 1744 a f )); +DATA(insert ( 1700 700 1745 i f )); +DATA(insert ( 1700 701 1746 i f )); + +/* Allow explicit coercions between int4 and bool */ +DATA(insert ( 23 16 2557 e f )); +DATA(insert ( 16 23 2558 e f )); + +/* + * OID category: allow implicit conversion from any integral type (including + * int8, to support OID literals > 2G) to OID, as well as assignment coercion + * from OID to int4 or int8. Similarly for each OID-alias type. Also allow + * implicit coercions between OID and each OID-alias type, as well as + * regproc<->regprocedure and regoper<->regoperator. (Other coercions + * between alias types must pass through OID.) Lastly, there are implicit + * casts from text and varchar to regclass, which exist mainly to support + * legacy forms of nextval() and related functions. + */ +DATA(insert ( 20 26 1287 i f )); +DATA(insert ( 21 26 313 i f )); +DATA(insert ( 23 26 0 i b )); +DATA(insert ( 26 20 1288 a f )); +DATA(insert ( 26 23 0 a b )); +DATA(insert ( 26 24 0 i b )); +DATA(insert ( 24 26 0 i b )); +DATA(insert ( 20 24 1287 i f )); +DATA(insert ( 21 24 313 i f )); +DATA(insert ( 23 24 0 i b )); +DATA(insert ( 24 20 1288 a f )); +DATA(insert ( 24 23 0 a b )); +DATA(insert ( 24 2202 0 i b )); +DATA(insert ( 2202 24 0 i b )); +DATA(insert ( 26 2202 0 i b )); +DATA(insert ( 2202 26 0 i b )); +DATA(insert ( 20 2202 1287 i f )); +DATA(insert ( 21 2202 313 i f )); +DATA(insert ( 23 2202 0 i b )); +DATA(insert ( 2202 20 1288 a f )); +DATA(insert ( 2202 23 0 a b )); +DATA(insert ( 26 2203 0 i b )); +DATA(insert ( 2203 26 0 i b )); +DATA(insert ( 20 2203 1287 i f )); +DATA(insert ( 21 2203 313 i f )); +DATA(insert ( 23 2203 0 i b )); +DATA(insert ( 2203 20 1288 a f )); +DATA(insert ( 2203 23 0 a b )); +DATA(insert ( 2203 2204 0 i b )); +DATA(insert ( 2204 2203 0 i b )); +DATA(insert ( 26 2204 0 i b )); +DATA(insert ( 2204 26 0 i b )); +DATA(insert ( 20 2204 1287 i f )); +DATA(insert ( 21 2204 313 i f )); +DATA(insert ( 23 2204 0 i b )); +DATA(insert ( 2204 20 1288 a f )); +DATA(insert ( 2204 23 0 a b )); +DATA(insert ( 26 2205 0 i b )); +DATA(insert ( 2205 26 0 i b )); +DATA(insert ( 20 2205 1287 i f )); +DATA(insert ( 21 2205 313 i f )); +DATA(insert ( 23 2205 0 i b )); +DATA(insert ( 2205 20 1288 a f )); +DATA(insert ( 2205 23 0 a b )); +DATA(insert ( 26 2206 0 i b )); +DATA(insert ( 2206 26 0 i b )); +DATA(insert ( 20 2206 1287 i f )); +DATA(insert ( 21 2206 313 i f )); +DATA(insert ( 23 2206 0 i b )); +DATA(insert ( 2206 20 1288 a f )); +DATA(insert ( 2206 23 0 a b )); +DATA(insert ( 26 3734 0 i b )); +DATA(insert ( 3734 26 0 i b )); +DATA(insert ( 20 3734 1287 i f )); +DATA(insert ( 21 3734 313 i f )); +DATA(insert ( 23 3734 0 i b )); +DATA(insert ( 3734 20 1288 a f )); +DATA(insert ( 3734 23 0 a b )); +DATA(insert ( 26 3769 0 i b )); +DATA(insert ( 3769 26 0 i b )); +DATA(insert ( 20 3769 1287 i f )); +DATA(insert ( 21 3769 313 i f )); +DATA(insert ( 23 3769 0 i b )); +DATA(insert ( 3769 20 1288 a f )); +DATA(insert ( 3769 23 0 a b )); +DATA(insert ( 25 2205 1079 i f )); +DATA(insert ( 1043 2205 1079 i f )); + +/* + * String category + */ +DATA(insert ( 25 1042 0 i b )); +DATA(insert ( 25 1043 0 i b )); +DATA(insert ( 1042 25 401 i f )); +DATA(insert ( 1042 1043 401 i f )); +DATA(insert ( 1043 25 0 i b )); +DATA(insert ( 1043 1042 0 i b )); +DATA(insert ( 18 25 946 i f )); +DATA(insert ( 18 1042 860 a f )); +DATA(insert ( 18 1043 946 a f )); +DATA(insert ( 19 25 406 i f )); +DATA(insert ( 19 1042 408 a f )); +DATA(insert ( 19 1043 1401 a f )); +DATA(insert ( 25 18 944 a f )); +DATA(insert ( 1042 18 944 a f )); +DATA(insert ( 1043 18 944 a f )); +DATA(insert ( 25 19 407 i f )); +DATA(insert ( 1042 19 409 i f )); +DATA(insert ( 1043 19 1400 i f )); + +/* Allow explicit coercions between int4 and "char" */ +DATA(insert ( 18 23 77 e f )); +DATA(insert ( 23 18 78 e f )); + +/* + * Datetime category + */ +DATA(insert ( 702 1082 1179 a f )); +DATA(insert ( 702 1083 1364 a f )); +DATA(insert ( 702 1114 2023 i f )); +DATA(insert ( 702 1184 1173 i f )); +DATA(insert ( 703 1186 1177 i f )); +DATA(insert ( 1082 1114 2024 i f )); +DATA(insert ( 1082 1184 1174 i f )); +DATA(insert ( 1083 1186 1370 i f )); +DATA(insert ( 1083 1266 2047 i f )); +DATA(insert ( 1114 702 2030 a f )); +DATA(insert ( 1114 1082 2029 a f )); +DATA(insert ( 1114 1083 1316 a f )); +DATA(insert ( 1114 1184 2028 i f )); +DATA(insert ( 1184 702 1180 a f )); +DATA(insert ( 1184 1082 1178 a f )); +DATA(insert ( 1184 1083 2019 a f )); +DATA(insert ( 1184 1114 2027 a f )); +DATA(insert ( 1184 1266 1388 a f )); +DATA(insert ( 1186 703 1194 a f )); +DATA(insert ( 1186 1083 1419 a f )); +DATA(insert ( 1266 1083 2046 a f )); +/* Cross-category casts between int4 and abstime, reltime */ +DATA(insert ( 23 702 0 e b )); +DATA(insert ( 702 23 0 e b )); +DATA(insert ( 23 703 0 e b )); +DATA(insert ( 703 23 0 e b )); + +/* + * Geometric category + */ +DATA(insert ( 601 600 1532 e f )); +DATA(insert ( 602 600 1533 e f )); +DATA(insert ( 602 604 1449 a f )); +DATA(insert ( 603 600 1534 e f )); +DATA(insert ( 603 601 1541 e f )); +DATA(insert ( 603 604 1448 a f )); +DATA(insert ( 603 718 1479 e f )); +DATA(insert ( 604 600 1540 e f )); +DATA(insert ( 604 602 1447 a f )); +DATA(insert ( 604 603 1446 e f )); +DATA(insert ( 604 718 1474 e f )); +DATA(insert ( 718 600 1416 e f )); +DATA(insert ( 718 603 1480 e f )); +DATA(insert ( 718 604 1544 e f )); + +/* + * INET category + */ +DATA(insert ( 650 869 0 i b )); +DATA(insert ( 869 650 1715 a f )); + +/* + * BitString category + */ +DATA(insert ( 1560 1562 0 i b )); +DATA(insert ( 1562 1560 0 i b )); +/* Cross-category casts between bit and int4, int8 */ +DATA(insert ( 20 1560 2075 e f )); +DATA(insert ( 23 1560 1683 e f )); +DATA(insert ( 1560 20 2076 e f )); +DATA(insert ( 1560 23 1684 e f )); + +/* + * Cross-category casts to and from TEXT + * + * We need entries here only for a few specialized cases where the behavior + * of the cast function differs from the datatype's I/O functions. Otherwise, + * parse_coerce.c will generate CoerceViaIO operations without any prompting. + * + * Note that the castcontext values specified here should be no stronger than + * parse_coerce.c's automatic casts ('a' to text, 'e' from text) else odd + * behavior will ensue when the automatic cast is applied instead of the + * pg_cast entry! + */ +DATA(insert ( 650 25 730 a f )); +DATA(insert ( 869 25 730 a f )); +DATA(insert ( 16 25 2971 a f )); +DATA(insert ( 142 25 0 a b )); +DATA(insert ( 25 142 2896 e f )); + +/* + * Cross-category casts to and from VARCHAR + * + * We support all the same casts as for TEXT. + */ +DATA(insert ( 650 1043 730 a f )); +DATA(insert ( 869 1043 730 a f )); +DATA(insert ( 16 1043 2971 a f )); +DATA(insert ( 142 1043 0 a b )); +DATA(insert ( 1043 142 2896 e f )); + +/* + * Cross-category casts to and from BPCHAR + * + * We support all the same casts as for TEXT. + */ +DATA(insert ( 650 1042 730 a f )); +DATA(insert ( 869 1042 730 a f )); +DATA(insert ( 16 1042 2971 a f )); +DATA(insert ( 142 1042 0 a b )); +DATA(insert ( 1042 142 2896 e f )); + +/* + * Length-coercion functions + */ +DATA(insert ( 1042 1042 668 i f )); +DATA(insert ( 1043 1043 669 i f )); +DATA(insert ( 1083 1083 1968 i f )); +DATA(insert ( 1114 1114 1961 i f )); +DATA(insert ( 1184 1184 1967 i f )); +DATA(insert ( 1186 1186 1200 i f )); +DATA(insert ( 1266 1266 1969 i f )); +DATA(insert ( 1560 1560 1685 i f )); +DATA(insert ( 1562 1562 1687 i f )); +DATA(insert ( 1700 1700 1703 i f )); + +#endif /* PG_CAST_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2850817484..b442121050 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2062,6 +2062,7 @@ typedef struct CreateCastStmt TypeName *targettype; FuncWithArgs *func; CoercionContext context; + bool inout; } CreateCastStmt; /* ---------------------- diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index a21c2ba374..87464ec9cf 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -22,7 +22,7 @@ create function binary_coercible(oid, oid) returns bool as $$ SELECT ($1 = $2) OR EXISTS(select 1 from pg_catalog.pg_cast where castsource = $1 and casttarget = $2 and - castfunc = 0 and castcontext = 'i') OR + castmethod = 'b' and castcontext = 'i') OR ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND EXISTS(select 1 from pg_catalog.pg_type where oid = $1 and typelem != 0 and typlen = -1)) @@ -33,7 +33,7 @@ create function physically_coercible(oid, oid) returns bool as $$ SELECT ($1 = $2) OR EXISTS(select 1 from pg_catalog.pg_cast where castsource = $1 and casttarget = $2 and - castfunc = 0) OR + castmethod = 'b') OR ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND EXISTS(select 1 from pg_catalog.pg_type where oid = $1 and typelem != 0 and typlen = -1)) @@ -262,9 +262,20 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT -- oidjoins test). SELECT * FROM pg_cast c -WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i'); - castsource | casttarget | castfunc | castcontext -------------+------------+----------+------------- +WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i') + OR castmethod NOT IN ('f', 'b' ,'i'); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +-- Check that castfunc is nonzero only for cast methods that need a function, +-- and zero otherwise +SELECT * +FROM pg_cast c +WHERE (castmethod = 'f' AND castfunc = 0) + OR (castmethod IN ('b', 'i') AND castfunc <> 0); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ (0 rows) -- Look for casts to/from the same type that aren't length coercion functions. @@ -273,15 +284,15 @@ WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i'); SELECT * FROM pg_cast c WHERE castsource = casttarget AND castfunc = 0; - castsource | casttarget | castfunc | castcontext -------------+------------+----------+------------- + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ (0 rows) SELECT c.* FROM pg_cast c, pg_proc p WHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget; - castsource | casttarget | castfunc | castcontext -------------+------------+----------+------------- + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ (0 rows) -- Look for cast functions that don't have the right signature. The @@ -299,8 +310,8 @@ WHERE c.castfunc = p.oid AND OR (c.castsource = 'character'::regtype AND p.proargtypes[0] = 'text'::regtype)) OR NOT binary_coercible(p.prorettype, c.casttarget)); - castsource | casttarget | castfunc | castcontext -------------+------------+----------+------------- + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ (0 rows) SELECT c.* @@ -308,8 +319,8 @@ FROM pg_cast c, pg_proc p WHERE c.castfunc = p.oid AND ((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR (p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype)); - castsource | casttarget | castfunc | castcontext -------------+------------+----------+------------- + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ (0 rows) -- Look for binary compatible casts that do not have the reverse @@ -324,19 +335,19 @@ WHERE c.castfunc = p.oid AND -- texttoxml(), which does an XML syntax check. SELECT * FROM pg_cast c -WHERE c.castfunc = 0 AND +WHERE c.castmethod = 'b' AND NOT EXISTS (SELECT 1 FROM pg_cast k - WHERE k.castfunc = 0 AND + WHERE k.castmethod = 'b' AND k.castsource = c.casttarget AND k.casttarget = c.castsource); - castsource | casttarget | castfunc | castcontext -------------+------------+----------+------------- - 25 | 1042 | 0 | i - 1043 | 1042 | 0 | i - 650 | 869 | 0 | i - 142 | 25 | 0 | a - 142 | 1043 | 0 | a - 142 | 1042 | 0 | a + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ + 25 | 1042 | 0 | i | b + 1043 | 1042 | 0 | i | b + 650 | 869 | 0 | i | b + 142 | 25 | 0 | a | b + 142 | 1043 | 0 | a | b + 142 | 1042 | 0 | a | b (6 rows) -- **************** pg_operator **************** diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 57c2cad951..c254a8b6cb 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -25,7 +25,7 @@ create function binary_coercible(oid, oid) returns bool as $$ SELECT ($1 = $2) OR EXISTS(select 1 from pg_catalog.pg_cast where castsource = $1 and casttarget = $2 and - castfunc = 0 and castcontext = 'i') OR + castmethod = 'b' and castcontext = 'i') OR ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND EXISTS(select 1 from pg_catalog.pg_type where oid = $1 and typelem != 0 and typlen = -1)) @@ -37,7 +37,7 @@ create function physically_coercible(oid, oid) returns bool as $$ SELECT ($1 = $2) OR EXISTS(select 1 from pg_catalog.pg_cast where castsource = $1 and casttarget = $2 and - castfunc = 0) OR + castmethod = 'b') OR ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND EXISTS(select 1 from pg_catalog.pg_type where oid = $1 and typelem != 0 and typlen = -1)) @@ -214,7 +214,16 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT SELECT * FROM pg_cast c -WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i'); +WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i') + OR castmethod NOT IN ('f', 'b' ,'i'); + +-- Check that castfunc is nonzero only for cast methods that need a function, +-- and zero otherwise + +SELECT * +FROM pg_cast c +WHERE (castmethod = 'f' AND castfunc = 0) + OR (castmethod IN ('b', 'i') AND castfunc <> 0); -- Look for casts to/from the same type that aren't length coercion functions. -- (We assume they are length coercions if they take multiple arguments.) @@ -267,9 +276,9 @@ WHERE c.castfunc = p.oid AND SELECT * FROM pg_cast c -WHERE c.castfunc = 0 AND +WHERE c.castmethod = 'b' AND NOT EXISTS (SELECT 1 FROM pg_cast k - WHERE k.castfunc = 0 AND + WHERE k.castmethod = 'b' AND k.castsource = c.casttarget AND k.casttarget = c.castsource); -- 2.11.4.GIT