📄 createplan.c
字号:
* in the inner relation. There will never be more than one index * used in the inner scan path, so we need only consider the first * set of qualifications in indxqual. * * But there may be more than one clause in this "first set" in the * case of multi-column indices. - vadim 03/18/97 */ List *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual); List *inner_qual; bool found = false; foreach(inner_qual, inner_indxqual) { if (!qual_clause_p((Node *) lfirst(inner_qual))) { found = true; break; } } /* * If we have in fact found a join index qualification, remove * these index clauses from the nestloop's join clauses and reset * the inner(index) scan's qualification so that the var nodes * refer to the proper outer join relation attributes. * * XXX Re-moving index clauses doesn't work properly: 1. * fix_indxqual_references may change varattno-s in * inner_indxqual; 2. clauses may be commuted I havn't time to fix * it at the moment. - vadim 04/24/97 */ if (found) { List *new_inner_qual = NIL; clauses = set_difference(clauses, inner_indxqual); /* XXX */ new_inner_qual = index_outerjoin_references(inner_indxqual, outer_node->targetlist, ((Scan *) inner_node)->scanrelid); ((IndexScan *) inner_node)->indxqual = lcons(new_inner_qual, NIL); } } else if (IsA_Join(inner_node)) { inner_node = (Plan *) make_noname(inner_tlist, NIL, NULL, inner_node, NONAME_MATERIAL); } join_node = make_nestloop(tlist, join_references(clauses, outer_tlist, inner_tlist), outer_node, inner_node); join_node->join.cost = best_path->path.path_cost; return join_node;}static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist, List *clauses, Plan *outer_node, List *outer_tlist, Plan *inner_node, List *inner_tlist){ List *qpqual, *mergeclauses; MergeJoin *join_node; /* * Separate the mergeclauses from the other join qualification clauses * and set those clauses to contain references to lower attributes. */ qpqual = join_references(set_difference(clauses, best_path->path_mergeclauses), outer_tlist, inner_tlist); /* * Now set the references in the mergeclauses and rearrange them so * that the outer variable is always on the left. */ mergeclauses = switch_outer(join_references(best_path->path_mergeclauses, outer_tlist, inner_tlist)); /* * Create explicit sort paths for the outer and inner join paths if * necessary. The sort cost was already accounted for in the path. */ if (best_path->outersortkeys) { Oid *outer_order = generate_merge_input_sortorder( best_path->outersortkeys, best_path->jpath.path.pathorder->ord.merge); outer_node = (Plan *) make_noname(outer_tlist, best_path->outersortkeys, outer_order, outer_node, NONAME_SORT); } if (best_path->innersortkeys) { Oid *inner_order = generate_merge_input_sortorder( best_path->innersortkeys, best_path->jpath.path.pathorder->ord.merge); inner_node = (Plan *) make_noname(inner_tlist, best_path->innersortkeys, inner_order, inner_node, NONAME_SORT); } join_node = make_mergejoin(tlist, qpqual, mergeclauses, inner_node, outer_node); join_node->join.cost = best_path->jpath.path.path_cost; return join_node;}/* * create_hashjoin_node-- XXX HASH * * Returns a new hashjoin node. * * XXX hash join ops are totally bogus -- how the hell do we choose * these?? at runtime? what about a hash index? */static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist, List *clauses, Plan *outer_node, List *outer_tlist, Plan *inner_node, List *inner_tlist){ List *qpqual; List *hashclauses; HashJoin *join_node; Hash *hash_node; Var *innerhashkey; /* * Separate the hashclauses from the other join qualification clauses * and set those clauses to contain references to lower attributes. */ qpqual = join_references(set_difference(clauses, best_path->path_hashclauses), outer_tlist, inner_tlist); /* * Now set the references in the hashclauses and rearrange them so * that the outer variable is always on the left. */ hashclauses = switch_outer(join_references(best_path->path_hashclauses, outer_tlist, inner_tlist)); innerhashkey = get_rightop(lfirst(hashclauses)); hash_node = make_hash(inner_tlist, innerhashkey, inner_node); join_node = make_hashjoin(tlist, qpqual, hashclauses, outer_node, (Plan *) hash_node); join_node->join.cost = best_path->jpath.path.path_cost; return join_node;}/***************************************************************************** * * SUPPORTING ROUTINES * *****************************************************************************//* * fix_indxqual_references * Adjust a qual clause to refer to an index instead of the original relation. * * Returns a modified copy of the given clause --- the original is not changed. */static Node *fix_indxqual_references(Node *clause, Path *index_path){ if (clause == NULL) return NULL; else if (IsA(clause, Var)) { if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno) { Node *newclause; int pos = 0; int varatt = ((Var *) clause)->varattno; int *indexkeys = ((IndexPath *) index_path)->indexkeys; if (indexkeys) { while (indexkeys[pos] != 0) { if (varatt == indexkeys[pos]) break; pos++; } } newclause = copyObject(clause); ((Var *) newclause)->varattno = pos + 1; return newclause; } /* The Var is not part of the indexed relation, leave it alone */ return copyObject(clause); } else if (single_node(clause)) return copyObject(clause); else if (is_opclause(clause) && is_funcclause((Node *) get_leftop((Expr *) clause)) && ((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex) { /* * This looks pretty seriously wrong to me, but I'm not sure what * it's supposed to be doing ... tgl 5/99 */ Var *newvar = makeVar((Index) lfirsti(index_path->parent->relids), 1, /* func indices have one key */ ((Func *) ((Expr *) clause)->oper)->functype, -1, 0, (Index) lfirsti(index_path->parent->relids), 0); return ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper, newvar, get_rightop((Expr *) clause))); } else if (IsA(clause, Expr)) { Expr *expr = (Expr *) clause; List *new_subclauses = NIL; List *i; foreach(i, expr->args) { Node *subclause = lfirst(i); new_subclauses = lappend(new_subclauses, fix_indxqual_references(subclause, index_path)); } return (Node *) make_clause(expr->opType, expr->oper, new_subclauses); } else if (IsA(clause, List)) { List *new_subclauses = NIL; List *i; foreach(i, (List *) clause) { Node *subclause = lfirst(i); new_subclauses = lappend(new_subclauses, fix_indxqual_references(subclause, index_path)); } return (Node *) new_subclauses; } else if (IsA(clause, ArrayRef)) { ArrayRef *oldnode = (ArrayRef *) clause; ArrayRef *newnode = makeNode(ArrayRef); newnode->refattrlength = oldnode->refattrlength; newnode->refelemlength = oldnode->refelemlength; newnode->refelemtype = oldnode->refelemtype; newnode->refelembyval = oldnode->refelembyval; newnode->refupperindexpr = (List *) fix_indxqual_references((Node *) oldnode->refupperindexpr, index_path); newnode->reflowerindexpr = (List *) fix_indxqual_references((Node *) oldnode->reflowerindexpr, index_path); newnode->refexpr = fix_indxqual_references(oldnode->refexpr, index_path); newnode->refassgnexpr = fix_indxqual_references(oldnode->refassgnexpr, index_path); return (Node *) newnode; } else if (IsA(clause, CaseExpr)) { CaseExpr *oldnode = (CaseExpr *) clause; CaseExpr *newnode = makeNode(CaseExpr); newnode->casetype = oldnode->casetype; newnode->arg = oldnode->arg; /* XXX should always be null * anyway ... */ newnode->args = (List *) fix_indxqual_references((Node *) oldnode->args, index_path); newnode->defresult = fix_indxqual_references(oldnode->defresult, index_path); return (Node *) newnode; } else if (IsA(clause, CaseWhen)) { CaseWhen *oldnode = (CaseWhen *) clause; CaseWhen *newnode = makeNode(CaseWhen); newnode->expr = fix_indxqual_references(oldnode->expr, index_path); newnode->result = fix_indxqual_references(oldnode->result, index_path); return (Node *) newnode; } else { elog(ERROR, "fix_indxqual_references: Cannot handle node type %d", nodeTag(clause)); return NULL; }}/* * switch_outer * Given a list of merge clauses, rearranges the elements within the * clauses so the outer join variable is on the left and the inner is on * the right. The original list is not touched; a modified list * is returned. */static List *switch_outer(List *clauses){ List *t_list = NIL; Expr *temp; List *i; Expr *clause; Node *op; foreach(i, clauses) { clause = lfirst(i); Assert(is_opclause((Node *) clause)); op = (Node *) get_rightop(clause); Assert(op != (Node *) NULL); if (IsA(op, ArrayRef)) op = ((ArrayRef *) op)->refexpr; Assert(IsA(op, Var)); if (var_is_outer((Var *) op)) { /* * Duplicate just enough of the structure to allow commuting * the clause without changing the original list. Could use * copyObject, but a complete deep copy is overkill. */ temp = make_clause(clause->opType, clause->oper, lcons(get_leftop(clause), lcons(get_rightop(clause), NIL))); /* Commute it --- note this modifies the temp node in-place. */ CommuteClause((Node *) temp); t_list = lappend(t_list, temp); } else t_list = lappend(t_list, clause); } return t_list;}/* * generate_merge_input_sortorder * * Generate the list of sort ops needed to sort one of the input paths for * a merge. We may have to use either left or right sortop for each item, * since the original mergejoin clause may or may not have been commuted * (compare switch_outer above). * * XXX This is largely a crock. It works only because group_clauses_by_order * only groups together mergejoin clauses that have identical MergeOrder info, * which means we can safely use a single MergeOrder input to deal with all * the data. There should be a more general data structure that allows coping * with groups of mergejoin clauses that have different join operators. */static Oid *generate_merge_input_sortorder(List *pathkeys, MergeOrder *mergeorder){ int listlength = length(pathkeys); Oid *result = (Oid *) palloc(sizeof(Oid) * (listlength + 1)); Oid *nextsortop = result; List *p; foreach(p, pathkeys) { Var *pkey = (Var *) lfirst((List *) lfirst(p)); Assert(IsA(pkey, Var)); if (pkey->vartype == mergeorder->left_type) *nextsortop++ = mergeorder->left_operator; else if (pkey->vartype == mergeorder->right_type) *nextsortop++ = mergeorder->right_operator; else elog(ERROR, "generate_merge_input_sortorder: can't handle data type %d", pkey->vartype);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -