home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************************
- ** * Recursion Planner (recurplanner.c) * **
- ** * Jimmy Bell * **
- ** * * **
- ***********************************************************************
- */
-
- /* RcsId ("$Header: /private/postgres/src/planner/plan/RCS/recurplanner.c,v 1.4 1990/10/17 15:36:00 choi Exp $"); */
-
- #include "planner/recurplanner.h"
- #include "parser/parsetree.h"
- #include "utils/log.h"
-
- /* ----------------
- * Recursive creator declaration
- * ----------------
- */
- extern Recursive RMakeRecursive();
-
-
- /* JJJ -DEBUGing routine */
- void
- Jshow (msg, obj)
- char *msg;
- LispValue obj;
- {
- printf("\n *** JJJ : %s : ", msg);
- lispDisplay(obj,0);
- }
- /* JJJ */
-
- /* JJJ -Message routine */
- void
- Jprint (msg)
- char *msg;
- {
- printf("\n *** JJJ -- %s -- ",msg);
- }
- /* JJJ */
-
-
-
-
- Recursive /* Recursive Node containing query plan */
- make_recursive (recursiveMethod, command, initPlans, loopPlans,
- cleanupPlans, checkpoints, resultRelationName)
- RecursiveMethod recursiveMethod;
- LispValue command;
- List initPlans;
- List loopPlans;
- List cleanupPlans;
- List checkpoints;
- LispValue resultRelationName;
- {
- Recursive node = RMakeRecursive();
-
- set_cost(node,0.0);
- set_fragment(node,0);
- set_state(node,(EState)NULL);
- set_qptargetlist(node,(TargetList)NULL);
- set_qpqual(node,LispNil);
- set_lefttree(node,(Plan)NULL);
- set_righttree(node,(Plan)NULL);
-
- set_recurMethod(node,recursiveMethod);
- set_recurCommand(node,command);
- set_recurInitPlans(node,initPlans);
- set_recurLoopPlans(node,loopPlans);
- set_recurCleanupPlans(node,cleanupPlans);
- set_recurCheckpoints(node,checkpoints);
- set_recurResultRelationName(node,resultRelationName);
-
- return(node);
- }
-
- /****
- * functions to facilitate conversions between the internal
- * form of plans and utility requests (like create FOO) and
- * their list equivalents.
- */
-
- GeneralPlan /* either a utility request or a plan */
- PlanOrUtilityToGeneralPlan (isUtility, planOrUtility)
- bool isUtility; /* false indicates 'plan' */
- PlanOrUtility planOrUtility;
- {
- GeneralPlan generalPlan;
-
- generalPlan.isUtility = isUtility;
- if (isUtility)
- generalPlan.planOrUtility.utility =
- lispString(planOrUtility.utility);
- else
- generalPlan.planOrUtility.plan = planOrUtility.plan;
-
- return generalPlan;
- }
-
- List /* List form of General Plan */
- GeneralPlanToList (generalPlan)
- GeneralPlan generalPlan; /* general plan to be converted */
- {
- if (generalPlan.isUtility)
- return lispCons(lispInteger(generalPlan.isUtility),
- lispCons(generalPlan.planOrUtility.utility,
- LispNil));
- else
- return lispCons(lispInteger(generalPlan.isUtility),
- lispCons(generalPlan.planOrUtility.plan,
- LispNil));
- }
-
- GeneralPlan /* General Plan extracted from List form */
- ListToGeneralPlan (list)
- List list; /* list being examined */
- {
- GeneralPlan generalPlan;
-
- if ( CInteger(CAR(list)) == 1 ) {
- generalPlan.isUtility = true;
- generalPlan.planOrUtility.utility =
- (UtilityRequest) CAR(CDR(list));
- }
- else {
- generalPlan.isUtility = false;
- generalPlan.planOrUtility.plan = (Plan) CAR(CDR(list));
- }
- return generalPlan;
- }
-
- GeneralPlan /* containing utility request from string */
- StringToGeneralPlan(str)
- String str;
- {
- GeneralPlan generalPlan;
-
- generalPlan.isUtility = true;
- generalPlan.planOrUtility.utility = lispString(str);
-
- return generalPlan;
- }
-
- /*
- * end of conversion functions
- *******
- */
-
- /*******
- * functions for checking linearity and verifying recursion
- */
-
- String /* name of result relation */
- ParseTreeGetResultRelationName(parseTree)
- ParseTree parseTree;
- {
- LispValue resultRelation;
- RangeTable rangeTable;
- String resultName;
-
- resultRelation = ParseTreeGetResultRelation( parseTree );
- rangeTable = ParseTreeGetRangeTable( parseTree );
-
- if ( null(resultRelation) )
- elog(WARN,"No result relation specified");
- else if ( lispIntegerp(resultRelation) )
- resultName = CString(rt_relname(
- nth (CInteger(resultRelation)-1,rangeTable)));
- else
- resultName = CString(CAR(CDR(resultRelation)));
-
- return resultName;
- }
-
- /*
- * ParseTreeGetVariablesOnResultRelation --
- * Take short-cut to approximate the number of tuple
- * var's used to refer to result relation. I count
- * occurrences of result's name string in range table.
- */
-
- int /* number of tuple variables on result relation */
- ParseTreeGetVariablesOnResultRelation(parseTree)
- ParseTree parseTree;
- {
- String resultName;
- RangeTable rangeTable;
- LispValue element;
- int count;
-
- rangeTable = ParseTreeGetRangeTable( parseTree );
- resultName = ParseTreeGetResultRelationName( parseTree );
- count = 0;
- foreach(element, rangeTable) {
- if ( strcmp(CString(rt_relname(CAR(element))),resultName) == 0 )
- count++;
- }
-
- return count;
- }
-
- /*
- * RecursiveQueryGetLinearity --
- * Returns the number of distinct tuple variables in the
- * query which reference the result relation. If the user
- * has not wasted tuple variables, this will be the level
- * of recursion. In delete and replace, a tuple variable
- * is automatically declared for the result relation.
- * Additional ones for any command are declared with the
- * "from" clause.
- *
- * Append* is only recursive if an assignment in the target list or
- * part of the qualification is based a tuple variable of
- * the result relation. If the user references the result
- * by name or declares tuple variables on it, assume recursive.
- *
- * Retrieve* is similar. We assume that the user has referenced
- * the result relation by name, so if any additional
- * tuple var's are declared for the result, we assume
- * non-linearity.
- *
- * Delete* is recursive only if an aggregate function or rule is
- * used which is sensitive either to a decrease in the
- * number of tuples, or to the absence of particular tuples.
- * The not-in operator is also hole-sensitive. If one of
- * these 3 references the result relation, it should be
- * assumed to be recursive (linear if exactly one tuple var).
- * We assume that since one provided it is used this way.
- * In the absence of not-in, this is not supported.
- *
- * Replace* is assumed to be recursive since mere assignment from
- * other relations based on a tuples field values can
- * cause tuples to requalify on the nexxt iteration. If
- * additional tuple var's are declared, assumed nonlinear.
- *
- * Execute* not supported at all.
- */
-
- int /* 0 if non-recursive, 1 if linear, 2+ if nonlinear */
- RecursiveQueryGetLinearity(parseTree)
- ParseTree parseTree;
- {
- int resultRelationVarCount;
-
- resultRelationVarCount =
- ParseTreeGetVariablesOnResultRelation(parseTree);
- switch ((Command) CInteger(ParseTreeGetCommandType(parseTree))) {
- case APPEND:
- case RETRIEVE:
- case DELETE:
- return resultRelationVarCount;
- break;
- case REPLACE:
- if ( resultRelationVarCount == 0 ) {
- return 1;
- }
- return ( resultRelationVarCount );
- case EXECUTE:
- elog(WARN,
- "RecursiveQueryGetLinearity: 'execute' not supported");
- default:
- elog(WARN,
- "RecursiveQueryGetLinearity: command not recognized");
- }
- }
-
- /*
- * RecursiveMethodChoose -
- * Determines which evaluation method to use on a recursive
- * query. Chooses between Naive and Seminaive based on a
- * simplified linearity check. Signals that the query is
- * not recursive at all by returning RecursiveMethodNone,
- * in which case the standard planner will take over.
- */
-
- RecursiveMethod /* the optimal evaluation method to use */
- RecursiveMethodChoose(parseTree)
- ParseTree parseTree; /* parse tree of query in question */
- {
- switch (RecursiveQueryGetLinearity(parseTree)) {
- case 0:
- return RecursiveMethodNone;
- break;
- case 1:
- return RecursiveMethodSemiNaive;
- break;
- default:
- return RecursiveMethodNaive;
- break;
- }
- }
-
- /* JJJ - Needed for hacky delete, but don't worry */
-
- /* assume clause has no subparts, since in cnf */
- bool /* true iff clause references given range table entry */
- ClauseRefersTo( clause, rangeTableIdx )
- List clause;
- LispValue rangeTableIdx;
- {
- /* *** DONE *** */
- List variableList;
-
- foreach(variableList,pull_var_clause(clause)) {
- if ( equal(rangeTableIdx,get_varno(CAR(variableList))) )
- return true;
- }
-
- return false;
- }
-
- List /* list of indexes to RT found in clause, except given one */
- ClauseGetOtherRefs ( clause, rangeTableIdx )
- List clause;
- LispValue rangeTableIdx;
- {
- /* *** DONE *** */
- List indexList;
- LispValue varNumber;
- List subList;
-
- indexList = lispList();
-
- foreach(subList,pull_var_clause(clause)) {
- varNumber = (LispValue) get_varno(CAR(subList));
- if (!equal(varNumber,rangeTableIdx) && !member(varNumber,indexList))
- indexList = append1(indexList,varNumber);
- }
-
- return indexList;
- }
-
- List /* list if RT indexes which only appear in one disjunct */
- BindingListGetSolos ( bindingList, conjunct )
- List bindingList;
- List conjunct;
- {
- /* *** DONE *** */
- LispValue index;
- List newBindingList;
- List list;
- List varList;
-
- newBindingList = lispList();
- varList = pull_var_clause(conjunct);
-
- foreach( list, bindingList ) {
- index = CAR(list);
- if ( ! member(index,varList) )
- newBindingList = append1(newBindingList,index);
- }
-
- return newBindingList;
- }
-
- /* JJJ remove_duplicates(foo,test);
- LispRemove(foo,bar); value bar;
- LispDelete(val,list); auto;
- set_difference(source,sub); value;
- push(this,onlist); value;
- integerp(foo);bool;
- findif;
- lispList(); value;
- */
-
-
- /*************
- * Removes the disjuncts which refer to the given tuple variable,
- * and recursively removes occurrences of tuple variables
- * which only have meaning in the presence of the deleted disjunct.
- *
- * Assumes qualification has already been preprocessed.
- *************
- */
- Qualification /* qual without references to certain variables */
- QualificationYankReferences(qual,rangeTableIdx)
- Qualification qual;
- LispValue rangeTableIdx;
- {
- Qualification newQual;
- LispValue list;
- LispValue subList;
- List bindingList;
- LispValue bindingSubList;
- List andClauseArg;
- List newAndClauseArgs;
- List orClauseArg;
- List newOrClauseArgs;
- LispValue newRangeTableIdx;
- bool isANotClause;
-
- /* Needs to be extended to deal with functions, etc. */
-
- /* qual is already preprocessed */
-
- if ( null(qual) )
- return qual;
- else if ( and_clause(qual) ) {
- newAndClauseArgs = lispList();
- foreach(list,get_andclauseargs(qual)) {
- andClauseArg = CAR(list);
- if ( not_clause(andClauseArg) ) {
- isANotClause = true;
- andClauseArg = get_orclauseargs(andClauseArg);
- }
- else
- isANotClause = false;
-
- /* JJJ *** need another check for NOT clauses */
-
- if ( or_clause(andClauseArg) ) {
- newOrClauseArgs = lispList();
- foreach(subList,get_orclauseargs(andClauseArg)) {
- orClauseArg = CAR(subList);
- if ( ClauseRefersTo(orClauseArg,rangeTableIdx) ) {
- /* omit it, and others (if this was necessary instance) */
- bindingList = ClauseGetOtherRefs(orClauseArg,rangeTableIdx);
- bindingList = BindingListGetSolos(bindingList,andClauseArg);
- /* construct newQual */
- newAndClauseArgs =
- append( newAndClauseArgs, ((isANotClause) ?
- make_notclause( make_orclause(append(
- newOrClauseArgs,subList))) :
- make_orclause(append(newOrClauseArgs,subList))) );
- newQual = make_andclause(append(newAndClauseArgs,
- list));
- foreach(bindingSubList,bindingList) {
- newQual = QualificationYankReferences(newQual,
- CAR(bindingSubList));
- }
- /* JJJ */ /* to avoid reconstructing my variables ... this is slow */
- return QualificationYankReferences(newQual,
- lispInteger(0));
- }
- else
- newOrClauseArgs = append1( newOrClauseArgs, orClauseArg );
- }
- newAndClauseArgs = append( newAndClauseArgs,
- ( (isANotClause) ? make_notclause(
- make_orclause(newOrClauseArgs)) :
- make_orclause(newOrClauseArgs)) );
- }
- else if ( is_clause(andClauseArg) ) {
- /* assume it is a simple qualification */
- if ( ! ClauseRefersTo(andClauseArg,rangeTableIdx) )
- newAndClauseArgs = append1( newAndClauseArgs,
- ( (isANotClause) ?
- make_notclause(andClauseArg ) :
- andClauseArg) );
- }
- else
- elog(WARN,"Bad And-Clause arg. in prep'd Qualification");
- }
- return make_andclause(newAndClauseArgs);
- }
- else if ( or_clause(qual) ) {
- newOrClauseArgs = lispList();
- foreach(list,get_orclauseargs(qual)) {
- orClauseArg = CAR(list);
- if ( ClauseRefersTo(orClauseArg,rangeTableIdx) ) {
- /* omit it, and leave others ... */
- }
- else
- newOrClauseArgs = append1( newOrClauseArgs, orClauseArg );
- }
- return make_orclause(newOrClauseArgs);
-
- }
- else if ( is_funcclause(qual) ) {
- elog(WARN,"Can't trim functions in recursion module");
- }
- else if ( not_clause(qual) ) {
- return make_notclause(
- QualificationYankReferences(get_notclausearg(qual),
- rangeTableIdx));
- }
- else if ( is_clause(qual) ) {
- if ( ClauseRefersTo(qual,rangeTableIdx) )
- return LispNil;
- else
- return qual;
- }
- else if ( single_node(qual) ) {
- elog(WARN,"Can't deal with single node in qualification");
- }
- else
- elog(WARN,"Unknown clause type in qualification");
-
-
- return qual;
- }
-
- /*
- * RetrieveRemoveRecursion --
- * Removes recursive traits from the qualification of the
- * query's parsetree. Does not affect target list, since
- * the query as written is assumed to work in the absence
- * of the result relation for the first pass. This view
- * of the command may change in the future.
- *
- * Does not change the range table, so hopefully the
- * most efficient plan will still be produced. And
- * hopefully no code depend on all the relations in the
- * range table begin used.
- */
-
- ParseTree /* parse tree of retrieve without self-reference */
- RetrieveRemoveRecursion (parseTree)
- ParseTree parseTree;
- {
- Qualification qual;
- Qualification newQual;
-
- qual = cnfify(ParseTreeGetQualification(parseTree),
- ParseTreeGetTargetList(parseTree));
- newQual = cnfify(QualificationYankReferences(qual,0),
- ParseTreeGetTargetList(parseTree));
-
- return lispCons(ParseTreeGetRoot(parseTree),
- lispCons(ParseTreeGetTargetList(parseTree),
- lispCons(newQual, LispNil)));
- }
-
- LispValue /* new index into range table */
- RangeTableGetReplacementIndex(rangeTable,newRelationName,oldIndex)
- RangeTable rangeTable;
- String newRelationName;
- LispValue oldIndex;
- {
- String oldName;
- int countVarsWithOldName;
- int currentIndex;
- List list;
- int countVarsWithNewName;
- int i;
-
- oldName = CString(rt_relname(nth(CInteger(oldIndex)-1,rangeTable)));
-
- countVarsWithOldName = 0;
- currentIndex = 0;
- foreach( list, rangeTable ) {
- currentIndex += 1;
- if ( strcmp(CString(rt_relname(CAR(list))),oldName) == 0 ) {
- countVarsWithOldName += 1;
- if ( currentIndex == CInteger(oldIndex) )
- break;
- }
- }
-
- countVarsWithNewName = 0;
- currentIndex = 0;
- foreach( list, rangeTable ) {
- currentIndex += 1;
- if ( strcmp(CString(rt_relname(CAR(list))),newRelationName) == 0 ) {
- countVarsWithNewName += 1;
- if ( countVarsWithNewName == countVarsWithOldName ) {
- return lispInteger(currentIndex);
- }
- }
- }
-
- /* not found, so create enough new entries */
- for( i = 1; i <= (countVarsWithOldName - countVarsWithNewName); i++ ) {
- nappend1(rangeTable,lispCons(lispString(newRelationName),
- lispCons(lispInteger(0),
- lispCons(lispInteger(0),
- lispCons(LispNil,
- lispCons(LispNil, LispNil))))) );
-
- }
-
- return
- lispInteger( currentIndex + countVarsWithOldName - countVarsWithNewName );
- }
-
- void /* doesn't assume cnf form */
- ClauseInstallTemps(clause,oldResultRelation,newChiefResultName,newExtraResultName,rangeTable)
- List clause;
- LispValue oldResultRelation;
- String newChiefResultName; /* main var for result */
- String newExtraResultName; /* others found in parse */
- RangeTable rangeTable; /* to be changed, if needed */
- {
- int oldChiefResultIndex;
- String oldResultName;
- LispValue newRangeTableIndex;
- List list;
-
- /* JJJ **** redo */
- oldChiefResultIndex = CInteger(oldResultRelation);
- oldResultName = CString(rt_relname(nth(oldChiefResultIndex-1,rangeTable)));
-
- if ( null(clause) )
- return;
- else if (IsA (clause,Var)) {
- /* may need refining */
- if ( ( newChiefResultName != NULL ) &&
- ( CInteger(get_varno(clause)) == oldChiefResultIndex ) ) {
- newRangeTableIndex = RangeTableGetReplacementIndex(rangeTable,
- newChiefResultName,
- get_varno(clause));
- set_varno(clause, newRangeTableIndex);
- CAR(get_varid(clause)) = newRangeTableIndex;
- }
- else if ( ( newExtraResultName != NULL ) &&
- ( strcmp(CString(rt_relname(nth(CInteger(get_varno(clause))-1,
- rangeTable))),
- oldResultName) == 0 ) ) {
- newRangeTableIndex = RangeTableGetReplacementIndex(rangeTable,
- newExtraResultName,
- get_varno(clause));
- set_varno(clause, newRangeTableIndex);
- CAR(get_varid(clause)) = newRangeTableIndex;
- }
- else {
- /* leave it alone */
- }
- }
- else if ( single_node (clause) )
- return;
- else if ( and_clause(clause) ) {
- foreach( list, get_andclauseargs(clause) ) {
- ClauseInstallTemps(CAR(list),
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable);
- }
- return;
- }
- else if ( or_clause(clause) ) {
- foreach( list, get_orclauseargs(clause) ) {
- ClauseInstallTemps(CAR(list),
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable);
- }
- return;
- }
- else if ( is_funcclause(clause) ) {
- foreach( list, get_funcargs(clause) ) {
- ClauseInstallTemps(CAR(list),
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable);
- }
- return;
- }
- else if ( not_clause(clause) ) {
- ClauseInstallTemps(get_notclausearg(clause),
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable);
-
- return;
- }
- else if ( is_clause(clause) ) {
- ClauseInstallTemps(get_leftop(clause),
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable);
- ClauseInstallTemps(get_rightop(clause),
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable);
- return;
- }
- else
- elog(WARN,"Can't install temporaries in this clause");
- }
-
- void
- TargetListInstallTemps(targetList,
- oldResultRelation,
- newChiefResultName,
- newExtraResultName,
- rangeTable)
- TargetList targetList; /* to be modified */
- LispValue oldResultRelation;
- String newChiefResultName; /* main var for result */
- String newExtraResultName; /* others found in parse */
- RangeTable rangeTable; /* to be changed, if needed */
- {
- int oldChiefResultIndex;
- String oldResultName;
- LispValue newRangeTableIndex;
- LispValue resultNumber;
- List list;
-
- oldChiefResultIndex = CInteger(oldResultRelation);
- oldResultName = CString(rt_relname(nth(oldChiefResultIndex-1,rangeTable)));
-
- foreach( list, targetList ) {
- resultNumber = lispInteger(get_resno(tl_resdom(CAR(list))));
- if ( CInteger(resultNumber) == oldChiefResultIndex ) {
- if ( newChiefResultName != NULL ) {
- /*
- newRangeTableIndex = RangeTableGetReplacementIndex(rangeTable,
- newChiefResultName,
- resultNumber);
- set_resno(tl_resdom(CAR(list)), newRangeTableIndex);
- */
- /* JJJ -- ask jeff how to recurse down expressions */
- }
- }
- else if ( strcmp(CString(rt_relname(nth(CInteger(resultNumber)-1,
- rangeTable))),
- oldResultName) == 0 ) {
- if ( newExtraResultName != NULL ) {
- /*
- newRangeTableIndex = RangeTableGetReplacementIndex(rangeTable,
- newExtraResultName,
- resultNumber);
- set_resno(tl_resdom(CAR(list)), newRangeTableIndex);
- */
- /* JJJ -- ask jeff how to recurse down expressions */
- }
- }
- else {
- /* leave it alone ??? */
- /* JJJ -- ask jeff how to recurse down expressions */
- }
-
- }
- }
-
- Plan /* plan for recursive query, with recursion node at root */
- RecursiveQueryPlan (parseTree)
- ParseTree parseTree; /* parse tree of query in question */
- {
- /* JJJ * current */
- ParseTree preppedParseTree;
- TargetList preppedTargetList;
- Qualification preppedQualification;
-
- ParseTree scratchParseTree;
- RangeTable scratchRangeTable; /* don't change pointer */
- Plan scratchPlan;
-
- String scratchString;
-
- List initPlans;
- List loopPlans;
- List cleanupPlans;
-
- List preppedResultRelation;
- String preppedResultRelationName;
- LispValue preppedCommandType;
-
- const String tempRelationFakeNameA = "pg_temp_A";
- const String tempRelationFakeNameB = "pg_temp_B";
- /* ** */
-
-
- ParseTree pureRecursiveQuery;
- ParseTree newParseTree;
- ParseTree workParseTree;
- LispValue newCommandType;
- List newResultRelation;
- List newRoot;
- Plan stdPlan;
- Plan newPlan;
- Plan newPlan2;
- Plan newPlan3;
- Plan pureRecursivePlan;
- RecursiveMethod recursiveMethod;
- List checkpoints;
- String utility;
- String commandString;
- String commandString2;
-
- Jprint("RecursiveQueryPlan");
-
- if ( null(ParseTreeGetResultRelation(parseTree)) ) {
- elog(WARN,
- "RecursiveQueryPlan: retrieve* to portal not supported");
- }
-
- recursiveMethod = RecursiveMethodChoose(parseTree);
- if ( recursiveMethod == RecursiveMethodNone )
- return (Plan)NULL;
-
- Jprint("passed recur. test");
-
- /* JJJ *** current variables *** */
- preppedParseTree = (ParseTree) lispCopy(parseTree);
-
- Jshow("prepped parse tree",preppedParseTree);
-
- preppedResultRelation = ParseTreeGetResultRelation( preppedParseTree );
- preppedResultRelationName =
- ParseTreeGetResultRelationName( preppedParseTree );
- preppedTargetList =
- preprocess_targetlist(ParseTreeGetTargetList(preppedParseTree),
- CInteger(ParseTreeGetCommandType(preppedParseTree)),
- ParseTreeGetResultRelation(preppedParseTree),
- ParseTreeGetRangeTable(preppedParseTree));
- ParseTreeGetTargetList(preppedParseTree) = preppedTargetList;
-
- Jshow("prepped parse tree after tl",preppedParseTree);
-
- preppedQualification = cnfify(ParseTreeGetQualification(preppedParseTree));
-
- Jshow("qual after cnf",preppedQualification);
-
- ParseTreeGetQualification(preppedParseTree) = preppedQualification;
-
- Jshow("prepped parse tree after q",preppedParseTree);
-
- preppedCommandType = ParseTreeGetCommandType(preppedParseTree);
-
- /* scratch stuff */
- scratchParseTree = (ParseTree) lispCopy(preppedParseTree);
- scratchRangeTable = ParseTreeGetRangeTable(scratchParseTree);
- /* *** */
-
-
-
- /* JJJ ****** check setf and == and = */
-
- switch (recursiveMethod) {
- case RecursiveMethodNaive:
-
- Jprint("Naive");
-
- switch ((Command) CInteger(preppedCommandType)) {
- case APPEND:
- Jprint("Append");
- /* JJJ *** DONE *** */
- /* -------------------------
- * Example : append* ANCESTOR( PARENT.name, PARENT.father )
- * where PARENT.name = "Jimmy"
- * or ANCESTOR.ancestor = PARENT.name
- *
- * Goes to :
- * INIT - append ANCESTOR( name = PARENT.name, ancestor = PARENT.father )
- * where PARENT.name = "Jimmy"
- * or ANCESTOR.ancestor = PARENT.name
- *
- * LOOP - append ANCESTOR( name = PARENT.name, ancestor = PARENT.father )
- * where PARENT.name = "Jimmy"
- * or ANCESTOR.ancestor = PARENT.name
- *
- * CLEANUP - (nothing)
- * -------------------------
- */
-
- /* --------------
- * INIT :
- * "append ANCESTOR( name = PARENT.name, ancestor = PARENT.father )
- * where PARENT.name = "Jimmy"
- * or ANCESTOR.ancestor = PARENT.name"
- * requires no changes in result variables, since no temps used.
- * It is the original query.
- * --------------
- */
- stdPlan = planner(parseTree);
- loopPlans = lispCons(PlanToList(stdPlan),LispNil);
- checkpoints = lispCons(lispInteger(1),LispNil);
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- LispNil,
- loopPlans,
- LispNil,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case REPLACE:
- Jprint("replace");
- /* JJJ *** DONE *** */
- stdPlan = planner(parseTree);
- loopPlans = lispCons(PlanToList(stdPlan),LispNil);
- checkpoints = lispCons(lispInteger(1),LispNil);
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- LispNil,
- loopPlans,
- LispNil,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case RETRIEVE:
- /* only 'retrieve* into' supported */
- Jprint("retrieve");
- /* same as 'append', but place retrieve in init */
-
- newParseTree = RetrieveRemoveRecursion(parseTree);
- stdPlan = planner(newParseTree);
-
- /* convert to 'append' */
- newCommandType = lispAtom("append");
- /* JJJ - first check for actual resultName */
- /* JJJ - need dummy id */
- newResultRelation = lispString("pg_temp_result");
- /* hope target list and qual can remain same */
-
- initPlans = lispCons(UtilityToList(utility),LispNil);
-
- /* same as APPEND */
-
- loopPlans = lispCons(PlanToList(stdPlan),LispNil);
- checkpoints = lispCons(lispInteger(1),LispNil);
-
- /* same as APPEND */
-
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- initPlans,
- loopPlans,
- LispNil,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case DELETE:
- Jprint("Delete");
- /* JJJ *** DONE *** */
- stdPlan = planner(parseTree);
- loopPlans = lispCons(PlanToList(stdPlan),LispNil);
- checkpoints = lispCons(lispInteger(1),LispNil);
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- LispNil,
- loopPlans,
- LispNil,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case EXECUTE:
- /* JRB -- Not a part of my master's project */
- elog(WARN,
- "RecursiveQueryPlan: 'execute' not supported");
- break;
- default:
- elog(WARN,"RecursiveQueryPlan: command not supported");
- break;
- }
- case RecursiveMethodSemiNaive:
- Jprint("Seminaive");
- switch ((Command) CInteger(preppedCommandType)) {
- case APPEND:
- Jprint("append");
- /** build initPlans **/
- /* make 'retrieve' */
- newCommandType = lispAtom("retrieve");
- newResultRelation = lispCons(lispAtom("into"),
- lispCons(lispString("pg_temp_A"),
- LispNil));
- /* should also do a "not-in <result>" check */
- newRoot = lispCons(ParseTreeGetNumLevels(parseTree),
- lispCons(newCommandType,
- lispCons(newResultRelation,
- CDR(CDR(CDR(CAR(parseTree)))))));
- newParseTree = lispCons(newRoot,CDR(parseTree));
- newPlan = planner(newParseTree);
- initPlans = lispCons(PlanToList(newPlan),LispNil);
-
- /* make 'append' */
- commandString = (String) palloc(strlen(
- "append foo ( pg_temp_A.all )")
- + RELATION_NAME_LENGTH );
- sprintf(commandString,"append %s ( pg_temp_A.all )",
- preppedResultRelationName);
- initPlans = append1(initPlans,
- StringToList(commandString));
-
- /** build loopPlans **/
-
- /* JJJ */ /* convert new plan to refer to tempB and tempA */
- loopPlans = lispCons(PlanToList(newPlan),LispNil);
-
- /* make 'append' */
- sprintf(commandString,"append %s ( pg_temp_B.all )",
- preppedResultRelationName);
- loopPlans = append1(loopPlans,
- StringToList(commandString));
-
- /* make 'destroy' */
- commandString2 = (String) palloc(strlen(
- "destroy pg_temp_A" + 1));
- sprintf(commandString2,"destroy pg_temp_A");
- loopPlans = append1(loopPlans,
- StringToList(commandString2));
- /* JJJ redo */ checkpoints = lispCons(lispInteger(1),LispNil);
-
- /** build cleanupPlans **/
- /* make 'destroy' */
- sprintf(commandString2,"destroy pg_temp_B");
- cleanupPlans = lispCons(StringToList(commandString2),
- LispNil);
-
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- initPlans,
- loopPlans,
- cleanupPlans,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case REPLACE:
- Jprint("replace");
- /*** JJJ - needs work ***/
- /* -------------------------
- * Example : replace* FOO( name = P.father )
- * where FOO.name = P.name
- *
- * Goes to :
- * INIT - retrieve into tempA( name = P.father, ... , x = FOO.x )
- * where FOO.name = P.name
- * delete FOO
- * where FOO.name = P.name
- * append FOO( tempA.all )
- *
- * LOOP - retrieve into tempB( name = P.father, ... , x = tempA.x )
- * where tempA.name = P.name
- * delete tempA
- * where tempA.name = P.name
- * delete FOO
- * where FOO.name = P.name
- * append FOO( tempA.all )
- * destroy tempB
- *
- * CLEANUP - destroy tempA
- * -------------------------
- */
-
- /* --------------
- * INIT :
- * "retrieve into tempA( name = P.father, ... , x = FOO.x )
- * where FOO.name = P.name"
- * requires no changes in result variables
- * --------------
- */
- scratchParseTree =
- (ParseTree) lispCopy(preppedParseTree);
-
- ParseTreeGetCommandType(scratchParseTree) =
- lispAtom("retrieve");
- ParseTreeGetResultRelation(scratchParseTree) =
- lispCons(lispAtom("into"),
- lispCons(lispString(tempRelationFakeNameA),
- LispNil));
- /* ---------
- * We should insure that new tuple is not-in target
- * ---------
- */
-
- scratchPlan = planner(scratchParseTree);
- /* JJJ following should reserve new copy */
- initPlans = lispCons(PlanToList(scratchPlan),LispNil);
-
- /* --------------
- * "delete FOO
- * where FOO.name = P.name"
- * its result variable is same as replace*
- * --------------
- */
- ParseTreeGetCommandType(scratchParseTree) =
- lispAtom("delete");
- ParseTreeGetResultRelation(scratchParseTree) =
- preppedResultRelation;
-
- scratchPlan = planner(scratchParseTree);
- /* JJJ following should reserve new copy */
- initPlans = append1(initPlans,PlanToList(scratchPlan));
-
- /* --------------
- * "append FOO ( tempA.all )"
- * is written as a utility string
- * --------------
- */
- scratchString = (String) palloc(strlen(
- "append foo ( pg_temp_A.all )")
- + RELATION_NAME_LENGTH );
- sprintf(scratchString,"append %s ( pg_temp_A.all )",
- preppedResultRelationName);
-
- initPlans = append1(initPlans,
- StringToList(scratchString));
-
- /* --------------
- * LOOP:
- * "retrieve into tempB( name = P.father, ... , x = tempA.x )
- * where tempA.name = P.name"
- * requires changing only the extra result var's to tempA,
- * and the minor change of result relation string to tempB
- * --------------
- */
- ParseTreeGetCommandType(scratchParseTree) =
- lispAtom("retrieve");
- ParseTreeGetResultRelation(scratchParseTree) =
- lispCons(lispAtom("into"),
- lispCons(lispString(tempRelationFakeNameB),
- LispNil));
- /* ---------
- * We should insure that new tuple is not-in target
- * ---------
- */
-
- ClauseInstallTemps(preppedQualification,
- preppedResultRelation,
- NULL,
- tempRelationFakeNameA,
- scratchRangeTable);
-
- TargetListInstallTemps(preppedTargetList,
- preppedResultRelation,
- NULL,
- tempRelationFakeNameA,
- scratchRangeTable);
-
- scratchPlan = planner(scratchParseTree);
- /* JJJ following should reserve new copy */
- loopPlans = lispCons(PlanToList(scratchPlan),LispNil);
-
- /* --------------
- * "delete tempA
- * where tempA.name = P.name"
- * change all references to result to be tempA
- * --------------
- */
- ParseTreeGetCommandType(scratchParseTree) =
- lispAtom("delete");
- ParseTreeGetResultRelation(scratchParseTree) =
- RangeTableGetReplacementIndex(scratchRangeTable,
- tempRelationFakeNameA,
- preppedResultRelation);
-
- ClauseInstallTemps(preppedQualification,
- preppedResultRelation,
- NULL,
- tempRelationFakeNameA,
- scratchRangeTable);
-
- TargetListInstallTemps(preppedTargetList,
- preppedResultRelation,
- NULL,
- tempRelationFakeNameA,
- scratchRangeTable);
-
- scratchPlan = planner(scratchParseTree);
- loopPlans = append1(loopPlans,PlanToList(scratchPlan));
-
- /* --------------
- * "delete FOO
- * where FOO.name = P.name"
- * its result variable is same as replace*
- * --------------
- */
- ParseTreeGetCommandType(scratchParseTree) =
- lispAtom("delete");
- ParseTreeGetResultRelation(scratchParseTree) =
- preppedResultRelation;
-
- scratchPlan = planner(scratchParseTree);
- /* JJJ following should reserve new copy */
- loopPlans = append1(loopPlans,PlanToList(scratchPlan));
-
- /* --------------
- * "append FOO ( tempA.all )"
- * is written as a utility string
- * --------------
- */
- scratchString = (String) palloc(strlen(
- "append foo ( pg_temp_A.all )")
- + RELATION_NAME_LENGTH );
- sprintf(scratchString,"append %s ( pg_temp_A.all )",
- preppedResultRelationName);
-
- loopPlans = append1(loopPlans,
- StringToList(scratchString));
-
- /* --------------
- * "destroy tempB"
- * is written as a utility string
- * --------------
- */
- loopPlans = append1(loopPlans,
- StringToList("destroy pg_temp_B"));
-
- /* JJJ *** Remember checkpoints */
- checkpoints = lispCons(lispInteger(1),LispNil);
-
- /* --------------
- * CLEANUP:
- * "destroy tempA"
- * --------------
- */
- cleanupPlans = lispCons(
- StringToList("destroy pg_temp_A"));
-
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- initPlans,
- loopPlans,
- cleanupPlans,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case RETRIEVE:
- /* only 'retrieve* into' supported */
- Jprint("retrieve");
- sprintf(utility,"create %s",preppedResultRelationName);
-
- newParseTree = RetrieveRemoveRecursion(parseTree);
-
-
- /* just create, and do append */
-
- stdPlan = planner(newParseTree);
- initPlans = lispCons(StringToList(utility),LispNil);
- loopPlans = lispCons(PlanToList(stdPlan),LispNil);
- checkpoints = lispCons(lispInteger(1),LispNil);
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- initPlans,
- loopPlans,
- LispNil,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case DELETE:
- Jprint("delete");
- /* change to retrieve into */
-
- /* simple deletes */
-
- stdPlan = planner(parseTree);
- loopPlans = lispCons(PlanToList(stdPlan),LispNil);
- checkpoints = lispCons(lispInteger(1),LispNil);
- return (Plan) make_recursive(recursiveMethod,
- preppedCommandType,
- LispNil,
- loopPlans,
- LispNil,
- checkpoints,
- lispString(preppedResultRelationName));
- break;
- case EXECUTE:
- /* JRB -- Not a part of my master's project */
- elog(WARN,
- "RecursiveQueryPlan: 'execute' not supported");
- break;
- default:
- elog(WARN,"RecursiveQueryPlan: command not supported");
- break;
- }
- }
- }
-