mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
Fix relcache inconsistency hazard in partition detach
During queries coming from ri_triggers.c, we need to omit partitions that are marked pending detach -- otherwise, the RI query is tricked into allowing a row into the referencing table whose corresponding row is in the detached partition. Which is bogus: once the detach operation completes, the row becomes an orphan. However, the code was not doing that in repeatable-read transactions, because relcache kept a copy of the partition descriptor that included the partition, and used it in the RI query. This commit changes the partdesc cache code to only keep descriptors that aren't dependent on a snapshot (namely: those where no detached partition exist, and those where detached partitions are included). When a partdesc-without- detached-partitions is requested, we create one afresh each time; also, those partdescs are stored in PortalContext instead of CacheMemoryContext. find_inheritance_children gets a new output *detached_exist boolean, which indicates whether any partition marked pending-detach is found. Its "include_detached" input flag is changed to "omit_detached", because that name captures desired the semantics more naturally. CreatePartitionDirectory() and RelationGetPartitionDesc() arguments are identically renamed. This was noticed because a buildfarm member that runs with relcache clobbering, which would not keep the improperly cached partdesc, broke one test, which led us to realize that the expected output of that test was bogus. This commit also corrects that expected output. Author: Amit Langote <amitlangote09@gmail.com> Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Discussion: https://postgr.es/m/3269784.1617215412@sss.pgh.pa.us
This commit is contained in:
@ -17,11 +17,19 @@
|
||||
|
||||
/*
|
||||
* Information about partitions of a partitioned table.
|
||||
*
|
||||
* For partitioned tables where detached partitions exist, we only cache
|
||||
* descriptors that include all partitions, including detached; when we're
|
||||
* requested a descriptor without the detached partitions, we create one
|
||||
* afresh each time. (The reason for this is that the set of detached
|
||||
* partitions that are visible to each caller depends on the snapshot it has,
|
||||
* so it's pretty much impossible to evict a descriptor from cache at the
|
||||
* right time.)
|
||||
*/
|
||||
typedef struct PartitionDescData
|
||||
{
|
||||
int nparts; /* Number of partitions */
|
||||
bool includes_detached; /* Does it include detached partitions */
|
||||
bool detached_exist; /* Are there any detached partitions? */
|
||||
Oid *oids; /* Array of 'nparts' elements containing
|
||||
* partition OIDs in order of the their bounds */
|
||||
bool *is_leaf; /* Array of 'nparts' elements storing whether
|
||||
@ -31,9 +39,9 @@ typedef struct PartitionDescData
|
||||
} PartitionDescData;
|
||||
|
||||
|
||||
extern PartitionDesc RelationGetPartitionDesc(Relation rel, bool include_detached);
|
||||
extern PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached);
|
||||
|
||||
extern PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt, bool include_detached);
|
||||
extern PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt, bool omit_detached);
|
||||
extern PartitionDesc PartitionDirectoryLookup(PartitionDirectory, Relation);
|
||||
extern void DestroyPartitionDirectory(PartitionDirectory pdir);
|
||||
|
||||
|
Reference in New Issue
Block a user