pg 绑定变量相关源码解析
下面以callstmt 为例 说明一下绑定参数的执行流程(基于pg13)
整体架构
1. exec_parse_message
解析变量。
--> parse_analyze_varparams 解析绑定参数$id
--->parse_variable_parameters , 把返回值paramTypes, numParams绑定到VarParamState *parstate中
--> transformTopLevelStmt
--> transformCallStmt
--> transformExpr
--> transformParamRef
--> p_paramref_hook variable_paramref_hook 转换参数,并设置 VarParamState *parstate.numParams,初始化paramTypes 为UNKNOWNOID。
--> ParseFuncOrColumn
--> p_coerce_param_hook variable_coerce_param_hook 设置param 节点及要返回的paramTypes中的类型
--> 判断paramTypes 中类型是否都准确设置, 不为UNKNOWNOID,InvalidOid
--> CompleteCachedPlan 设置plansource->param_types,plansource->num_params,plansource->resultDesc (返回结果)
--> PlanCacheComputeResultDesc
--> ChoosePortalStrategy 返回PORTAL_UTIL_SELECT
UtilityReturnsTuples 返回 如果有返回值则返回true
--> UtilityTupleDescriptor 有返回值,构造tuple
2. exec_bind_message
设置实际变量值。
exec_bind_message 根据plansource->param_types, plansource->num_params 来转换输入的变量值,构造ParamListInfo 保存转换后的值。然后调用PortalStart 设置portal->tupDesc,portal->portalParams -》ParamListInfo
3. exec_execute_message
portal 的执行策略
portal 的执行策略有如下几种:
typedef enum PortalStrategy
{
PORTAL_ONE_SELECT, // 一条select查询
PORTAL_ONE_RETURNING, //一条带有返回值的INSERT/UPDATE/DELETE查询(with a RETURNING clause)
PORTAL_ONE_MOD_WITH, // 一条带有data-modifying CTEs的select 查询
PORTAL_UTIL_SELECT, // 带返回结果的util
PORTAL_MULTI_QUERY // 所有其他情况: 没有返回值的util/INSERT/UPDATE/DELETE
} PortalStrategy;
PORTAL_ONE_SELECT 在 PortalStart时会调用CreateQueryDesc创建 QueryDesc,会设置params。 然后调用ExecutorStart,然后执行ExecInitNode, 最终会调用ExecInitExprRec 设置变量的实际值。
callstmt 为 portal 策略为 PORTAL_UTIL_SELECT
根据实际变量值,执行SQL。
--> PortalRun PORTAL_UTIL_SELECT
--> FillPortalStore Run the query and load result tuples into the portal's tuple store. portal->holdStore
--> standard_ProcessUtility
--> ExecuteCallStmt 传入ParamListInfo(portal->portalParams) 和DestReceiver *dest(返回值发送到dest, DestTuplestore, 实际为portal->holdStore)
--> PortalRunSelect forward=true, fetching from a completed holdStore
--> RunFromStore 从portal->holdStore 获取数据发给客户端,用portal->tupDesc描述结构