Обсуждение: Implicit coercions need to be reined in

Поиск
Список
Период
Сортировка

Implicit coercions need to be reined in

От
Tom Lane
Дата:
Currently, if PG has a single-argument function named after its result
type, the function is assumed to represent a valid implicit type
coercion.  For example, I can do

regression=# select now() || now();                         ?column?
------------------------------------------------------------2001-11-21 15:12:13.226482-052001-11-21 15:12:13.226482-05
(1 row)

because there is a function text(timestamp) returning text, and
this function gets invoked implicitly.

It strikes me that this is a bad idea, and will get a lot worse as we
add more conversion functions.  With enough implicit coercions one will
never be entirely sure how the system will interpret a mixed-datatype
expression.  Nonetheless, having more conversion functions seems like a
good idea --- I think there should be a numeric-to-text conversion
function, for example, and someone was just complaining in pggeneral
about the lack of a boolean-to-text coercion.  The problem is that
there's no way to create a conversion function without inducing an
implicit coercion path (unless you give the function a nonobvious name).

What I'd like to suggest (for 7.3 or later) is adding a boolean column
to pg_proc that indicates "can be implicit coercion".  A function for
which this is not set can be used as an explicitly requested coercion,
but not an implicit one.  Thus it'd be possible to define text(boolean)
and allow it to be called explicitly, without creating an implicit
coercion path and thereby losing a lot of type safety.

I have not gone over the existing implicit coercions to see which ones
I like and don't like, but I think a good first cut at maintaining
sanity would be to disable any cross-type-category implicit coercions.
Thus, for example, int4 to float8 seems like an okay implicit coercion,
but not int4 to text.

Note that this would cause the system to reject some things it accepts
now, for example:

regression=# select 45::int4 || 66::int4;?column?
----------4566
(1 row)

This sort of thing would need explicit coercions to text under my proposal.

Comments?
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Stephan Szabo
Дата:
On Wed, 21 Nov 2001, Tom Lane wrote:

> It strikes me that this is a bad idea, and will get a lot worse as we
> add more conversion functions.  With enough implicit coercions one will
> never be entirely sure how the system will interpret a mixed-datatype
> expression.  Nonetheless, having more conversion functions seems like a
> good idea --- I think there should be a numeric-to-text conversion
> function, for example, and someone was just complaining in pggeneral
> about the lack of a boolean-to-text coercion.  The problem is that
> there's no way to create a conversion function without inducing an
> implicit coercion path (unless you give the function a nonobvious name).
>
> What I'd like to suggest (for 7.3 or later) is adding a boolean column
> to pg_proc that indicates "can be implicit coercion".  A function for
> which this is not set can be used as an explicitly requested coercion,
> but not an implicit one.  Thus it'd be possible to define text(boolean)
> and allow it to be called explicitly, without creating an implicit
> coercion path and thereby losing a lot of type safety.

I think something of this sort is a good thing. :) It's a bit of a pain in
one way, but it makes understanding what's going on simpler, especially
given things like the person who was getting text cut off at 31 or
whatever characters due to the fact that there was an implicit coercion
through name.



Re: Implicit coercions need to be reined in

От
"Zeugswetter Andreas SB SD"
Дата:
> Thus, for example, int4 to float8 seems like an okay implicit
coercion,
> but not int4 to text.

int4 to text is imho one of the most important implicit coercions of
all.
Still, a field to mark an implicit coercion function is probably a good
thing. 

Imho a numeric to text implicit coercion would also be great :-) 

I come from a db where all coercions are possible implicitly,
this has not been a problem as long as there is a way to overrule.

Andreas


Re: Implicit coercions need to be reined in

От
Peter Eisentraut
Дата:
Tom Lane writes:

> What I'd like to suggest (for 7.3 or later) is adding a boolean column
> to pg_proc that indicates "can be implicit coercion".

Great!  I've always wished for this sort of thing.

I think from this there are only a few more steps to the full SQL99
specification of user-defined casts.  In particular it'd involve two
boolean flags: one that means "this is a cast function" (the function is
used internally for a CAST() invocation), and one for allowing it to be
used for automatic conversion.  We currently don't have the first one on
the radar because we use the function name and argument types as the
indicator.

One more thing is that instead of looking up a cast function from type A
to type B as "returns A, is named A, takes arg B" it could be looked up as
"returns A, takes arg B, is a cast function", which would generalize this
whole thing a bit more.

References: SQL99 Part 2 11.49, 11.52  (I haven't read the whole thing,
but I think it's the idea.)

-- 
Peter Eisentraut   peter_e@gmx.net



Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
"Zeugswetter Andreas SB SD" <ZeugswetterA@spardat.at> writes:
> I come from a db where all coercions are possible implicitly,
> this has not been a problem as long as there is a way to overrule.

Yeah, but how rich was its type structure compared to Postgres'?

It might indeed be safe/reasonable to allow implicit coercions to
text from all other types.  I'm not sure.  I am sure that if any
datatype coercion one could possibly want is available implicitly,
it's going to be very difficult to predict the system's behavior.
In fact, this would probably make the default behavior appear to
have *fewer* automatic coercions not more: anytime there wasn't
an exact type match, the parser would have too many alternatives
and would be unable to select a unique function or operator candidate
from among those it could reach by means of implicit coercions.
We've seen some reports of such problems already, and it'll get worse
as we add implicit coercions.

Of course, you could always turn on the "can be implicit coercion"
flag for whichever pg_proc entries you really wanted ...
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Peter Eisentraut <peter_e@gmx.net> writes:
> One more thing is that instead of looking up a cast function from type A
> to type B as "returns A, is named A, takes arg B" it could be looked up as
> "returns A, takes arg B, is a cast function", which would generalize this
> whole thing a bit more.

I thought about that, but it would require keeping an extra index on
pg_proc (there's no efficient way to search by result type now).  Not
clear that it's worth it, especially considering that there's really
only one reasonable name for a cast function anyway.  What else would
you want to call it than the name of the destination type?

Also, this convention assures that there's at most *one* cast function
for any type coercion A to B.  If the name could be anything then we'd
need some auxiliary mechanism to prevent conflicting cast functions
from being declared.  Seems like a lot of mechanism for a dubious goal.
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Awhile back I suggested adding a boolean column to pg_proc to control
which type coercion functions could be invoked implicitly, and which
would need an explicit cast:
http://archives.postgresql.org/pgsql-hackers/2001-11/msg00803.php
There is a relevant bug report #484 showing the dangers of too many
implicit coercion paths:
http://archives.postgresql.org/pgsql-bugs/2001-10/msg00108.php

I have added such a column as part of the pg_proc changes I'm currently
doing to migrate aggregates into pg_proc.  So it's now time to debate
the nitty-gritty: exactly which coercion functions should not be
implicitly invokable anymore?

My first-cut attempt at this is shown by the two printouts below.
The first cut does not allow any implicit coercions to text from types
that are not in the text category, which seems a necessary rule to me
--- the above-cited bug report shows why free coercions to text are
dangerous.  However, it turns out that several of the regression
tests fail with this rule; see the regression diffs below.

Should I consider these regression tests wrong, and correct them?
If not, how can we limit implicit coercions to text enough to avoid
the problems illustrated by bug #484?

Another interesting point is that I allowed implicit coercions from
float8 to numeric; this is necessary to avoid breaking cases likeinsert into foo(numeric_col) values(12.34);
since the constant will be initially typed as float8.  However, because
I didn't allow the reverse coercion implicitly, this makes numeric
"more preferred" than float8.  Thus, for example,select '12.34'::numeric + 12.34;
which draws a can't-resolve-operator error in 7.2, is resolved as
numeric addition with these changes.  Is this a good thing, or not?
We could preserve the can't-resolve behavior by marking numeric->float8
as an allowed implicit coercion, but that seems ugly.  I'm not sure we
can do a whole lot better without some more wide-ranging revisions of
the way we handle untyped numeric literals (as in past proposals to
invent an UNKNOWNNUMERIC pseudo-type).

Also, does anyone have any other nits to pick with this classification
of which coercions are implicitly okay?  I've started with a fairly
tough approach of disallowing most implicit coercions, but perhaps this
goes too far.
        regards, tom lane

Coercions allowed implicitly:
oid  |   result    |    input    |        prosrc         
------+-------------+-------------+----------------------- 860 | bpchar      | char        | char_bpchar 408 | bpchar
  | name        | name_bpchar 861 | char        | bpchar      | bpchar_char 944 | char        | text        | text_char
312| float4      | float8      | dtof 236 | float4      | int2        | i2tof 318 | float4      | int4        | i4tof
311| float8      | float4      | ftod 235 | float8      | int2        | i2tod 316 | float8      | int4        | i4tod
482| float8      | int8        | i8tod 314 | int2        | int4        | i4toi2 714 | int2        | int8        | int82
313| int4        | int2        | i2toi4 480 | int4        | int8        | int84 754 | int8        | int2        | int28
481| int8        | int4        | int481177 | interval    | reltime     | reltime_interval1370 | interval    | time
 | time_interval 409 | name        | bpchar      | bpchar_name 407 | name        | text        | text_name1400 | name
    | varchar     | text_name1742 | numeric     | float4      | float4_numeric1743 | numeric     | float8      |
float8_numeric1782| numeric     | int2        | int2_numeric1740 | numeric     | int4        | int4_numeric1781 |
numeric    | int8        | int8_numeric 946 | text        | char        | char_text 406 | text        | name        |
name_text2046| time        | timetz      | timetz_time2023 | timestamp   | abstime     | abstime_timestamp2024 |
timestamp  | date        | date_timestamp2027 | timestamp   | timestamptz | timestamptz_timestamp1173 | timestamptz |
abstime    | abstime_timestamptz1174 | timestamptz | date        | date_timestamptz2028 | timestamptz | timestamp   |
timestamp_timestamptz2047| timetz      | time        | time_timetz1401 | varchar     | name        | name_text
 
(38 rows)

Coercions that will require explicit CAST, ::type, or typename(x) syntax
(NB: in 7.2 all of these would have been allowed implicitly):
oid  |   result    |    input    |                        prosrc
------+-------------+-------------+------------------------------------------2030 | abstime     | timestamp   |
timestamp_abstime1180| abstime     | timestamptz | timestamptz_abstime1480 | box         | circle      | circle_box1446
|box         | polygon     | poly_box1714 | cidr        | text        | text_cidr1479 | circle      | box         |
box_circle1474| circle      | polygon     | poly_circle1179 | date        | abstime     | abstime_date 748 | date
| text        | text_date2029 | date        | timestamp   | timestamp_date1178 | date        | timestamptz |
timestamptz_date1745| float4      | numeric     | numeric_float4 839 | float4      | text        | text_float41746 |
float8     | numeric     | numeric_float8 838 | float8      | text        | text_float81713 | inet        | text
|text_inet 238 | int2        | float4      | ftoi2 237 | int2        | float8      | dtoi21783 | int2        | numeric
  | numeric_int2 818 | int2        | text        | text_int2 319 | int4        | float4      | ftoi4 317 | int4
|float8      | dtoi41744 | int4        | numeric     | numeric_int4 819 | int4        | text        | text_int4 483 |
int8       | float8      | dtoi81779 | int8        | numeric     | numeric_int81289 | int8        | text        |
text_int81263| interval    | text        | text_interval1541 | lseg        | box         | box_diagonal 767 | macaddr
 | text        | text_macaddr 817 | oid         | text        | text_oid1447 | path        | polygon     |
poly_path1534| point       | box         | box_center1416 | point       | circle      | circle_center1532 | point
|lseg        | lseg_center1533 | point       | path        | path_center1540 | point       | polygon     |
poly_center1448| polygon     | box         | box_poly1544 | polygon     | circle      | select polygon(12, $1)1449 |
polygon    | path        | path_poly1200 | reltime     | int4        | int4reltime1194 | reltime     | interval    |
interval_reltime749 | text        | date        | date_text 841 | text        | float4      | float4_text 840 | text
   | float8      | float8_text 730 | text        | inet        | network_show 113 | text        | int2        |
int2_text112 | text        | int4        | int4_text1288 | text        | int8        | int8_text1193 | text        |
interval   | interval_text 752 | text        | macaddr     | macaddr_text 114 | text        | oid         | oid_text
948| text        | time        | time_text2034 | text        | timestamp   | timestamp_text1192 | text        |
timestamptz| timestamptz_text 939 | text        | timetz      | timetz_text1364 | time        | abstime     | select
time(cast($1as timestamp without time zone))1419 | time        | interval    | interval_time 837 | time        | text
    | text_time1316 | time        | timestamp   | timestamp_time2022 | timestamp   | text        | text_timestamp1191 |
timestamptz| text        | text_timestamptz 938 | timetz      | text        | text_timetz1388 | timetz      |
timestamptz| timestamptz_timetz1619 | varchar     | int4        | int4_text1623 | varchar     | int8        |
int8_text
(66 rows)


Regression failures with this set of choices (I've edited the output to
remove diffs that are merely consequences of the actual failures):

*** ./expected/char.out    Mon May 21 12:54:46 2001
--- ./results/char.out    Wed Apr 10 11:48:16 2002
***************
*** 18,23 ****
--- 18,25 ---- -- any of the following three input formats are acceptable  INSERT INTO CHAR_TBL (f1) VALUES ('1');
INSERTINTO CHAR_TBL (f1) VALUES (2);
 
+ ERROR:  column "f1" is of type 'character' but expression is of type 'integer'
+     You will need to rewrite or cast the expression INSERT INTO CHAR_TBL (f1) VALUES ('3'); -- zero-length char
INSERTINTO CHAR_TBL (f1) VALUES ('');
 

*** ./expected/varchar.out    Mon May 21 12:54:46 2001
--- ./results/varchar.out    Wed Apr 10 11:48:17 2002
***************
*** 7,12 ****
--- 7,14 ---- -- any of the following three input formats are acceptable  INSERT INTO VARCHAR_TBL (f1) VALUES ('1');
INSERTINTO VARCHAR_TBL (f1) VALUES (2);
 
+ ERROR:  column "f1" is of type 'character varying' but expression is of type 'integer'
+     You will need to rewrite or cast the expression INSERT INTO VARCHAR_TBL (f1) VALUES ('3'); -- zero-length char
INSERTINTO VARCHAR_TBL (f1) VALUES ('');
 

*** ./expected/strings.out    Fri Jun  1 13:49:17 2001
--- ./results/strings.out    Wed Apr 10 11:49:29 2002
***************
*** 137,147 **** (1 row)  SELECT POSITION(5 IN '1234567890') = '5' AS "5";
!  5 
! ---
!  t
! (1 row)
!  -- -- test LIKE -- Be sure to form every test as a LIKE/NOT LIKE pair.
--- 137,145 ---- (1 row)  SELECT POSITION(5 IN '1234567890') = '5' AS "5";
! ERROR:  Function 'pg_catalog.position(unknown, int4)' does not exist
!     Unable to identify a function that satisfies the given argument types
!     You may need to add explicit typecasts -- -- test LIKE -- Be sure to form every test as a LIKE/NOT LIKE pair.

*** ./expected/alter_table.out    Fri Apr  5 12:03:45 2002
--- ./results/alter_table.out    Wed Apr 10 11:51:06 2002
***************
*** 363,374 **** CREATE TEMP TABLE FKTABLE (ftest1 varchar); ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references
pktable;NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s) -- As should this ALTER TABLE
FKTABLEADD FOREIGN KEY(ftest1) references pktable(ptest1); NOTICE:  ALTER TABLE will create implicit trigger(s) for
FOREIGNKEY check(s) DROP TABLE pktable;
 
- NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
- NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable" DROP TABLE fktable; CREATE
TEMPTABLE PKTABLE (ptest1 int, ptest2 text,                            PRIMARY KEY(ptest1, ptest2));
 
--- 363,376 ---- CREATE TEMP TABLE FKTABLE (ftest1 varchar); ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references
pktable;NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 
+ ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
+     You will have to retype this query using an explicit cast -- As should this ALTER TABLE FKTABLE ADD FOREIGN
KEY(ftest1)references pktable(ptest1); NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 
+ ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
+     You will have to retype this query using an explicit cast DROP TABLE pktable; DROP TABLE fktable; CREATE TEMP
TABLEPKTABLE (ptest1 int, ptest2 text,                            PRIMARY KEY(ptest1, ptest2));
 

*** ./expected/rules.out    Thu Mar 21 10:24:35 2002
--- ./results/rules.out    Wed Apr 10 11:51:11 2002
***************
*** 1026,1037 ****                                         'Al Bundy',
'epoch'::text                                    ); UPDATE shoelace_data SET sl_avail = 6 WHERE  sl_name = 'sl7';
SELECT* FROM shoelace_log;   sl_name   | sl_avail | log_who  |         log_when         
 
! ------------+----------+----------+--------------------------
!  sl7        |        6 | Al Bundy | Thu Jan 01 00:00:00 1970
! (1 row)      CREATE RULE shoelace_ins AS ON INSERT TO shoelace         DO INSTEAD
--- 1026,1038 ----                                         'Al Bundy',
'epoch'::text                                    );
 
+ ERROR:  column "log_when" is of type 'timestamp without time zone' but expression is of type 'text'
+     You will need to rewrite or cast the expression UPDATE shoelace_data SET sl_avail = 6 WHERE  sl_name = 'sl7';
SELECT* FROM shoelace_log;  sl_name | sl_avail | log_who | log_when 
 
! ---------+----------+---------+----------
! (0 rows)      CREATE RULE shoelace_ins AS ON INSERT TO shoelace         DO INSTEAD

*** ./expected/foreign_key.out    Wed Mar  6 01:10:56 2002
--- ./results/foreign_key.out    Wed Apr 10 11:51:17 2002
***************
*** 733,747 **** -- because varchar=int does exist CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable); NOTICE:
CREATETABLE will create implicit trigger(s) for FOREIGN KEY check(s) DROP TABLE FKTABLE;
 
! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable" -- As should this CREATE
TABLEFKTABLE (ftest1 varchar REFERENCES pktable(ptest1)); NOTICE:  CREATE TABLE will create implicit trigger(s) for
FOREIGNKEY check(s) DROP TABLE FKTABLE;
 
! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable" DROP TABLE PKTABLE; -- Two
columns,two tables CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
 
--- 733,749 ---- -- because varchar=int does exist CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable); NOTICE:
CREATETABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 
+ ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
+     You will have to retype this query using an explicit cast DROP TABLE FKTABLE;
! ERROR:  table "fktable" does not exist -- As should this CREATE TABLE FKTABLE (ftest1 varchar REFERENCES
pktable(ptest1));NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 
+ ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
+     You will have to retype this query using an explicit cast DROP TABLE FKTABLE;
! ERROR:  table "fktable" does not exist DROP TABLE PKTABLE; -- Two columns, two tables CREATE TABLE PKTABLE (ptest1
int,ptest2 text, PRIMARY KEY(ptest1, ptest2));
 

*** ./expected/domain.out    Wed Mar 20 13:34:37 2002
--- ./results/domain.out    Wed Apr 10 11:51:23 2002
***************
*** 111,116 ****
--- 111,118 ---- create domain ddef2 oid DEFAULT '12'; -- Type mixing, function returns int8 create domain ddef3 text
DEFAULT5;
 
+ ERROR:  Column "ddef3" is of type text but default expression is of type integer
+     You will need to rewrite or cast the expression create sequence ddef4_seq; create domain ddef4 int4 DEFAULT
nextval(cast('ddef4_seq'as text)); create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
 


Re: Implicit coercions need to be reined in

От
Barry Lind
Дата:
Tom,

My feeling is that this change as currently scoped will break a lot of 
existing apps.  Especially the case where people are using where clauses 
of the form:   bigintcolumn = '999'  to get a query to use the index on 
a column of type bigint.

thanks,
--Barry


Tom Lane wrote:
> Awhile back I suggested adding a boolean column to pg_proc to control
> which type coercion functions could be invoked implicitly, and which
> would need an explicit cast:
> http://archives.postgresql.org/pgsql-hackers/2001-11/msg00803.php
> There is a relevant bug report #484 showing the dangers of too many
> implicit coercion paths:
> http://archives.postgresql.org/pgsql-bugs/2001-10/msg00108.php
> 
> I have added such a column as part of the pg_proc changes I'm currently
> doing to migrate aggregates into pg_proc.  So it's now time to debate
> the nitty-gritty: exactly which coercion functions should not be
> implicitly invokable anymore?
> 
> My first-cut attempt at this is shown by the two printouts below.
> The first cut does not allow any implicit coercions to text from types
> that are not in the text category, which seems a necessary rule to me
> --- the above-cited bug report shows why free coercions to text are
> dangerous.  However, it turns out that several of the regression
> tests fail with this rule; see the regression diffs below.
> 
> Should I consider these regression tests wrong, and correct them?
> If not, how can we limit implicit coercions to text enough to avoid
> the problems illustrated by bug #484?
> 
> Another interesting point is that I allowed implicit coercions from
> float8 to numeric; this is necessary to avoid breaking cases like
>     insert into foo(numeric_col) values(12.34);
> since the constant will be initially typed as float8.  However, because
> I didn't allow the reverse coercion implicitly, this makes numeric
> "more preferred" than float8.  Thus, for example,
>     select '12.34'::numeric + 12.34;
> which draws a can't-resolve-operator error in 7.2, is resolved as
> numeric addition with these changes.  Is this a good thing, or not?
> We could preserve the can't-resolve behavior by marking numeric->float8
> as an allowed implicit coercion, but that seems ugly.  I'm not sure we
> can do a whole lot better without some more wide-ranging revisions of
> the way we handle untyped numeric literals (as in past proposals to
> invent an UNKNOWNNUMERIC pseudo-type).
> 
> Also, does anyone have any other nits to pick with this classification
> of which coercions are implicitly okay?  I've started with a fairly
> tough approach of disallowing most implicit coercions, but perhaps this
> goes too far.
> 
>             regards, tom lane
> 
> Coercions allowed implicitly:
> 
>  oid  |   result    |    input    |        prosrc         
> ------+-------------+-------------+-----------------------
>   860 | bpchar      | char        | char_bpchar
>   408 | bpchar      | name        | name_bpchar
>   861 | char        | bpchar      | bpchar_char
>   944 | char        | text        | text_char
>   312 | float4      | float8      | dtof
>   236 | float4      | int2        | i2tof
>   318 | float4      | int4        | i4tof
>   311 | float8      | float4      | ftod
>   235 | float8      | int2        | i2tod
>   316 | float8      | int4        | i4tod
>   482 | float8      | int8        | i8tod
>   314 | int2        | int4        | i4toi2
>   714 | int2        | int8        | int82
>   313 | int4        | int2        | i2toi4
>   480 | int4        | int8        | int84
>   754 | int8        | int2        | int28
>   481 | int8        | int4        | int48
>  1177 | interval    | reltime     | reltime_interval
>  1370 | interval    | time        | time_interval
>   409 | name        | bpchar      | bpchar_name
>   407 | name        | text        | text_name
>  1400 | name        | varchar     | text_name
>  1742 | numeric     | float4      | float4_numeric
>  1743 | numeric     | float8      | float8_numeric
>  1782 | numeric     | int2        | int2_numeric
>  1740 | numeric     | int4        | int4_numeric
>  1781 | numeric     | int8        | int8_numeric
>   946 | text        | char        | char_text
>   406 | text        | name        | name_text
>  2046 | time        | timetz      | timetz_time
>  2023 | timestamp   | abstime     | abstime_timestamp
>  2024 | timestamp   | date        | date_timestamp
>  2027 | timestamp   | timestamptz | timestamptz_timestamp
>  1173 | timestamptz | abstime     | abstime_timestamptz
>  1174 | timestamptz | date        | date_timestamptz
>  2028 | timestamptz | timestamp   | timestamp_timestamptz
>  2047 | timetz      | time        | time_timetz
>  1401 | varchar     | name        | name_text
> (38 rows)
> 
> Coercions that will require explicit CAST, ::type, or typename(x) syntax
> (NB: in 7.2 all of these would have been allowed implicitly):
> 
>  oid  |   result    |    input    |                        prosrc
> ------+-------------+-------------+------------------------------------------
>  2030 | abstime     | timestamp   | timestamp_abstime
>  1180 | abstime     | timestamptz | timestamptz_abstime
>  1480 | box         | circle      | circle_box
>  1446 | box         | polygon     | poly_box
>  1714 | cidr        | text        | text_cidr
>  1479 | circle      | box         | box_circle
>  1474 | circle      | polygon     | poly_circle
>  1179 | date        | abstime     | abstime_date
>   748 | date        | text        | text_date
>  2029 | date        | timestamp   | timestamp_date
>  1178 | date        | timestamptz | timestamptz_date
>  1745 | float4      | numeric     | numeric_float4
>   839 | float4      | text        | text_float4
>  1746 | float8      | numeric     | numeric_float8
>   838 | float8      | text        | text_float8
>  1713 | inet        | text        | text_inet
>   238 | int2        | float4      | ftoi2
>   237 | int2        | float8      | dtoi2
>  1783 | int2        | numeric     | numeric_int2
>   818 | int2        | text        | text_int2
>   319 | int4        | float4      | ftoi4
>   317 | int4        | float8      | dtoi4
>  1744 | int4        | numeric     | numeric_int4
>   819 | int4        | text        | text_int4
>   483 | int8        | float8      | dtoi8
>  1779 | int8        | numeric     | numeric_int8
>  1289 | int8        | text        | text_int8
>  1263 | interval    | text        | text_interval
>  1541 | lseg        | box         | box_diagonal
>   767 | macaddr     | text        | text_macaddr
>   817 | oid         | text        | text_oid
>  1447 | path        | polygon     | poly_path
>  1534 | point       | box         | box_center
>  1416 | point       | circle      | circle_center
>  1532 | point       | lseg        | lseg_center
>  1533 | point       | path        | path_center
>  1540 | point       | polygon     | poly_center
>  1448 | polygon     | box         | box_poly
>  1544 | polygon     | circle      | select polygon(12, $1)
>  1449 | polygon     | path        | path_poly
>  1200 | reltime     | int4        | int4reltime
>  1194 | reltime     | interval    | interval_reltime
>   749 | text        | date        | date_text
>   841 | text        | float4      | float4_text
>   840 | text        | float8      | float8_text
>   730 | text        | inet        | network_show
>   113 | text        | int2        | int2_text
>   112 | text        | int4        | int4_text
>  1288 | text        | int8        | int8_text
>  1193 | text        | interval    | interval_text
>   752 | text        | macaddr     | macaddr_text
>   114 | text        | oid         | oid_text
>   948 | text        | time        | time_text
>  2034 | text        | timestamp   | timestamp_text
>  1192 | text        | timestamptz | timestamptz_text
>   939 | text        | timetz      | timetz_text
>  1364 | time        | abstime     | select time(cast($1 as timestamp without time zone))
>  1419 | time        | interval    | interval_time
>   837 | time        | text        | text_time
>  1316 | time        | timestamp   | timestamp_time
>  2022 | timestamp   | text        | text_timestamp
>  1191 | timestamptz | text        | text_timestamptz
>   938 | timetz      | text        | text_timetz
>  1388 | timetz      | timestamptz | timestamptz_timetz
>  1619 | varchar     | int4        | int4_text
>  1623 | varchar     | int8        | int8_text
> (66 rows)
> 
> 
> Regression failures with this set of choices (I've edited the output to
> remove diffs that are merely consequences of the actual failures):
> 
> *** ./expected/char.out    Mon May 21 12:54:46 2001
> --- ./results/char.out    Wed Apr 10 11:48:16 2002
> ***************
> *** 18,23 ****
> --- 18,25 ----
>   -- any of the following three input formats are acceptable 
>   INSERT INTO CHAR_TBL (f1) VALUES ('1');
>   INSERT INTO CHAR_TBL (f1) VALUES (2);
> + ERROR:  column "f1" is of type 'character' but expression is of type 'integer'
> +     You will need to rewrite or cast the expression
>   INSERT INTO CHAR_TBL (f1) VALUES ('3');
>   -- zero-length char 
>   INSERT INTO CHAR_TBL (f1) VALUES ('');
> 
> *** ./expected/varchar.out    Mon May 21 12:54:46 2001
> --- ./results/varchar.out    Wed Apr 10 11:48:17 2002
> ***************
> *** 7,12 ****
> --- 7,14 ----
>   -- any of the following three input formats are acceptable 
>   INSERT INTO VARCHAR_TBL (f1) VALUES ('1');
>   INSERT INTO VARCHAR_TBL (f1) VALUES (2);
> + ERROR:  column "f1" is of type 'character varying' but expression is of type 'integer'
> +     You will need to rewrite or cast the expression
>   INSERT INTO VARCHAR_TBL (f1) VALUES ('3');
>   -- zero-length char 
>   INSERT INTO VARCHAR_TBL (f1) VALUES ('');
> 
> *** ./expected/strings.out    Fri Jun  1 13:49:17 2001
> --- ./results/strings.out    Wed Apr 10 11:49:29 2002
> ***************
> *** 137,147 ****
>   (1 row)
>   
>   SELECT POSITION(5 IN '1234567890') = '5' AS "5";
> !  5 
> ! ---
> !  t
> ! (1 row)
> ! 
>   --
>   -- test LIKE
>   -- Be sure to form every test as a LIKE/NOT LIKE pair.
> --- 137,145 ----
>   (1 row)
>   
>   SELECT POSITION(5 IN '1234567890') = '5' AS "5";
> ! ERROR:  Function 'pg_catalog.position(unknown, int4)' does not exist
> !     Unable to identify a function that satisfies the given argument types
> !     You may need to add explicit typecasts
>   --
>   -- test LIKE
>   -- Be sure to form every test as a LIKE/NOT LIKE pair.
> 
> *** ./expected/alter_table.out    Fri Apr  5 12:03:45 2002
> --- ./results/alter_table.out    Wed Apr 10 11:51:06 2002
> ***************
> *** 363,374 ****
>   CREATE TEMP TABLE FKTABLE (ftest1 varchar);
>   ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
>   NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
>   -- As should this
>   ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
>   NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
>   DROP TABLE pktable;
> - NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
> - NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "fktable"
>   DROP TABLE fktable;
>   CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 text,
>                              PRIMARY KEY(ptest1, ptest2));
> --- 363,376 ----
>   CREATE TEMP TABLE FKTABLE (ftest1 varchar);
>   ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
>   NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
> + ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
> +     You will have to retype this query using an explicit cast
>   -- As should this
>   ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
>   NOTICE:  ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
> + ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
> +     You will have to retype this query using an explicit cast
>   DROP TABLE pktable;
>   DROP TABLE fktable;
>   CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 text,
>                              PRIMARY KEY(ptest1, ptest2));
> 
> *** ./expected/rules.out    Thu Mar 21 10:24:35 2002
> --- ./results/rules.out    Wed Apr 10 11:51:11 2002
> ***************
> *** 1026,1037 ****
>                                           'Al Bundy',
>                                           'epoch'::text
>                                       );
>   UPDATE shoelace_data SET sl_avail = 6 WHERE  sl_name = 'sl7';
>   SELECT * FROM shoelace_log;
>     sl_name   | sl_avail | log_who  |         log_when         
> ! ------------+----------+----------+--------------------------
> !  sl7        |        6 | Al Bundy | Thu Jan 01 00:00:00 1970
> ! (1 row)
>   
>       CREATE RULE shoelace_ins AS ON INSERT TO shoelace
>           DO INSTEAD
> --- 1026,1038 ----
>                                           'Al Bundy',
>                                           'epoch'::text
>                                       );
> + ERROR:  column "log_when" is of type 'timestamp without time zone' but expression is of type 'text'
> +     You will need to rewrite or cast the expression
>   UPDATE shoelace_data SET sl_avail = 6 WHERE  sl_name = 'sl7';
>   SELECT * FROM shoelace_log;
>    sl_name | sl_avail | log_who | log_when 
> ! ---------+----------+---------+----------
> ! (0 rows)
>   
>       CREATE RULE shoelace_ins AS ON INSERT TO shoelace
>           DO INSTEAD
> 
> *** ./expected/foreign_key.out    Wed Mar  6 01:10:56 2002
> --- ./results/foreign_key.out    Wed Apr 10 11:51:17 2002
> ***************
> *** 733,747 ****
>   -- because varchar=int does exist
>   CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable);
>   NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
>   DROP TABLE FKTABLE;
> ! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
> ! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
>   -- As should this
>   CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable(ptest1));
>   NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
>   DROP TABLE FKTABLE;
> ! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
> ! NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "pktable"
>   DROP TABLE PKTABLE;
>   -- Two columns, two tables
>   CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
> --- 733,749 ----
>   -- because varchar=int does exist
>   CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable);
>   NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
> + ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
> +     You will have to retype this query using an explicit cast
>   DROP TABLE FKTABLE;
> ! ERROR:  table "fktable" does not exist
>   -- As should this
>   CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable(ptest1));
>   NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
> + ERROR:  Unable to identify an operator '=' for types 'character varying' and 'integer'
> +     You will have to retype this query using an explicit cast
>   DROP TABLE FKTABLE;
> ! ERROR:  table "fktable" does not exist
>   DROP TABLE PKTABLE;
>   -- Two columns, two tables
>   CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
> 
> *** ./expected/domain.out    Wed Mar 20 13:34:37 2002
> --- ./results/domain.out    Wed Apr 10 11:51:23 2002
> ***************
> *** 111,116 ****
> --- 111,118 ----
>   create domain ddef2 oid DEFAULT '12';
>   -- Type mixing, function returns int8
>   create domain ddef3 text DEFAULT 5;
> + ERROR:  Column "ddef3" is of type text but default expression is of type integer
> +     You will need to rewrite or cast the expression
>   create sequence ddef4_seq;
>   create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
>   create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster
> 




Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Barry Lind <barry@xythos.com> writes:
> My feeling is that this change as currently scoped will break a lot of 
> existing apps.  Especially the case where people are using where clauses 
> of the form:   bigintcolumn = '999'  to get a query to use the index on 
> a column of type bigint.

Eh?  That case will not change behavior in the slightest, because
there's no type conversion --- the literal is interpreted as the target
type to start with.
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Barry Lind
Дата:
OK.  My mistake.  In looking at the regression failures in your post, I 
thought I saw errors being reported of this type.  My bad.

--Barry

Tom Lane wrote:
> Barry Lind <barry@xythos.com> writes:
> 
>>My feeling is that this change as currently scoped will break a lot of 
>>existing apps.  Especially the case where people are using where clauses 
>>of the form:   bigintcolumn = '999'  to get a query to use the index on 
>>a column of type bigint.
> 
> 
> Eh?  That case will not change behavior in the slightest, because
> there's no type conversion --- the literal is interpreted as the target
> type to start with.
> 
>             regards, tom lane
> 




Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Barry Lind <barry@xythos.com> writes:
> OK.  My mistake.  In looking at the regression failures in your post, I 
> thought I saw errors being reported of this type.  My bad.

Well, although that particular case isn't a problem, I am sure that this
change will break some existing applications --- the question is how
many, and do we feel that they're all poorly coded?

I suspect that the main thing that will cause issues is removal of
implicit coercions to text.  For example, in 7.2 and before you can do

test72=# select 'At the tone, the time will be ' || now();                         ?column?
-------------------------------------------------------------At the tone, the time will be 2002-04-11
11:49:27.309181-04
(1 row)

since there is an implicit timestamp->text coercion; or in a less
plausible example,

test72=# select 123 || (33.0/7.0);     ?column?
---------------------1234.71428571428571
(1 row)

With my proposed changes, both of these examples will require explicit
casts.  The latter case might not bother people but I'm sure that
someone out there is using code much like the former case.

Since I didn't see an immediate batch of squawks, I think I will go
ahead and commit what I have; we can always revisit the implicit-allowed
flag settings later.
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Thomas Lockhart
Дата:
...
> Since I didn't see an immediate batch of squawks, I think I will go
> ahead and commit what I have; we can always revisit the implicit-allowed
> flag settings later.

Squawk. But I haven't had time to look at the full ramifications of your
proposed change, so it is inappropriate to comment, right?

We have never been in complete agreement on the optimal behavior for
type coersion, but it seems that most users are blissfully ignorant of
the potential downsides of the current behavior. Another way to phrase
that would be to say that it actually does the right thing in the vast
majority of cases out in the field.

We'll probably both agree that it would be nice to avoid *hard coded*
rules of any kind for this, but do you share my concern that moving this
to a database table-driven set of rules will affect performance too
much?
                  - Thomas


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Thomas Lockhart <lockhart@fourpalms.org> writes:
> We have never been in complete agreement on the optimal behavior for
> type coersion, but it seems that most users are blissfully ignorant of
> the potential downsides of the current behavior. Another way to phrase
> that would be to say that it actually does the right thing in the vast
> majority of cases out in the field.

Could be; we probably see more complaints about the lack of any coercion
path for particular cases than about inappropriate implicit coercions.
But we do see a fair number of the latter.  (And in the cases where I've
resisted adding more coercions, it was precisely because I thought it'd
be dangerous to allow them implicitly --- that concern goes away once
we can mark a coercion function as not implicitly invokable.)

> We'll probably both agree that it would be nice to avoid *hard coded*
> rules of any kind for this, but do you share my concern that moving this
> to a database table-driven set of rules will affect performance too
> much?

AFAICT the performance cost is negligible: find_coercion_function has to
look at the pg_proc row anyway.  The relevant change looks like
                           PointerGetDatum(oid_array),                           ObjectIdGetDatum(typnamespace));
!     if (!HeapTupleIsValid(ftup))
!     {
!         ReleaseSysCache(targetType);
!         return InvalidOid;
!     }
!     /* Make sure the function's result type is as expected, too */
!     pform = (Form_pg_proc) GETSTRUCT(ftup);
!     if (pform->prorettype != targetTypeId)     {         ReleaseSysCache(ftup);
-         ReleaseSysCache(targetType);
-         return InvalidOid;     }
!     funcid = ftup->t_data->t_oid;
!     ReleaseSysCache(ftup);     ReleaseSysCache(targetType);     return funcid; }
--- 711,734 ----                           Int16GetDatum(nargs),                           PointerGetDatum(oid_array),
                        ObjectIdGetDatum(typnamespace));
 
!     if (HeapTupleIsValid(ftup))     {
+         Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
+ 
+         /* Make sure the function's result type is as expected */
+         if (pform->prorettype == targetTypeId && !pform->proretset &&
+             !pform->proisagg)
+         {
+             /* If needed, make sure it can be invoked implicitly */
+             if (isExplicit || pform->proimplicit)
+             {
+                 /* Okay to use it */
+                 funcid = ftup->t_data->t_oid;
+             }
+         }         ReleaseSysCache(ftup);     }
!      ReleaseSysCache(targetType);     return funcid; }


I do not see any reason not to install the mechanism; we can fine-tune
the actual pg_class.proimplicit settings as we get experience with them.
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Since it seems we still want to debate this a little, I've modified the
initial set of implicit-coercion-allowed flags to allow silent coercions
from the standard datatypes to text.  This un-breaks most of the
regression tests that were failing before.  I still want to debate the
wisdom of allowing this, but there's no point in changing the regress
tests until we're agreed.

An interesting breakage that remained was that the foreign_key tests
were assuming a "text = integer" comparison would fail, while a
"varchar = integer" comparison would succeed ... which is not only
pretty bogus in itself, but becomes even more so when you notice that
there isn't a varchar = integer operator.  Apparently, because we had
implicit coercions in *both* directions between text and integer,
the system couldn't figure out how to resolve text = integer; but
since there was an int->varchar and no varchar->int coercion, it
would resolve varchar = integer as varchar = integer::varchar.

With the attached settings, both cases are accepted as doing text =
int::text.  I'm not convinced that this is a step forward; I'd prefer
to see explicit coercion needed to cross type categories.  But that's
the matter for debate.

The lines marked XXX are the ones that I enabled since yesterday, and
would like to disable again:
implicit |   result    |    input    |                        prosrc
----------+-------------+-------------+--------------------------------------no       | abstime     | timestamp   |
timestamp_abstimeno      | abstime     | timestamptz | timestamptz_abstimeno       | box         | circle      |
circle_boxno      | box         | polygon     | poly_boxyes      | bpchar      | char        | char_bpcharyes      |
bpchar     | name        | name_bpcharyes      | char        | text        | text_charno       | cidr        | text
  | text_cidrno       | circle      | box         | box_circleno       | circle      | polygon     | poly_circleno
| date        | abstime     | abstime_dateno       | date        | text        | text_dateno       | date        |
timestamp  | timestamp_dateno       | date        | timestamptz | timestamptz_dateyes      | float4      | float8
|dtofyes      | float4      | int2        | i2tofyes      | float4      | int4        | i4tofno       | float4      |
numeric    | numeric_float4no       | float4      | text        | text_float4yes      | float8      | float4      |
ftodyes     | float8      | int2        | i2todyes      | float8      | int4        | i4todyes      | float8      |
int8       | i8todno       | float8      | numeric     | numeric_float8no       | float8      | text        |
text_float8no      | inet        | text        | text_inetno       | int2        | float4      | ftoi2no       | int2
    | float8      | dtoi2yes      | int2        | int4        | i4toi2yes      | int2        | int8        | int82no
  | int2        | numeric     | numeric_int2no       | int2        | text        | text_int2no       | int4        |
float4     | ftoi4no       | int4        | float8      | dtoi4yes      | int4        | int2        | i2toi4yes      |
int4       | int8        | int84no       | int4        | numeric     | numeric_int4no       | int4        | text
|text_int4no       | int8        | float8      | dtoi8yes      | int8        | int2        | int28yes      | int8
| int4        | int48no       | int8        | numeric     | numeric_int8no       | int8        | text        |
text_int8yes     | interval    | reltime     | reltime_intervalno       | interval    | text        | text_intervalyes
   | interval    | time        | time_intervalno       | lseg        | box         | box_diagonalno       | macaddr
|text        | text_macaddryes      | name        | bpchar      | bpchar_nameyes      | name        | text        |
text_nameyes     | name        | varchar     | text_nameyes      | numeric     | float4      | float4_numericyes      |
numeric    | float8      | float8_numericyes      | numeric     | int2        | int2_numericyes      | numeric     |
int4       | int4_numericyes      | numeric     | int8        | int8_numericno       | oid         | text        |
text_oidno      | path        | polygon     | poly_pathno       | point       | box         | box_centerno       |
point      | circle      | circle_centerno       | point       | lseg        | lseg_centerno       | point       | path
      | path_centerno       | point       | polygon     | poly_centerno       | polygon     | box         | box_polyno
    | polygon     | circle      | select polygon(12, $1)no       | polygon     | path        | path_polyno       |
reltime    | int4        | int4reltimeno       | reltime     | interval    | interval_reltimeyes      | text        |
char       | char_textXXX      | text        | date        | date_textXXX      | text        | float4      |
float4_textXXX     | text        | float8      | float8_textno       | text        | inet        | network_showXXX
|text        | int2        | int2_textXXX      | text        | int4        | int4_textXXX      | text        | int8
  | int8_textXXX      | text        | interval    | interval_textno       | text        | macaddr     | macaddr_textyes
    | text        | name        | name_textno       | text        | oid         | oid_textXXX      | text        | time
      | time_textXXX      | text        | timestamp   | timestamp_textXXX      | text        | timestamptz |
timestamptz_textXXX     | text        | timetz      | timetz_textno       | time        | abstime     | select
time(cast($1as timestamp without time zone))no       | time        | interval    | interval_timeno       | time
|text        | text_timeno       | time        | timestamp   | timestamp_timeyes      | time        | timetz      |
timetz_timeyes     | timestamp   | abstime     | abstime_timestampyes      | timestamp   | date        |
date_timestampno      | timestamp   | text        | text_timestampyes      | timestamp   | timestamptz |
timestamptz_timestampyes     | timestamptz | abstime     | abstime_timestamptzyes      | timestamptz | date        |
date_timestamptzno      | timestamptz | text        | text_timestamptzyes      | timestamptz | timestamp   |
timestamp_timestamptzno      | timetz      | text        | text_timetzyes      | timetz      | time        |
time_timetzno      | timetz      | timestamptz | timestamptz_timetzno       | varchar     | int4        | int4_textno
   | varchar     | int8        | int8_textyes      | varchar     | name        | name_text
 
(103 rows)


        regards, tom lane


Re: Implicit coercions need to be reined in

От
"Zeugswetter Andreas SB SD"
Дата:
> I suspect that the main thing that will cause issues is removal of
> implicit coercions to text.  For example, in 7.2 and before you can do
>
> test72=# select 'At the tone, the time will be ' || now();
>                           ?column?
> -------------------------------------------------------------
>  At the tone, the time will be 2002-04-11 11:49:27.309181-04
> (1 row)

I have seen this coding practice extremely often and would be very unhappy if
it were not allowed any more. Imho automatic coercions are a good thing
and should be done where possible. Other extensible databases also allow this
without a cast. Imho the main culprit is finding a "number" format that will not
loose precision when implicitly propagated to.

Andreas


Re: Implicit coercions need to be reined in

От
"Zeugswetter Andreas SB SD"
Дата:
> The lines marked XXX are the ones that I enabled since yesterday, and
> would like to disable again:
>
>  implicit |   result    |    input    |                        prosrc
> ----------+-------------+-------------+--------------------------------------

>  no       | varchar     | int8        | int8_text

Wow, I am completely at a loss why you would not allow implicit coercions
that do not loose any data in the process.
Coercing an int to float would in some cases loose precision. It is thus imho
debateable what to do here, but not for the rest.

I would think it a major step in the wrong direction.

Andreas


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
"Zeugswetter Andreas SB SD" <ZeugswetterA@spardat.at> writes:
> Wow, I am completely at a loss why you would not allow implicit coercions
> that do not loose any data in the process. 

Haven't you read the previous threads?  Implicit coercions are
dangerous, because they cause the system to resolve operators in
unexpected ways.  See, eg, bug #484:
http://archives.postgresql.org/pgsql-bugs/2001-10/msg00103.php
http://archives.postgresql.org/pgsql-bugs/2001-10/msg00108.php

I'm not by any means opposed to *all* implicit coercions, but
cross-type-category ones strike me as bad news.

In particular, if all datatypes have implicit coercions to text then
type checking is pretty much a thing of the past :-( ... the system will
be able to resolve nearly anything by interpreting it as a text
operation.  See above bug.

I suspect you are going to argue that you are prepared to live with such
misbehavior because it's too darn convenient not to have to write
::text.  Well, maybe that is indeed the community consensus, but I want
to see a discussion about it first.  And in any case I want a fairly
well-defined, circumscribed policy about which implicit coercions we
will have.
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Thomas Lockhart
Дата:
...
> Haven't you read the previous threads?  Implicit coercions are
> dangerous, because they cause the system to resolve operators in
> unexpected ways.

Sure he's read the threads. The conclusion is *not* obvious, and any
blanket statement to that effect trivializes the issues in a non-helpful
way imho.

I'd like to see a continuing discussion of this before leaping to a
conclusion; now that we have (somewhat) more control over coersions some
additional tuning is certainly warranted but hopefully it will not
require removing reasonable and convenient behaviors.
                     - Thomas


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Thomas Lockhart <thomas@fourpalms.org> writes:
> I'd like to see a continuing discussion of this before leaping to a
> conclusion; now that we have (somewhat) more control over coersions some
> additional tuning is certainly warranted but hopefully it will not
> require removing reasonable and convenient behaviors.

Absolutely --- that's why I started this latest round of discussion.

What I'm really looking for is a way that we can allow (some?) implicit
text coercions while getting rid of the sort of misbehavior exemplified
by that bug report I keep referring to.  Has anyone got any ideas about
how to do that?  It's one thing to say that "apples || oranges" should
be interpreted as "apples::text || oranges::text", but it is quite
another to say that "apples <= oranges" should be handled that way.

Also: now that we can create non-implicit coercion functions, I would
like to add functions for bool<->int, numeric<->text, and other
coercions that would be handy to have, but previously we resisted on
the grounds that they'd turn the type checking system into a joke.
But perhaps some of these *should* be allowed as implicit coercions.
I'd like to develop a well-thought-out policy for which coercions should
be implicit, rather than making ad-hoc decisions.

So far the only policy-like idea that I've had is to forbid cross-type-
category implicit coercions.  That would solve the comparing-apples-to-
oranges problem; but if people think it'd cause too much collateral
damage, how about proposing some other rule?
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Thomas Lockhart
Дата:
...
> What I'm really looking for is a way that we can allow (some?) implicit
> text coercions while getting rid of the sort of misbehavior exemplified
> by that bug report I keep referring to.  Has anyone got any ideas about
> how to do that?  It's one thing to say that "apples || oranges" should
> be interpreted as "apples::text || oranges::text", but it is quite
> another to say that "apples <= oranges" should be handled that way.

Hmm. istm that we might need some information to travel with the
operators, not just the coersion functions themselves. We have a fairly
type-rich system, but need to preserve the ability to add types and a
*partial* set of functions and operators and get reasonable behaviors.
                     - Thomas


Re: Implicit coercions need to be reined in

От
Tom Lane
Дата:
Thomas Lockhart <thomas@fourpalms.org> writes:
>> It's one thing to say that "apples || oranges" should
>> be interpreted as "apples::text || oranges::text", but it is quite
>> another to say that "apples <= oranges" should be handled that way.

> Hmm. istm that we might need some information to travel with the
> operators, not just the coersion functions themselves. We have a fairly
> type-rich system, but need to preserve the ability to add types and a
> *partial* set of functions and operators and get reasonable behaviors.

Could we do anything based on looking at the whole set of candidate
operators?  For example, I think that the reason "apples || oranges"
is so appealing is that there really is only one way to interpret
the || operator; whereas of course there are lots of different <=
operators.  Perhaps we could be more forgiving of implicit coercions
when there are fewer candidate operators, in some way?  Again, something
based on type categories would make sense to me.  Perhaps allow
cross-category implicit coercions only if there are no candidate
operators accepting the input's native category?
        regards, tom lane


Re: Implicit coercions need to be reined in

От
Thomas Lockhart
Дата:
...
> Could we do anything based on looking at the whole set of candidate
> operators?  For example, I think that the reason "apples || oranges"
> is so appealing is that there really is only one way to interpret
> the || operator; whereas of course there are lots of different <=
> operators.  Perhaps we could be more forgiving of implicit coercions
> when there are fewer candidate operators, in some way?  Again, something
> based on type categories would make sense to me.  Perhaps allow
> cross-category implicit coercions only if there are no candidate
> operators accepting the input's native category?

Hmm. That might be a winner. Since everything can be turned into text,
there will always be a fallback to text available. Allow it for
operators which are text-only operators (are there any built in besides
"||"?) and disallow that fallback for the others?

One edge case which we are probably concerned about is the "typeless
literal". I'd guess that we make the right choice in *most* cases
already.

I guess I'm worried that we may be cutting back on the allowed implicit
coersions, when we might really be missing only one or two explicit
coersion functions to fill in the set. I haven't looked at that in a
while...
                  - Thomas


Re: Implicit coercions need to be reined in

От
Bruce Momjian
Дата:
Tom Lane wrote:
> Thomas Lockhart <thomas@fourpalms.org> writes:
> >> It's one thing to say that "apples || oranges" should
> >> be interpreted as "apples::text || oranges::text", but it is quite
> >> another to say that "apples <= oranges" should be handled that way.
> 
> > Hmm. istm that we might need some information to travel with the
> > operators, not just the coersion functions themselves. We have a fairly
> > type-rich system, but need to preserve the ability to add types and a
> > *partial* set of functions and operators and get reasonable behaviors.
> 
> Could we do anything based on looking at the whole set of candidate
> operators?  For example, I think that the reason "apples || oranges"
> is so appealing is that there really is only one way to interpret
> the || operator; whereas of course there are lots of different <=
> operators.  Perhaps we could be more forgiving of implicit coercions
> when there are fewer candidate operators, in some way?  Again, something
> based on type categories would make sense to me.  Perhaps allow
> cross-category implicit coercions only if there are no candidate
> operators accepting the input's native category?

Yes, I think any solution will have to consider the number of possible
conversions for a given mix of function/args.

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026