* exec_save_simple_expr --- extract simple expression from CachedPlan */
| 8002 | * exec_save_simple_expr --- extract simple expression from CachedPlan |
| 8003 | */ |
| 8004 | static void |
| 8005 | exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan) |
| 8006 | { |
| 8007 | PlannedStmt *stmt; |
| 8008 | Plan *plan; |
| 8009 | Expr *tle_expr; |
| 8010 | |
| 8011 | /* |
| 8012 | * Given the checks that exec_simple_check_plan did, none of the Asserts |
| 8013 | * here should ever fail. |
| 8014 | */ |
| 8015 | |
| 8016 | /* Extract the single PlannedStmt */ |
| 8017 | Assert(list_length(cplan->stmt_list) == 1); |
| 8018 | stmt = linitial_node(PlannedStmt, cplan->stmt_list); |
| 8019 | Assert(stmt->commandType == CMD_SELECT); |
| 8020 | |
| 8021 | /* |
| 8022 | * Ordinarily, the plan node should be a simple Result. However, if |
| 8023 | * force_parallel_mode is on, the planner might've stuck a Gather node |
| 8024 | * atop that. The simplest way to deal with this is to look through the |
| 8025 | * Gather node. The Gather node's tlist would normally contain a Var |
| 8026 | * referencing the child node's output, but it could also be a Param, or |
| 8027 | * it could be a Const that setrefs.c copied as-is. |
| 8028 | */ |
| 8029 | plan = stmt->planTree; |
| 8030 | for (;;) |
| 8031 | { |
| 8032 | /* Extract the single tlist expression */ |
| 8033 | Assert(list_length(plan->targetlist) == 1); |
| 8034 | tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr; |
| 8035 | |
| 8036 | if (IsA(plan, Result)) |
| 8037 | { |
| 8038 | Assert(plan->lefttree == NULL && |
| 8039 | plan->righttree == NULL && |
| 8040 | plan->initPlan == NULL && |
| 8041 | plan->qual == NULL && |
| 8042 | ((Result *) plan)->resconstantqual == NULL); |
| 8043 | break; |
| 8044 | } |
| 8045 | else if (IsA(plan, Gather)) |
| 8046 | { |
| 8047 | Assert(plan->lefttree != NULL && |
| 8048 | plan->righttree == NULL && |
| 8049 | plan->initPlan == NULL && |
| 8050 | plan->qual == NULL); |
| 8051 | /* If setrefs.c copied up a Const, no need to look further */ |
| 8052 | if (IsA(tle_expr, Const)) |
| 8053 | break; |
| 8054 | /* Otherwise, it had better be a Param or an outer Var */ |
| 8055 | Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) && |
| 8056 | ((Var *) tle_expr)->varno == OUTER_VAR)); |
| 8057 | /* Descend to the child node */ |
| 8058 | plan = plan->lefttree; |
| 8059 | } |
| 8060 | else |
| 8061 | elog(ERROR, "unexpected plan node type: %d", |
no test coverage detected