Re: Fix optimization of foreign-key on update actions

2019-03-18 Thread Peter Eisentraut
On 2019-03-11 12:57, Peter Eisentraut wrote:
> On 2019-02-06 23:15, Peter Eisentraut wrote:
>> On 05/02/2019 17:20, Tom Lane wrote:
>>> What I *don't* like about the proposed patch is that it installs a
>>> new, different comparison rule for the ON UPDATE CASCADE case only.
>>> If we were to go in this direction, I'd think we should try to use
>>> the same comparison rule for all FK row comparisons.
>>
>> That's easy to change.  I had it like that in earlier versions of the
>> patch.  I agree it would be better for consistency, but it would create
>> some cases where we do unnecessary extra work.
> 
> Updated patch with this change made, and some conflicts resolved.

Committed like this.

-- 
Peter Eisentraut  http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: Fix optimization of foreign-key on update actions

2019-03-11 Thread Peter Eisentraut
On 2019-02-06 23:15, Peter Eisentraut wrote:
> On 05/02/2019 17:20, Tom Lane wrote:
>> What I *don't* like about the proposed patch is that it installs a
>> new, different comparison rule for the ON UPDATE CASCADE case only.
>> If we were to go in this direction, I'd think we should try to use
>> the same comparison rule for all FK row comparisons.
> 
> That's easy to change.  I had it like that in earlier versions of the
> patch.  I agree it would be better for consistency, but it would create
> some cases where we do unnecessary extra work.

Updated patch with this change made, and some conflicts resolved.

-- 
Peter Eisentraut  http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From d8615fe224eed4747682e88202faad1251c317f6 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut 
Date: Tue, 5 Feb 2019 16:27:00 +0100
Subject: [PATCH v2 1/2] Test case for keys that "look" different but compare
 as equal

---
 src/test/regress/expected/foreign_key.out | 34 +++
 src/test/regress/sql/foreign_key.sql  | 20 +
 2 files changed, 54 insertions(+)

diff --git a/src/test/regress/expected/foreign_key.out 
b/src/test/regress/expected/foreign_key.out
index bf2c91d9f0..a68d055e40 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1474,6 +1474,40 @@ delete from pktable2 where f1 = 1;
 alter table fktable2 drop constraint fktable2_f1_fkey;
 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)
+
+-- buggy: did not update fktable2.x
+select * from fktable2;
+ x  | y  
++
+ -0 | -0
+(1 row)
+
 drop table pktable2, fktable2;
 --
 -- Foreign keys and partitioned tables
diff --git a/src/test/regress/sql/foreign_key.sql 
b/src/test/regress/sql/foreign_key.sql
index c8d1214d02..c1fc7d30b1 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -1106,6 +1106,26 @@ CREATE TEMP TABLE tasks (
 
 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;
+-- buggy: did not update fktable2.x
+select * from fktable2;
+
+drop table pktable2, fktable2;
+
 
 --
 -- Foreign keys and partitioned tables

base-commit: f2d84a4a6b4ec891a0a52f583ed5aa081c71acc6
-- 
2.21.0

From f9f05aceaed972147719345c65cce9222c50ef5e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut 
Date: Mon, 11 Mar 2019 12:55:22 +0100
Subject: [PATCH v2 2/2] 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-e54da466e...@2ndquadrant.com
---
 src/backend/utils/adt/datum.c | 57 +++
 src/backend/utils/adt/ri_triggers.c   | 40 ++--
 src/backend/utils/adt/rowtypes.c  | 41 +---
 src/include/utils/datum.h |  9 
 src/test/regress/expected/foreign_key.out |  8 ++--
 src/test/regress/sql/foreign_key.sql  |  2 +-
 6 files changed, 100 insertions(+), 57 

Re: Fix optimization of foreign-key on update actions

2019-02-06 Thread Peter Eisentraut
On 05/02/2019 17:20, Tom Lane wrote:
> What I *don't* like about the proposed patch is that it installs a
> new, different comparison rule for the ON UPDATE CASCADE case only.
> If we were to go in this direction, I'd think we should try to use
> the same comparison rule for all FK row comparisons.

That's easy to change.  I had it like that in earlier versions of the
patch.  I agree it would be better for consistency, but it would create
some cases where we do unnecessary extra work.

> The inconsistencies get messier the more you think about it,
> really.  If a referencing row was datatype-equal, but not byte-equal,
> to the PK row to start with, why would an update changing the PK row
> (perhaps to another datatype-equal value) result in forcing the
> referencing row to become byte-equal?  How does this fit in with
> the fact that our notion of what uniqueness means in the PK table
> is no-datatype-equality, rather than no-byte-equality?

This patch doesn't actually change the actual foreign key behavior.
Foreign keys already work like that.  The patch only touches an
optimization that checks whether it's worth running the full foreign key
behavior because the change was significant enough.  That shouldn't
affect the outcome.  It should be the case that if you replace
RI_FKey_pk_upd_check_required() by just "return true", then nothing
user-visible changes.

-- 
Peter Eisentraut  http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: Fix optimization of foreign-key on update actions

2019-02-06 Thread Peter Eisentraut
On 06/02/2019 12:23, Andrew Gierth wrote:
> Two values which are sql-equal but not identical, such as two strings in
> a case-insensitive collation that differ only by case, are
> distinguishable in some contexts but not others, so what context
> actually applies to the quoted rule?
> 
> I think the only reasonable interpretation is that it should use the
> same kind of distinctness that is being used by the unique constraint
> and the equality comparison that define whether the FK is satisfied.

By that logic, a command such as

UPDATE t1 SET x = '0' WHERE x = '-0';

could be optimized away as a noop, because in that world there is no
construct by which you can prove whether the update happened.

I think that would not be satisfactory.

-- 
Peter Eisentraut  http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services



Re: Fix optimization of foreign-key on update actions

2019-02-06 Thread Andrew Gierth
> "Laurenz" == Laurenz Albe  writes:

 Laurenz> Andrew Gierth wrote:
 >> SQL2016, 15.17 Execution of referential actions
 >> 
 >> 10) If a non-null value of a referenced column RC in the referenced
 >> table is updated to a value that is distinct from the current value
 >> of RC, then,
 >> 
 >> [snip all the stuff about how ON UPDATE actions work]
 >> 
 >> does that "is distinct from" mean that IS DISTINCT FROM would be true,
 >> or does it mean "is in some way distinguishable from"? Nothing I can see
 >> in the spec suggests the latter.

 Laurenz> My 2003 standard defines, and even condescends to be informal:

 Laurenz> 3.1.6.8 distinct (of a pair of comparable values): Capable of
 Laurenz> being distinguished within a given context. Informally, not
 Laurenz> equal, not both null. A null value and a non-null value are
 Laurenz> distinct.

Hrm. SQL2016 has similar language which I previously missed, but I don't
think it actually helps:

3.1.6.9  distinct (of a pair of comparable values)
 capable of being distinguished within a given context

   NOTE 8 -- Informally, two values are distinct if neither
   is null and the values are not equal. A null value and a
   non- null value are distinct. Two null values are not
   distinct. See Subclause 4.1.5, "Properties of distinct",
   and the General Rules of Subclause 8.15, "".

Two values which are sql-equal but not identical, such as two strings in
a case-insensitive collation that differ only by case, are
distinguishable in some contexts but not others, so what context
actually applies to the quoted rule?

I think the only reasonable interpretation is that it should use the
same kind of distinctness that is being used by the unique constraint
and the equality comparison that define whether the FK is satisfied.

-- 
Andrew.



Re: Fix optimization of foreign-key on update actions

2019-02-06 Thread Laurenz Albe
Andrew Gierth wrote:
> SQL2016, 15.17 Execution of referential actions
> 
> 10) If a non-null value of a referenced column RC in the referenced
> table is updated to a value that is distinct from the current value
> of RC, then,
> 
>   [snip all the stuff about how ON UPDATE actions work]
> 
> does that "is distinct from" mean that IS DISTINCT FROM would be true,
> or does it mean "is in some way distinguishable from"? Nothing I can see
> in the spec suggests the latter.

My 2003 standard defines, and even condescends to be informal:

3.1.6.8 distinct (of a pair of comparable values): Capable of being 
distinguished within a given context.
Informally, not equal, not both null. A null value and a non-null value are 
distinct.

Yours,
Laurenz Albe




Re: Fix optimization of foreign-key on update actions

2019-02-05 Thread Tom Lane
Andrew Gierth  writes:
> "Peter" == Peter Eisentraut  writes:
>  Peter> The SQL standard seems clear

> (since when has the SQL standard ever been clear?)

Point to Andrew ;-).  However, I kind of like Peter's idea anyway
on the grounds that byte-wise comparison is probably faster than
invoking the datatype comparators.  Also, language lawyering aside,
I think he may be right about what people would expect "should" happen.

What I *don't* like about the proposed patch is that it installs a
new, different comparison rule for the ON UPDATE CASCADE case only.
If we were to go in this direction, I'd think we should try to use
the same comparison rule for all FK row comparisons.

The inconsistencies get messier the more you think about it,
really.  If a referencing row was datatype-equal, but not byte-equal,
to the PK row to start with, why would an update changing the PK row
(perhaps to another datatype-equal value) result in forcing the
referencing row to become byte-equal?  How does this fit in with
the fact that our notion of what uniqueness means in the PK table
is no-datatype-equality, rather than no-byte-equality?

On the whole we might be better off leaving this alone.

regards, tom lane



Re: Fix optimization of foreign-key on update actions

2019-02-05 Thread Andrew Gierth
> "Peter" == Peter Eisentraut  writes:

 Peter> The SQL standard seems clear

ha

hahaha

HAHAHAHAHAHA

(since when has the SQL standard ever been clear?)

SQL2016, 15.17 Execution of referential actions

10) If a non-null value of a referenced column RC in the referenced
table is updated to a value that is distinct from the current value
of RC, then,

  [snip all the stuff about how ON UPDATE actions work]

does that "is distinct from" mean that IS DISTINCT FROM would be true,
or does it mean "is in some way distinguishable from"? Nothing I can see
in the spec suggests the latter.

-- 
Andrew (irc:RhodiumToad)