openGauss源码解析(123)
openGauss源码解析:执行器解析(16)
3. Limit算子
Limit算子节点主要用来处理LIMIT/OFFSET子句,用于限制子查询语句处理元组的数量,对应的代码源文件是“nodeLimit.cpp”。算子对应的主要函数如表7-26所示。
表7-26 Limit算子主要函数
主要函数 | 说明 |
ExecInitLimit | 初始化Limit状态节点 |
ExecLimit | 迭代获取元组 |
ExecEndLimit | 清理Limit状态节点 |
recompute_limits | 初始化limit/offset表达式 |
Limit算子对应的关键结构体是LimitState,相关代码如下:
typedef struct LimitState {
PlanState ps; /* 计划状态节点*/
ExprState* limitOffset; /* 偏移位置*/
ExprState* limitCount; /* 总数 */
int64 offset; /* 当前偏移位置 */
int64 count; /* 当前总数 */
bool noCount; /* 忽略总数标识 */
LimitStateCond lstate; /* 状态机当前状态 */
int64 position; /* 上一个元组的位置 */
TupleTableSlot* subSlot; /* 上一个元组 */
} LimitState;
ExecInitLimit函数用于把Limit计划节点转成Limit执行节点。主要执行流程如下。
(1) 初始化Limit状态节点(LimitState)并做子表达式处理,分别初始化limitOffset(调用“ExecInitExpr((Expr*)node->limitOffset, (PlanState*)limit_state)”函数)和limitCount(调用“ExecInitExpr((Expr*)node->limitCount, (PlanState*)limit_state);”函数)表达式。
(2) 调用“ExecInitResultTupleSlot(estate, &limit_state->ps)”函数做元组初始化。
(3) 外部计划初始化(调用“outer_plan = outerPlan(node); outerPlanState(limit_state) = ExecInitNode(outer_plan, estate, eflags);”函数)。
(4) 对投影信息置空(由于Limit无投影)。
ExecLimit是执行Limit算子的入口,每次返回一个元组。在函数体内部通过“switch (node->lstate) ”函数来处理Limit算子的各种Limit状态,如果Limit对应的状态不是叶子节点则调用ExecProcNode做递归处理。“node->lstate”对应的状态有LIMIT_INITIAL、LIMIT_RESCAN、LIMIT_EMPTY、LIMIT_INWINDOW、LIMIT_SUBPLANEOF、LIMIT_WINDOWEND、LIMIT_WINDOWSTART。其中LIMIT_INITIAL对应处理Limit算子初始化,LIMIT_RESCAN对应重新执行子节点计划,LIMIT_EMPTY对应Limit算子是空集,LIMIT_INWINDOW用于处理窗口函数(在窗口函数内前向和后向移动),LIMIT_SUBPLANEOF用于处理子节点计划(移动到子节点计划尾部),LIMIT_WINDOWEND用于在窗口尾部结束,LIMIT_WINDOWSTART用于在窗口开始处结束。
recompute_limits函数用于在初始化时处理limit/offset表达式。主要执行流程如下。