home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / test / testruleplan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  38.0 KB  |  1,573 lines

  1.  
  2. /* ----------------------------------------------------------------
  3.  *              Utilities to read/construct plans 
  4.  *
  5.  * $Header: /private/postgres/src/test/RCS/testruleplan.c,v 1.12 1992/07/04 04:03:33 mao Exp $
  6.  * ----------------------------------------------------------------
  7.  */
  8.  
  9.  
  10.  
  11. #include <stdio.h>
  12. #include "catalog/catname.h"
  13. #include "access/tupdesc.h"
  14. #include "access/ftup.h"
  15. #include "utils/log.h"
  16. #include "tcop/tcop.h"
  17. #include "rules/prs2.h"
  18. #include "rules/prs2stub.h"
  19. #include "access/heapam.h"
  20. #include "utils/rel.h"
  21. #include "executor/executor.h"
  22. #include "planner/keys.h"
  23. #include "nodes/plannodes.h"
  24. #include "nodes/plannodes.a.h"
  25. #include "nodes/primnodes.h"
  26. #include "nodes/primnodes.a.h"
  27. #include "tcop/dest.h"
  28.  
  29. /*--------------------- DEFINITIONS ---------------------------------*/
  30. #define MAX_RELATIONS        100
  31. #define MAX_NAME_LENGTH        100
  32.  
  33. #define IMPORT_ATTRNO(relNo)    (2*(relNo))
  34. #define EXPORT_ATTRNO(relNo)    (2*(relNo)-1)
  35.  
  36. #define ISBLANK(x)    ((x)==' ' || (x)=='\t' || (x)=='\n')
  37. #define ISDIGIT(x)    ((x)<='9' && (x)>='0')
  38.  
  39. /*----
  40.  * some postgres OIDs hardwired in this program...
  41.  * They might have to change....
  42.  */
  43. #define INT4_TYPE    23
  44. #define INT4_LENGTH    4
  45. #define INT4_EQUAL    65    /* NOTE: this is not a pg_operator.oid, */
  46.                 /* but a pg_proc.oid            */
  47. #define BOOL_TYPE    16
  48.  
  49. /*------
  50.  * LOCK FORMAT
  51.  */
  52. #define LOCK_FORMAT \
  53. "(numOfLocks: 1 (ruleId: %ld lockType: %c attrNo: %d planNo: %d partindx: %d npart: %d))"
  54.  
  55. /*--------------------- EXTERN VARIABLES& FUNCTIONS  ----------------*/
  56. extern int TESTRULE_DEBUG_FLAG;    /* define in testrules.c */
  57.  
  58. extern Var RMakeVar();
  59. extern Resdom RMakeResdom();
  60. extern Oper RMakeOper();
  61. extern Const RMakeConst();
  62. extern Param RMakeParam();
  63. extern JoinRuleInfo RMakeJoinRuleInfo();
  64. extern SeqScan RMakeSeqScan();
  65. extern NestLoop RMakeNestLoop();
  66. extern Result RMakeResult();
  67. extern double getTimer();
  68. extern EState CreateExecutorState();
  69. extern List QueryRewrite();
  70.  
  71. static Var my_make_var();
  72. static Resdom my_make_resdom();
  73. static Const my_make_const();
  74. static Param my_make_param();
  75. static List my_make_qual();
  76. static JoinRuleInfo my_make_ruleinfo();
  77. static void readName();
  78. static Result my_make_constresult();
  79. static Result my_make_paramresult();
  80.  
  81. List makePlanFromFile();
  82. List makeTestNLRulePlan();
  83. List makeNLRulePlan();
  84. List make_parsetree();
  85.  
  86.  
  87. /*==================================================================
  88.  *
  89.  * makePlanFromQuery
  90.  *
  91.  * Given a query create a list of 2-item lists containing
  92.  *    a) a feature (either EXEC_RUN or EXEC_RETONE)
  93.  *    b) a query descriptor
  94.  *
  95.  * If no query rewrite rules are involved then the top-level list must
  96.  * have only one item...
  97.  *
  98.  * NOTE: we support a new kind of POSTGRES command, called "retone"
  99.  * This command is tha same as retrieve, but it stops after the
  100.  * first tuple...
  101.  *
  102.  * Returns LispNil if the query is not a valid one..
  103.  */
  104. List
  105. makePlanFromQuery(queryString)
  106. char *queryString;
  107. {
  108.     List plan, qDesc, parseTrees, parseTree;
  109.     List res, t;
  110.     char *s;
  111.     char query[10000];
  112.     int retoneFlag;
  113.     bool unrewritten;
  114.     List rewritten, oneItem;
  115.     List operation;
  116.     char cmd[100];
  117.     int i;
  118.  
  119.     if (TESTRULE_DEBUG_FLAG) {
  120.     printf("DEBUG: makePlanFromQuery: query='%s'\n", queryString);
  121.     fflush(stdout);
  122.     }
  123.  
  124.     /*
  125.      * is it a "retone" command ??
  126.      */
  127.     retoneFlag = 0;
  128.     s = queryString;
  129.     /* 
  130.      * skip blanks
  131.      */
  132.     while (*s == ' ' || *s == '\t' || *s == '\n')
  133.     s++;
  134.     /*
  135.      * now find the first word
  136.      */
  137.     i=0;
  138.     while ((s[i]>='a' && s[i]<='z') || (s[i]>='A' && s[i]<='Z')) {
  139.     cmd[i] = s[i];
  140.     i++;
  141.     }
  142.     cmd[i] = '\0';
  143.  
  144.     if (!strcmp(cmd, "retone")) {
  145.     retoneFlag = 1;
  146.     operation = lispAtom("retrieve");
  147.         sprintf(query, "retrieve");
  148.         strcat(query, s+6);
  149.     } else if (!strcmp(cmd, "retrieve")) {
  150.     operation = lispAtom("retrieve");
  151.     strcpy(query, queryString);
  152.     } else if (!strcmp(cmd, "replace")) {
  153.     operation = lispAtom("replace");
  154.     strcpy(query, queryString);
  155.     } else if (!strcmp(cmd, "delete")) {
  156.     operation = lispAtom("delete");
  157.     strcpy(query, queryString);
  158.     } else if (!strcmp(cmd, "append")) {
  159.     operation = lispAtom("append");
  160.     strcpy(query, queryString);
  161.     } else {
  162.     fprintf(stderr, "makePlanFromQuery: Illegal command '%s'\n", cmd);
  163.     exitpg(1);
  164.     }
  165.  
  166.     /*
  167.      * parse the query...
  168.      */
  169.     parseTrees = lispList();
  170.     parser(query, parseTrees);
  171.  
  172.     unrewritten = true;
  173.     foreach (t, parseTrees) {
  174.     ValidateParse(CAR(t));
  175.     /*
  176.      * rewrite queries...
  177.      */
  178.     if (unrewritten == true) {
  179.         if (( rewritten = QueryRewrite ( CAR(t) )) != LispNil) {
  180.         CAR(t) = CAR(rewritten);
  181.         CDR(last(rewritten)) = CDR(t);
  182.         CDR(t) = CDR(rewritten);
  183.         unrewritten = false;
  184.         continue;
  185.         }
  186.         unrewritten = false;
  187.     }
  188.  
  189.     }
  190.  
  191.     /*
  192.      * create the plan & the query descriptor
  193.      */
  194.     res = LispNil;
  195.     foreach (t, parseTrees) {
  196.     parseTree = CAR(t);
  197.     init_planner();
  198.     plan = (List) planner(parseTree);
  199.     qDesc = MakeQueryDesc(operation,
  200.                     parseTree, plan, LispNil, LispNil,
  201.                     LispNil, LispNil, lispInteger(0), None);
  202.  
  203.     /*
  204.      * OK, now create the lsit with the "feature", & the query Desc.
  205.      */
  206.     if (retoneFlag) {
  207.         oneItem = lispCons(lispInteger(EXEC_RETONE),
  208.             lispCons(qDesc, LispNil));
  209.     } else {
  210.         oneItem = lispCons(lispInteger(EXEC_RUN),
  211.             lispCons(qDesc, LispNil));
  212.     }
  213.  
  214.     res = nappend1(res, oneItem);
  215.  
  216.     }
  217.  
  218.     if (TESTRULE_DEBUG_FLAG) {
  219.     printf("DEBUG: makePlanFromQuery: RESULT = ");
  220.     lispDisplay(res, 0);
  221.     printf("\n");
  222.     }
  223.  
  224.     return(res);
  225. }
  226.  
  227.  
  228. /*==================================================================
  229.  *
  230.  * makePlanFromFile
  231.  *
  232.  * read a Plan from a file. If fileName == NULL< then stdin is used
  233.  *
  234.  * The file format is as follows:
  235.  *
  236.  *  a) the number of the range table entries
  237.  *  b) the relation names (there must be as many names as the
  238.  *    number read in (a)
  239.  *  c) a plan
  240.  *
  241.  * Then the program constructs a fake pase tree (containing
  242.  * only the tange table) and finally a query descriptor (which can
  243.  * be passed to ExecMain).
  244.  * It returns a list containing 2-item list, the first item being
  245.  * EXEC_RUN (an int) and the second the query descriptor.
  246.  *
  247.  */
  248. List
  249. makePlanFromFile(fname)
  250. char *fname;
  251. {
  252.     FILE *fp;
  253.     char *s;
  254.     char relNames[MAX_RELATIONS][MAX_NAME_LENGTH];
  255.     int c;
  256.     int nRel;
  257.     int i,j;
  258.     List parseTree, plan, qDesc;
  259.     List res;
  260.     long size;
  261.     char *realloc();
  262.     List StringToPlan();
  263.  
  264.     if (fname == NULL) {
  265.     /* 
  266.      * read from standard input
  267.      */
  268.     fp = stdin;
  269.     } else {
  270.     fp = fopen(fname, "r");
  271.     if (fp==NULL) {
  272.         elog(WARN, "Could not open file `%s'", fname);
  273.     }
  274.     }
  275.  
  276.  
  277.     /*
  278.      * read the number of range table entries
  279.      */
  280.     if (fscanf(fp, "%d", &nRel) !=1) {
  281.     elog(WARN, "Could not read # of range table entries");
  282.     }
  283.  
  284.     if (TESTRULE_DEBUG_FLAG) {
  285.     printf("DEBUG: makePlanFromFile: rtable (%d entries)[", nRel);
  286.     fflush(stdout);
  287.     }
  288.  
  289.     if (nRel > MAX_RELATIONS) {
  290.     elog(WARN, "Can not have more than %d relation in the rtable",
  291.         MAX_RELATIONS);
  292.     }
  293.  
  294.     /*
  295.      * read one by one the name of the relations & construct
  296.      * the range table
  297.      */
  298.     for (i=0; i<nRel; i++) {
  299.     readName(fp, relNames[i], 1);
  300.     if (relNames[i][0] == '\0') {
  301.         elog(WARN, "EOF while reading relation names (%d/%d)", i+1, nRel);
  302.     }
  303.     if (TESTRULE_DEBUG_FLAG) {
  304.         printf(" %s", i, relNames[i]);
  305.         fflush(stdout);
  306.     }
  307.     }
  308.     if (TESTRULE_DEBUG_FLAG) {
  309.     printf("]\n");
  310.     fflush(stdout);
  311.     }
  312.  
  313.     parseTree = make_parsetree(nRel, relNames);
  314.  
  315.     /*
  316.      * now read the plan
  317.      */
  318.     s = "()";
  319.     size = 100;
  320.     s = malloc(size);
  321.     i = 0;
  322.     while ((c=fgetc(fp))!=EOF) {
  323.     s[i] = c;
  324.     i++;
  325.     if (i>=size) {
  326.         size = size + 100;
  327.         s = realloc(s, size);
  328.     }
  329.     }
  330.     s[i] = '\0';
  331.  
  332.     plan = StringToPlan(s);
  333.  
  334.     qDesc = MakeQueryDesc(lispAtom("retrieve"),
  335.                 parseTree,
  336.                 plan,
  337.                 LispNil,
  338.                 LispNil,
  339.                 LispNil,
  340.                 LispNil,
  341.                 lispInteger(0),
  342.                 None);
  343.  
  344.     res = lispCons(lispInteger(EXEC_RETONE),
  345.         lispCons(qDesc, LispNil));
  346.     res = lispCons(res, LispNil);
  347.  
  348.     if (TESTRULE_DEBUG_FLAG) {
  349.     printf("DEBUG: makePlanFromFile: RESULT = ");
  350.     lispDisplay(res, 0);
  351.     printf("\n");
  352.     }
  353.     
  354.     return(res);
  355. }
  356.  
  357.  
  358. /*==============================================================
  359.  *
  360.  * makePlanFromNLRule
  361.  *
  362.  * create a plan suitable for testing rule stubs...
  363.  *
  364.  * This plan corresponds to a query of the form:
  365.  *
  366.  *     REL1.attr1 = REL2.attr2 and 
  367.  *    REL2.attr3 = REL3.attr4 and 
  368.  *    ... and RELn.attrk = C
  369.  *
  370.  * where C is an integer constant
  371.  * All the attributes attr1, attr2 ... are assumed to be of type `int4'
  372.  *
  373.  * ARGUMENTS:
  374.  * the argument is a string containing the following info:
  375.  * a) the number N of relations  (an int)
  376.  * b) the relation names, i.e. N names (with no quotes!)
  377.  * c) the attribute numbers attr1, attr2, etc.
  378.  *    these are (2*N-1) integers.
  379.  * d) the constant value 'C'
  380.  *
  381.  * For example a valid string is:
  382.  *    '3 R1 R2 R3 2 3 4 2 1 123'
  383.  *
  384.  *----------
  385.  * First we call makeTestNLRulePlan to create the plan,
  386.  * and the we create a query descriptor and finally return
  387.  * a 2-item list the first item being EXEC_RUN (an int)
  388.  * and the second the query descriptor.
  389.  *
  390.  */
  391. List
  392. makePlanFromNLRule(string)
  393. char *string;
  394. {
  395.     int nRel;
  396.     char relNames[MAX_RELATIONS][MAX_NAME_LENGTH];
  397.     AttributeNumber attrnos[2*MAX_RELATIONS-1];
  398.     int constvalue;
  399.     List plan, rangeTable, parseTree, qDesc;
  400.     List res;
  401.     char *s;
  402.     int i,j;
  403.  
  404.     s = string;
  405.  
  406.     /*
  407.      * parse the given string to find 'nRel', 'relNames',
  408.      * 'attrnos' and 'constvalue'
  409.      */
  410.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  411.     nRel = 0;
  412.     while ((*s) && ISDIGIT(*s)) {
  413.     nRel = 10 * nRel + (*s) - '0';
  414.     s++;
  415.     }
  416.     if (nRel == 0) {
  417.     fprintf(stderr, "makePlanFromNLRule: illegal string '%s'\n", string);
  418.     exitpg(1);
  419.     }
  420.     for (i=0; i<nRel; i++) {
  421.     while ((*s) && ISBLANK(*s)) s++;    /* skip blanks */
  422.     j=0;
  423.     while((*s) && !ISBLANK(*s)) {
  424.         relNames[i][j] = *s;
  425.         s++;
  426.         j++;
  427.     }
  428.     relNames[i][j] = '\0';
  429.     }
  430.     for (i=0; i<2*nRel-1; i++) {
  431.     while ((*s) && ISBLANK(*s)) s++;    /* skip blanks */
  432.     attrnos[i] = 0;
  433.     while ((*s) && ISDIGIT(*s)) {
  434.         attrnos[i] = 10 * attrnos[i] + (*s) - '0';
  435.         s++;
  436.     }
  437.     if (attrnos[i] == 0) {
  438.         fprintf(stderr,
  439.         "makePlanFromNLRule: illegal string '%s'\n", string);
  440.         exitpg(1);
  441.     }
  442.     }
  443.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  444.     constvalue = 0;
  445.     while ((*s) && ISDIGIT(*s)) {
  446.     constvalue = 10 * constvalue + (*s) - '0';
  447.     s++;
  448.     }
  449.  
  450.  
  451.     if (TESTRULE_DEBUG_FLAG) {
  452.     int k;
  453.     printf("DEBUG: makePlanFromNLRule: string = '%s'\n", string);
  454.     printf("DEBUG: makePlanFromNLRule:  nRel=%d [", nRel);
  455.     for (k=0; k<nRel; k++){
  456.         printf(" %s", relNames[k]);
  457.     }
  458.     printf("] attrnos=[");
  459.     for (k=0; k<2*nRel-1; k++){
  460.         printf(" %hd", attrnos[k]);
  461.     }
  462.     printf("] c=%d\n", constvalue);
  463.     fflush(stdout);
  464.     }
  465.  
  466.     /*----------
  467.      * OK, now make the plan + parse tree etc....
  468.      */
  469.     plan = makeTestNLRulePlan(nRel, attrnos, true, constvalue, NULL);
  470.  
  471.     parseTree = make_parsetree(nRel, relNames);
  472.     rangeTable = root_rangetable(parse_root(parseTree));
  473.     qDesc = MakeQueryDesc(lispAtom("retrieve"),
  474.                 parseTree,
  475.                 plan,
  476.                 LispNil,
  477.                 LispNil,
  478.                 LispNil,
  479.                 LispNil,
  480.                 lispInteger(0),
  481.                 None);
  482.  
  483.     res = lispCons(lispInteger(EXEC_RETONE),
  484.         lispCons(qDesc, LispNil));
  485.     res = lispCons(res, LispNil);
  486.  
  487.     if (TESTRULE_DEBUG_FLAG) {
  488.     printf("DEBUG: makePlanFromNLRule: RESULT=");
  489.     lispDisplay(res,0);
  490.     printf("\n");
  491.     fflush(stdout);
  492.     }
  493.  
  494.     return(res);
  495.  
  496. }
  497.  
  498.  
  499. /*----------------------------------------------------------------
  500.  * readName
  501.  *
  502.  * read a name at most MAX_NAME_LENGTH - 1 chars long
  503.  * if 'skipNewlines' is zero, then we only look till
  504.  * a '\n'. Otherwise we continue reading until we actually find a name
  505.  * (i.e. a non blank character).
  506.  */
  507. static
  508. void
  509. readName(fp,s, skipNewlines)
  510. FILE *fp;
  511. char *s;
  512. int skipNewlines;
  513. {
  514.     int i;
  515.     int c;
  516.     int done;
  517.  
  518.     /*
  519.      * Skip Blanks
  520.      */
  521.     done = 0;
  522.     do {
  523.     c = fgetc(fp);
  524.     if (c == EOF || (!skipNewlines && c == '\n')) {
  525.         /* 
  526.          * we have reached EOF (or the end of line
  527.          * in no-skipNewlines mode)
  528.          */
  529.         s[0] = '\0';
  530.         return;
  531.     }
  532.     if (c!= ' ' && c!= '\t' && c!='\n') {
  533.         /*
  534.          * we found the beginning of the name
  535.          */
  536.         done = true;
  537.     }
  538.     } while(!done);
  539.  
  540.     /*
  541.      * read the name
  542.      */
  543.     i = 0;
  544.     s[i] = c;
  545.     while (c != EOF && c != ' ' && c != '\t' && c != '\n') {
  546.     if (i<MAX_NAME_LENGTH-1) {
  547.         s[i] = c;
  548.         i++;
  549.     }
  550.     c = fgetc(fp);
  551.     }
  552.     s[i] = '\0';
  553. }
  554.  
  555. /*-----------------------------------------------------------------
  556.  *
  557.  * my_make_var
  558.  */
  559.  
  560. static
  561. Var
  562. my_make_var(varno, attno, varid)
  563. Index varno;
  564. AttributeNumber attno;
  565. List varid;
  566. {
  567.     Var var;
  568.  
  569.     var = RMakeVar();
  570.     set_varno(var, varno);
  571.     set_varattno(var, attno);
  572.     set_vartype(var, (ObjectId) INT4_TYPE);        /* type = int4 */
  573.     set_varid(var, varid);
  574.     
  575.     return(var);
  576. }
  577.  
  578.  
  579. /*-----------------------------------------------------------------
  580.  *
  581.  * my_make_resdom
  582.  */
  583. static
  584. Resdom
  585. my_make_resdom(resno, resname)
  586. AttributeNumber resno;
  587. Name resname;
  588. {
  589.     Resdom res;
  590.  
  591.     res = RMakeResdom();
  592.  
  593.     set_resno(res, resno);
  594.     set_restype(res, (ObjectId) INT4_TYPE);    /* int4 */
  595.     set_reslen(res, (Size) INT4_LENGTH);
  596.     set_resname(res, resname);
  597.     set_reskeyop(res, 0);
  598.  
  599.     return(res);
  600. }
  601.  
  602. /*-----------------------------------------------------------------
  603.  *
  604.  * my_make_const
  605.  *
  606.  * create an integer constant with the given value
  607.  */
  608. static
  609. Const
  610. my_make_const(value)
  611. int value;
  612. {
  613.     Const cnst;
  614.  
  615.     cnst = RMakeConst();
  616.     set_consttype(cnst, (ObjectId) INT4_TYPE);    /* int4 */
  617.     set_constlen(cnst, (Size) INT4_LENGTH);
  618.     set_constisnull(cnst, false);
  619.     set_constbyval(cnst, true);
  620.     set_constvalue(cnst, Int32GetDatum(value));
  621.  
  622.     return(cnst);
  623. }
  624. /*-----------------------------------------------------------------
  625.  * my_make_param
  626.  */
  627. static
  628. Param
  629. my_make_param(id, name)
  630. int id;
  631. char *name;
  632. {
  633.     Param p;
  634.     Name nnn;
  635.  
  636.     nnn = (Name) palloc(sizeof(NameData));
  637.     bzero(nnn, sizeof(NameData));
  638.     strcpy(nnn, name);
  639.  
  640.     p = RMakeParam();
  641.     set_paramkind(p, PARAM_OLD);
  642.     set_paramid(p, (AttributeNumber) id);
  643.     set_paramname(p, nnn);
  644.     set_paramtype(p, (ObjectId) 0);
  645.  
  646.     return(p);
  647. }
  648.  
  649. /*-----------------------------------------------------------------
  650.  *
  651.  * my_make_qual
  652.  *
  653.  * make a qual of the form "var1 = var2" (where var1 & var2
  654.  * are int4
  655.  */
  656. static
  657. List
  658. my_make_qual(operand1, operand2)
  659. Node operand1;
  660. Node operand2;
  661. {
  662.     Oper oper;
  663.     List qual, qualClause;
  664.  
  665.     oper = RMakeOper();
  666.     set_opno(oper, (ObjectId) INT4_EQUAL);    /* `=' for int4 */
  667.     set_oprelationlevel(oper, LispNil);
  668.     set_opresulttype(oper, (ObjectId) BOOL_TYPE);    /* bool */
  669.     set_op_fcache(oper, NULL);
  670.  
  671.     qualClause = lispCons(oper, LispNil);
  672.     qualClause = nappend1(qualClause, operand1);
  673.     qualClause = nappend1(qualClause, operand2);
  674.  
  675.     qual = lispCons(qualClause, LispNil);
  676.  
  677.     return(qual);
  678. }
  679.  
  680. /*-----------------------------------------------------------------
  681.  *
  682.  * my_make_ruleinfo
  683.  */
  684. static
  685. JoinRuleInfo
  686. my_make_ruleinfo(stubId, innerattrno, outerattrno, lockString)
  687. int stubId;
  688. AttributeNumber innerattrno;
  689. AttributeNumber outerattrno;
  690. char *lockString;
  691. {
  692.     JoinRuleInfo ruleInfo;
  693.     ObjectId ruleId;
  694.     RuleLock lock;
  695.  
  696.  
  697.     ruleInfo = RMakeJoinRuleInfo();
  698.  
  699.     lock = StringToRuleLock(lockString);
  700.  
  701.     set_jri_operator(ruleInfo, (ObjectId)65);    /* '=' for int4 */
  702.     set_jri_inattrno(ruleInfo, innerattrno);
  703.     set_jri_outattrno(ruleInfo, outerattrno);
  704.     set_jri_lock(ruleInfo, lock);
  705.     set_jri_ruleid(ruleInfo, ruleId);
  706.     set_jri_stubid(ruleInfo, (Prs2StubId) stubId);
  707.     set_jri_stub(ruleInfo, (Prs2OneStub) NULL);
  708.     set_jri_stats(ruleInfo, (Prs2StubStats) NULL);
  709.     return(ruleInfo);
  710. }
  711.  
  712.  
  713. /*-----------------------------------------------------------------
  714.  *
  715.  * my_make_constresult
  716.  */
  717. static
  718. Result
  719. my_make_constresult(constvalue)
  720. int constvalue;
  721. {
  722.     Result node;
  723.     List tlist;
  724.     Resdom res;
  725.     Const cnst;
  726.  
  727.     /*
  728.      * construct the target list
  729.      */
  730.     res = my_make_resdom((AttributeNumber) 1, "const");
  731.     cnst = my_make_const(constvalue);
  732.     tlist = lispCons(
  733.         lispCons(res, lispCons(cnst, LispNil)),
  734.         LispNil);
  735.  
  736.     /*
  737.      * now construct the node
  738.      */
  739.     node = RMakeResult();
  740.  
  741.     set_cost((Plan) node, 0.0);
  742.     set_fragment((Plan) node, 0);
  743.     set_state((Plan) node, NULL);
  744.     set_qptargetlist((Plan)node, tlist);
  745.     set_qpqual((Plan) node, LispNil);
  746.     set_lefttree((Plan)node, LispNil);
  747.     set_righttree((Plan)node, LispNil);
  748.     set_resrellevelqual(node, LispNil);
  749.     set_resconstantqual(node, LispNil);
  750.     set_resstate(node, NULL);
  751.     
  752.     return(node);
  753. }
  754.  
  755. /*-----------------------------------------------------------------
  756.  *
  757.  * my_make_paramresult
  758.  */
  759. static
  760. Result
  761. my_make_paramresult(id, name)
  762. int id;
  763. char *name;
  764. {
  765.     Result node;
  766.     List tlist;
  767.     Resdom res;
  768.     Param param;
  769.  
  770.     /*
  771.      * construct the target list
  772.      */
  773.     res = my_make_resdom((AttributeNumber) 1, "param");
  774.     param = my_make_param(id, name);
  775.     tlist = lispCons(
  776.         lispCons(res, lispCons(param, LispNil)),
  777.         LispNil);
  778.  
  779.     /*
  780.      * now construct the node
  781.      */
  782.     node = RMakeResult();
  783.  
  784.     set_cost((Plan) node, 0.0);
  785.     set_fragment((Plan) node, 0);
  786.     set_state((Plan) node, NULL);
  787.     set_qptargetlist((Plan)node, tlist);
  788.     set_qpqual((Plan) node, LispNil);
  789.     set_lefttree((Plan)node, LispNil);
  790.     set_righttree((Plan)node, LispNil);
  791.     set_resrellevelqual(node, LispNil);
  792.     set_resconstantqual(node, LispNil);
  793.     set_resstate(node, NULL);
  794.     
  795.     return(node);
  796. }
  797.  
  798. /*==========================================================================
  799.  *
  800.  * makeTestNLRulePlan
  801.  *
  802.  * Create a plan suitable for testing rule stubs
  803.  *
  804.  * This plan corresponds to a query of the form:
  805.  *
  806.  *     REL1.attr1 = REL2.attr2 and 
  807.  *    REL2.attr3 = REL3.attr4 and 
  808.  *    ... and RELn.attrk = C
  809.  *
  810.  * All the attributes attr1, attr2 ... are assumed to be of type `int4'
  811.  *
  812.  * Parameters:
  813.  *    nRel = number of relations involved
  814.  *    attrs = an array of attribute numbers. there must be
  815.  *        (2 * nRel - 1) entries in this array.
  816.  *
  817.  *    isconstant: if true, then 'C' is a integer constant
  818.  *        with a value equal to `value'. (in this case
  819.  *        `name' is ignored).
  820.  *        If `isconstant' is false, then 'C' is a Param
  821.  *        with type = PARAM_OLD, name = `name' and id
  822.  *        (i.e. attribute number) = `value'.
  823.  */
  824.  
  825. List
  826. makeTestNLRulePlan(nRel, attrNumbers, isconstant, value, name)
  827. int nRel;
  828. AttributeNumber *attrNumbers;
  829. bool isconstant;
  830. int value;
  831. char *name;
  832. {
  833.     SeqScan scans[MAX_RELATIONS];
  834.     NestLoop nloops[MAX_RELATIONS];
  835.     char lockString[1000];
  836.     int i;
  837.  
  838.     if (nRel > MAX_RELATIONS) {
  839.     elog(WARN, "Only %d relations allowed", nRel);
  840.     }
  841.  
  842.     /*
  843.      * create the scan nodes, one for each relation
  844.      */
  845.     for (i=0; i<nRel; i++) {
  846.     Index scanrelid;
  847.     List qual;
  848.     List targetList;
  849.     AttributeNumber attnoImport, attnoExport;
  850.     Var var1, var2;
  851.     Resdom res1, res2;
  852.  
  853.     scanrelid = (Index) (i+1);
  854.     /*
  855.      * the target list will only contain the 2 attributes
  856.      * used in Joins. One of them is used in the qualification
  857.      * of the parent 'NestLoop' node (`import' attribute)
  858.      * and the other one is the one that will be actually
  859.      * projected by this NestLoop (export attribute).
  860.      *
  861.      */
  862.  
  863.     qual = LispNil;
  864.  
  865.     attnoImport = attrNumbers[IMPORT_ATTRNO(i)];
  866.     /*
  867.      * a special case: if this is the righmost
  868.      * scan node (i.e. scanrelid == 1)
  869.      * then have its export attribute equal to 1
  870.      */
  871.     if (i==0)
  872.         attnoExport = (AttributeNumber) 1;
  873.     else
  874.         attnoExport = attrNumbers[EXPORT_ATTRNO(i)];
  875.     var1 = my_make_var(scanrelid, attnoImport,
  876.             lispCons(lispInteger(scanrelid),
  877.             lispCons(lispInteger(attnoImport), LispNil)));
  878.     var2 = my_make_var(scanrelid, attnoExport,
  879.             lispCons(lispInteger(scanrelid),
  880.             lispCons(lispInteger(attnoExport), LispNil)));
  881.     res1 = my_make_resdom((AttributeNumber)1, "null");
  882.     res2 = my_make_resdom((AttributeNumber)2, "null");
  883.     targetList = lispCons(
  884.             lispCons(res1, lispCons(var1, LispNil)),
  885.             LispNil);
  886.     targetList = nappend1(targetList,
  887.             lispCons(res2, lispCons(var2, LispNil)));
  888.  
  889.     scans[i] = RMakeSeqScan();
  890.     set_fragment ( scans[i], 0 );
  891.     set_parallel ( scans[i], 1 );
  892.     set_state (scans[i], (EState)NULL);
  893.     set_qptargetlist (scans[i], targetList);
  894.     set_qpqual (scans[i] , qual);
  895.     set_lefttree (scans[i], (Plan) NULL);
  896.     set_righttree (scans[i] , (Plan) NULL);
  897.     set_scanrelid (scans[i] , scanrelid);
  898.     set_scanstate (scans[i], (ScanState)NULL);
  899.     }
  900.  
  901.     /*
  902.      * OK, now create the NestLoop nodes
  903.      */
  904.     for (i=0; i<nRel; i++) {
  905.     Var varjoin1, varjoin2, varout;
  906.     Node node;
  907.     Resdom res;
  908.     AttributeNumber attnoInner, attnoOuter;
  909.     Plan leftTree, rightTree;
  910.     List innerTargetList, outerTargetList, targetList;
  911.     List qual;
  912.     JoinRuleInfo ruleInfo;
  913.     AttributeNumber innerAttrNo;
  914.     Result resultNode;
  915.     List varid;
  916.  
  917.     if (i == 0) {
  918.         /*
  919.          * leftmost NestLoop node.
  920.          * the only one with its left children being a RESULT node.
  921.          * all the others have lefttree = nestloop and
  922.          * righttree = scan node.
  923.          */
  924.  
  925.         if (isconstant)
  926.         resultNode = my_make_constresult(value);
  927.         else
  928.         resultNode = my_make_paramresult(value, name);
  929.         leftTree = (Plan) resultNode;
  930.     } else {
  931.         leftTree = (Plan) nloops[i-1];
  932.     }
  933.     rightTree = (Plan) scans[nRel-1-i];
  934.     innerTargetList = get_qptargetlist(rightTree);
  935.     outerTargetList = get_qptargetlist(leftTree);
  936.  
  937.     /*
  938.      * Now create the target list
  939.      */
  940.     res = my_make_resdom((AttributeNumber)1, "foo");
  941.     varout = my_make_var((Index)INNER, (AttributeNumber)2,
  942.             get_varid(CADR(CADR(innerTargetList))));
  943.     targetList = lispCons(
  944.             lispCons(res, lispCons(varout, LispNil)),
  945.             LispNil);
  946.     
  947.     /*
  948.      * now the qualification
  949.      */
  950.     if (i != 0) {
  951.         /*
  952.          * this is not the leftmost nset loop node
  953.          */
  954.         varid = get_varid(CADR(CAR(outerTargetList)));
  955.         varjoin1 = my_make_var((Index)OUTER, (AttributeNumber)1, varid);
  956.         varid = get_varid(CADR(CAR(innerTargetList)));
  957.         varjoin2 = my_make_var((Index)INNER, (AttributeNumber)1, varid);
  958.         qual = my_make_qual(varjoin1, varjoin2);
  959.     } else {
  960.         /*
  961.          * this is the the one! Its left tree is a Result node
  962.          */
  963.         node = (Node) CADR(CAR(outerTargetList));
  964.         varid = get_varid(CADR(CAR(innerTargetList)));
  965.         varjoin2 = my_make_var((Index)INNER, (AttributeNumber)1, varid);
  966.         qual = my_make_qual(node, varjoin2);
  967.     }
  968.  
  969.     varid = get_varid(CADR(CADR(innerTargetList)));
  970.     innerAttrNo = (AttributeNumber) CInteger(CADR(varid));
  971.  
  972.  
  973.     /*
  974.      * now create the rule info for that node
  975.      */
  976.     sprintf(lockString, LOCK_FORMAT,
  977.         100+i, 'Z', innerAttrNo, 1, 0, 0);
  978.     ruleInfo = my_make_ruleinfo(i+1, innerAttrNo, (AttributeNumber) 1,
  979.                 lockString);
  980.     /*
  981.      * finally the NestLoop itself!
  982.      */
  983.     nloops[i] = RMakeNestLoop();
  984.     set_cost (nloops[i] , 0.0 );
  985.     set_fragment (nloops[i], 0 );
  986.     set_parallel (nloops[i], 1 );
  987.     set_state (nloops[i], (EState)NULL);
  988.     set_qptargetlist (nloops[i], targetList);
  989.     set_qpqual (nloops[i] , qual);
  990.     set_lefttree (nloops[i], leftTree);
  991.     set_righttree (nloops[i] , rightTree);
  992.     set_nlstate (nloops[i], (NestLoopState)NULL);
  993.     set_ruleinfo(nloops[i], ruleInfo);
  994.     }
  995.  
  996.     /*
  997.      * WE ARE DONE !!!!!
  998.      */
  999.     return((List)nloops[nRel-1]);
  1000. }
  1001.  
  1002. /*-----------------------------------------------------------------------
  1003.  * printRulePlanStats
  1004.  *-----------------------------------------------------------------------
  1005.  */
  1006. printRulePlanStats(plan, rangeTable)
  1007. Plan plan;
  1008. List rangeTable;
  1009. {
  1010.     JoinRuleInfo ruleInfo;
  1011.     Prs2StubStats stats;
  1012.     Plan leftTree, rightTree;
  1013.     Index scanrelid;
  1014.     List rt_entry;
  1015.     char *relName;
  1016.  
  1017.     if (ExecIsNestLoop(plan)) {
  1018.     /*
  1019.      * find the inner relation name
  1020.      */
  1021.     rightTree = (Plan) get_righttree(plan);
  1022.     if (rightTree != NULL && ExecIsSeqScan(rightTree)){
  1023.         scanrelid = get_scanrelid(rightTree);
  1024.         rt_entry = nth(scanrelid-1, rangeTable);
  1025.         relName = CString(rt_relname(rt_entry));
  1026.     }
  1027.     ruleInfo = get_ruleinfo(plan);
  1028.     if (ruleInfo != NULL) {
  1029.         stats = get_jri_stats(ruleInfo);
  1030.         if (stats != NULL) {
  1031.         printf("\n");
  1032.         printf(
  1033.         "+++ (printRuleStats) REL: %s, stubs +%d -%d, locks +%d, -%d\n",
  1034.         relName, stats->stubsAdded, stats->stubsDeleted,
  1035.         stats->locksAdded, stats->locksDeleted);
  1036.         } else {
  1037.         printf("+++ (printRuleStats) REL: %s, --nil--\n", relName);
  1038.         }
  1039.     }
  1040.     }
  1041.     leftTree = (Plan) get_lefttree(plan);
  1042.     rightTree = (Plan) get_righttree(plan);
  1043.     if (leftTree != NULL) {
  1044.     printRulePlanStats(leftTree, rangeTable);
  1045.     }
  1046.     if (rightTree != NULL) {
  1047.     printRulePlanStats(rightTree, rangeTable);
  1048.     }
  1049.  
  1050. }
  1051.  
  1052.  
  1053. /*-------------------------------------------------------------------
  1054.  * make_parsetree
  1055.  *
  1056.  * make a range table given the names of relations
  1057.  */
  1058. List
  1059. make_parsetree(nRel, relNames) 
  1060. int nRel;
  1061. char relNames[][MAX_NAME_LENGTH];
  1062. {
  1063.     int i;
  1064.     List rangeTable;
  1065.     List entry;
  1066.     ObjectId reloid;
  1067.     Relation rel;
  1068.     List parseTree;
  1069.     List root;
  1070.  
  1071.     rangeTable = LispNil;
  1072.  
  1073.     for (i=0; i<nRel; i++) {
  1074.     /*
  1075.      * now find the reloid of the relation
  1076.      */
  1077.     rel = RelationNameOpenHeapRelation(&(relNames[i][0]));
  1078.     reloid = RelationGetRelationId(rel);
  1079.     RelationCloseHeapRelation(rel);
  1080.     entry = lispCons(lispString(relNames[i]), LispNil);
  1081.     entry = nappend1(entry, lispString(relNames[i]));
  1082.     entry = nappend1(entry, lispInteger((int)reloid));
  1083.     entry = nappend1(entry, lispInteger(0));
  1084.     entry = nappend1(entry, LispNil);
  1085.     entry = nappend1(entry, LispNil);
  1086.     rangeTable = nappend1(rangeTable, entry);
  1087.     }
  1088.  
  1089.     /*
  1090.      * OK, now construct a fake parse tree.
  1091.      * As far as I know we only need:
  1092.      *  a) range table
  1093.      *  b) result Relation
  1094.      *  c) target list (only in a 'replace' command)
  1095.      */
  1096.     root = lispCons(lispInteger(1), LispNil);
  1097.     root = nappend1(root, lispAtom("retrieve"));
  1098.     root = nappend1(root, LispNil);
  1099.     root = nappend1(root, rangeTable);
  1100.     parseTree = lispCons(root, LispNil);
  1101.  
  1102.     return(parseTree);
  1103. }
  1104.  
  1105. /*==============================================================
  1106.  *
  1107.  * addRulePlan
  1108.  *
  1109.  * create a plan and add it to the pg_prs2plans
  1110.  *
  1111.  * This plan corresponds to a query of the form:
  1112.  *
  1113.  *     REL1.attr1 = REL2.attr2 and 
  1114.  *    REL2.attr3 = REL3.attr4 and 
  1115.  *    ... and RELn.attrk = PARAM
  1116.  *
  1117.  * where PARAM is a parameter.
  1118.  * All the attributes attr1, attr2 ... are assumed to be of type `int4'
  1119.  *
  1120.  * ARGUMENTS:
  1121.  * the argument is a string containing the following info:
  1122.  * a) the rule id
  1123.  * b) the plan id
  1124.  * c) the number N of relations  (an int)
  1125.  * d) the relation names, i.e. N names (with no quotes!)
  1126.  * e) the attribute numbers attr1, attr2, etc.
  1127.  *    these are (2*N-1) integers.
  1128.  * f) the parameter name and parameter id
  1129.  * g) the [nRel+1] locks to be associated with the stubs...
  1130.  *    of the nRel relations + the `export' lock to be stored in
  1131.  *     the rule catalog allong with the generated plan.
  1132.  *
  1133.  * For example a valid string is:
  1134.  *    '123453 2 3 R1 R2 R3 2 3 4 2 1 salary 2 \
  1135.  *    (numOfLocks:0)    \
  1136.  *    (numOfLocks:1 ........) \
  1137.  *    (numOfLocks:1 ........)'
  1138.  *
  1139.  *----------
  1140.  * First we call makeTestNLRulePlan to create the plan,
  1141.  *
  1142.  */
  1143. List
  1144. addRulePlan(string)
  1145. char *string;
  1146. {
  1147.     int nRel;
  1148.     char relNames[MAX_RELATIONS][MAX_NAME_LENGTH];
  1149.     AttributeNumber attrnos[2*MAX_RELATIONS-1];
  1150.     int ruleId, planId;
  1151.     int paramId;
  1152.     char paramName[MAX_NAME_LENGTH];
  1153.     char locks[MAX_RELATIONS+1][MAX_NAME_LENGTH];
  1154.     char *s;
  1155.     int i,j;
  1156.     LispValue plan, parseTree, res;
  1157.     char *lockString;
  1158.     Portal portal;
  1159.  
  1160.     s = string;
  1161.  
  1162.     /*
  1163.      * parse the given string to find 'nRel', 'relNames',
  1164.      * 'attrnos' and 'constvalue'
  1165.      */
  1166.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  1167.     /*
  1168.      * read rule id
  1169.      */
  1170.     ruleId = 0;
  1171.     while ((*s) && ISDIGIT(*s)) {
  1172.     ruleId = 10 * ruleId + (*s) - '0';
  1173.     s++;
  1174.     }
  1175.     if (ruleId == 0) {
  1176.     fprintf(stderr, "addRulePlan: illegal string '%s'\n", string);
  1177.     exitpg(1);
  1178.     }
  1179.     /*
  1180.      * now the plan id
  1181.      */
  1182.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  1183.     planId = 0;
  1184.     while ((*s) && ISDIGIT(*s)) {
  1185.     planId = 10 * planId + (*s) - '0';
  1186.     s++;
  1187.     }
  1188.     if (planId == 0) {
  1189.     fprintf(stderr, "addRulePlan: illegal string '%s'\n", string);
  1190.     exitpg(1);
  1191.     }
  1192.     /*
  1193.      * now the # of relations & th relation names...
  1194.      */
  1195.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  1196.     nRel = 0;
  1197.     while ((*s) && ISDIGIT(*s)) {
  1198.     nRel = 10 * nRel + (*s) - '0';
  1199.     s++;
  1200.     }
  1201.     if (nRel == 0) {
  1202.     fprintf(stderr, "addRulePlan: illegal string '%s'\n", string);
  1203.     exitpg(1);
  1204.     }
  1205.     for (i=0; i<nRel; i++) {
  1206.     while ((*s) && ISBLANK(*s)) s++;    /* skip blanks */
  1207.     j=0;
  1208.     while((*s) && !ISBLANK(*s)) {
  1209.         relNames[i][j] = *s;
  1210.         s++;
  1211.         j++;
  1212.     }
  1213.     relNames[i][j] = '\0';
  1214.     }
  1215.     for (i=0; i<2*nRel-1; i++) {
  1216.     while ((*s) && ISBLANK(*s)) s++;    /* skip blanks */
  1217.     attrnos[i] = 0;
  1218.     while ((*s) && ISDIGIT(*s)) {
  1219.         attrnos[i] = 10 * attrnos[i] + (*s) - '0';
  1220.         s++;
  1221.     }
  1222.     if (attrnos[i] == 0) {
  1223.         fprintf(stderr,
  1224.         "addRulePlan: illegal string '%s'\n", string);
  1225.         exitpg(1);
  1226.     }
  1227.     }
  1228.     /*
  1229.      * now the parameter name & id
  1230.      */
  1231.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  1232.     j=0;
  1233.     while((*s) && !ISBLANK(*s)) {
  1234.     paramName[j] = *s;
  1235.     s++;
  1236.     j++;
  1237.     }
  1238.     paramName[j] = '\0';
  1239.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  1240.     paramId = 0;
  1241.     while ((*s) && ISDIGIT(*s)) {
  1242.     paramId = 10 * paramId + (*s) - '0';
  1243.     s++;
  1244.     }
  1245.  
  1246.     /*
  1247.      * finally read the locks.
  1248.      * read from the first '(' up to the enclosing ')'
  1249.      */
  1250.     for (i=0; i<nRel+1; i++) {
  1251.     int level;
  1252.  
  1253.     while ((*s) && ISBLANK(*s)) s++;        /* skip blanks */
  1254.     if (*s!='(') {
  1255.         fprintf(stderr,
  1256.         "addRulePlan: illegal lock in '%s'\n", string);
  1257.         exitpg(1);
  1258.     }
  1259.     level = 1;
  1260.     j=0;
  1261.     locks[i][j] = *s;
  1262.     j++;
  1263.     s++;
  1264.     while(level >0) {
  1265.         if (*s == '\0') {
  1266.         fprintf(stderr,
  1267.             "addRulePlan: illegal lock in '%s'\n", string);
  1268.         exitpg(1);
  1269.         }
  1270.         if (*s == ')')
  1271.         level--;
  1272.         if (*s == '(')
  1273.         level++;
  1274.         locks[i][j] = *s;
  1275.         s++;
  1276.         j++;
  1277.     }
  1278.     locks[i][j] = '\0';
  1279.     }
  1280.     
  1281.     if (TESTRULE_DEBUG_FLAG) {
  1282.     int k;
  1283.     printf("DEBUG: addRulePlan: string = '%s'\n", string);
  1284.     printf("DEBUG: addRulePlan:  nRel=%d [", nRel);
  1285.     for (k=0; k<nRel; k++){
  1286.         printf(" %s", relNames[k]);
  1287.     }
  1288.     printf("] attrnos=[");
  1289.     for (k=0; k<2*nRel-1; k++){
  1290.         printf(" %hd", attrnos[k]);
  1291.     }
  1292.     printf("] param=$%s (%d)\n", paramName, paramId);
  1293.     fflush(stdout);
  1294.     }
  1295.  
  1296.     /*----------
  1297.      * OK, now make the plan + parse tree etc....
  1298.      */
  1299.     plan = makeNLRulePlan(nRel, attrnos, paramName, paramId, locks);
  1300.     parseTree = make_parsetree(nRel, relNames);
  1301.  
  1302.     if (TESTRULE_DEBUG_FLAG) {
  1303.     printf("DEBUG: addRulePlan: PLAN=");
  1304.     lispDisplay(plan);
  1305.     printf("\n");
  1306.     fflush(stdout);
  1307.     }
  1308.  
  1309.     lockString = &(locks[nRel][0]);
  1310.     res = nappend1(res, lispString(lockString));
  1311.     res = nappend1(res,
  1312.         lispCons(parseTree, lispCons(plan, LispNil)));
  1313.     res = lispCons(lispString(Prs2RulePlanType_EXPORT), res);
  1314.     
  1315.     StartTransactionCommand(portal);
  1316.     prs2InsertRulePlanInCatalog(ruleId, planId, res);
  1317.     CommitTransactionCommand();
  1318.  
  1319. }
  1320.  
  1321. /*==========================================================================
  1322.  *
  1323.  * makeNLRulePlan
  1324.  *
  1325.  * Create a plan for an export/import lock.
  1326.  *
  1327.  * This plan corresponds to a query of the form:
  1328.  *
  1329.  *     REL(0).attr(0) = REL(1).attr(1) and 
  1330.  *    REL(1).attr(2) = REL(2).attr(3) and 
  1331.  *    ... 
  1332.  *    REL(n-2).attr(k-3) = REL(n-1).attr(k-2) and 
  1333.  *    REL(n-1).attr(k-1) = PARAMETER
  1334.  *
  1335.  * where k = 2*n-1
  1336.  *
  1337.  * All the attributes attr1, attr2 ... are assumed to be of type `int4'
  1338.  *
  1339.  * Parameters:
  1340.  *    nRel = number of relations involved
  1341.  *    attrs = an array of attribute numbers. there must be
  1342.  *        (2 * nRel - 1) entries in this array.
  1343.  *    paramname, paramid: the name of attrno of PARAMETER
  1344.  *    planIds = an array (with nRel) elements, one for each
  1345.  *        node in the relation with the plan id for the
  1346.  *        corresponding stub.
  1347.  *    locks: the locks associated with each JoinRuleInfo
  1348.  *
  1349.  * The plan is a left deep tree with "n" scan nodes (one per
  1350.  * relation). Scan node "i" corresponds to relation "i" (i=0...n-1)
  1351.  * and all scan nodes have a null qualifcation except for
  1352.  * scan node "n-1" which has the qualifcation:
  1353.  *    REL(n-1).attr(k-1) = PARAMETER
  1354.  *
  1355.  * There are "n-1" Join nodes.
  1356.  * Join node "n-2" is the leftmost and has as left and right children
  1357.  * the scan nodes "n-1" and "n-2" respectively.
  1358.  * All other Join nodes "i" (i=0...n-3) have as left child
  1359.  * the Join node "i+1" and as right child the scan node "i".
  1360.  *
  1361.  * Every relation "REL(i)" has an import attribute: "attr(2*i)"
  1362.  * and en export attribute "attr(2*i-1)", with the exception
  1363.  * of "REL(0)" which does not have an export attribute.
  1364.  * (but in our code, we just assume an export attribute number = 1).
  1365.  * 
  1366.  * Each scan node has a target list with two elements, the first one
  1367.  * being the import attribute and the second one the export attribute
  1368.  * of the relation.
  1369.  * The only exception is scan node "n-1" (the leftmost one) which
  1370.  * only has one element, the export attribute of "REL(n-1)".
  1371.  *
  1372.  * Each Join has a target list with only one element, the export
  1373.  * attribute of the relation being scanned in its right subtree.
  1374.  * The join qualification for join node "i" is:
  1375.  *  OUTER.1 = INNER.1
  1376.  * (where OUTER.1 is the export attribute of REL(i-1) and INNER.1
  1377.  * is the import attribute of REL(i).
  1378.  * 
  1379.  */
  1380.  
  1381. List
  1382. makeNLRulePlan(nRel, attrNumbers, paramname, paramid, locks)
  1383. int nRel;
  1384. AttributeNumber *attrNumbers;
  1385. int paramid;
  1386. char *paramname;
  1387. char locks[MAX_RELATIONS+1][MAX_NAME_LENGTH];
  1388. {
  1389.     SeqScan scans[MAX_RELATIONS];
  1390.     NestLoop nloops[MAX_RELATIONS];
  1391.     int i;
  1392.  
  1393.     if (nRel > MAX_RELATIONS) {
  1394.     elog(WARN, "Only %d relations allowed", nRel);
  1395.     }
  1396.  
  1397.     /*
  1398.      * create the scan nodes, one for each relation
  1399.      */
  1400.     for (i=0; i<nRel; i++) {
  1401.     Index scanrelid;
  1402.     List qual;
  1403.     List targetList;
  1404.     AttributeNumber attnoImport, attnoExport;
  1405.     Var var1, var2;
  1406.     Resdom res1, res2;
  1407.     Param param;
  1408.  
  1409.     scanrelid = (Index) (i+1);
  1410.     /*
  1411.      * the target list will only contain the 2 attributes
  1412.      * used in Joins. One of them is used in the qualification
  1413.      * of the parent 'NestLoop' node (`import' attribute)
  1414.      * and the other one is the one that will be actually
  1415.      * projected by this NestLoop (export attribute).
  1416.      *
  1417.      */
  1418.     attnoImport = attrNumbers[IMPORT_ATTRNO(i)];
  1419.     /*
  1420.      * a special case: if this is the righmost
  1421.      * scan node (i.e. scanrelid == 1)
  1422.      * then have its export attribute equal to attrno=1
  1423.      */
  1424.     if (i==0)
  1425.         attnoExport = (AttributeNumber) 1;
  1426.     else
  1427.         attnoExport = attrNumbers[EXPORT_ATTRNO(i)];
  1428.     /*
  1429.      * another special case. If this is the leftmost node,
  1430.      * (i==nRel-1) then the target list will contain
  1431.      * only one element (the export attribute).
  1432.      */
  1433.     if (i==nRel-1) {
  1434.         var2 = my_make_var(scanrelid, attnoExport,
  1435.             lispCons(lispInteger(scanrelid),
  1436.             lispCons(lispInteger(attnoExport), LispNil)));
  1437.         res2 = my_make_resdom((AttributeNumber)2, "null");
  1438.         targetList = lispCons(
  1439.             lispCons(res2, lispCons(var2, LispNil)),
  1440.             LispNil);
  1441.     } else {
  1442.         /*
  1443.          * normal case: the target list has first an element
  1444.          * for the import attribute, and then one for the export
  1445.          * attribute.
  1446.          */
  1447.         var1 = my_make_var(scanrelid, attnoImport,
  1448.             lispCons(lispInteger(scanrelid),
  1449.             lispCons(lispInteger(attnoImport), LispNil)));
  1450.         var2 = my_make_var(scanrelid, attnoExport,
  1451.             lispCons(lispInteger(scanrelid),
  1452.             lispCons(lispInteger(attnoExport), LispNil)));
  1453.         res1 = my_make_resdom((AttributeNumber)1, "null");
  1454.         res2 = my_make_resdom((AttributeNumber)2, "null");
  1455.         targetList = lispCons(
  1456.             lispCons(res1, lispCons(var1, LispNil)),
  1457.             LispNil);
  1458.         targetList = nappend1(targetList,
  1459.             lispCons(res2, lispCons(var2, LispNil)));
  1460.     }
  1461.     /*
  1462.      * Now the qualification. This is nil, unless if this
  1463.      * is the leftmost node, in which case it must be
  1464.      * something like "import_attribute = parameter"
  1465.      */
  1466.     if (i==nRel-1) {
  1467.         var1 = my_make_var(scanrelid, attnoImport,
  1468.             lispCons(lispInteger(scanrelid),
  1469.             lispCons(lispInteger(attnoImport), LispNil)));
  1470.         param = my_make_param(paramid, paramname);
  1471.         qual = my_make_qual((Node)var1, (Node)param);
  1472.     } else {
  1473.         qual = LispNil;
  1474.     }
  1475.  
  1476.     scans[i] = RMakeSeqScan();
  1477.     set_fragment ( scans[i], 0 );
  1478.     set_parallel ( scans[i], 1 );
  1479.     set_state (scans[i], (EState)NULL);
  1480.     set_qptargetlist (scans[i], targetList);
  1481.     set_qpqual (scans[i] , qual);
  1482.     set_lefttree (scans[i], (Plan) NULL);
  1483.     set_righttree (scans[i] , (Plan) NULL);
  1484.     set_scanrelid (scans[i] , scanrelid);
  1485.     set_scanstate (scans[i], (ScanState)NULL);
  1486.     }
  1487.  
  1488.     /*
  1489.      * OK, now create the Join nodes
  1490.      * NOTE: currently we only support NestLoop joins....
  1491.      */
  1492.     for (i=nRel-2; i>=0; i--) {
  1493.     Var varjoin1, varjoin2, varout;
  1494.     Node node;
  1495.     Resdom res;
  1496.     AttributeNumber attnoInner, attnoOuter;
  1497.     Plan leftTree, rightTree;
  1498.     List innerTargetList, outerTargetList, targetList;
  1499.     List qual;
  1500.     JoinRuleInfo ruleInfo;
  1501.     AttributeNumber innerAttrNo;
  1502.     List varid;
  1503.  
  1504.     if (i == nRel-2) {
  1505.         /*
  1506.          * leftmost NestLoop node.
  1507.          * the only one with its left children being a scan node.
  1508.          * all the others have lefttree = nestloop and
  1509.          * righttree = scan node.
  1510.          */
  1511.         leftTree = (Plan) scans[nRel-1];
  1512.     } else {
  1513.         leftTree = (Plan) nloops[i+1];
  1514.     }
  1515.     rightTree = (Plan) scans[i];
  1516.     innerTargetList = get_qptargetlist(rightTree);
  1517.     outerTargetList = get_qptargetlist(leftTree);
  1518.  
  1519.     /*
  1520.      * Now create the target list
  1521.      * This will only have the INNER.2, i.e. the
  1522.      * export attribute of the inner relation "REL(i)"
  1523.      */
  1524.     res = my_make_resdom((AttributeNumber)1, "foo");
  1525.     varout = my_make_var((Index)INNER, (AttributeNumber)2,
  1526.             get_varid(CADR(CADR(innerTargetList))));
  1527.     targetList = lispCons(
  1528.             lispCons(res, lispCons(varout, LispNil)),
  1529.             LispNil);
  1530.     
  1531.     /*
  1532.      * now the qualification
  1533.      * this must be: "INNER.1 = OUTER.1"
  1534.      */
  1535.     varid = get_varid(CADR(CAR(outerTargetList)));
  1536.     varjoin1 = my_make_var((Index)OUTER, (AttributeNumber)1, varid);
  1537.     varid = get_varid(CADR(CAR(innerTargetList)));
  1538.     varjoin2 = my_make_var((Index)INNER, (AttributeNumber)1, varid);
  1539.     qual = my_make_qual(varjoin1, varjoin2);
  1540.  
  1541.     /*
  1542.      * now create the rule info for that node
  1543.      */
  1544.     varid = get_varid(CADR(CADR(innerTargetList)));
  1545.     innerAttrNo = (AttributeNumber) CInteger(CADR(varid));
  1546.     ruleInfo = my_make_ruleinfo(
  1547.         i,
  1548.         innerAttrNo,
  1549.         (AttributeNumber) 1,
  1550.         &(locks[i][0]));
  1551.  
  1552.     /*
  1553.      * finally the NestLoop itself!
  1554.      */
  1555.     nloops[i] = RMakeNestLoop();
  1556.     set_cost (nloops[i] , 0.0 );
  1557.     set_fragment (nloops[i], 0 );
  1558.     set_parallel (nloops[i], 1 );
  1559.     set_state (nloops[i], (EState)NULL);
  1560.     set_qptargetlist (nloops[i], targetList);
  1561.     set_qpqual (nloops[i] , qual);
  1562.     set_lefttree (nloops[i], leftTree);
  1563.     set_righttree (nloops[i] , rightTree);
  1564.     set_nlstate (nloops[i], (NestLoopState)NULL);
  1565.     set_ruleinfo(nloops[i], ruleInfo);
  1566.     }
  1567.  
  1568.     /*
  1569.      * WE ARE DONE !!!!!
  1570.      */
  1571.     return((List)nloops[0]);
  1572. }
  1573.