summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2019-03-18 17:01:40 +0100
committerPeter Eisentraut <peter@eisentraut.org>2019-03-18 17:19:21 +0100
commit1ffa59a85cb40a61f4523fb03c8960db97eea124 (patch)
tree98a8ed4bcff8600e2a548e72ca502243ceea7c04 /src/test
parentfb5806533f9fe0433290d84c9b019399cd69e9c2 (diff)
Fix optimization of foreign-key on update actions
In RI_FKey_pk_upd_check_required(), we check among other things whether the old and new key are equal, so that we don't need to run cascade actions when nothing has actually changed. This was using the equality operator. But the effect of this is that if a value in the primary key is changed to one that "looks" different but compares as equal, the update is not propagated. (Examples are float -0 and 0 and case-insensitive text.) This appears to violate the SQL standard, and it also behaves inconsistently if in a multicolumn key another key is also updated that would cause the row to compare as not equal. To fix, if we are looking at the PK table in ri_KeysEqual(), then do a bytewise comparison similar to record_image_eq() instead of using the equality operators. This only makes a difference for ON UPDATE CASCADE, but for consistency we treat all changes to the PK the same. For the FK table, we continue to use the equality operators. Discussion: https://www.postgresql.org/message-id/flat/3326fc2e-bc02-d4c5-e3e5-e54da466e89a@2ndquadrant.com
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/foreign_key.out34
-rw-r--r--src/test/regress/sql/foreign_key.sql20
2 files changed, 54 insertions, 0 deletions
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index f1a664e3394..401514a3e00 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1496,6 +1496,40 @@ ERROR: cannot ALTER TABLE "pktable2" because it has pending trigger events
commit;
drop table pktable2, fktable2;
--
+-- Test keys that "look" different but compare as equal
+--
+create table pktable2 (a float8, b float8, primary key (a, b));
+create table fktable2 (x float8, y float8, foreign key (x, y) references pktable2 (a, b) on update cascade);
+insert into pktable2 values ('-0', '-0');
+insert into fktable2 values ('-0', '-0');
+select * from pktable2;
+ a | b
+----+----
+ -0 | -0
+(1 row)
+
+select * from fktable2;
+ x | y
+----+----
+ -0 | -0
+(1 row)
+
+update pktable2 set a = '0' where a = '-0';
+select * from pktable2;
+ a | b
+---+----
+ 0 | -0
+(1 row)
+
+-- should have updated fktable2.x
+select * from fktable2;
+ x | y
+---+----
+ 0 | -0
+(1 row)
+
+drop table pktable2, fktable2;
+--
-- Foreign keys and partitioned tables
--
-- partitioned table in the referenced side are not allowed
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index 4639fb45093..beeaf3277d3 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -1120,6 +1120,26 @@ commit;
drop table pktable2, fktable2;
+--
+-- Test keys that "look" different but compare as equal
+--
+create table pktable2 (a float8, b float8, primary key (a, b));
+create table fktable2 (x float8, y float8, foreign key (x, y) references pktable2 (a, b) on update cascade);
+
+insert into pktable2 values ('-0', '-0');
+insert into fktable2 values ('-0', '-0');
+
+select * from pktable2;
+select * from fktable2;
+
+update pktable2 set a = '0' where a = '-0';
+
+select * from pktable2;
+-- should have updated fktable2.x
+select * from fktable2;
+
+drop table pktable2, fktable2;
+
--
-- Foreign keys and partitioned tables