diff --git a/contrib/cube/README.cube b/contrib/cube/README.cube index e83763f68e02849a4b22e93d00df69bbe58b8b43..56b06202dc332c6d142f47b161adc61b2d701b3e 100644 --- a/contrib/cube/README.cube +++ b/contrib/cube/README.cube @@ -236,10 +236,6 @@ cube_distance(cube, cube) returns double cube_distance returns the distance between two cubes. If both cubes are 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 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 diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index f58af9ef6786cde1e620ef8a47876562e55eda72..ec8cb72e3b7d5cf27fb0e5db00caa64965d94296 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -1,5 +1,5 @@ /****************************************************************************** - $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 called by the backend in the process of processing queries. The calling @@ -173,18 +173,6 @@ cube_in(PG_FUNCTION_ARGS) 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 diff --git a/contrib/cube/cube.sql.in b/contrib/cube/cube.sql.in index c1697b0ea97a7d336130715900d5ebfd99f3c160..2e5481280257cb626f73cacbda12530ba0ae1ed0 100644 --- a/contrib/cube/cube.sql.in +++ b/contrib/cube/cube.sql.in @@ -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)'''; --- 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 -- diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out index 4f643573b512196668068de6fcbe81f94aa6a241..86b33483a54f3166635bcc2580a7758aa7af0362 100644 --- a/contrib/cube/expected/cube.out +++ b/contrib/cube/expected/cube.out @@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); -- Test of cube function (text to cube) -- -SELECT cube('('||1||','||1.2||')'); +SELECT cube('(1,1.2)'::text); cube ---------- (1, 1.2) diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out index 49e6c3fa31d0c0ab1aa0a5ee8177fae82cedb9d9..8609c26106209ad2bc5c534e151ca4ad705c2a3f 100644 --- a/contrib/cube/expected/cube_1.out +++ b/contrib/cube/expected/cube_1.out @@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); -- Test of cube function (text to cube) -- -SELECT cube('('||1||','||1.2||')'); +SELECT cube('(1,1.2)'::text); cube ---------- (1, 1.2) diff --git a/contrib/cube/expected/cube_2.out b/contrib/cube/expected/cube_2.out index ff6dbc4e5c74f956357b9790dc9d52744801efd4..d8737c3cb38473db85a6fa5d6a0543e5b79f1602 100644 --- a/contrib/cube/expected/cube_2.out +++ b/contrib/cube/expected/cube_2.out @@ -826,7 +826,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); -- Test of cube function (text to cube) -- -SELECT cube('('||1||','||1.2||')'); +SELECT cube('(1,1.2)'::text); cube ---------- (1, 1.2) diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql index 49d9869c533083125e543f3e31aff15afabb03e1..1931dfbc8037e2daa6ed26ec574bfdcd7be73500 100644 --- a/contrib/cube/sql/cube.sql +++ b/contrib/cube/sql/cube.sql @@ -223,7 +223,7 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); -- Test of cube function (text to cube) -- -SELECT cube('('||1||','||1.2||')'); +SELECT cube('(1,1.2)'::text); SELECT cube(NULL); -- Test of cube_dim function (dimensions stored in cube) diff --git a/contrib/cube/uninstall_cube.sql b/contrib/cube/uninstall_cube.sql index 784138acd58a058f3824fafef8ea512adadef03f..2c5c164565204bbc6fcdb1c7943fdc45b1fe8317 100644 --- a/contrib/cube/uninstall_cube.sql +++ b/contrib/cube/uninstall_cube.sql @@ -92,8 +92,4 @@ DROP FUNCTION cube_ne(cube, cube); DROP FUNCTION cube_eq(cube, cube); -DROP CAST (text AS cube); - -DROP FUNCTION cube(text); - DROP TYPE cube CASCADE; diff --git a/contrib/isn/isn.c b/contrib/isn/isn.c index a4b2ebef9552bd944d5297b8af4d23e900eeb6db..1dfb940e92982d119a680ea72d558b691119dda0 100644 --- a/contrib/isn/isn.c +++ b/contrib/isn/isn.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * * 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", " static bool g_weak = 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) /* 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); Datum isbn_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 */ PG_FUNCTION_INFO_V1(is_valid); diff --git a/contrib/isn/isn.h b/contrib/isn/isn.h index 9606235228ae0f6392e0303b2c3d93c79d62b5d8..2dec9f0555086443cf0dc4904def48a80ab6b0ca 100644 --- a/contrib/isn/isn.h +++ b/contrib/isn/isn.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * * 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); extern Datum issn_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 ismn_cast_from_ean13(PG_FUNCTION_ARGS); extern Datum issn_cast_from_ean13(PG_FUNCTION_ARGS); diff --git a/contrib/isn/isn.sql.in b/contrib/isn/isn.sql.in index 1bae4b01d0bbfce467250ee1bc4d70d870afa025..55af24a9057bc5d61123b673f66b7014200621f6 100644 --- a/contrib/isn/isn.sql.in +++ b/contrib/isn/isn.sql.in @@ -2,7 +2,7 @@ -- PostgreSQL code for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) -- 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: -- create table test ( id isbn ); @@ -2966,73 +2966,6 @@ AS 'MODULE_PATHNAME', 'upc_cast_from_ean13' 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 isbn) WITH FUNCTION isbn(ean13); CREATE CAST (ean13 AS ismn13) WITH FUNCTION ismn13(ean13); @@ -3056,24 +2989,6 @@ CREATE CAST (ismn13 AS ismn) WITHOUT FUNCTION AS ASSIGNMENT; CREATE CAST (issn AS issn13) 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: -- diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 1bf95871c0e323e4a0f49fa13949cb2066769009..aa699ae62e14c43009aa7e805358f0e5ae187f15 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ -<!-- $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 --> @@ -1358,11 +1358,22 @@ </indexterm> <para> - The catalog <structname>pg_cast</structname> stores data type conversion paths, - both built-in paths and those defined with + The catalog <structname>pg_cast</structname> stores data type conversion + paths, both built-in paths and those defined with <xref linkend="sql-createcast" endterm="sql-createcast-title">. </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> <title><structfield>pg_cast</> Columns</title> diff --git a/doc/src/sgml/ref/create_cast.sgml b/doc/src/sgml/ref/create_cast.sgml index c6e944e26ae1de45138cd52e7558384f79055421..c329c36b190cabdb40a83cb810169feeebe4bec1 100644 --- a/doc/src/sgml/ref/create_cast.sgml +++ b/doc/src/sgml/ref/create_cast.sgml @@ -1,4 +1,4 @@ -<!-- $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"> <refmeta> @@ -35,11 +35,11 @@ CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</r specifies how to perform a conversion between two data types. For example: <programlisting> -SELECT CAST(42 AS text); +SELECT CAST(42 AS float8); </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 - <literal>text(int4)</>. (If no suitable cast has been defined, the + <literal>float8(int4)</>. (If no suitable cast has been defined, the conversion fails.) </para> @@ -69,8 +69,7 @@ SELECT CAST(42 AS text); INSERT INTO foo (f1) VALUES (42); </programlisting> will be allowed if the cast from type <type>integer</type> to type - <type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise - not. + <type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise not. (We generally use the term <firstterm>assignment cast</firstterm> to describe this kind of cast.) </para> @@ -78,19 +77,37 @@ INSERT INTO foo (f1) VALUES (42); <para> If the cast is marked <literal>AS IMPLICIT</> then it can be invoked implicitly in any context, whether assignment or internally in an - expression. For example, since <literal>||</> takes <type>text</> - operands, + expression. (We generally use the term <firstterm>implicit + cast</firstterm> to describe this kind of cast.) + For example, consider this query: <programlisting> -SELECT 'The time is ' || now(); +SELECT 2 + 4.0; </programlisting> - will be allowed only if the cast from type <type>timestamp</> to - <type>text</type> is marked <literal>AS IMPLICIT</>. Otherwise it - will be necessary to write the cast explicitly, for example: + The parser initially marks the constants as being of type <type>integer</> + and <type>numeric</> respectively. There is no <type>integer</> + <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</> — + which in fact it is. The parser will apply the implicit cast and resolve + the query as if it had been written <programlisting> -SELECT 'The time is ' || CAST(now() AS text); +SELECT CAST ( 2 AS numeric ) + 4.0; </programlisting> - (We generally use the term <firstterm>implicit - cast</firstterm> to describe this kind of cast.) + </para> + + <para> + Now, the catalogs also provide a cast from <type>numeric</> to + <type>integer</>. If that cast were marked <literal>AS IMPLICIT</> — + which it is not — 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> @@ -208,9 +225,7 @@ SELECT 'The time is ' || CAST(now() AS text); argument. This is used to represent type-specific length coercion 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 - second argument. (Since the grammar presently permits only certain - 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.) + second argument. </para> <para> @@ -237,6 +252,32 @@ SELECT 'The time is ' || CAST(now() AS text); need to declare casts both ways explicitly. </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> Prior to <productname>PostgreSQL</> 7.3, every function that had 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); <note> <para> - There is one small lie in the preceding paragraph: there is still one - case in which <structname>pg_cast</> will be used to resolve the - meaning of an apparent function call. If a - function call <replaceable>name</>(<replaceable>x</>) matches no - actual function, but <replaceable>name</> is the name of a data type - and <structname>pg_cast</> shows a binary-compatible cast to this - type from the type of <replaceable>x</>, then the call will be construed - as an explicit cast. This exception is made so that binary-compatible - casts can be invoked using functional syntax, even though they lack - any function. + Actually the preceding paragraph is an oversimplification: there are + two cases in which a function-call construct will be treated as a cast + request without having matched it to an actual function. + If a function call <replaceable>name</>(<replaceable>x</>) does not + exactly match any existing function, but <replaceable>name</> is the name + of a data type and <structname>pg_cast</> provides a binary-compatible cast + to this type from the type of <replaceable>x</>, then the call will be + construed as a binary-compatible cast. This exception is made so that + binary-compatible casts can be invoked using functional syntax, even + 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> </note> </refsect1> @@ -284,10 +329,10 @@ SELECT 'The time is ' || CAST(now() AS text); <title>Examples</title> <para> - To create a cast from type <type>text</type> to type - <type>int4</type> using the function <literal>int4(text)</literal>: + To create a cast from type <type>bigint</type> to type + <type>int4</type> using the function <literal>int4(bigint)</literal>: <programlisting> -CREATE CAST (text AS int4) WITH FUNCTION int4(text); +CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint); </programlisting> (This cast is already predefined in the system.) </para> diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml index f1b5fe9411e90a6dcbec0106ccdbb9074c759030..a869cd440aa849a945c982ccd80a0edabc831274 100644 --- a/doc/src/sgml/syntax.sgml +++ b/doc/src/sgml/syntax.sgml @@ -1,4 +1,4 @@ -<!-- $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"> <title>SQL Syntax</title> @@ -561,18 +561,18 @@ CAST ( '<replaceable>string</replaceable>' AS <replaceable>type</replaceable> ) The <literal>::</literal>, <literal>CAST()</literal>, and function-call syntaxes can also be used to specify run-time type conversions of arbitrary expressions, as discussed in <xref - linkend="sql-syntax-type-casts">. But the form - <literal><replaceable>type</replaceable> '<replaceable>string</replaceable>'</literal> - can only be used to specify the type of a literal constant. - Another restriction on - <literal><replaceable>type</replaceable> '<replaceable>string</replaceable>'</literal> - is that it does not work for array types; use <literal>::</literal> + linkend="sql-syntax-type-casts">. To avoid syntactic ambiguity, the + <literal><replaceable>type</> '<replaceable>string</>'</literal> + syntax can only be used to specify the type of a simple literal constant. + Another restriction on the + <literal><replaceable>type</> '<replaceable>string</>'</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. </para> <para> 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 for a few data types, but <productname>PostgreSQL</productname> allows it for all types. The syntax with @@ -1431,16 +1431,21 @@ CAST ( <replaceable>expression</replaceable> AS <replaceable>type</replaceable> double-quoted, because of syntactic conflicts. Therefore, the use of the function-like cast syntax leads to inconsistencies and should 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> + + <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 id="sql-syntax-scalar-subqueries"> diff --git a/doc/src/sgml/typeconv.sgml b/doc/src/sgml/typeconv.sgml index af4a8e916cb007a876d1816bc6eec01e501002f6..c5373aa753330cdc379784a7117ea0f637ac1d7c 100644 --- a/doc/src/sgml/typeconv.sgml +++ b/doc/src/sgml/typeconv.sgml @@ -1,4 +1,4 @@ -<!-- $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"> <title>Type Conversion</title> @@ -139,7 +139,8 @@ and for the <function>GREATEST</> and <function>LEAST</> functions. The system catalogs store information about which conversions, called <firstterm>casts</firstterm>, between data types are valid, and how to 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 between the built-in types has been carefully crafted and is best not altered.) @@ -336,28 +337,28 @@ Some examples follow. </para> <example> -<title>Exponentiation Operator Type Resolution</title> +<title>Factorial Operator Type Resolution</title> <para> -There is only one exponentiation -operator defined in the catalog, and it takes arguments of type -<type>double precision</type>. -The scanner assigns an initial type of <type>integer</type> to both arguments -of this query expression: +There is only one factorial operator (postfix <literal>!</>) +defined in the standard catalog, and it takes an argument of type +<type>bigint</type>. +The scanner assigns an initial type of <type>integer</type> to the argument +in this query expression: <screen> -SELECT 2 ^ 3 AS "exp"; +SELECT 40 ! AS "40 factorial"; - exp ------ - 8 + 40 factorial +-------------------------------------------------- + 815915283247897734345611269596115894272000000000 (1 row) </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 <screen> -SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "exp"; +SELECT CAST(40 AS bigint) ! AS "40 factorial"; </screen> </para> </example> @@ -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 entries is for type <type>float8</type>, which is the preferred type in 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> SELECT @ '-4.5' AS "abs"; abs @@ -429,9 +430,9 @@ SELECT @ '-4.5' AS "abs"; 4.5 (1 row) </screen> -Here the system has performed an implicit conversion from <type>text</type> to <type>float8</type> -before applying the chosen operator. We can verify that <type>float8</type> and -not some other type was used: +Here the system has implicitly resolved the unknown-type literal as type +<type>float8</type> before applying the chosen operator. We can verify that +<type>float8</type> and not some other type was used: <screen> SELECT @ '-4.5e500' AS "abs"; @@ -447,8 +448,8 @@ try a similar case with <literal>~</>, we get: SELECT ~ '20' AS "negation"; ERROR: operator is not unique: ~ "unknown" -HINT: Could not choose a best candidate operator. You might need to add explicit -type casts. +HINT: Could not choose a best candidate operator. You might need to add +explicit type casts. </screen> This happens because the system cannot decide which of the several possible <literal>~</> operators should be preferred. We can help @@ -518,12 +519,24 @@ this step.) <step performance="required"> <para> 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) 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 -data type. When these conditions are met, the function argument is converted -to the named data type without any actual function call. +an unknown-type literal, or a type that is binary-compatible with the named +data type, or a type that could be converted to the named data type by +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> </step> <step performance="required"> @@ -670,30 +683,31 @@ The parser learns from the <structname>pg_cast</> catalog that <type>text</type> and <type>varchar</type> are binary-compatible, meaning that one can be passed to a function that 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> </note> </para> <para> -And, if the function is called with an argument of type <type>integer</type>, the parser will -try to convert that to <type>text</type>: +And, if the function is called with an argument of type <type>integer</type>, +the parser will try to convert that to <type>text</type>: <screen> 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 -------- 34 (1 row) </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> </example> diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index e1d5101ae1e5ceb1ffd19d0efe7d0de2442aa3dc..6b58af652289614dbcd99ede204d814d77150d1c 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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, add_object_address(OCLASS_TYPE, relab->resulttype, 0, 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)) { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 50ab3ada237bf39e93480d14c1293637d8625e06..fd54b89f0a5c401d4fdad89a6616a41fe1c76594 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * 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, static Datum ExecEvalRelabelType(GenericExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); @@ -3504,6 +3507,40 @@ ExecEvalRelabelType(GenericExprState *exprstate, 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 * @@ -3850,6 +3887,26 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) gstate; } 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: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 34ef2808fb27a47842cc835d5bf7b325639c699f..39027b1dbc84706eb2cce718360184efadd52c46 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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) 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 */ @@ -3108,6 +3123,9 @@ copyObject(void *from) case T_RelabelType: retval = _copyRelabelType(from); break; + case T_CoerceViaIO: + retval = _copyCoerceViaIO(from); + break; case T_ArrayCoerceExpr: retval = _copyArrayCoerceExpr(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index bd237cd6f4ecd9cf12fe8d543cd9d079cefb3247..8a0957c117e5dad4578e5420e93432aed54d6aee 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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) 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 _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b) { @@ -2052,6 +2070,9 @@ equal(void *a, void *b) case T_RelabelType: retval = _equalRelabelType(a, b); break; + case T_CoerceViaIO: + retval = _equalCoerceViaIO(a, b); + break; case T_ArrayCoerceExpr: retval = _equalArrayCoerceExpr(a, b); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 4bf6764c18ad4fcc820ad4510332b3d34c269901..5de540642f482fa2b14a1ce96abc368ff3f1850f 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * 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 * Every node type that can appear in stored rules' parsetrees *must* @@ -870,6 +870,16 @@ _outRelabelType(StringInfo str, RelabelType *node) 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 _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node) { @@ -2165,6 +2175,9 @@ _outNode(StringInfo str, void *obj) case T_RelabelType: _outRelabelType(str, obj); break; + case T_CoerceViaIO: + _outCoerceViaIO(str, obj); + break; case T_ArrayCoerceExpr: _outArrayCoerceExpr(str, obj); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index be450e94c02f275fe635998103e97ac2629e50f3..86c9e911a7c8dfbdb2fa11b49e06c97c159a9af8 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * 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 * Path and Plan nodes do not have any readfuncs support, because we @@ -584,6 +584,21 @@ _readRelabelType(void) 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 */ @@ -1042,6 +1057,8 @@ parseNodeString(void) return_value = _readFieldStore(); else if (MATCH("RELABELTYPE", 11)) return_value = _readRelabelType(); + else if (MATCH("COERCEVIAIO", 11)) + return_value = _readCoerceViaIO(); else if (MATCH("ARRAYCOERCEEXPR", 15)) return_value = _readArrayCoerceExpr(); else if (MATCH("CONVERTROWTYPEEXPR", 18)) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 55c7648b9e7865042a179a63f2461458b454b755..a4d03e9f8f8d6071386736ec0c935b37092a17ed 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -54,7 +54,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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 @@ #include "optimizer/pathnode.h" #include "optimizer/planmain.h" #include "parser/parsetree.h" +#include "parser/parse_expr.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" #include "utils/tuplesort.h" @@ -1951,6 +1952,22 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context) context->total.per_tuple += get_func_cost(saop->opfuncid) * 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)) { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 5233a338e6fc5a5bd54773e92abf6492cbe500be..00f5f6e2c8175fb067bc77058e9470ec29a8d7c1 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * 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 * AUTHOR DATE MAJOR EVENT @@ -734,6 +734,25 @@ contain_mutable_functions_walker(Node *node, void *context) return true; /* 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)) { ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; @@ -826,6 +845,25 @@ contain_volatile_functions_walker(Node *node, void *context) return true; /* 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)) { ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; @@ -1124,6 +1162,13 @@ find_nonnullable_rels_walker(Node *node, bool 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)) { /* ArrayCoerceExpr is strict at the array level */ @@ -1486,6 +1531,13 @@ strip_implicit_coercions(Node *node) if (r->relabelformat == COERCE_IMPLICIT_CAST) 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)) { ArrayCoerceExpr *c = (ArrayCoerceExpr *) node; @@ -1537,6 +1589,8 @@ set_coercionform_dontcare_walker(Node *node, void *context) ((FuncExpr *) node)->funcformat = COERCE_DONTCARE; else if (IsA(node, RelabelType)) ((RelabelType *) node)->relabelformat = COERCE_DONTCARE; + else if (IsA(node, CoerceViaIO)) + ((CoerceViaIO *) node)->coerceformat = COERCE_DONTCARE; else if (IsA(node, ArrayCoerceExpr)) ((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE; else if (IsA(node, ConvertRowtypeExpr)) @@ -3471,6 +3525,8 @@ expression_tree_walker(Node *node, break; case T_RelabelType: return walker(((RelabelType *) node)->arg, context); + case T_CoerceViaIO: + return walker(((CoerceViaIO *) node)->arg, context); case T_ArrayCoerceExpr: return walker(((ArrayCoerceExpr *) node)->arg, context); case T_ConvertRowtypeExpr: @@ -3959,6 +4015,16 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } 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: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index c232dee4a58dc49af008dcaab5f5afc24e655c70..98cc6691124c0be2a3bb1832044ab1bdc9eb1120 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.153 2007/04/02 03:49:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.154 2007/06/05 21:31:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,9 +37,10 @@ static Node *coerce_type_typmod(Node *node, bool hideInputCoercion); static void hide_coercion_node(Node *node); static Node *build_coercion_expression(Node *node, - Oid funcId, bool arrayCoerce, - Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat, bool isExplicit); + CoercionPathType pathtype, + Oid funcId, + Oid targetTypeId, int32 targetTypMod, + CoercionForm cformat, bool isExplicit); static Node *coerce_record_to_complex(ParseState *pstate, Node *node, Oid targetTypeId, CoercionContext ccontext, @@ -121,8 +122,8 @@ coerce_type(ParseState *pstate, Node *node, CoercionContext ccontext, CoercionForm cformat) { Node *result; + CoercionPathType pathtype; Oid funcId; - bool arrayCoerce; if (targetTypeId == inputTypeId || node == NULL) @@ -280,10 +281,11 @@ coerce_type(ParseState *pstate, Node *node, return (Node *) param; } - if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext, - &funcId, &arrayCoerce)) + pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext, + &funcId); + if (pathtype != COERCION_PATH_NONE) { - if (OidIsValid(funcId) || arrayCoerce) + if (pathtype != COERCION_PATH_RELABELTYPE) { /* * Generate an expression tree representing run-time application @@ -298,7 +300,7 @@ coerce_type(ParseState *pstate, Node *node, baseTypeMod = targetTypeMod; baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod); - result = build_coercion_expression(node, funcId, arrayCoerce, + result = build_coercion_expression(node, pathtype, funcId, baseTypeId, baseTypeMod, cformat, (cformat != COERCE_IMPLICIT_CAST)); @@ -397,8 +399,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, { Oid inputTypeId = input_typeids[i]; Oid targetTypeId = target_typeids[i]; + CoercionPathType pathtype; Oid funcId; - bool arrayCoerce; /* no problem if same type */ if (inputTypeId == targetTypeId) @@ -426,8 +428,9 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, * If pg_cast shows that we can coerce, accept. This test now covers * both binary-compatible and coercion-function cases. */ - if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext, - &funcId, &arrayCoerce)) + pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext, + &funcId); + if (pathtype != COERCION_PATH_NONE) continue; /* @@ -567,8 +570,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, bool isExplicit, bool hideInputCoercion) { + CoercionPathType pathtype; Oid funcId; - bool arrayCoerce; /* * A negative typmod is assumed to mean that no coercion is wanted. Also, @@ -577,14 +580,15 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, if (targetTypMod < 0 || targetTypMod == exprTypmod(node)) return node; - if (find_typmod_coercion_function(targetTypeId, - &funcId, &arrayCoerce)) + pathtype = find_typmod_coercion_function(targetTypeId, &funcId); + + if (pathtype != COERCION_PATH_NONE) { /* Suppress display of nested coercion steps */ if (hideInputCoercion) hide_coercion_node(node); - node = build_coercion_expression(node, funcId, arrayCoerce, + node = build_coercion_expression(node, pathtype, funcId, targetTypeId, targetTypMod, cformat, isExplicit); } @@ -609,6 +613,8 @@ hide_coercion_node(Node *node) ((FuncExpr *) node)->funcformat = COERCE_IMPLICIT_CAST; else if (IsA(node, RelabelType)) ((RelabelType *) node)->relabelformat = COERCE_IMPLICIT_CAST; + else if (IsA(node, CoerceViaIO)) + ((CoerceViaIO *) node)->coerceformat = COERCE_IMPLICIT_CAST; else if (IsA(node, ArrayCoerceExpr)) ((ArrayCoerceExpr *) node)->coerceformat = COERCE_IMPLICIT_CAST; else if (IsA(node, ConvertRowtypeExpr)) @@ -630,7 +636,8 @@ hide_coercion_node(Node *node) */ static Node * build_coercion_expression(Node *node, - Oid funcId, bool arrayCoerce, + CoercionPathType pathtype, + Oid funcId, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, bool isExplicit) { @@ -651,7 +658,7 @@ build_coercion_expression(Node *node, /* * These Asserts essentially check that function is a legal coercion * function. We can't make the seemingly obvious tests on prorettype - * and proargtypes[0], even in the non-arrayCoerce case, because of + * and proargtypes[0], even in the COERCION_PATH_FUNC case, because of * various binary-compatibility cases. */ /* Assert(targetTypeId == procstruct->prorettype); */ @@ -666,26 +673,7 @@ build_coercion_expression(Node *node, ReleaseSysCache(tp); } - if (arrayCoerce) - { - /* We need to build an ArrayCoerceExpr */ - ArrayCoerceExpr *acoerce = makeNode(ArrayCoerceExpr); - - acoerce->arg = (Expr *) node; - acoerce->elemfuncid = funcId; - acoerce->resulttype = targetTypeId; - /* - * Label the output as having a particular typmod only if we are - * really invoking a length-coercion function, ie one with more - * than one argument. - */ - acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; - acoerce->isExplicit = isExplicit; - acoerce->coerceformat = cformat; - - return (Node *) acoerce; - } - else + if (pathtype == COERCION_PATH_FUNC) { /* We build an ordinary FuncExpr with special arguments */ List *args; @@ -723,6 +711,44 @@ build_coercion_expression(Node *node, return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat); } + else if (pathtype == COERCION_PATH_ARRAYCOERCE) + { + /* We need to build an ArrayCoerceExpr */ + ArrayCoerceExpr *acoerce = makeNode(ArrayCoerceExpr); + + acoerce->arg = (Expr *) node; + acoerce->elemfuncid = funcId; + acoerce->resulttype = targetTypeId; + /* + * Label the output as having a particular typmod only if we are + * really invoking a length-coercion function, ie one with more + * than one argument. + */ + acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; + acoerce->isExplicit = isExplicit; + acoerce->coerceformat = cformat; + + return (Node *) acoerce; + } + else if (pathtype == COERCION_PATH_COERCEVIAIO) + { + /* We need to build a CoerceViaIO node */ + CoerceViaIO *iocoerce = makeNode(CoerceViaIO); + + Assert(!OidIsValid(funcId)); + + iocoerce->arg = (Expr *) node; + iocoerce->resulttype = targetTypeId; + iocoerce->coerceformat = cformat; + + return (Node *) iocoerce; + } + else + { + elog(ERROR, "unsupported pathtype %d in build_coercion_expression", + (int) pathtype); + return NULL; /* keep compiler quiet */ + } } @@ -1711,29 +1737,38 @@ IsBinaryCoercible(Oid srctype, Oid targettype) * find_coercion_pathway * Look for a coercion pathway between two types. * + * Currently, this deals only with scalar-type cases; it does not consider + * polymorphic types nor casts between composite types. (Perhaps fold + * those in someday?) + * * ccontext determines the set of available casts. * - * If we find a suitable entry in pg_cast, return TRUE, and set *funcid - * to the castfunc value, which may be InvalidOid for a binary-compatible - * coercion. Also, arrayCoerce is set to indicate whether this is a plain - * or array coercion (if true, funcid actually shows how to coerce the - * array elements). + * The possible result codes are: + * COERCION_PATH_NONE: failed to find any coercion pathway + * *funcid is set to InvalidOid + * COERCION_PATH_FUNC: apply the coercion function returned in *funcid + * COERCION_PATH_RELABELTYPE: binary-compatible cast, no function needed + * *funcid is set to InvalidOid + * COERCION_PATH_ARRAYCOERCE: need an ArrayCoerceExpr node + * *funcid is set to the element cast function, or InvalidOid + * if the array elements are binary-compatible + * COERCION_PATH_COERCEVIAIO: need a CoerceViaIO node + * *funcid is set to InvalidOid * - * NOTE: *funcid == InvalidOid does not necessarily mean that no work is + * Note: COERCION_PATH_RELABELTYPE does not necessarily mean that no work is * needed to do the coercion; if the target is a domain then we may need to * apply domain constraint checking. If you want to check for a zero-effort * conversion then use IsBinaryCoercible(). */ -bool +CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, - Oid *funcid, bool *arrayCoerce) + Oid *funcid) { - bool result = false; + CoercionPathType result = COERCION_PATH_NONE; HeapTuple tuple; *funcid = InvalidOid; - *arrayCoerce = false; /* Perhaps the types are domains; if so, look at their base types */ if (OidIsValid(sourceTypeId)) @@ -1743,7 +1778,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, /* Domains are always coercible to and from their base type */ if (sourceTypeId == targetTypeId) - return true; + return COERCION_PATH_RELABELTYPE; /* Look in pg_cast */ tuple = SearchSysCache(CASTSOURCETARGET, @@ -1779,7 +1814,10 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, if (ccontext >= castcontext) { *funcid = castForm->castfunc; - result = true; + if (OidIsValid(*funcid)) + result = COERCION_PATH_FUNC; + else + result = COERCION_PATH_RELABELTYPE; } ReleaseSysCache(tuple); @@ -1789,7 +1827,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, /* * If there's no pg_cast entry, perhaps we are dealing with a pair of * array types. If so, and if the element types have a suitable cast, - * report that with arrayCoerce = true. + * report that we can coerce with an ArrayCoerceExpr. * * Hack: disallow coercions to oidvector and int2vector, which * otherwise tend to capture coercions that should go to "real" array @@ -1798,25 +1836,30 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * guaranteed to produce an output that meets the restrictions of * these datatypes, such as being 1-dimensional.) */ - Oid targetElemType; - Oid sourceElemType; - Oid elemfuncid; - bool elemarraycoerce; - - if (targetTypeId == OIDVECTOROID || targetTypeId == INT2VECTOROID) - return false; - - if ((targetElemType = get_element_type(targetTypeId)) != InvalidOid && - (sourceElemType = get_element_type(sourceTypeId)) != InvalidOid) + if (targetTypeId != OIDVECTOROID && targetTypeId != INT2VECTOROID) { - if (find_coercion_pathway(targetElemType, sourceElemType, - ccontext, - &elemfuncid, &elemarraycoerce) && - !elemarraycoerce) + Oid targetElem; + Oid sourceElem; + + if ((targetElem = get_element_type(targetTypeId)) != InvalidOid && + (sourceElem = get_element_type(sourceTypeId)) != InvalidOid) { - *funcid = elemfuncid; - *arrayCoerce = true; - result = true; + CoercionPathType elempathtype; + Oid elemfuncid; + + elempathtype = find_coercion_pathway(targetElem, + sourceElem, + ccontext, + &elemfuncid); + if (elempathtype != COERCION_PATH_NONE && + elempathtype != COERCION_PATH_ARRAYCOERCE) + { + *funcid = elemfuncid; + if (elempathtype == COERCION_PATH_COERCEVIAIO) + result = COERCION_PATH_COERCEVIAIO; + else + result = COERCION_PATH_ARRAYCOERCE; + } } } @@ -1826,14 +1869,39 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * mistakenly conclude that ANYENUM-to-some-enum-type is a * trivial cast. */ - if (!result) + if (result == COERCION_PATH_NONE) { if (type_is_enum(sourceTypeId)) result = find_coercion_pathway(targetTypeId, ANYENUMOID, - ccontext, funcid, arrayCoerce); + ccontext, funcid); else if (sourceTypeId != ANYENUMOID && type_is_enum(targetTypeId)) result = find_coercion_pathway(ANYENUMOID, sourceTypeId, - ccontext, funcid, arrayCoerce); + ccontext, funcid); + } + + /* + * If we still haven't found a possibility, consider automatic casting + * using I/O functions. We allow assignment casts to textual types + * and explicit casts from textual types to be handled this way. + * (The CoerceViaIO mechanism is a lot more general than that, but + * this is all we want to allow in the absence of a pg_cast entry.) + * It would probably be better to insist on explicit casts in both + * directions, but this is a compromise to preserve something of the + * pre-8.3 behavior that many types had implicit (yipes!) casts to + * text. + */ + if (result == COERCION_PATH_NONE) + { + if (ccontext >= COERCION_ASSIGNMENT && + (targetTypeId == TEXTOID || + targetTypeId == VARCHAROID || + targetTypeId == BPCHAROID)) + result = COERCION_PATH_COERCEVIAIO; + else if (ccontext >= COERCION_EXPLICIT && + (sourceTypeId == TEXTOID || + sourceTypeId == VARCHAROID || + sourceTypeId == BPCHAROID)) + result = COERCION_PATH_COERCEVIAIO; } } @@ -1851,19 +1919,26 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * * If the given type is a varlena array type, we do not look for a coercion * function associated directly with the array type, but instead look for - * one associated with the element type. If one exists, we report it with - * *arrayCoerce set to true. + * one associated with the element type. An ArrayCoerceExpr node must be + * used to apply such a function. + * + * We use the same result enum as find_coercion_pathway, but the only possible + * result codes are: + * COERCION_PATH_NONE: no length coercion needed + * COERCION_PATH_FUNC: apply the function returned in *funcid + * COERCION_PATH_ARRAYCOERCE: apply the function using ArrayCoerceExpr */ -bool +CoercionPathType find_typmod_coercion_function(Oid typeId, - Oid *funcid, bool *arrayCoerce) + Oid *funcid) { + CoercionPathType result; Type targetType; Form_pg_type typeForm; HeapTuple tuple; *funcid = InvalidOid; - *arrayCoerce = false; + result = COERCION_PATH_FUNC; targetType = typeidType(typeId); typeForm = (Form_pg_type) GETSTRUCT(targetType); @@ -1875,7 +1950,7 @@ find_typmod_coercion_function(Oid typeId, { /* Yes, switch our attention to the element type */ typeId = typeForm->typelem; - *arrayCoerce = true; + result = COERCION_PATH_ARRAYCOERCE; } ReleaseSysCache(targetType); @@ -1893,5 +1968,8 @@ find_typmod_coercion_function(Oid typeId, ReleaseSysCache(tuple); } - return OidIsValid(*funcid); + if (!OidIsValid(*funcid)) + result = COERCION_PATH_NONE; + + return result; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index a0f92f66a64ecf3eefac07f0c71b20c68ca83a09..45107e43acea9abb4d4e1f8552211a80a92e9979 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * 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) case T_FieldSelect: case T_FieldStore: case T_RelabelType: + case T_CoerceViaIO: case T_ArrayCoerceExpr: case T_ConvertRowtypeExpr: case T_CaseTestExpr: @@ -1806,6 +1807,9 @@ exprType(Node *expr) case T_RelabelType: type = ((RelabelType *) expr)->resulttype; break; + case T_CoerceViaIO: + type = ((CoerceViaIO *) expr)->resulttype; + break; case T_ArrayCoerceExpr: type = ((ArrayCoerceExpr *) expr)->resulttype; break; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 01593317b1fce722311e2381b4541450f6723998..5e7a1cccffa92ab6b519f7a3d181aaef39a0666b 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * 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, 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... */ return coerce_type(pstate, linitial(fargs), @@ -669,7 +669,7 @@ func_select_candidate(int nargs, * (exact match) is as quick as possible. * * 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 * from the superclasses of the original input arg types * 3) get a list of all possible argument type arrays to the function @@ -720,29 +720,35 @@ func_get_detail(List *funcname, * If we didn't find an exact match, next consider the possibility * that this is really a type-coercion request: a single-argument * 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 - * needed), then go ahead and treat the "function call" as a coercion. + * if the coercion path is RELABELTYPE or COERCEVIAIO, then go ahead + * and treat the "function call" as a coercion. + * * This interpretation needs to be given higher priority than * interpretations involving a type coercion followed by a function * 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 * entirely capable of selecting. * - * "Trivial" coercions are ones that involve binary-compatible types - * and ones that are coercing a previously-unknown-type literal - * constant to a specific type. + * We also treat a coercion of a previously-unknown-type literal + * constant to a specific type this way. + * + * 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 - * here is that we expect non-binary-compatible coercions to have an - * implementation function named after the target type. That function - * will be found by normal lookup if appropriate. + * The reason we reject COERCION_PATH_ARRAYCOERCE is mainly that + * you can't write "foo[] (something)" as a function call. In theory + * someone might want to invoke it as "_foo (something)" but we have + * 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 - * coerce_type can do, because the caller will try to apply - * coerce_type if we return FUNCDETAIL_COERCION. If we return that - * result for something coerce_type can't handle, we'll cause infinite - * recursion between this module and coerce_type! + * NB: it's important that this code does not exceed what coerce_type + * can do, because the caller will try to apply coerce_type if we + * return FUNCDETAIL_COERCION. If we return that result for something + * coerce_type can't handle, we'll cause infinite recursion between + * this module and coerce_type! */ if (nargs == 1 && fargs != NIL) { @@ -755,16 +761,28 @@ func_get_detail(List *funcname, { Oid sourceType = argtypes[0]; Node *arg1 = linitial(fargs); - Oid cfuncid; - bool arrayCoerce; - - if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) || - (find_coercion_pathway(targetType, sourceType, - COERCION_EXPLICIT, - &cfuncid, &arrayCoerce) && - cfuncid == InvalidOid && !arrayCoerce)) + bool iscoercion; + + if (sourceType == UNKNOWNOID && IsA(arg1, Const)) + { + /* always treat typename('literal') as coercion */ + iscoercion = true; + } + 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; *rettype = targetType; *retset = false; diff --git a/src/backend/utils/Gen_fmgrtab.sh b/src/backend/utils/Gen_fmgrtab.sh index ccd2da3d63fd40f2a7221e6949e59d5bd1c52c83..5543da5a61f9800c3604fb5ea3a9137ddbfb01fb 100644 --- a/src/backend/utils/Gen_fmgrtab.sh +++ b/src/backend/utils/Gen_fmgrtab.sh @@ -9,7 +9,7 @@ # # # 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 * NOTE: macros are named after the prosrc value, ie the actual C name * 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 - * 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, * its equivalent macro will be defined with the lowest OID among those * entries. diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c index e238e131beddcac10b1f8193968888a0d5a06f26..1e44bc1cb56f8358147bc27451540cacbf8d6fe7 100644 --- a/src/backend/utils/adt/bool.c +++ b/src/backend/utils/adt/bool.c @@ -8,7 +8,7 @@ * * * 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) 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 + * + * 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 booltext(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 7e4b461f8f18c8a16a0f9d30b8962f7e7376e9ef..4914736116fa6d0b509ff5402a4eb3b836232d2c 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * 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) } -/* 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 *****************************************************************************/ @@ -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() * Extract specified field from time type. */ @@ -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() * Extract specified field from time type. */ diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index 635d232912ec6861eed5a91b2b23559d3f18eac2..a5506a0c1b365a73c09c8b1a57efe5aa945abdc2 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -7,7 +7,7 @@ * * * 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 @@ #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 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 enum_in(PG_FUNCTION_ARGS) { - char *name = PG_GETARG_CSTRING(0); - 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; + char *name = PG_GETARG_CSTRING(0); + Oid enumtypoid = PG_GETARG_OID(1); Oid enumoid; + HeapTuple tup; /* must check length to prevent Assert failure within SearchSysCache */ - if (strlen(name) >= NAMEDATALEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input value for enum %s: \"%s\"", + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input value for enum %s: \"%s\"", format_type_be(enumtypoid), - name))); + name))); tup = SearchSysCache(ENUMTYPOIDNAME, ObjectIdGetDatum(enumtypoid), CStringGetDatum(name), 0, 0); - if (tup == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input value for enum %s: \"%s\"", + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input value for enum %s: \"%s\"", format_type_be(enumtypoid), - name))); + name))); enumoid = HeapTupleGetOid(tup); ReleaseSysCache(tup); - return enumoid; + + PG_RETURN_OID(enumoid); } Datum enum_out(PG_FUNCTION_ARGS) { - Oid enumoid = PG_GETARG_OID(0); - - PG_RETURN_CSTRING(enum_cstring(enumoid)); -} - -/* guts of enum_out and enum-to-text */ -static char * -enum_cstring(Oid enumval) -{ + Oid enumval = PG_GETARG_OID(0); + char *result; HeapTuple tup; Form_pg_enum en; - char *label; tup = SearchSysCache(ENUMOID, ObjectIdGetDatum(enumval), 0, 0, 0); - if (tup == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), - errmsg("invalid internal value for enum: %u", - enumval))); + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid internal value for enum: %u", + enumval))); en = (Form_pg_enum) GETSTRUCT(tup); - label = pstrdup(NameStr(en->enumlabel)); + result = pstrdup(NameStr(en->enumlabel)); ReleaseSysCache(tup); - return label; + + PG_RETURN_CSTRING(result); } /* Comparison functions and related */ @@ -191,47 +174,6 @@ enum_cmp(PG_FUNCTION_ARGS) 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 */ Datum @@ -266,7 +208,7 @@ enum_first(PG_FUNCTION_ARGS) ReleaseCatCacheList(list); - if (!OidIsValid(min)) /* should not happen */ + if (!OidIsValid(min)) /* should not happen */ elog(ERROR, "no values found for enum %s", format_type_be(enumtypoid)); @@ -276,10 +218,10 @@ enum_first(PG_FUNCTION_ARGS) Datum enum_last(PG_FUNCTION_ARGS) { - Oid enumtypoid; - Oid max = InvalidOid; - CatCList *list; - int num, i; + Oid enumtypoid; + Oid max = InvalidOid; + CatCList *list; + int num, i; /* * We rely on being able to get the specific enum type from the calling @@ -292,24 +234,24 @@ enum_last(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine actual enum type"))); - list = SearchSysCacheList(ENUMTYPOIDNAME, 1, - ObjectIdGetDatum(enumtypoid), + list = SearchSysCacheList(ENUMTYPOIDNAME, 1, + ObjectIdGetDatum(enumtypoid), 0, 0, 0); - num = list->n_members; - for (i = 0; i < num; i++) - { + num = list->n_members; + for (i = 0; i < num; i++) + { Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data); - if(!OidIsValid(max) || valoid > max) - max = valoid; - } + if (!OidIsValid(max) || valoid > max) + max = valoid; + } ReleaseCatCacheList(list); - if (!OidIsValid(max)) /* should not happen */ + if (!OidIsValid(max)) /* should not happen */ elog(ERROR, "no values found for enum %s", format_type_be(enumtypoid)); - PG_RETURN_OID(max); + PG_RETURN_OID(max); } /* 2-argument variant of enum_range */ @@ -368,26 +310,26 @@ static ArrayType * enum_range_internal(Oid enumtypoid, Oid lower, Oid upper) { ArrayType *result; - CatCList *list; - int total, i, j; - Datum *elems; + CatCList *list; + int total, i, j; + Datum *elems; list = SearchSysCacheList(ENUMTYPOIDNAME, 1, - ObjectIdGetDatum(enumtypoid), + ObjectIdGetDatum(enumtypoid), 0, 0, 0); total = list->n_members; elems = (Datum *) palloc(total * sizeof(Datum)); j = 0; - for (i = 0; i < total; i++) - { + for (i = 0; i < total; i++) + { Oid val = HeapTupleGetOid(&(list->members[i]->tuple)); if ((!OidIsValid(lower) || lower <= val) && (!OidIsValid(upper) || val <= upper)) - elems[j++] = ObjectIdGetDatum(val); - } + elems[j++] = ObjectIdGetDatum(val); + } /* shouldn't need the cache anymore */ ReleaseCatCacheList(list); diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index f2c229375649ac80cb363cc5547c52be6eca214d..7a66bd4c56b08e1d81ed21a2c980c6ad5bde7bae 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -8,7 +8,7 @@ * * * 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) } -/* - * 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 diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index d6d590220776f77b2e18b28ea1544a756972e33b..405b16ecef857ae4d1538c9ce6d7625550fcb2af 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -8,7 +8,7 @@ * * * 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 @@ * int2in, int2out, int2recv, int2send * int4in, int4out, int4recv, int4send * int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend - * Conversion routines: - * itoi, int2_text, int4_text * Boolean operators: * inteq, intne, intlt, intle, intgt, intge * Arithmetic operators: @@ -343,68 +341,6 @@ i4toi2(PG_FUNCTION_ARGS) 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 */ Datum int4_bool(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 25672b680fc88bd4ea50b9ecf0faddda1f5c04a5..3a88a0591c6d3b904253dd486fdb68ad9758eab6 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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) 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 */ diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index fa13abe4618d8596e36bb4982ce36fe5e0b2626f..aa13589b8a62659e62cb18d9c68685c372491993 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -1,7 +1,7 @@ /* * 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" @@ -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: */ diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 7a190719b89b2cbafbf1d6665aaa67dc690e286f..10c1285bd600ddd30d1745636a563923dc4ab057 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -1,7 +1,7 @@ /* * 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 */ @@ -22,7 +22,6 @@ #include "utils/inet.h" -static inet *text_network(text *src, bool is_cidr); static int32 network_cmp_internal(inet *a1, inet *a2); static int bitncmp(void *l, void *r, int n); static bool addressOK(unsigned char *a, int bits, int family); @@ -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 inet_to_cidr(PG_FUNCTION_ARGS) { @@ -655,6 +625,11 @@ network_host(PG_FUNCTION_ARGS) 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 network_show(PG_FUNCTION_ARGS) { diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 6a6f3d44afb0c1e66c4064bd19e169910ebd9aa9..aa585f4267b236222cf75b5d1d65e46657760f73 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -14,7 +14,7 @@ * Copyright (c) 1998-2007, PostgreSQL Global Development Group * * 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) } -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 diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index 8a9f971a227fbcb59c236599ba98c26f62783d1e..fc37b18434f29b6c41331bb22b94b82dd847c0b1 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -8,7 +8,7 @@ * * * 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 @@ *****************************************************************************/ static Oid -oidin_subr(const char *funcname, const char *s, char **endloc) +oidin_subr(const char *s, char **endloc) { unsigned long cvt; char *endptr; @@ -116,7 +116,7 @@ oidin(PG_FUNCTION_ARGS) char *s = PG_GETARG_CSTRING(0); Oid result; - result = oidin_subr("oidin", s, NULL); + result = oidin_subr(s, NULL); PG_RETURN_OID(result); } @@ -202,7 +202,7 @@ oidvectorin(PG_FUNCTION_ARGS) oidString++; if (*oidString == '\0') break; - result->values[n] = oidin_subr("oidvectorin", oidString, &oidString); + result->values[n] = oidin_subr(oidString, &oidString); } while (*oidString && isspace((unsigned char) *oidString)) oidString++; @@ -419,45 +419,3 @@ oidvectorgt(PG_FUNCTION_ARGS) 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); -} diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index bf4bcc365ed2644c0a11b304349e5c3468f142ed..88b0c1d26669244105f849c2fcb9c322e6687756 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -13,7 +13,7 @@ * * * 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) /* * 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 text_regclass(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index b9a026c7ea119c17b9197dd1fbaf0edb1d0a14d8..3f257f375f431f1e109acaf13fc220edc2427453 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -15,7 +15,7 @@ * * 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) Oid lefttype, righttype, castfunc; - bool arrayCoerce; + CoercionPathType pathtype; /* We always need to know how to call the equality operator */ fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo, @@ -3885,20 +3885,28 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid) * here and in ri_AttributesEqual(). At the moment there is no * point because cases involving nonidentical array types will * 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); Assert(lefttype == righttype); if (typeid == lefttype) castfunc = InvalidOid; /* simplest case */ - else if (!find_coercion_pathway(lefttype, typeid, COERCION_IMPLICIT, - &castfunc, &arrayCoerce) - || arrayCoerce) /* XXX fixme */ + else { - /* 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)); + pathtype = find_coercion_pathway(lefttype, typeid, + COERCION_IMPLICIT, + &castfunc); + if (pathtype != COERCION_PATH_FUNC && + 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)) fmgr_info_cxt(castfunc, &entry->cast_func_finfo, diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index d5de627df1b15bafaf6df191d2814043bc006a25..78be35ef36da901bf22009750b2333dde13f9e79 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * 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) case T_RelabelType: return isSimpleNode((Node *) ((RelabelType *) node)->arg, node, prettyFlags); + case T_CoerceViaIO: + return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg, + node, prettyFlags); case T_ArrayCoerceExpr: return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg, node, prettyFlags); @@ -3595,6 +3598,27 @@ get_rule_expr(Node *node, deparse_context *context, } 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: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index f9fb9ef58207f107253b2a302a61da8dad3e0335..f7c385ad46aec60c3b3cea4ab4d429884b18e195 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * 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) *---------------------------------------------------------*/ -/* 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() * Truncate timestamp to specified units. */ diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c index d01fef4b574eec3e52ccffb89220b2b7d3bc52e9..24b05f34266fa01e78cf7454eff0122df50694f0 100644 --- a/src/backend/utils/adt/uuid.c +++ b/src/backend/utils/adt/uuid.c @@ -6,7 +6,7 @@ * Copyright (c) 2007, PostgreSQL Global Development Group * * 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) pg_uuid_t *key = PG_GETARG_UUID_P(0); 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)); -} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 8f79a7a92032d9a8d97eb4694ee1aa6a17d202ea..ec6d516713932127a254f8a72f1cee581bd84287 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200706012 +#define CATALOG_VERSION_NO 200706051 #endif diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 0b518265a36aab154072e90a367b8cbfec27584d..82016774e80595d9816037b799e6ea323e41c487 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -10,7 +10,7 @@ * * 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 * the genbki.sh script reads this file and generates .bki @@ -173,7 +173,7 @@ DATA(insert ( 25 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 1043 0 i )); @@ -193,7 +193,8 @@ DATA(insert ( 1043 18 944 a )); DATA(insert ( 25 19 407 i )); DATA(insert ( 1042 19 409 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 ( 23 18 78 e )); @@ -265,127 +266,42 @@ DATA(insert ( 1560 23 1684 e )); /* * Cross-category casts to and from TEXT * - * For historical reasons, most casts to TEXT are implicit. This is BAD - * and should be reined in. + * We need entries here only for a few specialized cases where the behavior + * of the cast function differs from the datatype's I/O functions. Otherwise, + * parse_coerce.c will generate CoerceViaIO operations without any prompting. + * + * Note that the castcontext values specified here should be no stronger than + * parse_coerce.c's automatic casts ('a' to text, 'e' from text) else odd + * behavior will ensue when the automatic cast is applied instead of the + * pg_cast entry! */ -DATA(insert ( 20 25 1289 i )); -DATA(insert ( 25 20 1290 e )); -DATA(insert ( 21 25 113 i )); -DATA(insert ( 25 21 818 e )); -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 ( 650 25 730 a )); +DATA(insert ( 869 25 730 a )); +DATA(insert ( 16 25 2971 a )); +DATA(insert ( 142 25 2922 a )); 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 * - * 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 ( 1043 20 1290 e )); -DATA(insert ( 21 1043 113 a )); -DATA(insert ( 1043 21 818 e )); -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 ( 650 1043 730 a )); +DATA(insert ( 869 1043 730 a )); +DATA(insert ( 16 1043 2971 a )); +DATA(insert ( 142 1043 2922 a )); 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 * - * A function supporting cast to TEXT/VARCHAR can be used for cast to BPCHAR, - * 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...) + * We support all the same casts as for TEXT. */ -DATA(insert ( 20 1042 1289 a )); -DATA(insert ( 1042 20 1290 e )); -DATA(insert ( 21 1042 113 a )); -DATA(insert ( 1042 21 818 e )); -DATA(insert ( 23 1042 112 a )); -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 )); +DATA(insert ( 650 1042 730 a )); +DATA(insert ( 869 1042 730 a )); +DATA(insert ( 16 1042 2971 a )); +DATA(insert ( 142 1042 2922 a )); +DATA(insert ( 1042 142 2896 e )); /* * Length-coercion functions @@ -401,16 +317,4 @@ DATA(insert ( 1560 1560 1685 i )); DATA(insert ( 1562 1562 1687 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 */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 7145b021ac976f0777123761c144676a896082d5..c656c7a6717f5cc00c7c121ce164acaba1c2e28a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.457 2007/06/01 23:40:18 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.458 2007/06/05 21:31:07 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -238,12 +238,6 @@ DESCR("I/O"); DATA(insert OID = 110 ( unknownout PGNSP PGUID 12 1 0 f f t f i 1 2275 "705" _null_ _null_ _null_ unknownout - _null_ )); DESCR("I/O"); DATA(insert OID = 111 ( numeric_fac PGNSP PGUID 12 1 0 f f t f i 1 1700 "20" _null_ _null_ _null_ numeric_fac - _null_ )); -DATA(insert OID = 112 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "23" _null_ _null_ _null_ int4_text - _null_ )); -DESCR("convert int4 to text"); -DATA(insert OID = 113 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "21" _null_ _null_ _null_ int2_text - _null_ )); -DESCR("convert int2 to text"); -DATA(insert OID = 114 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "26" _null_ _null_ _null_ oid_text - _null_ )); -DESCR("convert oid to text"); DATA(insert OID = 115 ( box_above_eq PGNSP PGUID 12 1 0 f f t f i 2 16 "603 603" _null_ _null_ _null_ box_above_eq - _null_ )); DESCR("is above (allows touching)"); @@ -513,7 +507,7 @@ DESCR("abstime in tinterval"); DATA(insert OID = 249 ( tintervalrel PGNSP PGUID 12 1 0 f f t f i 1 703 "704" _null_ _null_ _null_ tintervalrel - _null_ )); DESCR("tinterval to reltime"); DATA(insert OID = 250 ( timenow PGNSP PGUID 12 1 0 f f t f s 0 702 "" _null_ _null_ _null_ timenow - _null_ )); -DESCR("Current date and time (abstime)"); +DESCR("current date and time (abstime)"); DATA(insert OID = 251 ( abstimeeq PGNSP PGUID 12 1 0 f f t f i 2 16 "702 702" _null_ _null_ _null_ abstimeeq - _null_ )); DESCR("equal"); DATA(insert OID = 252 ( abstimene PGNSP PGUID 12 1 0 f f t f i 2 16 "702 702" _null_ _null_ _null_ abstimene - _null_ )); @@ -561,7 +555,7 @@ DESCR("start of interval"); DATA(insert OID = 273 ( tintervalend PGNSP PGUID 12 1 0 f f t f i 1 702 "704" _null_ _null_ _null_ tintervalend - _null_ )); DESCR("end of interval"); DATA(insert OID = 274 ( timeofday PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ timeofday - _null_ )); -DESCR("Current date and time - increments during transactions"); +DESCR("current date and time - increments during transactions"); DATA(insert OID = 275 ( isfinite PGNSP PGUID 12 1 0 f f t f i 1 16 "702" _null_ _null_ _null_ abstime_finite - _null_ )); DESCR("finite abstime?"); @@ -1091,22 +1085,6 @@ DESCR("greater-than-or-equal"); /* OIDS 800 - 899 */ -DATA(insert OID = 817 ( oid PGNSP PGUID 12 1 0 f f t f i 1 26 "25" _null_ _null_ _null_ text_oid - _null_ )); -DESCR("convert text to oid"); -DATA(insert OID = 818 ( int2 PGNSP PGUID 12 1 0 f f t f i 1 21 "25" _null_ _null_ _null_ text_int2 - _null_ )); -DESCR("convert text to int2"); -DATA(insert OID = 819 ( int4 PGNSP PGUID 12 1 0 f f t f i 1 23 "25" _null_ _null_ _null_ text_int4 - _null_ )); -DESCR("convert text to int4"); - -DATA(insert OID = 838 ( float8 PGNSP PGUID 12 1 0 f f t f i 1 701 "25" _null_ _null_ _null_ text_float8 - _null_ )); -DESCR("convert text to float8"); -DATA(insert OID = 839 ( float4 PGNSP PGUID 12 1 0 f f t f i 1 700 "25" _null_ _null_ _null_ text_float4 - _null_ )); -DESCR("convert text to float4"); -DATA(insert OID = 840 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "701" _null_ _null_ _null_ float8_text - _null_ )); -DESCR("convert float8 to text"); -DATA(insert OID = 841 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "700" _null_ _null_ _null_ float4_text - _null_ )); -DESCR("convert float4 to text"); - DATA(insert OID = 846 ( cash_mul_flt4 PGNSP PGUID 12 1 0 f f t f i 2 790 "790 700" _null_ _null_ _null_ cash_mul_flt4 - _null_ )); DESCR("multiply"); DATA(insert OID = 847 ( cash_div_flt4 PGNSP PGUID 12 1 0 f f t f i 2 790 "790 700" _null_ _null_ _null_ cash_div_flt4 - _null_ )); @@ -1303,19 +1281,6 @@ DESCR("horizontal?"); DATA(insert OID = 999 ( lseg_eq PGNSP PGUID 12 1 0 f f t f i 2 16 "601 601" _null_ _null_ _null_ lseg_eq - _null_ )); DESCR("equal"); -DATA(insert OID = 748 ( date PGNSP PGUID 12 1 0 f f t f s 1 1082 "25" _null_ _null_ _null_ text_date - _null_ )); -DESCR("convert text to date"); -DATA(insert OID = 749 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "1082" _null_ _null_ _null_ date_text - _null_ )); -DESCR("convert date to text"); -DATA(insert OID = 837 ( time PGNSP PGUID 12 1 0 f f t f s 1 1083 "25" _null_ _null_ _null_ text_time - _null_ )); -DESCR("convert text to time"); -DATA(insert OID = 948 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "1083" _null_ _null_ _null_ time_text - _null_ )); -DESCR("convert time to text"); -DATA(insert OID = 938 ( timetz PGNSP PGUID 12 1 0 f f t f s 1 1266 "25" _null_ _null_ _null_ text_timetz - _null_ )); -DESCR("convert text to timetz"); -DATA(insert OID = 939 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "1266" _null_ _null_ _null_ timetz_text - _null_ )); -DESCR("convert timetz to text"); - /* OIDS 1000 - 1999 */ DATA(insert OID = 1026 ( timezone PGNSP PGUID 12 1 0 f f t f i 2 1114 "1186 1184" _null_ _null_ _null_ timestamptz_izone - _null_ )); @@ -1524,12 +1489,6 @@ DATA(insert OID = 1189 ( timestamptz_pl_interval PGNSP PGUID 12 1 0 f f t f s 2 DESCR("plus"); DATA(insert OID = 1190 ( timestamptz_mi_interval PGNSP PGUID 12 1 0 f f t f s 2 1184 "1184 1186" _null_ _null_ _null_ timestamptz_mi_interval - _null_ )); DESCR("minus"); -DATA(insert OID = 1191 ( timestamptz PGNSP PGUID 12 1 0 f f t f s 1 1184 "25" _null_ _null_ _null_ text_timestamptz - _null_ )); -DESCR("convert text to timestamp with time zone"); -DATA(insert OID = 1192 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "1184" _null_ _null_ _null_ timestamptz_text - _null_ )); -DESCR("convert timestamp with time zone to text"); -DATA(insert OID = 1193 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "1186" _null_ _null_ _null_ interval_text - _null_ )); -DESCR("convert interval to text"); DATA(insert OID = 1194 ( reltime PGNSP PGUID 12 1 0 f f t f i 1 703 "1186" _null_ _null_ _null_ interval_reltime - _null_ )); DESCR("convert interval to reltime"); DATA(insert OID = 1195 ( timestamptz_smaller PGNSP PGUID 12 1 0 f f t f i 2 1184 "1184 1184" _null_ _null_ _null_ timestamp_smaller - _null_ )); @@ -1586,9 +1545,6 @@ DESCR("absolute value"); DATA(insert OID = 1253 ( int2abs PGNSP PGUID 12 1 0 f f t f i 1 21 "21" _null_ _null_ _null_ int2abs - _null_ )); DESCR("absolute value"); -DATA(insert OID = 1263 ( interval PGNSP PGUID 12 1 0 f f t f s 1 1186 "25" _null_ _null_ _null_ text_interval - _null_ )); -DESCR("convert text to interval"); - DATA(insert OID = 1271 ( overlaps PGNSP PGUID 12 1 0 f f f f i 4 16 "1266 1266 1266 1266" _null_ _null_ _null_ overlaps_timetz - _null_ )); DESCR("SQL92 interval comparison"); DATA(insert OID = 1272 ( datetime_pl PGNSP PGUID 12 1 0 f f t f i 2 1114 "1082 1083" _null_ _null_ _null_ datetime_timestamp - _null_ )); @@ -1617,11 +1573,6 @@ DESCR("convert int8 to oid"); DATA(insert OID = 1288 ( int8 PGNSP PGUID 12 1 0 f f t f i 1 20 "26" _null_ _null_ _null_ oidtoi8 - _null_ )); DESCR("convert oid to int8"); -DATA(insert OID = 1289 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "20" _null_ _null_ _null_ int8_text - _null_ )); -DESCR("convert int8 to text"); -DATA(insert OID = 1290 ( int8 PGNSP PGUID 12 1 0 f f t f i 1 20 "25" _null_ _null_ _null_ text_int8 - _null_ )); -DESCR("convert text to int8"); - DATA(insert OID = 1292 ( tideq PGNSP PGUID 12 1 0 f f t f i 2 16 "27 27" _null_ _null_ _null_ tideq - _null_ )); DESCR("equal"); DATA(insert OID = 1293 ( currtid PGNSP PGUID 12 1 0 f f t f v 2 27 "26 27" _null_ _null_ _null_ currtid_byreloid - _null_ )); @@ -2407,12 +2358,8 @@ DESCR("I/O"); DATA(insert OID = 437 ( macaddr_out PGNSP PGUID 12 1 0 f f t f i 1 2275 "829" _null_ _null_ _null_ macaddr_out - _null_ )); DESCR("I/O"); -DATA(insert OID = 752 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "829" _null_ _null_ _null_ macaddr_text - _null_ )); -DESCR("MAC address to text"); DATA(insert OID = 753 ( trunc PGNSP PGUID 12 1 0 f f t f i 1 829 "829" _null_ _null_ _null_ macaddr_trunc - _null_ )); DESCR("MAC manufacturer fields"); -DATA(insert OID = 767 ( macaddr PGNSP PGUID 12 1 0 f f t f i 1 829 "25" _null_ _null_ _null_ text_macaddr - _null_ )); -DESCR("text to MAC address"); DATA(insert OID = 830 ( macaddr_eq PGNSP PGUID 12 1 0 f f t f i 2 16 "829 829" _null_ _null_ _null_ macaddr_eq - _null_ )); DESCR("equal"); @@ -2490,10 +2437,6 @@ DATA(insert OID = 730 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "869" _null_ DESCR("show all parts of inet/cidr value"); DATA(insert OID = 1362 ( hostmask PGNSP PGUID 12 1 0 f f t f i 1 869 "869" _null_ _null_ _null_ network_hostmask - _null_ )); DESCR("hostmask of address"); -DATA(insert OID = 1713 ( inet PGNSP PGUID 12 1 0 f f t f i 1 869 "25" _null_ _null_ _null_ text_inet - _null_ )); -DESCR("text to inet"); -DATA(insert OID = 1714 ( cidr PGNSP PGUID 12 1 0 f f t f i 1 650 "25" _null_ _null_ _null_ text_cidr - _null_ )); -DESCR("text to cidr"); DATA(insert OID = 1715 ( cidr PGNSP PGUID 12 1 0 f f t f i 1 650 "869" _null_ _null_ _null_ inet_to_cidr - _null_ )); DESCR("coerce inet to cidr"); @@ -2521,11 +2464,6 @@ DESCR("subtract integer from inet value"); DATA(insert OID = 2633 ( inetmi PGNSP PGUID 12 1 0 f f t f i 2 20 "869 869" _null_ _null_ _null_ inetmi - _null_ )); DESCR("subtract inet values"); -DATA(insert OID = 1686 ( numeric PGNSP PGUID 12 1 0 f f t f i 1 1700 "25" _null_ _null_ _null_ text_numeric - _null_ )); -DESCR("(internal)"); -DATA(insert OID = 1688 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "1700" _null_ _null_ _null_ numeric_text - _null_ )); -DESCR("(internal)"); - DATA(insert OID = 1690 ( time_mi_time PGNSP PGUID 12 1 0 f f t f i 2 1186 "1083 1083" _null_ _null_ _null_ time_mi_time - _null_ )); DESCR("minus"); @@ -3009,9 +2947,9 @@ DATA(insert OID = 2274 ( pg_stat_reset PGNSP PGUID 12 1 0 f f f f v 0 2278 DESCR("Statistics: Reset collected statistics for current database"); DATA(insert OID = 1946 ( encode PGNSP PGUID 12 1 0 f f t f i 2 25 "17 25" _null_ _null_ _null_ binary_encode - _null_ )); -DESCR("Convert bytea value into some ascii-only text string"); +DESCR("convert bytea value into some ascii-only text string"); DATA(insert OID = 1947 ( decode PGNSP PGUID 12 1 0 f f t f i 2 17 "25 25" _null_ _null_ _null_ binary_decode - _null_ )); -DESCR("Convert ascii-encoded text string into bytea value"); +DESCR("convert ascii-encoded text string into bytea value"); DATA(insert OID = 1948 ( byteaeq PGNSP PGUID 12 1 0 f f t f i 2 16 "17 17" _null_ _null_ _null_ byteaeq - _null_ )); DESCR("equal"); @@ -3076,8 +3014,6 @@ DATA(insert OID = 2020 ( date_trunc PGNSP PGUID 12 1 0 f f t f i 2 1114 "25 11 DESCR("truncate timestamp to specified units"); DATA(insert OID = 2021 ( date_part PGNSP PGUID 12 1 0 f f t f i 2 701 "25 1114" _null_ _null_ _null_ timestamp_part - _null_ )); DESCR("extract field from timestamp"); -DATA(insert OID = 2022 ( timestamp PGNSP PGUID 12 1 0 f f t f s 1 1114 "25" _null_ _null_ _null_ text_timestamp - _null_ )); -DESCR("convert text to timestamp"); DATA(insert OID = 2023 ( timestamp PGNSP PGUID 12 1 0 f f t f s 1 1114 "702" _null_ _null_ _null_ abstime_timestamp - _null_ )); DESCR("convert abstime to timestamp"); DATA(insert OID = 2024 ( timestamp PGNSP PGUID 12 1 0 f f t f i 1 1114 "1082" _null_ _null_ _null_ date_timestamp - _null_ )); @@ -3098,8 +3034,6 @@ DATA(insert OID = 2032 ( timestamp_pl_interval PGNSP PGUID 12 1 0 f f t f i 2 1 DESCR("plus"); DATA(insert OID = 2033 ( timestamp_mi_interval PGNSP PGUID 12 1 0 f f t f i 2 1114 "1114 1186" _null_ _null_ _null_ timestamp_mi_interval - _null_ )); DESCR("minus"); -DATA(insert OID = 2034 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "1114" _null_ _null_ _null_ timestamp_text - _null_ )); -DESCR("convert timestamp to text"); DATA(insert OID = 2035 ( timestamp_smaller PGNSP PGUID 12 1 0 f f t f i 2 1114 "1114 1114" _null_ _null_ _null_ timestamp_smaller - _null_ )); DESCR("smaller of two"); DATA(insert OID = 2036 ( timestamp_larger PGNSP PGUID 12 1 0 f f t f i 2 1114 "1114 1114" _null_ _null_ _null_ timestamp_larger - _null_ )); @@ -3191,13 +3125,13 @@ DATA(insert OID = 2855 ( pg_is_other_temp_schema PGNSP PGUID 12 1 0 f f t f s 1 DESCR("is schema another session's temp schema?"); DATA(insert OID = 2171 ( pg_cancel_backend PGNSP PGUID 12 1 0 f f t f v 1 16 "23" _null_ _null_ _null_ pg_cancel_backend - _null_ )); -DESCR("Cancel a server process' current query"); +DESCR("cancel a server process' current query"); DATA(insert OID = 2172 ( pg_start_backup PGNSP PGUID 12 1 0 f f t f v 1 25 "25" _null_ _null_ _null_ pg_start_backup - _null_ )); -DESCR("Prepare for taking an online backup"); +DESCR("prepare for taking an online backup"); DATA(insert OID = 2173 ( pg_stop_backup PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ pg_stop_backup - _null_ )); -DESCR("Finish taking an online backup"); +DESCR("finish taking an online backup"); DATA(insert OID = 2848 ( pg_switch_xlog PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ pg_switch_xlog - _null_ )); -DESCR("Switch to new xlog file"); +DESCR("switch to new xlog file"); DATA(insert OID = 2849 ( pg_current_xlog_location PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ pg_current_xlog_location - _null_ )); DESCR("current xlog write location"); DATA(insert OID = 2852 ( pg_current_xlog_insert_location PGNSP PGUID 12 1 0 f f t f v 0 25 "" _null_ _null_ _null_ pg_current_xlog_insert_location - _null_ )); @@ -3208,23 +3142,21 @@ DATA(insert OID = 2851 ( pg_xlogfile_name PGNSP PGUID 12 1 0 f f t f i 1 25 "2 DESCR("xlog filename, given an xlog location"); DATA(insert OID = 2621 ( pg_reload_conf PGNSP PGUID 12 1 0 f f t f v 0 16 "" _null_ _null_ _null_ pg_reload_conf - _null_ )); -DESCR("Reload configuration files"); +DESCR("reload configuration files"); DATA(insert OID = 2622 ( pg_rotate_logfile PGNSP PGUID 12 1 0 f f t f v 0 16 "" _null_ _null_ _null_ pg_rotate_logfile - _null_ )); -DESCR("Rotate log file"); +DESCR("rotate log file"); DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 1 0 f f t f v 1 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" pg_stat_file - _null_ )); -DESCR("Return file information"); +DESCR("return file information"); DATA(insert OID = 2624 ( pg_read_file PGNSP PGUID 12 1 0 f f t f v 3 25 "25 20 20" _null_ _null_ _null_ pg_read_file - _null_ )); -DESCR("Read text from a file"); +DESCR("read text from a file"); DATA(insert OID = 2625 ( pg_ls_dir PGNSP PGUID 12 1 1000 f f t t v 1 25 "25" _null_ _null_ _null_ pg_ls_dir - _null_ )); -DESCR("List all files in a directory"); +DESCR("list all files in a directory"); DATA(insert OID = 2626 ( pg_sleep PGNSP PGUID 12 1 0 f f t f v 1 2278 "701" _null_ _null_ _null_ pg_sleep - _null_ )); -DESCR("Sleep for the specified time in seconds"); +DESCR("sleep for the specified time in seconds"); -DATA(insert OID = 2970 ( boolean PGNSP PGUID 12 1 0 f f t f i 1 16 "25" _null_ _null_ _null_ textbool - _null_ )); -DESCR("text to boolean"); DATA(insert OID = 2971 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "16" _null_ _null_ _null_ booltext - _null_ )); -DESCR("boolean to text"); +DESCR("convert boolean to text"); /* Aggregates (moved here from pg_aggregate for 7.3) */ @@ -3491,23 +3423,23 @@ DESCR("current user privilege on role by role oid"); DATA(insert OID = 1269 ( pg_column_size PGNSP PGUID 12 1 0 f f t f s 1 23 "2276" _null_ _null_ _null_ pg_column_size - _null_ )); DESCR("bytes required to store the value, perhaps with compression"); DATA(insert OID = 2322 ( pg_tablespace_size PGNSP PGUID 12 1 0 f f t f v 1 20 "26" _null_ _null_ _null_ pg_tablespace_size_oid - _null_ )); -DESCR("Calculate total disk space usage for the specified tablespace"); +DESCR("total disk space usage for the specified tablespace"); DATA(insert OID = 2323 ( pg_tablespace_size PGNSP PGUID 12 1 0 f f t f v 1 20 "19" _null_ _null_ _null_ pg_tablespace_size_name - _null_ )); -DESCR("Calculate total disk space usage for the specified tablespace"); +DESCR("total disk space usage for the specified tablespace"); DATA(insert OID = 2324 ( pg_database_size PGNSP PGUID 12 1 0 f f t f v 1 20 "26" _null_ _null_ _null_ pg_database_size_oid - _null_ )); -DESCR("Calculate total disk space usage for the specified database"); +DESCR("total disk space usage for the specified database"); DATA(insert OID = 2168 ( pg_database_size PGNSP PGUID 12 1 0 f f t f v 1 20 "19" _null_ _null_ _null_ pg_database_size_name - _null_ )); -DESCR("Calculate total disk space usage for the specified database"); +DESCR("total disk space usage for the specified database"); DATA(insert OID = 2325 ( pg_relation_size PGNSP PGUID 12 1 0 f f t f v 1 20 "26" _null_ _null_ _null_ pg_relation_size_oid - _null_ )); -DESCR("Calculate disk space usage for the specified table or index"); +DESCR("disk space usage for the specified table or index"); DATA(insert OID = 2289 ( pg_relation_size PGNSP PGUID 12 1 0 f f t f v 1 20 "25" _null_ _null_ _null_ pg_relation_size_name - _null_ )); -DESCR("Calculate disk space usage for the specified table or index"); +DESCR("disk space usage for the specified table or index"); DATA(insert OID = 2286 ( pg_total_relation_size PGNSP PGUID 12 1 0 f f t f v 1 20 "26" _null_ _null_ _null_ pg_total_relation_size_oid - _null_ )); -DESCR("Calculate total disk space usage for the specified table and associated indexes and toast tables"); +DESCR("total disk space usage for the specified table and associated indexes and toast tables"); DATA(insert OID = 2287 ( pg_total_relation_size PGNSP PGUID 12 1 0 f f t f v 1 20 "25" _null_ _null_ _null_ pg_total_relation_size_name - _null_ )); -DESCR("Calculate total disk space usage for the specified table and associated indexes and toast tables"); +DESCR("total disk space usage for the specified table and associated indexes and toast tables"); DATA(insert OID = 2288 ( pg_size_pretty PGNSP PGUID 12 1 0 f f t f v 1 25 "20" _null_ _null_ _null_ pg_size_pretty - _null_ )); -DESCR("Convert a long int to a human readable text using size units"); +DESCR("convert a long int to a human readable text using size units"); DATA(insert OID = 2290 ( record_in PGNSP PGUID 12 1 0 f f t f v 3 2249 "2275 26 23" _null_ _null_ _null_ record_in - _null_ )); DESCR("I/O"); @@ -4150,10 +4082,6 @@ DATA(insert OID = 2962 ( uuid_send PGNSP PGUID 12 1 0 f f t f i 1 17 "2950" DESCR("I/O"); DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "2950" _null_ _null_ _null_ uuid_hash - _null_ )); DESCR("hash"); -DATA(insert OID = 2964 ( uuid PGNSP PGUID 12 1 0 f f t f i 1 2950 "25" _null_ _null_ _null_ text_uuid - _null_ )); -DESCR("convert text to uuid"); -DATA(insert OID = 2965 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "2950" _null_ _null_ _null_ uuid_text - _null_ )); -DESCR("convert uuid to text"); /* enum related procs */ DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 f f t f i 1 3500 "2275" _null_ _null_ _null_ anyenum_in - _null_ )); @@ -4190,10 +4118,6 @@ DATA(insert OID = 3528 ( enum_first PGNSP PGUID 12 1 0 f f f f s 1 3500 "3500" DATA(insert OID = 3529 ( enum_last PGNSP PGUID 12 1 0 f f f f s 1 3500 "3500" _null_ _null_ _null_ enum_last - _null_ )); DATA(insert OID = 3530 ( enum_range PGNSP PGUID 12 1 0 f f f f s 2 2277 "3500 3500" _null_ _null_ _null_ enum_range_bounds - _null_ )); DATA(insert OID = 3531 ( enum_range PGNSP PGUID 12 1 0 f f f f s 1 2277 "3500" _null_ _null_ _null_ enum_range_all - _null_ )); -DATA(insert OID = 3532 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "3500" _null_ _null_ _null_ enum_text - _null_ )); -DESCR("convert enum to text"); -DATA(insert OID = 3533 ( enum PGNSP PGUID 12 1 0 f f t f s 1 3500 "25" _null_ _null_ _null_ text_enum - _null_ )); -DESCR("convert text to enum"); /* * Symbolic values for provolatile column: these indicate whether the result diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index b6b7ddcde6fdb45d30f3c0d198b6867cb8c9e113..ccc243cfd062ad6396de64b06b0954cc939c3871 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 TupleDesc argdesc; /* tupdesc for most recent input */ } 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 * ---------------- diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fc48961c5caddc3bf607cf679be4f8af6c6cdaee..31186930d20c3381b4edfbaa152fb03c8f40193e 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 T_FieldSelect, T_FieldStore, T_RelabelType, + T_CoerceViaIO, T_ArrayCoerceExpr, T_ConvertRowtypeExpr, T_CaseExpr, @@ -160,6 +161,7 @@ typedef enum NodeTag T_SubPlanState, T_FieldSelectState, T_FieldStoreState, + T_CoerceViaIOState, T_ArrayCoerceExprState, T_ConvertRowtypeExprState, T_CaseExprState, diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index ccad1329a6470a6e0bf083bb4ce5d15f33c23ebb..a567a8e26d49f5edd2a7a94caedb3ab914a69c5e 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 CoercionForm relabelformat; /* how to display this node */ } 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 * diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 23aaa87cfae584ac99498cd26f0e503925a31794..959ac50cde918aee77eedba371d37490f2bd1716 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 @@ #include "parser/parse_node.h" +/* Type categories (kluge ... ought to be extensible) */ typedef enum CATEGORY { INVALID_TYPE, @@ -33,6 +34,16 @@ typedef enum CATEGORY USER_TYPE } 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 IsPreferredType(CATEGORY category, Oid type); @@ -75,10 +86,11 @@ extern Oid resolve_generic_type(Oid declared_type, Oid context_actual_type, Oid context_declared_type); -extern bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, - CoercionContext ccontext, - Oid *funcid, bool *arrayCoerce); -extern bool find_typmod_coercion_function(Oid typeId, - Oid *funcid, bool *arrayCoerce); +extern CoercionPathType find_coercion_pathway(Oid targetTypeId, + Oid sourceTypeId, + CoercionContext ccontext, + Oid *funcid); +extern CoercionPathType find_typmod_coercion_function(Oid typeId, + Oid *funcid); #endif /* PARSE_COERCE_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index d0a7329f10f7331317ab9eb545cc86cdd94c5d23..5ff4fe738fc631116a95d3f81c03de239c31a197 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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); extern Datum boolrecv(PG_FUNCTION_ARGS); extern Datum boolsend(PG_FUNCTION_ARGS); extern Datum booltext(PG_FUNCTION_ARGS); -extern Datum textbool(PG_FUNCTION_ARGS); extern Datum booleq(PG_FUNCTION_ARGS); extern Datum boolne(PG_FUNCTION_ARGS); extern Datum boollt(PG_FUNCTION_ARGS); @@ -115,8 +114,6 @@ extern Datum enum_ne(PG_FUNCTION_ARGS); extern Datum enum_ge(PG_FUNCTION_ARGS); extern Datum enum_gt(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_larger(PG_FUNCTION_ARGS); extern Datum enum_first(PG_FUNCTION_ARGS); @@ -140,12 +137,8 @@ extern Datum int4recv(PG_FUNCTION_ARGS); extern Datum int4send(PG_FUNCTION_ARGS); extern Datum i2toi4(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 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 int4ne(PG_FUNCTION_ARGS); extern Datum int4lt(PG_FUNCTION_ARGS); @@ -334,10 +327,6 @@ extern Datum i4tof(PG_FUNCTION_ARGS); extern Datum i2tof(PG_FUNCTION_ARGS); extern Datum ftoi4(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 dceil(PG_FUNCTION_ARGS); extern Datum dfloor(PG_FUNCTION_ARGS); @@ -446,8 +435,6 @@ extern Datum oidge(PG_FUNCTION_ARGS); extern Datum oidgt(PG_FUNCTION_ARGS); extern Datum oidlarger(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 oidvectorout(PG_FUNCTION_ARGS); extern Datum oidvectorrecv(PG_FUNCTION_ARGS); @@ -782,8 +769,6 @@ extern Datum network_show(PG_FUNCTION_ARGS); extern Datum inet_abbrev(PG_FUNCTION_ARGS); extern Datum cidr_abbrev(PG_FUNCTION_ARGS); 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_set_masklen(PG_FUNCTION_ARGS); extern Datum cidr_set_masklen(PG_FUNCTION_ARGS); @@ -814,8 +799,6 @@ extern Datum macaddr_ge(PG_FUNCTION_ARGS); extern Datum macaddr_gt(PG_FUNCTION_ARGS); extern Datum macaddr_ne(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); /* numeric.c */ @@ -866,8 +849,6 @@ extern Datum numeric_float8(PG_FUNCTION_ARGS); extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); extern Datum float4_numeric(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_avg_accum(PG_FUNCTION_ARGS); extern Datum int2_accum(PG_FUNCTION_ARGS); @@ -970,7 +951,5 @@ extern Datum uuid_gt(PG_FUNCTION_ARGS); extern Datum uuid_ne(PG_FUNCTION_ARGS); extern Datum uuid_cmp(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 */ diff --git a/src/include/utils/date.h b/src/include/utils/date.h index e58c6a03b90f1c0962f21b82c54b13a3a3de184a..c7f9f7323920ae174542ee80a494570040f9559e 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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); extern Datum timestamptz_date(PG_FUNCTION_ARGS); extern Datum datetime_timestamp(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_out(PG_FUNCTION_ARGS); @@ -158,8 +156,6 @@ extern Datum timestamp_time(PG_FUNCTION_ARGS); extern Datum timestamptz_time(PG_FUNCTION_ARGS); extern Datum time_interval(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_mi_interval(PG_FUNCTION_ARGS); extern Datum time_part(PG_FUNCTION_ARGS); @@ -186,8 +182,6 @@ extern Datum timetz_time(PG_FUNCTION_ARGS); extern Datum time_timetz(PG_FUNCTION_ARGS); extern Datum timestamptz_timetz(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_zone(PG_FUNCTION_ARGS); extern Datum timetz_izone(PG_FUNCTION_ARGS); diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index d43cf6450a0f6e72407c83e24161a9257decb689..1331d554f9a17dd79e301d7d3dff33f979203213 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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 * These data types are supported on all 64-bit architectures, and may @@ -111,9 +111,6 @@ extern Datum ftoi8(PG_FUNCTION_ARGS); extern Datum i8tooid(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_step_int8(PG_FUNCTION_ARGS); diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 5923c354936594db7cf878d3c68b71f81da1276b..629aa36564208f4d4d7a7e58e383b6470c5a7c9d 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * 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); extern Datum interval_justify_hours(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 interval_trunc(PG_FUNCTION_ARGS); extern Datum timestamp_part(PG_FUNCTION_ARGS); @@ -291,8 +287,6 @@ extern Datum timestamp_mi_interval(PG_FUNCTION_ARGS); extern Datum timestamp_age(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_mi_interval(PG_FUNCTION_ARGS); extern Datum timestamptz_age(PG_FUNCTION_ARGS); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index af6430f1ff434c582044079a3ba562e511178d4c..2582935452d0150c76ff429476c414f8fa00b4d8 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -8,7 +8,7 @@ * * * 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) case T_RelabelType: return exec_simple_check_node((Node *) ((RelabelType *) node)->arg); + case T_CoerceViaIO: + return exec_simple_check_node((Node *) ((CoerceViaIO *) node)->arg); + case T_ArrayCoerceExpr: return exec_simple_check_node((Node *) ((ArrayCoerceExpr *) node)->arg); diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 41c2f397882daf8d032f0dd12a6b74a4b867cf1b..3c0dd7f0872df01829d8e5a518c98e4b822a6ff1 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -1125,10 +1125,12 @@ ALTER TABLE fktable ADD CONSTRAINT fk_3_1 FOREIGN KEY (x3) REFERENCES pktable(id1); ERROR: foreign key constraint "fk_3_1" cannot be implemented DETAIL: Key columns "x3" and "id1" are of incompatible types: real and integer. --- should succeed --- int4 promotes to text, so this is allowed (though pretty durn debatable) +-- int4 does not promote to text ALTER TABLE fktable ADD CONSTRAINT fk_1_2 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 ALTER TABLE fktable ADD CONSTRAINT fk_1_3 FOREIGN KEY (x1) REFERENCES pktable(id3); @@ -1150,7 +1152,7 @@ FOREIGN KEY (x2,x5,x3) REFERENCES pktable(id2,id1,id3); ALTER TABLE fktable ADD CONSTRAINT fk_123_231 FOREIGN KEY (x1,x2,x3) REFERENCES pktable(id2,id3,id1); 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 FOREIGN KEY (x2,x4,x1) REFERENCES pktable(id1,id3,id2); 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 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 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 fk_1_3 on table fktable NOTICE: drop cascades to constraint fktable_x3_fkey on table fktable diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index bd82846b1a41f8da60830fdf888839d4d178b8e7..31ab2bb546379cc28db93956e1cd2a656512df7c 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -450,7 +450,7 @@ SELECT POSITION('4' IN '1234567890') = '4' AS "4"; t (1 row) -SELECT POSITION(5 IN '1234567890') = '5' AS "5"; +SELECT POSITION('5' IN '1234567890') = '5' AS "5"; 5 --- t diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index f36b5acfe8653f51d82d14c0e1ae2a28b8fa16de..5f50ba6e00d03dfbefb2bf12776b547b0ae2ee3b 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -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 parts (partnum, cost) values (1, 1234.56); 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; ttype | ordnum | partnum | value -------+--------+---------+--------- diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index 16eee1e75456ae4e71e68a12701e2f6bd9ae75c3..5a0140c280ea969c0f376133438b4eedab1e0019 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -760,12 +760,12 @@ FOREIGN KEY (x2) REFERENCES pktable(id1); ALTER TABLE fktable ADD CONSTRAINT fk_3_1 FOREIGN KEY (x3) REFERENCES pktable(id1); --- should succeed - --- int4 promotes to text, so this is allowed (though pretty durn debatable) +-- int4 does not promote to text ALTER TABLE fktable ADD CONSTRAINT fk_1_2 FOREIGN KEY (x1) REFERENCES pktable(id2); +-- should succeed + -- int4 promotes to real ALTER TABLE fktable ADD CONSTRAINT fk_1_3 FOREIGN KEY (x1) REFERENCES pktable(id3); diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index 800028e4fcbdc0bfed7db3abf4b735cde028e5f4..43b35ab667ffbc4d03a627e28e4f8e1845622a3d 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -142,7 +142,7 @@ SELECT regexp_split_to_array('thE QUick bROWn FOx jUMPed ovEr THE lazy dOG', 'e' -- E021-11 position expression 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 SELECT OVERLAY('abcdef' PLACING '45' FROM 4) AS "abc45f"; diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index b8cb45c6fc75d0204f6cecb68f978e0ba13edbd1..3c501f1d1bac6e19be11aa3f74fb6351f228d354 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -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 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;