subselect.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,118 行 · 第 1/3 页
C
1,118 行
* ininfo->sub_targetlist is filled with a list of Vars * representing the subselect outputs. */ exprs = convert_sublink_opers(sublink->lefthand, sublink->operOids, subselect->targetList, rtindex, &ininfo->sub_targetlist); return (Node *) make_ands_explicit(exprs);}/* * Replace correlation vars (uplevel vars) with Params. * * Uplevel aggregates are replaced, too. * * Note: it is critical that this runs immediately after SS_process_sublinks. * Since we do not recurse into the arguments of uplevel aggregates, they will * get copied to the appropriate subplan args list in the parent query with * uplevel vars not replaced by Params, but only adjusted in level (see * replace_outer_agg). That's exactly what we want for the vars of the parent * level --- but if an aggregate's argument contains any further-up variables, * they have to be replaced with Params in their turn. That will happen when * the parent level runs SS_replace_correlation_vars. Therefore it must do * so after expanding its sublinks to subplans. And we don't want any steps * in between, else those steps would never get applied to the aggregate * argument expressions, either in the parent or the child level. */Node *SS_replace_correlation_vars(Node *expr){ /* No setup needed for tree walk, so away we go */ return replace_correlation_vars_mutator(expr, NULL);}static Node *replace_correlation_vars_mutator(Node *node, void *context){ if (node == NULL) return NULL; if (IsA(node, Var)) { if (((Var *) node)->varlevelsup > 0) return (Node *) replace_outer_var((Var *) node); } if (IsA(node, Aggref)) { if (((Aggref *) node)->agglevelsup > 0) return (Node *) replace_outer_agg((Aggref *) node); } return expression_tree_mutator(node, replace_correlation_vars_mutator, context);}/* * Expand SubLinks to SubPlans in the given expression. * * The isQual argument tells whether or not this expression is a WHERE/HAVING * qualifier expression. If it is, any sublinks appearing at top level need * not distinguish FALSE from UNKNOWN return values. */Node *SS_process_sublinks(Node *expr, bool isQual){ /* The only context needed is the initial are-we-in-a-qual flag */ return process_sublinks_mutator(expr, &isQual);}static Node *process_sublinks_mutator(Node *node, bool *isTopQual){ bool locTopQual; if (node == NULL) return NULL; if (IsA(node, SubLink)) { SubLink *sublink = (SubLink *) node; List *lefthand; /* * First, recursively process the lefthand-side expressions, if * any. */ locTopQual = false; lefthand = (List *) process_sublinks_mutator((Node *) sublink->lefthand, &locTopQual); /* * Now build the SubPlan node and make the expr to return. */ return make_subplan(sublink, lefthand, *isTopQual); } /* * We should never see a SubPlan expression in the input (since this * is the very routine that creates 'em to begin with). We shouldn't * find ourselves invoked directly on a Query, either. */ Assert(!is_subplan(node)); Assert(!IsA(node, Query)); /* * If we recurse down through anything other than a List node, we are * definitely not at top qual level anymore. */ if (IsA(node, List)) locTopQual = *isTopQual; else locTopQual = false; 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. */voidSS_finalize_plan(Plan *plan, List *rtable){ Bitmapset *outer_params = NULL; Bitmapset *valid_params = NULL; int paramid; List *lst; /* * 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. */ paramid = 0; foreach(lst, PlannerParamList) { PlannerParamItem *pitem = (PlannerParamItem *) lfirst(lst); 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);}/* * 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; List *lst; 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)->indxqual, &context); /* * we need not look at indxqualorig, since it will have the * same param references as indxqual. */ 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: foreach(lst, ((Append *) plan)->appendplans) { context.paramids = bms_add_members(context.paramids, finalize_plan((Plan *) lfirst(lst), 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: finalize_primnode((Node *) ((Hash *) plan)->hashkeys, &context); break; 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);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?