Re: SQL:2011 application time
Paul A Jungwirth <pj@illuminatedcomputing.com>
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Rename gist stratnum support function
- 32edf732e8dc 18.0 landed
-
Remove support for temporal RESTRICT foreign keys
- b83e8a2ca2eb 18.0 landed
-
Cache NO ACTION foreign keys separately from RESTRICT foreign keys
- 9926f854d077 18.0 landed
-
Fix NO ACTION temporal foreign keys when the referenced endpoints change
- 1772d554b089 18.0 landed
-
Improve whitespace in without_overlaps test
- 888d4523f0c2 18.0 landed
-
Tests for logical replication with temporal keys
- 939b0908c87a 18.0 landed
-
Support for GiST in get_equal_strategy_number()
- 74edabce7a33 18.0 landed
-
Make the conditions in IsIndexUsableForReplicaIdentityFull() more explicit
- 13544e790ef8 18.0 landed
-
Replace get_equal_strategy_number_for_am() by get_equal_strategy_number()
- a2a475b011cf 18.0 landed
-
Improve internal logical replication error for missing equality strategy
- 321c287351f7 18.0 landed
-
Simplify IsIndexUsableForReplicaIdentityFull()
- 7727049e8f66 18.0 landed
-
Fix ALTER TABLE / REPLICA IDENTITY for temporal tables
- 79b575d3bc09 18.0 landed
-
doc: Update pg_constraint.conexclop docs for WITHOUT OVERLAPS
- f683ba0867da 18.0 landed
-
doc: Add PERIOD to ALTER TABLE reference docs
- d56af4c882e2 18.0 landed
-
doc: Add WITHOUT OVERLAPS to ALTER TABLE reference docs
- bf621059500b 18.0 landed
-
Add temporal FOREIGN KEY contraints
- 89f908a6d0ac 18.0 landed
- 34768ee36165 17.0 landed
-
Add temporal PRIMARY KEY and UNIQUE constraints
- fc0438b4e805 18.0 landed
- 46a0cd4cefb4 17.0 landed
-
Add stratnum GiST support function
- 7406ab623fee 18.0 landed
- 6db4598fcb82 17.0 landed
-
Avoid crashing when a JIT-inlined backend function throws an error.
- 5d6c64d29097 17.0 cited
-
Revert temporal primary keys and foreign keys
- 8aee330af55d 17.0 landed
-
Fix ON CONFLICT DO NOTHING/UPDATE for temporal indexes
- 144c2ce0cc75 17.0 landed
-
Add test for REPLICA IDENTITY with a temporal key
- 482e108cd38d 17.0 landed
-
Use half-open interval notation in without_overlaps tests
- 5577a71fb0cc 17.0 landed
-
Use daterange and YMD in without_overlaps tests instead of tsrange.
- a88c800deb6f 17.0 landed
-
Rename pg_constraint.conwithoutoverlaps to conperiod
- 030e10ff1a36 17.0 landed
-
Fix comment on gist_stratnum_btree
- 86232a49a437 17.0 landed
-
Add missing TAP test name
- 1ab763fc22ad 16.0 cited
-
Improve error handling of HMAC computations
- 5513dc6a304d 15.0 cited
-
Rename functions to avoid future conflicts
- ee419607381d 15.0 landed
On 2/13/25 05:23, Peter Eisentraut wrote:
> On 23.01.25 16:40, Peter Eisentraut wrote:
>> I think my interpretation of what RESTRICT should do is different.
>>
>> The clause "Execution of referential actions" in the SQL standard only talks about referenced and
>> referencing columns, not periods. So this would mean you can change the period columns all you
>> want (as long as they maintain referential integrity). So it would be like the NO ACTION case.
>> But you can't change any of the non-period columns on the primary key if they are referenced by
>> any referencing columns, even if the respective periods are disjoint.
>>
>> Maybe this makes sense, or maybe this is a mistake (neglected to update this part when periods
>> were introduced?). But in any case, I can't get from this to what the patch does. When I apply
>> the tests in the patch without the code changes, what I would intuitively like are more errors
>> than the starting state, but your patch results in fewer errors.
>
> After staring at this a bit more, I think my interpretation above was not correct. This seems better:
>
> The clause "Execution of referential actions" in the SQL standard only
> talks about referenced and referencing columns, not periods. The RESTRICT error is raised when a
> "matching row" exists in the referencing table. The "matching row" is determined purely by looking
> at the "normal" columns of the key, not the period columns.
>
> So in our implementation in ri_restrict(), ISTM, we just need to ignore the period/range columns
> when doing the RESTRICT check.
>
> Attached is a quick patch that demonstrates how this could work. I think the semantics of this are
> right and make sense.
I can see how this is plausible given a very strict reading of the standard, but I don't think it
makes sense practically. And perhaps an ever stricter reading will take us back to a more practical
understanding.
Starting with the practical argument: let's say the referenced table has two rows, with (id,
valid_at) of (1, '[2000-01-01,2001-01-01)') and (1, '[2010-01-01,2011-01-01)'), and the referencing
table has a row with (id, valid_at) of (1, '[2010-03-01,2010-04-01)'), and we have `referencing (id,
PERIOD valid_at) REFERENCES referenced (id, PERIOD valid_at)`. then deleting *either* referenced row
would cause a RESTRICT key to fail? If that is what the user wants, why not just make a non-temporal
foreign key? If I create a temporal foreign key, it would be very surprising for it simply to ignore
its temporal parts.
No major RDBMS vendor has implemented temporal foreign keys yet, so we don't have much to compare
to. But Vik's periods extension doesn't behave this way for RESTRICT keys.[1] I don't think Hettie's
does either,[2] although I'm less familiar with her project. I think she might not distinguish
between NO ACTION and RESTRICT. I will see if I can find any other examples of how this is
implemented, but even XTDB doesn't seem to have temporal FKs. I also checked the Teradata docs,[4]
but they seem to support temporal FKs only as documentation, and don't enforce them. (Also
Teradata's support precedes SQL:2011, so it's not a great guide anyway.) The IBM DB2[5] docs don't
describe any difference between RESTRICT and NO ACTION in considering the PERIOD. (In my tests their
temporal FKs have never actually worked, but I'll try again and see what results I get.)
None of the books about temporal tables written after SQL:2011 say RESTRICT constraints should
ignore valid-time, but surely they would call out such a counterintuitive behavior. They criticize
the standard pretty freely in other ways. There are lots of shorter writeups about SQL:2011 foreign
keys,[3] and I've never seen any say that a RESTRICT key should work this way.
I think this interpretation has some tunnel vision. When we have a section that has nothing to say
about temporal foreign keys, we shouldn't use it to discard what other sections *do* say about them.
Also I think an even stricter reading is possible. The standard says, "any change to a referenced
column in the referenced table is prohibited if there is a matching row." The "referenced column" is
about the *change*, but the "matching row" doesn't talk about columns or non-columns. Nothing says
we should ignore the PERIOD part when finding matches. In addition, even for the "change" part, I
think "referenced columns" should include the start/end columns of the PERIOD. Those are part of the
reference. If they change, we need to look for matches.
But here are a few more subtle questions. In all cases suppose you have the same rows as above, with
an ON UPDATE RESTRICT ON DELETE RESTRICT constraint.
Suppose you UPDATE the referenced 2010 row to be (1, '[2010-01-02,2011-01-01)'). Should it fail? I
say no: you didn't remove any part of the referenced valid time.
Suppose you UPDATE the referenced 2010 row to be (1, '[2010-06-01,2011-01-01)'). Should it fail? I
say yes: you did remove part of the referenced valid time.
Support you DELETE the referenced 2010 row with `FOR PORTION OF valid_at FROM 2010-01-01 TO
2010-01-05`. I say it shouldn't fail, because again you didn't erase any of the referenced valid
time. Otherwise you're saying that one referenced tuple spanning all of 2010 behaves differently
from two tuples, one for '[2010-01-01,2010-01-05)' and another for '[2010-01-05,2011-01-01)'. That
doesn't make sense, because they represent the same history.
Support you DELETE the referenced 2010 row with `FOR PORTION OF valid_at FROM 2010-01-01 TO
2010-06-01`. I say it should fail, because again you did erase part of the referenced valid time.
Instead of those two DELETE commands, suppose you UPDATE the id to 2, with the same FOR PORTION OF.
The first should pass and the second should fail. I but I could see an argument why they should both
fail (like the next question).
Now suppose you UPDATE some other column, but not the id, with `FOR PORTION OF valid_at FROM
2010-01-01 TO 2010-02-01`. Should it fail? The old referenced row is now valid only from Jan 1 to
Feb 1, orphaning part of the reference. But you also inserted a replacement with valid_at of
'[2010-02-01,2011-01-01)'. So the reference is still okay. With NO ACTION this is clearly allowed.
With RESTRICT I'm inclined to say it's *still* allowed, but you could make a case that it's not.
One reason I think these cases are still allowed, even with RESTRICT, is that inserting "leftovers"
should be transparent. It shouldn't matter whether you have one row with a big span, or many rows
with little spans. It is surprising to get a failure in one case but not the other, when they
represent the same history. With such unpredictability, I can't see a developer ever using a
RESTRICT temporal constraint.
To me this is all pretty straightforward, but perhaps it would be safest to just disable RESTRICT
for now. I can send a patch for that shortly.
Yours,
[1] https://github.com/xocolatl/periods/blob/master/periods--1.2.sql#L1715-L1744 and
https://github.com/xocolatl/periods/blob/master/periods--1.2.sql#L2100
[2] https://github.com/hettie-d/pg_bitemporal/tree/master/sql
[3] For example https://sigmodrecord.org/publications/sigmodRecord/1209/pdfs/07.industry.kulkarni.pdf
[4]
https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/ANSI-Temporal-Table-Support/Working-With-ANSI-Valid-Time-Tables/Creating-ANSI-Valid-Time-Tables/Usage-Notes-for-Creating-ANSI-Valid-Time-Tables/Temporal-Referential-Constraints-for-ANSI-Valid-Time-Tables
[5] https://www.ibm.com/docs/en/db2-for-zos/12?topic=constraints-referential
--
Paul ~{:-)
pj@illuminatedcomputing.com