PgSQL技术内幕 - case when表达式实现机制
CASE表达式如同 C语言中的if/else语句一样,为SQL添加了条件逻辑处理能力,可以根据不同条件返回不同结果。PgSQL支持两种语法:简单表达式和搜索表达式。
1、搜索表达式
语法如下:
CASE WHEN condition THEN result[WHEN ...][ELSE result]
END
表达式计算过程:
按照顺序依次计算WHEN子句的条件表达式:condition1,condition2...,当遇到结果为真的分支就返回相应的THEN结果;若不为真,则继续下一个WHEN条件计算;若所有WHEN都不为真,则返回ELSE默认值;当没有指定ELSE时,就返回NULL。
2、简单表达式
语法如下:
CASE expressionWHEN value THEN result[WHEN ...][ELSE result]
END
表达式计算过程:
首先计算表达式testexpr的值,然后依次与WHEN中值:value1,value2...进行比较,遇到匹配的就返回THEN对应的结果;如果没有匹配则继续下一个WHEN值比较;若所有WHEN都不匹配则返回ELSE的默认值;如果没有指定ELSE则返回NULL。
3、搜索表达式实现机制
3.1 结构体
3.2 搜索表达式的实现机制
首先生成表达式计算步骤:ExecInitExprRec函数的T_CaseExpr分支。大致分为2大部分:
1)所有when的表达式caseExpr->args。首先通过ExecInitExprRec初始化when->expr的表达式计算步骤;然后添加EEOP_JUMP_IF_NOT_TRUE步骤,当when->expr表达式步骤计算为false时需要跳到下一个when,后面的state->steps[whenstep].d.jump.jumpdone = state->steps即为跳转位置;接着ExecInitExprRec初始化THEN的表达式(when->result)计算步骤;最后通过EEOP_JUMP跳到case的结束位置,它的结束位置需要计算完ELSE表达式后进行调整。
2)所有when表达式计算步骤生成后,需要对ELSE表达式进行初始化,即调用ExecInitExprRec对caseExpr->defresult生成计算步骤;最后调整EEOP_JUMP的跳转位置
3.3 简单表达式的实现机制
和搜索表达式不同,需要对CASE的表达式生成计算步骤,即caseExpr->arg的步骤;当该表达式结果类型为变长类型时,需要添加EEOP_MAKE_READONLY步骤进行结果值拷贝。
当没有ELSE时怎么办?
transformCaseExpr...defresult = (Node *) c->defresult;if (defresult == NULL){A_Const *n = makeNode(A_Const);n->val.type = T_Null;n->location = -1;defresult = (Node *) n;}newc->defresult = (Expr *) transformExprRecurse(pstate, defresult);...
也就是会添加一个const节点表示NULL,caseExpr->defresult总是有值。
参考
https://www.postgresql.org/docs/12/functions-conditional.html