setrefs.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,627 行 · 第 1/4 页
C
1,627 行
splan->resconstantqual = fix_scan_expr(glob, splan->resconstantqual, rtoffset); } break; case T_Append: { Append *splan = (Append *) plan; /* * Append, like Sort et al, doesn't actually evaluate its * targetlist or check quals. */ set_dummy_tlist_references(plan, rtoffset); Assert(splan->plan.qual == NIL); foreach(l, splan->appendplans) { lfirst(l) = set_plan_refs(glob, (Plan *) lfirst(l), rtoffset); } } break; case T_BitmapAnd: { BitmapAnd *splan = (BitmapAnd *) plan; /* BitmapAnd works like Append, but has no tlist */ Assert(splan->plan.targetlist == NIL); Assert(splan->plan.qual == NIL); foreach(l, splan->bitmapplans) { lfirst(l) = set_plan_refs(glob, (Plan *) lfirst(l), rtoffset); } } break; case T_BitmapOr: { BitmapOr *splan = (BitmapOr *) plan; /* BitmapOr works like Append, but has no tlist */ Assert(splan->plan.targetlist == NIL); Assert(splan->plan.qual == NIL); foreach(l, splan->bitmapplans) { lfirst(l) = set_plan_refs(glob, (Plan *) lfirst(l), rtoffset); } } break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(plan)); break; } /* * Now recurse into child plans, if any * * NOTE: it is essential that we recurse into child plans AFTER we set * subplan references in this plan's tlist and quals. If we did the * reference-adjustments bottom-up, then we would fail to match this * plan's var nodes against the already-modified nodes of the children. */ plan->lefttree = set_plan_refs(glob, plan->lefttree, rtoffset); plan->righttree = set_plan_refs(glob, plan->righttree, rtoffset); return plan;}/* * set_subqueryscan_references * Do set_plan_references processing on a SubqueryScan * * We try to strip out the SubqueryScan entirely; if we can't, we have * to do the normal processing on it. */static Plan *set_subqueryscan_references(PlannerGlobal *glob, SubqueryScan *plan, int rtoffset){ Plan *result; /* First, recursively process the subplan */ plan->subplan = set_plan_references(glob, plan->subplan, plan->subrtable); /* subrtable is no longer needed in the plan tree */ plan->subrtable = NIL; if (trivial_subqueryscan(plan)) { /* * We can omit the SubqueryScan node and just pull up the subplan. */ ListCell *lp, *lc; result = plan->subplan; /* We have to be sure we don't lose any initplans */ result->initPlan = list_concat(plan->scan.plan.initPlan, result->initPlan); /* * We also have to transfer the SubqueryScan's result-column names * into the subplan, else columns sent to client will be improperly * labeled if this is the topmost plan level. Copy the "source * column" information too. */ forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist) { TargetEntry *ptle = (TargetEntry *) lfirst(lp); TargetEntry *ctle = (TargetEntry *) lfirst(lc); ctle->resname = ptle->resname; ctle->resorigtbl = ptle->resorigtbl; ctle->resorigcol = ptle->resorigcol; } } else { /* * Keep the SubqueryScan node. We have to do the processing that * set_plan_references would otherwise have done on it. Notice we do * not do set_upper_references() here, because a SubqueryScan will * always have been created with correct references to its subplan's * outputs to begin with. */ plan->scan.scanrelid += rtoffset; plan->scan.plan.targetlist = fix_scan_list(glob, plan->scan.plan.targetlist, rtoffset); plan->scan.plan.qual = fix_scan_list(glob, plan->scan.plan.qual, rtoffset); result = (Plan *) plan; } return result;}/* * trivial_subqueryscan * Detect whether a SubqueryScan can be deleted from the plan tree. * * We can delete it if it has no qual to check and the targetlist just * regurgitates the output of the child plan. */static booltrivial_subqueryscan(SubqueryScan *plan){ int attrno; ListCell *lp, *lc; if (plan->scan.plan.qual != NIL) return false; if (list_length(plan->scan.plan.targetlist) != list_length(plan->subplan->targetlist)) return false; /* tlists not same length */ attrno = 1; forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist) { TargetEntry *ptle = (TargetEntry *) lfirst(lp); TargetEntry *ctle = (TargetEntry *) lfirst(lc); if (ptle->resjunk != ctle->resjunk) return false; /* tlist doesn't match junk status */ /* * We accept either a Var referencing the corresponding element of the * subplan tlist, or a Const equaling the subplan element. See * generate_setop_tlist() for motivation. */ if (ptle->expr && IsA(ptle->expr, Var)) { Var *var = (Var *) ptle->expr; Assert(var->varno == plan->scan.scanrelid); Assert(var->varlevelsup == 0); if (var->varattno != attrno) return false; /* out of order */ } else if (ptle->expr && IsA(ptle->expr, Const)) { if (!equal(ptle->expr, ctle->expr)) return false; } else return false; attrno++; } return true;}/* * copyVar * Copy a Var node. * * fix_scan_expr and friends do this enough times that it's worth having * a bespoke routine instead of using the generic copyObject() function. */static inline Var *copyVar(Var *var){ Var *newvar = (Var *) palloc(sizeof(Var)); *newvar = *var; return newvar;}/* * fix_scan_expr * Do set_plan_references processing on a scan-level expression * * This consists of incrementing all Vars' varnos by rtoffset, * looking up operator opcode info for OpExpr and related nodes, * and adding OIDs from regclass Const nodes into glob->relationOids. */static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset){ fix_scan_expr_context context; context.glob = glob; context.rtoffset = rtoffset; if (rtoffset != 0) { return fix_scan_expr_mutator(node, &context); } else { /* * If rtoffset == 0, we don't need to change any Vars, which makes * it OK to just scribble on the input node tree instead of copying * (since the only change, filling in any unset opfuncid fields, * is harmless). This saves just enough cycles to be noticeable on * trivial queries. */ (void) fix_scan_expr_walker(node, &context); return node; }}static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context){ if (node == NULL) return NULL; if (IsA(node, Var)) { Var *var = copyVar((Var *) node); Assert(var->varlevelsup == 0); /* * We should not see any Vars marked INNER, but in a nestloop inner * scan there could be OUTER Vars. Leave them alone. */ Assert(var->varno != INNER); if (var->varno > 0 && var->varno != OUTER) var->varno += context->rtoffset; if (var->varnoold > 0) var->varnoold += context->rtoffset; return (Node *) var; } if (IsA(node, CurrentOfExpr)) { CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node); Assert(cexpr->cvarno != INNER); Assert(cexpr->cvarno != OUTER); cexpr->cvarno += context->rtoffset; return (Node *) cexpr; } /* * Since we update opcode info in-place, this part could possibly scribble * on the planner's input data structures, but it's OK. */ if (IsA(node, OpExpr)) set_opfuncid((OpExpr *) node); else if (IsA(node, DistinctExpr)) set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ else if (IsA(node, NullIfExpr)) set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ else if (IsA(node, ScalarArrayOpExpr)) set_sa_opfuncid((ScalarArrayOpExpr *) node); else if (IsA(node, Const)) { Const *con = (Const *) node; /* Check for regclass reference */ if (ISREGCLASSCONST(con)) context->glob->relationOids = lappend_oid(context->glob->relationOids, DatumGetObjectId(con->constvalue)); /* Fall through to let expression_tree_mutator copy it */ } return expression_tree_mutator(node, fix_scan_expr_mutator, (void *) context);}static boolfix_scan_expr_walker(Node *node, fix_scan_expr_context *context){ if (node == NULL) return false; if (IsA(node, OpExpr)) set_opfuncid((OpExpr *) node); else if (IsA(node, DistinctExpr)) set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ else if (IsA(node, NullIfExpr)) set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ else if (IsA(node, ScalarArrayOpExpr)) set_sa_opfuncid((ScalarArrayOpExpr *) node); else if (IsA(node, Const)) { Const *con = (Const *) node; /* Check for regclass reference */ if (ISREGCLASSCONST(con)) context->glob->relationOids = lappend_oid(context->glob->relationOids, DatumGetObjectId(con->constvalue)); return false; } return expression_tree_walker(node, fix_scan_expr_walker, (void *) context);}/* * set_join_references * Modify the target list and quals of a join node to reference its * subplans, by setting the varnos to OUTER or INNER and setting attno * values to the result domain number of either the corresponding outer * or inner join tuple item. Also perform opcode lookup for these * expressions. and add regclass OIDs to glob->relationOids. * * In the case of a nestloop with inner indexscan, we will also need to * apply the same transformation to any outer vars appearing in the * quals of the child indexscan. set_inner_join_references does that. */static voidset_join_references(PlannerGlobal *glob, Join *join, int rtoffset){ Plan *outer_plan = join->plan.lefttree; Plan *inner_plan = join->plan.righttree; indexed_tlist *outer_itlist; indexed_tlist *inner_itlist; outer_itlist = build_tlist_index(outer_plan->targetlist); inner_itlist = build_tlist_index(inner_plan->targetlist); /* All join plans have tlist, qual, and joinqual */ join->plan.targetlist = fix_join_expr(glob, join->plan.targetlist, outer_itlist, inner_itlist, (Index) 0, rtoffset); join->plan.qual = fix_join_expr(glob, join->plan.qual, outer_itlist, inner_itlist, (Index) 0, rtoffset); join->joinqual = fix_join_expr(glob, join->joinqual, outer_itlist, inner_itlist, (Index) 0, rtoffset); /* Now do join-type-specific stuff */ if (IsA(join, NestLoop)) { /* This processing is split out to handle possible recursion */ set_inner_join_references(glob, inner_plan, outer_itlist); } else if (IsA(join, MergeJoin)) { MergeJoin *mj = (MergeJoin *) join; mj->mergeclauses = fix_join_expr(glob, mj->mergeclauses, outer_itlist, inner_itlist, (Index) 0, rtoffset); } else if (IsA(join, HashJoin)) { HashJoin *hj = (HashJoin *) join; hj->hashclauses = fix_join_expr(glob, hj->hashclauses, outer_itlist, inner_itlist, (Index) 0,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?