Update execCurrent.cpp

This commit is contained in:
bjyb 2023-09-26 14:28:35 +08:00
parent 7758348b68
commit 1a882a9ee6
1 changed files with 107 additions and 0 deletions

View File

@ -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