Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 092bc49

Browse files
committed
Add support for user-defined I/O conversion casts.
1 parent 34e37d5 commit 092bc49

File tree

14 files changed

+396
-269
lines changed

14 files changed

+396
-269
lines changed

doc/src/sgml/catalogs.sgml

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.179 2008/10/17 22:10:29 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.180 2008/10/31 08:39:19 heikki Exp $ -->
22
<!--
33
Documentation of the system catalogs, directed toward PostgreSQL developers
44
-->
@@ -1415,9 +1415,10 @@
14151415
cannot be deduced from some generic rule. For example, casting between a
14161416
domain and its base type is not explicitly represented in
14171417
<structname>pg_cast</structname>. Another important exception is that
1418-
<quote>I/O conversion casts</>, those performed using a data type's own
1419-
I/O functions to convert to or from <type>text</> or other string types,
1420-
are not explicitly represented in <structname>pg_cast</structname>.
1418+
<quote>automatic I/O conversion casts</>, those performed using a data
1419+
type's own I/O functions to convert to or from <type>text</> or other
1420+
string types, are not explicitly represented in
1421+
<structname>pg_cast</structname>.
14211422
</para>
14221423

14231424
<table>
@@ -1454,8 +1455,7 @@
14541455
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
14551456
<entry>
14561457
The OID of the function to use to perform this cast. Zero is
1457-
stored if the data types are binary coercible (that is, no
1458-
run-time operation is needed to perform the cast)
1458+
stored if the cast method doesn't require a function.
14591459
</entry>
14601460
</row>
14611461

@@ -1473,6 +1473,17 @@
14731473
other cases
14741474
</entry>
14751475
</row>
1476+
<row>
1477+
<entry><structfield>castmethod</structfield></entry>
1478+
<entry><type>char</type></entry>
1479+
<entry></entry>
1480+
<entry>
1481+
Indicates how the cast is performed.
1482+
<literal>f</> means that the function specified in the <structfield>castfunc</> field is used.
1483+
<literal>i</> means that the input/output functions are used.
1484+
<literal>b</> means that the types are binary-coercible, thus no conversion is required
1485+
</entry>
1486+
</row>
14761487
</tbody>
14771488
</tgroup>
14781489
</table>

doc/src/sgml/ref/create_cast.sgml

+29-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.29 2008/07/30 21:23:17 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.30 2008/10/31 08:39:20 heikki Exp $ -->
22

33
<refentry id="SQL-CREATECAST">
44
<refmeta>
@@ -24,6 +24,10 @@ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r
2424
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
2525
WITHOUT FUNCTION
2626
[ AS ASSIGNMENT | AS IMPLICIT ]
27+
28+
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
29+
WITH INOUT
30+
[ AS ASSIGNMENT | AS IMPLICIT ]
2731
</synopsis>
2832
</refsynopsisdiv>
2933

@@ -58,6 +62,13 @@ SELECT CAST(42 AS float8);
5862
binary compatible.)
5963
</para>
6064

65+
<para>
66+
You can define a cast as an <firstterm>I/O conversion cast</> using
67+
the <literal>WITH INOUT</literal> syntax. An I/O conversion cast is
68+
performed by invoking the output function of the source data type, and
69+
passing the result to the input function of the target data type.
70+
</para>
71+
6172
<para>
6273
By default, a cast can be invoked only by an explicit cast request,
6374
that is an explicit <literal>CAST(<replaceable>x</> AS
@@ -199,6 +210,18 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
199210
</listitem>
200211
</varlistentry>
201212

213+
<varlistentry>
214+
<term><literal>WITH INOUT</literal></term>
215+
216+
<listitem>
217+
<para>
218+
Indicates that the cast is an I/O conversion cast, performed by
219+
invoking the output function of the source data type, and passing the
220+
result to the input function of the target data type.
221+
</para>
222+
</listitem>
223+
</varlistentry>
224+
202225
<varlistentry>
203226
<term><literal>AS ASSIGNMENT</literal></term>
204227

@@ -284,15 +307,12 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
284307
It is normally not necessary to create casts between user-defined types
285308
and the standard string types (<type>text</>, <type>varchar</>, and
286309
<type>char(<replaceable>n</>)</type>, as well as user-defined types that
287-
are defined to be in the string category). <productname>PostgreSQL</> will
288-
automatically handle a cast to a string type by invoking the other
289-
type's output function, or conversely handle a cast from a string type
290-
by invoking the other type's input function. These
291-
automatically-provided casts are known as <firstterm>I/O conversion
292-
casts</>. I/O conversion casts to string types are treated as
293-
assignment casts, while I/O conversion casts from string types are
310+
are defined to be in the string category). <productname>PostgreSQL</>
311+
provides automatic I/O conversion casts for that. The automatic casts to
312+
string types are treated as assignment casts, while the automatic casts
313+
from string types are
294314
explicit-only. You can override this behavior by declaring your own
295-
cast to replace an I/O conversion cast, but usually the only reason to
315+
cast to replace an automatic cast, but usually the only reason to
296316
do so is if you want the conversion to be more easily invokable than the
297317
standard assignment-only or explicit-only setting. Another possible
298318
reason is that you want the conversion to behave differently from the

src/backend/commands/functioncmds.c

+17-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.99 2008/10/21 10:38:51 petere Exp $
13+
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.100 2008/10/31 08:39:20 heikki Exp $
1414
*
1515
* DESCRIPTION
1616
* These routines take the parse tree and pick out the
@@ -1383,6 +1383,7 @@ CreateCast(CreateCastStmt *stmt)
13831383
Oid funcid;
13841384
int nargs;
13851385
char castcontext;
1386+
char castmethod;
13861387
Relation relation;
13871388
HeapTuple tuple;
13881389
Datum values[Natts_pg_cast];
@@ -1415,7 +1416,15 @@ CreateCast(CreateCastStmt *stmt)
14151416
format_type_be(sourcetypeid),
14161417
format_type_be(targettypeid))));
14171418

1419+
/* Detemine the cast method */
14181420
if (stmt->func != NULL)
1421+
castmethod = COERCION_METHOD_FUNCTION;
1422+
else if(stmt->inout)
1423+
castmethod = COERCION_METHOD_INOUT;
1424+
else
1425+
castmethod = COERCION_METHOD_BINARY;
1426+
1427+
if (castmethod == COERCION_METHOD_FUNCTION)
14191428
{
14201429
Form_pg_proc procstruct;
14211430

@@ -1475,6 +1484,12 @@ CreateCast(CreateCastStmt *stmt)
14751484
ReleaseSysCache(tuple);
14761485
}
14771486
else
1487+
{
1488+
funcid = InvalidOid;
1489+
nargs = 0;
1490+
}
1491+
1492+
if (castmethod == COERCION_METHOD_BINARY)
14781493
{
14791494
int16 typ1len;
14801495
int16 typ2len;
@@ -1483,10 +1498,6 @@ CreateCast(CreateCastStmt *stmt)
14831498
char typ1align;
14841499
char typ2align;
14851500

1486-
/* indicates binary coercibility */
1487-
funcid = InvalidOid;
1488-
nargs = 0;
1489-
14901501
/*
14911502
* Must be superuser to create binary-compatible casts, since
14921503
* erroneous casts can easily crash the backend.
@@ -1562,6 +1573,7 @@ CreateCast(CreateCastStmt *stmt)
15621573
values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
15631574
values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
15641575
values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
1576+
values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);
15651577

15661578
MemSet(nulls, ' ', Natts_pg_cast);
15671579

src/backend/nodes/copyfuncs.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.409 2008/10/21 20:42:52 tgl Exp $
18+
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.410 2008/10/31 08:39:20 heikki Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -3042,6 +3042,7 @@ _copyCreateCastStmt(CreateCastStmt *from)
30423042
COPY_NODE_FIELD(targettype);
30433043
COPY_NODE_FIELD(func);
30443044
COPY_SCALAR_FIELD(context);
3045+
COPY_SCALAR_FIELD(inout);
30453046

30463047
return newnode;
30473048
}

src/backend/nodes/equalfuncs.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* Portions Copyright (c) 1994, Regents of the University of California
2323
*
2424
* IDENTIFICATION
25-
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.334 2008/10/21 20:42:52 tgl Exp $
25+
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.335 2008/10/31 08:39:20 heikki Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -1666,6 +1666,7 @@ _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
16661666
COMPARE_NODE_FIELD(targettype);
16671667
COMPARE_NODE_FIELD(func);
16681668
COMPARE_SCALAR_FIELD(context);
1669+
COMPARE_SCALAR_FIELD(inout);
16691670

16701671
return true;
16711672
}

src/backend/parser/gram.y

+14-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.632 2008/10/29 11:24:53 petere Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.633 2008/10/31 08:39:20 heikki Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -4590,6 +4590,7 @@ CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
45904590
n->targettype = $6;
45914591
n->func = $10;
45924592
n->context = (CoercionContext) $11;
4593+
n->inout = false;
45934594
$$ = (Node *)n;
45944595
}
45954596
| CREATE CAST '(' Typename AS Typename ')'
@@ -4600,6 +4601,18 @@ CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
46004601
n->targettype = $6;
46014602
n->func = NULL;
46024603
n->context = (CoercionContext) $10;
4604+
n->inout = false;
4605+
$$ = (Node *)n;
4606+
}
4607+
| CREATE CAST '(' Typename AS Typename ')'
4608+
WITH INOUT cast_context
4609+
{
4610+
CreateCastStmt *n = makeNode(CreateCastStmt);
4611+
n->sourcetype = $4;
4612+
n->targettype = $6;
4613+
n->func = NULL;
4614+
n->context = (CoercionContext) $10;
4615+
n->inout = true;
46034616
$$ = (Node *)n;
46044617
}
46054618
;

src/backend/parser/parse_coerce.c

+18-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.170 2008/10/25 17:19:09 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.171 2008/10/31 08:39:21 heikki Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1909,11 +1909,23 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
19091909
/* Rely on ordering of enum for correct behavior here */
19101910
if (ccontext >= castcontext)
19111911
{
1912-
*funcid = castForm->castfunc;
1913-
if (OidIsValid(*funcid))
1914-
result = COERCION_PATH_FUNC;
1915-
else
1916-
result = COERCION_PATH_RELABELTYPE;
1912+
switch (castForm->castmethod)
1913+
{
1914+
case COERCION_METHOD_FUNCTION:
1915+
result = COERCION_PATH_FUNC;
1916+
*funcid = castForm->castfunc;
1917+
break;
1918+
case COERCION_METHOD_INOUT:
1919+
result = COERCION_PATH_COERCEVIAIO;
1920+
break;
1921+
case COERCION_METHOD_BINARY:
1922+
result = COERCION_PATH_RELABELTYPE;
1923+
break;
1924+
default:
1925+
elog(ERROR, "unrecognized castmethod: %d",
1926+
(int) castForm->castmethod);
1927+
break;
1928+
}
19171929
}
19181930

19191931
ReleaseSysCache(tuple);

src/bin/pg_dump/pg_dump.c

+36-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* by PostgreSQL
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.502 2008/09/24 19:33:15 heikki Exp $
15+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.503 2008/10/31 08:39:21 heikki Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -36,6 +36,7 @@ int optreset;
3636

3737
#include "access/attnum.h"
3838
#include "access/sysattr.h"
39+
#include "catalog/pg_cast.h"
3940
#include "catalog/pg_class.h"
4041
#include "catalog/pg_proc.h"
4142
#include "catalog/pg_trigger.h"
@@ -4410,21 +4411,31 @@ getCasts(int *numCasts)
44104411
int i_casttarget;
44114412
int i_castfunc;
44124413
int i_castcontext;
4414+
int i_castmethod;
44134415

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

4417-
if (g_fout->remoteVersion >= 70300)
4419+
if (g_fout->remoteVersion >= 80400)
4420+
{
4421+
appendPQExpBuffer(query, "SELECT tableoid, oid, "
4422+
"castsource, casttarget, castfunc, castcontext, "
4423+
"castmethod "
4424+
"FROM pg_cast ORDER BY 3,4");
4425+
}
4426+
else if (g_fout->remoteVersion >= 70300)
44184427
{
44194428
appendPQExpBuffer(query, "SELECT tableoid, oid, "
4420-
"castsource, casttarget, castfunc, castcontext "
4429+
"castsource, casttarget, castfunc, castcontext, "
4430+
"CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
44214431
"FROM pg_cast ORDER BY 3,4");
44224432
}
44234433
else
44244434
{
44254435
appendPQExpBuffer(query, "SELECT 0 as tableoid, p.oid, "
44264436
"t1.oid as castsource, t2.oid as casttarget, "
4427-
"p.oid as castfunc, 'e' as castcontext "
4437+
"p.oid as castfunc, 'e' as castcontext, "
4438+
"'f' as castmethod "
44284439
"FROM pg_type t1, pg_type t2, pg_proc p "
44294440
"WHERE p.pronargs = 1 AND "
44304441
"p.proargtypes[0] = t1.oid AND "
@@ -4447,6 +4458,7 @@ getCasts(int *numCasts)
44474458
i_casttarget = PQfnumber(res, "casttarget");
44484459
i_castfunc = PQfnumber(res, "castfunc");
44494460
i_castcontext = PQfnumber(res, "castcontext");
4461+
i_castmethod = PQfnumber(res, "castmethod");
44504462

44514463
for (i = 0; i < ntups; i++)
44524464
{
@@ -4462,6 +4474,7 @@ getCasts(int *numCasts)
44624474
castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
44634475
castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
44644476
castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
4477+
castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
44654478

44664479
/*
44674480
* Try to name cast as concatenation of typnames. This is only used
@@ -7188,18 +7201,26 @@ dumpCast(Archive *fout, CastInfo *cast)
71887201
getFormattedTypeName(cast->castsource, zeroAsNone),
71897202
getFormattedTypeName(cast->casttarget, zeroAsNone));
71907203

7191-
if (!OidIsValid(cast->castfunc))
7192-
appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7193-
else
7204+
switch(cast->castmethod)
71947205
{
7195-
/*
7196-
* Always qualify the function name, in case it is not in pg_catalog
7197-
* schema (format_function_signature won't qualify it).
7198-
*/
7199-
appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7200-
fmtId(funcInfo->dobj.namespace->dobj.name));
7201-
appendPQExpBuffer(defqry, "%s",
7202-
format_function_signature(funcInfo, true));
7206+
case COERCION_METHOD_BINARY:
7207+
appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7208+
break;
7209+
case COERCION_METHOD_INOUT:
7210+
appendPQExpBuffer(defqry, "WITH INOUT");
7211+
break;
7212+
case COERCION_METHOD_FUNCTION:
7213+
/*
7214+
* Always qualify the function name, in case it is not in
7215+
* pg_catalog schema (format_function_signature won't qualify it).
7216+
*/
7217+
appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7218+
fmtId(funcInfo->dobj.namespace->dobj.name));
7219+
appendPQExpBuffer(defqry, "%s",
7220+
format_function_signature(funcInfo, true));
7221+
break;
7222+
default:
7223+
write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
72037224
}
72047225

72057226
if (cast->castcontext == 'a')

0 commit comments

Comments
 (0)