head 1.39; access; symbols Version_2_1:1.19 C_Demo_1:1.8 Retrieve_x_qual:1.5 Retrieve_x_all:1.4 Retrieve_x_1:1.3; locks; strict; comment @ * @; 1.39 date 92.07.23.15.37.36; author joey; state Exp; branches; next 1.38; 1.38 date 92.07.04.04.03.44; author mao; state Exp; branches; next 1.37; 1.37 date 92.07.03.03.28.46; author hong; state Exp; branches; next 1.36; 1.36 date 92.07.02.21.50.09; author mer; state Exp; branches; next 1.35; 1.35 date 92.06.28.03.49.14; author mao; state Exp; branches; next 1.34; 1.34 date 92.03.31.23.13.48; author mer; state Exp; branches; next 1.33; 1.33 date 92.02.25.15.30.38; author clarsen; state Exp; branches; next 1.32; 1.32 date 91.11.17.20.46.19; author mer; state Exp; branches; next 1.31; 1.31 date 91.11.15.16.26.16; author hong; state Exp; branches; next 1.30; 1.30 date 91.11.02.21.43.19; author hong; state Exp; branches; next 1.29; 1.29 date 91.09.22.22.05.07; author hong; state Exp; branches; next 1.28; 1.28 date 91.08.18.01.55.54; author caetta; state Exp; branches; next 1.27; 1.27 date 91.08.16.15.45.00; author caetta; state Exp; branches; next 1.26; 1.26 date 91.08.15.18.03.28; author caetta; state Exp; branches; next 1.25; 1.25 date 91.07.09.02.44.32; author mao; state Exp; branches; next 1.24; 1.24 date 91.05.29.23.13.59; author hong; state Exp; branches; next 1.23; 1.23 date 91.05.08.15.11.17; author hong; state Exp; branches; next 1.22; 1.22 date 91.04.27.14.18.32; author hong; state Exp; branches; next 1.21; 1.21 date 91.04.25.04.20.04; author hong; state Exp; branches; next 1.20; 1.20 date 91.04.24.12.14.33; author hong; state Exp; branches; next 1.19; 1.19 date 90.12.27.19.20.05; author sp; state Exp; branches; next 1.18; 1.18 date 90.11.02.11.19.49; author goh; state Exp; branches; next 1.17; 1.17 date 90.11.02.10.56.04; author goh; state Exp; branches; next 1.16; 1.16 date 90.09.25.16.36.41; author kemnitz; state Exp; branches; next 1.15; 1.15 date 90.05.30.18.56.55; author cimarron; state Exp; branches; next 1.14; 1.14 date 89.12.06.20.40.13; author sp; state Exp; branches; next 1.13; 1.13 date 89.12.06.14.42.49; author sp; state Exp; branches; next 1.12; 1.12 date 89.12.06.11.06.00; author goh; state Exp; branches; next 1.11; 1.11 date 89.12.04.11.40.16; author goh; state Exp; branches; next 1.10; 1.10 date 89.12.03.20.09.49; author sp; state Exp; branches; next 1.9; 1.9 date 89.10.01.15.03.13; author ong; state Exp; branches; next 1.8; 1.8 date 89.09.05.17.17.55; author mao; state C_Demo_1; branches; next 1.7; 1.7 date 89.08.30.09.04.57; author cimarron; state Exp; branches; next 1.6; 1.6 date 89.08.23.16.04.13; author ong; state Exp; branches; next 1.5; 1.5 date 89.08.04.14.30.04; author goh; state Exp; branches; next 1.4; 1.4 date 89.08.04.13.28.48; author goh; state Exp; branches; next 1.3; 1.3 date 89.08.01.14.36.16; author goh; state Exp; branches; next 1.2; 1.2 date 89.07.21.12.37.02; author goh; state Exp; branches; next 1.1; 1.1 date 89.07.18.15.16.51; author ong; state Exp; branches; next ; desc @routines to plan a single query. @ 1.39 log @fix call to nconc to set result to equal first argument. this protects us if first argument is NULL and cannot be conc'ed. @ text @ /* * FILE * planmain * * DESCRIPTION * Routines to plan a single query * */ /* RcsId ("$Header: /private/joey/pg/src/planner/plan/RCS/planmain.c,v 1.38 1992/07/04 04:03:44 mao Exp joey $"); */ /* * EXPORTS * Plan query_planner(); */ #include "nodes/pg_lisp.h" #include "nodes/plannodes.h" #include "nodes/plannodes.a.h" #include "nodes/relation.h" #include "nodes/relation.a.h" #include "parser/parse.h" #include "planner/internal.h" #include "planner/allpaths.h" #include "planner/clause.h" #include "planner/createplan.h" #include "planner/keys.h" #include "planner/planmain.h" #include "planner/setrefs.h" #include "planner/sortresult.h" #include "planner/sortresult.h" #include "planner/tlist.h" #include "tcop/dest.h" #include "utils/log.h" #include "nodes/mnodes.h" #include "utils/mcxt.h" extern int testFlag; /* * query_planner * * Routine to create a query plan. It does so by first creating a * subplan for the topmost level of attributes in the query. Then, * it modifies all target list and qualifications to consider the next * level of nesting and creates a plan for this modified query by * recursively calling itself. The two pieces are then merged together * by creating a result node that indicates which attributes should * be placed where and any relation level qualifications to be * satisfied. * * 'command-type' is the query command, e.g., retrieve, delete, etc. * 'tlist' is the target list of the query * 'qual' is the qualification of the query * 'currentlevel' is the current nesting level * 'maxlevel' is the maximum nesting level in this query * * Returns a query plan. * */ /* .. init-query-planner, query_planner */ Plan query_planner (command_type,tlist,qual,currentlevel,maxlevel) int command_type; List tlist,qual; int currentlevel; int maxlevel ; { LispValue constant_qual = LispNil; LispValue sortkeys = LispNil; LispValue flattened_tlist = LispNil; List level_tlist = LispNil; List result_of_flatten_tlist = LispNil; List agg_tlist = LispNil; List all_but_agg_tlist = LispNil; int aggidnum = -17; /* okay, a hack on uniquness */ Plan thePlan = (Plan)NULL; Plan subplan = (Plan)NULL; List subtlist = LispNil; Plan restplan = (Plan)NULL; List resttlist = LispNil; List relation_level_clauses = LispNil; Plan plan = (Plan)NULL; /* For the topmost nesting level, */ /* 1. Pull out any non-variable qualifications so these can be put in */ /* the topmost result node. The opids for the remaining */ /* qualifications will be changed to regprocs later. */ /* ------ * NOTE: we used to have one field called 'opno' in the Oper * nodes which used to be also be called 'opid' in some comments. * This field was either the pg_operator oid, or the * regproc oid. However now we have two separate * fields, the 'opno' (pg_operator oid) and the 'opid' (pg_proc * oid) so things are a little bit more clear now... [sp.] * ------ */ /* 2. Determine the keys on which the result is to be sorted. */ /* 3. Create a target list that consists solely of (resdom var) target */ /* list entries, i.e., contains no arbitrary expressions. */ if ( currentlevel == 1) { /* A command without a target list or qualification is an error, */ /* except for "delete foo". */ if (null (tlist) && null (qual)) { if ( command_type == DELETE || /* Total hack here. I don't know how to handle statements like notify in action bodies. Notify doesn't return anything but scans a system table. */ command_type == NOTIFY) { return ((Plan)make_seqscan(LispNil, LispNil, (Index)CInteger(_query_result_relation_), (Plan)NULL)); } else return((Plan)NULL); } constant_qual = pull_constant_clauses (qual); qual = nset_difference (qual,constant_qual); fix_opids (constant_qual); sortkeys = relation_sortkeys (tlist); /* flatten_tlist will now return (var, aggs, rest) */ result_of_flatten_tlist = flatten_tlist(tlist); flattened_tlist = CAR(result_of_flatten_tlist); agg_tlist = CADR(result_of_flatten_tlist); result_of_flatten_tlist = CDR(result_of_flatten_tlist); all_but_agg_tlist = CADR(result_of_flatten_tlist); if (flattened_tlist) level_tlist = flattened_tlist; else if (tlist) level_tlist = all_but_agg_tlist; /* orig_tlist minus the aggregates */ else level_tlist = (List)NULL; } if(agg_tlist) { if(all_but_agg_tlist) { thePlan = query_planner(command_type, all_but_agg_tlist, qual, currentlevel, maxlevel); } else { /* all we have are aggregates */ thePlan = (Plan)make_agg(CAR(agg_tlist), --aggidnum); /* also, there should never be a case by now where we neither * have aggs nor all_but_aggs */ agg_tlist = CDR(agg_tlist); } if(agg_tlist != NULL) { /* are there any aggs left */ thePlan = make_aggplan(thePlan, agg_tlist, aggidnum); } return(thePlan); } /* A query may have a non-variable target list and a non-variable */ /* qualification only under certain conditions: */ /* - the query creates all-new tuples, or */ /* - the query is a replace (a scan must still be done in this case). */ if ((0 == maxlevel || (1 == currentlevel && null (flattened_tlist))) && null (qual)) { switch (command_type) { case RETRIEVE : case APPEND : return ((Plan)make_result (tlist, LispNil, constant_qual, (Plan)NULL, (Plan)NULL)); break; case DELETE : case REPLACE : { /* XXX - let form, maybe incorrect */ SeqScan scan = make_seqscan (tlist, LispNil, (Index)CInteger( _query_result_relation_), (Plan)NULL); if ( consp (constant_qual) ) { return ((Plan)make_result (tlist, LispNil, constant_qual, (Plan)scan, (Plan)NULL)); } else { return ((Plan)scan); } } break; default: /* return nil */ return((Plan)NULL); } } /* Find the subplan (access path) for attributes at this nesting level */ /* and destructively modify the target list of the newly created */ /* subplan to contain the appropriate join references. */ subplan = subplanner (level_tlist, tlist, qual, currentlevel, sortkeys); subtlist = get_qptargetlist (subplan); set_tlist_references (subplan); /* If there are further nesting levels, call the planner again to */ /* create subplans for lower levels of nesting. Modify the target */ /* list and qualifications to reflect the new nesting level. */ if (currentlevel != maxlevel) { elog(WARN, "level mismatch -- should never happen with new nested dot parsing scheme!"); } /* Build a result node linking the plan for deeper nesting levels and */ /* the subplan for this level. Note that a plan that has no right */ /* subtree may still have relation level and constant quals, so we */ /* still have to build an appropriate result node. */ relation_level_clauses = pull_relation_level_clauses (qual); if ( restplan || relation_level_clauses || constant_qual) { List resttlist = LispNil; List subtlist = LispNil; Plan plan; if ( restplan ) resttlist = get_qptargetlist (restplan); subtlist = get_qptargetlist (subplan); plan = (Plan)make_result (new_result_tlist (tlist, subtlist, resttlist, currentlevel, valid_sortkeys(sortkeys)), new_result_qual(relation_level_clauses, subtlist, resttlist, currentlevel), constant_qual, subplan, restplan); /* * Change all varno's of the Result's node target list. */ set_result_tlist_references((Result)plan); if ( valid_numkeys (sortkeys) ) return (sort_level_result (plan, CInteger(sortkeys))); else return (plan); } /* * fix up the flattened target list of the plan root node so that * expressions are evaluated. this forces expression evaluations * that may involve expensive function calls to be delayed to * the very last stage of query execution. this could be bad. * but it is joey's responsibility to optimally push these * expressions down the plan tree. -- Wei */ set_qptargetlist (subplan, flatten_tlist_vars (tlist, get_qptargetlist (subplan))); /* * Destructively modify the query plan's targetlist to add fjoin * lists to flatten functions that return sets of base types */ set_qptargetlist(subplan, generate_fjoin(get_qptargetlist(subplan))); /* If a sort is required, explicitly sort this subplan since: */ /* there is only one level of attributes in this query, and */ /*the sort spans across expressions and/or multiple relations and so */ /* indices were not considered in planning the sort. */ if ( valid_numkeys (sortkeys) ) return (sort_level_result (subplan,CInteger(sortkeys))); else return (subplan); } /* function end */ /* * subplanner * * Subplanner creates an entire plan consisting of joins and scans * for processing a single level of attributes. Nested attributes are * transparent (i.e., essentially ignored) from here on. * * 'flat-tlist' is the flattened target list * --which now is of the form (vars, aggs)--, jc * 'original-tlist' is the unflattened target list * 'qual' is the qualification to be satisfied * 'level' is the current nesting level * * Returns a subplan. * */ /* .. query_planner */ Plan subplanner (flat_tlist,original_tlist,qual,level,sortkeys) LispValue flat_tlist,original_tlist,qual,sortkeys ; int level; { Rel final_relation; List final_relation_list; /* Initialize the targetlist and qualification, adding entries to */ /* *query-relation-list* as relation references are found (e.g., in the */ /* qualification, the targetlist, etc.) */ _base_relation_list_ = LispNil; _join_relation_list_ = LispNil; initialize_targetlist (flat_tlist); initialize_qualification (qual); /* Find all possible scan and join paths. */ /* Mark all the clauses and relations that can be processed using special */ /* join methods, then do the exhaustive path search. */ initialize_join_clause_info (_base_relation_list_); final_relation_list = find_paths (_base_relation_list_, level, sortkeys); if (final_relation_list) final_relation = (Rel)CAR (final_relation_list); else final_relation = (Rel)LispNil; /* If we want a sorted result and indices could have been used to do so, */ /* then explicitly sort those paths that weren't sorted by indices so we */ /* can determine whether using the implicit sort (index) is better than an */ /* explicit one. */ if ( valid_sortkeys (sortkeys)) { sort_relation_paths (get_pathlist (final_relation), sortkeys, final_relation, compute_targetlist_width(original_tlist)); } /* Determine the cheapest path and create a subplan corresponding to it. */ if (final_relation) { if (testFlag) { List planlist = LispNil; List pathlist = LispNil; LispValue x; Path path; Plan plan; Choose chooseplan; pathlist = get_pathlist(final_relation); foreach (x, pathlist) { path = (Path)CAR(x); plan = create_plan(path); planlist = nappend1(planlist, (LispValue)plan); } chooseplan = RMakeChoose(); set_chooseplanlist(chooseplan, planlist); set_qptargetlist((Plan)chooseplan, get_qptargetlist(plan)); return (Plan)chooseplan; } return (create_plan ((Path)get_cheapestpath (final_relation))); } else { printf(" Warn: final relation is nil \n"); return(create_plan ((Path)NULL)); } } /* function end */ Result make_result( tlist,resrellevelqual,resconstantqual,left,right) List tlist; List resrellevelqual,resconstantqual; Plan left,right; { Result node = RMakeResult(); tlist = generate_fjoin(tlist); set_cost((Plan) node, 0.0); set_fragment((Plan) node, 0); set_state((Plan) node, NULL); set_qptargetlist((Plan)node, tlist); set_qpqual((Plan) node, LispNil); set_lefttree((Plan)node, (PlanPtr)left); set_righttree((Plan)node, (PlanPtr)right); set_resrellevelqual(node, resrellevelqual); set_resconstantqual(node, resconstantqual); set_resstate(node, NULL); return(node); } /* for modifying in case of aggregates. * we know that there are aggregates in the tlist*/ Plan make_aggplan(subplan, agg_tlist, aggidnum) Plan subplan; List agg_tlist; int aggidnum; { List agg_tl_entry = LispNil; List add_to_tl = LispNil; NestLoop joinnode = (NestLoop)NULL; LispValue entry = LispNil; List level_tlist = LispNil; Agg aggnode; /* extern search_quals(); */ /* we're assuming that subplan is not null from the caller*/ agg_tl_entry = CAR(agg_tlist); aggnode = make_agg(agg_tl_entry, --aggidnum); set_qptargetlist(subplan, nconc(get_qptargetlist(subplan), get_qptargetlist((Plan)aggnode))); level_tlist = get_qptargetlist(subplan); joinnode = make_nestloop(level_tlist, LispNil, (Plan)aggnode, subplan); /* inner tree is the aggregate, outer tree is the rest of * the plan. quals are nil here since we don't have aggregate * functions yet. */ if(CDR(agg_tlist)) { /* is this the last agg_tlist entry? */ /* if not */ return make_aggplan((Plan)joinnode, CDR(agg_tlist), aggidnum); /* XXX jc. type problem with joinnode and Plan subplan? */ } else { /* if so */ return((Plan) joinnode); } } bool plan_isomorphic(p1, p2) Plan p1, p2; { if (p1 == NULL) return (p2 == NULL); if (p2 == NULL) return (p1 == NULL); if (IsA(p1,Join) && IsA(p2,Join)) { return (plan_isomorphic(get_lefttree(p1), get_lefttree(p2)) && plan_isomorphic(get_righttree(p1), get_righttree(p2))); } if (IsA(p1,Scan) && IsA(p2,Scan)) { if (get_scanrelid((Scan)p1) == get_scanrelid((Scan)p2)) if (get_scanrelid((Scan)p1) == _TEMP_RELATION_ID_) return plan_isomorphic(get_lefttree(p1), get_lefttree(p2)); else return true; else if (get_scanrelid((Scan)p1) == _TEMP_RELATION_ID_) return plan_isomorphic(get_lefttree(p1), p2); else if (get_scanrelid((Scan)p2) == _TEMP_RELATION_ID_) return plan_isomorphic(p1, get_lefttree(p2)); return false; } if (IsA(p1,Temp) || IsA(p1,Hash) || (IsA(p1,Scan) && get_scanrelid((Scan)p1) == _TEMP_RELATION_ID_)) return plan_isomorphic(get_lefttree(p1), p2); if (IsA(p2,Temp) || IsA(p2,Hash) || (IsA(p2,Scan) && get_scanrelid((Scan)p2) == _TEMP_RELATION_ID_)) return plan_isomorphic(p1, get_lefttree(p2)); return false; } List group_planlist(planlist) List planlist; { List plangroups = LispNil; Plan p1, p2; List plist; List g, x; plist = planlist; while (!lispNullp(plist)) { p1 = (Plan)CAR(plist); g = lispCons((LispValue)p1, LispNil); foreach (x, CDR(plist)) { p2 = (Plan)CAR(x); if (plan_isomorphic(p1, p2)) { g = nappend1(g, (LispValue)p2); } } plist = nset_difference(plist, g); plangroups = nappend1(plangroups, g); } return plangroups; } bool allNestLoop(plan) Plan plan; { if (plan == NULL) return true; if (IsA(plan,Temp) || (IsA(plan,Scan) && get_scanrelid((Scan)plan) == _TEMP_RELATION_ID_)) return allNestLoop(get_lefttree(plan)); if (IsA(plan,NestLoop)) { return allNestLoop(get_lefttree(plan)) && allNestLoop(get_righttree(plan)); } if (IsA(plan,Join)) return false; return true; } Plan pickNestLoopPlan(plangroup) List plangroup; { LispValue x; Plan p; foreach (x, plangroup) { p = (Plan)CAR(x); if (allNestLoop(p)) return p; } return NULL; } void setPlanStats(p1, p2) Plan p1, p2; { if (p1 == NULL || p2 == NULL) return; if (IsA(p1,Join) && IsA(p2,Join)) { set_plan_size(p2, get_plan_size(p1)); setPlanStats(get_lefttree(p1), get_lefttree(p2)); /* setPlanStats(get_righttree(p1), get_righttree(p2)); */ return; } if (IsA(p1,Temp) || IsA(p1,Hash) || (IsA(p1,Scan) && get_scanrelid((Scan)p1) == _TEMP_RELATION_ID_)) { setPlanStats(get_lefttree(p1), p2); return; } if (IsA(p2,Temp) || IsA(p2,Hash) || (IsA(p2,Scan) && get_scanrelid((Scan)p2) == _TEMP_RELATION_ID_)) { set_plan_size(p2, get_plan_size(p1)); setPlanStats(p1, get_lefttree(p2)); return; } if (IsA(p1,Scan) && IsA(p2,Scan)) { set_plan_size(p2, get_plan_size(p1)); return; } return; } void resetPlanStats(p) Plan p; { if (p == NULL) return; set_plan_size(p, 0); if (IsA(p,Join)) { resetPlanStats(get_lefttree(p)); resetPlanStats(get_righttree(p)); return; } if (IsA(p,Scan)) { if (get_scanrelid((Scan)p) == _TEMP_RELATION_ID_) resetPlanStats(get_lefttree(p)); return; } resetPlanStats(get_lefttree(p)); return; } void setPlanGroupStats(plan, planlist) Plan plan; List planlist; { List x; Plan p; foreach (x, planlist) { p = (Plan)CAR(x); setPlanStats(plan, p); } } bool _exec_collect_stats_ = false; /* * XXX mao speaking: * * i assume that this routine is used by some planner wizard to * collect actual plan execution costs, and that it's not run * during ordinary postgres processing. the planner shouldn't * be executing queries directly, right? */ List setRealPlanStats(parsetree, planlist) List parsetree; List planlist; { List plangroups; List plangroup; LispValue x; List ordered_planlist; Plan nlplan; _exec_collect_stats_ = true; plangroups = group_planlist(planlist); ordered_planlist = LispNil; foreach (x, plangroups) { plangroup = CAR(x); nlplan = pickNestLoopPlan(plangroup); if (nlplan == NULL) { elog(NOTICE, "no nestloop plan in plan group!"); break; } if (IsA(nlplan,Join)) { resetPlanStats(nlplan); p_plan(nlplan); ResetUsage(); ProcessQuery(parsetree, nlplan, (char *) NULL, (ObjectId *) NULL, 0, None); ShowUsage(); plangroup = nLispRemove(plangroup, (LispValue)nlplan); setPlanGroupStats(nlplan, plangroup); } else { ordered_planlist = plangroup; break; } ordered_planlist = nconc(ordered_planlist, plangroup); } _exec_collect_stats_ = false; return ordered_planlist; } bool plan_contain_redundant_hashjoin(plan) Plan plan; { Plan outerplan, innerplan; int outerpages, innerpages; if (plan == NULL) return false; if (IsA(plan,HashJoin)) { outerplan = (Plan) get_lefttree(plan); innerplan = (Plan) get_lefttree((Plan)get_righttree(plan)); outerpages = page_size(get_plan_size(outerplan), get_plan_width(outerplan)); innerpages = page_size(get_plan_size(innerplan), get_plan_width(innerplan)); if (!IsA(outerplan,Join) && outerpages < innerpages) return true; } if (IsA(plan,Join)) return plan_contain_redundant_hashjoin(get_lefttree(plan)) || plan_contain_redundant_hashjoin(get_righttree(plan)); if (IsA(plan,Temp) || IsA(plan,Hash) || (IsA(plan,Scan) && get_scanrelid((Scan)plan) == _TEMP_RELATION_ID_)) return plan_contain_redundant_hashjoin(get_lefttree(plan)); return false; } List pruneHashJoinPlans(planlist) List planlist; { LispValue x; Plan plan; List retlist; retlist = LispNil; foreach (x, planlist) { plan = (Plan)CAR(x); if (!plan_contain_redundant_hashjoin(plan)) retlist = nappend1(retlist, (LispValue)plan); } return retlist; } @ 1.38 log @fixes for arrays, array refs, and nested dots @ text @d10 1 a10 1 /* RcsId ("$Header: /private/mao/postgres/src/planner/plan/RCS/planmain.c,v 1.37 1992/07/03 03:28:46 hong Exp mao $"); */ d433 3 a435 2 level_tlist = nconc(get_qptargetlist(subplan), get_qptargetlist((Plan)aggnode)); @ 1.37 log @cleaned up final targetlist generation part, put generate_fjoin() in place @ text @d10 1 a10 1 /* RcsId ("$Header: plan/RCS/planmain.c,v 1.36 92/07/02 21:50:09 mer Exp Locker: hong $"); */ d226 2 a227 10 if ( !(currentlevel == maxlevel ) ) { restplan = query_planner (command_type, new_level_tlist (level_tlist, subtlist, currentlevel), new_level_qual (qual, subtlist, currentlevel), currentlevel + 1, maxlevel); @ 1.36 log @special case Result plan fjoin generation in the target list @ text @d10 1 a10 1 /* RcsId ("$Header: /private/mer/pg/src/planner/plan/RCS/planmain.c,v 1.35 1992/06/28 03:49:14 mao Exp mer $"); */ d277 10 a286 11 /* Remodify the target list of the subplan so it no longer is */ /* 'flattened', unless this has already been done in create_plan */ /* for a path that had to be explicitly sorted. */ if ( 1 == maxlevel && !(IsA(subplan,Temp) || (IsA(subplan,SeqScan) && get_lefttree(subplan) && IsA (get_lefttree (subplan),Temp)))) { set_qptargetlist (subplan, flatten_tlist_vars (tlist, d288 6 a293 1 } d380 1 a380 1 plan = create_plan(path, original_tlist); d388 1 a388 2 return (create_plan ((Path)get_cheapestpath (final_relation), original_tlist)); d392 1 a392 1 return(create_plan ((Path)NULL, original_tlist)); @ 1.35 log @rearrange parse, plan to support postquel function invocations @ text @d10 1 a10 1 /* RcsId ("$Header: /private/mao/postgres/src/planner/plan/RCS/planmain.c,v 1.34 1992/03/31 23:13:48 mer Exp mao $"); */ d402 1 @ 1.34 log @change accessor functions into macros @ text @d10 1 a10 1 /* RcsId ("$Header: /users/mer/pg/src/planner/plan/RCS/planmain.c,v 1.33 1992/02/25 15:30:38 clarsen Exp mer $"); */ d615 9 d649 2 a650 1 ProcessQuery(parsetree, nlplan, None); @ 1.33 log @async portals. @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.32 91/11/17 20:46:19 mer Exp Locker: clarsen $"); */ d384 1 a384 1 return (create_plan (get_cheapestpath (final_relation), d407 2 a408 2 set_lefttree((Plan)node, left); set_righttree((Plan)node, right); d665 1 a665 1 innerplan = (Plan) get_lefttree(get_righttree(plan)); @ 1.32 log @prototyping @ text @d10 1 a10 1 /* RcsId ("$Header: /users/mer/postgres/src/planner/plan/RCS/planmain.c,v 1.31 1991/11/15 16:26:16 hong Exp mer $"); */ d112 6 a117 1 if ( command_type == DELETE ) { a173 1 @ 1.31 log @planner prototyping @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.30 91/11/02 21:43:19 hong Exp $"); */ d373 1 a373 1 planlist = nappend1(planlist, plan); d498 1 a498 1 g = lispCons(p1, LispNil); d502 1 a502 1 g = nappend1(g, p2); d638 1 a638 1 plangroup = nLispRemove(plangroup, nlplan); d690 1 a690 1 retlist = nappend1(retlist, plan); @ 1.30 log @cleaned up bushy tree plan generation code @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.29 91/09/22 22:05:07 hong Exp $"); */ d30 1 d32 1 a41 6 /* ---------------- * Result creator declaration * ---------------- */ extern Result RMakeResult(); extern Choose RMakeChoose(); a89 2 extern Plan subplanner(); d113 3 a115 5 return ((Plan)make_seqscan((List) NULL, (List) NULL, (Index) CInteger( _query_result_relation_), (Node) NULL )); d155 1 a155 1 thePlan = (Plan)make_aggplan(thePlan, agg_tlist, aggidnum); d175 2 a176 2 LispNil, LispNil)); d185 1 a185 1 (Index) CInteger( d187 1 a187 1 LispNil); d192 2 a193 2 scan, LispNil)); d266 1 a266 1 set_result_tlist_references(plan); d269 1 a269 1 return (sort_level_result (plan,sortkeys)); d292 1 a292 1 return (sort_level_result (subplan,sortkeys)); d319 2 a320 1 LispValue flat_tlist,original_tlist,qual,level,sortkeys ; d377 1 a377 1 set_qptargetlist(chooseplan, get_qptargetlist(plan)); d385 1 a385 1 return(create_plan (LispNil,original_tlist)); a416 1 LispValue agg_tlist; d418 1 d434 2 a435 2 get_qptargetlist(aggnode)); joinnode = make_nestloop(level_tlist, LispNil, aggnode, d444 1 a444 1 return make_aggplan(joinnode, CDR(agg_tlist), aggidnum); d466 2 a467 2 if (get_scanrelid(p1) == get_scanrelid(p2)) if (get_scanrelid(p1) == _TEMP_RELATION_ID_) d471 1 a471 1 else if (get_scanrelid(p1) == _TEMP_RELATION_ID_) d473 1 a473 1 else if (get_scanrelid(p2) == _TEMP_RELATION_ID_) d478 1 a478 1 (IsA(p1,Scan) && get_scanrelid(p1) == _TEMP_RELATION_ID_)) d481 1 a481 1 (IsA(p2,Scan) && get_scanrelid(p2) == _TEMP_RELATION_ID_)) d517 1 a517 1 (IsA(plan,Scan) && get_scanrelid(plan) == _TEMP_RELATION_ID_)) d558 1 a558 1 (IsA(p1,Scan) && get_scanrelid(p1) == _TEMP_RELATION_ID_)) { d563 1 a563 1 (IsA(p2,Scan) && get_scanrelid(p2) == _TEMP_RELATION_ID_)) { d587 1 a587 1 if (get_scanrelid(p) == _TEMP_RELATION_ID_) d673 1 a673 1 (IsA(plan,Scan) && get_scanrelid(plan) == _TEMP_RELATION_ID_)) @ 1.29 log @mixed up left and right tree in hashjoin before @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.28 91/08/18 01:55:54 caetta Exp $"); */ a39 1 extern GlobalMemory ParserPlannerContext; d330 1 d336 2 a337 1 _query_relation_list_ = LispNil; d346 2 a347 2 initialize_join_clause_info (_query_relation_list_); _query_relation_list_ = find_paths (_query_relation_list_, d350 2 a351 2 if (_query_relation_list_) final_relation = (Rel)CAR (_query_relation_list_); a376 3 /* MemoryContextSwitchTo(ParserPlannerContext); */ d523 3 @ 1.28 log @a kinder, gentler planner... @ text @d10 1 a10 1 /* RcsId ("$Header: planner/plan/RCS/planmain.c,v 1.27 91/08/16 15:45:00 caetta Exp Locker: caetta $"); */ d666 2 a667 2 outerplan = (Plan) get_lefttree(get_lefttree(plan)); innerplan = (Plan) get_righttree(plan); d672 1 a672 1 if (!IsA(outerplan,Join) && outerpages > innerpages) @ 1.27 log @fix from being broken by aggregates @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.26 91/08/15 18:03:28 caetta Exp $"); */ a96 1 d444 2 a445 2 joinnode = make_nestloop(level_tlist, LispNil, subplan, aggnode); @ 1.26 log @for aggregates, building the plan @ text @d10 1 a10 1 /* RcsId ("$Header: planner/plan/RCS/planmain.c,v 1.25 91/07/09 02:44:32 mao Exp Locker: caetta $"); */ d85 1 d87 1 d141 1 d145 1 a145 1 level_tlist = CADR(result_of_flatten_tlist); d151 19 d176 1 a176 1 (1 == currentlevel && null (result_of_flatten_tlist))) && d219 1 a219 2 if(level_tlist != NULL) { subplan = subplanner (level_tlist, d224 1 a224 16 } else if(agg_tlist != NULL) { /* level_tlist was null in this case so our base plan is the aggnode */ subplan = (Plan)make_agg(CAR(agg_tlist), --aggidnum); /* this calls the planner on the inner query, builds the Agg node, * sets the appropriate fields, and returns the Agg node. */ agg_tlist = CDR(agg_tlist); } /* we're assuming we Have a targetlist at this point */ if(agg_tlist != NULL) { /* are there any aggs left...*/ subplan = (Plan)make_aggplan(subplan, agg_tlist, aggidnum); } @ 1.25 log @get rid of compile-time warning @ text @d10 1 a10 1 /* RcsId ("$Header: /users/mao/postgres/src/planner/plan/RCS/planmain.c,v 1.24 1991/05/29 23:13:59 hong Exp mao $"); */ d83 3 d131 8 a138 1 flattened_tlist = flatten_tlist (tlist); d142 2 a143 1 level_tlist = tlist; d154 1 a154 1 (1 == currentlevel && null (flattened_tlist))) && d197 22 a218 5 subplan = subplanner (level_tlist, tlist, qual, currentlevel, sortkeys); d310 1 d416 42 @ 1.24 log @some changes that only affect my experiments @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.23 91/05/08 15:11:17 hong Exp $"); */ d590 2 a591 2 outerplan = get_lefttree(get_lefttree(plan)); innerplan = get_righttree(plan); @ 1.23 log @some changes in wei's special code, no affect to anyone else @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.22 91/04/27 14:18:32 hong Exp $"); */ d35 3 d40 1 d342 3 d396 1 a396 3 plan_isomorphic(get_righttree(p1), get_righttree(p2))) || (plan_isomorphic(get_lefttree(p1), get_righttree(p2)) && plan_isomorphic(get_righttree(p1), get_lefttree(p2))); d481 4 a484 8 if (plan_isomorphic(get_lefttree(p1), get_lefttree(p2))) { setPlanStats(get_lefttree(p1), get_lefttree(p2)); setPlanStats(get_righttree(p1), get_righttree(p2)); } else { setPlanStats(get_lefttree(p1), get_righttree(p2)); setPlanStats(get_righttree(p1), get_lefttree(p2)); } d487 2 a488 7 if (IsA(p1,Scan) && IsA(p2,Scan)) { set_plan_size(p2, get_plan_size(p1)); if (get_scanrelid(p1) == _TEMP_RELATION_ID_) setPlanStats(get_lefttree(p1), get_lefttree(p2)); return; } if (IsA(p1,Temp)) { d492 2 a493 1 if (IsA(p2,Temp)) { d498 4 d554 1 d558 4 d564 2 d567 3 a569 1 setPlanGroupStats(nlplan, nLispRemove(plangroup, nlplan)); d571 2 a572 1 else d574 2 d578 20 a597 3 ordered_planlist = LispNil; foreach (x, plangroups) { ordered_planlist = nconc(ordered_planlist, CAR(x)); d599 24 a622 1 return ordered_planlist; @ 1.22 log @added code to collect real execution stats for plans this has to do with my experiments only. @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.21 91/04/25 04:20:04 hong Exp Locker: hong $"); */ a332 1 List prunePathListForTest(); a337 1 pathlist = prunePathListForTest(pathlist); a381 62 pathShouldPruned(path, order_expected) Path path; bool order_expected; { if (IsA(path,MergePath)) { return pathShouldPruned(get_outerjoinpath(path), !get_outersortkeys(path)) || pathShouldPruned(get_innerjoinpath(path), !get_innersortkeys(path)); } if (IsA(path,HashPath)) { return pathShouldPruned(get_outerjoinpath(path), false) || pathShouldPruned(get_innerjoinpath(path), false); } if (IsA(path,JoinPath)) { if (!IsA(get_innerjoinpath(path),IndexPath) && !IsA(get_innerjoinpath(path),JoinPath) && length(get_relids(get_parent(get_innerjoinpath(path)))) == 1) return true; return pathShouldPruned(get_outerjoinpath(path), order_expected) || pathShouldPruned(get_innerjoinpath(path), false); } if (IsA(path,IndexPath)) { return lispNullp(get_indexqual(path)) && !order_expected; } return false; } List prunePathListForTest(pathlist) List pathlist; { LispValue x, y; Path path, path1; List path_prune_list = LispNil; List new_pathlist; foreach (x, pathlist) { path = (Path)CAR(x); if (pathShouldPruned(path, false)) path_prune_list = nappend1(path_prune_list, path); } new_pathlist = nset_difference(pathlist, path_prune_list); path_prune_list = LispNil; foreach (x, new_pathlist) { path = (Path)CAR(x); if (IsA(path,MergePath)) { foreach (y, CDR(x)) { path1 = (Path)CAR(y); if (IsA(path1,MergePath) && equal(get_outerjoinpath(path), get_innerjoinpath(path1)) && equal(get_innerjoinpath(path), get_outerjoinpath(path1))) path_prune_list = nappend1(path_prune_list, path1); } } } new_pathlist = nset_difference(new_pathlist, path_prune_list); return new_pathlist; } bool d405 2 a406 1 if (IsA(p1,Temp) || IsA(p1,Hash)) d408 2 a409 1 if (IsA(p2,Temp) || IsA(p2,Hash)) @ 1.21 log @more special-case code for my experiments only, will be got rid of later. -- Wei @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.20 91/04/24 12:14:33 hong Exp Locker: hong $"); */ d34 1 d121 1 a121 1 qual = set_difference (qual,constant_qual); d426 1 a426 1 new_pathlist = set_difference(pathlist, path_prune_list); d440 1 a440 1 new_pathlist = set_difference(new_pathlist, path_prune_list); d443 189 @ 1.20 log @added a special case for my experiments @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.19 90/12/27 19:20:05 sp Exp Locker: hong $"); */ d331 2 d337 3 a339 1 foreach (x, get_pathlist(final_relation)) { d381 62 @ 1.19 log @Oper nodes now have a new field (opid) where the oid of the regproc is stored (that used to be stored in 'opno' overriding the pg_operator oid). @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.18 90/11/02 11:19:49 goh Exp Locker: sp $"); */ d35 1 d41 1 d328 17 a344 1 if (final_relation) d347 1 @ 1.18 log @ reverse the fix_opid change because it breaks since selectivities are computed from operator rather than function ids. Bummer maybe someday we'll fix it (again). - jeff @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.16 90/09/25 16:36:41 kemnitz Exp $"); */ d90 9 @ 1.17 log @planner no longer fixes opids @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.16 90/08/14 11:40:12 cimarron Exp $"); */ a109 1 #ifdef PLANNER_FIX_OPIDS a110 1 #endif @ 1.16 log @Updating from revision 1.15 to revision 1.16 @ text @d110 1 d112 1 @ 1.15 log @CreateNode(Foo) --> RMakeFoo() change @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.14 89/12/06 20:40:13 sp Exp $"); */ d17 9 d27 3 a29 6 #include "pg_lisp.h" #include "parse.h" #include "relation.h" #include "relation.a.h" #include "plannodes.h" #include "plannodes.a.h" a30 1 #include "planner/clause.h" d32 1 a33 3 #include "planner/sortresult.h" #include "planner/createplan.h" #include "planner/allpaths.h" @ 1.14 log @Call set_tlist_references() to modify the target list of a Result node. @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.13 89/12/06 14:42:49 sp Exp Locker: sp $"); */ d32 5 d330 1 a330 3 extern void PrintResult(); extern bool EqualResult(); Result node = New_Node(Result); a343 2 node->printFunc = PrintResult; node->equalFunc = EqualResult; @ 1.13 log @_query_result_relation_ is a LispValue, so we should call CInteger() to get its actual value... @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.12 89/12/06 11:06:00 goh Exp $"); */ d215 5 a219 3 if ( constant_qual ) { set_join_tlist_references ( plan ); } @ 1.12 log @fixes the bug that spyros found about the "Gen" scripts @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.11 89/12/04 11:40:16 goh Exp Locker: goh $"); */ d94 2 a95 1 (Index) _query_result_relation_, @ 1.11 log @Hopefully the correct fix for constant qualifications. Unfortunately, since the previous hack (using the outer-scan tuple) didn't work, it appears that the executor will need major fixing to execute "nested-dot" plans. @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.10 89/12/03 20:09:49 sp Exp Locker: goh $"); */ d92 1 a92 1 return ((Plan)MakeSeqScan ((List) NULL, @ 1.10 log @Two bug fixes: 1) Delete with constant quals (like "delete foo where 1 = 1 ") are now correctly planned (the planner used to generate a NULL plan) 2) _query_result_relation_ is a LispValue, so we should first call CInteger before passing it as argument to make_seqscan() @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.9 89/10/01 15:03:13 ong Exp $"); */ d201 1 d214 3 a216 1 @ 1.9 log @added resconstantqual as arg. to make_result() @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.8 89/09/05 17:17:55 mao C_Demo_1 $"); */ d131 1 d137 2 a138 1 _query_result_relation_, @ 1.8 log @Working version of C-only demo @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.7 89/08/30 09:04:57 cimarron Exp $"); */ d200 4 a203 4 subtlist, resttlist, currentlevel, valid_sortkeys(sortkeys)), d208 1 a208 1 constant_qual, d312 1 a312 1 make_result( tlist,resrellevelqual,left,right) d314 1 a314 1 List resrellevelqual; d330 1 a330 1 set_resconstantqual(node, LispNil); @ 1.7 log @fixed make_result() @ text @d10 1 a10 1 /* RcsId ("$Header: RCS/planmain.c,v 1.6 89/08/23 16:04:13 ong Exp Locker: goh $"); */ @ 1.6 log @planner supports all but rules and mergesort @ text @d10 1 a10 1 /* RcsId ("$Header: /n/postgres/a/postgres/ong/postgres/src/planner/plan/RCS/planmain.c,v 1.5 89/08/04 14:30:04 goh Exp $"); */ d321 7 a327 6 set_cost ((Plan)node,0.0); set_qptargetlist ((Plan)node, tlist); set_lefttree((Plan)node,left); set_righttree((Plan)node,right); set_resrellevelqual( node ,resrellevelqual); set_resconstantqual( node ,LispNil); d329 4 @ 1.5 log @reorganised header files @ text @d10 1 a10 1 /* RcsId ("$Header: planmain.c,v 1.4 89/08/04 13:28:48 goh Locked $"); */ d134 1 a134 1 SeqScan scan = MakeSeqScan (tlist, d270 3 a272 3 _query_relation_list_ = LispNil; initialize_targetlist (flat_tlist); initialize_qualification (qual); d274 1 a274 1 d279 8 a286 8 initialize_join_clause_info (_query_relation_list_); _query_relation_list_ = find_paths (_query_relation_list_, level, sortkeys); if (_query_relation_list_) final_relation = (Rel)CAR (_query_relation_list_); else final_relation = (Rel)LispNil; d294 1 a294 1 sort_relation_paths (get_pathlist (final_relation), d296 2 a297 2 final_relation, compute_targetlist_width(original_tlist)); d308 1 a308 1 d318 1 a318 1 d321 1 a321 2 set_resrellevelqual( node ,resrellevelqual); set_resconstantqual( node ,LispNil); d325 3 d329 1 @ 1.4 log @checkin for retrieve (x.all) @ text @d10 1 a10 1 /* RcsId ("$Header: planmain.c,v 1.3 89/08/01 14:36:16 goh Locked $"); */ d17 1 a17 1 #include "internal.h" d24 7 a30 6 #include "clause.h" #include "sortresult.h" #include "tlist.h" #include "sortresult.h" #include "createplan.h" #include "allpaths.h" d32 1 a32 1 extern Result make_result(); d315 1 @ 1.3 log @retrieve (x=1) checkin @ text @d10 1 a10 1 /* RcsId ("$Header: planmain.c,v 1.2 89/07/21 12:37:02 goh Locked $"); */ a62 1 /* XXX - prog form, maybe incorrect */ d67 3 a69 3 Plan subplan; List subtlist; Plan restplan; d72 1 a72 1 Plan plan; d283 1 a283 1 final_relation = CAR (_query_relation_list_); @ 1.2 log @phase 2-3 checkin @ text @d10 1 a10 1 /* RcsId ("$Header: planmain.c,v 1.1 89/07/18 15:16:51 goh Locked $"); */ d31 1 d92 1 a92 1 return ((Plan)make_seqscan ((List) NULL, d110 1 a110 1 } d112 1 a112 1 /* A query may have a non-variable target list and a non-variable */ d124 1 a124 1 return ((Plan)MakeResult (tlist, d139 1 a139 1 return ((Plan)MakeResult (tlist, d171 1 a171 1 if ( !(equal (currentlevel,maxlevel))) { d199 1 a199 1 plan = (Plan)MakeResult (new_result_tlist (tlist, d222 2 a223 2 !(temp_p(subplan) || (seqscan_p(subplan) && d225 1 a225 1 temp_p (get_lefttree (subplan))))) { d264 1 a264 1 LispValue final_relation = LispNil; d274 1 d283 4 a286 1 final_relation = CAR (_query_relation_list_); d300 8 d309 1 a309 2 return (create_plan (get_cheapest_path (final_relation), original_tlist)); d311 17 a327 1 } /* function end */ @ 1.1 log @Initial revision @ text @d10 1 a10 1 /* RcsId ("$Header: planmain.c,v 1.1 89/04/27 21:04:51 ong Locked $"); */ d14 1 a14 1 * query_planner d18 12 a30 8 extern LispValue subplanner(); #define DELETE 10 #define APPEND 11 #define RETRIEVE 12 #define REPLACE 13 d55 1 a55 1 LispValue d57 4 a60 1 LispValue command_type,tlist,qual,currentlevel,maxlevel ; d66 7 a72 7 LispValue level_tlist = LispNil; LispValue subplan = LispNil; LispValue subtlist = LispNil; LispValue restplan = LispNil; LispValue resttlist = LispNil; LispValue relation_level_clauses = LispNil; LispValue plan = LispNil; d74 3 d84 1 a84 1 d86 24 a109 20 /* A command without a target list or qualification is an error, */ /* except for "delete foo". */ if (null (tlist) && null (qual)) { if ( equal (command_type,DELETE) ) { return (make_seqscan (LispNil, LispNil, _query_result_relation_, LispNil)); } else return(LispNil); } constant_qual = pull_constant_clauses (qual); qual = set_difference (qual,constant_qual); fix_opids (constant_qual); sortkeys = relation_sortkeys (tlist); flattened_tlist = flatten_tlist (tlist); level_tlist = or (flattened_tlist,tlist); } d111 1 a111 1 /* A query may have a non-variable target list and a non-variable */ d123 1 a123 1 return (make_result (tlist, d133 14 a146 14 LispValue scan = make_seqscan (tlist, LispNil, _query_result_relation_, LispNil); if ( consp (constant_qual) ) { return (make_result (tlist, LispNil, constant_qual, scan, LispNil)); } else { return (scan); } d149 1 a149 1 d151 1 a151 1 return(LispNil); d191 3 a193 3 LispValue resttlist = LispNil; LispValue subtlist = LispNil; LispValue plan = LispNil; d198 4 a201 4 plan = make_result (new_result_tlist (tlist, subtlist, resttlist, currentlevel, d203 8 a210 7 new_result_qual(relation_level_clauses, subtlist, resttlist, currentlevel), constant_qual, subplan, restplan); d259 1 a259 1 LispValue @