diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/common/heaptuple.c | 26 | ||||
-rw-r--r-- | src/backend/executor/execCurrent.c | 79 |
2 files changed, 85 insertions, 20 deletions
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 6d0f3f37673..8bcb4ce2ba8 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -1300,6 +1300,32 @@ slot_attisnull(TupleTableSlot *slot, int attnum) } /* + * slot_getsysattr + * This function fetches a system attribute of the slot's current tuple. + * Unlike slot_getattr, if the slot does not contain system attributes, + * this will return false (with a NULL attribute value) instead of + * throwing an error. + */ +bool +slot_getsysattr(TupleTableSlot *slot, int attnum, + Datum *value, bool *isnull) +{ + HeapTuple tuple = slot->tts_tuple; + + Assert(attnum < 0); /* else caller error */ + if (tuple == NULL || + tuple == &(slot->tts_minhdr)) + { + /* No physical tuple, or minimal tuple, so fail */ + *value = (Datum) 0; + *isnull = true; + return false; + } + *value = heap_getsysattr(tuple, attnum, slot->tts_tupleDescriptor, isnull); + return true; +} + +/* * heap_freetuple */ void diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c index 2e4e485a064..e2ae2e18452 100644 --- a/src/backend/executor/execCurrent.c +++ b/src/backend/executor/execCurrent.c @@ -12,6 +12,7 @@ */ #include "postgres.h" +#include "access/relscan.h" #include "access/sysattr.h" #include "catalog/pg_type.h" #include "executor/executor.h" @@ -149,16 +150,13 @@ execCurrentOf(CurrentOfExpr *cexpr, } else { - ScanState *scanstate; - bool lisnull; - Oid tuple_tableoid PG_USED_FOR_ASSERTS_ONLY; - ItemPointer tuple_tid; - /* * Without FOR UPDATE, we dig through the cursor's plan to find the * scan node. Fail if it's not there or buried underneath * aggregation. */ + ScanState *scanstate; + scanstate = search_plan_tree(queryDesc->planstate, table_oid); if (!scanstate) ereport(ERROR, @@ -183,21 +181,62 @@ execCurrentOf(CurrentOfExpr *cexpr, if (TupIsNull(scanstate->ss_ScanTupleSlot)) return false; - /* Use slot_getattr to catch any possible mistakes */ - tuple_tableoid = - DatumGetObjectId(slot_getattr(scanstate->ss_ScanTupleSlot, - TableOidAttributeNumber, - &lisnull)); - Assert(!lisnull); - tuple_tid = (ItemPointer) - DatumGetPointer(slot_getattr(scanstate->ss_ScanTupleSlot, - SelfItemPointerAttributeNumber, - &lisnull)); - Assert(!lisnull); - - Assert(tuple_tableoid == table_oid); - - *current_tid = *tuple_tid; + /* + * Extract TID of the scan's current row. The mechanism for this is + * in principle scan-type-dependent, but for most scan types, we can + * just dig the TID out of the physical scan tuple. + */ + if (IsA(scanstate, IndexOnlyScanState)) + { + /* + * For IndexOnlyScan, the tuple stored in ss_ScanTupleSlot may be + * a virtual tuple that does not have the ctid column, so we have + * to get the TID from xs_ctup.t_self. + */ + IndexScanDesc scan = ((IndexOnlyScanState *) scanstate)->ioss_ScanDesc; + + *current_tid = scan->xs_ctup.t_self; + } + else + { + /* + * Default case: try to fetch TID from the scan node's current + * tuple. As an extra cross-check, verify tableoid in the current + * tuple. If the scan hasn't provided a physical tuple, we have + * to fail. + */ + Datum ldatum; + bool lisnull; + ItemPointer tuple_tid; + +#ifdef USE_ASSERT_CHECKING + if (!slot_getsysattr(scanstate->ss_ScanTupleSlot, + TableOidAttributeNumber, + &ldatum, + &lisnull)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_CURSOR_STATE), + errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"", + cursor_name, table_name))); + Assert(!lisnull); + Assert(DatumGetObjectId(ldatum) == table_oid); +#endif + + if (!slot_getsysattr(scanstate->ss_ScanTupleSlot, + SelfItemPointerAttributeNumber, + &ldatum, + &lisnull)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_CURSOR_STATE), + errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"", + cursor_name, table_name))); + Assert(!lisnull); + tuple_tid = (ItemPointer) DatumGetPointer(ldatum); + + *current_tid = *tuple_tid; + } + + Assert(ItemPointerIsValid(current_tid)); return true; } |