1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-26 23:43:30 +03:00

Extend pg_cast castimplicit column to a three-way value; this allows us

to be flexible about assignment casts without introducing ambiguity in
operator/function resolution.  Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
This commit is contained in:
Tom Lane
2002-09-18 21:35:25 +00:00
parent cc70ba2e4d
commit b26dfb9522
70 changed files with 1642 additions and 1528 deletions

View File

@@ -13,10 +13,14 @@ create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test coercions
SELECT cast('123456' as domainvarchar); -- fail
ERROR: value too long for type character varying(5)
SELECT cast('12345' as domainvarchar); -- pass
-- Test explicit coercions --- these should succeed (and truncate)
SELECT cast('123456' as domainvarchar);
domainvarchar
---------------
12345
(1 row)
SELECT cast('12345' as domainvarchar);
domainvarchar
---------------
12345

View File

@@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
Sat Jan 01 10:00:00 1994
(1 row)
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
ERROR: Bad time external representation '11:00-5'
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
Jan_01_1994_11am
--------------------------
Sat Jan 01 11:00:00 1994
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
Jan_01_1994_8am
------------------------------
Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
Jan_01_1994_8am
------------------------------
Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
@@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
(1 row)
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
ERROR: Cannot cast type 'time with time zone' to 'interval'
ERROR: Cannot cast type time with time zone to interval
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
ERROR: Cannot cast type 'interval' to 'time with time zone'
ERROR: Cannot cast type interval to time with time zone
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
23:29:00-08
-------------

View File

@@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
Sat Jan 01 10:00:00 1994
(1 row)
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
ERROR: Bad time external representation '11:00-5'
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
Jan_01_1994_11am
--------------------------
Sat Jan 01 11:00:00 1994
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
Jan_01_1994_8am
------------------------------
Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
Jan_01_1994_8am
------------------------------
Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
@@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
(1 row)
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
ERROR: Cannot cast type 'time with time zone' to 'interval'
ERROR: Cannot cast type time with time zone to interval
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
ERROR: Cannot cast type 'interval' to 'time with time zone'
ERROR: Cannot cast type interval to time with time zone
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
23:29:00-08
-------------

View File

@@ -354,12 +354,16 @@ SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
Sat Jan 01 10:00:00 1994
(1 row)
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
ERROR: Bad time external representation '11:00-5'
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
Jan_01_1994_11am
--------------------------
Sat Jan 01 11:00:00 1994
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
Jan_01_1994_8am
------------------------------
Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
Jan_01_1994_8am
------------------------------
Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
@@ -762,9 +766,9 @@ SELECT interval '04:30' - time '01:02' AS "20:32:00";
(1 row)
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
ERROR: Cannot cast type 'time with time zone' to 'interval'
ERROR: Cannot cast type time with time zone to interval
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
ERROR: Cannot cast type 'interval' to 'time with time zone'
ERROR: Cannot cast type interval to time with time zone
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
23:29:00-08
-------------

View File

@@ -202,33 +202,35 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
-- useless.
-- useless. Also catch bogus values in pg_cast columns (other than
-- cases detected by oidjoins test).
SELECT *
FROM pg_cast c
WHERE c.castsource = c.casttarget;
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
OR castcontext NOT IN ('e', 'a', 'i');
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
-- Look for cast functions with incorrect number or type of argument
-- or return value.
-- Look for cast functions that don't have the right signature. The
-- argument and result types in pg_proc must be the same as, or binary
-- compatible with, what it says in pg_cast.
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
(p.pronargs <> 1 OR
p.proargtypes[0] <> c.castsource OR
p.prorettype <> c.casttarget);
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
(0 rows)
-- Look for binary compatible casts that are not implicit. This is
-- legal, but probably not intended.
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND NOT c.castimplicit;
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
(p.pronargs <> 1
OR NOT (c.castsource = p.proargtypes[0] OR
EXISTS (SELECT 1 FROM pg_cast k
WHERE k.castfunc = 0 AND
k.castsource = c.castsource AND
k.casttarget = p.proargtypes[0]))
OR NOT (p.prorettype = c.casttarget OR
EXISTS (SELECT 1 FROM pg_cast k
WHERE k.castfunc = 0 AND
k.castsource = p.prorettype AND
k.casttarget = c.casttarget)));
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
-- Look for binary compatible casts that do not have the reverse
@@ -241,8 +243,8 @@ WHERE c.castfunc = 0 AND
WHERE k.castfunc = 0 AND
k.castsource = c.casttarget AND
k.casttarget = c.castsource);
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
-- **************** pg_operator ****************
@@ -414,20 +416,18 @@ WHERE p1.oprlsortop != p1.oprrsortop AND
-- Hashing only works on simple equality operators "type = sametype",
-- since the hash itself depends on the bitwise representation of the type.
-- Check that allegedly hashable operators look like they might be "=".
-- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
-- NOTE: in 7.3, this search finds xideqint4.
-- Until we have some cleaner way of dealing with binary-equivalent types,
-- just leave those three tuples in the expected output.
-- just leave that tuple in the expected output.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
oid | oprname
------+---------
353 | =
1136 | =
1137 | =
(3 rows)
oid | oprname
-----+---------
353 | =
(1 row)
-- In 6.5 we accepted hashable array equality operators when the array element
-- type is hashable. However, what we actually need to make hashjoin work on

View File

@@ -75,7 +75,7 @@ EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true);
ERROR: Wrong number of parameters, expected 6 but got 7
-- wrong param types
EXECUTE q3(5::smallint, 10.5::float, false, 500::oid, 4::bigint, 'bytea');
ERROR: Parameter $2 of type double precision cannot be coerced into the expected type integer
ERROR: Parameter $3 of type boolean cannot be coerced into the expected type double precision
You will need to rewrite or cast the expression
-- invalid type
PREPARE q4(nonexistenttype) AS SELECT $1;

View File

@@ -1321,10 +1321,10 @@ SELECT tablename, rulename, definition FROM pg_rules
rtest_nothn1 | rtest_nothn_r2 | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
rtest_nothn2 | rtest_nothn_r3 | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);
rtest_nothn2 | rtest_nothn_r4 | CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2 DO INSTEAD NOTHING;
rtest_order1 | rtest_order_r1 | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 1 - this should run 3rd or 4th'::text);
rtest_order1 | rtest_order_r2 | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 2 - this should run 1st'::text);
rtest_order1 | rtest_order_r3 | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 3 - this should run 3rd or 4th'::text);
rtest_order1 | rtest_order_r4 | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 4 - this should run 2nd'::text);
rtest_order1 | rtest_order_r1 | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 1 - this should run 3rd or 4th'::text);
rtest_order1 | rtest_order_r2 | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 2 - this should run 1st'::text);
rtest_order1 | rtest_order_r3 | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 3 - this should run 3rd or 4th'::text);
rtest_order1 | rtest_order_r4 | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 4 - this should run 2nd'::text);
rtest_person | rtest_pers_del | CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person DO DELETE FROM rtest_admin WHERE (rtest_admin.pname = old.pname);
rtest_person | rtest_pers_upd | CREATE RULE rtest_pers_upd AS ON UPDATE TO rtest_person DO UPDATE rtest_admin SET pname = new.pname WHERE (rtest_admin.pname = old.pname);
rtest_system | rtest_sys_del | CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system DO (DELETE FROM rtest_interface WHERE (rtest_interface.sysname = old.sysname); DELETE FROM rtest_admin WHERE (rtest_admin.sysname = old.sysname); );

View File

@@ -47,8 +47,15 @@ SELECT CAST(name 'namefield' AS text) AS "text(name)";
namefield
(1 row)
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
ERROR: value too long for type character(10)
-- since this is an explicit cast, it should truncate w/o error:
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
char(text)
------------
doh!
hi de ho n
(2 rows)
-- note: implicit-cast case is tested in char.sql
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
char(text)
----------------------

View File

@@ -90,7 +90,7 @@ SELECT 1.1 AS two UNION ALL SELECT 2;
SELECT 1.0 AS two UNION ALL SELECT 1;
two
-----
1
1.0
1
(2 rows)

View File

@@ -20,9 +20,9 @@ create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test coercions
SELECT cast('123456' as domainvarchar); -- fail
SELECT cast('12345' as domainvarchar); -- pass
-- Test explicit coercions --- these should succeed (and truncate)
SELECT cast('123456' as domainvarchar);
SELECT cast('12345' as domainvarchar);
-- Test tables using domains
create table basictest

View File

@@ -90,8 +90,8 @@ SELECT (timestamp without time zone 'tomorrow' > 'now') as "True";
-- to enable support for SQL99 timestamp type syntax.
SELECT date '1994-01-01' + time '11:00' AS "Jan_01_1994_11am";
SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;

View File

@@ -162,28 +162,32 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
-- useless.
-- useless. Also catch bogus values in pg_cast columns (other than
-- cases detected by oidjoins test).
SELECT *
FROM pg_cast c
WHERE c.castsource = c.casttarget;
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
OR castcontext NOT IN ('e', 'a', 'i');
-- Look for cast functions with incorrect number or type of argument
-- or return value.
-- Look for cast functions that don't have the right signature. The
-- argument and result types in pg_proc must be the same as, or binary
-- compatible with, what it says in pg_cast.
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
(p.pronargs <> 1 OR
p.proargtypes[0] <> c.castsource OR
p.prorettype <> c.casttarget);
-- Look for binary compatible casts that are not implicit. This is
-- legal, but probably not intended.
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND NOT c.castimplicit;
(p.pronargs <> 1
OR NOT (c.castsource = p.proargtypes[0] OR
EXISTS (SELECT 1 FROM pg_cast k
WHERE k.castfunc = 0 AND
k.castsource = c.castsource AND
k.casttarget = p.proargtypes[0]))
OR NOT (p.prorettype = c.casttarget OR
EXISTS (SELECT 1 FROM pg_cast k
WHERE k.castfunc = 0 AND
k.castsource = p.prorettype AND
k.casttarget = c.casttarget)));
-- Look for binary compatible casts that do not have the reverse
-- direction registered as well, or where the reverse direction is not
@@ -341,9 +345,9 @@ WHERE p1.oprlsortop != p1.oprrsortop AND
-- Hashing only works on simple equality operators "type = sametype",
-- since the hash itself depends on the bitwise representation of the type.
-- Check that allegedly hashable operators look like they might be "=".
-- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
-- NOTE: in 7.3, this search finds xideqint4.
-- Until we have some cleaner way of dealing with binary-equivalent types,
-- just leave those three tuples in the expected output.
-- just leave that tuple in the expected output.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1

View File

@@ -27,7 +27,9 @@ SELECT CAST(f1 AS text) AS "text(varchar)" FROM VARCHAR_TBL;
SELECT CAST(name 'namefield' AS text) AS "text(name)";
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
-- since this is an explicit cast, it should truncate w/o error:
SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
-- note: implicit-cast case is tested in char.sql
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;