1/*-------------------------------------------------------------------------
4 * executor support for WHERE CURRENT OF cursor
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/backend/executor/execCurrent.c
11 *-------------------------------------------------------------------------
28 bool *pending_rescan);
34 * Given a CURRENT OF expression and the OID of a table, determine which row
35 * of the table is currently being scanned by the cursor named by CURRENT OF,
36 * and return the row's TID into *current_tid.
38 * Returns true if a row was identified. Returns false if the cursor is valid
39 * for the table but is not currently scanning a row of the table (this is a
40 * legal situation in inheritance cases). Raises error if cursor is not a
41 * valid updatable scan of the specified table.
54 /* Get the cursor name --- may have to look up a parameter reference */
60 /* Fetch table name for possible use in error messages */
62 if (table_name == NULL)
63 elog(
ERROR,
"cache lookup failed for relation %u", table_oid);
65 /* Find the cursor's portal */
69 (
errcode(ERRCODE_UNDEFINED_CURSOR),
70 errmsg(
"cursor \"%s\" does not exist", cursor_name)));
73 * We have to watch out for non-SELECT queries as well as held cursors,
74 * both of which may have null queryDesc.
78 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
79 errmsg(
"cursor \"%s\" is not a SELECT query",
82 if (queryDesc == NULL || queryDesc->
estate == NULL)
84 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
85 errmsg(
"cursor \"%s\" is held from a previous transaction",
89 * We have two different strategies depending on whether the cursor uses
90 * FOR UPDATE/SHARE or not. The reason for supporting both is that the
91 * FOR UPDATE code is able to identify a target table in many cases where
92 * the other code can't, while the non-FOR-UPDATE case allows use of WHERE
93 * CURRENT OF with an insensitive cursor.
101 * Here, the query must have exactly one FOR UPDATE/SHARE reference to
102 * the target table, and we dig the ctid info out of that.
109 if (thiserm == NULL ||
111 continue;
/* ignore non-FOR UPDATE/SHARE items */
113 if (thiserm->
relid == table_oid)
117 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
118 errmsg(
"cursor \"%s\" has multiple FOR UPDATE/SHARE references to table \"%s\"",
119 cursor_name, table_name)));
126 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
127 errmsg(
"cursor \"%s\" does not have a FOR UPDATE/SHARE reference to table \"%s\"",
128 cursor_name, table_name)));
131 * The cursor must have a current result row: per the SQL spec, it's
136 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
137 errmsg(
"cursor \"%s\" is not positioned on a row",
140 /* Return the currently scanned TID, if there is one */
148 * This table didn't produce the cursor's current row; some other
149 * inheritance child of the same parent must have. Signal caller to
150 * do nothing on this table.
157 * Without FOR UPDATE, we dig through the cursor's plan to find the
158 * scan node. Fail if it's not there or buried underneath
162 bool pending_rescan =
false;
168 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
169 errmsg(
"cursor \"%s\" is not a simply updatable scan of table \"%s\"",
170 cursor_name, table_name)));
173 * The cursor must have a current result row: per the SQL spec, it's
174 * an error if not. We test this at the top level, rather than at the
175 * scan node level, because in inheritance cases any one table scan
176 * could easily not be on a row. We want to return false, not raise
177 * error, if the passed-in table OID is for one of the inactive scans.
181 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
182 errmsg(
"cursor \"%s\" is not positioned on a row",
186 * Now OK to return false if we found an inactive scan. It is
187 * inactive either if it's not positioned on a row, or there's a
188 * rescan pending for it.
194 * Extract TID of the scan's current row. The mechanism for this is
195 * in principle scan-type-dependent, but for most scan types, we can
196 * just dig the TID out of the physical scan tuple.
201 * For IndexOnlyScan, the tuple stored in ss_ScanTupleSlot may be
202 * a virtual tuple that does not have the ctid column, so we have
203 * to get the TID from xs_heaptid.
212 * Default case: try to fetch TID from the scan node's current
213 * tuple. As an extra cross-check, verify tableoid in the current
214 * tuple. If the scan hasn't provided a physical tuple, we have
221#ifdef USE_ASSERT_CHECKING
227 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
228 errmsg(
"cursor \"%s\" is not a simply updatable scan of table \"%s\"",
229 cursor_name, table_name)));
238 (
errcode(ERRCODE_INVALID_CURSOR_STATE),
239 errmsg(
"cursor \"%s\" is not a simply updatable scan of table \"%s\"",
240 cursor_name, table_name)));
243 *current_tid = *tuple_tid;
253 * fetch_cursor_param_value
255 * Fetch the string value of a param, verifying it is of type REFCURSOR.
263 paramId > 0 && paramId <= paramInfo->numParams)
268 /* give hook a chance in case parameter is dynamic */
270 prm = paramInfo->
paramFetch(paramInfo, paramId,
false, &prmdata);
272 prm = ¶mInfo->
params[paramId - 1];
276 /* safety check in case hook did something unexpected */
277 if (prm->
ptype != REFCURSOROID)
279 (
errcode(ERRCODE_DATATYPE_MISMATCH),
280 errmsg(
"type of parameter %d (%s) does not match that when preparing the plan (%s)",
285 /* We know that refcursor uses text's I/O routines */
291 (
errcode(ERRCODE_UNDEFINED_OBJECT),
292 errmsg(
"no value found for parameter %d", paramId)));
299 * Search through a PlanState tree for a scan node on the specified table.
300 * Return NULL if not found or multiple candidates.
302 * CAUTION: this function is not charged simply with finding some candidate
303 * scan, but with ensuring that that scan returned the plan tree's current
304 * output row. That's why we must reject multiple-match cases.
306 * If a candidate is found, set *pending_rescan to true if that candidate
307 * or any node above it has a pending rescan action, i.e. chgParam != NULL.
308 * That indicates that we shouldn't consider the node to be positioned on a
309 * valid tuple, even if its own state would indicate that it is. (Caller
310 * must initialize *pending_rescan to false, and should not trust its state
311 * if multiple candidates are found.)
315 bool *pending_rescan)
324 * Relation scan nodes can all be treated alike: check to see if
325 * they are scanning the specified table.
327 * ForeignScan and CustomScan might not have a currentRelation, in
328 * which case we just ignore them. (We dare not descend to any
329 * child plan nodes they might have, since we do not know the
330 * relationship of such a node's current output tuple to the
331 * children's current outputs.)
334 case T_SampleScanState:
335 case T_IndexScanState:
336 case T_IndexOnlyScanState:
337 case T_BitmapHeapScanState:
339 case T_TidRangeScanState:
340 case T_ForeignScanState:
341 case T_CustomScanState:
352 * For Append, we can check each input node. It is safe to
353 * descend to the inputs because only the input that resulted in
354 * the Append's current output node could be positioned on a tuple
355 * at all; the other inputs are either at EOF or not yet started.
356 * Hence, if the desired table is scanned by some
357 * currently-inactive input node, we will find that node but then
358 * our caller will realize that it didn't emit the tuple of
361 * We do need to watch out for multiple matches (possible if
362 * Append was from UNION ALL rather than an inheritance tree).
364 * Note: we can NOT descend through MergeAppend similarly, since
365 * its inputs are likely all active, and we don't know which one
366 * returned the current output tuple. (Perhaps that could be
367 * fixed if we were to let this code know more about MergeAppend's
368 * internal state, but it does not seem worth the trouble. Users
369 * should not expect plans for ORDER BY queries to be considered
370 * simply-updatable, since they won't be if the sorting is
371 * implemented by a Sort node.)
387 return NULL;
/* multiple matches */
394 * Result and Limit can be descended through (these are safe
395 * because they always return their input's current row)
405 * SubqueryScan too, but it keeps the child in a different place
407 case T_SubqueryScanState:
414 /* Otherwise, assume we can't descend through it */
419 * If we found a candidate at or below this node, then this node's
420 * chgParam indicates a pending rescan that will affect the candidate.
422 if (result && node->
chgParam != NULL)
423 *pending_rescan =
true;
#define TextDatumGetCString(d)
#define OidIsValid(objectId)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
static ScanState * search_plan_tree(PlanState *node, Oid table_oid, bool *pending_rescan)
static char * fetch_cursor_param_value(ExprContext *econtext, int paramId)
bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Oid table_oid, ItemPointer current_tid)
#define outerPlanState(node)
Assert(PointerIsAligned(start, uint64))
ItemPointerData * ItemPointer
static bool ItemPointerIsValid(const ItemPointerData *pointer)
char * get_rel_name(Oid relid)
#define IsA(nodeptr, _type_)
#define RowMarkRequiresRowShareLock(marktype)
Portal GetPortalByName(const char *name)
static Oid DatumGetObjectId(Datum X)
static Pointer DatumGetPointer(Datum X)
#define RelationGetRelid(relation)
ExecRowMark ** es_rowmarks
Index es_range_table_size
ParamListInfo ecxt_param_list_info
ItemPointerData xs_heaptid
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
ParamFetchHook paramFetch
Relation ss_currentRelation
TupleTableSlot * ss_ScanTupleSlot
#define TableOidAttributeNumber
#define SelfItemPointerAttributeNumber
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)