PostgreSQL: Edit and delete rows of a partitioned table - #1326
Merged
Conversation
limit1() identifies the row by its ctid, which is unique only within a single relation. A partitioned table is not one relation, so the condition is evaluated in every partition and matches whatever row sits at the same (block, offset) in each of them. Editing or deleting one row of a table with 64 partitions can affect 64 rows. The ctid is used only when the row has no unique key, which is also the case where the damage goes unnoticed - the affected rows are unrelated to the edited one. Matching (tableoid, ctid) restricts the condition to the partition holding the row. tableoid is a system column of every table, so the statement keeps its behaviour on ordinary tables, and tables using INHERITS are fixed as well.
Owner
|
I am really sorry about this. Thanks for the excellent report and the fix. |
Contributor
Author
|
Thank you for merging it, and for Adminer itself. It has helped me over the years, nice for something to go the other way. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Editing or deleting a single row of a partitioned table affects one row in every partition.
limit1()identifies the row by itsctid, which is unique only within a single relation. A partitioned table is not one relation, so the condition is evaluated in each partition and matches whatever row sits at the same(block, offset)there. Thectidis used only when the row has no unique key, which is also the case where the damage goes unnoticed, because the other affected rows are unrelated to the edited one.I hit this on a table with 64 partitions loaded without primary keys (they are created after the import for speed): deleting one row in Adminer reported 64 deleted rows, and the 63 unrelated posts were gone. It took a while to suspect the tool rather than the import.
Reproduction
Both rows are the first one in their partition, so both have the ctid
(0,1). Openpartsin Adminer, edit the row1, oneand save: the other row becomesunoas well. Deleting one row reports two affected rows.Without the UI:
The change
(tableoid, ctid)restricts the condition to the partition holding the row.tableoidis a system column of every table, so on an ordinary table the condition still matches the same single row.INHERITSmechanism have the same ambiguity and are fixed too.is_view()branch.The test creates the table above, edits one row, checks that the row in the other partition kept its value, deletes one row and expects one affected row. It fails on the current code with
2 items have been affected.Verified manually on PostgreSQL 18.6 for both UPDATE and DELETE, on partitioned and ordinary tables.