Update execCurrent.cpp

This commit is contained in:
ljh0804 2023-08-10 21:14:09 +08:00
parent 50230625f0
commit 44f750e018
1 changed files with 41 additions and 56 deletions

View File

@ -1,13 +1,13 @@
/* -------------------------------------------------------------------------
*
* execCurrent.c
* executor support for WHERE CURRENT OF cursor
* WHERE CURRENT OF游标执行程序支持WHERE CURRENT OF游标
*
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* (c) 1996-2012, PostgreSQL全球发展集团
* (c) 1994
*
* IDENTIFICATION
*
* src/backend/executor/execCurrent.c
*
* -------------------------------------------------------------------------
@ -38,14 +38,12 @@ static ScanState* search_plan_tree(PlanState *node, Oid table_oid);
/*
* execCurrentOf
*
* Given a CURRENT OF expression and the OID of a table, determine which row
* of the table is currently being scanned by the cursor named by CURRENT OF,
* and return the row's TID into *current_tid.
* CURRENT OF表达式和表的OID
* CURRENT of的游标扫描
* TID为*current_tid
*
* Returns TRUE if a row was identified. Returns FALSE if the cursor is valid
* for the table but is not currently scanning a row of the table (this is a
* legal situation in inheritance cases). Raises error if cursor is not a
* valid updatable scan of the specified table.
* TRUEFALSE
* ()
*/
bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relation, ItemPointer current_tid,
RelationPtr partitionOfCursor_tid)
@ -55,14 +53,14 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
QueryDesc *query_desc = NULL;
Oid table_oid = RelationGetRelid(relation);
/* 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);
}
/* Find the cursor's portal */
/* 找到游标的入口 */
portal = GetPortalByName(cursor_name);
if (!PortalIsValid(portal)) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_CURSOR),
@ -70,8 +68,7 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
}
/*
* We have to watch out for non-SELECT queries as well as held cursors,
* both of which may have null query_desc.
* select查询和持有的游标query_desc都可能为空
*/
if (portal->strategy != PORTAL_ONE_SELECT) {
ereport(ERROR,
@ -85,26 +82,23 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
}
/*
* We have two different strategies depending on whether the cursor uses
* FOR UPDATE/SHARE or not. The reason for supporting both is that the
* FOR UPDATE code is able to identify a target table in many cases where
* the other code can't, while the non-FOR-UPDATE case allows use of WHERE
* CURRENT OF with an insensitive cursor.
* 使
* /
* FOR UPDATE代码能够识别目标表FOR-UPDATE情况允许使用不敏感游标的when CURRENT of
*/
if (query_desc->estate->es_rowMarks) {
ExecRowMark *erm = NULL;
ListCell *lc = NULL;
/*
* Here, the query must have exactly one FOR UPDATE/SHARE reference to
* the target table, and we dig the ctid info out of that.
* FOR UPDATE/SHARE引用ctid信息
*/
erm = NULL;
foreach (lc, query_desc->estate->es_rowMarks) {
ExecRowMark *thiserm = (ExecRowMark *)lfirst(lc);
if (!RowMarkRequiresRowShareLock(thiserm->markType)) {
continue; /* ignore non-FOR UPDATE/SHARE items */
continue; /* 忽略非for UPDATE/SHARE项 */
}
if (RelationGetRelid(thiserm->relation) == table_oid) {
@ -124,15 +118,14 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
}
/*
* The cursor must have a current result row: per the SQL spec, it's
* an error if not.
* :SQL规范
*/
if (portal->atStart || portal->atEnd) {
ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not positioned on a row when the cursor uses for UPDATE/SHARE", cursor_name)));
}
/* Return the currently scanned TID, if there is one */
/* 返回当前扫描的TID(如果有) */
if (ItemPointerIsValid(&(erm->curCtid))) {
*current_tid = erm->curCtid;
@ -144,9 +137,7 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
}
/*
* This table didn't produce the cursor's current row; some other
* inheritance child of the same parent must have. Signal caller to
* do nothing on this table.
* ;
*/
return false;
} else {
@ -156,9 +147,7 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
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.
* FOR UPDATE
*/
scanstate = search_plan_tree(query_desc->planstate, table_oid);
if (scanstate == NULL) {
@ -168,23 +157,21 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
}
/*
* The cursor must have a current result row: per the SQL spec, it's
* an error if not. We test this at the top level, rather than at the
* scan node level, because in inheritance cases any one table scan
* could easily not be on a row. We want to return false, not raise
* error, if the passed-in table OID is for one of the inactive scans.
* :SQL规范
*
* OID是用于非活动扫描的false
*/
if (portal->atStart || portal->atEnd) {
ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE), errmsg(
"cursor \"%s\" is not positioned on a row when the cursor doesn't use for UPDATE/SHARE", cursor_name)));
}
/* Now OK to return false if we found an inactive scan */
/* 现在OK返回false如果我们发现一个非活动扫描 */
if (TupIsNull(scanstate->ss_ScanTupleSlot)) {
return false;
}
/* Use slot_getattr to catch any possible mistakes */
/* 使用slot_getattr捕获任何可能的错误 */
tuple_tableoid = DatumGetObjectId(tableam_tslot_getattr(scanstate->ss_ScanTupleSlot, TableOidAttributeNumber, &lisnull));
Assert(!lisnull);
tuple_tid = (ItemPointer)DatumGetPointer(
@ -206,7 +193,7 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio
/*
* fetch_cursor_param_value
*
* Fetch the string value of a param, verifying it is of type REFCURSOR.
* REFCURSOR类型.
*/
static char *fetch_cursor_param_value(ExprContext *econtext, int paramId)
{
@ -215,20 +202,20 @@ static char *fetch_cursor_param_value(ExprContext *econtext, int paramId)
if (paramInfo && paramId > 0 && paramId <= paramInfo->numParams) {
ParamExternData *prm = &paramInfo->params[paramId - 1];
/* give hook a chance in case parameter is dynamic */
/* 如果参数是动态的,给钩子一个机会 */
if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL) {
(*paramInfo->paramFetch)(paramInfo, paramId);
}
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 */
/* 我们知道refcursor使用text的I/O例程 */
return TextDatumGetCString(prm->value);
}
}
@ -240,8 +227,8 @@ static char *fetch_cursor_param_value(ExprContext *econtext, int paramId)
/*
* search_plan_tree
*
* Search through a PlanState tree for a scan node on the specified table.
* Return NULL if not found or multiple candidates.
* PlanState树中搜索指定表上的扫描节点
* NULL
*/
#ifdef PGXC
ScanState* search_plan_tree(PlanState* node, Oid table_oid)
@ -262,7 +249,7 @@ static ScanState* search_plan_tree(PlanState* node, Oid table_oid)
}
#endif
/*
* scan nodes can all be treated alike
*
*/
case T_SeqScanState:
case T_IndexScanState:
@ -284,8 +271,7 @@ static ScanState* search_plan_tree(PlanState* node, Oid table_oid)
return result;
}
/*
* For Append, we must look through the members; watch out for
* multiple matches (possible if it was from UNION ALL)
* Append;(UNION ALL)
*/
case T_AppendState: {
AppendState *astate = (AppendState *)node;
@ -297,14 +283,14 @@ static ScanState* search_plan_tree(PlanState* node, Oid table_oid)
if (elem == NULL)
continue;
if (result != NULL)
return NULL; /* multiple matches */
return NULL; /* 多个匹配 */
result = elem;
}
return result;
}
/*
* Similarly for MergeAppend
* MergeAppend
*/
case T_MergeAppendState: {
MergeAppendState *mstate = (MergeAppendState *)node;
@ -318,15 +304,14 @@ static ScanState* search_plan_tree(PlanState* node, Oid table_oid)
continue;
}
if (result != NULL) {
return NULL; /* multiple matches */
return NULL; /* 多个匹配 */
}
result = elem;
}
return result;
}
/*
* Result and Limit can be descended through (these are safe
* because they always return their input's current row)
* Result和Limit可以依次下降()
*/
#ifdef PGXC
case T_MaterialState:
@ -337,13 +322,13 @@ static ScanState* search_plan_tree(PlanState* node, Oid table_oid)
return search_plan_tree(node->lefttree, table_oid);
/*
* SubqueryScan too, but it keeps the child in a different place
* SubqueryScan也可以
*/
case T_SubqueryScanState:
return search_plan_tree(((SubqueryScanState *)node)->subplan, table_oid);
default:
/* Otherwise, assume we can't descend through it */
/* 否则,假设我们不能从里面下去 */
break;
}
return NULL;