表达式计算解析(3)

引言

这篇文章我将继续介绍表达式计算的相关内容,主要介绍ExecEvalFunc函数、ExecMakeFunctionResultNoSets函数和ExecTargetList函数。

函数所在源文件为src\gausskernel\runtime\executor\execQual.cpp.

函数分析

执行阶段

ExecEvalFunc

函数源码
 
  1. //代码清单1
  2. static Datum ExecEvalFunc(FuncExprState* fcache, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
  3. {
  4. /* This is called only the first time through */
  5. FuncExpr* func = (FuncExpr*)fcache->xprstate.expr;
  6. Oid target_type = InvalidOid;
  7. Oid source_type = InvalidOid;
  8. /* Initialize function lookup info */
  9. init_fcache<false>(func->funcid, func->inputcollid, fcache, econtext->ecxt_per_query_memory, true);
  10. bool has_refcursor = func_has_refcursor_args(func->funcid, &fcache->fcinfo_data);
  11. int cursor_return_number = fcache->fcinfo_data.refcursor_data.return_number;
  12. if (func->funcformat == COERCE_EXPLICIT_CAST || func->funcformat == COERCE_IMPLICIT_CAST) {
  13. target_type = func->funcresulttype;
  14. source_type = fcache->fcinfo_data.argTypes[0];
  15. HeapTuple proc_tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(func->funcid), 0, 0, 0);
  16. if (HeapTupleIsValid(proc_tuple)) {
  17. Form_pg_proc proc_struct = (Form_pg_proc)GETSTRUCT(proc_tuple);
  18. source_type = proc_struct->proargtypes.values[0];
  19. ReleaseSysCache(proc_tuple);
  20. }
  21. HeapTuple cast_tuple = SearchSysCache2(CASTSOURCETARGET, ObjectIdGetDatum(source_type),
  22. ObjectIdGetDatum(target_type));
  23. if (HeapTupleIsValid(cast_tuple)) {
  24. Relation cast_rel = heap_open(CastRelationId, AccessShareLock);
  25. int castowner_Anum = Anum_pg_cast_castowner;
  26. if (castowner_Anum <= (int)HeapTupleHeaderGetNatts(cast_tuple->t_data, cast_rel->rd_att)) {
  27. bool isnull = true;
  28. Datum datum = fastgetattr(cast_tuple, Anum_pg_cast_castowner, cast_rel->rd_att, &isnull);
  29. if (!isnull) {
  30. u_sess->exec_cxt.cast_owner = DatumGetObjectId(datum);
  31. } else {
  32. u_sess->exec_cxt.cast_owner = InvalidCastOwnerId;
  33. }
  34. }
  35. heap_close(cast_rel, AccessShareLock);
  36. ReleaseSysCache(cast_tuple);
  37. }
  38. }
  39. /*
  40. * We need to invoke ExecMakeFunctionResult if either the function itself
  41. * or any of its input expressions can return a set. Otherwise, invoke
  42. * ExecMakeFunctionResultNoSets. In either case, change the evalfunc
  43. * pointer to go directly there on subsequent uses.
  44. */
  45. if (fcache->func.fn_retset) {
  46. if (has_refcursor) {
  47. if (cursor_return_number > 0) {
  48. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<true, true, true>;
  49. return ExecMakeFunctionResult<true, true, true>(fcache, econtext, isNull, isDone);
  50. } else {
  51. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<true, false, true>;
  52. return ExecMakeFunctionResult<true, false, true>(fcache, econtext, isNull, isDone);
  53. }
  54. } else {
  55. if (cursor_return_number > 0) {
  56. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<false, true, true>;
  57. return ExecMakeFunctionResult<false, true, true>(fcache, econtext, isNull, isDone);
  58. } else {
  59. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<false, false, true>;
  60. return ExecMakeFunctionResult<false, false, true>(fcache, econtext, isNull, isDone);
  61. }
  62. }
  63. } else if (expression_returns_set((Node*)func->args)) {
  64. if (has_refcursor) {
  65. if (cursor_return_number > 0) {
  66. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<true, true, false>;
  67. return ExecMakeFunctionResult<true, true, false>(fcache, econtext, isNull, isDone);
  68. } else {
  69. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<true, false, false>;
  70. return ExecMakeFunctionResult<true, false, false>(fcache, econtext, isNull, isDone);
  71. }
  72. } else {
  73. if (cursor_return_number > 0) {
  74. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<false, true, false>;
  75. return ExecMakeFunctionResult<false, true, false>(fcache, econtext, isNull, isDone);
  76. } else {
  77. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResult<false, false, false>;
  78. return ExecMakeFunctionResult<false, false, false>(fcache, econtext, isNull, isDone);
  79. }
  80. }
  81. } else {
  82. if (has_refcursor) {
  83. if (cursor_return_number > 0) {
  84. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResultNoSets<true, true>;
  85. return ExecMakeFunctionResultNoSets<true, true>(fcache, econtext, isNull, isDone);
  86. } else {
  87. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResultNoSets<true, false>;
  88. return ExecMakeFunctionResultNoSets<true, false>(fcache, econtext, isNull, isDone);
  89. }
  90. } else {
  91. if (cursor_return_number > 0) {
  92. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResultNoSets<false, true>;
  93. return ExecMakeFunctionResultNoSets<false, true>(fcache, econtext, isNull, isDone);
  94. } else {
  95. fcache->xprstate.evalfunc = (ExprStateEvalFunc)ExecMakeFunctionResultNoSets<false, false>;
  96. return ExecMakeFunctionResultNoSets<false, false>(fcache, econtext, isNull, isDone);
  97. }
  98. }
  99. }
  100. }
执行过程

函数的执行过程较为简单,下面简要介绍:

  1. 首先初始化fcache,包括初始化参数,内存上下文管理等,并且在系统缓存里读取元组并更新相关信息。
  2. 根据表达式结点的信息,调用ExecMakeFunctionResult或ExecMakeFunctionResultNoSets函数。

函数执行过程可以用一个流程图来简单表示:

ExecEvalFunc

ExecEvalOper函数与ExecEvalFunc函数功能类似,这里不再展开叙述。

ExecMakeFunctionResultNoSets和ExecMakeFunctionResult

ExecMakeFunctionResultNoSets和ExecMakeFunctionResult函数是表达式计算中的核心函数,两个函数不同的地方在于一个用于集合,一个用于单值,单值可以看做是集合的特殊情况。由于ExecMakeFunctionResultNoSets和ExecMakeFunctionResult函数类似,为了不冗余,这里只介绍前者的作用。

  1. 遍历表达式参数,调用ExecEvalExpr宏函数获取参数值。
  2. 判断参数是否为空,若为空则返回空,否则调用FunctionCallInvoke宏函数计算表达式结果。

ExecTargetList

返回值

函数的返回值为bool类型的值,当返回true时代表表达式还未执行完,返回false时代表表达式全部执行完。

执行流程

ExecTargetList函数的作用是对传入参数tartgetlist里面的每个表达式计算并将结果存储到元组中。

主要的执行流程如下:

  1. 遍历targetlist列表中的每个表达式,并使用ExecEvalExpr宏函数计算每个表达式的结果,把结果储存在values数组中。
  2. 判断每个表达式是否返回集合,如果返回单值则另isDone为ExprEndResult;如果返回集合则判断表达式产生的此集合是否已经完备,若不完备则再次调用ExecEvalExpr宏函数直到完备为止。

小结

这几篇文章我简要解析了表达式计算的几个步骤,表达式计算和执行算子有着密不可分的联系,算子执行过程中需要表达式的值进行元组过滤,以减少内存开销。总的来说,执行算子离不开表达式,表达式服务于执行算子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值