📄 subselect.c
字号:
List *newargs = NIL; ListCell *l; foreach(l, ((BoolExpr *) node)->args) { Node *newarg; newarg = process_sublinks_mutator(lfirst(l), (void *) &locTopQual); if (or_clause(newarg)) newargs = list_concat(newargs, ((BoolExpr *) newarg)->args); else newargs = lappend(newargs, newarg); } return (Node *) make_orclause(newargs); } return expression_tree_mutator(node, process_sublinks_mutator, (void *) &locTopQual);}/* * SS_finalize_plan - do final sublink processing for a completed Plan. * * This recursively computes the extParam and allParam sets for every Plan * node in the given plan tree. It also attaches any generated InitPlans * to the top plan node. */voidSS_finalize_plan(Plan *plan, List *rtable){ Bitmapset *outer_params, *valid_params, *initExtParam, *initSetParam; Cost initplan_cost; int paramid; ListCell *l; /* * First, scan the param list to discover the sets of params that are * available from outer query levels and my own query level. We do this * once to save time in the per-plan recursion steps. */ outer_params = valid_params = NULL; paramid = 0; foreach(l, PlannerParamList) { PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l); if (pitem->abslevel < PlannerQueryLevel) { /* valid outer-level parameter */ outer_params = bms_add_member(outer_params, paramid); valid_params = bms_add_member(valid_params, paramid); } else if (pitem->abslevel == PlannerQueryLevel && IsA(pitem->item, Param)) { /* valid local parameter (i.e., a setParam of my child) */ valid_params = bms_add_member(valid_params, paramid); } paramid++; } /* * Now recurse through plan tree. */ (void) finalize_plan(plan, rtable, outer_params, valid_params); bms_free(outer_params); bms_free(valid_params); /* * Finally, attach any initPlans to the topmost plan node, and add their * extParams to the topmost node's, too. However, any setParams of the * initPlans should not be present in the topmost node's extParams, only * in its allParams. (As of PG 8.1, it's possible that some initPlans * have extParams that are setParams of other initPlans, so we have to * take care of this situation explicitly.) * * We also add the total_cost of each initPlan to the startup cost of the * top node. This is a conservative overestimate, since in fact each * initPlan might be executed later than plan startup, or even not at all. */ plan->initPlan = PlannerInitPlan; PlannerInitPlan = NIL; /* make sure they're not attached twice */ initExtParam = initSetParam = NULL; initplan_cost = 0; foreach(l, plan->initPlan) { SubPlan *initplan = (SubPlan *) lfirst(l); ListCell *l2; initExtParam = bms_add_members(initExtParam, initplan->plan->extParam); foreach(l2, initplan->setParam) { initSetParam = bms_add_member(initSetParam, lfirst_int(l2)); } initplan_cost += initplan->plan->total_cost; } /* allParam must include all these params */ plan->allParam = bms_add_members(plan->allParam, initExtParam); plan->allParam = bms_add_members(plan->allParam, initSetParam); /* but extParam shouldn't include any setParams */ initExtParam = bms_del_members(initExtParam, initSetParam); /* empty test ensures extParam is exactly NULL if it's empty */ if (!bms_is_empty(initExtParam)) plan->extParam = bms_join(plan->extParam, initExtParam); plan->startup_cost += initplan_cost; plan->total_cost += initplan_cost;}/* * Recursive processing of all nodes in the plan tree * * The return value is the computed allParam set for the given Plan node. * This is just an internal notational convenience. */static Bitmapset *finalize_plan(Plan *plan, List *rtable, Bitmapset *outer_params, Bitmapset *valid_params){ finalize_primnode_context context; if (plan == NULL) return NULL; context.paramids = NULL; /* initialize set to empty */ context.outer_params = outer_params; /* * When we call finalize_primnode, context.paramids sets are automatically * merged together. But when recursing to self, we have to do it the hard * way. We want the paramids set to include params in subplans as well as * at this level. */ /* Find params in targetlist and qual */ finalize_primnode((Node *) plan->targetlist, &context); finalize_primnode((Node *) plan->qual, &context); /* Check additional node-type-specific fields */ switch (nodeTag(plan)) { case T_Result: finalize_primnode(((Result *) plan)->resconstantqual, &context); break; case T_IndexScan: finalize_primnode((Node *) ((IndexScan *) plan)->indexqual, &context); /* * we need not look at indexqualorig, since it will have the same * param references as indexqual. */ break; case T_BitmapIndexScan: finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual, &context); /* * we need not look at indexqualorig, since it will have the same * param references as indexqual. */ break; case T_BitmapHeapScan: finalize_primnode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig, &context); break; case T_TidScan: finalize_primnode((Node *) ((TidScan *) plan)->tideval, &context); break; case T_SubqueryScan: /* * In a SubqueryScan, SS_finalize_plan has already been run on the * subplan by the inner invocation of subquery_planner, so there's * no need to do it again. Instead, just pull out the subplan's * extParams list, which represents the params it needs from my * level and higher levels. */ context.paramids = bms_add_members(context.paramids, ((SubqueryScan *) plan)->subplan->extParam); break; case T_FunctionScan: { RangeTblEntry *rte; rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid, rtable); Assert(rte->rtekind == RTE_FUNCTION); finalize_primnode(rte->funcexpr, &context); } break; case T_Append: { ListCell *l; foreach(l, ((Append *) plan)->appendplans) { context.paramids = bms_add_members(context.paramids, finalize_plan((Plan *) lfirst(l), rtable, outer_params, valid_params)); } } break; case T_BitmapAnd: { ListCell *l; foreach(l, ((BitmapAnd *) plan)->bitmapplans) { context.paramids = bms_add_members(context.paramids, finalize_plan((Plan *) lfirst(l), rtable, outer_params, valid_params)); } } break; case T_BitmapOr: { ListCell *l; foreach(l, ((BitmapOr *) plan)->bitmapplans) { context.paramids = bms_add_members(context.paramids, finalize_plan((Plan *) lfirst(l), rtable, outer_params, valid_params)); } } break; case T_NestLoop: finalize_primnode((Node *) ((Join *) plan)->joinqual, &context); break; case T_MergeJoin: finalize_primnode((Node *) ((Join *) plan)->joinqual, &context); finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses, &context); break; case T_HashJoin: finalize_primnode((Node *) ((Join *) plan)->joinqual, &context); finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses, &context); break; case T_Limit: finalize_primnode(((Limit *) plan)->limitOffset, &context); finalize_primnode(((Limit *) plan)->limitCount, &context); break; case T_Hash: case T_Agg: case T_SeqScan: case T_Material: case T_Sort: case T_Unique: case T_SetOp: case T_Group: break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(plan)); } /* Process left and right child plans, if any */ context.paramids = bms_add_members(context.paramids, finalize_plan(plan->lefttree, rtable, outer_params, valid_params)); context.paramids = bms_add_members(context.paramids, finalize_plan(plan->righttree, rtable, outer_params, valid_params)); /* Now we have all the paramids */ if (!bms_is_subset(context.paramids, valid_params)) elog(ERROR, "plan should not reference subplan's variable"); plan->extParam = bms_intersect(context.paramids, outer_params); plan->allParam = context.paramids; /* * For speed at execution time, make sure extParam/allParam are actually * NULL if they are empty sets. */ if (bms_is_empty(plan->extParam)) { bms_free(plan->extParam); plan->extParam = NULL; } if (bms_is_empty(plan->allParam)) { bms_free(plan->allParam); plan->allParam = NULL; } return plan->allParam;}/* * finalize_primnode: add IDs of all PARAM_EXEC params appearing in the given * expression tree to the result set. */static boolfinalize_primnode(Node *node, finalize_primnode_context *context){ if (node == NULL) return false; if (IsA(node, Param)) { if (((Param *) node)->paramkind == PARAM_EXEC) { int paramid = (int) ((Param *) node)->paramid; context->paramids = bms_add_member(context->paramids, paramid); } return false; /* no more to do here */ } if (is_subplan(node)) { SubPlan *subplan = (SubPlan *) node; /* Add outer-level params needed by the subplan to paramids */ context->paramids = bms_join(context->paramids, bms_intersect(subplan->plan->extParam, context->outer_params)); /* fall through to recurse into subplan args */ } return expression_tree_walker(node, finalize_primnode, (void *) context);}/* * SS_make_initplan_from_plan - given a plan tree, make it an InitPlan * * The plan is expected to return a scalar value of the indicated type. * We build an EXPR_SUBLINK SubPlan node and put it into the initplan * list for the current query level. A Param that represents the initplan's * output is returned. * * We assume the plan hasn't been put through SS_finalize_plan. */Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, Oid resulttype, int32 resulttypmod){ List *saved_initplan = PlannerInitPlan; SubPlan *node; Param *prm; /* * Set up for a new level of subquery. This is just to keep * SS_finalize_plan from becoming confused. */ PlannerQueryLevel++; PlannerInitPlan = NIL; /* * Build extParam/allParam sets for plan nodes. */ SS_finalize_plan(plan, root->parse->rtable); /* Return to outer subquery context */ PlannerQueryLevel--; PlannerInitPlan = saved_initplan; /* * Create a SubPlan node and add it to the outer list of InitPlans. */ node = makeNode(SubPlan); node->subLinkType = EXPR_SUBLINK; node->plan = plan; node->plan_id = PlannerPlanId++; /* Assign unique ID to this SubPlan */ node->rtable = root->parse->rtable; PlannerInitPlan = lappend(PlannerInitPlan, node); /* * The node can't have any inputs (since it's an initplan), so the * parParam and args lists remain empty. */ /* * Make a Param that will be the subplan's output. */ prm = generate_new_param(resulttype, resulttypmod); node->setParam = list_make1_int(prm->paramid); return prm;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -