diff options
Diffstat (limited to 'src/backend/commands/recipe.c')
-rw-r--r-- | src/backend/commands/recipe.c | 2130 |
1 files changed, 1166 insertions, 964 deletions
diff --git a/src/backend/commands/recipe.c b/src/backend/commands/recipe.c index e6aa009bd33..bf05c293d13 100644 --- a/src/backend/commands/recipe.c +++ b/src/backend/commands/recipe.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * recipe.c-- - * routines for handling execution of Tioga recipes + * routines for handling execution of Tioga recipes * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.6 1997/08/12 20:15:11 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.7 1997/09/07 04:40:53 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,7 @@ #include <commands/recipe.h> #include <libpq/libpq-be.h> #include <utils/builtins.h> -#include <utils/relcache.h> /* for RelationNameGetRelation*/ +#include <utils/relcache.h> /* for RelationNameGetRelation */ #include <parser/parse_query.h> #include <rewrite/rewriteHandler.h> #include <rewrite/rewriteManip.h> @@ -35,9 +35,12 @@ extern CommandDest whereToSendOutput; #ifndef TIOGA -void beginRecipe(RecipeStmt *stmt) { - elog(NOTICE,"You must compile with TIOGA defined in order to use recipes\n"); +void +beginRecipe(RecipeStmt * stmt) +{ + elog(NOTICE, "You must compile with TIOGA defined in order to use recipes\n"); } + #else #include <tioga/tgRecipe.h> @@ -45,49 +48,59 @@ void beginRecipe(RecipeStmt *stmt) { #define DEBUG_RECIPE 1 /* structure to keep track of the tee node plans */ -typedef struct _teePlanInfo { - char* tpi_relName; - Query* tpi_parsetree; - Plan* tpi_plan; -} TeePlanInfo; - -typedef struct _teeInfo { - int num; - TeePlanInfo *val; -} TeeInfo; - -QueryTreeList *appendQlist(QueryTreeList *q1, QueryTreeList *q2); -void OffsetVarAttno(Node* node, int varno, int offset); - -static void appendTeeQuery(TeeInfo *teeInfo, - QueryTreeList *q, - char* teeNodeName); - -static Plan* replaceTeeScans(Plan* plan, - Query* parsetree, - TeeInfo *teeInfo); -static void replaceSeqScan(Plan* plan, - Plan* parent, - int rt_ind, - Plan* tplan); - -static void tg_rewriteQuery(TgRecipe* r, TgNode *n, - QueryTreeList *q, - QueryTreeList *inputQlist); -static Node *tg_replaceNumberedParam(Node* expression, - int pnum, - int rt_ind, - char *teeRelName); -static Node *tg_rewriteParamsInExpr(Node *expression, - QueryTreeList *inputQlist); -static QueryTreeList *tg_parseSubQuery(TgRecipe* r, - TgNode* n, - TeeInfo* teeInfo); -static QueryTreeList* tg_parseTeeNode(TgRecipe *r, - TgNode *n, - int i, - QueryTreeList *qList, - TeeInfo* teeInfo); +typedef struct _teePlanInfo +{ + char *tpi_relName; + Query *tpi_parsetree; + Plan *tpi_plan; +} TeePlanInfo; + +typedef struct _teeInfo +{ + int num; + TeePlanInfo *val; +} TeeInfo; + +QueryTreeList *appendQlist(QueryTreeList * q1, QueryTreeList * q2); +void OffsetVarAttno(Node * node, int varno, int offset); + +static void +appendTeeQuery(TeeInfo * teeInfo, + QueryTreeList * q, + char *teeNodeName); + +static Plan * +replaceTeeScans(Plan * plan, + Query * parsetree, + TeeInfo * teeInfo); +static void +replaceSeqScan(Plan * plan, + Plan * parent, + int rt_ind, + Plan * tplan); + +static void +tg_rewriteQuery(TgRecipe * r, TgNode * n, + QueryTreeList * q, + QueryTreeList * inputQlist); +static Node * +tg_replaceNumberedParam(Node * expression, + int pnum, + int rt_ind, + char *teeRelName); +static Node * +tg_rewriteParamsInExpr(Node * expression, + QueryTreeList * inputQlist); +static QueryTreeList * +tg_parseSubQuery(TgRecipe * r, + TgNode * n, + TeeInfo * teeInfo); +static QueryTreeList * +tg_parseTeeNode(TgRecipe * r, + TgNode * n, + int i, + QueryTreeList * qList, + TeeInfo * teeInfo); /* @@ -96,172 +109,192 @@ static QueryTreeList* tg_parseTeeNode(TgRecipe *r, To parse a Tioga recipe, we start from an eye node and go backwards through its input nodes. To rewrite a Tioga node, we do the following: - 1) parse the node we're at in the standard way (calling parser() ) - 2) rewrite its input nodes recursively using Tioga rewrite - 3) now, with the rewritten input parse trees and the original parse tree - of the node, we rewrite the the node. - To do the rewrite, we use the target lists, range tables, and - qualifications of the input parse trees + 1) parse the node we're at in the standard way (calling parser() ) + 2) rewrite its input nodes recursively using Tioga rewrite + 3) now, with the rewritten input parse trees and the original parse tree + of the node, we rewrite the the node. + To do the rewrite, we use the target lists, range tables, and + qualifications of the input parse trees */ /* * beginRecipe: - * this is the main function to recipe execution - * this function is invoked for EXECUTE RECIPE ... statements - * - * takes in a RecipeStmt structure from the parser + * this is the main function to recipe execution + * this function is invoked for EXECUTE RECIPE ... statements + * + * takes in a RecipeStmt structure from the parser * and returns a list of cursor names */ void -beginRecipe(RecipeStmt* stmt) +beginRecipe(RecipeStmt * stmt) { - TgRecipe* r; - int i; - QueryTreeList *qList; - char portalName[1024]; - - Plan *plan; - TupleDesc attinfo; - QueryDesc *queryDesc; - Query *parsetree; - - int numTees; - TeeInfo* teeInfo; - - /* retrieveRecipe() reads the recipe from the database - and returns a TgRecipe* structure we can work with */ - - r = retrieveRecipe(stmt->recipeName); - - if (r == NULL) return; - - /* find the number of tees in the recipe */ - numTees = r->tees->num; - - if (numTees > 0) { - /* allocate a teePlan structure */ - teeInfo = (TeeInfo*)malloc(sizeof(TeeInfo)); - teeInfo->num = numTees; - teeInfo->val = (TeePlanInfo*)malloc(numTees * sizeof(TeePlanInfo)); - for (i=0;i<numTees;i++) { - teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName; - teeInfo->val[i].tpi_parsetree = NULL; - teeInfo->val[i].tpi_plan = NULL; - } - } else - teeInfo = NULL; - - /* - * for each viewer in the recipe, go backwards from each viewer input - * and generate a plan. Attach the plan to cursors. - **/ - for (i=0;i<r->eyes->num;i++) { - TgNodePtr e; - - e = r->eyes->val[i]; - if (e->inNodes->num > 1) { - elog(NOTICE, - "beginRecipe: Currently eyes cannot have more than one input"); - } - if (e->inNodes->num == 0) { - /* no input to this eye, skip it */ - continue; - } + TgRecipe *r; + int i; + QueryTreeList *qList; + char portalName[1024]; + + Plan *plan; + TupleDesc attinfo; + QueryDesc *queryDesc; + Query *parsetree; + + int numTees; + TeeInfo *teeInfo; + + /* + * retrieveRecipe() reads the recipe from the database and returns a + * TgRecipe* structure we can work with + */ + + r = retrieveRecipe(stmt->recipeName); + + if (r == NULL) + return; + + /* find the number of tees in the recipe */ + numTees = r->tees->num; + + if (numTees > 0) + { + /* allocate a teePlan structure */ + teeInfo = (TeeInfo *) malloc(sizeof(TeeInfo)); + teeInfo->num = numTees; + teeInfo->val = (TeePlanInfo *) malloc(numTees * sizeof(TeePlanInfo)); + for (i = 0; i < numTees; i++) + { + teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName; + teeInfo->val[i].tpi_parsetree = NULL; + teeInfo->val[i].tpi_plan = NULL; + } + } + else + teeInfo = NULL; + + /* + * for each viewer in the recipe, go backwards from each viewer input + * and generate a plan. Attach the plan to cursors. + */ + for (i = 0; i < r->eyes->num; i++) + { + TgNodePtr e; + + e = r->eyes->val[i]; + if (e->inNodes->num > 1) + { + elog(NOTICE, + "beginRecipe: Currently eyes cannot have more than one input"); + } + if (e->inNodes->num == 0) + { + /* no input to this eye, skip it */ + continue; + } #ifdef DEBUG_RECIPE - elog(NOTICE,"beginRecipe: eyes[%d] = %s\n", i, e->nodeName); -#endif /* DEBUG_RECIPE */ - - qList = tg_parseSubQuery(r,e->inNodes->val[0], teeInfo); - - if (qList == NULL) { - /* eye is directly connected to a tee node */ - /* XXX TODO: handle this case */ - } - - /* now, plan the queries */ - /* should really do everything pg_plan() does, but for now, - we skip the rule rewrite and time qual stuff */ - - /* ---------------------------------------------------------- - * 1) plan the main query, everything from an eye node back to - a Tee - * ---------------------------------------------------------- */ - parsetree = qList->qtrees[0]; - - /* before we plan, we want to see all the changes - we did, during the rewrite phase, such as - creating the tee tables, - setheapoverride() allows us to see the changes */ - setheapoverride(true); - plan = planner(parsetree); - - /* ---------------------------------------------------------- - * 2) plan the tee queries, (subgraphs rooted from a Tee) - by the time the eye is processed, all tees that contribute - to that eye will have been included in the teeInfo list - * ---------------------------------------------------------- */ - if (teeInfo) { - int t; - Plan* tplan; - Tee* newplan; - - for (t=0; t<teeInfo->num;t++) { - if (teeInfo->val[t].tpi_plan == NULL) { - /* plan it in the usual fashion */ - tplan = planner(teeInfo->val[t].tpi_parsetree); - - /* now add a tee node to the root of the plan */ -elog(NOTICE, "adding tee plan node to the root of the %s\n", - teeInfo->val[t].tpi_relName); - newplan = (Tee*)makeNode(Tee); - newplan->plan.targetlist = tplan->targetlist; - newplan->plan.qual = NULL; /* tplan->qual; */ - newplan->plan.lefttree = tplan; - newplan->plan.righttree = NULL; - newplan->leftParent = NULL; - newplan->rightParent = NULL; - /* the range table of the tee is the range table - of the tplan */ - newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable; - strcpy(newplan->teeTableName, - teeInfo->val[t].tpi_relName); - teeInfo->val[t].tpi_plan = (Plan*)newplan; - } - } - - /* ---------------------------------------------------------- - * 3) replace the tee table scans in the main plan with - actual tee plannodes - * ---------------------------------------------------------- */ - - plan = replaceTeeScans(plan, parsetree, teeInfo); - - } /* if (teeInfo) */ - - setheapoverride(false); - - /* define a portal for this viewer input */ - /* for now, eyes can only have one input */ - sprintf(portalName, "%s%d",e->nodeName,0); - - queryDesc = CreateQueryDesc(parsetree, - plan, - whereToSendOutput); - /* ---------------- - * call ExecStart to prepare the plan for execution - * ---------------- - */ - attinfo = ExecutorStart(queryDesc,NULL); - - ProcessPortal(portalName, - parsetree, - plan, - attinfo, - whereToSendOutput); -elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName); - } + elog(NOTICE, "beginRecipe: eyes[%d] = %s\n", i, e->nodeName); +#endif /* DEBUG_RECIPE */ + + qList = tg_parseSubQuery(r, e->inNodes->val[0], teeInfo); + + if (qList == NULL) + { + /* eye is directly connected to a tee node */ + /* XXX TODO: handle this case */ + } + + /* now, plan the queries */ + + /* + * should really do everything pg_plan() does, but for now, we + * skip the rule rewrite and time qual stuff + */ + + /* ---------------------------------------------------------- + * 1) plan the main query, everything from an eye node back to + a Tee + * ---------------------------------------------------------- */ + parsetree = qList->qtrees[0]; + + /* + * before we plan, we want to see all the changes we did, during + * the rewrite phase, such as creating the tee tables, + * setheapoverride() allows us to see the changes + */ + setheapoverride(true); + plan = planner(parsetree); + + /* ---------------------------------------------------------- + * 2) plan the tee queries, (subgraphs rooted from a Tee) + by the time the eye is processed, all tees that contribute + to that eye will have been included in the teeInfo list + * ---------------------------------------------------------- */ + if (teeInfo) + { + int t; + Plan *tplan; + Tee *newplan; + + for (t = 0; t < teeInfo->num; t++) + { + if (teeInfo->val[t].tpi_plan == NULL) + { + /* plan it in the usual fashion */ + tplan = planner(teeInfo->val[t].tpi_parsetree); + + /* now add a tee node to the root of the plan */ + elog(NOTICE, "adding tee plan node to the root of the %s\n", + teeInfo->val[t].tpi_relName); + newplan = (Tee *) makeNode(Tee); + newplan->plan.targetlist = tplan->targetlist; + newplan->plan.qual = NULL; /* tplan->qual; */ + newplan->plan.lefttree = tplan; + newplan->plan.righttree = NULL; + newplan->leftParent = NULL; + newplan->rightParent = NULL; + + /* + * the range table of the tee is the range table of + * the tplan + */ + newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable; + strcpy(newplan->teeTableName, + teeInfo->val[t].tpi_relName); + teeInfo->val[t].tpi_plan = (Plan *) newplan; + } + } + + /* ---------------------------------------------------------- + * 3) replace the tee table scans in the main plan with + actual tee plannodes + * ---------------------------------------------------------- */ + + plan = replaceTeeScans(plan, parsetree, teeInfo); + + } /* if (teeInfo) */ + + setheapoverride(false); + + /* define a portal for this viewer input */ + /* for now, eyes can only have one input */ + sprintf(portalName, "%s%d", e->nodeName, 0); + + queryDesc = CreateQueryDesc(parsetree, + plan, + whereToSendOutput); + /* ---------------- + * call ExecStart to prepare the plan for execution + * ---------------- + */ + attinfo = ExecutorStart(queryDesc, NULL); + + ProcessPortal(portalName, + parsetree, + plan, + attinfo, + whereToSendOutput); + elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName); + } } @@ -269,109 +302,122 @@ elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName); /* * tg_rewriteQuery - - * r - the recipe being rewritten - * n - the node that we're current at - * q - a QueryTree List containing the parse tree of the node - * inputQlist - the parsetrees of its input nodes, - * the size of inputQlist must be the same as the - * number of input nodes. Some elements in the inpuQlist - * may be null if the inputs to those nodes are unconnected + * r - the recipe being rewritten + * n - the node that we're current at + * q - a QueryTree List containing the parse tree of the node + * inputQlist - the parsetrees of its input nodes, + * the size of inputQlist must be the same as the + * number of input nodes. Some elements in the inpuQlist + * may be null if the inputs to those nodes are unconnected * - * this is the main routine for rewriting the recipe queries - * the original query tree 'q' is modified + * this is the main routine for rewriting the recipe queries + * the original query tree 'q' is modified */ -static void -tg_rewriteQuery(TgRecipe* r, - TgNode *n, - QueryTreeList *q, - QueryTreeList *inputQlist) +static void +tg_rewriteQuery(TgRecipe * r, + TgNode * n, + QueryTreeList * q, + QueryTreeList * inputQlist) { - Query* orig; - Query* inputQ; - int i; - List *rtable; - List *input_rtable; - int rt_length; - - /* orig is the original parse tree of the node */ - orig = q->qtrees[0]; - - - /*------------------------------------------------------------------- - step 1: - - form a combined range table from all the range tables in the original - query as well as the input nodes - - form a combined qualification from the qual in the original plus - the quals of the input nodes - ------------------------------------------------------------------- - */ - - /* start with the original range table */ - rtable = orig->rtable; - rt_length = length(rtable); - - for (i=0;i<n->inNodes->num;i++) { - if (n->inNodes->val[i] != NULL && - n->inNodes->val[i]->nodeType != TG_TEE_NODE) { - inputQ = inputQlist->qtrees[i]; - input_rtable = inputQ->rtable; - - /* need to offset the var nodes in the qual and targetlist - because they are indexed off the original rtable */ - OffsetVarNodes((Node*)inputQ->qual, rt_length); - OffsetVarNodes((Node*)inputQ->targetList, rt_length); - - /* append the range tables from the children nodes */ - rtable = nconc (rtable, input_rtable); - - /* append the qualifications of the child node into the - original qual list */ - AddQual(orig, inputQ->qual); + Query *orig; + Query *inputQ; + int i; + List *rtable; + List *input_rtable; + int rt_length; + + /* orig is the original parse tree of the node */ + orig = q->qtrees[0]; + + + /*------------------------------------------------------------------- + step 1: + + form a combined range table from all the range tables in the original + query as well as the input nodes + + form a combined qualification from the qual in the original plus + the quals of the input nodes + ------------------------------------------------------------------- + */ + + /* start with the original range table */ + rtable = orig->rtable; + rt_length = length(rtable); + + for (i = 0; i < n->inNodes->num; i++) + { + if (n->inNodes->val[i] != NULL && + n->inNodes->val[i]->nodeType != TG_TEE_NODE) + { + inputQ = inputQlist->qtrees[i]; + input_rtable = inputQ->rtable; + + /* + * need to offset the var nodes in the qual and targetlist + * because they are indexed off the original rtable + */ + OffsetVarNodes((Node *) inputQ->qual, rt_length); + OffsetVarNodes((Node *) inputQ->targetList, rt_length); + + /* append the range tables from the children nodes */ + rtable = nconc(rtable, input_rtable); + + /* + * append the qualifications of the child node into the + * original qual list + */ + AddQual(orig, inputQ->qual); + } } - } - orig->rtable = rtable; - - /* step 2: - rewrite the target list of the original parse tree - if there are any references to params, replace them with - the appropriate target list entry of the children node - */ - if (orig->targetList != NIL) { - List *tl; - TargetEntry *tle; - - foreach (tl, orig->targetList) { - tle = lfirst(tl); - if (tle->resdom != NULL) { - tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist); - } - } - } - - /* step 3: - rewrite the qual of the original parse tree - if there are any references to params, replace them with - the appropriate target list entry of the children node - */ - if (orig->qual) { - if (nodeTag(orig->qual) == T_List) { - elog(WARN, "tg_rewriteQuery: Whoa! why is my qual a List???"); + orig->rtable = rtable; + + /* + * step 2: rewrite the target list of the original parse tree if there + * are any references to params, replace them with the appropriate + * target list entry of the children node + */ + if (orig->targetList != NIL) + { + List *tl; + TargetEntry *tle; + + foreach(tl, orig->targetList) + { + tle = lfirst(tl); + if (tle->resdom != NULL) + { + tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist); + } + } + } + + /* + * step 3: rewrite the qual of the original parse tree if there are + * any references to params, replace them with the appropriate target + * list entry of the children node + */ + if (orig->qual) + { + if (nodeTag(orig->qual) == T_List) + { + elog(WARN, "tg_rewriteQuery: Whoa! why is my qual a List???"); + } + orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist); } - orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist); - } - /* at this point, we're done with the rewrite, the querytreelist q - has been modified */ + /* + * at this point, we're done with the rewrite, the querytreelist q has + * been modified + */ } /* tg_replaceNumberedParam: - this procedure replaces the specified numbered param with a + this procedure replaces the specified numbered param with a reference to a range table this procedure recursively calls itself @@ -379,104 +425,137 @@ tg_rewriteQuery(TgRecipe* r, it returns a (possibly modified) Node*. */ -static Node* -tg_replaceNumberedParam(Node *expression, - int pnum, /* the number of the parameter */ - int rt_ind, /* the range table index */ - char *teeRelName) /* the relname of the tee table */ +static Node * +tg_replaceNumberedParam(Node * expression, + int pnum, /* the number of the parameter */ + int rt_ind, /* the range table index */ + char *teeRelName) /* the relname of the tee + * table */ { - TargetEntry *param_tle; - Param* p; - Var *newVar,*oldVar; - - if (expression == NULL) return NULL; - - switch (nodeTag(expression)) { - case T_Param: - { - /* the node is a parameter, - substitute the entry from the target list of the child that - corresponds to the parameter number*/ - p = (Param*)expression; - - /* we only deal with the case of numbered parameters */ - if (p->paramkind == PARAM_NUM && p->paramid == pnum) { - - if (p->param_tlist) { - /* we have a parameter with an attribute like $N.foo - so replace it with a new var node */ - - /* param tlist can only have one entry in them! */ - param_tle = (TargetEntry*)(lfirst(p->param_tlist)); - oldVar = (Var*)param_tle->expr; - oldVar->varno = rt_ind; - oldVar->varnoold = rt_ind; - return (Node*)oldVar; - } else { - /* we have $N without the .foo */ - bool defined; - bool isRel; - /* TODO here, we need to check to see whether the type of the - tee is a complex type (relation) or a simple type */ - /* if it is a simple type, then we need to get the "result" - attribute from the tee relation */ - - isRel = (typeid_get_relid(p->paramtype) != 0); - if (isRel) { - newVar = makeVar(rt_ind, - 0, /* the whole tuple */ - TypeGet(teeRelName,&defined), - rt_ind, - 0); - return (Node*)newVar; - } else - newVar = makeVar(rt_ind, - 1, /* just the first field, which is 'result' */ - TypeGet(teeRelName,&defined), - rt_ind, - 0); - return (Node*)newVar; - - } - } - else { - elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind); - } - } - break; - case T_Expr: - { - /* the node is an expression, we need to recursively - call ourselves until we find parameter nodes */ - List *l; - Expr *expr = (Expr*)expression; - List *newArgs; - - /* we have to make a new args lists because Params - can be replaced by Var nodes in tg_replaceNumberedParam()*/ - newArgs = NIL; - - /* we only care about argument to expressions, - it doesn't matter when the opType is */ - /* recursively rewrite the arguments of this expression */ - foreach (l, expr->args) { - newArgs = lappend(newArgs, - tg_replaceNumberedParam(lfirst(l), - pnum, - rt_ind, - teeRelName)); - } - /* change the arguments of the expression */ - expr->args = newArgs; - } - break; - default: - { - /* ignore other expr types */ - } - } - - return expression; + TargetEntry *param_tle; + Param *p; + Var *newVar, + *oldVar; + + if (expression == NULL) + return NULL; + + switch (nodeTag(expression)) + { + case T_Param: + { + + /* + * the node is a parameter, substitute the entry from the + * target list of the child that corresponds to the parameter + * number + */ + p = (Param *) expression; + + /* we only deal with the case of numbered parameters */ + if (p->paramkind == PARAM_NUM && p->paramid == pnum) + { + + if (p->param_tlist) + { + + /* + * we have a parameter with an attribute like $N.foo + * so replace it with a new var node + */ + + /* param tlist can only have one entry in them! */ + param_tle = (TargetEntry *) (lfirst(p->param_tlist)); + oldVar = (Var *) param_tle->expr; + oldVar->varno = rt_ind; + oldVar->varnoold = rt_ind; + return (Node *) oldVar; + } + else + { + /* we have $N without the .foo */ + bool defined; + bool isRel; + + /* + * TODO here, we need to check to see whether the type + * of the tee is a complex type (relation) or a simple + * type + */ + + /* + * if it is a simple type, then we need to get the + * "result" attribute from the tee relation + */ + + isRel = (typeid_get_relid(p->paramtype) != 0); + if (isRel) + { + newVar = makeVar(rt_ind, + 0, /* the whole tuple */ + TypeGet(teeRelName, &defined), + rt_ind, + 0); + return (Node *) newVar; + } + else + newVar = makeVar(rt_ind, + 1, /* just the first field, + * which is 'result' */ + TypeGet(teeRelName, &defined), + rt_ind, + 0); + return (Node *) newVar; + + } + } + else + { + elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind); + } + } + break; + case T_Expr: + { + + /* + * the node is an expression, we need to recursively call + * ourselves until we find parameter nodes + */ + List *l; + Expr *expr = (Expr *) expression; + List *newArgs; + + /* + * we have to make a new args lists because Params can be + * replaced by Var nodes in tg_replaceNumberedParam() + */ + newArgs = NIL; + + /* + * we only care about argument to expressions, it doesn't + * matter when the opType is + */ + /* recursively rewrite the arguments of this expression */ + foreach(l, expr->args) + { + newArgs = lappend(newArgs, + tg_replaceNumberedParam(lfirst(l), + pnum, + rt_ind, + teeRelName)); + } + /* change the arguments of the expression */ + expr->args = newArgs; + } + break; + default: + { + /* ignore other expr types */ + } + } + + return expression; } @@ -485,694 +564,817 @@ tg_replaceNumberedParam(Node *expression, /* tg_rewriteParamsInExpr: - rewrite the params in expressions by using the targetlist entries - from the input parsetrees + rewrite the params in expressions by using the targetlist entries + from the input parsetrees this procedure recursively calls itself it returns a (possibly modified) Node*. */ -static Node* -tg_rewriteParamsInExpr(Node *expression, QueryTreeList *inputQlist) +static Node * +tg_rewriteParamsInExpr(Node * expression, QueryTreeList * inputQlist) { - List *tl; - TargetEntry *param_tle, *tle; - Param* p; - int childno; - char *resname; - - if (expression == NULL) return NULL; - - switch (nodeTag(expression)) { - case T_Param: - { - /* the node is a parameter, - substitute the entry from the target list of the child that - corresponds to the parameter number*/ - p = (Param*)expression; - - /* we only deal with the case of numbered parameters */ - if (p->paramkind == PARAM_NUM) { - /* paramid's start from 1*/ - childno = p->paramid - 1; - - if (p->param_tlist) { - /* we have a parameter with an attribute like $N.foo - so match the resname "foo" against the target list - of the (N-1)th inputQlist */ - - /* param tlist can only have one entry in them! */ - param_tle = (TargetEntry*)(lfirst(p->param_tlist)); - resname = param_tle->resdom->resname; - - if (inputQlist->qtrees[childno]) { - foreach (tl, inputQlist->qtrees[childno]->targetList) { - tle = lfirst(tl); - if (strcmp(resname, tle->resdom->resname) == 0) { - return tle->expr; - } - } - } - else { - elog(WARN,"tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid); - } - - } else { - /* we have $N without the .foo */ - /* use the first resdom in the targetlist of the */ - /* appropriate child query */ - tl = inputQlist->qtrees[childno]->targetList; - tle = lfirst(tl); - return tle->expr; - } - } - else { - elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind); - } - } - break; - case T_Expr: - { - /* the node is an expression, we need to recursively - call ourselves until we find parameter nodes */ - List *l; - Expr *expr = (Expr*)expression; - List *newArgs; - - /* we have to make a new args lists because Params - can be replaced by Var nodes in tg_rewriteParamsInExpr()*/ - newArgs = NIL; - - /* we only care about argument to expressions, - it doesn't matter when the opType is */ - /* recursively rewrite the arguments of this expression */ - foreach (l, expr->args) { - newArgs = lappend(newArgs, - tg_rewriteParamsInExpr(lfirst(l), inputQlist)); - } - /* change the arguments of the expression */ - expr->args = newArgs; - } - break; - default: - { - /* ignore other expr types */ - } - } - - return expression; + List *tl; + TargetEntry *param_tle, + *tle; + Param *p; + int childno; + char *resname; + + if (expression == NULL) + return NULL; + + switch (nodeTag(expression)) + { + case T_Param: + { + + /* + * the node is a parameter, substitute the entry from the + * target list of the child that corresponds to the parameter + * number + */ + p = (Param *) expression; + + /* we only deal with the case of numbered parameters */ + if (p->paramkind == PARAM_NUM) + { + /* paramid's start from 1 */ + childno = p->paramid - 1; + + if (p->param_tlist) + { + + /* + * we have a parameter with an attribute like $N.foo + * so match the resname "foo" against the target list + * of the (N-1)th inputQlist + */ + + /* param tlist can only have one entry in them! */ + param_tle = (TargetEntry *) (lfirst(p->param_tlist)); + resname = param_tle->resdom->resname; + + if (inputQlist->qtrees[childno]) + { + foreach(tl, inputQlist->qtrees[childno]->targetList) + { + tle = lfirst(tl); + if (strcmp(resname, tle->resdom->resname) == 0) + { + return tle->expr; + } + } + } + else + { + elog(WARN, "tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid); + } + + } + else + { + /* we have $N without the .foo */ + /* use the first resdom in the targetlist of the */ + /* appropriate child query */ + tl = inputQlist->qtrees[childno]->targetList; + tle = lfirst(tl); + return tle->expr; + } + } + else + { + elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind); + } + } + break; + case T_Expr: + { + + /* + * the node is an expression, we need to recursively call + * ourselves until we find parameter nodes + */ + List *l; + Expr *expr = (Expr *) expression; + List *newArgs; + + /* + * we have to make a new args lists because Params can be + * replaced by Var nodes in tg_rewriteParamsInExpr() + */ + newArgs = NIL; + + /* + * we only care about argument to expressions, it doesn't + * matter when the opType is + */ + /* recursively rewrite the arguments of this expression */ + foreach(l, expr->args) + { + newArgs = lappend(newArgs, + tg_rewriteParamsInExpr(lfirst(l), inputQlist)); + } + /* change the arguments of the expression */ + expr->args = newArgs; + } + break; + default: + { + /* ignore other expr types */ + } + } + + return expression; } /* getParamTypes: - given an element, finds its parameter types. - the typev array argument is set to the parameter types. - the parameterCount is returned - - this code is very similar to ProcedureDefine() in pg_proc.c + given an element, finds its parameter types. + the typev array argument is set to the parameter types. + the parameterCount is returned + + this code is very similar to ProcedureDefine() in pg_proc.c */ static int -getParamTypes (TgElement *elem, Oid typev[]) +getParamTypes(TgElement * elem, Oid typev[]) { - /* this code is similar to ProcedureDefine() */ - int16 parameterCount; - bool defined; - Oid toid; - char *t; - int i,j; - - parameterCount = 0; - for (i=0;i<8;i++) { - typev[i] = 0; - } - for (j=0;j<elem->inTypes->num;j++) { - if (parameterCount == 8) { - elog(WARN, - "getParamTypes: Ingredients cannot take > 8 arguments"); + /* this code is similar to ProcedureDefine() */ + int16 parameterCount; + bool defined; + Oid toid; + char *t; + int i, + j; + + parameterCount = 0; + for (i = 0; i < 8; i++) + { + typev[i] = 0; } - t = elem->inTypes->val[j]; - if (strcmp(t,"opaque") == 0) { - elog(WARN, - "getParamTypes: Ingredient functions cannot take type 'opaque'"); - } else { - toid = TypeGet(elem->inTypes->val[j], &defined); - if (!OidIsValid(toid)) { - elog(WARN, "getParamTypes: arg type '%s' is not defined",t); - } - if (!defined) { - elog(NOTICE, "getParamTypes: arg type '%s' is only a shell",t); - } + for (j = 0; j < elem->inTypes->num; j++) + { + if (parameterCount == 8) + { + elog(WARN, + "getParamTypes: Ingredients cannot take > 8 arguments"); + } + t = elem->inTypes->val[j]; + if (strcmp(t, "opaque") == 0) + { + elog(WARN, + "getParamTypes: Ingredient functions cannot take type 'opaque'"); + } + else + { + toid = TypeGet(elem->inTypes->val[j], &defined); + if (!OidIsValid(toid)) + { + elog(WARN, "getParamTypes: arg type '%s' is not defined", t); + } + if (!defined) + { + elog(NOTICE, "getParamTypes: arg type '%s' is only a shell", t); + } + } + typev[parameterCount++] = toid; } - typev[parameterCount++] = toid; - } - return parameterCount; + return parameterCount; } /* * tg_parseTeeNode - * - * handles the parsing of the tee node - * + * + * handles the parsing of the tee node + * * */ -static QueryTreeList* -tg_parseTeeNode(TgRecipe *r, - TgNode *n, /* the tee node */ - int i, /* which input this node is to its parent */ - QueryTreeList *qList, - TeeInfo* teeInfo) +static QueryTreeList * +tg_parseTeeNode(TgRecipe * r, + TgNode * n, /* the tee node */ + int i, /* which input this node is to its parent */ + QueryTreeList * qList, + TeeInfo * teeInfo) { - QueryTreeList *q; - char* tt; - int rt_ind; - Query* orig; - - /* the input Node is a tee node, so we need to do the following: - * we need to parse the child of the tee node, - we add that to our query tree list - * we need the name of the tee node table - the tee node table is the table into which the tee node - may materialize results. Call it TT - * we add a range table to our existing query with TT in it - * we need to replace the parameter $i with TT - (otherwise the optimizer won't know to use the table - on expression containining $i) - After that rewrite, the optimizer will generate - sequential scans of TT - - Later, in the glue phase, we replace all instances of TT - sequential scans with the actual Tee node - */ - q = tg_parseSubQuery(r,n, teeInfo); - - /* tt is the name of the tee node table */ - tt = n->nodeName; - - if (q) - appendTeeQuery(teeInfo,q,tt); - - orig = qList->qtrees[0]; - rt_ind = RangeTablePosn(orig->rtable,tt); - /* check to see that this table is not part of - the range table already. This usually only - happens if multiple inputs are connected to the - same Tee. */ - if (rt_ind == 0) { - orig->rtable = lappend(orig->rtable, - addRangeTableEntry(NULL, - tt, - tt, - FALSE, - FALSE, - NULL)); - rt_ind = length(orig->rtable); - } - - orig->qual = tg_replaceNumberedParam(orig->qual, - i+1, /* params start at 1*/ - rt_ind, - tt); - return qList; + QueryTreeList *q; + char *tt; + int rt_ind; + Query *orig; + + /* + * the input Node is a tee node, so we need to do the following: we + * need to parse the child of the tee node, we add that to our query + * tree list we need the name of the tee node table the tee node table + * is the table into which the tee node may materialize results. Call + * it TT we add a range table to our existing query with TT in it we + * need to replace the parameter $i with TT (otherwise the optimizer + * won't know to use the table on expression containining $i) After + * that rewrite, the optimizer will generate sequential scans of TT + * + * Later, in the glue phase, we replace all instances of TT sequential + * scans with the actual Tee node + */ + q = tg_parseSubQuery(r, n, teeInfo); + + /* tt is the name of the tee node table */ + tt = n->nodeName; + + if (q) + appendTeeQuery(teeInfo, q, tt); + + orig = qList->qtrees[0]; + rt_ind = RangeTablePosn(orig->rtable, tt); + + /* + * check to see that this table is not part of the range table + * already. This usually only happens if multiple inputs are + * connected to the same Tee. + */ + if (rt_ind == 0) + { + orig->rtable = lappend(orig->rtable, + addRangeTableEntry(NULL, + tt, + tt, + FALSE, + FALSE, + NULL)); + rt_ind = length(orig->rtable); + } + + orig->qual = tg_replaceNumberedParam(orig->qual, + i + 1, /* params start at 1 */ + rt_ind, + tt); + return qList; } /* * tg_parseSubQuery: - * go backwards from a node and parse the query + * go backwards from a node and parse the query * - * the result parse tree is passed back - * - * could return NULL if trying to parse a teeNode + * the result parse tree is passed back + * + * could return NULL if trying to parse a teeNode * that's already been processed by another parent - * + * */ -static QueryTreeList* -tg_parseSubQuery(TgRecipe* r, TgNode* n, TeeInfo* teeInfo) +static QueryTreeList * +tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo) { - TgElement *elem; - char* funcName; - Oid typev[8]; /* eight arguments maximum */ - int i; - int parameterCount; - - QueryTreeList *qList; /* the parse tree of the nodeElement */ - QueryTreeList *inputQlist; /* the list of parse trees for the - inputs to this node */ - QueryTreeList *q; - Oid relid; - TgNode* child; - Relation rel; - unsigned int len; - TupleDesc tupdesc; - - qList = NULL; - - if (n->nodeType == TG_INGRED_NODE) { - /* parse each ingredient node in turn */ - - elem = n->nodeElem; - switch (elem->srcLang) { - case TG_SQL: - { - /* for SQL ingredients, the SQL query is contained in the - 'src' field */ + TgElement *elem; + char *funcName; + Oid typev[8]; /* eight arguments maximum */ + int i; + int parameterCount; + + QueryTreeList *qList; /* the parse tree of the nodeElement */ + QueryTreeList *inputQlist; /* the list of parse trees for the inputs + * to this node */ + QueryTreeList *q; + Oid relid; + TgNode *child; + Relation rel; + unsigned int len; + TupleDesc tupdesc; + + qList = NULL; + + if (n->nodeType == TG_INGRED_NODE) + { + /* parse each ingredient node in turn */ + + elem = n->nodeElem; + switch (elem->srcLang) + { + case TG_SQL: + { + + /* + * for SQL ingredients, the SQL query is contained in the + * 'src' field + */ #ifdef DEBUG_RECIPE -elog(NOTICE,"calling parser with %s",elem->src); -#endif /* DEBUG_RECIPE */ + elog(NOTICE, "calling parser with %s", elem->src); +#endif /* DEBUG_RECIPE */ - parameterCount = getParamTypes(elem,typev); + parameterCount = getParamTypes(elem, typev); - qList = parser(elem->src,typev,parameterCount); + qList = parser(elem->src, typev, parameterCount); - if (qList->len > 1) { - elog(NOTICE, - "tg_parseSubQuery: parser produced > 1 query tree"); - } - } - break; - case TG_C: - { - /* C ingredients are registered functions in postgres */ - /* we create a new query string by using the function name - (found in the 'src' field) and adding parameters to it - so if the function was FOOBAR and took in two arguments, - we would create a string - select FOOBAR($1,$2) - */ - char newquery[1000]; - - funcName = elem->src; - parameterCount = getParamTypes(elem,typev); - - if (parameterCount > 0) { - int i; - sprintf(newquery,"select %s($1",funcName); - for (i=1;i<parameterCount;i++) { - sprintf(newquery,"%s,$%d",newquery,i); - } - sprintf(newquery,"%s)",newquery); - } else - sprintf(newquery,"select %s()",funcName); + if (qList->len > 1) + { + elog(NOTICE, + "tg_parseSubQuery: parser produced > 1 query tree"); + } + } + break; + case TG_C: + { + /* C ingredients are registered functions in postgres */ + + /* + * we create a new query string by using the function name + * (found in the 'src' field) and adding parameters to it + * so if the function was FOOBAR and took in two + * arguments, we would create a string select + * FOOBAR($1,$2) + */ + char newquery[1000]; + + funcName = elem->src; + parameterCount = getParamTypes(elem, typev); + + if (parameterCount > 0) + { + int i; + + sprintf(newquery, "select %s($1", funcName); + for (i = 1; i < parameterCount; i++) + { + sprintf(newquery, "%s,$%d", newquery, i); + } + sprintf(newquery, "%s)", newquery); + } + else + sprintf(newquery, "select %s()", funcName); #ifdef DEBUG_RECIPE -elog(NOTICE,"calling parser with %s", newquery); -#endif /* DEBUG_RECIPE */ + elog(NOTICE, "calling parser with %s", newquery); +#endif /* DEBUG_RECIPE */ + + qList = parser(newquery, typev, parameterCount); + if (qList->len > 1) + { + elog(NOTICE, + "tg_parseSubQuery: parser produced > 1 query tree"); + } + } + break; + case TG_RECIPE_GRAPH: + elog(NOTICE, "tg_parseSubQuery: can't parse recipe graph ingredients yet!"); + break; + case TG_COMPILED: + elog(NOTICE, "tg_parseSubQuery: can't parse compiled ingredients yet!"); + break; + default: + elog(NOTICE, "tg_parseSubQuery: unknown srcLang: %d", elem->srcLang); + } + + /* parse each of the subrecipes that are input to this node */ + + if (n->inNodes->num > 0) + { + inputQlist = malloc(sizeof(QueryTreeList)); + inputQlist->len = n->inNodes->num + 1; + inputQlist->qtrees = (Query **) malloc(inputQlist->len * sizeof(Query *)); + for (i = 0; i < n->inNodes->num; i++) + { + + inputQlist->qtrees[i] = NULL; + if (n->inNodes->val[i]) + { + if (n->inNodes->val[i]->nodeType == TG_TEE_NODE) + { + qList = tg_parseTeeNode(r, n->inNodes->val[i], + i, qList, teeInfo); + } + else + { /* input node is not a Tee */ + q = tg_parseSubQuery(r, n->inNodes->val[i], + teeInfo); + Assert(q->len == 1); + inputQlist->qtrees[i] = q->qtrees[0]; + } + } + } - qList = parser(newquery,typev,parameterCount); - if (qList->len > 1) { - elog(NOTICE, - "tg_parseSubQuery: parser produced > 1 query tree"); + /* now, we have all the query trees from our input nodes */ + /* transform the original parse tree appropriately */ + tg_rewriteQuery(r, n, qList, inputQlist); } - } - break; - case TG_RECIPE_GRAPH: - elog(NOTICE,"tg_parseSubQuery: can't parse recipe graph ingredients yet!"); - break; - case TG_COMPILED: - elog(NOTICE,"tg_parseSubQuery: can't parse compiled ingredients yet!"); - break; - default: - elog(NOTICE,"tg_parseSubQuery: unknown srcLang: %d",elem->srcLang); } + else if (n->nodeType == TG_EYE_NODE) + { - /* parse each of the subrecipes that are input to this node*/ - - if (n->inNodes->num > 0) { - inputQlist = malloc(sizeof(QueryTreeList)); - inputQlist->len = n->inNodes->num + 1 ; - inputQlist->qtrees = (Query**)malloc(inputQlist->len * sizeof(Query*)); - for (i=0;i<n->inNodes->num;i++) { - - inputQlist->qtrees[i] = NULL; - if (n->inNodes->val[i]) { - if (n->inNodes->val[i]->nodeType == TG_TEE_NODE) { - qList = tg_parseTeeNode(r,n->inNodes->val[i], - i,qList,teeInfo); - } - else - { /* input node is not a Tee */ - q = tg_parseSubQuery(r,n->inNodes->val[i], - teeInfo); - Assert (q->len == 1); - inputQlist->qtrees[i] = q->qtrees[0]; - } + /* + * if we hit an eye, we need to stop and make what we have into a + * subrecipe query block + */ + elog(NOTICE, "tg_parseSubQuery: can't handle eye nodes yet"); + } + else if (n->nodeType == TG_TEE_NODE) + { + + /* + * if we hit a tee, check to see if the parsing has been done for + * this tee already by the other parent + */ + + rel = RelationNameGetRelation(n->nodeName); + if (RelationIsValid(rel)) + { + + /* + * this tee has already been visited, no need to do any + * further processing + */ + return NULL; } - } + else + { + /* we need to process the child of the tee first, */ + child = n->inNodes->val[0]; + + if (child->nodeType == TG_TEE_NODE) + { + /* nested Tee nodes */ + qList = tg_parseTeeNode(r, child, 0, qList, teeInfo); + return qList; + } - /* now, we have all the query trees from our input nodes */ - /* transform the original parse tree appropriately */ - tg_rewriteQuery(r,n,qList,inputQlist); + Assert(child != NULL); + + /* parse the input node */ + q = tg_parseSubQuery(r, child, teeInfo); + Assert(q->len == 1); + + /* add the parsed query to the main list of queries */ + qList = appendQlist(qList, q); + + /* need to create the tee table here */ + + /* + * the tee table created is used both for materializing the + * values at the tee node, and for parsing and optimization. + * The optimization needs to have a real table before it will + * consider scans on it + */ + + /* + * first, find the type of the tuples being produced by the + * tee. The type is the same as the output type of the child + * node. + * + * NOTE: we are assuming that the child node only has a single + * output here! + */ + getParamTypes(child->nodeElem, typev); + + /* + * the output type is either a complex type, (and is thus a + * relation) or is a simple type + */ + + rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]); + + if (RelationIsValid(rel)) + { + + /* + * for complex types, create new relation with the same + * tuple descriptor as the output table type + */ + len = length(q->qtrees[0]->targetList); + tupdesc = rel->rd_att; + + relid = heap_create(child->nodeElem->outTypes->val[0], + NULL, /* XXX */ + 'n', + DEFAULT_SMGR, + tupdesc); + } + else + { + + /* + * we have to create a relation with one attribute of the + * simple base type. That attribute will have an attr + * name of "result" + */ + /* NOTE: ignore array types for the time being */ + + len = 1; + tupdesc = CreateTemplateTupleDesc(len); + + if (!TupleDescInitEntry(tupdesc, 1, + "result", + NULL, + 0, false)) + { + elog(NOTICE, "tg_parseSubQuery: unexpected result from TupleDescInitEntry"); + } + else + { + relid = heap_create(child->nodeElem->outTypes->val[0], + NULL, /* XXX */ + 'n', + DEFAULT_SMGR, + tupdesc); + } + } + } } - } - else if (n->nodeType == TG_EYE_NODE) { - /* if we hit an eye, we need to stop and make what we have - into a subrecipe query block*/ - elog(NOTICE,"tg_parseSubQuery: can't handle eye nodes yet"); - } - else if (n->nodeType == TG_TEE_NODE) { - /* if we hit a tee, check to see if the parsing has been done - for this tee already by the other parent */ - - rel = RelationNameGetRelation(n->nodeName); - if (RelationIsValid(rel)) { - /* this tee has already been visited, - no need to do any further processing */ - return NULL; - } else { - /* we need to process the child of the tee first, */ - child = n->inNodes->val[0]; - - if (child->nodeType == TG_TEE_NODE) { - /* nested Tee nodes */ - qList = tg_parseTeeNode(r,child,0,qList,teeInfo); - return qList; - } - - Assert (child != NULL); - - /* parse the input node */ - q = tg_parseSubQuery(r,child, teeInfo); - Assert (q->len == 1); - - /* add the parsed query to the main list of queries */ - qList = appendQlist(qList,q); - - /* need to create the tee table here */ - /* the tee table created is used both for materializing the values - at the tee node, and for parsing and optimization. - The optimization needs to have a real table before it will - consider scans on it */ - - /* first, find the type of the tuples being produced by the - tee. The type is the same as the output type of - the child node. - - NOTE: we are assuming that the child node only has a single - output here! */ - getParamTypes(child->nodeElem,typev); - - /* the output type is either a complex type, - (and is thus a relation) or is a simple type */ - - rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]); - - if (RelationIsValid(rel)) { - /* for complex types, create new relation with the same - tuple descriptor as the output table type*/ - len = length(q->qtrees[0]->targetList); - tupdesc = rel->rd_att; - - relid = heap_create(child->nodeElem->outTypes->val[0], - NULL, /* XXX */ - 'n', - DEFAULT_SMGR, - tupdesc); - } - else { - /* we have to create a relation with one attribute of - the simple base type. That attribute will have - an attr name of "result" */ - /*NOTE: ignore array types for the time being */ - - len = 1; - tupdesc = CreateTemplateTupleDesc(len); - - if ( !TupleDescInitEntry(tupdesc,1, - "result", - NULL, - 0, false)) { - elog(NOTICE,"tg_parseSubQuery: unexpected result from TupleDescInitEntry"); - } else { - relid = heap_create(child->nodeElem->outTypes->val[0], - NULL, /* XXX */ - 'n', - DEFAULT_SMGR, - tupdesc); - } - } + else if (n->nodeType == TG_RECIPE_NODE) + { + elog(NOTICE, "tg_parseSubQuery: can't handle embedded recipes yet!"); } - } - else if (n->nodeType == TG_RECIPE_NODE) { - elog(NOTICE,"tg_parseSubQuery: can't handle embedded recipes yet!"); - } else - elog (NOTICE, "unknown nodeType: %d", n->nodeType); + else + elog(NOTICE, "unknown nodeType: %d", n->nodeType); - return qList; + return qList; } /* * OffsetVarAttno - - * recursively find all the var nodes with the specified varno + * recursively find all the var nodes with the specified varno * and offset their varattno with the offset - * - * code is similar to OffsetVarNodes in rewriteManip.c + * + * code is similar to OffsetVarNodes in rewriteManip.c */ void -OffsetVarAttno(Node* node, int varno, int offset) +OffsetVarAttno(Node * node, int varno, int offset) { - if (node == NULL) return; - switch (nodeTag(node)) { - case T_TargetEntry: - { - TargetEntry *tle = (TargetEntry *)node; - OffsetVarAttno(tle->expr, varno, offset); - } - break; - case T_Expr: - { - Expr *expr = (Expr*)node; - OffsetVarAttno((Node*)expr->args, varno, offset); - } - break; - case T_Var: + if (node == NULL) + return; + switch (nodeTag(node)) { - Var *var = (Var*)node; - if (var->varno == varno) - var->varattno += offset; - } - break; - case T_List: - { - List *l; + case T_TargetEntry: + { + TargetEntry *tle = (TargetEntry *) node; + + OffsetVarAttno(tle->expr, varno, offset); + } + break; + case T_Expr: + { + Expr *expr = (Expr *) node; + + OffsetVarAttno((Node *) expr->args, varno, offset); + } + break; + case T_Var: + { + Var *var = (Var *) node; - foreach(l, (List*)node) { - OffsetVarAttno(lfirst(l), varno, offset); - } + if (var->varno == varno) + var->varattno += offset; + } + break; + case T_List: + { + List *l; + + foreach(l, (List *) node) + { + OffsetVarAttno(lfirst(l), varno, offset); + } + } + break; + default: + /* ignore the others */ + break; } - break; - default: - /* ignore the others */ - break; - } } /* - * appendQlist - * add the contents of a QueryTreeList q2 to the end of the QueryTreeList - * q1 + * appendQlist + * add the contents of a QueryTreeList q2 to the end of the QueryTreeList + * q1 * - * returns a new querytree list + * returns a new querytree list */ -QueryTreeList* -appendQlist(QueryTreeList *q1, QueryTreeList *q2) +QueryTreeList * +appendQlist(QueryTreeList * q1, QueryTreeList * q2) { - QueryTreeList* newq; - int i,j; - int newlen; - - if (q1 == NULL) - return q2; - - if (q2 == NULL) - return q1; - - newlen = q1->len + q2->len; - newq = (QueryTreeList*)malloc(sizeof(QueryTreeList)); - newq->len = newlen; - newq->qtrees = (Query**)malloc(newlen * sizeof(Query*)); - for (i=0;i<q1->len;i++) - newq->qtrees[i] = q1->qtrees[i]; - for (j=0;j<q2->len;j++) { - newq->qtrees[i + j] = q2->qtrees[j]; - } - return newq; + QueryTreeList *newq; + int i, + j; + int newlen; + + if (q1 == NULL) + return q2; + + if (q2 == NULL) + return q1; + + newlen = q1->len + q2->len; + newq = (QueryTreeList *) malloc(sizeof(QueryTreeList)); + newq->len = newlen; + newq->qtrees = (Query **) malloc(newlen * sizeof(Query *)); + for (i = 0; i < q1->len; i++) + newq->qtrees[i] = q1->qtrees[i]; + for (j = 0; j < q2->len; j++) + { + newq->qtrees[i + j] = q2->qtrees[j]; + } + return newq; } /* - * appendTeeQuery - * - * modify the query field of the teeInfo list of the particular tee node + * appendTeeQuery + * + * modify the query field of the teeInfo list of the particular tee node */ static void -appendTeeQuery(TeeInfo *teeInfo, QueryTreeList *q, char* teeNodeName) +appendTeeQuery(TeeInfo * teeInfo, QueryTreeList * q, char *teeNodeName) { - int i; - - Assert(teeInfo); + int i; - for (i=0;i<teeInfo->num;i++) { - if ( strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0) { + Assert(teeInfo); + + for (i = 0; i < teeInfo->num; i++) + { + if (strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0) + { - Assert(q->len == 1); - teeInfo->val[i].tpi_parsetree = q->qtrees[0]; - return; + Assert(q->len == 1); + teeInfo->val[i].tpi_parsetree = q->qtrees[0]; + return; + } } - } - elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo"); + elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo"); } /* - * replaceSeqScan - * replaces sequential scans of a specified relation with the tee plan - * the relation is specified by its index in the range table, rt_ind + * replaceSeqScan + * replaces sequential scans of a specified relation with the tee plan + * the relation is specified by its index in the range table, rt_ind * * returns the modified plan * the offset_attno is the offset that needs to be added to the parent's * qual or targetlist because the child plan has been replaced with a tee node */ static void -replaceSeqScan(Plan* plan, Plan* parent, - int rt_ind, Plan* tplan) +replaceSeqScan(Plan * plan, Plan * parent, + int rt_ind, Plan * tplan) { - Scan* snode; - Tee* teePlan; - Result* newPlan; - - if (plan == NULL) { - return; - } - - if (plan->type == T_SeqScan) { - snode = (Scan*)plan; - if (snode->scanrelid == rt_ind) { - /* found the sequential scan that should be replaced - with the tplan. */ - /* we replace the plan, but we also need to modify its parent*/ - - /* replace the sequential scan with a Result node - the reason we use a result node is so that we get the proper - projection behavior. The Result node is simply (ab)used as - a projection node */ - - newPlan = makeNode(Result); - newPlan->plan.cost = 0.0; - newPlan->plan.state = (EState*)NULL; - newPlan->plan.targetlist = plan->targetlist; - newPlan->plan.lefttree = tplan; - newPlan->plan.righttree = NULL; - newPlan->resconstantqual = NULL; - newPlan->resstate = NULL; - - /* change all the varno's to 1*/ - ChangeVarNodes((Node*)newPlan->plan.targetlist, - snode->scanrelid, 1); - - if (parent) { - teePlan = (Tee*)tplan; - - if (parent->lefttree == plan) - parent->lefttree = (Plan*)newPlan; - else - parent->righttree = (Plan*)newPlan; - + Scan *snode; + Tee *teePlan; + Result *newPlan; - if (teePlan->leftParent == NULL) - teePlan->leftParent = (Plan*)newPlan; - else - teePlan->rightParent = (Plan*)newPlan; + if (plan == NULL) + { + return; + } + + if (plan->type == T_SeqScan) + { + snode = (Scan *) plan; + if (snode->scanrelid == rt_ind) + { + + /* + * found the sequential scan that should be replaced with the + * tplan. + */ + /* we replace the plan, but we also need to modify its parent */ + + /* + * replace the sequential scan with a Result node the reason + * we use a result node is so that we get the proper + * projection behavior. The Result node is simply (ab)used as + * a projection node + */ + + newPlan = makeNode(Result); + newPlan->plan.cost = 0.0; + newPlan->plan.state = (EState *) NULL; + newPlan->plan.targetlist = plan->targetlist; + newPlan->plan.lefttree = tplan; + newPlan->plan.righttree = NULL; + newPlan->resconstantqual = NULL; + newPlan->resstate = NULL; + + /* change all the varno's to 1 */ + ChangeVarNodes((Node *) newPlan->plan.targetlist, + snode->scanrelid, 1); + + if (parent) + { + teePlan = (Tee *) tplan; + + if (parent->lefttree == plan) + parent->lefttree = (Plan *) newPlan; + else + parent->righttree = (Plan *) newPlan; + + + if (teePlan->leftParent == NULL) + teePlan->leftParent = (Plan *) newPlan; + else + teePlan->rightParent = (Plan *) newPlan; /* comment for now to test out executor-stuff - if (parent->state) { - ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan); - } + if (parent->state) { + ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan); + } */ - } - } + } + } - } else { - if (plan->lefttree) { - replaceSeqScan(plan->lefttree, plan, rt_ind, tplan); } - if (plan->righttree) { - replaceSeqScan(plan->righttree, plan, rt_ind, tplan); + else + { + if (plan->lefttree) + { + replaceSeqScan(plan->lefttree, plan, rt_ind, tplan); + } + if (plan->righttree) + { + replaceSeqScan(plan->righttree, plan, rt_ind, tplan); + } } - } } /* - * replaceTeeScans - * places the sequential scans of the Tee table with + * replaceTeeScans + * places the sequential scans of the Tee table with * a connection to the actual tee plan node */ -static Plan* -replaceTeeScans(Plan* plan, Query* parsetree, TeeInfo *teeInfo) +static Plan * +replaceTeeScans(Plan * plan, Query * parsetree, TeeInfo * teeInfo) { - int i; - List* rtable; - RangeTblEntry *rte; - char prefix[5]; - int rt_ind; - Plan* tplan; - - rtable = parsetree->rtable; - if (rtable == NULL) - return plan; + int i; + List *rtable; + RangeTblEntry *rte; + char prefix[5]; + int rt_ind; + Plan *tplan; + + rtable = parsetree->rtable; + if (rtable == NULL) + return plan; + + /* + * look through the range table for the tee relation entry, that will + * give use the varno we need to detect which sequential scans need to + * be replaced with tee nodes + */ + + rt_ind = 0; + while (rtable != NIL) + { + rte = lfirst(rtable); + rtable = lnext(rtable); + rt_ind++; /* range table references in varno fields + * start w/ 1 */ + + /* + * look for the "tee_" prefix in the refname, also check to see + * that the relname and the refname are the same this should + * eliminate any user-specified table and leave us with the tee + * table entries only + */ + if ((strlen(rte->refname) < 4) || + (strcmp(rte->relname, rte->refname) != 0)) + continue; + strNcpy(prefix, rte->refname, 4); + if (strcmp(prefix, "tee_") == 0) + { + /* okay, we found a tee node entry in the range table */ + + /* find the appropriate plan in the teeInfo list */ + tplan = NULL; + for (i = 0; i < teeInfo->num; i++) + { + if (strcmp(teeInfo->val[i].tpi_relName, + rte->refname) == 0) + { + tplan = teeInfo->val[i].tpi_plan; + } + } + if (tplan == NULL) + { + elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan"); + } - /* look through the range table for the tee relation entry, - that will give use the varno we need to detect which - sequential scans need to be replaced with tee nodes*/ - - rt_ind = 0; - while (rtable != NIL) { - rte = lfirst(rtable); - rtable = lnext(rtable); - rt_ind++; /* range table references in varno fields start w/ 1 */ - - /* look for the "tee_" prefix in the refname, - also check to see that the relname and the refname are the same - this should eliminate any user-specified table and leave - us with the tee table entries only*/ - if ((strlen(rte->refname) < 4) || - (strcmp (rte->relname, rte->refname) != 0)) - continue; - strNcpy(prefix,rte->refname,4); - if (strcmp(prefix,"tee_") == 0) { - /* okay, we found a tee node entry in the range table */ - - /* find the appropriate plan in the teeInfo list */ - tplan = NULL; - for (i=0;i<teeInfo->num;i++) { - if (strcmp(teeInfo->val[i].tpi_relName, - rte->refname) == 0) { - tplan = teeInfo->val[i].tpi_plan; + /* + * replace the sequential scan node with that var number with + * the tee plan node + */ + replaceSeqScan(plan, NULL, rt_ind, tplan); } - } - if (tplan == NULL) { - elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan"); } - - /* replace the sequential scan node with that var number - with the tee plan node */ - replaceSeqScan(plan, NULL, rt_ind, tplan); } - } - return plan; + return plan; } -#endif /* TIOGA */ +#endif /* TIOGA */ |