recipe.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:31k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * recipe.c
  4.  *   routines for handling execution of Tioga recipes
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/commands/_deadcode/recipe.c,v 1.4.2.1 1999/08/02 05:57:01 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "catalog/pg_type.h"
  16. #include "commands/recipe.h"
  17. #include "executor/executor.h"
  18. #include "libpq/libpq-be.h"
  19. #include "nodes/execnodes.h"
  20. #include "nodes/makefuncs.h"
  21. #include "nodes/parsenodes.h"
  22. #include "nodes/plannodes.h"
  23. #include "optimizer/planner.h"
  24. #include "parser/parse_node.h"
  25. #include "rewrite/rewriteHandler.h"
  26. #include "rewrite/rewriteManip.h"
  27. #include "tcop/dest.h"
  28. #include "tcop/pquery.h"
  29. #include "utils/builtins.h"
  30. #include "utils/relcache.h"
  31. /* from tcop/postgres.c */
  32. extern CommandDest whereToSendOutput;
  33. #ifndef TIOGA
  34. void
  35. beginRecipe(RecipeStmt *stmt)
  36. {
  37. elog(NOTICE, "You must compile with TIOGA defined in order to use recipesn");
  38. }
  39. #else
  40. #include "tioga/tgRecipe.h"
  41. #define DEBUG_RECIPE 1
  42. /* structure to keep track of the tee node plans */
  43. typedef struct _teePlanInfo
  44. {
  45. char    *tpi_relName;
  46. Query    *tpi_parsetree;
  47. Plan    *tpi_plan;
  48. } TeePlanInfo;
  49. typedef struct _teeInfo
  50. {
  51. int num;
  52. TeePlanInfo *val;
  53. } TeeInfo;
  54. QueryTreeList *appendQlist(QueryTreeList * q1, QueryTreeList * q2);
  55. void OffsetVarAttno(Node *node, int varno, int offset);
  56. static void appendTeeQuery(TeeInfo * teeInfo,
  57.    QueryTreeList * q,
  58.    char *teeNodeName);
  59. static Plan *replaceTeeScans(Plan *plan,
  60. Query *parsetree,
  61. TeeInfo * teeInfo);
  62. static void replaceSeqScan(Plan *plan,
  63.    Plan *parent,
  64.    int rt_ind,
  65.    Plan *tplan);
  66. static void tg_rewriteQuery(TgRecipe * r, TgNode * n,
  67. QueryTreeList * q,
  68. QueryTreeList * inputQlist);
  69. static Node *tg_replaceNumberedParam(Node *expression,
  70. int pnum,
  71. int rt_ind,
  72. char *teeRelName);
  73. static Node *tg_rewriteParamsInExpr(Node *expression,
  74.    QueryTreeList * inputQlist);
  75. static QueryTreeList *tg_parseSubQuery(TgRecipe * r,
  76.  TgNode * n,
  77.  TeeInfo * teeInfo);
  78. static QueryTreeList *tg_parseTeeNode(TgRecipe * r,
  79. TgNode * n,
  80. int i,
  81. QueryTreeList * qList,
  82. TeeInfo * teeInfo);
  83. /*
  84.    The Tioga recipe rewrite algorithm:
  85.    To parse a Tioga recipe, we start from an eye node and go backwards through
  86.    its input nodes.  To rewrite a Tioga node, we do the following:
  87.   1) parse the node we're at in the standard way (calling parser() )
  88.   2) rewrite its input nodes recursively using Tioga rewrite
  89.   3) now, with the rewritten input parse trees and the original parse tree
  90.  of the node,  we rewrite the the node.
  91.  To do the rewrite, we use the target lists, range tables, and
  92.  qualifications of the input parse trees
  93. */
  94. /*
  95.  * beginRecipe:
  96.  *   this is the main function to recipe execution
  97.  *  this function is invoked for EXECUTE RECIPE ...  statements
  98.  *
  99.  * takes in a RecipeStmt structure from the parser
  100.  * and returns a list of cursor names
  101.  */
  102. void
  103. beginRecipe(RecipeStmt *stmt)
  104. {
  105. TgRecipe   *r;
  106. int i,
  107. numTees;
  108. QueryTreeList *qList;
  109. char portalName[1024];
  110. Plan    *plan;
  111. TupleDesc attinfo;
  112. QueryDesc  *queryDesc;
  113. Query    *parsetree;
  114. TeeInfo    *teeInfo;
  115. /*
  116.  * retrieveRecipe() reads the recipe from the database and returns a
  117.  * TgRecipe* structure we can work with
  118.  */
  119. r = retrieveRecipe(stmt->recipeName);
  120. if (r == NULL)
  121. return;
  122. /* find the number of tees in the recipe */
  123. numTees = r->tees->num;
  124. if (numTees > 0)
  125. {
  126. /* allocate a teePlan structure */
  127. teeInfo = (TeeInfo *) malloc(sizeof(TeeInfo));
  128. teeInfo->num = numTees;
  129. teeInfo->val = (TeePlanInfo *) malloc(numTees * sizeof(TeePlanInfo));
  130. for (i = 0; i < numTees; i++)
  131. {
  132. teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName;
  133. teeInfo->val[i].tpi_parsetree = NULL;
  134. teeInfo->val[i].tpi_plan = NULL;
  135. }
  136. }
  137. else
  138. teeInfo = NULL;
  139. /*
  140.  * for each viewer in the recipe, go backwards from each viewer input
  141.  * and generate a plan.  Attach the plan to cursors.
  142.  */
  143. for (i = 0; i < r->eyes->num; i++)
  144. {
  145. TgNodePtr e;
  146. e = r->eyes->val[i];
  147. if (e->inNodes->num > 1)
  148. {
  149. elog(NOTICE,
  150.  "beginRecipe: Currently eyes cannot have more than one input");
  151. }
  152. if (e->inNodes->num == 0)
  153. {
  154. /* no input to this eye, skip it */
  155. continue;
  156. }
  157. #ifdef DEBUG_RECIPE
  158. elog(NOTICE, "beginRecipe: eyes[%d] = %sn", i, e->nodeName);
  159. #endif  /* DEBUG_RECIPE */
  160. qList = tg_parseSubQuery(r, e->inNodes->val[0], teeInfo);
  161. if (qList == NULL)
  162. {
  163. /* eye is directly connected to a tee node */
  164. /* XXX TODO: handle this case */
  165. }
  166. /* now, plan the queries */
  167. /*
  168.  * should really do everything pg_plan() does, but for now, we
  169.  * skip the rule rewrite and time qual stuff
  170.  */
  171. /* ----------------------------------------------------------
  172.  * 1) plan the main query, everything from an eye node back to
  173.  a Tee
  174.  * ---------------------------------------------------------- */
  175. parsetree = qList->qtrees[0];
  176. /*
  177.  * before we plan, we want to see all the changes we did, during
  178.  * the rewrite phase, such as creating the tee tables,
  179.  * setheapoverride() allows us to see the changes
  180.  */
  181. setheapoverride(true);
  182. plan = planner(parsetree);
  183. /* ----------------------------------------------------------
  184.  * 2) plan the tee queries, (subgraphs rooted from a Tee)
  185.  by the time the eye is processed, all tees that contribute
  186.  to that eye will have been included in the teeInfo list
  187.  * ---------------------------------------------------------- */
  188. if (teeInfo)
  189. {
  190. int t;
  191. Plan    *tplan;
  192. Tee    *newplan;
  193. for (t = 0; t < teeInfo->num; t++)
  194. {
  195. if (teeInfo->val[t].tpi_plan == NULL)
  196. {
  197. /* plan it in the usual fashion */
  198. tplan = planner(teeInfo->val[t].tpi_parsetree);
  199. /* now add a tee node to the root of the plan */
  200. elog(NOTICE, "adding tee plan node to the root of the %sn",
  201.  teeInfo->val[t].tpi_relName);
  202. newplan = (Tee *) makeNode(Tee);
  203. newplan->plan.targetlist = tplan->targetlist;
  204. newplan->plan.qual = NULL; /* tplan->qual; */
  205. newplan->plan.lefttree = tplan;
  206. newplan->plan.righttree = NULL;
  207. newplan->leftParent = NULL;
  208. newplan->rightParent = NULL;
  209. /*
  210.  * the range table of the tee is the range table of
  211.  * the tplan
  212.  */
  213. newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable;
  214. strcpy(newplan->teeTableName,
  215.    teeInfo->val[t].tpi_relName);
  216. teeInfo->val[t].tpi_plan = (Plan *) newplan;
  217. }
  218. }
  219. /* ----------------------------------------------------------
  220.  * 3) replace the tee table scans in the main plan with
  221.   actual tee plannodes
  222.  * ---------------------------------------------------------- */
  223. plan = replaceTeeScans(plan, parsetree, teeInfo);
  224. } /* if (teeInfo) */
  225. setheapoverride(false);
  226. /* define a portal for this viewer input */
  227. /* for now, eyes can only have one input */
  228. snprintf(portalName, 1024, "%s%d", e->nodeName, 0);
  229. queryDesc = CreateQueryDesc(parsetree,
  230. plan,
  231. whereToSendOutput);
  232. /* ----------------
  233.  *   call ExecStart to prepare the plan for execution
  234.  * ----------------
  235.  */
  236. attinfo = ExecutorStart(queryDesc, NULL);
  237. ProcessPortal(portalName,
  238.   parsetree,
  239.   plan,
  240.   attinfo,
  241.   whereToSendOutput);
  242. elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
  243. }
  244. }
  245. /*
  246.  * tg_rewriteQuery -
  247.  *   r - the recipe being rewritten
  248.  *   n - the node that we're current at
  249.  *   q - a QueryTree List containing the parse tree of the node
  250.  *   inputQlist - the parsetrees of its input nodes,
  251.  *    the size of inputQlist must be the same as the
  252.  *    number of input nodes.  Some elements in the inpuQlist
  253.  *    may be null if the inputs to those nodes are unconnected
  254.  *
  255.  * this is the main routine for rewriting the recipe queries
  256.  * the original query tree 'q' is modified
  257.  */
  258. static void
  259. tg_rewriteQuery(TgRecipe * r,
  260. TgNode * n,
  261. QueryTreeList * q,
  262. QueryTreeList * inputQlist)
  263. {
  264. Query    *orig;
  265. Query    *inputQ;
  266. int i;
  267. List    *rtable;
  268. List    *input_rtable;
  269. int rt_length;
  270. /* orig is the original parse tree of the node */
  271. orig = q->qtrees[0];
  272. /*-------------------------------------------------------------------
  273.    step 1:
  274.    form a combined range table from all the range tables in the original
  275.    query as well as the input nodes
  276.    form a combined qualification from the qual in the original plus
  277.    the quals of the input nodes
  278.   -------------------------------------------------------------------
  279. */
  280. /* start with the original range table */
  281. rtable = orig->rtable;
  282. rt_length = length(rtable);
  283. for (i = 0; i < n->inNodes->num; i++)
  284. {
  285. if (n->inNodes->val[i] != NULL &&
  286. n->inNodes->val[i]->nodeType != TG_TEE_NODE)
  287. {
  288. inputQ = inputQlist->qtrees[i];
  289. input_rtable = inputQ->rtable;
  290. /*
  291.  * need to offset the var nodes in the qual and targetlist
  292.  * because they are indexed off the original rtable
  293.  */
  294. OffsetVarNodes((Node *) inputQ->qual, rt_length, 0);
  295. OffsetVarNodes((Node *) inputQ->targetList, rt_length, 0);
  296. /* append the range tables from the children nodes */
  297. rtable = nconc(rtable, input_rtable);
  298. /*
  299.  * append the qualifications of the child node into the
  300.  * original qual list
  301.  */
  302. AddQual(orig, inputQ->qual);
  303. }
  304. }
  305. orig->rtable = rtable;
  306. /*
  307.  * step 2: rewrite the target list of the original parse tree if there
  308.  * are any references to params, replace them with the appropriate
  309.  * target list entry of the children node
  310.  */
  311. if (orig->targetList != NIL)
  312. {
  313. List    *tl;
  314. TargetEntry *tle;
  315. foreach(tl, orig->targetList)
  316. {
  317. tle = lfirst(tl);
  318. if (tle->resdom != NULL)
  319. tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist);
  320. }
  321. }
  322. /*
  323.  * step 3: rewrite the qual of the original parse tree if there are
  324.  * any references to params, replace them with the appropriate target
  325.  * list entry of the children node
  326.  */
  327. if (orig->qual)
  328. {
  329. if (nodeTag(orig->qual) == T_List)
  330. elog(ERROR, "tg_rewriteQuery: Whoa! why is my qual a List???");
  331. orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist);
  332. }
  333. /*
  334.  * at this point, we're done with the rewrite, the querytreelist q has
  335.  * been modified
  336.  */
  337. }
  338. /* tg_replaceNumberedParam:
  339.    this procedure replaces the specified numbered param with a
  340.    reference to a range table
  341.    this procedure recursively calls itself
  342.    it returns a (possibly modified) Node*.
  343. */
  344. static Node *
  345. tg_replaceNumberedParam(Node *expression,
  346. int pnum, /* the number of the parameter */
  347. int rt_ind, /* the range table index */
  348. char *teeRelName) /* the relname of the tee
  349.  * table */
  350. {
  351. TargetEntry *param_tle;
  352. Param    *p;
  353. Var    *newVar,
  354.    *oldVar;
  355. if (expression == NULL)
  356. return NULL;
  357. switch (nodeTag(expression))
  358. {
  359. case T_Param:
  360. {
  361. /*
  362.  * the node is a parameter, substitute the entry from the
  363.  * target list of the child that corresponds to the
  364.  * parameter number
  365.  */
  366. p = (Param *) expression;
  367. /* we only deal with the case of numbered parameters */
  368. if (p->paramkind == PARAM_NUM && p->paramid == pnum)
  369. {
  370. if (p->param_tlist)
  371. {
  372. /*
  373.  * we have a parameter with an attribute like
  374.  * $N.foo so replace it with a new var node
  375.  */
  376. /* param tlist can only have one entry in them! */
  377. param_tle = (TargetEntry *) (lfirst(p->param_tlist));
  378. oldVar = (Var *) param_tle->expr;
  379. oldVar->varno = rt_ind;
  380. oldVar->varnoold = rt_ind;
  381. return (Node *) oldVar;
  382. }
  383. else
  384. {
  385. /* we have $N without the .foo */
  386. bool defined;
  387. bool isRel;
  388. /*
  389.  * TODO here, we need to check to see whether the
  390.  * type of the tee is a complex type (relation) or
  391.  * a simple type
  392.  */
  393. /*
  394.  * if it is a simple type, then we need to get the
  395.  * "result" attribute from the tee relation
  396.  */
  397. isRel = (typeidTypeRelid(p->paramtype) != 0);
  398. if (isRel)
  399. {
  400. newVar = makeVar(rt_ind,
  401.  0, /* the whole tuple */
  402.    TypeGet(teeRelName, &defined),
  403.  -1,
  404.  0,
  405.  rt_ind,
  406.  0);
  407. return (Node *) newVar;
  408. }
  409. else
  410. newVar = makeVar(rt_ind,
  411.  1, /* just the first field,
  412.  * which is 'result' */
  413.    TypeGet(teeRelName, &defined),
  414.  -1,
  415.  0,
  416.  rt_ind,
  417.  0);
  418. return (Node *) newVar;
  419. }
  420. }
  421. else
  422. elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind);
  423. }
  424. break;
  425. case T_Expr:
  426. {
  427. /*
  428.  * the node is an expression, we need to recursively call
  429.  * ourselves until we find parameter nodes
  430.  */
  431. List    *l;
  432. Expr    *expr = (Expr *) expression;
  433. List    *newArgs;
  434. /*
  435.  * we have to make a new args lists because Params can be
  436.  * replaced by Var nodes in tg_replaceNumberedParam()
  437.  */
  438. newArgs = NIL;
  439. /*
  440.  * we only care about argument to expressions, it doesn't
  441.  * matter when the opType is
  442.  */
  443. /* recursively rewrite the arguments of this expression */
  444. foreach(l, expr->args)
  445. {
  446. newArgs = lappend(newArgs,
  447.   tg_replaceNumberedParam(lfirst(l),
  448.   pnum,
  449.   rt_ind,
  450. teeRelName));
  451. }
  452. /* change the arguments of the expression */
  453. expr->args = newArgs;
  454. }
  455. break;
  456. default:
  457. {
  458. /* ignore other expr types */
  459. }
  460. }
  461. return expression;
  462. }
  463. /* tg_rewriteParamsInExpr:
  464.    rewrite the params in expressions by using the targetlist entries
  465.    from the input parsetrees
  466.    this procedure recursively calls itself
  467.    it returns a (possibly modified) Node*.
  468. */
  469. static Node *
  470. tg_rewriteParamsInExpr(Node *expression, QueryTreeList * inputQlist)
  471. {
  472. List    *tl;
  473. TargetEntry *param_tle,
  474.    *tle;
  475. Param    *p;
  476. int childno;
  477. char    *resname;
  478. if (expression == NULL)
  479. return NULL;
  480. switch (nodeTag(expression))
  481. {
  482. case T_Param:
  483. {
  484. /*
  485.  * the node is a parameter, substitute the entry from the
  486.  * target list of the child that corresponds to the
  487.  * parameter number
  488.  */
  489. p = (Param *) expression;
  490. /* we only deal with the case of numbered parameters */
  491. if (p->paramkind == PARAM_NUM)
  492. {
  493. /* paramid's start from 1 */
  494. childno = p->paramid - 1;
  495. if (p->param_tlist)
  496. {
  497. /*
  498.  * we have a parameter with an attribute like
  499.  * $N.foo so match the resname "foo" against the
  500.  * target list of the (N-1)th inputQlist
  501.  */
  502. /* param tlist can only have one entry in them! */
  503. param_tle = (TargetEntry *) (lfirst(p->param_tlist));
  504. resname = param_tle->resdom->resname;
  505. if (inputQlist->qtrees[childno])
  506. {
  507. foreach(tl, inputQlist->qtrees[childno]->targetList)
  508. {
  509. tle = lfirst(tl);
  510. if (strcmp(resname, tle->resdom->resname) == 0)
  511. return tle->expr;
  512. }
  513. }
  514. else
  515. elog(ERROR, "tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid);
  516. }
  517. else
  518. {
  519. /* we have $N without the .foo */
  520. /* use the first resdom in the targetlist of the */
  521. /* appropriate child query */
  522. tl = inputQlist->qtrees[childno]->targetList;
  523. tle = lfirst(tl);
  524. return tle->expr;
  525. }
  526. }
  527. else
  528. elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind);
  529. }
  530. break;
  531. case T_Expr:
  532. {
  533. /*
  534.  * the node is an expression, we need to recursively call
  535.  * ourselves until we find parameter nodes
  536.  */
  537. List    *l;
  538. Expr    *expr = (Expr *) expression;
  539. List    *newArgs;
  540. /*
  541.  * we have to make a new args lists because Params can be
  542.  * replaced by Var nodes in tg_rewriteParamsInExpr()
  543.  */
  544. newArgs = NIL;
  545. /*
  546.  * we only care about argument to expressions, it doesn't
  547.  * matter when the opType is
  548.  */
  549. /* recursively rewrite the arguments of this expression */
  550. foreach(l, expr->args)
  551. {
  552. newArgs = lappend(newArgs,
  553.   tg_rewriteParamsInExpr(lfirst(l), inputQlist));
  554. }
  555. /* change the arguments of the expression */
  556. expr->args = newArgs;
  557. }
  558. break;
  559. default:
  560. {
  561. /* ignore other expr types */
  562. }
  563. }
  564. return expression;
  565. }
  566. /*
  567.    getParamTypes:
  568.   given an element, finds its parameter types.
  569.   the typev array argument is set to the parameter types.
  570.   the parameterCount is returned
  571.    this code is very similar to ProcedureDefine() in pg_proc.c
  572. */
  573. static int
  574. getParamTypes(TgElement * elem, Oid *typev)
  575. {
  576. /* this code is similar to ProcedureDefine() */
  577. int16 parameterCount;
  578. bool defined;
  579. Oid toid;
  580. char    *t;
  581. int i,
  582. j;
  583. parameterCount = 0;
  584. for (i = 0; i < 8; i++)
  585. typev[i] = 0;
  586. for (j = 0; j < elem->inTypes->num; j++)
  587. {
  588. if (parameterCount == 8)
  589. {
  590. elog(ERROR,
  591.  "getParamTypes: Ingredients cannot take > 8 arguments");
  592. }
  593. t = elem->inTypes->val[j];
  594. if (strcmp(t, "opaque") == 0)
  595. {
  596. elog(ERROR,
  597.  "getParamTypes: Ingredient functions cannot take type 'opaque'");
  598. }
  599. else
  600. {
  601. toid = TypeGet(elem->inTypes->val[j], &defined);
  602. if (!OidIsValid(toid))
  603. elog(ERROR, "getParamTypes: arg type '%s' is not defined", t);
  604. if (!defined)
  605. elog(NOTICE, "getParamTypes: arg type '%s' is only a shell", t);
  606. }
  607. typev[parameterCount++] = toid;
  608. }
  609. return parameterCount;
  610. }
  611. /*
  612.  * tg_parseTeeNode
  613.  *
  614.  *  handles the parsing of the tee node
  615.  *
  616.  *
  617.  */
  618. static QueryTreeList *
  619. tg_parseTeeNode(TgRecipe * r,
  620. TgNode * n, /* the tee node */
  621. int i, /* which input this node is to its parent */
  622. QueryTreeList * qList,
  623. TeeInfo * teeInfo)
  624. {
  625. QueryTreeList *q;
  626. char    *tt;
  627. int rt_ind;
  628. Query    *orig;
  629. /*
  630.  * the input Node is a tee node, so we need to do the following: we
  631.  * need to parse the child of the tee node, we add that to our query
  632.  * tree list we need the name of the tee node table the tee node table
  633.  * is the table into which the tee node may materialize results.  Call
  634.  * it TT we add a range table to our existing query with TT in it we
  635.  * need to replace the parameter $i with TT (otherwise the optimizer
  636.  * won't know to use the table on expression containining $i) After
  637.  * that rewrite, the optimizer will generate sequential scans of TT
  638.  *
  639.  * Later, in the glue phase, we replace all instances of TT sequential
  640.  * scans with the actual Tee node
  641.  */
  642. q = tg_parseSubQuery(r, n, teeInfo);
  643. /* tt is the name of the tee node table */
  644. tt = n->nodeName;
  645. if (q)
  646. appendTeeQuery(teeInfo, q, tt);
  647. orig = qList->qtrees[0];
  648. rt_ind = RangeTablePosn(orig->rtable, tt);
  649. /*
  650.  * check to see that this table is not part of the range table
  651.  * already.  This usually only happens if multiple inputs are
  652.  * connected to the same Tee.
  653.  */
  654. if (rt_ind == 0)
  655. {
  656. orig->rtable = lappend(orig->rtable,
  657.    addRangeTableEntry(NULL,
  658.   tt,
  659.   tt,
  660.   FALSE,
  661.   FALSE));
  662. rt_ind = length(orig->rtable);
  663. }
  664. orig->qual = tg_replaceNumberedParam(orig->qual,
  665.  i + 1, /* params start at 1 */
  666.  rt_ind,
  667.  tt);
  668. return qList;
  669. }
  670. /*
  671.  * tg_parseSubQuery:
  672.  *   go backwards from a node and parse the query
  673.  *
  674.  *  the result parse tree is passed back
  675.  *
  676.  * could return NULL if trying to parse a teeNode
  677.  * that's already been processed by another parent
  678.  *
  679.  */
  680. static QueryTreeList *
  681. tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
  682. {
  683. TgElement  *elem;
  684. char    *funcName;
  685. Oid typev[8], /* eight arguments maximum */
  686. relid;
  687. int i,
  688. parameterCount;
  689. QueryTreeList *qList; /* the parse tree of the nodeElement */
  690. QueryTreeList *inputQlist; /* the list of parse trees for the inputs
  691.  * to this node */
  692. QueryTreeList *q;
  693. TgNode    *child;
  694. Relation rel;
  695. unsigned int len;
  696. TupleDesc tupdesc;
  697. qList = NULL;
  698. if (n->nodeType == TG_INGRED_NODE)
  699. {
  700. /* parse each ingredient node in turn */
  701. elem = n->nodeElem;
  702. switch (elem->srcLang)
  703. {
  704. case TG_SQL:
  705. {
  706. /*
  707.  * for SQL ingredients, the SQL query is contained in
  708.  * the 'src' field
  709.  */
  710. #ifdef DEBUG_RECIPE
  711. elog(NOTICE, "calling parser with %s", elem->src);
  712. #endif  /* DEBUG_RECIPE */
  713. parameterCount = getParamTypes(elem, typev);
  714. qList = parser(elem->src, typev, parameterCount);
  715. if (qList->len > 1)
  716. {
  717. elog(NOTICE,
  718.  "tg_parseSubQuery: parser produced > 1 query tree");
  719. }
  720. }
  721. break;
  722. case TG_C:
  723. {
  724. /* C ingredients are registered functions in postgres */
  725. /*
  726.  * we create a new query string by using the function
  727.  * name (found in the 'src' field) and adding
  728.  * parameters to it so if the function was FOOBAR and
  729.  * took in two arguments, we would create a string
  730.  * select FOOBAR($1,$2)
  731.  */
  732. char newquery[1000];
  733. funcName = elem->src;
  734. parameterCount = getParamTypes(elem, typev);
  735. if (parameterCount > 0)
  736. {
  737. int i;
  738. snprintf(newquery, 1000, "select %s($1", funcName);
  739. for (i = 1; i < parameterCount; i++)
  740. snprintf(newquery, 1000, "%s,$%d", pstrdup(newquery), i);
  741. snprintf(newquery, 1000, "%s)", pstrdup(newquery));
  742. }
  743. else
  744. snprintf(newquery, 1000, "select %s()", funcName);
  745. #ifdef DEBUG_RECIPE
  746. elog(NOTICE, "calling parser with %s", newquery);
  747. #endif  /* DEBUG_RECIPE */
  748. qList = parser(newquery, typev, parameterCount);
  749. if (qList->len > 1)
  750. {
  751. elog(NOTICE,
  752.  "tg_parseSubQuery: parser produced > 1 query tree");
  753. }
  754. }
  755. break;
  756. case TG_RECIPE_GRAPH:
  757. elog(NOTICE, "tg_parseSubQuery: can't parse recipe graph ingredients yet!");
  758. break;
  759. case TG_COMPILED:
  760. elog(NOTICE, "tg_parseSubQuery: can't parse compiled ingredients yet!");
  761. break;
  762. default:
  763. elog(NOTICE, "tg_parseSubQuery: unknown srcLang: %d", elem->srcLang);
  764. }
  765. /* parse each of the subrecipes that are input to this node */
  766. if (n->inNodes->num > 0)
  767. {
  768. inputQlist = malloc(sizeof(QueryTreeList));
  769. inputQlist->len = n->inNodes->num + 1;
  770. inputQlist->qtrees = (Query **) malloc(inputQlist->len * sizeof(Query *));
  771. for (i = 0; i < n->inNodes->num; i++)
  772. {
  773. inputQlist->qtrees[i] = NULL;
  774. if (n->inNodes->val[i])
  775. {
  776. if (n->inNodes->val[i]->nodeType == TG_TEE_NODE)
  777. {
  778. qList = tg_parseTeeNode(r, n->inNodes->val[i],
  779. i, qList, teeInfo);
  780. }
  781. else
  782. { /* input node is not a Tee */
  783. q = tg_parseSubQuery(r, n->inNodes->val[i],
  784.  teeInfo);
  785. Assert(q->len == 1);
  786. inputQlist->qtrees[i] = q->qtrees[0];
  787. }
  788. }
  789. }
  790. /* now, we have all the query trees from our input nodes */
  791. /* transform the original parse tree appropriately */
  792. tg_rewriteQuery(r, n, qList, inputQlist);
  793. }
  794. }
  795. else if (n->nodeType == TG_EYE_NODE)
  796. {
  797. /*
  798.  * if we hit an eye, we need to stop and make what we have into a
  799.  * subrecipe query block
  800.  */
  801. elog(NOTICE, "tg_parseSubQuery: can't handle eye nodes yet");
  802. }
  803. else if (n->nodeType == TG_TEE_NODE)
  804. {
  805. /*
  806.  * if we hit a tee, check to see if the parsing has been done for
  807.  * this tee already by the other parent
  808.  */
  809. rel = RelationNameGetRelation(n->nodeName);
  810. if (RelationIsValid(rel))
  811. {
  812. /*
  813.  * this tee has already been visited, no need to do any
  814.  * further processing
  815.  */
  816. return NULL;
  817. }
  818. else
  819. {
  820. /* we need to process the child of the tee first, */
  821. child = n->inNodes->val[0];
  822. if (child->nodeType == TG_TEE_NODE)
  823. {
  824. /* nested Tee nodes */
  825. qList = tg_parseTeeNode(r, child, 0, qList, teeInfo);
  826. return qList;
  827. }
  828. Assert(child != NULL);
  829. /* parse the input node */
  830. q = tg_parseSubQuery(r, child, teeInfo);
  831. Assert(q->len == 1);
  832. /* add the parsed query to the main list of queries */
  833. qList = appendQlist(qList, q);
  834. /* need to create the tee table here */
  835. /*
  836.  * the tee table created is used both for materializing the
  837.  * values at the tee node, and for parsing and optimization.
  838.  * The optimization needs to have a real table before it will
  839.  * consider scans on it
  840.  */
  841. /*
  842.  * first, find the type of the tuples being produced by the
  843.  * tee.  The type is the same as the output type of the child
  844.  * node.
  845.  *
  846.  * NOTE: we are assuming that the child node only has a single
  847.  * output here!
  848.  */
  849. getParamTypes(child->nodeElem, typev);
  850. /*
  851.  * the output type is either a complex type, (and is thus a
  852.  * relation) or is a simple type
  853.  */
  854. rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]);
  855. if (RelationIsValid(rel))
  856. {
  857. /*
  858.  * for complex types, create new relation with the same
  859.  * tuple descriptor as the output table type
  860.  */
  861. len = length(q->qtrees[0]->targetList);
  862. tupdesc = rel->rd_att;
  863. relid = heap_create_with_catalog(
  864.    child->nodeElem->outTypes->val[0],
  865.    tupdesc, RELKIND_RELATION, false);
  866. }
  867. else
  868. {
  869. /*
  870.  * we have to create a relation with one attribute of the
  871.  * simple base type.  That attribute will have an attr
  872.  * name of "result"
  873.  */
  874. /* NOTE: ignore array types for the time being */
  875. len = 1;
  876. tupdesc = CreateTemplateTupleDesc(len);
  877. if (!TupleDescInitEntry(tupdesc, 1,
  878. "result",
  879. InvalidOid,
  880. -1, 0, false))
  881. elog(NOTICE, "tg_parseSubQuery: unexpected result from TupleDescInitEntry");
  882. else
  883. {
  884. relid = heap_create_with_catalog(
  885.    child->nodeElem->outTypes->val[0],
  886.    tupdesc, RELKIND_RELATION, false);
  887. }
  888. }
  889. }
  890. }
  891. else if (n->nodeType == TG_RECIPE_NODE)
  892. elog(NOTICE, "tg_parseSubQuery: can't handle embedded recipes yet!");
  893. else
  894. elog(NOTICE, "unknown nodeType: %d", n->nodeType);
  895. return qList;
  896. }
  897. /*
  898.  * OffsetVarAttno -
  899.  *   recursively find all the var nodes with the specified varno
  900.  * and offset their varattno with the offset
  901.  *
  902.  * code is similar to OffsetVarNodes in rewriteManip.c
  903.  */
  904. void
  905. OffsetVarAttno(Node *node, int varno, int offset)
  906. {
  907. if (node == NULL)
  908. return;
  909. switch (nodeTag(node))
  910. {
  911. case T_TargetEntry:
  912. {
  913. TargetEntry *tle = (TargetEntry *) node;
  914. OffsetVarAttno(tle->expr, varno, offset);
  915. }
  916. break;
  917. case T_Expr:
  918. {
  919. Expr    *expr = (Expr *) node;
  920. OffsetVarAttno((Node *) expr->args, varno, offset);
  921. }
  922. break;
  923. case T_Var:
  924. {
  925. Var    *var = (Var *) node;
  926. if (var->varno == varno)
  927. var->varattno += offset;
  928. }
  929. break;
  930. case T_List:
  931. {
  932. List    *l;
  933. foreach(l, (List *) node)
  934. OffsetVarAttno(lfirst(l), varno, offset);
  935. }
  936. break;
  937. default:
  938. /* ignore the others */
  939. break;
  940. }
  941. }
  942. /*
  943.  * appendQlist
  944.  *   add the contents of a QueryTreeList q2 to the end of the QueryTreeList
  945.  *  q1
  946.  *
  947.  * returns a new querytree list
  948.  */
  949. QueryTreeList *
  950. appendQlist(QueryTreeList * q1, QueryTreeList * q2)
  951. {
  952. QueryTreeList *newq;
  953. int i,
  954. j;
  955. int newlen;
  956. if (q1 == NULL)
  957. return q2;
  958. if (q2 == NULL)
  959. return q1;
  960. newlen = q1->len + q2->len;
  961. newq = (QueryTreeList *) malloc(sizeof(QueryTreeList));
  962. newq->len = newlen;
  963. newq->qtrees = (Query **) malloc(newlen * sizeof(Query *));
  964. for (i = 0; i < q1->len; i++)
  965. newq->qtrees[i] = q1->qtrees[i];
  966. for (j = 0; j < q2->len; j++)
  967. newq->qtrees[i + j] = q2->qtrees[j];
  968. return newq;
  969. }
  970. /*
  971.  * appendTeeQuery
  972.  *
  973.  * modify the query field of the teeInfo list of the particular tee node
  974.  */
  975. static void
  976. appendTeeQuery(TeeInfo * teeInfo, QueryTreeList * q, char *teeNodeName)
  977. {
  978. int i;
  979. Assert(teeInfo);
  980. for (i = 0; i < teeInfo->num; i++)
  981. {
  982. if (strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0)
  983. {
  984. Assert(q->len == 1);
  985. teeInfo->val[i].tpi_parsetree = q->qtrees[0];
  986. return;
  987. }
  988. }
  989. elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo");
  990. }
  991. /*
  992.  * replaceSeqScan
  993.  *   replaces sequential scans of a specified relation with the tee plan
  994.  * the relation is specified by its index in the range table,  rt_ind
  995.  *
  996.  * returns the modified plan
  997.  * the offset_attno is the offset that needs to be added to the parent's
  998.  * qual or targetlist because the child plan has been replaced with a tee node
  999.  */
  1000. static void
  1001. replaceSeqScan(Plan *plan, Plan *parent,
  1002.    int rt_ind, Plan *tplan)
  1003. {
  1004. Scan    *snode;
  1005. Tee    *teePlan;
  1006. Result    *newPlan;
  1007. if (plan == NULL)
  1008. return;
  1009. if (plan->type == T_SeqScan)
  1010. {
  1011. snode = (Scan *) plan;
  1012. if (snode->scanrelid == rt_ind)
  1013. {
  1014. /*
  1015.  * found the sequential scan that should be replaced with the
  1016.  * tplan.
  1017.  */
  1018. /* we replace the plan, but we also need to modify its parent */
  1019. /*
  1020.  * replace the sequential scan with a Result node the reason
  1021.  * we use a result node is so that we get the proper
  1022.  * projection behavior.  The Result node is simply (ab)used as
  1023.  * a projection node
  1024.  */
  1025. newPlan = makeNode(Result);
  1026. newPlan->plan.cost = 0.0;
  1027. newPlan->plan.state = (EState *) NULL;
  1028. newPlan->plan.targetlist = plan->targetlist;
  1029. newPlan->plan.lefttree = tplan;
  1030. newPlan->plan.righttree = NULL;
  1031. newPlan->resconstantqual = NULL;
  1032. newPlan->resstate = NULL;
  1033. /* change all the varno's to 1 */
  1034. ChangeVarNodes((Node *) newPlan->plan.targetlist,
  1035.    snode->scanrelid, 1);
  1036. if (parent)
  1037. {
  1038. teePlan = (Tee *) tplan;
  1039. if (parent->lefttree == plan)
  1040. parent->lefttree = (Plan *) newPlan;
  1041. else
  1042. parent->righttree = (Plan *) newPlan;
  1043. if (teePlan->leftParent == NULL)
  1044. teePlan->leftParent = (Plan *) newPlan;
  1045. else
  1046. teePlan->rightParent = (Plan *) newPlan;
  1047. /* comment for now to test out executor-stuff
  1048. if (parent->state) {
  1049. ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan);
  1050. }
  1051. */
  1052. }
  1053. }
  1054. }
  1055. else
  1056. {
  1057. if (plan->lefttree)
  1058. replaceSeqScan(plan->lefttree, plan, rt_ind, tplan);
  1059. if (plan->righttree)
  1060. replaceSeqScan(plan->righttree, plan, rt_ind, tplan);
  1061. }
  1062. }
  1063. /*
  1064.  * replaceTeeScans
  1065.  *   places the sequential scans of the Tee table with
  1066.  * a connection to the actual tee plan node
  1067.  */
  1068. static Plan *
  1069. replaceTeeScans(Plan *plan, Query *parsetree, TeeInfo * teeInfo)
  1070. {
  1071. int i;
  1072. List    *rtable;
  1073. RangeTblEntry *rte;
  1074. char prefix[5];
  1075. int rt_ind;
  1076. Plan    *tplan;
  1077. rtable = parsetree->rtable;
  1078. if (rtable == NULL)
  1079. return plan;
  1080. /*
  1081.  * look through the range table for the tee relation entry, that will
  1082.  * give use the varno we need to detect which sequential scans need to
  1083.  * be replaced with tee nodes
  1084.  */
  1085. rt_ind = 0;
  1086. while (rtable != NIL)
  1087. {
  1088. rte = lfirst(rtable);
  1089. rtable = lnext(rtable);
  1090. rt_ind++; /* range table references in varno fields
  1091.  * start w/ 1 */
  1092. /*
  1093.  * look for the "tee_" prefix in the refname, also check to see
  1094.  * that the relname and the refname are the same this should
  1095.  * eliminate any user-specified table and leave us with the tee
  1096.  * table entries only
  1097.  */
  1098. if ((strlen(rte->refname) < 4) ||
  1099. (strcmp(rte->relname, rte->refname) != 0))
  1100. continue;
  1101. StrNCpy(prefix, rte->refname, 5);
  1102. if (strcmp(prefix, "tee_") == 0)
  1103. {
  1104. /* okay, we found a tee node entry in the range table */
  1105. /* find the appropriate plan in the teeInfo list */
  1106. tplan = NULL;
  1107. for (i = 0; i < teeInfo->num; i++)
  1108. {
  1109. if (strcmp(teeInfo->val[i].tpi_relName,
  1110.    rte->refname) == 0)
  1111. tplan = teeInfo->val[i].tpi_plan;
  1112. }
  1113. if (tplan == NULL)
  1114. elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan");
  1115. /*
  1116.  * replace the sequential scan node with that var number with
  1117.  * the tee plan node
  1118.  */
  1119. replaceSeqScan(plan, NULL, rt_ind, tplan);
  1120. }
  1121. }
  1122. return plan;
  1123. }
  1124. #endif  /* TIOGA */