From 1a882a9ee6f0c745107ec9eb3cee46aba4cc6cdf Mon Sep 17 00:00:00 2001 From: bjyb <1091839467@qq.com> Date: Tue, 26 Sep 2023 14:28:35 +0800 Subject: [PATCH] Update execCurrent.cpp --- .../runtime/executor/execCurrent.cpp | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/gausskernel/runtime/executor/execCurrent.cpp b/src/gausskernel/runtime/executor/execCurrent.cpp index 9e49bdc14..2e3770e07 100644 --- a/src/gausskernel/runtime/executor/execCurrent.cpp +++ b/src/gausskernel/runtime/executor/execCurrent.cpp @@ -47,6 +47,63 @@ static ScanState* search_plan_tree(PlanState *node, Oid table_oid); * legal situation in inheritance cases). Raises error if cursor is not a * valid updatable scan of the specified table. */ +/*The segment code defines a function named execCurrentOf, which is used to execute the CURRENT OF expression in SQL query. +The CURRENT OF expression is a part of SQL/PSM (Persistent Storage Module), +which is used to implement sensitive operations on a cursor. +The function execCurrentOf receives five parameters: + +1. cexpr: a pointer to the CurrentOfExpr structure, which contains the information of the CURRENT OF expression. +2. econtext: a pointer to ExprContext structure, which contains the context information of expression execution. +3. Relationship: A pointer to the relationship structure, which represents a relationship (i.e. a table) in the database. +4. current_tid: a pointer to the ItemPointer structure, which represents the current transaction ID. +5. partitionOfCursor_tid: A pointer to the RelationPtr structure, which represents the partition of the cursor. + +The function first obtains the name of the cursor according to cexpr, and +then finds the corresponding Portal according to the name. +If a valid Portal cannot be found, an error is reported. Then, the function checks +the query description (query_desc) corresponding to the Portal. +An error is also reported if the query description does not exist +or the status of the query description is invalid. + +Then, the function decides which strategy to execute according to the row marks in the query description. +If there is a line mark, use FOR UPDATE/SHARE; Otherwise, use a FOR-UPDATE method. + +It defines a variable named `erm` with an initial value of NULL. Then it traverses ` query _ desc-> estate-> es _ row marks`, +which is a list of all the rowmarks in the cursor query. During traversal, it +checks whether each row tag needs a row share lock, and if not, it ignores the row tag. + +For the row tag that needs a row sharing lock, the code checks whether the table associated with the row tag is +the target table (that is, the OID returned by the RelationGetRelid' of `thiserm-> relation' is equal to table_oid'). +If it is, and there is already a row tag associated with the target table, it will report an error because +the cursor cannot have more than one FOR UPDATE/SHARE reference to the same table. + +After the traversal is completed, if the row tag associated with the target table is not found, it will report an error, +because the cursor must have a FOR UPDATE/SHARE reference to the target table. + +Next, the code checks whether the cursor currently has a result row. +If not, it will report an error, because in the SQL specification, this is wrong. + +Finally, if there is a valid TID (transaction ID) of the current scan, it will set' current_tid' and check whether +the relationship is partitioned. If the relationship is partitioned, it will set `partition of cursor _ tid' to NULL. +Then return true, indicating that the related TID has been found. If a valid TID is not found, it will return false, +indicating that this table has not generated the current row of the cursor, and other inherited +sub-tables may have generated the current row of the cursor. + +Some variables are defined, including a pointer named scanstate', a boolean variable` lisnull', +an Oid variable` tuple_tableoid' and an ItemPointer variable` tuple_tid'. + +Then, it searches the search_plan_tree by calling the `search _ plan _ tree` function to find the scan node +associated with the given table OID. If the scan node is not found, +or the scan node is overwritten by the aggregation operation, it will report an error. + +Next, the code checks whether the cursor currently has a result row. If not, +it will report an error, because in the SQL specification, this is wrong. + +Then, if the current scan tuple in the scan state is NULL, it will return false. + +Finally, the code uses the slot_getattr function to get the table OID and transaction ID of +the tuple and check whether they are valid. If the relationship is partitioned, it will also check +whether the table OID is the same as the parent table OID of the partition.*/ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relation, ItemPointer current_tid, RelationPtr partitionOfCursor_tid) { @@ -208,6 +265,22 @@ bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Relation relatio * * Fetch the string value of a param, verifying it is of type REFCURSOR. */ +/*This code defines a function `fetch _ cursor _ param _ value`, which is used to get the specified +parameter value, especially when the parameter is of the reference cursor type. + +The input parameters of the function include a pointer to an ExprContext structure and an integer paramId. +The ExprContext' structure contains the execution context of the expression, which may contain +some parameter information. ParamId' is the ID of the parameter to get. + +The function first checks whether there is parameter information and whether the parameter ID is within the valid range. +Then, it locates the specific parameter and checks its type. If the parameter type is dynamic (that is, its type identifier is invalid) +and there is a parameter obtaining function, it will call this function to obtain the value of the parameter. + +If the parameter type is valid and not null, the function will check further. If the parameter type is not a reference refcursor, +it will report an error because the function only deals with this type. If the parameter type is a reference cursor, +the function will convert its value to a C string and return this string. + +If the value of the parameter is not found during the execution of the function, it will report an error and return NULL.*/ static char *fetch_cursor_param_value(ExprContext *econtext, int paramId) { ParamListInfo paramInfo = econtext->ecxt_param_list_info; @@ -243,6 +316,40 @@ static char *fetch_cursor_param_value(ExprContext *econtext, int paramId) * Search through a PlanState tree for a scan node on the specified table. * Return NULL if not found or multiple candidates. */ +/*t searches the PlanState tree for scan nodes on the specified table. +In PostgreSQL, the PlanState tree is a data structure representing the query execution plan. +The function `search _ plan _ tree` receives two parameters: a pointer` node of PlanState and +a ` table _ Oid` of oid type. The function starts searching from the given node +and finds the scanning node that matches the OID of the specified table. +In the code, use the switch statement to judge the type of the node. For each scan node type that can be processed +(for example, sequential scan, index scan, index only scan, bitmap heap scan and TID scan), the code checks whether the ID +of the current relationship (that is, the scanned table) matches the given table OID. +If there is a match, the function returns a pointer to the scan node. + +For the `t _ remotequerystate` node, the code will return the scanning status of the node. +For the `t _ extensibleplanstate' node, the code will check whether the ID of the current relationship matches +the given table OID, and return the scanning status at the time of matching. + +For the `t _ appendstate` node, the code will iterate through all the attached plans and recursively call the `search _ plan _ tree` function. +If multiple matching scan nodes are found in the attached schedule, the function will return NULL. + +-`T_AppendState' and `t _ mergeappendState': Both node types represent a method of combining multiple subquery results into one result. +The code will traverse each subquery and recursively call the `search _ plan _ tree` function for each subquery. +If a matching scanning node is found, and no matching node has been found before, the matching node is assigned to result. +If multiple matching nodes are found, the function will return NULL. +-`t _ resultstate`, `t _ limitstate`, `t _ partiteratorstate`, and `t _ materialstate` (only exists in PGXC): These node types can be +traversed directly because they always return the current line of their input. +-`T_SubqueryScanState: This node type represents the scanning of the subquery, +and the code will return the scanning node in the subquery. +-Default: If the node is not of any of the above types, +the code will assume that it cannot traverse through the node, so it will return NULL. + +The main purpose of this function is to find the scanning node corresponding to a specific table in the query execution plan. +This is very useful for understanding and tracking query execution, especially +when it is necessary to understand and debug query performance problems. + +Generally speaking, this function is used to find the scan node corresponding to the specified table in the query execution plan.*/ + #ifdef PGXC ScanState* search_plan_tree(PlanState* node, Oid table_oid) #else