Commit 092bc496 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Add support for user-defined I/O conversion casts.

parent 34e37d58
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.179 2008/10/17 22:10:29 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.180 2008/10/31 08:39:19 heikki Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
......@@ -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
<structname>pg_cast</structname>. Another important exception is that
<quote>I/O conversion casts</>, those performed using a data type's own
I/O functions to convert to or from <type>text</> or other string types,
are not explicitly represented in <structname>pg_cast</structname>.
<quote>automatic I/O conversion casts</>, those performed using a data
type's own I/O functions to convert to or from <type>text</> or other
string types, are not explicitly represented in
<structname>pg_cast</structname>.
</para>
<table>
......@@ -1454,8 +1455,7 @@
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>
The OID of the function to use to perform this cast. Zero is
stored if the data types are binary coercible (that is, no
run-time operation is needed to perform the cast)
stored if the cast method doesn't require a function.
</entry>
</row>
......@@ -1473,6 +1473,17 @@
other cases
</entry>
</row>
<row>
<entry><structfield>castmethod</structfield></entry>
<entry><type>char</type></entry>
<entry></entry>
<entry>
Indicates how the cast is performed.
<literal>f</> means that the function specified in the <structfield>castfunc</> field is used.
<literal>i</> means that the input/output functions are used.
<literal>b</> means that the types are binary-coercible, thus no conversion is required
</entry>
</row>
</tbody>
</tgroup>
</table>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.29 2008/07/30 21:23:17 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.30 2008/10/31 08:39:20 heikki Exp $ -->
<refentry id="SQL-CREATECAST">
<refmeta>
......@@ -24,6 +24,10 @@ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITHOUT FUNCTION
[ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITH INOUT
[ AS ASSIGNMENT | AS IMPLICIT ]
</synopsis>
</refsynopsisdiv>
......@@ -58,6 +62,13 @@ SELECT CAST(42 AS float8);
binary compatible.)
</para>
<para>
You can define a cast as an <firstterm>I/O conversion cast</> using
the <literal>WITH INOUT</literal> syntax. An I/O conversion cast is
performed by invoking the output function of the source data type, and
passing the result to the input function of the target data type.
</para>
<para>
By default, a cast can be invoked only by an explicit cast request,
that is an explicit <literal>CAST(<replaceable>x</> AS
......@@ -199,6 +210,18 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
</listitem>
</varlistentry>
<varlistentry>
<term><literal>WITH INOUT</literal></term>
<listitem>
<para>
Indicates that the cast is an I/O conversion cast, performed by
invoking the output function of the source data type, and passing the
result to the input function of the target data type.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>AS ASSIGNMENT</literal></term>
......@@ -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 (<type>text</>, <type>varchar</>, and
<type>char(<replaceable>n</>)</type>, as well as user-defined types that
are defined to be in the string category). <productname>PostgreSQL</> will
automatically handle a cast to a string type by invoking the other
type's output function, or conversely handle a cast from a string type
by invoking the other type's input function. These
automatically-provided casts are known as <firstterm>I/O conversion
casts</>. I/O conversion casts to string types are treated as
assignment casts, while I/O conversion casts from string types are
are defined to be in the string category). <productname>PostgreSQL</>
provides automatic I/O conversion casts for that. The automatic casts to
string types are treated as assignment casts, while the automatic casts
from string types are
explicit-only. You can override this behavior by declaring your own
cast to replace an I/O conversion cast, but usually the only reason to
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
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.99 2008/10/21 10:38:51 petere Exp $
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.100 2008/10/31 08:39:20 heikki Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
......@@ -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;
......@@ -1475,6 +1484,12 @@ CreateCast(CreateCastStmt *stmt)
ReleaseSysCache(tuple);
}
else
{
funcid = InvalidOid;
nargs = 0;
}
if (castmethod == COERCION_METHOD_BINARY)
{
int16 typ1len;
int16 typ2len;
......@@ -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);
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.409 2008/10/21 20:42:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.410 2008/10/31 08:39:20 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -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;
}
......
......@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.334 2008/10/21 20:42:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.335 2008/10/31 08:39:20 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -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;
}
......
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.632 2008/10/29 11:24:53 petere Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.633 2008/10/31 08:39:20 heikki Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -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;
}
;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.170 2008/10/25 17:19:09 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.171 2008/10/31 08:39:21 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -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);
......
......@@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.502 2008/09/24 19:33:15 heikki Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.503 2008/10/31 08:39:21 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -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')
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.141 2008/09/08 15:26:23 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.142 2008/10/31 08:39:21 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -376,6 +376,7 @@ typedef struct _castInfo
Oid casttarget;
Oid castfunc;
char castcontext;
char castmethod;
} CastInfo;
/* InhInfo isn't a DumpableObject, just temporary state */
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.499 2008/10/17 22:10:30 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.500 2008/10/31 08:39:22 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200810171
#define CATALOG_VERSION_NO 200810311
#endif
This diff is collapsed.
......@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.376 2008/10/04 21:56:55 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.377 2008/10/31 08:39:22 heikki Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -2062,6 +2062,7 @@ typedef struct CreateCastStmt
TypeName *targettype;
FuncWithArgs *func;
CoercionContext context;
bool inout;
} CreateCastStmt;
/* ----------------------
......
......@@ -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 ****************
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment