aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execCurrent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execCurrent.c')
-rw-r--r--src/backend/executor/execCurrent.c79
1 files changed, 59 insertions, 20 deletions
diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c
index ce7d4ac592a..f70e54fe2af 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;
}