/* Get the cursor name --- may have to look up a parameter reference */ if (cexpr->cursor_name)
cursor_name = cexpr->cursor_name; else
cursor_name = fetch_cursor_param_value(econtext, cexpr->cursor_param);
/* Fetch table name for possible use in error messages */
table_name = get_rel_name(table_oid); if (table_name == NULL)
elog(ERROR, "cache lookup failed for relation %u", table_oid);
/* Find the cursor's portal */
portal = GetPortalByName(cursor_name); if (!PortalIsValid(portal))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_CURSOR),
errmsg("cursor \"%s\" does not exist", cursor_name)));
/* *Wehavetowatchoutfornon-SELECTqueriesaswellasheldcursors, *bothofwhichmayhavenullqueryDesc.
*/ if (portal->strategy != PORTAL_ONE_SELECT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not a SELECT query",
cursor_name)));
queryDesc = portal->queryDesc; if (queryDesc == NULL || queryDesc->estate == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is held from a previous transaction",
cursor_name)));
/* *Wehavetwodifferentstrategiesdependingonwhetherthecursoruses *FORUPDATE/SHAREornot.Thereasonforsupportingbothisthatthe *FORUPDATEcodeisabletoidentifyatargettableinmanycaseswhere *theothercodecan't,whilethenon-FOR-UPDATEcaseallowsuseofWHERE *CURRENTOFwithaninsensitivecursor.
*/ if (queryDesc->estate->es_rowmarks)
{
ExecRowMark *erm;
Index i;
/* *Here,thequerymusthaveexactlyoneFORUPDATE/SHAREreferenceto *thetargettable,andwedigthectidinfooutofthat.
*/
erm = NULL; for (i = 0; i < queryDesc->estate->es_range_table_size; i++)
{
ExecRowMark *thiserm = queryDesc->estate->es_rowmarks[i];
if (thiserm->relid == table_oid)
{ if (erm)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" has multiple FOR UPDATE/SHARE references to table \"%s\"",
cursor_name, table_name)));
erm = thiserm;
}
}
if (erm == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" does not have a FOR UPDATE/SHARE reference to table \"%s\"",
cursor_name, table_name)));
/* *Thecursormusthaveacurrentresultrow:pertheSQLspec,it's *anerrorifnot.
*/ if (portal->atStart || portal->atEnd)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not positioned on a row",
cursor_name)));
/* Return the currently scanned TID, if there is one */ if (ItemPointerIsValid(&(erm->curCtid)))
{
*current_tid = erm->curCtid; returntrue;
}
scanstate = search_plan_tree(queryDesc->planstate, table_oid,
&pending_rescan); if (!scanstate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
cursor_name, table_name)));
/* *Thecursormusthaveacurrentresultrow:pertheSQLspec,it's *anerrorifnot.Wetestthisatthetoplevel,ratherthanatthe *scannodelevel,becauseininheritancecasesanyonetablescan *couldeasilynotbeonarow.Wewanttoreturnfalse,notraise *error,ifthepassed-intableOIDisforoneoftheinactivescans.
*/ if (portal->atStart || portal->atEnd)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not positioned on a row",
cursor_name)));
/* *NowOKtoreturnfalseifwefoundaninactivescan.Itis *inactiveeitherifit'snotpositionedonarow,orthere'sa *rescanpendingforit.
*/ if (TupIsNull(scanstate->ss_ScanTupleSlot) || pending_rescan) returnfalse;
/* give hook a chance in case parameter is dynamic */ if (paramInfo->paramFetch != NULL)
prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata); else
prm = ¶mInfo->params[paramId - 1];
if (OidIsValid(prm->ptype) && !prm->isnull)
{ /* safety check in case hook did something unexpected */ if (prm->ptype != REFCURSOROID)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
paramId,
format_type_be(prm->ptype),
format_type_be(REFCURSOROID))));
/* We know that refcursor uses text's I/O routines */ return TextDatumGetCString(prm->value);
}
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("no value found for parameter %d", paramId))); return NULL;
}
if (node == NULL) return NULL; switch (nodeTag(node))
{ /* *Relationscannodescanallbetreatedalike:checktoseeif *theyarescanningthespecifiedtable. * *ForeignScanandCustomScanmightnothaveacurrentRelation,in *whichcasewejustignorethem.(Wedarenotdescendtoany *childplannodestheymighthave,sincewedonotknowthe *relationshipofsuchanode'scurrentoutputtupletothe *children'scurrentoutputs.)
*/ case T_SeqScanState: case T_SampleScanState: case T_IndexScanState: case T_IndexOnlyScanState: case T_BitmapHeapScanState: case T_TidScanState: case T_TidRangeScanState: case T_ForeignScanState: case T_CustomScanState:
{
ScanState *sstate = (ScanState *) node;
if (sstate->ss_currentRelation &&
RelationGetRelid(sstate->ss_currentRelation) == table_oid)
result = sstate; break;
}
for (i = 0; i < astate->as_nplans; i++)
{
ScanState *elem = search_plan_tree(astate->appendplans[i],
table_oid,
pending_rescan);
if (!elem) continue; if (result) return NULL; /* multiple matches */
result = elem;
} break;
}
/* *ResultandLimitcanbedescendedthrough(thesearesafe *becausetheyalwaysreturntheirinput'scurrentrow)
*/ case T_ResultState: case T_LimitState:
result = search_plan_tree(outerPlanState(node),
table_oid,
pending_rescan); break;
/* *SubqueryScantoo,butitkeepsthechildinadifferentplace
*/ case T_SubqueryScanState:
result = search_plan_tree(((SubqueryScanState *) node)->subplan,
table_oid,
pending_rescan); break;
default: /* Otherwise, assume we can't descend through it */ break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.