📄 prepjointree.c
字号:
reduce_outer_joins_pass2(j->rarg, right_state, root, pass_nonnullable); } bms_free(local_nonnullable); } } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode));}/* * find_nonnullable_rels * Determine which base rels are forced nonnullable by given quals * * We don't use expression_tree_walker here because we don't want to * descend through very many kinds of nodes; only the ones we can be sure * are strict. We can descend through the top level of implicit AND'ing, * but not through any explicit ANDs (or ORs) below that, since those are not * strict constructs. The List case handles the top-level implicit AND list * as well as lists of arguments to strict operators/functions. */static Relidsfind_nonnullable_rels(Node *node, bool top_level){ Relids result = NULL; if (node == NULL) return NULL; if (IsA(node, Var)) { Var *var = (Var *) node; if (var->varlevelsup == 0) result = bms_make_singleton(var->varno); } else if (IsA(node, List)) { ListCell *l; foreach(l, (List *) node) { result = bms_join(result, find_nonnullable_rels(lfirst(l), top_level)); } } else if (IsA(node, FuncExpr)) { FuncExpr *expr = (FuncExpr *) node; if (func_strict(expr->funcid)) result = find_nonnullable_rels((Node *) expr->args, false); } else if (IsA(node, OpExpr)) { OpExpr *expr = (OpExpr *) node; if (op_strict(expr->opno)) result = find_nonnullable_rels((Node *) expr->args, false); } else if (IsA(node, BoolExpr)) { BoolExpr *expr = (BoolExpr *) node; /* NOT is strict, others are not */ if (expr->boolop == NOT_EXPR) result = find_nonnullable_rels((Node *) expr->args, false); } else if (IsA(node, RelabelType)) { RelabelType *expr = (RelabelType *) node; result = find_nonnullable_rels((Node *) expr->arg, top_level); } else if (IsA(node, ConvertRowtypeExpr)) { /* not clear this is useful, but it can't hurt */ ConvertRowtypeExpr *expr = (ConvertRowtypeExpr *) node; result = find_nonnullable_rels((Node *) expr->arg, top_level); } else if (IsA(node, NullTest)) { NullTest *expr = (NullTest *) node; /* * IS NOT NULL can be considered strict, but only at top level; else * we might have something like NOT (x IS NOT NULL). */ if (top_level && expr->nulltesttype == IS_NOT_NULL) result = find_nonnullable_rels((Node *) expr->arg, false); } else if (IsA(node, BooleanTest)) { BooleanTest *expr = (BooleanTest *) node; /* * Appropriate boolean tests are strict at top level. */ if (top_level && (expr->booltesttype == IS_TRUE || expr->booltesttype == IS_FALSE || expr->booltesttype == IS_NOT_UNKNOWN)) result = find_nonnullable_rels((Node *) expr->arg, false); } return result;}/* * simplify_jointree * Attempt to simplify a query's jointree. * * If we succeed in pulling up a subquery then we might form a jointree * in which a FromExpr is a direct child of another FromExpr. In that * case we can consider collapsing the two FromExprs into one. This is * an optional conversion, since the planner will work correctly either * way. But we may find a better plan (at the cost of more planning time) * if we merge the two nodes, creating a single join search space out of * two. To allow the user to trade off planning time against plan quality, * we provide a control parameter from_collapse_limit that limits the size * of the join search space that can be created this way. * * We also consider flattening explicit inner JOINs into FromExprs (which * will in turn allow them to be merged into parent FromExprs). The tradeoffs * here are the same as for flattening FromExprs, but we use a different * control parameter so that the user can use explicit JOINs to control the * join order even when they are inner JOINs. * * NOTE: don't try to do this in the same jointree scan that does subquery * pullup! Since we're changing the jointree structure here, that wouldn't * work reliably --- see comments for pull_up_subqueries(). */Node *simplify_jointree(PlannerInfo *root, Node *jtnode){ if (jtnode == NULL) return NULL; if (IsA(jtnode, RangeTblRef)) { /* nothing to do here... */ } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; List *newlist = NIL; int children_remaining; ListCell *l; children_remaining = list_length(f->fromlist); foreach(l, f->fromlist) { Node *child = (Node *) lfirst(l); children_remaining--; /* Recursively simplify this child... */ child = simplify_jointree(root, child); /* Now, is it a FromExpr? */ if (child && IsA(child, FromExpr)) { /* * Yes, so do we want to merge it into parent? Always do so * if child has just one element (since that doesn't make the * parent's list any longer). Otherwise merge if the * resulting join list would be no longer than * from_collapse_limit. */ FromExpr *subf = (FromExpr *) child; int childlen = list_length(subf->fromlist); int myothers = list_length(newlist) + children_remaining; if (childlen <= 1 || (childlen + myothers) <= from_collapse_limit) { newlist = list_concat(newlist, subf->fromlist); /* * By now, the quals have been converted to implicit-AND * lists, so we just need to join the lists. NOTE: we put * the pulled-up quals first. */ f->quals = (Node *) list_concat((List *) subf->quals, (List *) f->quals); } else newlist = lappend(newlist, child); } else newlist = lappend(newlist, child); } f->fromlist = newlist; } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; /* Recursively simplify the children... */ j->larg = simplify_jointree(root, j->larg); j->rarg = simplify_jointree(root, j->rarg); /* * If it is an outer join, we must not flatten it. An inner join is * semantically equivalent to a FromExpr; we convert it to one, * allowing it to be flattened into its parent, if the resulting * FromExpr would have no more than join_collapse_limit members. */ if (j->jointype == JOIN_INNER && join_collapse_limit > 1) { int leftlen, rightlen; if (j->larg && IsA(j->larg, FromExpr)) leftlen = list_length(((FromExpr *) j->larg)->fromlist); else leftlen = 1; if (j->rarg && IsA(j->rarg, FromExpr)) rightlen = list_length(((FromExpr *) j->rarg)->fromlist); else rightlen = 1; if ((leftlen + rightlen) <= join_collapse_limit) { FromExpr *f = makeNode(FromExpr); f->fromlist = NIL; f->quals = NULL; if (j->larg && IsA(j->larg, FromExpr)) { FromExpr *subf = (FromExpr *) j->larg; f->fromlist = subf->fromlist; f->quals = subf->quals; } else f->fromlist = list_make1(j->larg); if (j->rarg && IsA(j->rarg, FromExpr)) { FromExpr *subf = (FromExpr *) j->rarg; f->fromlist = list_concat(f->fromlist, subf->fromlist); f->quals = (Node *) list_concat((List *) f->quals, (List *) subf->quals); } else f->fromlist = lappend(f->fromlist, j->rarg); /* pulled-up quals first */ f->quals = (Node *) list_concat((List *) f->quals, (List *) j->quals); return (Node *) f; } } } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); return jtnode;}/* * fix_in_clause_relids: update RT-index sets of InClauseInfo nodes * * When we pull up a subquery, any InClauseInfo references to the subquery's * RT index have to be replaced by the set of substituted relids. * * We assume we may modify the InClauseInfo nodes in-place. */static voidfix_in_clause_relids(List *in_info_list, int varno, Relids subrelids){ ListCell *l; foreach(l, in_info_list) { InClauseInfo *ininfo = (InClauseInfo *) lfirst(l); if (bms_is_member(varno, ininfo->lefthand)) { ininfo->lefthand = bms_del_member(ininfo->lefthand, varno); ininfo->lefthand = bms_add_members(ininfo->lefthand, subrelids); } if (bms_is_member(varno, ininfo->righthand)) { ininfo->righthand = bms_del_member(ininfo->righthand, varno); ininfo->righthand = bms_add_members(ininfo->righthand, subrelids); } }}/* * get_relids_in_jointree: get set of base RT indexes present in a jointree */Relidsget_relids_in_jointree(Node *jtnode){ Relids result = NULL; if (jtnode == NULL) return result; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; result = bms_make_singleton(varno); } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; foreach(l, f->fromlist) { result = bms_join(result, get_relids_in_jointree(lfirst(l))); } } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; /* join's own RT index is not wanted in result */ result = get_relids_in_jointree(j->larg); result = bms_join(result, get_relids_in_jointree(j->rarg)); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); return result;}/* * get_relids_for_join: get set of base RT indexes making up a join * * NB: this will not work reliably after simplify_jointree() is run, * since that may eliminate join nodes from the jointree. */Relidsget_relids_for_join(PlannerInfo *root, int joinrelid){ Node *jtnode; jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree, joinrelid); if (!jtnode) elog(ERROR, "could not find join node %d", joinrelid); return get_relids_in_jointree(jtnode);}/* * find_jointree_node_for_rel: locate jointree node for a base or join RT index * * Returns NULL if not found */static Node *find_jointree_node_for_rel(Node *jtnode, int relid){ if (jtnode == NULL) return NULL; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; if (relid == varno) return jtnode; } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; foreach(l, f->fromlist) { jtnode = find_jointree_node_for_rel(lfirst(l), relid); if (jtnode) return jtnode; } } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; if (relid == j->rtindex) return jtnode; jtnode = find_jointree_node_for_rel(j->larg, relid); if (jtnode) return jtnode; jtnode = find_jointree_node_for_rel(j->rarg, relid); if (jtnode) return jtnode; } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -