/*-------------------------------------------------------------------------
*
* 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.25 1998/10/21 16:21:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <catalog/pg_type.h>
#include <commands/recipe.h>
#include <libpq/libpq-be.h>
+#include <parser/parse_node.h>
#include <utils/builtins.h>
-#include <utils/relcache.h> /* for RelationNameGetRelation*/
-#include <parser/parse_query.h>
+#include <utils/relcache.h> /* for RelationNameGetRelation */
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteManip.h>
#include <tcop/pquery.h>
#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>
#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 _teePlanInfo
+{
+ char *tpi_relName;
+ Query *tpi_parsetree;
+ Plan *tpi_plan;
+} TeePlanInfo;
-typedef struct _teeInfo {
- int num;
- TeePlanInfo *val;
-} TeeInfo;
+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);
+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);
/*
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);
+ }
}
/*
* 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, 0);
+ OffsetVarNodes((Node *) inputQ->targetList, rt_length, 0);
+
+ /* 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);
+ }
}
- }
- 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???");
+
+ /*
+ * 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(ERROR, "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
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 = (typeidTypeRelid(p->paramtype) != 0);
+ if (isRel)
+ {
+ newVar = makeVar(rt_ind,
+ 0, /* the whole tuple */
+ TypeGet(teeRelName, &defined),
+ -1,
+ 0,
+ rt_ind,
+ 0);
+ return (Node *) newVar;
+ }
+ else
+ newVar = makeVar(rt_ind,
+ 1, /* just the first field,
+ * which is 'result' */
+ TypeGet(teeRelName, &defined),
+ -1,
+ 0,
+ 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;
}
/* 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*
+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(ERROR, "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");
- }
- 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);
- }
+ /* 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(ERROR,
+ "getParamTypes: Ingredients cannot take > 8 arguments");
+ }
+ t = elem->inTypes->val[j];
+ if (strcmp(t, "opaque") == 0)
+ {
+ elog(ERROR,
+ "getParamTypes: Ingredient functions cannot take type 'opaque'");
+ }
+ else
+ {
+ toid = TypeGet(elem->inTypes->val[j], &defined);
+ if (!OidIsValid(toid))
+ elog(ERROR, "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));
+ 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 */
-#ifdef DEBUG_RECIPE
-elog(NOTICE,"calling parser with %s",elem->src);
-#endif /* DEBUG_RECIPE */
+ elem = n->nodeElem;
+ switch (elem->srcLang)
+ {
+ case TG_SQL:
+ {
- parameterCount = getParamTypes(elem,typev);
+ /*
+ * for SQL ingredients, the SQL query is contained in
+ * the 'src' field
+ */
- qList = parser(elem->src,typev,parameterCount);
+#ifdef DEBUG_RECIPE
+ elog(NOTICE, "calling parser with %s", elem->src);
+#endif /* DEBUG_RECIPE */
+
+ parameterCount = getParamTypes(elem, typev);
+
+ 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");
+#ifdef 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);
}
- }
- 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 */
+ /* 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);
- }
- }
- 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);
- }
- }
+ 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_with_catalog(
+ child->nodeElem->outTypes->val[0],
+ tupdesc, RELKIND_RELATION);
+ }
+ 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",
+ InvalidOid,
+ -1, 0, false))
+ elog(NOTICE, "tg_parseSubQuery: unexpected result from TupleDescInitEntry");
+ else
+ {
+ relid = heap_create_with_catalog(
+ child->nodeElem->outTypes->val[0],
+ tupdesc, RELKIND_RELATION);
+ }
+ }
+ }
}
- }
- 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 if (n->nodeType == TG_RECIPE_NODE)
+ elog(NOTICE, "tg_parseSubQuery: can't handle embedded recipes yet!");
+ 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:
+ if (node == NULL)
+ return;
+ switch (nodeTag(node))
{
- 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;
- 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;
- foreach(l, (List*)node) {
- OffsetVarAttno(lfirst(l), varno, offset);
- }
+ OffsetVarAttno((Node *) expr->args, varno, offset);
+ }
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
+
+ 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*
+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;
-
- /* 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;
+ 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, 5);
+ 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");
+
+ /*
+ * 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 */