mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
tableam: Add helper for indexes to check if a corresponding table tuples exist.
This is, likely exclusively, useful to verify that conflicts detected in a unique index are with live tuples, rather than dead ones. Author: Andres Freund Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
This commit is contained in:
parent
aa1419e63f
commit
71bdc99d0d
@ -15,9 +15,9 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/heapam.h"
|
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "access/nbtxlog.h"
|
#include "access/nbtxlog.h"
|
||||||
|
#include "access/tableam.h"
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/xloginsert.h"
|
#include "access/xloginsert.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
@ -431,11 +431,13 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We check the whole HOT-chain to see if there is any tuple
|
* Check if there's any table tuples for this index entry
|
||||||
* that satisfies SnapshotDirty. This is necessary because we
|
* satisfying SnapshotDirty. This is necessary because for AMs
|
||||||
* have just a single index entry for the entire chain.
|
* with optimizations like heap's HOT, we have just a single
|
||||||
|
* index entry for the entire chain.
|
||||||
*/
|
*/
|
||||||
else if (heap_hot_search(&htid, heapRel, &SnapshotDirty,
|
else if (table_index_fetch_tuple_check(heapRel, &htid,
|
||||||
|
&SnapshotDirty,
|
||||||
&all_dead))
|
&all_dead))
|
||||||
{
|
{
|
||||||
TransactionId xwait;
|
TransactionId xwait;
|
||||||
@ -489,7 +491,8 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
|
|||||||
* entry.
|
* entry.
|
||||||
*/
|
*/
|
||||||
htid = itup->t_tid;
|
htid = itup->t_tid;
|
||||||
if (heap_hot_search(&htid, heapRel, SnapshotSelf, NULL))
|
if (table_index_fetch_tuple_check(heapRel, &htid,
|
||||||
|
SnapshotSelf, NULL))
|
||||||
{
|
{
|
||||||
/* Normal case --- it's still live */
|
/* Normal case --- it's still live */
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,10 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/heapam.h"
|
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "access/parallel.h"
|
#include "access/parallel.h"
|
||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
|
#include "access/table.h"
|
||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "access/xlog.h"
|
#include "access/xlog.h"
|
||||||
|
@ -176,6 +176,40 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc parallel_scan)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* Index scan related functions.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To perform that check simply start an index scan, create the necessary
|
||||||
|
* slot, do the heap lookup, and shut everything down again. This could be
|
||||||
|
* optimized, but is unlikely to matter from a performance POV. If there
|
||||||
|
* frequently are live index pointers also matching a unique index key, the
|
||||||
|
* CPU overhead of this routine is unlikely to matter.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
table_index_fetch_tuple_check(Relation rel,
|
||||||
|
ItemPointer tid,
|
||||||
|
Snapshot snapshot,
|
||||||
|
bool *all_dead)
|
||||||
|
{
|
||||||
|
IndexFetchTableData *scan;
|
||||||
|
TupleTableSlot *slot;
|
||||||
|
bool call_again = false;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
slot = table_slot_create(rel, NULL);
|
||||||
|
scan = table_index_fetch_begin(rel);
|
||||||
|
found = table_index_fetch_tuple(scan, tid, snapshot, slot, &call_again,
|
||||||
|
all_dead);
|
||||||
|
table_index_fetch_end(scan);
|
||||||
|
ExecDropSingleTupleTableSlot(slot);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Functions to make modifications a bit simpler.
|
* Functions to make modifications a bit simpler.
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
|
@ -256,9 +256,10 @@ typedef struct TableAmRoutine
|
|||||||
* needs be set to true by index_fetch_tuple, signalling to the caller
|
* needs be set to true by index_fetch_tuple, signalling to the caller
|
||||||
* that index_fetch_tuple should be called again for the same tid.
|
* that index_fetch_tuple should be called again for the same tid.
|
||||||
*
|
*
|
||||||
* *all_dead should be set to true by index_fetch_tuple iff it is
|
* *all_dead, if all_dead is not NULL, should be set to true if by
|
||||||
* guaranteed that no backend needs to see that tuple. Index AMs can use
|
* index_fetch_tuple iff it is guaranteed that no backend needs to see
|
||||||
* that do avoid returning that tid in future searches.
|
* that tuple. Index AMs can use that do avoid returning that tid in
|
||||||
|
* future searches.
|
||||||
*/
|
*/
|
||||||
bool (*index_fetch_tuple) (struct IndexFetchTableData *scan,
|
bool (*index_fetch_tuple) (struct IndexFetchTableData *scan,
|
||||||
ItemPointer tid,
|
ItemPointer tid,
|
||||||
@ -594,9 +595,10 @@ table_index_fetch_end(struct IndexFetchTableData *scan)
|
|||||||
* will be set to true, signalling that table_index_fetch_tuple() should be called
|
* will be set to true, signalling that table_index_fetch_tuple() should be called
|
||||||
* again for the same tid.
|
* again for the same tid.
|
||||||
*
|
*
|
||||||
* *all_dead will be set to true by table_index_fetch_tuple() iff it is guaranteed
|
* *all_dead, if all_dead is not NULL, will be set to true by
|
||||||
* that no backend needs to see that tuple. Index AMs can use that do avoid
|
* table_index_fetch_tuple() iff it is guaranteed that no backend needs to see
|
||||||
* returning that tid in future searches.
|
* that tuple. Index AMs can use that do avoid returning that tid in future
|
||||||
|
* searches.
|
||||||
*
|
*
|
||||||
* The difference between this function and table_fetch_row_version is that
|
* The difference between this function and table_fetch_row_version is that
|
||||||
* this function returns the currently visible version of a row if the AM
|
* this function returns the currently visible version of a row if the AM
|
||||||
@ -618,6 +620,17 @@ table_index_fetch_tuple(struct IndexFetchTableData *scan,
|
|||||||
all_dead);
|
all_dead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a convenience wrapper around table_index_fetch_tuple() which
|
||||||
|
* returns whether there are table tuple items corresponding to an index
|
||||||
|
* entry. This likely is only useful to verify if there's a conflict in a
|
||||||
|
* unique index.
|
||||||
|
*/
|
||||||
|
extern bool table_index_fetch_tuple_check(Relation rel,
|
||||||
|
ItemPointer tid,
|
||||||
|
Snapshot snapshot,
|
||||||
|
bool *all_dead);
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------
|
||||||
* Functions for non-modifying operations on individual tuples
|
* Functions for non-modifying operations on individual tuples
|
||||||
|
Loading…
x
Reference in New Issue
Block a user