home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / planner / sys / pppp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  17.3 KB  |  786 lines

  1. /*
  2.  *      FILE
  3.  *         pppp
  4.  *
  5.  *      DESCRIPTION
  6.  *         POSTGRES plan pretty printer
  7.  *
  8.  */
  9.  
  10. #include "tmp/postgres.h"
  11.  
  12. RcsId("$Header: /private/postgres/src/planner/sys/RCS/pppp.c,v 1.20 1992/07/04 04:03:48 mao Exp $");
  13.  
  14. #define    INDENT(c)    printf("%*s", (2 * (c)), "")
  15.  
  16. /*     
  17.  *      EXPORTS
  18.  *             print_parse
  19.  *             print_plan
  20.  *
  21.  *  provide ("pppp");
  22.  */
  23.  
  24. #include "nodes/nodes.h"
  25. #include "nodes/pg_lisp.h"
  26. #include "nodes/plannodes.h"
  27. #include "nodes/plannodes.a.h"
  28. #include "nodes/primnodes.h"
  29. #include "nodes/primnodes.a.h"
  30. #include "nodes/execnodes.h"
  31. #include "nodes/relation.h"
  32. #include "nodes/relation.a.h"
  33. #include "tags.h"
  34.  
  35. #include "planner/internal.h"
  36. #include "planner/clauses.h"
  37. #include "planner/keys.h"
  38. #include "planner/prepqual.h"
  39.  
  40. void print_parse ARGS((LispValue parse ));
  41. void print_root ARGS((LispValue root ));
  42. void print_plan ARGS((Plan plan , int levelnum ));
  43. char *subplan_type ARGS((int type ));
  44. void print_subplan ARGS((LispValue subplan , int levels ));
  45. void print_rtentries ARGS((LispValue rt , int levels ));
  46. void print_tlist ARGS((LispValue tlist , int levels ));
  47. void print_tlistentry ARGS((LispValue tlistentry , int level ));
  48. void print_allqual ARGS((LispValue quals , int levels ));
  49. void print_qual ARGS((LispValue qual , int levels ));
  50. void print_var ARGS((LispValue var ));
  51. void print_clause ARGS((LispValue clause , int levels ));
  52. void print_const ARGS((LispValue node ));
  53. void print_param ARGS((LispValue param ));
  54. void pplan ARGS((Plan plan ));
  55. void set_query_range_table ARGS((List parsetree ));
  56. void p_plan ARGS((Plan plan ));
  57. void p_plans ARGS((List plans ));
  58. char *path_type ARGS((Path path ));
  59. void ppath ARGS((Path path ));
  60. void p_path ARGS((Path path ));
  61. void p_paths ARGS((List paths ));
  62. void p_rel ARGS((Rel rel ));
  63. void p_rels ARGS((List rels ));
  64.  
  65. /*  #ifdef opus43
  66.  *  declare (special (_newline_))
  67.  *  #endif
  68.  */
  69.  
  70. /* #ifdef (opus43 && pg_production)
  71.  * declare (localf (print_root, print_subplan, print_rtentries,
  72.  *         print_tlist, print_tlistentry, print_allqual,
  73.  *         print_qual, print_var, print_clause, print_clauses,
  74.  *         print_const, print_param,indent)
  75.  *      )
  76.  * #endif
  77.  */
  78. void
  79. print_parse (parse)
  80.     LispValue parse;
  81. {
  82.     _query_range_table_ = root_rangetable (parse_root (parse));
  83.     print_root (parse_root (parse));
  84.     printf ("TargetList:\n");
  85.     print_tlist (parse_targetlist (parse),0);
  86.     printf ("Qualification:\n");
  87.     print_qual (cnfify (parse_qualification (parse), false),0);
  88. }
  89.  
  90. /*  .. print_parse
  91.  */
  92. void
  93. print_root (root)
  94.     LispValue root;
  95. {
  96.     printf ("NumLevels: %d\nCommandType: %d\nResultRelation: ",
  97.         root_numlevels(root), root_command_type(root));
  98.     lispDisplay(root_result_relation (root));
  99.     printf("\nRangetable:\n");
  100.     print_rtentries (root_rangetable (root), 0);
  101.     printf ("Priority: %d\nRuleInfo: ", CInteger(root_priority(root)));
  102.     lispDisplay(root_ruleinfo(root));
  103.     printf("\n");
  104. }
  105.  
  106. /*  .. print_plan, print_subplan
  107.  */
  108. void
  109. print_plan(plan, levelnum)
  110.     Plan plan;
  111.     int levelnum;
  112. {
  113.     int i;
  114.     LispValue saved_rt;
  115.     extern LispValue copy_seq_tree();
  116.     extern LispValue fix_rangetable();
  117.  
  118.     if (IsA(plan,Append)) {
  119.         INDENT(levelnum);
  120.         printf("Append %d\n\nInheritance Relid : %ld\n", levelnum,
  121.             get_unionrelid((Append)plan));
  122.  
  123.         saved_rt = copy_seq_tree (_query_range_table_);
  124.  
  125.         for (i = 0; i < (length(get_unionplans((Append)plan))); i++){
  126.             INDENT(levelnum);
  127.             printf("Appended Plan %d\n", i);
  128.             _query_range_table_ =
  129.                 fix_rangetable(_query_range_table_,
  130.                     get_unionrelid ((Append)plan),
  131.                     nth(i, get_unionrtentries((Append)plan)));
  132.             print_plan((Plan)nth(i, get_unionplans((Append)plan)),
  133.                    levelnum + 1);
  134.         };
  135.  
  136.         /* XXX need to free the munged tree */
  137.         _query_range_table_ = saved_rt;
  138.  
  139.         INDENT(levelnum);
  140.         printf("Inheritance Range Table :\n");
  141.         print_rtentries ((LispValue)get_unionrtentries((Append)plan), levelnum);
  142.  
  143.     } else if (IsA(plan,Existential)) {
  144.         INDENT(levelnum);
  145.         printf("Existential %d\n", levelnum);
  146.  
  147.         if (get_lefttree((Plan)plan)) {
  148.             INDENT(levelnum);
  149.             printf("\nExistential Plan %d\n", levelnum);
  150.             print_plan ((Plan)get_lefttree (plan), 
  151.                     levelnum + 1);
  152.         };
  153.  
  154.         if (get_righttree((Plan)plan)) {
  155.             INDENT(levelnum);
  156.             printf("\nQuery Plan %d\n", levelnum);
  157.             print_plan ((Plan)get_righttree (plan),
  158.                     levelnum + 1);
  159.         };
  160.  
  161.     } else if (IsA(plan,Existential)) {
  162.         INDENT(levelnum);
  163.         printf("Result %d\n\n", levelnum);
  164.  
  165.         INDENT(levelnum);
  166.         printf("TargetList :\n");
  167.         print_tlist(get_qptargetlist((Plan)plan), levelnum + 1);
  168.  
  169.         INDENT(levelnum);
  170.         printf("RelLevelQual :\n");
  171.         print_qual(get_resrellevelqual((Result)plan), levelnum+1);
  172.  
  173.         INDENT(levelnum);
  174.         printf("ConstantQual :\n");
  175.         print_qual(get_resconstantqual((Result)plan), levelnum+1);
  176.  
  177.         if (get_lefttree(plan)) {
  178.             INDENT(levelnum);
  179.             printf("\nSubplan %d\n\n", levelnum);
  180.             print_subplan((LispValue)get_lefttree(plan),
  181.                       levelnum + 1);
  182.         };
  183.  
  184.         if (get_righttree(plan)) {
  185.             print_plan((Plan)get_righttree(plan), (levelnum + 1));
  186.         };
  187.     } else {
  188.  
  189.         /*
  190.          *  Better hope we get this right.
  191.          */
  192.  
  193.         printf("Subplan %d\n\n", levelnum);
  194.         print_subplan((LispValue)plan, levelnum + 1);
  195.     }
  196. }
  197.  
  198. char*
  199. subplan_type(type)
  200. int type;
  201. {
  202.     switch (type) {
  203.     case T_NestLoop:  return("NestLoop");
  204.     case T_MergeJoin: return("MergeJoin");
  205.     case T_HashJoin:  return("HashJoin");
  206.     case T_SeqScan:    return("SeqScan");
  207.     case T_IndexScan:    return("IndexScan");
  208.     case T_Sort:    return("Sort");
  209.     case T_Hash:    return("Hash");
  210.     case T_Material:return("Material");
  211.     case T_Temp:    return("Temp");
  212.     case T_Append:    return("Append");
  213.     case T_Result:    return("Result");
  214.     case T_Existential: return("Existential");
  215.     case T_ScanTemps: return("ScanTemps");
  216.     default: return("???");
  217.     }
  218. }
  219.  
  220. /*  .. print_plan, print_subplan
  221.  */
  222. void
  223. print_subplan (subplan, levels)
  224.     LispValue subplan;
  225.     int levels;
  226. {
  227.     INDENT(levels);
  228.     printf("Type : %s\n", subplan_type(((Node)subplan)->type));
  229.     INDENT (levels);
  230.     printf("Cost : %f\n", get_cost((Plan)subplan));
  231.     INDENT (levels);
  232.     printf("Size : %d\n", get_plan_size((Plan)subplan));
  233.     INDENT (levels);
  234.     printf("Width : %d\n", get_plan_width((Plan)subplan));
  235.     if (IsA(subplan,Scan)) {
  236.         INDENT (levels);
  237.         printf("Relid: ");
  238.  
  239.         /* XXX help, jeff, what's integerp become? */
  240.         /*
  241.          * if (integerp (get_scanrelid (subplan)) &&
  242.          *     (_TEMP_RELATION_ID_ != get_scanrelid (subplan)))
  243.          */
  244.         if (_TEMP_RELATION_ID_ != get_scanrelid((Scan)subplan)) {
  245.             printf( "%s",
  246.                 CString(getrelname(get_scanrelid((Scan)subplan),
  247.                            _query_range_table_)));
  248.         } else {
  249.             printf("%ld", get_scanrelid ((Scan)subplan));
  250.         };
  251.         printf("\n");
  252.     };
  253.     if (IsA(subplan,Temp)) {
  254.         INDENT (levels);
  255.         printf("TempID: %d\n", get_tempid((Temp)subplan));
  256.         INDENT (levels);
  257.         printf("KeyCount: %d\n", get_keycount((Temp)subplan));
  258.         INDENT (levels);
  259.         printf ("TempList:\n");
  260.         print_tlist(get_qptargetlist((Plan)subplan), (levels + 1)); 
  261.  
  262.     } else if (IsA(subplan,Hash)) {
  263.         INDENT(levels);
  264.         printf("HashKey: ");
  265.         print_var((LispValue)get_hashkey((Hash)subplan));
  266.     } else  {
  267.         INDENT(levels);
  268.         printf("TargetList :\n");
  269.         print_tlist((LispValue)get_qptargetlist((Plan)subplan), (levels + 1));
  270.  
  271.         INDENT (levels);
  272.         printf("Qual:\n");
  273.         print_qual((LispValue)get_qpqual((Plan)subplan), (levels + 1));
  274.     }
  275.  
  276.     if (IsA(subplan,MergeJoin)) {
  277.         INDENT (levels);
  278.         printf("MergeSortOp:%ld\n",get_mergesortop((MergeJoin)subplan));
  279.  
  280.         INDENT (levels);
  281.         printf("MergeClauses :\n");
  282.         print_qual(get_mergeclauses((MergeJoin)subplan), (levels + 1));
  283.     }
  284.     if (IsA(subplan,HashJoin)) {
  285.         INDENT (levels);
  286.         printf("hashClauses :\n");
  287.         print_qual(get_hashclauses((HashJoin)subplan), (levels + 1));
  288.     }
  289.     if (IsA(subplan,IndexScan)) {
  290.         /*
  291.          *  XXX need to add a function to print list at
  292.          *  the current nesting level.  until then...
  293.          *
  294.          * INDENT(levels);
  295.          * printf("IndexID: XXX", get_indxid (subplan), "\n");
  296.          */
  297.  
  298.         INDENT(levels);
  299.         printf("IndexQual:\n");
  300.         print_allqual(get_indxqual ((IndexScan)subplan), (levels + 1));
  301.  
  302.         printf ("\n");
  303.     };
  304.     if (IsA(subplan,Join)) {
  305.         printf("\n");
  306.         INDENT(levels);
  307.         printf("Outer Path:\n");
  308.         print_subplan((LispValue)get_lefttree((Plan)subplan),
  309.                   (levels + 1));
  310.         printf("\n");
  311.         INDENT(levels);
  312.         printf("Inner Path:\n");
  313.         print_subplan((LispValue)get_righttree((Plan)subplan), (levels + 1));
  314.  
  315.     } else if (get_lefttree((Plan)subplan)) {
  316.         printf ("\n");
  317.         if (IsA(get_lefttree((Plan)subplan),Result)) {
  318.             print_plan((Plan)get_lefttree((Plan)subplan), levels + 1);
  319.         } else {
  320.             print_subplan((LispValue)get_lefttree((Plan)subplan), levels + 1);
  321.         }
  322.     }
  323. }
  324.  
  325. /*  .. print_plan, print_root
  326.  */
  327. void
  328. print_rtentries (rt, levels)
  329.     LispValue rt;
  330.     int levels;
  331. {
  332.     LispValue i;
  333.     LispValue rtentry;
  334.  
  335.     /* XXX how do we re-write foreach loops? */
  336.     foreach (i, rt) {
  337.         rtentry = CAR(i);
  338.  
  339.         INDENT (levels + 1);
  340.         lispDisplay(rtentry);
  341.  
  342. #ifdef NOTYET
  343.         /* XXX integerp becomes what? */
  344.         if (integerp (rt_rulelocks (rtentry))) {
  345.             printf ("\n");
  346.             INDENT (levels + 1);
  347.             print_rule_lock_intermediate(rt_rulelocks(rtentry));
  348.         } else {
  349.             /*
  350.              *  XXX what the hell does this do???
  351.              *
  352.              *  printf (rt_rulelocks (rtentry));
  353.              */
  354.         }
  355. #endif /* NOTYET */
  356.         printf ("\n");
  357.     }
  358. }
  359.  
  360. /*  .. print_parse, print_plan, print_subplan */
  361. void
  362. print_tlist (tlist, levels)
  363.      LispValue tlist;
  364.      int levels;
  365. {
  366.     LispValue entry;
  367.     LispValue i;
  368.  
  369.     foreach (i, tlist) {
  370.         entry = CAR(i);
  371.         print_tlistentry(entry, (levels + 1));
  372.     }
  373. }
  374.  
  375. /*  .. print_tlist 
  376. */
  377. void
  378. print_tlistentry(tlistentry, level)
  379.     LispValue tlistentry;
  380.     int level;
  381. {
  382.     LispValue resdom;
  383.     LispValue expr;
  384.  
  385.     resdom = (LispValue) tl_resdom(tlistentry);
  386.     expr = (LispValue) get_expr(tlistentry);
  387.  
  388.     INDENT(level);
  389.     printf ("(%d ", get_resno((Resdom)resdom));
  390.  
  391.     if (get_reskey((Resdom)resdom) != 0) {
  392.         /*
  393.          *  XXX should print the tuple form, but we just print the
  394.          *  address for now.
  395.          */
  396.         printf("(%d 0x%lx)",
  397.             get_reskey((Resdom)resdom),get_reskeyop((Resdom)resdom));
  398.     };
  399.     /*
  400.      * if (get_resname(resdom) != (char *) NULL) {
  401.      *     printf ("%s", get_resname(resdom));
  402.      * };
  403.      */
  404.     print_clause (expr, level);
  405.     printf (")\n");
  406. }
  407.  
  408. /*  .. print_subplan 
  409. */
  410.  
  411. void
  412. print_allqual(quals, levels)
  413.     LispValue quals;
  414.     int levels;
  415. {
  416.     LispValue qual;
  417.     LispValue i;
  418.  
  419.     /* XXX how do we do foreach() loops?  */
  420.     foreach (i, quals) {
  421.         qual = CAR(i);
  422.         print_qual(qual,levels + 1);
  423.         printf ("\n");
  424.     };
  425. }
  426.  
  427. /*  .. print_allqual, print_parse, print_plan, print_subplan
  428.  */
  429.  
  430. void
  431. print_qual(qual, levels)
  432.     LispValue qual;
  433.     int levels;
  434. {
  435.     LispValue clause;
  436.     LispValue i;
  437.  
  438.     INDENT (levels);
  439.     foreach (i, qual) {
  440.         clause = CAR(i);
  441.         print_clause(clause, levels);
  442.         printf ("\n");
  443.     };
  444. }
  445.  
  446. /*  .. print_clause
  447.  */
  448. void
  449. print_var(var)
  450.     LispValue var;
  451. {
  452.     Index varno;
  453.     AttributeNumber attnum;
  454.     printf ("(");
  455.     if(_query_range_table_ && (_TEMP_RELATION_ID_ != get_varno((Var)var)))
  456.     {
  457.         varno = get_varno((Var)var);
  458.         attnum = get_varattno ((Var)var);
  459.         if (varno == INNER || varno == OUTER) {
  460.            List varid = get_varid((Var)var);
  461.            varno = CInteger(CAR(varid));
  462.            attnum = CInteger(CADR(varid));
  463.           }
  464.         printf("%s %s",
  465.             CString(getrelname(varno, _query_range_table_)),
  466.                 get_attname(CInteger(getrelid(varno,
  467.                  _query_range_table_)), attnum));
  468.  
  469.     } else {
  470.         printf ("%d %d", get_varno((Var)var), get_varattno((Var)var));
  471.     }
  472.     printf (")");
  473. }
  474.  
  475. /*  .. print_clause, print_clauses, print_qual, print_tlistentry
  476.  */
  477. void
  478. print_clause(clause, levels)
  479.     LispValue clause;
  480.     int levels;
  481. {
  482.     if (clause) {
  483.         INDENT (levels);
  484.         if (IsA(clause,Var)) {
  485.             print_var (clause);
  486.  
  487.         } else if (IsA(clause,Const)) {
  488.             print_const (clause);
  489.  
  490.         } else if (IsA(clause,Param)) {
  491.             print_param (clause);
  492.  
  493.         /*
  494.          * XXX don't know about these node types.
  495.          *
  496.          * } else if (or_clause (clause)) {
  497.          *     printf ("(OR ");
  498.          *     print_clauses (get_orclauseargs (clause));
  499.          *     printf (") ");
  500.          *
  501.          * } else if (not_clause (clause)) {
  502.          *     printf ("(NOT ");
  503.          *     print_clause (get_notclausearg (clause), 0);
  504.          *     printf (") ");
  505.          *
  506.          * } else if (is_funcclause (clause)) {
  507.          *     printf ("(", get_funcid (get_function (clause)), " ");
  508.          *     print_clauses (get_funcargs (clause));
  509.          *     printf (") ");
  510.          */
  511.  
  512.          } else {
  513.              printf("(%d ", get_opno((Oper)get_op(clause)));
  514.              print_clause((LispValue)get_leftop(clause), levels);
  515.              printf(" ");
  516.             print_clause((LispValue)get_rightop(clause), levels);
  517.             printf(") ");
  518.         }
  519.     }
  520. }
  521.  
  522. /*  .. print_clause
  523.  */
  524. /*
  525.  *  XXX this routine no longer needed.
  526.  *
  527.  *
  528.  * LispValue
  529.  * print_clauses (clauses)
  530.  *      LispValue clauses ;
  531.  * {
  532.  *    foreach (clause, clauses) {
  533.  *       print_clause (clause, 0);
  534.  *       
  535.  *    };
  536.  * }
  537.  */
  538.  
  539. /*  .. print_clause
  540.  */
  541. void
  542. print_const(node)
  543.     LispValue node;
  544. {
  545.     if (get_constisnull((Const)node)) {
  546.         printf("*NULL*");
  547.     /*
  548.      * } else if (stringp (get_constvalue (node))) {
  549.      *     printf("%s",get_constvalue (node));
  550.      * } else {
  551.      *     printf("%s", lisp_print (get_constvalue(node)));
  552.      * }
  553.      */
  554.  
  555.     } else {
  556.         /*
  557.          *  XXX -- neet to figure out what type of constant this
  558.          *  is, and print it for real.
  559.          */
  560.         printf("%ld", DatumGetUInt32(((Const)node)->constvalue));
  561.     }
  562. }
  563.  
  564. /*  .. print_clause
  565.  */
  566. void
  567. print_param (param)
  568.     LispValue param;
  569. {
  570.  
  571.     printf (" $%ld", get_paramid((Param)param));
  572.  
  573.     /*
  574.      * if (stringp (get_paramid (param))) {
  575.      *     printf(".");
  576.      * } else {
  577.      *     printf("");
  578.      * }
  579.      */
  580.  
  581.      if (get_paramname((Param)param) != (Name) NULL)
  582.         printf("(\"%s\")", get_paramname((Param)param));
  583. }
  584.  
  585. void
  586. pplan(plan)
  587. Plan plan;
  588. {
  589.     if (plan == NULL) return;
  590.     fprintf(stderr, "(%s ", subplan_type(plan->type));
  591.     switch (NodeType(plan)) {
  592.     case classTag(SeqScan):
  593.     case classTag(IndexScan):
  594.     if (_TEMP_RELATION_ID_ != get_scanrelid((Scan)plan)) {
  595.         fprintf(stderr,  "%s", CString(getrelname(get_scanrelid((Scan)plan),
  596.                   _query_range_table_)));
  597.       }
  598.     else {
  599.         pplan((Plan)get_lefttree(plan));
  600.       }
  601.     break;
  602.     case classTag(ScanTemps):
  603.     {   LispValue x;
  604.         Relation tmpreldesc;
  605.         foreach (x, get_temprelDescs((ScanTemps)plan)) {
  606.         tmpreldesc = (Relation)CAR(x);
  607.         fprintf(stderr, " %s", &(tmpreldesc->rd_rel->relname));
  608.           }
  609.     }
  610.     case classTag(MergeJoin):
  611.     case classTag(HashJoin):
  612.     case classTag(NestLoop):
  613.     pplan((Plan)get_lefttree(plan));
  614.     fprintf(stderr, " ");
  615.     pplan((Plan)get_righttree(plan));
  616.     break;
  617.     case classTag(Hash):
  618.     case classTag(Sort):
  619.     case classTag(Material):
  620.     case classTag(Result):
  621.     pplan((Plan)get_lefttree(plan));
  622.     break;
  623.     case classTag(Existential):
  624.     pplan((Plan)get_lefttree(plan));
  625.     fprintf(stderr, " ");
  626.     pplan((Plan)get_righttree(plan));
  627.     break;
  628.     case classTag(Append):
  629.     {  LispValue saved_rt;
  630.        extern LispValue copy_seq_tree();
  631.        extern LispValue fix_rangetable();
  632.        int i;
  633.  
  634.        saved_rt = copy_seq_tree(_query_range_table_);
  635.        for (i=0; i<(length(get_unionplans((Append)plan))); i++) {
  636.            _query_range_table_ = 
  637.             fix_rangetable(_query_range_table_,
  638.                    get_unionrelid((Append)plan),
  639.                    nth(i,get_unionrtentries((Append)plan)));
  640.            pplan((Plan)nth(i, get_unionplans((Append)plan)));
  641.          }
  642.         _query_range_table_ = saved_rt;
  643.         break;
  644.      }
  645.      default:
  646.      fprintf(stderr, "unknown plan type.\n");
  647.      break;
  648.       }
  649.      fprintf(stderr, ")");
  650.      return;
  651. }
  652.  
  653. void
  654. set_query_range_table(parsetree)
  655. List parsetree;
  656. {
  657.     _query_range_table_ = root_rangetable(parse_root(parsetree));
  658. }
  659.  
  660. void
  661. p_plan(plan)
  662. Plan plan;
  663. {
  664.     fprintf(stderr, "\n");
  665.     pplan(plan);
  666.     fprintf(stderr, "\n");
  667. }
  668.  
  669. void
  670. p_plans(plans)
  671. List plans;
  672. {
  673.     LispValue x;
  674.  
  675.     foreach (x, plans) {
  676.     p_plan((Plan)CAR(x));
  677.       }
  678. }
  679.  
  680. char *
  681. path_type(path)
  682. Path path;
  683. {
  684.     switch (NodeType(path)) {
  685.     case classTag(HashPath): return "HashJoin";
  686.     case classTag(MergePath): return "MergeJoin";
  687.     case classTag(JoinPath): return "NestLoop";
  688.     case classTag(IndexPath): return "IndexScan";
  689.     case classTag(Path): return "SeqScan";
  690.     default: return "???";
  691.     }
  692. }
  693.  
  694. void
  695. ppath(path)
  696. Path path;
  697. {
  698.     if (path == NULL) return;
  699.     fprintf(stderr, "(%s ", path_type(path));
  700.     switch (NodeType(path)) {
  701.     case classTag(HashPath):
  702.     ppath((Path)get_outerjoinpath((JoinPath)path));
  703.     fprintf(stderr, " (Hash ");
  704.     ppath((Path)get_innerjoinpath((JoinPath)path));
  705.     fprintf(stderr, ")");
  706.     break;
  707.     case classTag(MergePath):
  708.     if (get_outersortkeys((MergePath)path)) {
  709.         fprintf(stderr, "(SeqScan (Sort ");
  710.         ppath((Path)get_outerjoinpath((JoinPath)path));
  711.         fprintf(stderr, "))");
  712.       }
  713.     else
  714.         ppath((Path)get_outerjoinpath((JoinPath)path));
  715.     fprintf(stderr, " ");
  716.     if (get_innersortkeys((MergePath)path)) {
  717.         fprintf(stderr, "(SeqScan (Sort ");
  718.         ppath((Path)get_innerjoinpath((JoinPath)path));
  719.         fprintf(stderr, "))");
  720.       }
  721.     else
  722.         ppath((Path)get_innerjoinpath((JoinPath)path));
  723.     break;
  724.     case classTag(JoinPath):
  725.     ppath((Path)get_outerjoinpath((JoinPath)path));
  726.     fprintf(stderr, " ");
  727.     ppath((Path)get_innerjoinpath((JoinPath)path));
  728.     break;
  729.     case classTag(IndexPath):
  730.     case classTag(Path):
  731.     fprintf(stderr, "%s", 
  732.       CString(getrelname(CInteger(CAR(get_relids(get_parent(path)))),
  733.                  _query_range_table_)));
  734.     break;
  735.     default:
  736.     fprintf(stderr, "unknown plan type.\n");
  737.     break;
  738.       }
  739.     fprintf(stderr, ")");
  740.     return;
  741. }
  742.  
  743. void
  744. p_path(path)
  745. Path path;
  746. {
  747.     ppath(path);
  748.     fprintf(stderr, "\n");
  749. }
  750.  
  751. void
  752. p_paths(paths)
  753. List paths;
  754. {
  755.     LispValue x;
  756.  
  757.     foreach (x, paths) {
  758.     p_path((Path)CAR(x));
  759.       }
  760. }
  761.  
  762. void
  763. p_rel(rel)
  764. Rel rel;
  765. {
  766.     fprintf(stderr, "relids: ");
  767.     lispDisplay(get_relids(rel));
  768.     fprintf(stderr, "\npathlist:\n");
  769.     p_paths(get_pathlist(rel));
  770.     fprintf(stderr, "unorderedpath:\n");
  771.     p_path((Path)get_unorderedpath(rel));
  772.     fprintf(stderr, "cheapestpath:\n");
  773.     p_path((Path)get_cheapestpath(rel));
  774. }
  775.  
  776. void
  777. p_rels(rels)
  778. List rels;
  779. {
  780.     LispValue x;
  781.  
  782.     foreach (x, rels) {
  783.     p_rel((Rel)CAR(x));
  784.       }
  785. }
  786.