📄 planner.c
字号:
extravars = nconc(extravars, pull_var_clause(parse->havingQual)); foreach(gl, extravars) { Var *v = (Var *) lfirst(gl); if (tlist_member(v, sub_tlist) == NULL) { /* * Make sure sub_tlist element is a fresh object not shared * with any other structure; not sure if anything will break * if it is shared, but better to be safe... */ sub_tlist = lappend(sub_tlist, create_tl_element((Var *) copyObject(v), next_resno)); next_resno++; } } return sub_tlist;}static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup, List *groupClause, AttrNumber *grpColIdx, Plan *subplan){ List *sort_tlist; List *sl; Sort *sortplan; Group *grpplan; int numCols = length(groupClause); /* * Make the targetlist for the Sort node; it always just references * each of the corresponding target items of the subplan. We need to * ensure that simple Vars in the subplan's target list are * recognizable by replace_vars_with_subplan_refs when it's applied to * the Sort/Group target list, so copy up their varnoold/varoattno. */ sort_tlist = NIL; foreach(sl, subplan->targetlist) { TargetEntry *te = (TargetEntry *) lfirst(sl); Resdom *resdom = te->resdom; Var *newvar; if (IsA(te->expr, Var)) { Var *subvar = (Var *) te->expr; newvar = makeVar(1, resdom->resno, resdom->restype, resdom->restypmod, 0, subvar->varnoold, subvar->varoattno); } else { newvar = makeVar(1, resdom->resno, resdom->restype, resdom->restypmod, 0, -1, resdom->resno); } sort_tlist = lappend(sort_tlist, makeTargetEntry((Resdom *) copyObject(resdom), (Node *) newvar)); } /* * Make the Sort node */ sortplan = make_sort(sort_tlist, _NONAME_RELATION_ID_, subplan, numCols); sortplan->plan.cost = subplan->cost; /* XXX assume no cost */ /* * If the caller gave us a target list, use it after fixing the * variables. If not, we need the same sort of "repeater" tlist as for * the Sort node. */ if (group_tlist) { group_tlist = copyObject(group_tlist); /* necessary?? */ replace_tlist_with_subplan_refs(group_tlist, (Index) 0, subplan->targetlist); } else group_tlist = copyObject(sort_tlist); /* * Make the Group node */ grpplan = make_group(group_tlist, tuplePerGroup, numCols, grpColIdx, sortplan); return (Plan *) grpplan;}/* * make_sortplan * Returns a sortplan which is basically a SORT node attached to the * top of the plan returned from the planner. It also adds the * cost of sorting into the plan. * * sortkeys: ( resdom1 resdom2 resdom3 ...) * sortops: (sortop1 sortop2 sortop3 ...) */static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode){ Plan *sortplan = (Plan *) NULL; List *temp_tlist = NIL; List *i = NIL; Resdom *resnode = (Resdom *) NULL; Resdom *resdom = (Resdom *) NULL; int keyno = 1; /* * First make a copy of the tlist so that we don't corrupt the the * original . */ temp_tlist = new_unsorted_tlist(tlist); foreach(i, sortcls) { SortClause *sortcl = (SortClause *) lfirst(i); resnode = sortcl->resdom; resdom = tlist_resdom(temp_tlist, resnode); /* * Order the resdom keys and replace the operator OID for each key * with the regproc OID. */ resdom->reskey = keyno; resdom->reskeyop = get_opcode(sortcl->opoid); keyno += 1; } sortplan = (Plan *) make_sort(temp_tlist, _NONAME_RELATION_ID_, (Plan *) plannode, length(sortcls)); /* * XXX Assuming that an internal sort has no. cost. This is wrong, but * given that at this point, we don't know the no. of tuples returned, * etc, we can't do better than to add a constant cost. This will be * fixed once we move the sort further into the planner, but for now * ... functionality.... */ sortplan->cost = plannode->cost; return sortplan;}/* * pg_checkretval() -- check return value of a list of sql parse * trees. * * The return value of a sql function is the value returned by * the final query in the function. We do some ad-hoc define-time * type checking here to be sure that the user is returning the * type he claims. * * XXX Why is this function in this module? */voidpg_checkretval(Oid rettype, List *queryTreeList){ Query *parse; List *tlist; List *rt; int cmd; Type typ; Resdom *resnode; Relation reln; Oid relid; Oid tletype; int relnatts; int i; /* find the final query */ parse = (Query *) nth(length(queryTreeList) - 1, queryTreeList); /* * test 1: if the last query is a utility invocation, then there had * better not be a return value declared. */ if (parse->commandType == CMD_UTILITY) { if (rettype == InvalidOid) return; else elog(ERROR, "return type mismatch in function decl: final query is a catalog utility"); } /* okay, it's an ordinary query */ tlist = parse->targetList; rt = parse->rtable; cmd = parse->commandType; /* * test 2: if the function is declared to return no value, then the * final query had better not be a retrieve. */ if (rettype == InvalidOid) { if (cmd == CMD_SELECT) elog(ERROR, "function declared with no return type, but final query is a retrieve"); else return; } /* by here, the function is declared to return some type */ if ((typ = typeidType(rettype)) == NULL) elog(ERROR, "can't find return type %u for function\n", rettype); /* * test 3: if the function is declared to return a value, then the * final query had better be a retrieve. */ if (cmd != CMD_SELECT) elog(ERROR, "function declared to return type %s, but final query is not a retrieve", typeTypeName(typ)); /* * test 4: for base type returns, the target list should have exactly * one entry, and its type should agree with what the user declared. */ if (typeTypeRelid(typ) == InvalidOid) { if (ExecTargetListLength(tlist) > 1) elog(ERROR, "function declared to return %s returns multiple values in final retrieve", typeTypeName(typ)); resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom; if (resnode->restype != rettype) elog(ERROR, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(typ), typeidTypeName(resnode->restype)); /* by here, base return types match */ return; } /* * If the target list is of length 1, and the type of the varnode in * the target list is the same as the declared return type, this is * okay. This can happen, for example, where the body of the function * is 'retrieve (x = func2())', where func2 has the same return type * as the function that's calling it. */ if (ExecTargetListLength(tlist) == 1) { resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom; if (resnode->restype == rettype) return; } /* * By here, the procedure returns a (set of) tuples. This part of the * typechecking is a hack. We look up the relation that is the * declared return type, and be sure that attributes 1 .. n in the * target list match the declared types. */ reln = heap_open(typeTypeRelid(typ)); if (!RelationIsValid(reln)) elog(ERROR, "cannot open relation relid %u", typeTypeRelid(typ)); relid = reln->rd_id; relnatts = reln->rd_rel->relnatts; if (ExecTargetListLength(tlist) != relnatts) elog(ERROR, "function declared to return type %s does not retrieve (%s.*)", typeTypeName(typ), typeTypeName(typ)); /* expect attributes 1 .. n in order */ for (i = 1; i <= relnatts; i++) { TargetEntry *tle = lfirst(tlist); Node *thenode = tle->expr; tlist = lnext(tlist); tletype = exprType(thenode);#ifdef NOT_USED /* fix me */ /* this is tedious */ if (IsA(thenode, Var)) tletype = (Oid) ((Var *) thenode)->vartype; else if (IsA(thenode, Const)) tletype = (Oid) ((Const *) thenode)->consttype; else if (IsA(thenode, Param)) tletype = (Oid) ((Param *) thenode)->paramtype; else if (IsA(thenode, Expr)) tletype = Expr; else if (IsA(thenode, LispList)) { thenode = lfirst(thenode); if (IsA(thenode, Oper)) tletype = (Oid) get_opresulttype((Oper *) thenode); else if (IsA(thenode, Func)) tletype = (Oid) get_functype((Func *) thenode); else elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ)); } else elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));#endif /* reach right in there, why don't you? */ if (tletype != reln->rd_att->attrs[i - 1]->atttypid) elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ)); } heap_close(reln); /* success */ return;}/* ---------- * Support function for need_sortplan * ---------- */static TargetEntry *get_matching_tle(Plan *plan, Resdom *resdom){ List *i; TargetEntry *tle; foreach(i, plan->targetlist) { tle = (TargetEntry *) lfirst(i); if (tle->resdom->resno == resdom->resno) return tle; } return NULL;}/* ---------- * Check if a user requested ORDER BY is already satisfied by * the choosen index scan. * * Returns TRUE if sort is required, FALSE if can be omitted. * ---------- */static boolneed_sortplan(List *sortcls, Plan *plan){ Relation indexRel; IndexScan *indexScan; Oid indexId; List *i; HeapTuple htup; Form_pg_index index_tup; int key_no = 0; /* ---------- * Must be an IndexScan * ---------- */ if (nodeTag(plan) != T_IndexScan) return TRUE; indexScan = (IndexScan *) plan; /* ---------- * Should not have left- or righttree * ---------- */ if (plan->lefttree != NULL) return TRUE; if (plan->righttree != NULL) return TRUE; /* ---------- * Must be a single index scan * ---------- */ if (length(indexScan->indxid) != 1) return TRUE; /* ---------- * Indices can only have up to 8 attributes. So an ORDER BY using * more that 8 attributes could never be satisfied by an index. * ---------- */ if (length(sortcls) > 8) return TRUE; /* ---------- * The choosen Index must be a btree * ---------- */ indexId = lfirsti(indexScan->indxid); indexRel = index_open(indexId); if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0) { heap_close(indexRel); return TRUE; } heap_close(indexRel); /* ---------- * Fetch the index tuple * ---------- */ htup = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(indexId), 0, 0, 0); if (!HeapTupleIsValid(htup)) elog(ERROR, "cache lookup for index %u failed", indexId); index_tup = (Form_pg_index) GETSTRUCT(htup); /* ---------- * Check if all the sort clauses match the attributes in the index * ---------- */ foreach(i, sortcls) { SortClause *sortcl; Resdom *resdom; TargetEntry *tle; Var *var; sortcl = (SortClause *) lfirst(i); resdom = sortcl->resdom; tle = get_matching_tle(plan, resdom); if (tle == NULL) { /* ---------- * Could this happen? * ---------- */ return TRUE; } if (nodeTag(tle->expr) != T_Var) { /* ---------- * The target list expression isn't a var, so it * cannot be the indexed attribute * ---------- */ return TRUE; } var = (Var *) (tle->expr); if (var->varno != indexScan->scan.scanrelid) { /* ---------- * This Var isn't from the scan relation. So it isn't * that of the index * ---------- */ return TRUE; } if (var->varattno != index_tup->indkey[key_no]) { /* ---------- * It isn't the indexed attribute. * ---------- */ return TRUE; } if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid) { /* ---------- * Sort order isn't in ascending order. * ---------- */ return TRUE; } key_no++; } /* ---------- * Index matches ORDER BY - sort not required * ---------- */ return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -