Commit 31edbadf authored by Tom Lane's avatar Tom Lane

Downgrade implicit casts to text to be assignment-only, except for the ones

from the other string-category types; this eliminates a lot of surprising
interpretations that the parser could formerly make when there was no directly
applicable operator.

Create a general mechanism that supports casts to and from the standard string
types (text,varchar,bpchar) for *every* datatype, by invoking the datatype's
I/O functions.  These new casts are assignment-only in the to-string direction,
explicit-only in the other, and therefore should create no surprising behavior.
Remove a bunch of thereby-obsoleted datatype-specific casting functions.

The "general mechanism" is a new expression node type CoerceViaIO that can
actually convert between *any* two datatypes if their external text
representations are compatible.  This is more general than needed for the
immediate feature, but might be useful in plpgsql or other places in future.

This commit does nothing about the issue that applying the concatenation
operator || to non-text types will now fail, often with strange error messages
due to misinterpreting the operator as array concatenation.  Since it often
(not always) worked before, we should either make it succeed or at least give
a more user-friendly error; but details are still under debate.

Peter Eisentraut and Tom Lane
parent 1120b994
...@@ -236,10 +236,6 @@ cube_distance(cube, cube) returns double ...@@ -236,10 +236,6 @@ cube_distance(cube, cube) returns double
cube_distance returns the distance between two cubes. If both cubes are cube_distance returns the distance between two cubes. If both cubes are
points, this is the normal distance function. points, this is the normal distance function.
cube(text) returns cube
cube takes text input and returns a cube. This is useful for making cubes
from computed strings.
cube(float8) returns cube cube(float8) returns cube
This makes a one dimensional cube with both coordinates the same. This makes a one dimensional cube with both coordinates the same.
If the type of the argument is a numeric type other than float8 an If the type of the argument is a numeric type other than float8 an
......
/****************************************************************************** /******************************************************************************
$PostgreSQL: pgsql/contrib/cube/cube.c,v 1.32 2007/03/07 21:21:11 teodor Exp $ $PostgreSQL: pgsql/contrib/cube/cube.c,v 1.33 2007/06/05 21:31:03 tgl Exp $
This file contains routines that can be bound to a Postgres backend and This file contains routines that can be bound to a Postgres backend and
called by the backend in the process of processing queries. The calling called by the backend in the process of processing queries. The calling
...@@ -173,18 +173,6 @@ cube_in(PG_FUNCTION_ARGS) ...@@ -173,18 +173,6 @@ cube_in(PG_FUNCTION_ARGS)
PG_RETURN_NDBOX(result); PG_RETURN_NDBOX(result);
} }
/* Allow conversion from text to cube to allow input of computed strings */
/* There may be issues with toasted data here. I don't know enough to be sure.*/
Datum
cube(PG_FUNCTION_ARGS)
{
char *cstring;
cstring = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
PG_RETURN_DATUM(DirectFunctionCall1(cube_in, PointerGetDatum(cstring)));
}
/* /*
** Allows the construction of a cube from 2 float[]'s ** Allows the construction of a cube from 2 float[]'s
......
...@@ -31,16 +31,6 @@ CREATE TYPE cube ( ...@@ -31,16 +31,6 @@ CREATE TYPE cube (
COMMENT ON TYPE cube IS 'multi-dimensional cube ''(FLOAT-1, FLOAT-2, ..., FLOAT-N), (FLOAT-1, FLOAT-2, ..., FLOAT-N)'''; COMMENT ON TYPE cube IS 'multi-dimensional cube ''(FLOAT-1, FLOAT-2, ..., FLOAT-N), (FLOAT-1, FLOAT-2, ..., FLOAT-N)''';
-- Convert from text to cube
CREATE OR REPLACE FUNCTION cube(text) RETURNS cube
AS 'MODULE_PATHNAME'
LANGUAGE C IMMUTABLE STRICT;
COMMENT ON FUNCTION cube(text) IS 'convert text to cube';
CREATE CAST (text AS cube) WITH FUNCTION cube(text) AS ASSIGNMENT;
-- --
-- External C-functions for R-tree methods -- External C-functions for R-tree methods
-- --
......
...@@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); ...@@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
-- Test of cube function (text to cube) -- Test of cube function (text to cube)
-- --
SELECT cube('('||1||','||1.2||')'); SELECT cube('(1,1.2)'::text);
cube cube
---------- ----------
(1, 1.2) (1, 1.2)
......
...@@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); ...@@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
-- Test of cube function (text to cube) -- Test of cube function (text to cube)
-- --
SELECT cube('('||1||','||1.2||')'); SELECT cube('(1,1.2)'::text);
cube cube
---------- ----------
(1, 1.2) (1, 1.2)
......
...@@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); ...@@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
-- Test of cube function (text to cube) -- Test of cube function (text to cube)
-- --
SELECT cube('('||1||','||1.2||')'); SELECT cube('(1,1.2)'::text);
cube cube
---------- ----------
(1, 1.2) (1, 1.2)
......
...@@ -223,7 +223,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); ...@@ -223,7 +223,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
-- Test of cube function (text to cube) -- Test of cube function (text to cube)
-- --
SELECT cube('('||1||','||1.2||')'); SELECT cube('(1,1.2)'::text);
SELECT cube(NULL); SELECT cube(NULL);
-- Test of cube_dim function (dimensions stored in cube) -- Test of cube_dim function (dimensions stored in cube)
......
...@@ -92,8 +92,4 @@ DROP FUNCTION cube_ne(cube, cube); ...@@ -92,8 +92,4 @@ DROP FUNCTION cube_ne(cube, cube);
DROP FUNCTION cube_eq(cube, cube); DROP FUNCTION cube_eq(cube, cube);
DROP CAST (text AS cube);
DROP FUNCTION cube(text);
DROP TYPE cube CASCADE; DROP TYPE cube CASCADE;
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.5 2007/01/05 22:19:18 momjian Exp $ * $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.6 2007/06/05 21:31:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,10 +39,6 @@ static const char *isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", " ...@@ -39,10 +39,6 @@ static const char *isn_names[] = {"EAN13/UPC/ISxN", "EAN13/UPC/ISxN", "EAN13", "
static bool g_weak = false; static bool g_weak = false;
static bool g_initialized = false; static bool g_initialized = false;
/* Macros for converting TEXT to and from c-string */
#define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
/*********************************************************************** /***********************************************************************
** **
...@@ -1042,30 +1038,6 @@ upc_in(PG_FUNCTION_ARGS) ...@@ -1042,30 +1038,6 @@ upc_in(PG_FUNCTION_ARGS)
/* casting functions /* casting functions
*/ */
PG_FUNCTION_INFO_V1(ean13_cast_to_text);
Datum
ean13_cast_to_text(PG_FUNCTION_ARGS)
{
ean13 val = PG_GETARG_EAN13(0);
char buf[MAXEAN13LEN + 1];
(void) ean2string(val, false, buf, false);
PG_RETURN_TEXT_P(GET_TEXT(buf));
}
PG_FUNCTION_INFO_V1(isn_cast_to_text);
Datum
isn_cast_to_text(PG_FUNCTION_ARGS)
{
ean13 val = PG_GETARG_EAN13(0);
char buf[MAXEAN13LEN + 1];
(void) ean2string(val, false, buf, true);
PG_RETURN_TEXT_P(GET_TEXT(buf));
}
PG_FUNCTION_INFO_V1(isbn_cast_from_ean13); PG_FUNCTION_INFO_V1(isbn_cast_from_ean13);
Datum Datum
isbn_cast_from_ean13(PG_FUNCTION_ARGS) isbn_cast_from_ean13(PG_FUNCTION_ARGS)
...@@ -1115,61 +1087,6 @@ upc_cast_from_ean13(PG_FUNCTION_ARGS) ...@@ -1115,61 +1087,6 @@ upc_cast_from_ean13(PG_FUNCTION_ARGS)
} }
PG_FUNCTION_INFO_V1(ean13_cast_from_text);
Datum
ean13_cast_from_text(PG_FUNCTION_ARGS)
{
const char *str = GET_STR(PG_GETARG_TEXT_P(0));
ean13 result;
(void) string2ean(str, false, &result, EAN13);
PG_RETURN_EAN13(result);
}
PG_FUNCTION_INFO_V1(isbn_cast_from_text);
Datum
isbn_cast_from_text(PG_FUNCTION_ARGS)
{
const char *str = GET_STR(PG_GETARG_TEXT_P(0));
ean13 result;
(void) string2ean(str, false, &result, ISBN);
PG_RETURN_EAN13(result);
}
PG_FUNCTION_INFO_V1(ismn_cast_from_text);
Datum
ismn_cast_from_text(PG_FUNCTION_ARGS)
{
const char *str = GET_STR(PG_GETARG_TEXT_P(0));
ean13 result;
(void) string2ean(str, false, &result, ISMN);
PG_RETURN_EAN13(result);
}
PG_FUNCTION_INFO_V1(issn_cast_from_text);
Datum
issn_cast_from_text(PG_FUNCTION_ARGS)
{
const char *str = GET_STR(PG_GETARG_TEXT_P(0));
ean13 result;
(void) string2ean(str, false, &result, ISSN);
PG_RETURN_EAN13(result);
}
PG_FUNCTION_INFO_V1(upc_cast_from_text);
Datum
upc_cast_from_text(PG_FUNCTION_ARGS)
{
const char *str = GET_STR(PG_GETARG_TEXT_P(0));
ean13 result;
(void) string2ean(str, false, &result, UPC);
PG_RETURN_EAN13(result);
}
/* is_valid - returns false if the "invalid-check-digit-on-input" is set /* is_valid - returns false if the "invalid-check-digit-on-input" is set
*/ */
PG_FUNCTION_INFO_V1(is_valid); PG_FUNCTION_INFO_V1(is_valid);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/contrib/isn/isn.h,v 1.3 2007/01/05 22:19:18 momjian Exp $ * $PostgreSQL: pgsql/contrib/isn/isn.h,v 1.4 2007/06/05 21:31:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -38,13 +38,6 @@ extern Datum ismn_in(PG_FUNCTION_ARGS); ...@@ -38,13 +38,6 @@ extern Datum ismn_in(PG_FUNCTION_ARGS);
extern Datum issn_in(PG_FUNCTION_ARGS); extern Datum issn_in(PG_FUNCTION_ARGS);
extern Datum upc_in(PG_FUNCTION_ARGS); extern Datum upc_in(PG_FUNCTION_ARGS);
extern Datum ean13_cast_to_text(PG_FUNCTION_ARGS);
extern Datum isn_cast_to_text(PG_FUNCTION_ARGS);
extern Datum ean13_cast_from_text(PG_FUNCTION_ARGS);
extern Datum isbn_cast_from_text(PG_FUNCTION_ARGS);
extern Datum ismn_cast_from_text(PG_FUNCTION_ARGS);
extern Datum issn_cast_from_text(PG_FUNCTION_ARGS);
extern Datum upc_cast_from_text(PG_FUNCTION_ARGS);
extern Datum isbn_cast_from_ean13(PG_FUNCTION_ARGS); extern Datum isbn_cast_from_ean13(PG_FUNCTION_ARGS);
extern Datum ismn_cast_from_ean13(PG_FUNCTION_ARGS); extern Datum ismn_cast_from_ean13(PG_FUNCTION_ARGS);
extern Datum issn_cast_from_ean13(PG_FUNCTION_ARGS); extern Datum issn_cast_from_ean13(PG_FUNCTION_ARGS);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-- PostgreSQL code for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) -- PostgreSQL code for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
-- Copyright (c) 2004-2006, German Mendez Bravo (Kronuz) -- Copyright (c) 2004-2006, German Mendez Bravo (Kronuz)
-- --
-- $PostgreSQL: pgsql/contrib/isn/isn.sql.in,v 1.4 2006/11/24 18:44:37 tgl Exp $ -- $PostgreSQL: pgsql/contrib/isn/isn.sql.in,v 1.5 2007/06/05 21:31:03 tgl Exp $
-- --
-- Example: -- Example:
-- create table test ( id isbn ); -- create table test ( id isbn );
...@@ -2966,73 +2966,6 @@ AS 'MODULE_PATHNAME', 'upc_cast_from_ean13' ...@@ -2966,73 +2966,6 @@ AS 'MODULE_PATHNAME', 'upc_cast_from_ean13'
LANGUAGE 'C' IMMUTABLE STRICT; LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION ean13(text)
RETURNS ean13
AS 'MODULE_PATHNAME', 'ean13_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION isbn13(text)
RETURNS isbn13
AS 'MODULE_PATHNAME', 'isbn_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION ismn13(text)
RETURNS ismn13
AS 'MODULE_PATHNAME', 'ismn_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION issn13(text)
RETURNS issn13
AS 'MODULE_PATHNAME', 'issn_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION isbn(text)
RETURNS isbn
AS 'MODULE_PATHNAME', 'isbn_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION ismn(text)
RETURNS ismn
AS 'MODULE_PATHNAME', 'ismn_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION issn(text)
RETURNS issn
AS 'MODULE_PATHNAME', 'issn_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION upc(text)
RETURNS upc
AS 'MODULE_PATHNAME', 'upc_cast_from_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(ean13)
RETURNS text
AS 'MODULE_PATHNAME', 'ean13_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(isbn13)
RETURNS text
AS 'MODULE_PATHNAME', 'ean13_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(ismn13)
RETURNS text
AS 'MODULE_PATHNAME', 'ean13_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(issn13)
RETURNS text
AS 'MODULE_PATHNAME', 'ean13_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(isbn)
RETURNS text
AS 'MODULE_PATHNAME', 'isn_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(ismn)
RETURNS text
AS 'MODULE_PATHNAME', 'isn_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(issn)
RETURNS text
AS 'MODULE_PATHNAME', 'isn_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE FUNCTION text(upc)
RETURNS text
AS 'MODULE_PATHNAME', 'isn_cast_to_text'
LANGUAGE 'C' IMMUTABLE STRICT;
CREATE CAST (ean13 AS isbn13) WITH FUNCTION isbn13(ean13); CREATE CAST (ean13 AS isbn13) WITH FUNCTION isbn13(ean13);
CREATE CAST (ean13 AS isbn) WITH FUNCTION isbn(ean13); CREATE CAST (ean13 AS isbn) WITH FUNCTION isbn(ean13);
CREATE CAST (ean13 AS ismn13) WITH FUNCTION ismn13(ean13); CREATE CAST (ean13 AS ismn13) WITH FUNCTION ismn13(ean13);
...@@ -3056,24 +2989,6 @@ CREATE CAST (ismn13 AS ismn) WITHOUT FUNCTION AS ASSIGNMENT; ...@@ -3056,24 +2989,6 @@ CREATE CAST (ismn13 AS ismn) WITHOUT FUNCTION AS ASSIGNMENT;
CREATE CAST (issn AS issn13) WITHOUT FUNCTION AS ASSIGNMENT; CREATE CAST (issn AS issn13) WITHOUT FUNCTION AS ASSIGNMENT;
CREATE CAST (issn13 AS issn) WITHOUT FUNCTION AS ASSIGNMENT; CREATE CAST (issn13 AS issn) WITHOUT FUNCTION AS ASSIGNMENT;
CREATE CAST (text AS ean13) WITH FUNCTION ean13(text);
CREATE CAST (text AS isbn13) WITH FUNCTION isbn13(text);
CREATE CAST (text AS ismn13) WITH FUNCTION ismn13(text);
CREATE CAST (text AS issn13) WITH FUNCTION issn13(text);
CREATE CAST (text AS isbn) WITH FUNCTION isbn(text);
CREATE CAST (text AS ismn) WITH FUNCTION ismn(text);
CREATE CAST (text AS issn) WITH FUNCTION issn(text);
CREATE CAST (text AS upc) WITH FUNCTION upc(text);
CREATE CAST (ean13 AS text) WITH FUNCTION text(ean13);
CREATE CAST (isbn13 AS text) WITH FUNCTION text(isbn13);
CREATE CAST (ismn13 AS text) WITH FUNCTION text(ismn13);
CREATE CAST (issn13 AS text) WITH FUNCTION text(issn13);
CREATE CAST (isbn AS text) WITH FUNCTION text(isbn);
CREATE CAST (ismn AS text) WITH FUNCTION text(ismn);
CREATE CAST (issn AS text) WITH FUNCTION text(issn);
CREATE CAST (upc AS text) WITH FUNCTION text(upc);
-- --
-- Validation stuff for lose types: -- Validation stuff for lose types:
-- --
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.152 2007/05/15 19:13:54 neilc Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.153 2007/06/05 21:31:03 tgl Exp $ -->
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
...@@ -1358,11 +1358,22 @@ ...@@ -1358,11 +1358,22 @@
</indexterm> </indexterm>
<para> <para>
The catalog <structname>pg_cast</structname> stores data type conversion paths, The catalog <structname>pg_cast</structname> stores data type conversion
both built-in paths and those defined with paths, both built-in paths and those defined with
<xref linkend="sql-createcast" endterm="sql-createcast-title">. <xref linkend="sql-createcast" endterm="sql-createcast-title">.
</para> </para>
<para>
It should be noted that <structname>pg_cast</structname> does not represent
every type conversion that the system knows how to perform; only those that
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>.
</para>
<table> <table>
<title><structfield>pg_cast</> Columns</title> <title><structfield>pg_cast</> Columns</title>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.25 2007/02/01 00:28:18 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.26 2007/06/05 21:31:04 tgl Exp $ -->
<refentry id="SQL-CREATECAST"> <refentry id="SQL-CREATECAST">
<refmeta> <refmeta>
...@@ -35,11 +35,11 @@ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r ...@@ -35,11 +35,11 @@ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r
specifies how to perform a conversion between specifies how to perform a conversion between
two data types. For example: two data types. For example:
<programlisting> <programlisting>
SELECT CAST(42 AS text); SELECT CAST(42 AS float8);
</programlisting> </programlisting>
converts the integer constant 42 to type <type>text</type> by converts the integer constant 42 to type <type>float8</type> by
invoking a previously specified function, in this case invoking a previously specified function, in this case
<literal>text(int4)</>. (If no suitable cast has been defined, the <literal>float8(int4)</>. (If no suitable cast has been defined, the
conversion fails.) conversion fails.)
</para> </para>
...@@ -69,8 +69,7 @@ SELECT CAST(42 AS text); ...@@ -69,8 +69,7 @@ SELECT CAST(42 AS text);
INSERT INTO foo (f1) VALUES (42); INSERT INTO foo (f1) VALUES (42);
</programlisting> </programlisting>
will be allowed if the cast from type <type>integer</type> to type will be allowed if the cast from type <type>integer</type> to type
<type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise <type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise not.
not.
(We generally use the term <firstterm>assignment (We generally use the term <firstterm>assignment
cast</firstterm> to describe this kind of cast.) cast</firstterm> to describe this kind of cast.)
</para> </para>
...@@ -78,19 +77,37 @@ INSERT INTO foo (f1) VALUES (42); ...@@ -78,19 +77,37 @@ INSERT INTO foo (f1) VALUES (42);
<para> <para>
If the cast is marked <literal>AS IMPLICIT</> then it can be invoked If the cast is marked <literal>AS IMPLICIT</> then it can be invoked
implicitly in any context, whether assignment or internally in an implicitly in any context, whether assignment or internally in an
expression. For example, since <literal>||</> takes <type>text</> expression. (We generally use the term <firstterm>implicit
operands, cast</firstterm> to describe this kind of cast.)
For example, consider this query:
<programlisting> <programlisting>
SELECT 'The time is ' || now(); SELECT 2 + 4.0;
</programlisting> </programlisting>
will be allowed only if the cast from type <type>timestamp</> to The parser initially marks the constants as being of type <type>integer</>
<type>text</type> is marked <literal>AS IMPLICIT</>. Otherwise it and <type>numeric</> respectively. There is no <type>integer</>
will be necessary to write the cast explicitly, for example: <literal>+</> <type>numeric</> operator in the system catalogs,
but there is a <type>numeric</> <literal>+</> <type>numeric</> operator.
The query will therefore succeed if a cast from <type>integer</> to
<type>numeric</> is available and is marked <literal>AS IMPLICIT</> &mdash;
which in fact it is. The parser will apply the implicit cast and resolve
the query as if it had been written
<programlisting> <programlisting>
SELECT 'The time is ' || CAST(now() AS text); SELECT CAST ( 2 AS numeric ) + 4.0;
</programlisting> </programlisting>
(We generally use the term <firstterm>implicit </para>
cast</firstterm> to describe this kind of cast.)
<para>
Now, the catalogs also provide a cast from <type>numeric</> to
<type>integer</>. If that cast were marked <literal>AS IMPLICIT</> &mdash;
which it is not &mdash; then the parser would be faced with choosing
between the above interpretation and the alternative of casting the
<type>numeric</> constant to <type>integer</> and applying the
<type>integer</> <literal>+</> <type>integer</> operator. Lacking any
knowledge of which choice to prefer, it would give up and declare the
query ambiguous. The fact that only one of the two casts is
implicit is the way in which we teach the parser to prefer resolution
of a mixed <type>numeric</>-and-<type>integer</> expression as
<type>numeric</>; there is no built-in knowledge about that.
</para> </para>
<para> <para>
...@@ -208,9 +225,7 @@ SELECT 'The time is ' || CAST(now() AS text); ...@@ -208,9 +225,7 @@ SELECT 'The time is ' || CAST(now() AS text);
argument. This is used to represent type-specific length coercion argument. This is used to represent type-specific length coercion
functions in the system catalogs. The named function is used to functions in the system catalogs. The named function is used to
coerce a value of the type to the type modifier value given by its coerce a value of the type to the type modifier value given by its
second argument. (Since the grammar presently permits only certain second argument.
built-in data types to have type modifiers, this feature is of no
use for user-defined target types, but we mention it for completeness.)
</para> </para>
<para> <para>
...@@ -237,6 +252,32 @@ SELECT 'The time is ' || CAST(now() AS text); ...@@ -237,6 +252,32 @@ SELECT 'The time is ' || CAST(now() AS text);
need to declare casts both ways explicitly. need to declare casts both ways explicitly.
</para> </para>
<indexterm zone="sql-createcast">
<primary>cast</primary>
<secondary>I/O conversion</secondary>
</indexterm>
<para>
It is normally not necessary to create casts between user-defined types
and the standard string types (<type>text</>, <type>varchar</>, and
<type>char(<replaceable>n</>)</type>). <productname>PostgreSQL</> will
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
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
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
type's I/O function; but that is sufficiently surprising that you
should think twice about whether it's a good idea. (A small number of
the built-in types do indeed have different behaviors for conversions,
mostly because of requirements of the SQL standard.)
</para>
<para> <para>
Prior to <productname>PostgreSQL</> 7.3, every function that had Prior to <productname>PostgreSQL</> 7.3, every function that had
the same name as a data type, returned that data type, and took one the same name as a data type, returned that data type, and took one
...@@ -265,16 +306,20 @@ SELECT 'The time is ' || CAST(now() AS text); ...@@ -265,16 +306,20 @@ SELECT 'The time is ' || CAST(now() AS text);
<note> <note>
<para> <para>
There is one small lie in the preceding paragraph: there is still one Actually the preceding paragraph is an oversimplification: there are
case in which <structname>pg_cast</> will be used to resolve the two cases in which a function-call construct will be treated as a cast
meaning of an apparent function call. If a request without having matched it to an actual function.
function call <replaceable>name</>(<replaceable>x</>) matches no If a function call <replaceable>name</>(<replaceable>x</>) does not
actual function, but <replaceable>name</> is the name of a data type exactly match any existing function, but <replaceable>name</> is the name
and <structname>pg_cast</> shows a binary-compatible cast to this of a data type and <structname>pg_cast</> provides a binary-compatible cast
type from the type of <replaceable>x</>, then the call will be construed to this type from the type of <replaceable>x</>, then the call will be
as an explicit cast. This exception is made so that binary-compatible construed as a binary-compatible cast. This exception is made so that
casts can be invoked using functional syntax, even though they lack binary-compatible casts can be invoked using functional syntax, even
any function. though they lack any function. Likewise, if there is no
<structname>pg_cast</> entry but the cast would be to or from a string
type, the call will be construed as an I/O conversion cast. This
exception allows I/O conversion casts to be invoked using functional
syntax.
</para> </para>
</note> </note>
</refsect1> </refsect1>
...@@ -284,10 +329,10 @@ SELECT 'The time is ' || CAST(now() AS text); ...@@ -284,10 +329,10 @@ SELECT 'The time is ' || CAST(now() AS text);
<title>Examples</title> <title>Examples</title>
<para> <para>
To create a cast from type <type>text</type> to type To create a cast from type <type>bigint</type> to type
<type>int4</type> using the function <literal>int4(text)</literal>: <type>int4</type> using the function <literal>int4(bigint)</literal>:
<programlisting> <programlisting>
CREATE CAST (text AS int4) WITH FUNCTION int4(text); CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint);
</programlisting> </programlisting>
(This cast is already predefined in the system.) (This cast is already predefined in the system.)
</para> </para>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.118 2007/05/11 17:57:11 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.119 2007/06/05 21:31:04 tgl Exp $ -->
<chapter id="sql-syntax"> <chapter id="sql-syntax">
<title>SQL Syntax</title> <title>SQL Syntax</title>
...@@ -561,18 +561,18 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> ) ...@@ -561,18 +561,18 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> )
The <literal>::</literal>, <literal>CAST()</literal>, and The <literal>::</literal>, <literal>CAST()</literal>, and
function-call syntaxes can also be used to specify run-time type function-call syntaxes can also be used to specify run-time type
conversions of arbitrary expressions, as discussed in <xref conversions of arbitrary expressions, as discussed in <xref
linkend="sql-syntax-type-casts">. But the form linkend="sql-syntax-type-casts">. To avoid syntactic ambiguity, the
<literal><replaceable>type</replaceable> '<replaceable>string</replaceable>'</literal> <literal><replaceable>type</> '<replaceable>string</>'</literal>
can only be used to specify the type of a literal constant. syntax can only be used to specify the type of a simple literal constant.
Another restriction on Another restriction on the
<literal><replaceable>type</replaceable> '<replaceable>string</replaceable>'</literal> <literal><replaceable>type</> '<replaceable>string</>'</literal>
is that it does not work for array types; use <literal>::</literal> syntax is that it does not work for array types; use <literal>::</literal>
or <literal>CAST()</literal> to specify the type of an array constant. or <literal>CAST()</literal> to specify the type of an array constant.
</para> </para>
<para> <para>
The <literal>CAST()</> syntax conforms to SQL. The The <literal>CAST()</> syntax conforms to SQL. The
<literal><replaceable>type</replaceable> '<replaceable>string</replaceable>'</literal> <literal><replaceable>type</> '<replaceable>string</>'</literal>
syntax is a generalization of the standard: SQL specifies this syntax only syntax is a generalization of the standard: SQL specifies this syntax only
for a few data types, but <productname>PostgreSQL</productname> allows it for a few data types, but <productname>PostgreSQL</productname> allows it
for all types. The syntax with for all types. The syntax with
...@@ -1431,16 +1431,21 @@ CAST ( <replaceable>expression</replaceable> AS <replaceable>type</replaceable> ...@@ -1431,16 +1431,21 @@ CAST ( <replaceable>expression</replaceable> AS <replaceable>type</replaceable>
double-quoted, because of syntactic conflicts. Therefore, the use of double-quoted, because of syntactic conflicts. Therefore, the use of
the function-like cast syntax leads to inconsistencies and should the function-like cast syntax leads to inconsistencies and should
probably be avoided in new applications. probably be avoided in new applications.
(The function-like syntax is in fact just a function call. When
one of the two standard cast syntaxes is used to do a run-time
conversion, it will internally invoke a registered function to
perform the conversion. By convention, these conversion functions
have the same name as their output type, and thus the <quote>function-like
syntax</> is nothing more than a direct invocation of the underlying
conversion function. Obviously, this is not something that a portable
application should rely on.)
</para> </para>
<note>
<para>
The function-like syntax is in fact just a function call. When
one of the two standard cast syntaxes is used to do a run-time
conversion, it will internally invoke a registered function to
perform the conversion. By convention, these conversion functions
have the same name as their output type, and thus the <quote>function-like
syntax</> is nothing more than a direct invocation of the underlying
conversion function. Obviously, this is not something that a portable
application should rely on. For further details see
<xref linkend="sql-createcast" endterm="sql-createcast-title">.
</para>
</note>
</sect2> </sect2>
<sect2 id="sql-syntax-scalar-subqueries"> <sect2 id="sql-syntax-scalar-subqueries">
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.51 2007/02/01 19:10:24 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/typeconv.sgml,v 1.52 2007/06/05 21:31:04 tgl Exp $ -->
<chapter Id="typeconv"> <chapter Id="typeconv">
<title>Type Conversion</title> <title>Type Conversion</title>
...@@ -139,7 +139,8 @@ and for the <function>GREATEST</> and <function>LEAST</> functions. ...@@ -139,7 +139,8 @@ and for the <function>GREATEST</> and <function>LEAST</> functions.
The system catalogs store information about which conversions, called The system catalogs store information about which conversions, called
<firstterm>casts</firstterm>, between data types are valid, and how to <firstterm>casts</firstterm>, between data types are valid, and how to
perform those conversions. Additional casts can be added by the user perform those conversions. Additional casts can be added by the user
with the <command>CREATE CAST</command> command. (This is usually with the <xref linkend="sql-createcast" endterm="sql-createcast-title">
command. (This is usually
done in conjunction with defining new data types. The set of casts done in conjunction with defining new data types. The set of casts
between the built-in types has been carefully crafted and is best not between the built-in types has been carefully crafted and is best not
altered.) altered.)
...@@ -336,28 +337,28 @@ Some examples follow. ...@@ -336,28 +337,28 @@ Some examples follow.
</para> </para>
<example> <example>
<title>Exponentiation Operator Type Resolution</title> <title>Factorial Operator Type Resolution</title>
<para> <para>
There is only one exponentiation There is only one factorial operator (postfix <literal>!</>)
operator defined in the catalog, and it takes arguments of type defined in the standard catalog, and it takes an argument of type
<type>double precision</type>. <type>bigint</type>.
The scanner assigns an initial type of <type>integer</type> to both arguments The scanner assigns an initial type of <type>integer</type> to the argument
of this query expression: in this query expression:
<screen> <screen>
SELECT 2 ^ 3 AS "exp"; SELECT 40 ! AS "40 factorial";
exp 40 factorial
----- --------------------------------------------------
8 815915283247897734345611269596115894272000000000
(1 row) (1 row)
</screen> </screen>
So the parser does a type conversion on both operands and the query So the parser does a type conversion on the operand and the query
is equivalent to is equivalent to
<screen> <screen>
SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "exp"; SELECT CAST(40 AS bigint) ! AS "40 factorial";
</screen> </screen>
</para> </para>
</example> </example>
...@@ -421,7 +422,7 @@ entries for the prefix operator <literal>@</>, all of which implement ...@@ -421,7 +422,7 @@ entries for the prefix operator <literal>@</>, all of which implement
absolute-value operations for various numeric data types. One of these absolute-value operations for various numeric data types. One of these
entries is for type <type>float8</type>, which is the preferred type in entries is for type <type>float8</type>, which is the preferred type in
the numeric category. Therefore, <productname>PostgreSQL</productname> the numeric category. Therefore, <productname>PostgreSQL</productname>
will use that entry when faced with a non-numeric input: will use that entry when faced with an <type>unknown</> input:
<screen> <screen>
SELECT @ '-4.5' AS "abs"; SELECT @ '-4.5' AS "abs";
abs abs
...@@ -429,9 +430,9 @@ SELECT @ '-4.5' AS "abs"; ...@@ -429,9 +430,9 @@ SELECT @ '-4.5' AS "abs";
4.5 4.5
(1 row) (1 row)
</screen> </screen>
Here the system has performed an implicit conversion from <type>text</type> to <type>float8</type> Here the system has implicitly resolved the unknown-type literal as type
before applying the chosen operator. We can verify that <type>float8</type> and <type>float8</type> before applying the chosen operator. We can verify that
not some other type was used: <type>float8</type> and not some other type was used:
<screen> <screen>
SELECT @ '-4.5e500' AS "abs"; SELECT @ '-4.5e500' AS "abs";
...@@ -447,8 +448,8 @@ try a similar case with <literal>~</>, we get: ...@@ -447,8 +448,8 @@ try a similar case with <literal>~</>, we get:
SELECT ~ '20' AS "negation"; SELECT ~ '20' AS "negation";
ERROR: operator is not unique: ~ "unknown" ERROR: operator is not unique: ~ "unknown"
HINT: Could not choose a best candidate operator. You might need to add explicit HINT: Could not choose a best candidate operator. You might need to add
type casts. explicit type casts.
</screen> </screen>
This happens because the system cannot decide which of the several This happens because the system cannot decide which of the several
possible <literal>~</> operators should be preferred. We can help possible <literal>~</> operators should be preferred. We can help
...@@ -518,12 +519,24 @@ this step.) ...@@ -518,12 +519,24 @@ this step.)
<step performance="required"> <step performance="required">
<para> <para>
If no exact match is found, see whether the function call appears If no exact match is found, see whether the function call appears
to be a trivial type conversion request. This happens if the function call to be a special type conversion request. This happens if the function call
has just one argument and the function name is the same as the (internal) has just one argument and the function name is the same as the (internal)
name of some data type. Furthermore, the function argument must be either name of some data type. Furthermore, the function argument must be either
an unknown-type literal or a type that is binary-compatible with the named an unknown-type literal, or a type that is binary-compatible with the named
data type. When these conditions are met, the function argument is converted data type, or a type that could be converted to the named data type by
to the named data type without any actual function call. applying that type's I/O functions (that is, the conversion is either to or
from one of the standard string types). When these conditions are met,
the function call is treated as a form of <literal>CAST</> specification.
<footnote>
<para>
The reason for this step is to support function-style cast specifications
in cases where there is not an actual cast function. If there is a cast
function, it is conventionally named after its output type, and so there
is no need to have a special case. See
<xref linkend="sql-createcast" endterm="sql-createcast-title">
for additional commentary.
</para>
</footnote>
</para> </para>
</step> </step>
<step performance="required"> <step performance="required">
...@@ -670,30 +683,31 @@ The parser learns from the <structname>pg_cast</> catalog that ...@@ -670,30 +683,31 @@ The parser learns from the <structname>pg_cast</> catalog that
<type>text</type> and <type>varchar</type> <type>text</type> and <type>varchar</type>
are binary-compatible, meaning that one can be passed to a function that are binary-compatible, meaning that one can be passed to a function that
accepts the other without doing any physical conversion. Therefore, no accepts the other without doing any physical conversion. Therefore, no
explicit type conversion call is really inserted in this case. type conversion call is really inserted in this case.
</para> </para>
</note> </note>
</para> </para>
<para> <para>
And, if the function is called with an argument of type <type>integer</type>, the parser will And, if the function is called with an argument of type <type>integer</type>,
try to convert that to <type>text</type>: the parser will try to convert that to <type>text</type>:
<screen> <screen>
SELECT substr(1234, 3); SELECT substr(1234, 3);
ERROR: function substr(integer, integer) does not exist
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
</screen>
This does not work because <type>integer</> does not have an implicit cast
to <type>text</>. An explicit cast will work, however:
<screen>
SELECT substr(CAST (1234 AS text), 3);
substr substr
-------- --------
34 34
(1 row) (1 row)
</screen> </screen>
This actually executes as
<screen>
SELECT substr(CAST (1234 AS text), 3);
</screen>
This automatic transformation can succeed because there is an
implicitly invocable cast from <type>integer</type> to
<type>text</type>.
</para> </para>
</example> </example>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.65 2007/03/27 23:21:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.66 2007/06/05 21:31:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1315,6 +1315,14 @@ find_expr_references_walker(Node *node, ...@@ -1315,6 +1315,14 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_TYPE, relab->resulttype, 0, add_object_address(OCLASS_TYPE, relab->resulttype, 0,
context->addrs); context->addrs);
} }
if (IsA(node, CoerceViaIO))
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
/* since there is no exposed function, need to depend on type */
add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0,
context->addrs);
}
if (IsA(node, ArrayCoerceExpr)) if (IsA(node, ArrayCoerceExpr))
{ {
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.217 2007/04/06 04:21:42 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.218 2007/06/05 21:31:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -145,6 +145,9 @@ static Datum ExecEvalFieldStore(FieldStoreState *fstate, ...@@ -145,6 +145,9 @@ static Datum ExecEvalFieldStore(FieldStoreState *fstate,
static Datum ExecEvalRelabelType(GenericExprState *exprstate, static Datum ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
...@@ -3504,6 +3507,40 @@ ExecEvalRelabelType(GenericExprState *exprstate, ...@@ -3504,6 +3507,40 @@ ExecEvalRelabelType(GenericExprState *exprstate,
return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone); return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
} }
/* ----------------------------------------------------------------
* ExecEvalCoerceViaIO
*
* Evaluate a CoerceViaIO node.
* ----------------------------------------------------------------
*/
static Datum
ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Datum result;
Datum inputval;
char *string;
inputval = ExecEvalExpr(iostate->arg, econtext, isNull, isDone);
if (isDone && *isDone == ExprEndResult)
return inputval; /* nothing to do */
if (*isNull)
string = NULL; /* output functions are not called on nulls */
else
string = OutputFunctionCall(&iostate->outfunc, inputval);
result = InputFunctionCall(&iostate->infunc,
string,
iostate->intypioparam,
-1);
/* The input function cannot change the null/not-null status */
return result;
}
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecEvalArrayCoerceExpr * ExecEvalArrayCoerceExpr
* *
...@@ -3850,6 +3887,26 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -3850,6 +3887,26 @@ ExecInitExpr(Expr *node, PlanState *parent)
state = (ExprState *) gstate; state = (ExprState *) gstate;
} }
break; break;
case T_CoerceViaIO:
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
CoerceViaIOState *iostate = makeNode(CoerceViaIOState);
Oid iofunc;
bool typisvarlena;
iostate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoerceViaIO;
iostate->arg = ExecInitExpr(iocoerce->arg, parent);
/* lookup the result type's input function */
getTypeInputInfo(iocoerce->resulttype, &iofunc,
&iostate->intypioparam);
fmgr_info(iofunc, &iostate->infunc);
/* lookup the input type's output function */
getTypeOutputInfo(exprType((Node *) iocoerce->arg),
&iofunc, &typisvarlena);
fmgr_info(iofunc, &iostate->outfunc);
state = (ExprState *) iostate;
}
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
{ {
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.376 2007/05/22 23:23:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.377 2007/06/05 21:31:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1021,6 +1021,21 @@ _copyRelabelType(RelabelType *from) ...@@ -1021,6 +1021,21 @@ _copyRelabelType(RelabelType *from)
return newnode; return newnode;
} }
/*
* _copyCoerceViaIO
*/
static CoerceViaIO *
_copyCoerceViaIO(CoerceViaIO *from)
{
CoerceViaIO *newnode = makeNode(CoerceViaIO);
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(coerceformat);
return newnode;
}
/* /*
* _copyArrayCoerceExpr * _copyArrayCoerceExpr
*/ */
...@@ -3108,6 +3123,9 @@ copyObject(void *from) ...@@ -3108,6 +3123,9 @@ copyObject(void *from)
case T_RelabelType: case T_RelabelType:
retval = _copyRelabelType(from); retval = _copyRelabelType(from);
break; break;
case T_CoerceViaIO:
retval = _copyCoerceViaIO(from);
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
retval = _copyArrayCoerceExpr(from); retval = _copyArrayCoerceExpr(from);
break; break;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.307 2007/05/22 23:23:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.308 2007/06/05 21:31:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -359,6 +359,24 @@ _equalRelabelType(RelabelType *a, RelabelType *b) ...@@ -359,6 +359,24 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
return true; return true;
} }
static bool
_equalCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b)
{
COMPARE_NODE_FIELD(arg);
COMPARE_SCALAR_FIELD(resulttype);
/*
* Special-case COERCE_DONTCARE, so that planner can build coercion nodes
* that are equal() to both explicit and implicit coercions.
*/
if (a->coerceformat != b->coerceformat &&
a->coerceformat != COERCE_DONTCARE &&
b->coerceformat != COERCE_DONTCARE)
return false;
return true;
}
static bool static bool
_equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b) _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b)
{ {
...@@ -2052,6 +2070,9 @@ equal(void *a, void *b) ...@@ -2052,6 +2070,9 @@ equal(void *a, void *b)
case T_RelabelType: case T_RelabelType:
retval = _equalRelabelType(a, b); retval = _equalRelabelType(a, b);
break; break;
case T_CoerceViaIO:
retval = _equalCoerceViaIO(a, b);
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
retval = _equalArrayCoerceExpr(a, b); retval = _equalArrayCoerceExpr(a, b);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.308 2007/05/22 23:23:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.309 2007/06/05 21:31:04 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -870,6 +870,16 @@ _outRelabelType(StringInfo str, RelabelType *node) ...@@ -870,6 +870,16 @@ _outRelabelType(StringInfo str, RelabelType *node)
WRITE_ENUM_FIELD(relabelformat, CoercionForm); WRITE_ENUM_FIELD(relabelformat, CoercionForm);
} }
static void
_outCoerceViaIO(StringInfo str, CoerceViaIO *node)
{
WRITE_NODE_TYPE("COERCEVIAIO");
WRITE_NODE_FIELD(arg);
WRITE_OID_FIELD(resulttype);
WRITE_ENUM_FIELD(coerceformat, CoercionForm);
}
static void static void
_outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node) _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node)
{ {
...@@ -2165,6 +2175,9 @@ _outNode(StringInfo str, void *obj) ...@@ -2165,6 +2175,9 @@ _outNode(StringInfo str, void *obj)
case T_RelabelType: case T_RelabelType:
_outRelabelType(str, obj); _outRelabelType(str, obj);
break; break;
case T_CoerceViaIO:
_outCoerceViaIO(str, obj);
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
_outArrayCoerceExpr(str, obj); _outArrayCoerceExpr(str, obj);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.206 2007/04/27 22:05:47 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.207 2007/06/05 21:31:04 tgl Exp $
* *
* NOTES * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
...@@ -584,6 +584,21 @@ _readRelabelType(void) ...@@ -584,6 +584,21 @@ _readRelabelType(void)
READ_DONE(); READ_DONE();
} }
/*
* _readCoerceViaIO
*/
static CoerceViaIO *
_readCoerceViaIO(void)
{
READ_LOCALS(CoerceViaIO);
READ_NODE_FIELD(arg);
READ_OID_FIELD(resulttype);
READ_ENUM_FIELD(coerceformat, CoercionForm);
READ_DONE();
}
/* /*
* _readArrayCoerceExpr * _readArrayCoerceExpr
*/ */
...@@ -1042,6 +1057,8 @@ parseNodeString(void) ...@@ -1042,6 +1057,8 @@ parseNodeString(void)
return_value = _readFieldStore(); return_value = _readFieldStore();
else if (MATCH("RELABELTYPE", 11)) else if (MATCH("RELABELTYPE", 11))
return_value = _readRelabelType(); return_value = _readRelabelType();
else if (MATCH("COERCEVIAIO", 11))
return_value = _readCoerceViaIO();
else if (MATCH("ARRAYCOERCEEXPR", 15)) else if (MATCH("ARRAYCOERCEEXPR", 15))
return_value = _readArrayCoerceExpr(); return_value = _readArrayCoerceExpr();
else if (MATCH("CONVERTROWTYPEEXPR", 18)) else if (MATCH("CONVERTROWTYPEEXPR", 18))
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.183 2007/05/21 17:57:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.184 2007/06/05 21:31:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_expr.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/selfuncs.h" #include "utils/selfuncs.h"
#include "utils/tuplesort.h" #include "utils/tuplesort.h"
...@@ -1951,6 +1952,22 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context) ...@@ -1951,6 +1952,22 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
context->total.per_tuple += get_func_cost(saop->opfuncid) * context->total.per_tuple += get_func_cost(saop->opfuncid) *
cpu_operator_cost * estimate_array_length(arraynode) * 0.5; cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
} }
else if (IsA(node, CoerceViaIO))
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
Oid iofunc;
Oid typioparam;
bool typisvarlena;
/* check the result type's input function */
getTypeInputInfo(iocoerce->resulttype,
&iofunc, &typioparam);
context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost;
/* check the input type's output function */
getTypeOutputInfo(exprType((Node *) iocoerce->arg),
&iofunc, &typisvarlena);
context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost;
}
else if (IsA(node, ArrayCoerceExpr)) else if (IsA(node, ArrayCoerceExpr))
{ {
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.244 2007/05/01 18:53:51 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.245 2007/06/05 21:31:05 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -734,6 +734,25 @@ contain_mutable_functions_walker(Node *node, void *context) ...@@ -734,6 +734,25 @@ contain_mutable_functions_walker(Node *node, void *context)
return true; return true;
/* else fall through to check args */ /* else fall through to check args */
} }
else if (IsA(node, CoerceViaIO))
{
CoerceViaIO *expr = (CoerceViaIO *) node;
Oid iofunc;
Oid typioparam;
bool typisvarlena;
/* check the result type's input function */
getTypeInputInfo(expr->resulttype,
&iofunc, &typioparam);
if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE)
return true;
/* check the input type's output function */
getTypeOutputInfo(exprType((Node *) expr->arg),
&iofunc, &typisvarlena);
if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE)
return true;
/* else fall through to check args */
}
else if (IsA(node, ArrayCoerceExpr)) else if (IsA(node, ArrayCoerceExpr))
{ {
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
...@@ -826,6 +845,25 @@ contain_volatile_functions_walker(Node *node, void *context) ...@@ -826,6 +845,25 @@ contain_volatile_functions_walker(Node *node, void *context)
return true; return true;
/* else fall through to check args */ /* else fall through to check args */
} }
else if (IsA(node, CoerceViaIO))
{
CoerceViaIO *expr = (CoerceViaIO *) node;
Oid iofunc;
Oid typioparam;
bool typisvarlena;
/* check the result type's input function */
getTypeInputInfo(expr->resulttype,
&iofunc, &typioparam);
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
return true;
/* check the input type's output function */
getTypeOutputInfo(exprType((Node *) expr->arg),
&iofunc, &typisvarlena);
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
return true;
/* else fall through to check args */
}
else if (IsA(node, ArrayCoerceExpr)) else if (IsA(node, ArrayCoerceExpr))
{ {
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
...@@ -1124,6 +1162,13 @@ find_nonnullable_rels_walker(Node *node, bool top_level) ...@@ -1124,6 +1162,13 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
result = find_nonnullable_rels_walker((Node *) expr->arg, top_level); result = find_nonnullable_rels_walker((Node *) expr->arg, top_level);
} }
else if (IsA(node, CoerceViaIO))
{
/* not clear this is useful, but it can't hurt */
CoerceViaIO *expr = (CoerceViaIO *) node;
result = find_nonnullable_rels_walker((Node *) expr->arg, top_level);
}
else if (IsA(node, ArrayCoerceExpr)) else if (IsA(node, ArrayCoerceExpr))
{ {
/* ArrayCoerceExpr is strict at the array level */ /* ArrayCoerceExpr is strict at the array level */
...@@ -1486,6 +1531,13 @@ strip_implicit_coercions(Node *node) ...@@ -1486,6 +1531,13 @@ strip_implicit_coercions(Node *node)
if (r->relabelformat == COERCE_IMPLICIT_CAST) if (r->relabelformat == COERCE_IMPLICIT_CAST)
return strip_implicit_coercions((Node *) r->arg); return strip_implicit_coercions((Node *) r->arg);
} }
else if (IsA(node, CoerceViaIO))
{
CoerceViaIO *c = (CoerceViaIO *) node;
if (c->coerceformat == COERCE_IMPLICIT_CAST)
return strip_implicit_coercions((Node *) c->arg);
}
else if (IsA(node, ArrayCoerceExpr)) else if (IsA(node, ArrayCoerceExpr))
{ {
ArrayCoerceExpr *c = (ArrayCoerceExpr *) node; ArrayCoerceExpr *c = (ArrayCoerceExpr *) node;
...@@ -1537,6 +1589,8 @@ set_coercionform_dontcare_walker(Node *node, void *context) ...@@ -1537,6 +1589,8 @@ set_coercionform_dontcare_walker(Node *node, void *context)
((FuncExpr *) node)->funcformat = COERCE_DONTCARE; ((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
else if (IsA(node, RelabelType)) else if (IsA(node, RelabelType))
((RelabelType *) node)->relabelformat = COERCE_DONTCARE; ((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
else if (IsA(node, CoerceViaIO))
((CoerceViaIO *) node)->coerceformat = COERCE_DONTCARE;
else if (IsA(node, ArrayCoerceExpr)) else if (IsA(node, ArrayCoerceExpr))
((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE; ((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE;
else if (IsA(node, ConvertRowtypeExpr)) else if (IsA(node, ConvertRowtypeExpr))
...@@ -3471,6 +3525,8 @@ expression_tree_walker(Node *node, ...@@ -3471,6 +3525,8 @@ expression_tree_walker(Node *node,
break; break;
case T_RelabelType: case T_RelabelType:
return walker(((RelabelType *) node)->arg, context); return walker(((RelabelType *) node)->arg, context);
case T_CoerceViaIO:
return walker(((CoerceViaIO *) node)->arg, context);
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
return walker(((ArrayCoerceExpr *) node)->arg, context); return walker(((ArrayCoerceExpr *) node)->arg, context);
case T_ConvertRowtypeExpr: case T_ConvertRowtypeExpr:
...@@ -3959,6 +4015,16 @@ expression_tree_mutator(Node *node, ...@@ -3959,6 +4015,16 @@ expression_tree_mutator(Node *node,
return (Node *) newnode; return (Node *) newnode;
} }
break; break;
case T_CoerceViaIO:
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
CoerceViaIO *newnode;
FLATCOPY(newnode, iocoerce, CoerceViaIO);
MUTATE(newnode->arg, iocoerce->arg, Expr *);
return (Node *) newnode;
}
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
{ {
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.217 2007/04/27 22:05:48 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.218 2007/06/05 21:31:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -265,6 +265,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -265,6 +265,7 @@ transformExpr(ParseState *pstate, Node *expr)
case T_FieldSelect: case T_FieldSelect:
case T_FieldStore: case T_FieldStore:
case T_RelabelType: case T_RelabelType:
case T_CoerceViaIO:
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
case T_ConvertRowtypeExpr: case T_ConvertRowtypeExpr:
case T_CaseTestExpr: case T_CaseTestExpr:
...@@ -1806,6 +1807,9 @@ exprType(Node *expr) ...@@ -1806,6 +1807,9 @@ exprType(Node *expr)
case T_RelabelType: case T_RelabelType:
type = ((RelabelType *) expr)->resulttype; type = ((RelabelType *) expr)->resulttype;
break; break;
case T_CoerceViaIO:
type = ((CoerceViaIO *) expr)->resulttype;
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
type = ((ArrayCoerceExpr *) expr)->resulttype; type = ((ArrayCoerceExpr *) expr)->resulttype;
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.195 2007/03/27 23:21:10 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.196 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -160,7 +160,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -160,7 +160,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
if (fdresult == FUNCDETAIL_COERCION) if (fdresult == FUNCDETAIL_COERCION)
{ {
/* /*
* We can do it as a trivial coercion. coerce_type can handle these * We interpreted it as a type coercion. coerce_type can handle these
* cases, so why duplicate code... * cases, so why duplicate code...
*/ */
return coerce_type(pstate, linitial(fargs), return coerce_type(pstate, linitial(fargs),
...@@ -669,7 +669,7 @@ func_select_candidate(int nargs, ...@@ -669,7 +669,7 @@ func_select_candidate(int nargs,
* (exact match) is as quick as possible. * (exact match) is as quick as possible.
* *
* If an exact match isn't found: * If an exact match isn't found:
* 1) check for possible interpretation as a trivial type coercion * 1) check for possible interpretation as a type coercion request
* 2) get a vector of all possible input arg type arrays constructed * 2) get a vector of all possible input arg type arrays constructed
* from the superclasses of the original input arg types * from the superclasses of the original input arg types
* 3) get a list of all possible argument type arrays to the function * 3) get a list of all possible argument type arrays to the function
...@@ -720,29 +720,35 @@ func_get_detail(List *funcname, ...@@ -720,29 +720,35 @@ func_get_detail(List *funcname,
* If we didn't find an exact match, next consider the possibility * If we didn't find an exact match, next consider the possibility
* that this is really a type-coercion request: a single-argument * that this is really a type-coercion request: a single-argument
* function call where the function name is a type name. If so, and * function call where the function name is a type name. If so, and
* if we can do the coercion trivially (no run-time function call * if the coercion path is RELABELTYPE or COERCEVIAIO, then go ahead
* needed), then go ahead and treat the "function call" as a coercion. * and treat the "function call" as a coercion.
*
* This interpretation needs to be given higher priority than * This interpretation needs to be given higher priority than
* interpretations involving a type coercion followed by a function * interpretations involving a type coercion followed by a function
* call, otherwise we can produce surprising results. For example, we * call, otherwise we can produce surprising results. For example, we
* want "text(varchar)" to be interpreted as a trivial coercion, not * want "text(varchar)" to be interpreted as a simple coercion, not
* as "text(name(varchar))" which the code below this point is * as "text(name(varchar))" which the code below this point is
* entirely capable of selecting. * entirely capable of selecting.
* *
* "Trivial" coercions are ones that involve binary-compatible types * We also treat a coercion of a previously-unknown-type literal
* and ones that are coercing a previously-unknown-type literal * constant to a specific type this way.
* constant to a specific type. *
* The reason we reject COERCION_PATH_FUNC here is that we expect the
* cast implementation function to be named after the target type.
* Thus the function will be found by normal lookup if appropriate.
* *
* The reason we can restrict our check to binary-compatible coercions * The reason we reject COERCION_PATH_ARRAYCOERCE is mainly that
* here is that we expect non-binary-compatible coercions to have an * you can't write "foo[] (something)" as a function call. In theory
* implementation function named after the target type. That function * someone might want to invoke it as "_foo (something)" but we have
* will be found by normal lookup if appropriate. * never supported that historically, so we can insist that people
* write it as a normal cast instead. Lack of historical support is
* also the reason for not considering composite-type casts here.
* *
* NB: it's important that this code stays in sync with what * NB: it's important that this code does not exceed what coerce_type
* coerce_type can do, because the caller will try to apply * can do, because the caller will try to apply coerce_type if we
* coerce_type if we return FUNCDETAIL_COERCION. If we return that * return FUNCDETAIL_COERCION. If we return that result for something
* result for something coerce_type can't handle, we'll cause infinite * coerce_type can't handle, we'll cause infinite recursion between
* recursion between this module and coerce_type! * this module and coerce_type!
*/ */
if (nargs == 1 && fargs != NIL) if (nargs == 1 && fargs != NIL)
{ {
...@@ -755,16 +761,28 @@ func_get_detail(List *funcname, ...@@ -755,16 +761,28 @@ func_get_detail(List *funcname,
{ {
Oid sourceType = argtypes[0]; Oid sourceType = argtypes[0];
Node *arg1 = linitial(fargs); Node *arg1 = linitial(fargs);
Oid cfuncid; bool iscoercion;
bool arrayCoerce;
if (sourceType == UNKNOWNOID && IsA(arg1, Const))
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) || {
(find_coercion_pathway(targetType, sourceType, /* always treat typename('literal') as coercion */
COERCION_EXPLICIT, iscoercion = true;
&cfuncid, &arrayCoerce) && }
cfuncid == InvalidOid && !arrayCoerce)) else
{
CoercionPathType cpathtype;
Oid cfuncid;
cpathtype = find_coercion_pathway(targetType, sourceType,
COERCION_EXPLICIT,
&cfuncid);
iscoercion = (cpathtype == COERCION_PATH_RELABELTYPE ||
cpathtype == COERCION_PATH_COERCEVIAIO);
}
if (iscoercion)
{ {
/* Yup, it's a trivial type coercion */ /* Treat it as a type coercion */
*funcid = InvalidOid; *funcid = InvalidOid;
*rettype = targetType; *rettype = targetType;
*retset = false; *retset = false;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# #
# #
# IDENTIFICATION # IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.35 2007/01/22 01:35:21 tgl Exp $ # $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.36 2007/06/05 21:31:06 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -127,7 +127,7 @@ cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf ...@@ -127,7 +127,7 @@ cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf
* NOTE: macros are named after the prosrc value, ie the actual C name * NOTE: macros are named after the prosrc value, ie the actual C name
* of the implementing function, not the proname which may be overloaded. * of the implementing function, not the proname which may be overloaded.
* For example, we want to be able to assign different macro names to both * For example, we want to be able to assign different macro names to both
* char_text() and int4_text() even though these both appear with proname * char_text() and name_text() even though these both appear with proname
* 'text'. If the same C function appears in more than one pg_proc entry, * 'text'. If the same C function appears in more than one pg_proc entry,
* its equivalent macro will be defined with the lowest OID among those * its equivalent macro will be defined with the lowest OID among those
* entries. * entries.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/bool.c,v 1.39 2007/06/01 23:40:18 neilc Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/bool.c,v 1.40 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -142,22 +142,11 @@ boolsend(PG_FUNCTION_ARGS) ...@@ -142,22 +142,11 @@ boolsend(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
} }
/*
* textbool - cast function for text => bool
*/
Datum
textbool(PG_FUNCTION_ARGS)
{
Datum in_text = PG_GETARG_DATUM(0);
char *str;
str = DatumGetCString(DirectFunctionCall1(textout, in_text));
PG_RETURN_DATUM(DirectFunctionCall1(boolin, CStringGetDatum(str)));
}
/* /*
* booltext - cast function for bool => text * booltext - cast function for bool => text
*
* We need this because it's different from the behavior of boolout();
* this function follows the SQL-spec result (except for producing lower case)
*/ */
Datum Datum
booltext(PG_FUNCTION_ARGS) booltext(PG_FUNCTION_ARGS)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.131 2007/06/02 16:41:09 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.132 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -873,65 +873,6 @@ abstime_date(PG_FUNCTION_ARGS) ...@@ -873,65 +873,6 @@ abstime_date(PG_FUNCTION_ARGS)
} }
/* date_text()
* Convert date to text data type.
*/
Datum
date_text(PG_FUNCTION_ARGS)
{
/* Input is a Date, but may as well leave it in Datum form */
Datum date = PG_GETARG_DATUM(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(date_out, date));
len = strlen(str) + VARHDRSZ;
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_date()
* Convert text string to date.
* Text type is not null terminated, so use temporary string
* then call the standard input routine.
*/
Datum
text_date(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int i;
char *sp,
*dp,
dstr[MAXDATELEN + 1];
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for type date: \"%s\"",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(str))))));
sp = VARDATA(str);
dp = dstr;
for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
*dp++ = *sp++;
*dp = '\0';
return DirectFunctionCall1(date_in,
CStringGetDatum(dstr));
}
/***************************************************************************** /*****************************************************************************
* Time ADT * Time ADT
*****************************************************************************/ *****************************************************************************/
...@@ -1617,62 +1558,6 @@ time_mi_interval(PG_FUNCTION_ARGS) ...@@ -1617,62 +1558,6 @@ time_mi_interval(PG_FUNCTION_ARGS)
} }
/* time_text()
* Convert time to text data type.
*/
Datum
time_text(PG_FUNCTION_ARGS)
{
/* Input is a Time, but may as well leave it in Datum form */
Datum time = PG_GETARG_DATUM(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(time_out, time));
len = strlen(str) + VARHDRSZ;
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, len - VARHDRSZ);
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_time()
* Convert text string to time.
* Text type is not null terminated, so use temporary string
* then call the standard input routine.
*/
Datum
text_time(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
char dstr[MAXDATELEN + 1];
size_t len;
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for type time: \"%s\"",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(str))))));
len = VARSIZE(str) - VARHDRSZ;
memcpy(dstr, VARDATA(str), len);
dstr[len] = '\0';
return DirectFunctionCall3(time_in,
CStringGetDatum(dstr),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
}
/* time_part() /* time_part()
* Extract specified field from time type. * Extract specified field from time type.
*/ */
...@@ -2400,66 +2285,6 @@ datetimetz_timestamptz(PG_FUNCTION_ARGS) ...@@ -2400,66 +2285,6 @@ datetimetz_timestamptz(PG_FUNCTION_ARGS)
} }
/* timetz_text()
* Convert timetz to text data type.
*/
Datum
timetz_text(PG_FUNCTION_ARGS)
{
/* Input is a Timetz, but may as well leave it in Datum form */
Datum timetz = PG_GETARG_DATUM(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(timetz_out, timetz));
len = strlen(str) + VARHDRSZ;
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_timetz()
* Convert text string to timetz.
* Text type is not null terminated, so use temporary string
* then call the standard input routine.
*/
Datum
text_timetz(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int i;
char *sp,
*dp,
dstr[MAXDATELEN + 1];
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for type time with time zone: \"%s\"",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(str))))));
sp = VARDATA(str);
dp = dstr;
for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
*dp++ = *sp++;
*dp = '\0';
return DirectFunctionCall3(timetz_in,
CStringGetDatum(dstr),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
}
/* timetz_part() /* timetz_part()
* Extract specified field from time type. * Extract specified field from time type.
*/ */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.2 2007/04/02 22:14:17 adunstan Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.3 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#include "utils/syscache.h" #include "utils/syscache.h"
static Oid cstring_enum(char *name, Oid enumtypoid);
static char *enum_cstring(Oid enumval);
static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper); static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper);
static int enum_elem_cmp(const void *left, const void *right); static int enum_elem_cmp(const void *left, const void *right);
...@@ -32,75 +30,60 @@ static int enum_elem_cmp(const void *left, const void *right); ...@@ -32,75 +30,60 @@ static int enum_elem_cmp(const void *left, const void *right);
Datum Datum
enum_in(PG_FUNCTION_ARGS) enum_in(PG_FUNCTION_ARGS)
{ {
char *name = PG_GETARG_CSTRING(0); char *name = PG_GETARG_CSTRING(0);
Oid enumtypoid = PG_GETARG_OID(1); Oid enumtypoid = PG_GETARG_OID(1);
PG_RETURN_OID(cstring_enum(name, enumtypoid));
}
/* guts of enum_in and text-to-enum */
static Oid
cstring_enum(char *name, Oid enumtypoid)
{
HeapTuple tup;
Oid enumoid; Oid enumoid;
HeapTuple tup;
/* must check length to prevent Assert failure within SearchSysCache */ /* must check length to prevent Assert failure within SearchSysCache */
if (strlen(name) >= NAMEDATALEN) if (strlen(name) >= NAMEDATALEN)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input value for enum %s: \"%s\"", errmsg("invalid input value for enum %s: \"%s\"",
format_type_be(enumtypoid), format_type_be(enumtypoid),
name))); name)));
tup = SearchSysCache(ENUMTYPOIDNAME, tup = SearchSysCache(ENUMTYPOIDNAME,
ObjectIdGetDatum(enumtypoid), ObjectIdGetDatum(enumtypoid),
CStringGetDatum(name), CStringGetDatum(name),
0, 0); 0, 0);
if (tup == NULL) if (!HeapTupleIsValid(tup))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input value for enum %s: \"%s\"", errmsg("invalid input value for enum %s: \"%s\"",
format_type_be(enumtypoid), format_type_be(enumtypoid),
name))); name)));
enumoid = HeapTupleGetOid(tup); enumoid = HeapTupleGetOid(tup);
ReleaseSysCache(tup); ReleaseSysCache(tup);
return enumoid;
PG_RETURN_OID(enumoid);
} }
Datum Datum
enum_out(PG_FUNCTION_ARGS) enum_out(PG_FUNCTION_ARGS)
{ {
Oid enumoid = PG_GETARG_OID(0); Oid enumval = PG_GETARG_OID(0);
char *result;
PG_RETURN_CSTRING(enum_cstring(enumoid));
}
/* guts of enum_out and enum-to-text */
static char *
enum_cstring(Oid enumval)
{
HeapTuple tup; HeapTuple tup;
Form_pg_enum en; Form_pg_enum en;
char *label;
tup = SearchSysCache(ENUMOID, tup = SearchSysCache(ENUMOID,
ObjectIdGetDatum(enumval), ObjectIdGetDatum(enumval),
0, 0, 0); 0, 0, 0);
if (tup == NULL) if (!HeapTupleIsValid(tup))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid internal value for enum: %u", errmsg("invalid internal value for enum: %u",
enumval))); enumval)));
en = (Form_pg_enum) GETSTRUCT(tup); en = (Form_pg_enum) GETSTRUCT(tup);
label = pstrdup(NameStr(en->enumlabel)); result = pstrdup(NameStr(en->enumlabel));
ReleaseSysCache(tup); ReleaseSysCache(tup);
return label;
PG_RETURN_CSTRING(result);
} }
/* Comparison functions and related */ /* Comparison functions and related */
...@@ -191,47 +174,6 @@ enum_cmp(PG_FUNCTION_ARGS) ...@@ -191,47 +174,6 @@ enum_cmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(-1); PG_RETURN_INT32(-1);
} }
/* Casts between text and enum */
Datum
enum_text(PG_FUNCTION_ARGS)
{
Oid enumval = PG_GETARG_OID(0);
text *result;
char *cstr;
int len;
cstr = enum_cstring(enumval);
len = strlen(cstr);
result = (text *) palloc(VARHDRSZ + len);
SET_VARSIZE(result, VARHDRSZ + len);
memcpy(VARDATA(result), cstr, len);
pfree(cstr);
PG_RETURN_TEXT_P(result);
}
Datum
text_enum(PG_FUNCTION_ARGS)
{
text *textval = PG_GETARG_TEXT_P(0);
Oid enumtypoid;
char *str;
/*
* We rely on being able to get the specific enum type from the calling
* expression tree.
*/
enumtypoid = get_fn_expr_rettype(fcinfo->flinfo);
if (enumtypoid == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine actual enum type")));
str = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(textval)));
PG_RETURN_OID(cstring_enum(str, enumtypoid));
}
/* Enum programming support functions */ /* Enum programming support functions */
Datum Datum
...@@ -266,7 +208,7 @@ enum_first(PG_FUNCTION_ARGS) ...@@ -266,7 +208,7 @@ enum_first(PG_FUNCTION_ARGS)
ReleaseCatCacheList(list); ReleaseCatCacheList(list);
if (!OidIsValid(min)) /* should not happen */ if (!OidIsValid(min)) /* should not happen */
elog(ERROR, "no values found for enum %s", elog(ERROR, "no values found for enum %s",
format_type_be(enumtypoid)); format_type_be(enumtypoid));
...@@ -276,10 +218,10 @@ enum_first(PG_FUNCTION_ARGS) ...@@ -276,10 +218,10 @@ enum_first(PG_FUNCTION_ARGS)
Datum Datum
enum_last(PG_FUNCTION_ARGS) enum_last(PG_FUNCTION_ARGS)
{ {
Oid enumtypoid; Oid enumtypoid;
Oid max = InvalidOid; Oid max = InvalidOid;
CatCList *list; CatCList *list;
int num, i; int num, i;
/* /*
* We rely on being able to get the specific enum type from the calling * We rely on being able to get the specific enum type from the calling
...@@ -292,24 +234,24 @@ enum_last(PG_FUNCTION_ARGS) ...@@ -292,24 +234,24 @@ enum_last(PG_FUNCTION_ARGS)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine actual enum type"))); errmsg("could not determine actual enum type")));
list = SearchSysCacheList(ENUMTYPOIDNAME, 1, list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
ObjectIdGetDatum(enumtypoid), ObjectIdGetDatum(enumtypoid),
0, 0, 0); 0, 0, 0);
num = list->n_members; num = list->n_members;
for (i = 0; i < num; i++) for (i = 0; i < num; i++)
{ {
Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data); Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data);
if(!OidIsValid(max) || valoid > max) if (!OidIsValid(max) || valoid > max)
max = valoid; max = valoid;
} }
ReleaseCatCacheList(list); ReleaseCatCacheList(list);
if (!OidIsValid(max)) /* should not happen */ if (!OidIsValid(max)) /* should not happen */
elog(ERROR, "no values found for enum %s", elog(ERROR, "no values found for enum %s",
format_type_be(enumtypoid)); format_type_be(enumtypoid));
PG_RETURN_OID(max); PG_RETURN_OID(max);
} }
/* 2-argument variant of enum_range */ /* 2-argument variant of enum_range */
...@@ -368,26 +310,26 @@ static ArrayType * ...@@ -368,26 +310,26 @@ static ArrayType *
enum_range_internal(Oid enumtypoid, Oid lower, Oid upper) enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
{ {
ArrayType *result; ArrayType *result;
CatCList *list; CatCList *list;
int total, i, j; int total, i, j;
Datum *elems; Datum *elems;
list = SearchSysCacheList(ENUMTYPOIDNAME, 1, list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
ObjectIdGetDatum(enumtypoid), ObjectIdGetDatum(enumtypoid),
0, 0, 0); 0, 0, 0);
total = list->n_members; total = list->n_members;
elems = (Datum *) palloc(total * sizeof(Datum)); elems = (Datum *) palloc(total * sizeof(Datum));
j = 0; j = 0;
for (i = 0; i < total; i++) for (i = 0; i < total; i++)
{ {
Oid val = HeapTupleGetOid(&(list->members[i]->tuple)); Oid val = HeapTupleGetOid(&(list->members[i]->tuple));
if ((!OidIsValid(lower) || lower <= val) && if ((!OidIsValid(lower) || lower <= val) &&
(!OidIsValid(upper) || val <= upper)) (!OidIsValid(upper) || val <= upper))
elems[j++] = ObjectIdGetDatum(val); elems[j++] = ObjectIdGetDatum(val);
} }
/* shouldn't need the cache anymore */ /* shouldn't need the cache anymore */
ReleaseCatCacheList(list); ReleaseCatCacheList(list);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.149 2007/02/27 23:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.150 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1196,108 +1196,6 @@ i2tof(PG_FUNCTION_ARGS) ...@@ -1196,108 +1196,6 @@ i2tof(PG_FUNCTION_ARGS)
} }
/*
* float8_text - converts a float8 number to a text string
*/
Datum
float8_text(PG_FUNCTION_ARGS)
{
float8 num = PG_GETARG_FLOAT8(0);
text *result;
int len;
char *str;
str = DatumGetCString(DirectFunctionCall1(float8out,
Float8GetDatum(num)));
len = strlen(str) + VARHDRSZ;
result = (text *) palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
/*
* text_float8 - converts a text string to a float8 number
*/
Datum
text_float8(PG_FUNCTION_ARGS)
{
text *string = PG_GETARG_TEXT_P(0);
Datum result;
int len;
char *str;
len = (VARSIZE(string) - VARHDRSZ);
str = palloc(len + 1);
memcpy(str, VARDATA(string), len);
*(str + len) = '\0';
result = DirectFunctionCall1(float8in, CStringGetDatum(str));
pfree(str);
PG_RETURN_DATUM(result);
}
/*
* float4_text - converts a float4 number to a text string
*/
Datum
float4_text(PG_FUNCTION_ARGS)
{
float4 num = PG_GETARG_FLOAT4(0);
text *result;
int len;
char *str;
str = DatumGetCString(DirectFunctionCall1(float4out,
Float4GetDatum(num)));
len = strlen(str) + VARHDRSZ;
result = (text *) palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
/*
* text_float4 - converts a text string to a float4 number
*/
Datum
text_float4(PG_FUNCTION_ARGS)
{
text *string = PG_GETARG_TEXT_P(0);
Datum result;
int len;
char *str;
len = (VARSIZE(string) - VARHDRSZ);
str = palloc(len + 1);
memcpy(str, VARDATA(string), len);
*(str + len) = '\0';
result = DirectFunctionCall1(float4in, CStringGetDatum(str));
pfree(str);
PG_RETURN_DATUM(result);
}
/* /*
* ======================= * =======================
* RANDOM FLOAT8 OPERATORS * RANDOM FLOAT8 OPERATORS
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.79 2007/02/27 23:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.80 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
* int2in, int2out, int2recv, int2send * int2in, int2out, int2recv, int2send
* int4in, int4out, int4recv, int4send * int4in, int4out, int4recv, int4send
* int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend * int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend
* Conversion routines:
* itoi, int2_text, int4_text
* Boolean operators: * Boolean operators:
* inteq, intne, intlt, intle, intgt, intge * inteq, intne, intlt, intle, intgt, intge
* Arithmetic operators: * Arithmetic operators:
...@@ -343,68 +341,6 @@ i4toi2(PG_FUNCTION_ARGS) ...@@ -343,68 +341,6 @@ i4toi2(PG_FUNCTION_ARGS)
PG_RETURN_INT16((int16) arg1); PG_RETURN_INT16((int16) arg1);
} }
Datum
int2_text(PG_FUNCTION_ARGS)
{
int16 arg1 = PG_GETARG_INT16(0);
text *result = (text *) palloc(7 + VARHDRSZ); /* sign,5 digits, '\0' */
pg_itoa(arg1, VARDATA(result));
SET_VARSIZE(result, strlen(VARDATA(result)) + VARHDRSZ);
PG_RETURN_TEXT_P(result);
}
Datum
text_int2(PG_FUNCTION_ARGS)
{
text *string = PG_GETARG_TEXT_P(0);
Datum result;
int len;
char *str;
len = VARSIZE(string) - VARHDRSZ;
str = palloc(len + 1);
memcpy(str, VARDATA(string), len);
*(str + len) = '\0';
result = DirectFunctionCall1(int2in, CStringGetDatum(str));
pfree(str);
return result;
}
Datum
int4_text(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
text *result = (text *) palloc(12 + VARHDRSZ); /* sign,10 digits,'\0' */
pg_ltoa(arg1, VARDATA(result));
SET_VARSIZE(result, strlen(VARDATA(result)) + VARHDRSZ);
PG_RETURN_TEXT_P(result);
}
Datum
text_int4(PG_FUNCTION_ARGS)
{
text *string = PG_GETARG_TEXT_P(0);
Datum result;
int len;
char *str;
len = VARSIZE(string) - VARHDRSZ;
str = palloc(len + 1);
memcpy(str, VARDATA(string), len);
*(str + len) = '\0';
result = DirectFunctionCall1(int4in, CStringGetDatum(str));
pfree(str);
return result;
}
/* Cast int4 -> bool */ /* Cast int4 -> bool */
Datum Datum
int4_bool(PG_FUNCTION_ARGS) int4_bool(PG_FUNCTION_ARGS)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.65 2007/02/27 23:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.66 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1137,48 +1137,6 @@ oidtoi8(PG_FUNCTION_ARGS) ...@@ -1137,48 +1137,6 @@ oidtoi8(PG_FUNCTION_ARGS)
PG_RETURN_INT64((int64) arg); PG_RETURN_INT64((int64) arg);
} }
Datum
text_int8(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int len;
char *s;
Datum result;
len = (VARSIZE(str) - VARHDRSZ);
s = palloc(len + 1);
memcpy(s, VARDATA(str), len);
*(s + len) = '\0';
result = DirectFunctionCall1(int8in, CStringGetDatum(s));
pfree(s);
return result;
}
Datum
int8_text(PG_FUNCTION_ARGS)
{
/* arg is int64, but easier to leave it as Datum */
Datum arg = PG_GETARG_DATUM(0);
char *s;
int len;
text *result;
s = DatumGetCString(DirectFunctionCall1(int8out, arg));
len = strlen(s);
result = (text *) palloc(VARHDRSZ + len);
SET_VARSIZE(result, VARHDRSZ + len);
memcpy(VARDATA(result), s, len);
pfree(s);
PG_RETURN_TEXT_P(result);
}
/* /*
* non-persistent numeric series generator * non-persistent numeric series generator
*/ */
......
/* /*
* PostgreSQL type definitions for MAC addresses. * PostgreSQL type definitions for MAC addresses.
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/mac.c,v 1.37 2007/02/27 23:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/mac.c,v 1.38 2007/06/05 21:31:06 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -144,59 +144,6 @@ macaddr_send(PG_FUNCTION_ARGS) ...@@ -144,59 +144,6 @@ macaddr_send(PG_FUNCTION_ARGS)
} }
/*
* Convert macaddr to text data type.
*/
Datum
macaddr_text(PG_FUNCTION_ARGS)
{
/* Input is a macaddr, but may as well leave it in Datum form */
Datum addr = PG_GETARG_DATUM(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(macaddr_out, addr));
len = (strlen(str) + VARHDRSZ);
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
/*
* Convert text to macaddr data type.
*/
Datum
text_macaddr(PG_FUNCTION_ARGS)
{
text *addr = PG_GETARG_TEXT_P(0);
Datum result;
char str[100];
int len;
len = (VARSIZE(addr) - VARHDRSZ);
if (len >= sizeof(str))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("text too long to convert to MAC address")));
memcpy(str, VARDATA(addr), len);
*(str + len) = '\0';
result = DirectFunctionCall1(macaddr_in, CStringGetDatum(str));
return result;
}
/* /*
* Comparison function for sorting: * Comparison function for sorting:
*/ */
......
/* /*
* PostgreSQL type definitions for the INET and CIDR types. * PostgreSQL type definitions for the INET and CIDR types.
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.70 2007/05/17 23:31:49 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.71 2007/06/05 21:31:06 tgl Exp $
* *
* Jon Postel RIP 16 Oct 1998 * Jon Postel RIP 16 Oct 1998
*/ */
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include "utils/inet.h" #include "utils/inet.h"
static inet *text_network(text *src, bool is_cidr);
static int32 network_cmp_internal(inet *a1, inet *a2); static int32 network_cmp_internal(inet *a1, inet *a2);
static int bitncmp(void *l, void *r, int n); static int bitncmp(void *l, void *r, int n);
static bool addressOK(unsigned char *a, int bits, int family); static bool addressOK(unsigned char *a, int bits, int family);
...@@ -314,35 +313,6 @@ cidr_send(PG_FUNCTION_ARGS) ...@@ -314,35 +313,6 @@ cidr_send(PG_FUNCTION_ARGS)
} }
static inet *
text_network(text *src, bool is_cidr)
{
int len = VARSIZE(src) - VARHDRSZ;
char *str = palloc(len + 1);
memcpy(str, VARDATA(src), len);
str[len] = '\0';
return network_in(str, is_cidr);
}
Datum
text_inet(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_P(0);
PG_RETURN_INET_P(text_network(src, false));
}
Datum
text_cidr(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_P(0);
PG_RETURN_INET_P(text_network(src, true));
}
Datum Datum
inet_to_cidr(PG_FUNCTION_ARGS) inet_to_cidr(PG_FUNCTION_ARGS)
{ {
...@@ -655,6 +625,11 @@ network_host(PG_FUNCTION_ARGS) ...@@ -655,6 +625,11 @@ network_host(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(ret); PG_RETURN_TEXT_P(ret);
} }
/*
* network_show implements the inet and cidr casts to text. This is not
* quite the same behavior as network_out, hence we can't drop it in favor
* of CoerceViaIO.
*/
Datum Datum
network_show(PG_FUNCTION_ARGS) network_show(PG_FUNCTION_ARGS)
{ {
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* Copyright (c) 1998-2007, PostgreSQL Global Development Group * Copyright (c) 1998-2007, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.102 2007/05/08 18:56:47 neilc Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.103 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2146,50 +2146,6 @@ numeric_float4(PG_FUNCTION_ARGS) ...@@ -2146,50 +2146,6 @@ numeric_float4(PG_FUNCTION_ARGS)
} }
Datum
text_numeric(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int len;
char *s;
Datum result;
len = (VARSIZE(str) - VARHDRSZ);
s = palloc(len + 1);
memcpy(s, VARDATA(str), len);
*(s + len) = '\0';
result = DirectFunctionCall3(numeric_in, CStringGetDatum(s),
ObjectIdGetDatum(0), Int32GetDatum(-1));
pfree(s);
return result;
}
Datum
numeric_text(PG_FUNCTION_ARGS)
{
/* val is numeric, but easier to leave it as Datum */
Datum val = PG_GETARG_DATUM(0);
char *s;
int len;
text *result;
s = DatumGetCString(DirectFunctionCall1(numeric_out, val));
len = strlen(s);
result = (text *) palloc(VARHDRSZ + len);
SET_VARSIZE(result, VARHDRSZ + len);
memcpy(VARDATA(result), s, len);
pfree(s);
PG_RETURN_TEXT_P(result);
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* *
* Aggregate functions * Aggregate functions
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.71 2007/02/27 23:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.72 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
*****************************************************************************/ *****************************************************************************/
static Oid static Oid
oidin_subr(const char *funcname, const char *s, char **endloc) oidin_subr(const char *s, char **endloc)
{ {
unsigned long cvt; unsigned long cvt;
char *endptr; char *endptr;
...@@ -116,7 +116,7 @@ oidin(PG_FUNCTION_ARGS) ...@@ -116,7 +116,7 @@ oidin(PG_FUNCTION_ARGS)
char *s = PG_GETARG_CSTRING(0); char *s = PG_GETARG_CSTRING(0);
Oid result; Oid result;
result = oidin_subr("oidin", s, NULL); result = oidin_subr(s, NULL);
PG_RETURN_OID(result); PG_RETURN_OID(result);
} }
...@@ -202,7 +202,7 @@ oidvectorin(PG_FUNCTION_ARGS) ...@@ -202,7 +202,7 @@ oidvectorin(PG_FUNCTION_ARGS)
oidString++; oidString++;
if (*oidString == '\0') if (*oidString == '\0')
break; break;
result->values[n] = oidin_subr("oidvectorin", oidString, &oidString); result->values[n] = oidin_subr(oidString, &oidString);
} }
while (*oidString && isspace((unsigned char) *oidString)) while (*oidString && isspace((unsigned char) *oidString))
oidString++; oidString++;
...@@ -419,45 +419,3 @@ oidvectorgt(PG_FUNCTION_ARGS) ...@@ -419,45 +419,3 @@ oidvectorgt(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(cmp > 0); PG_RETURN_BOOL(cmp > 0);
} }
Datum
oid_text(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
text *result;
int len;
char *str;
str = DatumGetCString(DirectFunctionCall1(oidout,
ObjectIdGetDatum(oid)));
len = strlen(str) + VARHDRSZ;
result = (text *) palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
Datum
text_oid(PG_FUNCTION_ARGS)
{
text *string = PG_GETARG_TEXT_P(0);
Oid result;
int len;
char *str;
len = (VARSIZE(string) - VARHDRSZ);
str = palloc(len + 1);
memcpy(str, VARDATA(string), len);
*(str + len) = '\0';
result = oidin_subr("text_oid", str, NULL);
pfree(str);
PG_RETURN_OID(result);
}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.100 2007/01/05 22:19:41 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.101 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1070,6 +1070,10 @@ regtypesend(PG_FUNCTION_ARGS) ...@@ -1070,6 +1070,10 @@ regtypesend(PG_FUNCTION_ARGS)
/* /*
* text_regclass: convert text to regclass * text_regclass: convert text to regclass
*
* This could be replaced by CoerceViaIO, except that we need to treat
* text-to-regclass as an implicit cast to support legacy forms of nextval()
* and related functions.
*/ */
Datum Datum
text_regclass(PG_FUNCTION_ARGS) text_regclass(PG_FUNCTION_ARGS)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.94 2007/03/27 23:21:10 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.95 2007/06/05 21:31:06 tgl Exp $
* *
* ---------- * ----------
*/ */
...@@ -3871,7 +3871,7 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid) ...@@ -3871,7 +3871,7 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid)
Oid lefttype, Oid lefttype,
righttype, righttype,
castfunc; castfunc;
bool arrayCoerce; CoercionPathType pathtype;
/* We always need to know how to call the equality operator */ /* We always need to know how to call the equality operator */
fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo, fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo,
...@@ -3885,20 +3885,28 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid) ...@@ -3885,20 +3885,28 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid)
* here and in ri_AttributesEqual(). At the moment there is no * here and in ri_AttributesEqual(). At the moment there is no
* point because cases involving nonidentical array types will * point because cases involving nonidentical array types will
* be rejected at constraint creation time. * be rejected at constraint creation time.
*
* XXX perhaps also consider supporting CoerceViaIO? No need at the
* moment since that will never be generated for implicit coercions.
*/ */
op_input_types(eq_opr, &lefttype, &righttype); op_input_types(eq_opr, &lefttype, &righttype);
Assert(lefttype == righttype); Assert(lefttype == righttype);
if (typeid == lefttype) if (typeid == lefttype)
castfunc = InvalidOid; /* simplest case */ castfunc = InvalidOid; /* simplest case */
else if (!find_coercion_pathway(lefttype, typeid, COERCION_IMPLICIT, else
&castfunc, &arrayCoerce)
|| arrayCoerce) /* XXX fixme */
{ {
/* If target is ANYARRAY, assume it's OK, else punt. */ pathtype = find_coercion_pathway(lefttype, typeid,
if (lefttype != ANYARRAYOID) COERCION_IMPLICIT,
elog(ERROR, "no conversion function from %s to %s", &castfunc);
format_type_be(typeid), if (pathtype != COERCION_PATH_FUNC &&
format_type_be(lefttype)); pathtype != COERCION_PATH_RELABELTYPE)
{
/* If target is ANYARRAY, assume it's OK, else punt. */
if (lefttype != ANYARRAYOID)
elog(ERROR, "no conversion function from %s to %s",
format_type_be(typeid),
format_type_be(lefttype));
}
} }
if (OidIsValid(castfunc)) if (OidIsValid(castfunc))
fmgr_info_cxt(castfunc, &entry->cast_func_finfo, fmgr_info_cxt(castfunc, &entry->cast_func_finfo,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.258 2007/05/24 18:58:42 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.259 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3127,6 +3127,9 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) ...@@ -3127,6 +3127,9 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RelabelType: case T_RelabelType:
return isSimpleNode((Node *) ((RelabelType *) node)->arg, return isSimpleNode((Node *) ((RelabelType *) node)->arg,
node, prettyFlags); node, prettyFlags);
case T_CoerceViaIO:
return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
node, prettyFlags);
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg, return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
node, prettyFlags); node, prettyFlags);
...@@ -3595,6 +3598,27 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -3595,6 +3598,27 @@ get_rule_expr(Node *node, deparse_context *context,
} }
break; break;
case T_CoerceViaIO:
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
Node *arg = (Node *) iocoerce->arg;
if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
!showimplicit)
{
/* don't show the implicit cast */
get_rule_expr_paren(arg, context, false, node);
}
else
{
get_coercion_expr(arg, context,
iocoerce->resulttype,
-1,
node);
}
}
break;
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
{ {
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.176 2007/04/30 21:01:52 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.177 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3229,187 +3229,6 @@ timestamptz_age(PG_FUNCTION_ARGS) ...@@ -3229,187 +3229,6 @@ timestamptz_age(PG_FUNCTION_ARGS)
*---------------------------------------------------------*/ *---------------------------------------------------------*/
/* timestamp_text()
* Convert timestamp to text data type.
*/
Datum
timestamp_text(PG_FUNCTION_ARGS)
{
/* Input is a Timestamp, but may as well leave it in Datum form */
Datum timestamp = PG_GETARG_DATUM(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(timestamp_out, timestamp));
len = (strlen(str) + VARHDRSZ);
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, len - VARHDRSZ);
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_timestamp()
* Convert text string to timestamp.
* Text type is not null terminated, so use temporary string
* then call the standard input routine.
*/
Datum
text_timestamp(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int i;
char *sp,
*dp,
dstr[MAXDATELEN + 1];
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for type timestamp: \"%s\"",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(str))))));
sp = VARDATA(str);
dp = dstr;
for (i = 0; i < VARSIZE(str) - VARHDRSZ; i++)
*dp++ = *sp++;
*dp = '\0';
return DirectFunctionCall3(timestamp_in,
CStringGetDatum(dstr),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
}
/* timestamptz_text()
* Convert timestamp with time zone to text data type.
*/
Datum
timestamptz_text(PG_FUNCTION_ARGS)
{
/* Input is a Timestamp, but may as well leave it in Datum form */
Datum timestamp = PG_GETARG_DATUM(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(timestamptz_out, timestamp));
len = strlen(str) + VARHDRSZ;
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, len - VARHDRSZ);
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_timestamptz()
* Convert text string to timestamp with time zone.
* Text type is not null terminated, so use temporary string
* then call the standard input routine.
*/
Datum
text_timestamptz(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int i;
char *sp,
*dp,
dstr[MAXDATELEN + 1];
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for type timestamp with time zone: \"%s\"",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(str))))));
sp = VARDATA(str);
dp = dstr;
for (i = 0; i < VARSIZE(str) - VARHDRSZ; i++)
*dp++ = *sp++;
*dp = '\0';
return DirectFunctionCall3(timestamptz_in,
CStringGetDatum(dstr),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
}
/* interval_text()
* Convert interval to text data type.
*/
Datum
interval_text(PG_FUNCTION_ARGS)
{
Interval *interval = PG_GETARG_INTERVAL_P(0);
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(interval_out,
IntervalPGetDatum(interval)));
len = strlen(str) + VARHDRSZ;
result = palloc(len);
SET_VARSIZE(result, len);
memcpy(VARDATA(result), str, len - VARHDRSZ);
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_interval()
* Convert text string to interval.
* Text type may not be null terminated, so copy to temporary string
* then call the standard input routine.
*/
Datum
text_interval(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int i;
char *sp,
*dp,
dstr[MAXDATELEN + 1];
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
errmsg("invalid input syntax for type interval: \"%s\"",
DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(str))))));
sp = VARDATA(str);
dp = dstr;
for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
*dp++ = *sp++;
*dp = '\0';
return DirectFunctionCall3(interval_in,
CStringGetDatum(dstr),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1));
}
/* timestamp_trunc() /* timestamp_trunc()
* Truncate timestamp to specified units. * Truncate timestamp to specified units.
*/ */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (c) 2007, PostgreSQL Global Development Group * Copyright (c) 2007, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.3 2007/01/31 19:33:54 neilc Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.4 2007/06/05 21:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -238,32 +238,3 @@ uuid_hash(PG_FUNCTION_ARGS) ...@@ -238,32 +238,3 @@ uuid_hash(PG_FUNCTION_ARGS)
pg_uuid_t *key = PG_GETARG_UUID_P(0); pg_uuid_t *key = PG_GETARG_UUID_P(0);
return hash_any(key->data, UUID_LEN); return hash_any(key->data, UUID_LEN);
} }
/* cast text to uuid */
Datum
text_uuid(PG_FUNCTION_ARGS)
{
text *input = PG_GETARG_TEXT_P(0);
int length;
char *str;
Datum result;
length = VARSIZE(input) - VARHDRSZ;
str = palloc(length + 1);
memcpy(str, VARDATA(input), length);
*(str + length) = '\0';
result = DirectFunctionCall1(uuid_in, CStringGetDatum(str));
pfree(str);
PG_RETURN_DATUM(result);
}
/* cast uuid to text */
Datum
uuid_text(PG_FUNCTION_ARGS)
{
pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
Datum uuid_str = DirectFunctionCall1(uuid_out, UUIDPGetDatum(uuid));
PG_RETURN_DATUM(DirectFunctionCall1(textin, uuid_str));
}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.409 2007/06/01 23:40:18 neilc Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.410 2007/06/05 21:31:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200706012 #define CATALOG_VERSION_NO 200706051
#endif #endif
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* Copyright (c) 2002-2007, PostgreSQL Global Development Group * Copyright (c) 2002-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.33 2007/06/01 23:40:18 neilc Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.34 2007/06/05 21:31:07 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -173,7 +173,7 @@ DATA(insert ( 25 2205 1079 i )); ...@@ -173,7 +173,7 @@ DATA(insert ( 25 2205 1079 i ));
DATA(insert ( 1043 2205 1079 i )); DATA(insert ( 1043 2205 1079 i ));
/* /*
* String category: this needs to be tightened up * String category
*/ */
DATA(insert ( 25 1042 0 i )); DATA(insert ( 25 1042 0 i ));
DATA(insert ( 25 1043 0 i )); DATA(insert ( 25 1043 0 i ));
...@@ -193,7 +193,8 @@ DATA(insert ( 1043 18 944 a )); ...@@ -193,7 +193,8 @@ DATA(insert ( 1043 18 944 a ));
DATA(insert ( 25 19 407 i )); DATA(insert ( 25 19 407 i ));
DATA(insert ( 1042 19 409 i )); DATA(insert ( 1042 19 409 i ));
DATA(insert ( 1043 19 1400 i )); DATA(insert ( 1043 19 1400 i ));
/* Cross-category casts between int4 and "char" */
/* Allow explicit coercions between int4 and "char" */
DATA(insert ( 18 23 77 e )); DATA(insert ( 18 23 77 e ));
DATA(insert ( 23 18 78 e )); DATA(insert ( 23 18 78 e ));
...@@ -265,127 +266,42 @@ DATA(insert ( 1560 23 1684 e )); ...@@ -265,127 +266,42 @@ DATA(insert ( 1560 23 1684 e ));
/* /*
* Cross-category casts to and from TEXT * Cross-category casts to and from TEXT
* *
* For historical reasons, most casts to TEXT are implicit. This is BAD * We need entries here only for a few specialized cases where the behavior
* and should be reined in. * 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 ( 20 25 1289 i )); DATA(insert ( 650 25 730 a ));
DATA(insert ( 25 20 1290 e )); DATA(insert ( 869 25 730 a ));
DATA(insert ( 21 25 113 i )); DATA(insert ( 16 25 2971 a ));
DATA(insert ( 25 21 818 e )); DATA(insert ( 142 25 2922 a ));
DATA(insert ( 23 25 112 i ));
DATA(insert ( 25 23 819 e ));
DATA(insert ( 26 25 114 i ));
DATA(insert ( 25 26 817 e ));
DATA(insert ( 25 650 1714 e ));
DATA(insert ( 700 25 841 i ));
DATA(insert ( 25 700 839 e ));
DATA(insert ( 701 25 840 i ));
DATA(insert ( 25 701 838 e ));
DATA(insert ( 829 25 752 e ));
DATA(insert ( 25 829 767 e ));
DATA(insert ( 650 25 730 e ));
DATA(insert ( 869 25 730 e ));
DATA(insert ( 25 869 1713 e ));
DATA(insert ( 1082 25 749 i ));
DATA(insert ( 25 1082 748 e ));
DATA(insert ( 1083 25 948 i ));
DATA(insert ( 25 1083 837 e ));
DATA(insert ( 1114 25 2034 i ));
DATA(insert ( 25 1114 2022 e ));
DATA(insert ( 1184 25 1192 i ));
DATA(insert ( 25 1184 1191 e ));
DATA(insert ( 1186 25 1193 i ));
DATA(insert ( 25 1186 1263 e ));
DATA(insert ( 1266 25 939 i ));
DATA(insert ( 25 1266 938 e ));
DATA(insert ( 1700 25 1688 i ));
DATA(insert ( 25 1700 1686 e ));
DATA(insert ( 142 25 2922 e ));
DATA(insert ( 25 142 2896 e )); DATA(insert ( 25 142 2896 e ));
DATA(insert ( 16 25 2971 e ));
DATA(insert ( 25 16 2970 e ));
/* /*
* Cross-category casts to and from VARCHAR * Cross-category casts to and from VARCHAR
* *
* We support all the same casts as for TEXT, but none are implicit. * We support all the same casts as for TEXT.
*/ */
DATA(insert ( 20 1043 1289 a )); DATA(insert ( 650 1043 730 a ));
DATA(insert ( 1043 20 1290 e )); DATA(insert ( 869 1043 730 a ));
DATA(insert ( 21 1043 113 a )); DATA(insert ( 16 1043 2971 a ));
DATA(insert ( 1043 21 818 e )); DATA(insert ( 142 1043 2922 a ));
DATA(insert ( 23 1043 112 a ));
DATA(insert ( 1043 23 819 e ));
DATA(insert ( 26 1043 114 a ));
DATA(insert ( 1043 26 817 e ));
DATA(insert ( 1043 650 1714 e ));
DATA(insert ( 700 1043 841 a ));
DATA(insert ( 1043 700 839 e ));
DATA(insert ( 701 1043 840 a ));
DATA(insert ( 1043 701 838 e ));
DATA(insert ( 829 1043 752 e ));
DATA(insert ( 1043 829 767 e ));
DATA(insert ( 650 1043 730 e ));
DATA(insert ( 869 1043 730 e ));
DATA(insert ( 1043 869 1713 e ));
DATA(insert ( 1082 1043 749 a ));
DATA(insert ( 1043 1082 748 e ));
DATA(insert ( 1083 1043 948 a ));
DATA(insert ( 1043 1083 837 e ));
DATA(insert ( 1114 1043 2034 a ));
DATA(insert ( 1043 1114 2022 e ));
DATA(insert ( 1184 1043 1192 a ));
DATA(insert ( 1043 1184 1191 e ));
DATA(insert ( 1186 1043 1193 a ));
DATA(insert ( 1043 1186 1263 e ));
DATA(insert ( 1266 1043 939 a ));
DATA(insert ( 1043 1266 938 e ));
DATA(insert ( 1700 1043 1688 a ));
DATA(insert ( 1043 1700 1686 e ));
DATA(insert ( 142 1043 2922 e ));
DATA(insert ( 1043 142 2896 e )); DATA(insert ( 1043 142 2896 e ));
DATA(insert ( 16 1043 2971 e ));
DATA(insert ( 1043 16 2970 e ));
/* /*
* Cross-category casts to and from BPCHAR * Cross-category casts to and from BPCHAR
* *
* A function supporting cast to TEXT/VARCHAR can be used for cast to BPCHAR, * We support all the same casts as for TEXT.
* but the other direction is okay only if the function treats trailing
* blanks as insignificant. So this is a subset of the VARCHAR list.
* (Arguably the holdouts should be fixed, but I'm not doing that now...)
*/ */
DATA(insert ( 20 1042 1289 a )); DATA(insert ( 650 1042 730 a ));
DATA(insert ( 1042 20 1290 e )); DATA(insert ( 869 1042 730 a ));
DATA(insert ( 21 1042 113 a )); DATA(insert ( 16 1042 2971 a ));
DATA(insert ( 1042 21 818 e )); DATA(insert ( 142 1042 2922 a ));
DATA(insert ( 23 1042 112 a )); DATA(insert ( 1042 142 2896 e ));
DATA(insert ( 1042 23 819 e ));
DATA(insert ( 26 1042 114 a ));
DATA(insert ( 1042 26 817 e ));
DATA(insert ( 700 1042 841 a ));
DATA(insert ( 1042 700 839 e ));
DATA(insert ( 701 1042 840 a ));
DATA(insert ( 1042 701 838 e ));
DATA(insert ( 829 1042 752 e ));
DATA(insert ( 1042 829 767 e ));
DATA(insert ( 650 1042 730 e ));
DATA(insert ( 869 1042 730 e ));
DATA(insert ( 1082 1042 749 a ));
DATA(insert ( 1042 1082 748 e ));
DATA(insert ( 1083 1042 948 a ));
DATA(insert ( 1042 1083 837 e ));
DATA(insert ( 1114 1042 2034 a ));
DATA(insert ( 1042 1114 2022 e ));
DATA(insert ( 1184 1042 1192 a ));
DATA(insert ( 1042 1184 1191 e ));
DATA(insert ( 1186 1042 1193 a ));
DATA(insert ( 1042 1186 1263 e ));
DATA(insert ( 1266 1042 939 a ));
DATA(insert ( 1042 1266 938 e ));
DATA(insert ( 1700 1042 1688 a ));
DATA(insert ( 1042 1700 1686 e ));
DATA(insert ( 142 1042 2922 e ));
/* /*
* Length-coercion functions * Length-coercion functions
...@@ -401,16 +317,4 @@ DATA(insert ( 1560 1560 1685 i )); ...@@ -401,16 +317,4 @@ DATA(insert ( 1560 1560 1685 i ));
DATA(insert ( 1562 1562 1687 i )); DATA(insert ( 1562 1562 1687 i ));
DATA(insert ( 1700 1700 1703 i )); DATA(insert ( 1700 1700 1703 i ));
/* casts to and from uuid */
DATA(insert ( 25 2950 2964 a ));
DATA(insert ( 2950 25 2965 a ));
DATA(insert ( 1043 2950 2964 a ));
DATA(insert ( 2950 1043 2965 a ));
/*
* enums
*/
DATA(insert ( 3500 25 3532 e ));
DATA(insert ( 25 3500 3533 e ));
#endif /* PG_CAST_H */ #endif /* PG_CAST_H */
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.175 2007/05/21 17:57:34 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.176 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -637,6 +637,19 @@ typedef struct FieldStoreState ...@@ -637,6 +637,19 @@ typedef struct FieldStoreState
TupleDesc argdesc; /* tupdesc for most recent input */ TupleDesc argdesc; /* tupdesc for most recent input */
} FieldStoreState; } FieldStoreState;
/* ----------------
* CoerceViaIOState node
* ----------------
*/
typedef struct CoerceViaIOState
{
ExprState xprstate;
ExprState *arg; /* input expression */
FmgrInfo outfunc; /* lookup info for source output function */
FmgrInfo infunc; /* lookup info for result input function */
Oid intypioparam; /* argument needed for input function */
} CoerceViaIOState;
/* ---------------- /* ----------------
* ArrayCoerceExprState node * ArrayCoerceExprState node
* ---------------- * ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.199 2007/04/26 16:13:14 neilc Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.200 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -121,6 +121,7 @@ typedef enum NodeTag ...@@ -121,6 +121,7 @@ typedef enum NodeTag
T_FieldSelect, T_FieldSelect,
T_FieldStore, T_FieldStore,
T_RelabelType, T_RelabelType,
T_CoerceViaIO,
T_ArrayCoerceExpr, T_ArrayCoerceExpr,
T_ConvertRowtypeExpr, T_ConvertRowtypeExpr,
T_CaseExpr, T_CaseExpr,
...@@ -160,6 +161,7 @@ typedef enum NodeTag ...@@ -160,6 +161,7 @@ typedef enum NodeTag
T_SubPlanState, T_SubPlanState,
T_FieldSelectState, T_FieldSelectState,
T_FieldStoreState, T_FieldStoreState,
T_CoerceViaIOState,
T_ArrayCoerceExprState, T_ArrayCoerceExprState,
T_ConvertRowtypeExprState, T_ConvertRowtypeExprState,
T_CaseExprState, T_CaseExprState,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.129 2007/03/27 23:21:12 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.130 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -550,6 +550,24 @@ typedef struct RelabelType ...@@ -550,6 +550,24 @@ typedef struct RelabelType
CoercionForm relabelformat; /* how to display this node */ CoercionForm relabelformat; /* how to display this node */
} RelabelType; } RelabelType;
/* ----------------
* CoerceViaIO
*
* CoerceViaIO represents a type coercion between two types whose textual
* representations are compatible, implemented by invoking the source type's
* typoutput function then the destination type's typinput function.
* ----------------
*/
typedef struct CoerceViaIO
{
Expr xpr;
Expr *arg; /* input expression */
Oid resulttype; /* output type of coercion */
/* output typmod is not stored, but is presumed -1 */
CoercionForm coerceformat; /* how to display this node */
} CoerceViaIO;
/* ---------------- /* ----------------
* ArrayCoerceExpr * ArrayCoerceExpr
* *
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.70 2007/03/27 23:21:12 tgl Exp $ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.71 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
/* Type categories (kluge ... ought to be extensible) */
typedef enum CATEGORY typedef enum CATEGORY
{ {
INVALID_TYPE, INVALID_TYPE,
...@@ -33,6 +34,16 @@ typedef enum CATEGORY ...@@ -33,6 +34,16 @@ typedef enum CATEGORY
USER_TYPE USER_TYPE
} CATEGORY; } CATEGORY;
/* Result codes for find_coercion_pathway */
typedef enum CoercionPathType
{
COERCION_PATH_NONE, /* failed to find any coercion pathway */
COERCION_PATH_FUNC, /* apply the specified coercion function */
COERCION_PATH_RELABELTYPE, /* binary-compatible cast, no function */
COERCION_PATH_ARRAYCOERCE, /* need an ArrayCoerceExpr node */
COERCION_PATH_COERCEVIAIO /* need a CoerceViaIO node */
} CoercionPathType;
extern bool IsBinaryCoercible(Oid srctype, Oid targettype); extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
extern bool IsPreferredType(CATEGORY category, Oid type); extern bool IsPreferredType(CATEGORY category, Oid type);
...@@ -75,10 +86,11 @@ extern Oid resolve_generic_type(Oid declared_type, ...@@ -75,10 +86,11 @@ extern Oid resolve_generic_type(Oid declared_type,
Oid context_actual_type, Oid context_actual_type,
Oid context_declared_type); Oid context_declared_type);
extern bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, extern CoercionPathType find_coercion_pathway(Oid targetTypeId,
CoercionContext ccontext, Oid sourceTypeId,
Oid *funcid, bool *arrayCoerce); CoercionContext ccontext,
extern bool find_typmod_coercion_function(Oid typeId, Oid *funcid);
Oid *funcid, bool *arrayCoerce); extern CoercionPathType find_typmod_coercion_function(Oid typeId,
Oid *funcid);
#endif /* PARSE_COERCE_H */ #endif /* PARSE_COERCE_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.294 2007/06/01 23:40:19 neilc Exp $ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.295 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -71,7 +71,6 @@ extern Datum boolout(PG_FUNCTION_ARGS); ...@@ -71,7 +71,6 @@ extern Datum boolout(PG_FUNCTION_ARGS);
extern Datum boolrecv(PG_FUNCTION_ARGS); extern Datum boolrecv(PG_FUNCTION_ARGS);
extern Datum boolsend(PG_FUNCTION_ARGS); extern Datum boolsend(PG_FUNCTION_ARGS);
extern Datum booltext(PG_FUNCTION_ARGS); extern Datum booltext(PG_FUNCTION_ARGS);
extern Datum textbool(PG_FUNCTION_ARGS);
extern Datum booleq(PG_FUNCTION_ARGS); extern Datum booleq(PG_FUNCTION_ARGS);
extern Datum boolne(PG_FUNCTION_ARGS); extern Datum boolne(PG_FUNCTION_ARGS);
extern Datum boollt(PG_FUNCTION_ARGS); extern Datum boollt(PG_FUNCTION_ARGS);
...@@ -115,8 +114,6 @@ extern Datum enum_ne(PG_FUNCTION_ARGS); ...@@ -115,8 +114,6 @@ extern Datum enum_ne(PG_FUNCTION_ARGS);
extern Datum enum_ge(PG_FUNCTION_ARGS); extern Datum enum_ge(PG_FUNCTION_ARGS);
extern Datum enum_gt(PG_FUNCTION_ARGS); extern Datum enum_gt(PG_FUNCTION_ARGS);
extern Datum enum_cmp(PG_FUNCTION_ARGS); extern Datum enum_cmp(PG_FUNCTION_ARGS);
extern Datum enum_text(PG_FUNCTION_ARGS);
extern Datum text_enum(PG_FUNCTION_ARGS);
extern Datum enum_smaller(PG_FUNCTION_ARGS); extern Datum enum_smaller(PG_FUNCTION_ARGS);
extern Datum enum_larger(PG_FUNCTION_ARGS); extern Datum enum_larger(PG_FUNCTION_ARGS);
extern Datum enum_first(PG_FUNCTION_ARGS); extern Datum enum_first(PG_FUNCTION_ARGS);
...@@ -140,12 +137,8 @@ extern Datum int4recv(PG_FUNCTION_ARGS); ...@@ -140,12 +137,8 @@ extern Datum int4recv(PG_FUNCTION_ARGS);
extern Datum int4send(PG_FUNCTION_ARGS); extern Datum int4send(PG_FUNCTION_ARGS);
extern Datum i2toi4(PG_FUNCTION_ARGS); extern Datum i2toi4(PG_FUNCTION_ARGS);
extern Datum i4toi2(PG_FUNCTION_ARGS); extern Datum i4toi2(PG_FUNCTION_ARGS);
extern Datum int2_text(PG_FUNCTION_ARGS);
extern Datum text_int2(PG_FUNCTION_ARGS);
extern Datum int4_bool(PG_FUNCTION_ARGS); extern Datum int4_bool(PG_FUNCTION_ARGS);
extern Datum bool_int4(PG_FUNCTION_ARGS); extern Datum bool_int4(PG_FUNCTION_ARGS);
extern Datum int4_text(PG_FUNCTION_ARGS);
extern Datum text_int4(PG_FUNCTION_ARGS);
extern Datum int4eq(PG_FUNCTION_ARGS); extern Datum int4eq(PG_FUNCTION_ARGS);
extern Datum int4ne(PG_FUNCTION_ARGS); extern Datum int4ne(PG_FUNCTION_ARGS);
extern Datum int4lt(PG_FUNCTION_ARGS); extern Datum int4lt(PG_FUNCTION_ARGS);
...@@ -334,10 +327,6 @@ extern Datum i4tof(PG_FUNCTION_ARGS); ...@@ -334,10 +327,6 @@ extern Datum i4tof(PG_FUNCTION_ARGS);
extern Datum i2tof(PG_FUNCTION_ARGS); extern Datum i2tof(PG_FUNCTION_ARGS);
extern Datum ftoi4(PG_FUNCTION_ARGS); extern Datum ftoi4(PG_FUNCTION_ARGS);
extern Datum ftoi2(PG_FUNCTION_ARGS); extern Datum ftoi2(PG_FUNCTION_ARGS);
extern Datum text_float8(PG_FUNCTION_ARGS);
extern Datum text_float4(PG_FUNCTION_ARGS);
extern Datum float8_text(PG_FUNCTION_ARGS);
extern Datum float4_text(PG_FUNCTION_ARGS);
extern Datum dround(PG_FUNCTION_ARGS); extern Datum dround(PG_FUNCTION_ARGS);
extern Datum dceil(PG_FUNCTION_ARGS); extern Datum dceil(PG_FUNCTION_ARGS);
extern Datum dfloor(PG_FUNCTION_ARGS); extern Datum dfloor(PG_FUNCTION_ARGS);
...@@ -446,8 +435,6 @@ extern Datum oidge(PG_FUNCTION_ARGS); ...@@ -446,8 +435,6 @@ extern Datum oidge(PG_FUNCTION_ARGS);
extern Datum oidgt(PG_FUNCTION_ARGS); extern Datum oidgt(PG_FUNCTION_ARGS);
extern Datum oidlarger(PG_FUNCTION_ARGS); extern Datum oidlarger(PG_FUNCTION_ARGS);
extern Datum oidsmaller(PG_FUNCTION_ARGS); extern Datum oidsmaller(PG_FUNCTION_ARGS);
extern Datum oid_text(PG_FUNCTION_ARGS);
extern Datum text_oid(PG_FUNCTION_ARGS);
extern Datum oidvectorin(PG_FUNCTION_ARGS); extern Datum oidvectorin(PG_FUNCTION_ARGS);
extern Datum oidvectorout(PG_FUNCTION_ARGS); extern Datum oidvectorout(PG_FUNCTION_ARGS);
extern Datum oidvectorrecv(PG_FUNCTION_ARGS); extern Datum oidvectorrecv(PG_FUNCTION_ARGS);
...@@ -782,8 +769,6 @@ extern Datum network_show(PG_FUNCTION_ARGS); ...@@ -782,8 +769,6 @@ extern Datum network_show(PG_FUNCTION_ARGS);
extern Datum inet_abbrev(PG_FUNCTION_ARGS); extern Datum inet_abbrev(PG_FUNCTION_ARGS);
extern Datum cidr_abbrev(PG_FUNCTION_ARGS); extern Datum cidr_abbrev(PG_FUNCTION_ARGS);
extern double convert_network_to_scalar(Datum value, Oid typid); extern double convert_network_to_scalar(Datum value, Oid typid);
extern Datum text_cidr(PG_FUNCTION_ARGS);
extern Datum text_inet(PG_FUNCTION_ARGS);
extern Datum inet_to_cidr(PG_FUNCTION_ARGS); extern Datum inet_to_cidr(PG_FUNCTION_ARGS);
extern Datum inet_set_masklen(PG_FUNCTION_ARGS); extern Datum inet_set_masklen(PG_FUNCTION_ARGS);
extern Datum cidr_set_masklen(PG_FUNCTION_ARGS); extern Datum cidr_set_masklen(PG_FUNCTION_ARGS);
...@@ -814,8 +799,6 @@ extern Datum macaddr_ge(PG_FUNCTION_ARGS); ...@@ -814,8 +799,6 @@ extern Datum macaddr_ge(PG_FUNCTION_ARGS);
extern Datum macaddr_gt(PG_FUNCTION_ARGS); extern Datum macaddr_gt(PG_FUNCTION_ARGS);
extern Datum macaddr_ne(PG_FUNCTION_ARGS); extern Datum macaddr_ne(PG_FUNCTION_ARGS);
extern Datum macaddr_trunc(PG_FUNCTION_ARGS); extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
extern Datum macaddr_text(PG_FUNCTION_ARGS);
extern Datum text_macaddr(PG_FUNCTION_ARGS);
extern Datum hashmacaddr(PG_FUNCTION_ARGS); extern Datum hashmacaddr(PG_FUNCTION_ARGS);
/* numeric.c */ /* numeric.c */
...@@ -866,8 +849,6 @@ extern Datum numeric_float8(PG_FUNCTION_ARGS); ...@@ -866,8 +849,6 @@ extern Datum numeric_float8(PG_FUNCTION_ARGS);
extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS);
extern Datum float4_numeric(PG_FUNCTION_ARGS); extern Datum float4_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_float4(PG_FUNCTION_ARGS); extern Datum numeric_float4(PG_FUNCTION_ARGS);
extern Datum text_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_text(PG_FUNCTION_ARGS);
extern Datum numeric_accum(PG_FUNCTION_ARGS); extern Datum numeric_accum(PG_FUNCTION_ARGS);
extern Datum numeric_avg_accum(PG_FUNCTION_ARGS); extern Datum numeric_avg_accum(PG_FUNCTION_ARGS);
extern Datum int2_accum(PG_FUNCTION_ARGS); extern Datum int2_accum(PG_FUNCTION_ARGS);
...@@ -970,7 +951,5 @@ extern Datum uuid_gt(PG_FUNCTION_ARGS); ...@@ -970,7 +951,5 @@ extern Datum uuid_gt(PG_FUNCTION_ARGS);
extern Datum uuid_ne(PG_FUNCTION_ARGS); extern Datum uuid_ne(PG_FUNCTION_ARGS);
extern Datum uuid_cmp(PG_FUNCTION_ARGS); extern Datum uuid_cmp(PG_FUNCTION_ARGS);
extern Datum uuid_hash(PG_FUNCTION_ARGS); extern Datum uuid_hash(PG_FUNCTION_ARGS);
extern Datum text_uuid(PG_FUNCTION_ARGS);
extern Datum uuid_text(PG_FUNCTION_ARGS);
#endif /* BUILTINS_H */ #endif /* BUILTINS_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/date.h,v 1.36 2007/01/05 22:19:59 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/date.h,v 1.37 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -133,8 +133,6 @@ extern Datum date_timestamptz(PG_FUNCTION_ARGS); ...@@ -133,8 +133,6 @@ extern Datum date_timestamptz(PG_FUNCTION_ARGS);
extern Datum timestamptz_date(PG_FUNCTION_ARGS); extern Datum timestamptz_date(PG_FUNCTION_ARGS);
extern Datum datetime_timestamp(PG_FUNCTION_ARGS); extern Datum datetime_timestamp(PG_FUNCTION_ARGS);
extern Datum abstime_date(PG_FUNCTION_ARGS); extern Datum abstime_date(PG_FUNCTION_ARGS);
extern Datum text_date(PG_FUNCTION_ARGS);
extern Datum date_text(PG_FUNCTION_ARGS);
extern Datum time_in(PG_FUNCTION_ARGS); extern Datum time_in(PG_FUNCTION_ARGS);
extern Datum time_out(PG_FUNCTION_ARGS); extern Datum time_out(PG_FUNCTION_ARGS);
...@@ -158,8 +156,6 @@ extern Datum timestamp_time(PG_FUNCTION_ARGS); ...@@ -158,8 +156,6 @@ extern Datum timestamp_time(PG_FUNCTION_ARGS);
extern Datum timestamptz_time(PG_FUNCTION_ARGS); extern Datum timestamptz_time(PG_FUNCTION_ARGS);
extern Datum time_interval(PG_FUNCTION_ARGS); extern Datum time_interval(PG_FUNCTION_ARGS);
extern Datum interval_time(PG_FUNCTION_ARGS); extern Datum interval_time(PG_FUNCTION_ARGS);
extern Datum text_time(PG_FUNCTION_ARGS);
extern Datum time_text(PG_FUNCTION_ARGS);
extern Datum time_pl_interval(PG_FUNCTION_ARGS); extern Datum time_pl_interval(PG_FUNCTION_ARGS);
extern Datum time_mi_interval(PG_FUNCTION_ARGS); extern Datum time_mi_interval(PG_FUNCTION_ARGS);
extern Datum time_part(PG_FUNCTION_ARGS); extern Datum time_part(PG_FUNCTION_ARGS);
...@@ -186,8 +182,6 @@ extern Datum timetz_time(PG_FUNCTION_ARGS); ...@@ -186,8 +182,6 @@ extern Datum timetz_time(PG_FUNCTION_ARGS);
extern Datum time_timetz(PG_FUNCTION_ARGS); extern Datum time_timetz(PG_FUNCTION_ARGS);
extern Datum timestamptz_timetz(PG_FUNCTION_ARGS); extern Datum timestamptz_timetz(PG_FUNCTION_ARGS);
extern Datum datetimetz_timestamptz(PG_FUNCTION_ARGS); extern Datum datetimetz_timestamptz(PG_FUNCTION_ARGS);
extern Datum text_timetz(PG_FUNCTION_ARGS);
extern Datum timetz_text(PG_FUNCTION_ARGS);
extern Datum timetz_part(PG_FUNCTION_ARGS); extern Datum timetz_part(PG_FUNCTION_ARGS);
extern Datum timetz_zone(PG_FUNCTION_ARGS); extern Datum timetz_zone(PG_FUNCTION_ARGS);
extern Datum timetz_izone(PG_FUNCTION_ARGS); extern Datum timetz_izone(PG_FUNCTION_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.46 2007/01/05 22:19:59 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.47 2007/06/05 21:31:08 tgl Exp $
* *
* NOTES * NOTES
* These data types are supported on all 64-bit architectures, and may * These data types are supported on all 64-bit architectures, and may
...@@ -111,9 +111,6 @@ extern Datum ftoi8(PG_FUNCTION_ARGS); ...@@ -111,9 +111,6 @@ extern Datum ftoi8(PG_FUNCTION_ARGS);
extern Datum i8tooid(PG_FUNCTION_ARGS); extern Datum i8tooid(PG_FUNCTION_ARGS);
extern Datum oidtoi8(PG_FUNCTION_ARGS); extern Datum oidtoi8(PG_FUNCTION_ARGS);
extern Datum int8_text(PG_FUNCTION_ARGS);
extern Datum text_int8(PG_FUNCTION_ARGS);
extern Datum generate_series_int8(PG_FUNCTION_ARGS); extern Datum generate_series_int8(PG_FUNCTION_ARGS);
extern Datum generate_series_step_int8(PG_FUNCTION_ARGS); extern Datum generate_series_step_int8(PG_FUNCTION_ARGS);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.69 2007/04/30 21:01:53 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.70 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -252,10 +252,6 @@ extern Datum interval_justify_interval(PG_FUNCTION_ARGS); ...@@ -252,10 +252,6 @@ extern Datum interval_justify_interval(PG_FUNCTION_ARGS);
extern Datum interval_justify_hours(PG_FUNCTION_ARGS); extern Datum interval_justify_hours(PG_FUNCTION_ARGS);
extern Datum interval_justify_days(PG_FUNCTION_ARGS); extern Datum interval_justify_days(PG_FUNCTION_ARGS);
extern Datum timestamp_text(PG_FUNCTION_ARGS);
extern Datum text_timestamp(PG_FUNCTION_ARGS);
extern Datum interval_text(PG_FUNCTION_ARGS);
extern Datum text_interval(PG_FUNCTION_ARGS);
extern Datum timestamp_trunc(PG_FUNCTION_ARGS); extern Datum timestamp_trunc(PG_FUNCTION_ARGS);
extern Datum interval_trunc(PG_FUNCTION_ARGS); extern Datum interval_trunc(PG_FUNCTION_ARGS);
extern Datum timestamp_part(PG_FUNCTION_ARGS); extern Datum timestamp_part(PG_FUNCTION_ARGS);
...@@ -291,8 +287,6 @@ extern Datum timestamp_mi_interval(PG_FUNCTION_ARGS); ...@@ -291,8 +287,6 @@ extern Datum timestamp_mi_interval(PG_FUNCTION_ARGS);
extern Datum timestamp_age(PG_FUNCTION_ARGS); extern Datum timestamp_age(PG_FUNCTION_ARGS);
extern Datum overlaps_timestamp(PG_FUNCTION_ARGS); extern Datum overlaps_timestamp(PG_FUNCTION_ARGS);
extern Datum timestamptz_text(PG_FUNCTION_ARGS);
extern Datum text_timestamptz(PG_FUNCTION_ARGS);
extern Datum timestamptz_pl_interval(PG_FUNCTION_ARGS); extern Datum timestamptz_pl_interval(PG_FUNCTION_ARGS);
extern Datum timestamptz_mi_interval(PG_FUNCTION_ARGS); extern Datum timestamptz_mi_interval(PG_FUNCTION_ARGS);
extern Datum timestamptz_age(PG_FUNCTION_ARGS); extern Datum timestamptz_age(PG_FUNCTION_ARGS);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.196 2007/04/29 01:21:09 neilc Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.197 2007/06/05 21:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -4610,6 +4610,9 @@ exec_simple_check_node(Node *node) ...@@ -4610,6 +4610,9 @@ exec_simple_check_node(Node *node)
case T_RelabelType: case T_RelabelType:
return exec_simple_check_node((Node *) ((RelabelType *) node)->arg); return exec_simple_check_node((Node *) ((RelabelType *) node)->arg);
case T_CoerceViaIO:
return exec_simple_check_node((Node *) ((CoerceViaIO *) node)->arg);
case T_ArrayCoerceExpr: case T_ArrayCoerceExpr:
return exec_simple_check_node((Node *) ((ArrayCoerceExpr *) node)->arg); return exec_simple_check_node((Node *) ((ArrayCoerceExpr *) node)->arg);
......
...@@ -1125,10 +1125,12 @@ ALTER TABLE fktable ADD CONSTRAINT fk_3_1 ...@@ -1125,10 +1125,12 @@ ALTER TABLE fktable ADD CONSTRAINT fk_3_1
FOREIGN KEY (x3) REFERENCES pktable(id1); FOREIGN KEY (x3) REFERENCES pktable(id1);
ERROR: foreign key constraint "fk_3_1" cannot be implemented ERROR: foreign key constraint "fk_3_1" cannot be implemented
DETAIL: Key columns "x3" and "id1" are of incompatible types: real and integer. DETAIL: Key columns "x3" and "id1" are of incompatible types: real and integer.
-- should succeed -- int4 does not promote to text
-- int4 promotes to text, so this is allowed (though pretty durn debatable)
ALTER TABLE fktable ADD CONSTRAINT fk_1_2 ALTER TABLE fktable ADD CONSTRAINT fk_1_2
FOREIGN KEY (x1) REFERENCES pktable(id2); FOREIGN KEY (x1) REFERENCES pktable(id2);
ERROR: foreign key constraint "fk_1_2" cannot be implemented
DETAIL: Key columns "x1" and "id2" are of incompatible types: integer and character varying.
-- should succeed
-- int4 promotes to real -- int4 promotes to real
ALTER TABLE fktable ADD CONSTRAINT fk_1_3 ALTER TABLE fktable ADD CONSTRAINT fk_1_3
FOREIGN KEY (x1) REFERENCES pktable(id3); FOREIGN KEY (x1) REFERENCES pktable(id3);
...@@ -1150,7 +1152,7 @@ FOREIGN KEY (x2,x5,x3) REFERENCES pktable(id2,id1,id3); ...@@ -1150,7 +1152,7 @@ FOREIGN KEY (x2,x5,x3) REFERENCES pktable(id2,id1,id3);
ALTER TABLE fktable ADD CONSTRAINT fk_123_231 ALTER TABLE fktable ADD CONSTRAINT fk_123_231
FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id2,id3,id1); FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id2,id3,id1);
ERROR: foreign key constraint "fk_123_231" cannot be implemented ERROR: foreign key constraint "fk_123_231" cannot be implemented
DETAIL: Key columns "x2" and "id3" are of incompatible types: character varying and real. DETAIL: Key columns "x1" and "id2" are of incompatible types: integer and character varying.
ALTER TABLE fktable ADD CONSTRAINT fk_241_132 ALTER TABLE fktable ADD CONSTRAINT fk_241_132
FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2); FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2);
ERROR: foreign key constraint "fk_241_132" cannot be implemented ERROR: foreign key constraint "fk_241_132" cannot be implemented
...@@ -1162,7 +1164,6 @@ NOTICE: drop cascades to constraint fk_123_123 on table fktable ...@@ -1162,7 +1164,6 @@ NOTICE: drop cascades to constraint fk_123_123 on table fktable
NOTICE: drop cascades to constraint fk_5_1 on table fktable NOTICE: drop cascades to constraint fk_5_1 on table fktable
NOTICE: drop cascades to constraint fktable_x1_fkey on table fktable NOTICE: drop cascades to constraint fktable_x1_fkey on table fktable
NOTICE: drop cascades to constraint fk_4_2 on table fktable NOTICE: drop cascades to constraint fk_4_2 on table fktable
NOTICE: drop cascades to constraint fk_1_2 on table fktable
NOTICE: drop cascades to constraint fktable_x2_fkey on table fktable NOTICE: drop cascades to constraint fktable_x2_fkey on table fktable
NOTICE: drop cascades to constraint fk_1_3 on table fktable NOTICE: drop cascades to constraint fk_1_3 on table fktable
NOTICE: drop cascades to constraint fktable_x3_fkey on table fktable NOTICE: drop cascades to constraint fktable_x3_fkey on table fktable
......
...@@ -450,7 +450,7 @@ SELECT POSITION('4' IN '1234567890') = '4' AS "4"; ...@@ -450,7 +450,7 @@ SELECT POSITION('4' IN '1234567890') = '4' AS "4";
t t
(1 row) (1 row)
SELECT POSITION(5 IN '1234567890') = '5' AS "5"; SELECT POSITION('5' IN '1234567890') = '5' AS "5";
5 5
--- ---
t t
......
...@@ -354,7 +354,7 @@ create rule shipped_view_insert as on insert to shipped_view do instead ...@@ -354,7 +354,7 @@ create rule shipped_view_insert as on insert to shipped_view do instead
insert into shipped values('wt', new.ordnum, new.partnum, new.value); insert into shipped values('wt', new.ordnum, new.partnum, new.value);
insert into parts (partnum, cost) values (1, 1234.56); insert into parts (partnum, cost) values (1, 1234.56);
insert into shipped_view (ordnum, partnum, value) insert into shipped_view (ordnum, partnum, value)
values (0, 1, (select cost from parts where partnum = 1)); values (0, 1, (select cost from parts where partnum = '1'));
select * from shipped_view; select * from shipped_view;
ttype | ordnum | partnum | value ttype | ordnum | partnum | value
-------+--------+---------+--------- -------+--------+---------+---------
......
...@@ -760,12 +760,12 @@ FOREIGN KEY (x2) REFERENCES pktable(id1); ...@@ -760,12 +760,12 @@ FOREIGN KEY (x2) REFERENCES pktable(id1);
ALTER TABLE fktable ADD CONSTRAINT fk_3_1 ALTER TABLE fktable ADD CONSTRAINT fk_3_1
FOREIGN KEY (x3) REFERENCES pktable(id1); FOREIGN KEY (x3) REFERENCES pktable(id1);
-- should succeed -- int4 does not promote to text
-- int4 promotes to text, so this is allowed (though pretty durn debatable)
ALTER TABLE fktable ADD CONSTRAINT fk_1_2 ALTER TABLE fktable ADD CONSTRAINT fk_1_2
FOREIGN KEY (x1) REFERENCES pktable(id2); FOREIGN KEY (x1) REFERENCES pktable(id2);
-- should succeed
-- int4 promotes to real -- int4 promotes to real
ALTER TABLE fktable ADD CONSTRAINT fk_1_3 ALTER TABLE fktable ADD CONSTRAINT fk_1_3
FOREIGN KEY (x1) REFERENCES pktable(id3); FOREIGN KEY (x1) REFERENCES pktable(id3);
......
...@@ -142,7 +142,7 @@ SELECT regexp_split_to_array('thE QUick bROWn FOx jUMPed ovEr THE lazy dOG', 'e' ...@@ -142,7 +142,7 @@ SELECT regexp_split_to_array('thE QUick bROWn FOx jUMPed ovEr THE lazy dOG', 'e'
-- E021-11 position expression -- E021-11 position expression
SELECT POSITION('4' IN '1234567890') = '4' AS "4"; SELECT POSITION('4' IN '1234567890') = '4' AS "4";
SELECT POSITION(5 IN '1234567890') = '5' AS "5"; SELECT POSITION('5' IN '1234567890') = '5' AS "5";
-- T312 character overlay function -- T312 character overlay function
SELECT OVERLAY('abcdef' PLACING '45' FROM 4) AS "abc45f"; SELECT OVERLAY('abcdef' PLACING '45' FROM 4) AS "abc45f";
......
...@@ -218,7 +218,7 @@ create rule shipped_view_insert as on insert to shipped_view do instead ...@@ -218,7 +218,7 @@ create rule shipped_view_insert as on insert to shipped_view do instead
insert into parts (partnum, cost) values (1, 1234.56); insert into parts (partnum, cost) values (1, 1234.56);
insert into shipped_view (ordnum, partnum, value) insert into shipped_view (ordnum, partnum, value)
values (0, 1, (select cost from parts where partnum = 1)); values (0, 1, (select cost from parts where partnum = '1'));
select * from shipped_view; select * from shipped_view;
......
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