Explain XML patch - Mailing list pgsql-patches

From raneyt@cecs.pdx.edu
Subject Explain XML patch
Date
Msg-id 20080626214839.xbfsvm8740gsswos@webmail.cecs.pdx.edu
Whole thread Raw
Responses Re: Explain XML patch  (Simon Riggs <simon@2ndquadrant.com>)
List pgsql-patches
*** src/backend/nodes/copyfuncs.c.orig    2008-06-26 18:18:19.000000000 -0700
--- src/backend/nodes/copyfuncs.c    2008-06-26 07:26:46.000000000 -0700
***************
*** 2568,2573 ****
--- 2568,2575 ----
       COPY_NODE_FIELD(query);
       COPY_SCALAR_FIELD(verbose);
       COPY_SCALAR_FIELD(analyze);
+     COPY_SCALAR_FIELD(xml);
+     COPY_SCALAR_FIELD(dtd);

       return newnode;
   }
*** src/backend/nodes/equalfuncs.c.orig    2008-06-26 18:18:39.000000000 -0700
--- src/backend/nodes/equalfuncs.c    2008-06-26 07:25:33.000000000 -0700
***************
*** 1358,1363 ****
--- 1358,1365 ----
       COMPARE_NODE_FIELD(query);
       COMPARE_SCALAR_FIELD(verbose);
       COMPARE_SCALAR_FIELD(analyze);
+     COMPARE_SCALAR_FIELD(xml);
+     COMPARE_SCALAR_FIELD(dtd);

       return true;
   }
*** src/backend/commands/explain.c.orig    2008-06-10 09:59:12.000000000 -0700
--- src/backend/commands/explain.c    2008-06-26 15:39:38.000000000 -0700
***************
*** 45,50 ****
--- 45,51 ----
       /* options */
       bool        printTList;        /* print plan targetlists */
       bool        printAnalyze;    /* print actual times */
+     bool        printXML;    /* print output as XML */
       /* other states */
       PlannedStmt *pstmt;            /* top of plan */
       List       *rtable;            /* range table */
***************
*** 54,60 ****
                   const char *queryString,
                   ParamListInfo params, TupOutputState *tstate);
   static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
!                 StringInfo buf);
   static double elapsed_time(instr_time *starttime);
   static void explain_outNode(StringInfo str,
                   Plan *plan, PlanState *planstate,
--- 55,61 ----
                   const char *queryString,
                   ParamListInfo params, TupOutputState *tstate);
   static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
!                 StringInfo buf, bool show_xml);
   static double elapsed_time(instr_time *starttime);
   static void explain_outNode(StringInfo str,
                   Plan *plan, PlanState *planstate,
***************
*** 67,78 ****
                  StringInfo str, int indent, ExplainState *es);
   static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
                   StringInfo str, int indent, ExplainState *es);
! static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
                  const char *qlabel,
                  StringInfo str, int indent, ExplainState *es);
- static void show_sort_info(SortState *sortstate,
-                StringInfo str, int indent, ExplainState *es);
   static const char *explain_get_index_name(Oid indexId);


   /*
--- 68,79 ----
                  StringInfo str, int indent, ExplainState *es);
   static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
                   StringInfo str, int indent, ExplainState *es);
! static void show_sort_keys(SortState *sortstate, Plan *sortplan, int
nkeys, AttrNumber *keycols,
                  const char *qlabel,
                  StringInfo str, int indent, ExplainState *es);
   static const char *explain_get_index_name(Oid indexId);
+ static void show_dtd(StringInfo str);
+


   /*
***************
*** 269,280 ****

       es->printTList = stmt->verbose;
       es->printAnalyze = stmt->analyze;
       es->pstmt = queryDesc->plannedstmt;
       es->rtable = queryDesc->plannedstmt->rtable;

       initStringInfo(&buf);
!     explain_outNode(&buf,
!                     queryDesc->plannedstmt->planTree, queryDesc->planstate,
                       NULL, 0, es);

       /*
--- 270,293 ----

       es->printTList = stmt->verbose;
       es->printAnalyze = stmt->analyze;
+     es->printXML = stmt->xml;
       es->pstmt = queryDesc->plannedstmt;
       es->rtable = queryDesc->plannedstmt->rtable;

       initStringInfo(&buf);
!
!     if (stmt->xml) {
!         appendStringInfo (&buf, "<?xml version=\"1.0\"?>\n\n");
!
!         /* Only include the DTD if the user *really* wants it */
!         if (stmt->dtd)
!             show_dtd(&buf);
!
!         appendStringInfo (&buf, "<explain version=\"%s\">\n", PG_VERSION);
!     }
!
!
!     explain_outNode(&buf, queryDesc->plannedstmt->planTree,
queryDesc->planstate,
                       NULL, 0, es);

       /*
***************
*** 302,313 ****
           show_relname = (numrels > 1 || targrels != NIL);
           rInfo = queryDesc->estate->es_result_relations;
           for (nr = 0; nr < numrels; rInfo++, nr++)
!             report_triggers(rInfo, show_relname, &buf);

           foreach(l, targrels)
           {
               rInfo = (ResultRelInfo *) lfirst(l);
!             report_triggers(rInfo, show_relname, &buf);
           }
       }

--- 315,326 ----
           show_relname = (numrels > 1 || targrels != NIL);
           rInfo = queryDesc->estate->es_result_relations;
           for (nr = 0; nr < numrels; rInfo++, nr++)
!             report_triggers(rInfo, show_relname, &buf, stmt->xml);

           foreach(l, targrels)
           {
               rInfo = (ResultRelInfo *) lfirst(l);
!             report_triggers(rInfo, show_relname, &buf, stmt->xml);
           }
       }

***************
*** 330,337 ****
       totaltime += elapsed_time(&starttime);

       if (stmt->analyze)
!         appendStringInfo(&buf, "Total runtime: %.3f ms\n",
                            1000.0 * totaltime);
       do_text_output_multiline(tstate, buf.data);

       pfree(buf.data);
--- 343,359 ----
       totaltime += elapsed_time(&starttime);

       if (stmt->analyze)
!     {
!         if (stmt->xml)
!             appendStringInfo(&buf, "<runtime ms=\"%.3f\" />\n",
!                          1000.0 * totaltime);
!         else
!             appendStringInfo(&buf, "Total runtime: %.3f ms\n",
                            1000.0 * totaltime);
+     }
+     if (stmt->xml)
+         appendStringInfo(&buf, "</explain>\n");
+
       do_text_output_multiline(tstate, buf.data);

       pfree(buf.data);
***************
*** 343,349 ****
    *        report execution stats for a single relation's triggers
    */
   static void
! report_triggers(ResultRelInfo *rInfo, bool show_relname, StringInfo buf)
   {
       int            nt;

--- 365,371 ----
    *        report execution stats for a single relation's triggers
    */
   static void
! report_triggers(ResultRelInfo *rInfo, bool show_relname, StringInfo
buf, bool show_xml)
   {
       int            nt;

***************
*** 354,359 ****
--- 376,383 ----
           Trigger    *trig = rInfo->ri_TrigDesc->triggers + nt;
           Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
           char       *conname;
+         StringInfo triggerStr;
+         triggerStr = makeStringInfo();

           /* Must clean up instrumentation state */
           InstrEndLoop(instr);
***************
*** 368,385 ****
           if (OidIsValid(trig->tgconstraint) &&
               (conname = get_constraint_name(trig->tgconstraint)) != NULL)
           {
!             appendStringInfo(buf, "Trigger for constraint %s", conname);
               pfree(conname);
           }
!         else
!             appendStringInfo(buf, "Trigger %s", trig->tgname);
!
!         if (show_relname)
!             appendStringInfo(buf, " on %s",
                                RelationGetRelationName(rInfo->ri_RelationDesc));

!         appendStringInfo(buf, ": time=%.3f calls=%.0f\n",
                            1000.0 * instr->total, instr->ntuples);
       }
   }

--- 392,433 ----
           if (OidIsValid(trig->tgconstraint) &&
               (conname = get_constraint_name(trig->tgconstraint)) != NULL)
           {
!             if (!show_xml)
!                 appendStringInfo(buf, "Trigger for constraint %s", conname);
!             else
!                 appendStringInfo(triggerStr, "constraint=\"%s\"", conname);
               pfree(conname);
           }
!         else {
!             if (!show_xml)
!                 appendStringInfo(buf, "Trigger %s", trig->tgname);
!             else
!                 appendStringInfo(triggerStr, "name=\"%s\"", trig->tgname);
!         }
!         if (show_relname)
!         {
!             if (!show_xml)
!                 appendStringInfo(buf, " on %s",
!                              RelationGetRelationName(rInfo->ri_RelationDesc));
!             else
!                 appendStringInfo(triggerStr, " on=\"%s\"",
                                RelationGetRelationName(rInfo->ri_RelationDesc));

!         }
!
!         if (show_xml)
!             appendStringInfo(buf, "  <trigger %s "
!                                  "time=%.3f calls=%.0f />\n",
!                                   triggerStr->data,
!                                   1000.0 * instr->total,
!                                   instr->ntuples);
!         else
!             appendStringInfo(buf, ": time=%.3f calls=%.0f\n",
                            1000.0 * instr->total, instr->ntuples);
+
+
+         pfree(triggerStr->data);
+         pfree(triggerStr);
       }
   }

***************
*** 417,423 ****

       if (plan == NULL)
       {
!         appendStringInfoChar(str, '\n');
           return;
       }

--- 465,475 ----

       if (plan == NULL)
       {
!         if (es->printXML)
!             appendStringInfo(str, "<plan />\n");
!         else
!             appendStringInfoChar(str, '\n');
!
           return;
       }

***************
*** 588,601 ****
               break;
       }

!     appendStringInfoString(str, pname);
       switch (nodeTag(plan))
       {
           case T_IndexScan:
               if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
!                 appendStringInfoString(str, " Backward");
!             appendStringInfo(str, " using %s",
!                       explain_get_index_name(((IndexScan *) plan)->indexid));
               /* FALL THRU */
           case T_SeqScan:
           case T_BitmapHeapScan:
--- 640,677 ----
               break;
       }

!     if (es->printXML)
!         appendStringInfo(str, "<plan name=\"%s\" indent=\"%d\">\n", pname,
indent);
!     else
!         appendStringInfoString(str, pname);
!
       switch (nodeTag(plan))
       {
           case T_IndexScan:
+         {
+             StringInfo index;
+             index = makeStringInfo();
+             appendStringInfo(index, "name=\"%s\"",
explain_get_index_name(((IndexScan *) plan)->indexid));
+
               if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
!             {
!                 if (es->printXML)
!                     appendStringInfoString(index, " backward");
!                 else
!                     appendStringInfoString(str, " Backward");
!
!             }
!
!             if (es->printXML)
!                 appendStringInfo(str, "  <index %s />\n",
!                      index->data);
!             else
!                 appendStringInfo(str, " using %s",
!                     explain_get_index_name(((IndexScan *) plan)->indexid));
!
!             pfree(index->data);
!             pfree(index);
!         }
               /* FALL THRU */
           case T_SeqScan:
           case T_BitmapHeapScan:
***************
*** 605,610 ****
--- 681,689 ----
                   RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
                                                 es->rtable);
                   char       *relname;
+                 StringInfo resname;
+
+                 resname = makeStringInfo();

                   /* Assume it's on a real relation */
                   Assert(rte->rtekind == RTE_RELATION);
***************
*** 612,627 ****
                   /* We only show the rel name, not schema name */
                   relname = get_rel_name(rte->relid);

!                 appendStringInfo(str, " on %s",
                                    quote_identifier(relname));
                   if (strcmp(rte->eref->aliasname, relname) != 0)
!                     appendStringInfo(str, " %s",
!                                      quote_identifier(rte->eref->aliasname));
               }
               break;
           case T_BitmapIndexScan:
!             appendStringInfo(str, " on %s",
!                 explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
               break;
           case T_SubqueryScan:
               if (((Scan *) plan)->scanrelid > 0)
--- 691,733 ----
                   /* We only show the rel name, not schema name */
                   relname = get_rel_name(rte->relid);

!                 if (es->printXML)
!                 {
!                     appendStringInfo(resname, "name=\"%s\"",
!                                  quote_identifier(relname));
!                 } else
!                 {
!                     appendStringInfo(str, " on %s",
                                    quote_identifier(relname));
+                 }
+
+
                   if (strcmp(rte->eref->aliasname, relname) != 0)
!                 {
!                     if (es->printXML)
!                         appendStringInfo(resname, " alias=\"%s\"",
!                             quote_identifier(rte->eref->aliasname));
!                     else
!                         appendStringInfo(str, " %s",
!                             quote_identifier(rte->eref->aliasname));
!                 }
!
!                 if (es->printXML)
!                     appendStringInfo(str, "  <table %s/>\n",
!                                  resname->data);
!
!                 pfree(resname->data);
!                 pfree(resname);
               }
               break;
           case T_BitmapIndexScan:
!             if (es->printXML)
!                 appendStringInfo(str, "  <index name=\"%s\" />\n",
!                     explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
!             else
!                 appendStringInfo(str, " on %s",
!                     explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
!
               break;
           case T_SubqueryScan:
               if (((Scan *) plan)->scanrelid > 0)
***************
*** 629,636 ****
                   RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
                                                 es->rtable);

!                 appendStringInfo(str, " %s",
                                    quote_identifier(rte->eref->aliasname));
               }
               break;
           case T_FunctionScan:
--- 735,747 ----
                   RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
                                                 es->rtable);

!                 if (es->printXML)
!                     appendStringInfo(str, "  <table alias=\"%s\" />\n",
                                    quote_identifier(rte->eref->aliasname));
+                 else
+                     appendStringInfo(str, " %s",
+                                  quote_identifier(rte->eref->aliasname));
+
               }
               break;
           case T_FunctionScan:
***************
*** 641,646 ****
--- 752,761 ----
                   Node       *funcexpr;
                   char       *proname;

+                 StringInfo resname;
+
+                 resname = makeStringInfo();
+
                   /* Assert it's on a RangeFunction */
                   Assert(rte->rtekind == RTE_FUNCTION);

***************
*** 661,671 ****
                   else
                       proname = rte->eref->aliasname;

!                 appendStringInfo(str, " on %s",
                                    quote_identifier(proname));
                   if (strcmp(rte->eref->aliasname, proname) != 0)
!                     appendStringInfo(str, " %s",
                                        quote_identifier(rte->eref->aliasname));
               }
               break;
           case T_ValuesScan:
--- 776,805 ----
                   else
                       proname = rte->eref->aliasname;

!                 if (es->printXML)
!                     appendStringInfo(resname, "name=\"%s\"",
!                                  quote_identifier(proname));
!                 else
!                     appendStringInfo(str, " on %s",
                                    quote_identifier(proname));
+
                   if (strcmp(rte->eref->aliasname, proname) != 0)
!                 {
!                     if (es->printXML)
!                         appendStringInfo(resname, " alias=\"%s\"",
!                                       quote_identifier(rte->eref->aliasname));
!                     else
!                         appendStringInfo(str, " %s",
                                        quote_identifier(rte->eref->aliasname));
+
+                 }
+
+                 if (es->printXML)
+                     appendStringInfo(str, "  <function %s />\n",
+                                  resname->data);
+                 pfree(resname->data);
+                 pfree(resname);
+
               }
               break;
           case T_ValuesScan:
***************
*** 680,686 ****

                   valsname = rte->eref->aliasname;

!                 appendStringInfo(str, " on %s",
                                    quote_identifier(valsname));
               }
               break;
--- 814,824 ----

                   valsname = rte->eref->aliasname;

!                 if (es->printXML)
!                     appendStringInfo(str, "name=\"%s\"",
!                                  quote_identifier(valsname));
!                 else
!                     appendStringInfo(str, " on %s",
                                    quote_identifier(valsname));
               }
               break;
***************
*** 688,694 ****
               break;
       }

!     appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
                        plan->startup_cost, plan->total_cost,
                        plan->plan_rows, plan->plan_width);

--- 826,838 ----
               break;
       }

!     if (es->printXML)
!         appendStringInfo(str, "  <cost startup=\"%.2f\" total=\"%.2f\" "
!                      "rows=\"%.0f\" width=\"%d\" />\n",
!                      plan->startup_cost, plan->total_cost,
!                      plan->plan_rows, plan->plan_width);
!     else
!         appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
                        plan->startup_cost, plan->total_cost,
                        plan->plan_rows, plan->plan_width);

***************
*** 703,717 ****
       {
           double        nloops = planstate->instrument->nloops;

!         appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
!                          1000.0 * planstate->instrument->startup / nloops,
!                          1000.0 * planstate->instrument->total / nloops,
!                          planstate->instrument->ntuples / nloops,
!                          planstate->instrument->nloops);
       }
       else if (es->printAnalyze)
!         appendStringInfo(str, " (never executed)");
!     appendStringInfoChar(str, '\n');

       /* target list */
       if (es->printTList)
--- 847,878 ----
       {
           double        nloops = planstate->instrument->nloops;

!         if (es->printXML)
!             appendStringInfo(str,
!                 "  <analyze time_start=\"%.3f\" time_end=\"%.3f\" "
!                 "rows=\"%.0f\" loops=\"%.0f\" />\n",
!                 1000.0 * planstate->instrument->startup / nloops,
!                 1000.0 * planstate->instrument->total / nloops,
!                 planstate->instrument->ntuples / nloops,
!                 planstate->instrument->nloops);
!         else
!             appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
!                 1000.0 * planstate->instrument->startup / nloops,
!                 1000.0 * planstate->instrument->total / nloops,
!                 planstate->instrument->ntuples / nloops,
!                 planstate->instrument->nloops);
       }
       else if (es->printAnalyze)
!     {
!         if (es->printXML)
!             appendStringInfo(str, "  <analyze never />");
!         else
!             appendStringInfo(str, " (never executed)");
!
!     }
!
!     if (!es->printXML)
!         appendStringInfoChar(str, '\n');

       /* target list */
       if (es->printTList)
***************
*** 823,835 ****
                               str, indent, es);
               break;
           case T_Sort:
!             show_sort_keys(plan,
                              ((Sort *) plan)->numCols,
                              ((Sort *) plan)->sortColIdx,
                              "Sort Key",
                              str, indent, es);
-             show_sort_info((SortState *) planstate,
-                            str, indent, es);
               break;
           case T_Result:
               show_upper_qual((List *) ((Result *) plan)->resconstantqual,
--- 984,994 ----
                               str, indent, es);
               break;
           case T_Sort:
!             show_sort_keys((SortState *) planstate, plan,
                              ((Sort *) plan)->numCols,
                              ((Sort *) plan)->sortColIdx,
                              "Sort Key",
                              str, indent, es);
               break;
           case T_Result:
               show_upper_qual((List *) ((Result *) plan)->resconstantqual,
***************
*** 843,856 ****
               break;
       }

       /* initPlan-s */
       if (plan->initPlan)
       {
           ListCell   *lst;

!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  InitPlan\n");
           foreach(lst, planstate->initPlan)
           {
               SubPlanState *sps = (SubPlanState *) lfirst(lst);
--- 1002,1023 ----
               break;
       }

+     if (es->printXML)
+         appendStringInfo(str, "</plan>\n");
+
       /* initPlan-s */
       if (plan->initPlan)
       {
           ListCell   *lst;

!         if (!es->printXML)
!         {
!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!
!             appendStringInfo(str, "  InitPlan\n");
!         }
!
           foreach(lst, planstate->initPlan)
           {
               SubPlanState *sps = (SubPlanState *) lfirst(lst);
***************
*** 858,864 ****

               for (i = 0; i < indent; i++)
                   appendStringInfo(str, "  ");
!             appendStringInfo(str, "    ->  ");
               explain_outNode(str,
                               exec_subplan_get_plan(es->pstmt, sp),
                               sps->planstate,
--- 1025,1034 ----

               for (i = 0; i < indent; i++)
                   appendStringInfo(str, "  ");
!
!             if (!es->printXML)
!                 appendStringInfo(str, "    ->  ");
!
               explain_outNode(str,
                               exec_subplan_get_plan(es->pstmt, sp),
                               sps->planstate,
***************
*** 870,878 ****
       /* lefttree */
       if (outerPlan(plan))
       {
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  ->  ");

           /*
            * Ordinarily we don't pass down our own outer_plan value to our child
--- 1040,1052 ----
       /* lefttree */
       if (outerPlan(plan))
       {
!
!         if (!es->printXML)
!         {
!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  ->  ");
!         }

           /*
            * Ordinarily we don't pass down our own outer_plan value to our child
***************
*** 888,896 ****
       /* righttree */
       if (innerPlan(plan))
       {
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  ->  ");
           explain_outNode(str, innerPlan(plan),
                           innerPlanState(planstate),
                           outerPlan(plan),
--- 1062,1073 ----
       /* righttree */
       if (innerPlan(plan))
       {
!         if (!es->printXML)
!         {
!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  ->  ");
!         }
           explain_outNode(str, innerPlan(plan),
                           innerPlanState(planstate),
                           outerPlan(plan),
***************
*** 909,917 ****
           {
               Plan       *subnode = (Plan *) lfirst(lst);

!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  ->  ");

               /*
                * Ordinarily we don't pass down our own outer_plan value to our
--- 1086,1097 ----
           {
               Plan       *subnode = (Plan *) lfirst(lst);

!             if (!es->printXML)
!             {
!                 for (i = 0; i < indent; i++)
!                     appendStringInfo(str, "  ");
!                 appendStringInfo(str, "  ->  ");
!             }

               /*
                * Ordinarily we don't pass down our own outer_plan value to our
***************
*** 939,947 ****
           {
               Plan       *subnode = (Plan *) lfirst(lst);

!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  ->  ");

               explain_outNode(str, subnode,
                               bitmapandstate->bitmapplans[j],
--- 1119,1130 ----
           {
               Plan       *subnode = (Plan *) lfirst(lst);

!             if (!es->printXML)
!             {
!                 for (i = 0; i < indent; i++)
!                     appendStringInfo(str, "  ");
!                 appendStringInfo(str, "  ->  ");
!             }

               explain_outNode(str, subnode,
                               bitmapandstate->bitmapplans[j],
***************
*** 963,971 ****
           {
               Plan       *subnode = (Plan *) lfirst(lst);

!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  ->  ");

               explain_outNode(str, subnode,
                               bitmaporstate->bitmapplans[j],
--- 1146,1157 ----
           {
               Plan       *subnode = (Plan *) lfirst(lst);

!             if (!es->printXML)
!             {
!                 for (i = 0; i < indent; i++)
!                     appendStringInfo(str, "  ");
!                 appendStringInfo(str, "  ->  ");
!             }

               explain_outNode(str, subnode,
                               bitmaporstate->bitmapplans[j],
***************
*** 981,989 ****
           SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
           Plan       *subnode = subqueryscan->subplan;

!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  ->  ");

           explain_outNode(str, subnode,
                           subquerystate->subplan,
--- 1167,1178 ----
           SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
           Plan       *subnode = subqueryscan->subplan;

!         if (!es->printXML)
!         {
!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  ->  ");
!         }

           explain_outNode(str, subnode,
                           subquerystate->subplan,
***************
*** 996,1004 ****
       {
           ListCell   *lst;

!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  SubPlan\n");
           foreach(lst, planstate->subPlan)
           {
               SubPlanState *sps = (SubPlanState *) lfirst(lst);
--- 1185,1196 ----
       {
           ListCell   *lst;

!         if (!es->printXML)
!         {
!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "  SubPlan\n");
!         }
           foreach(lst, planstate->subPlan)
           {
               SubPlanState *sps = (SubPlanState *) lfirst(lst);
***************
*** 1006,1012 ****

               for (i = 0; i < indent; i++)
                   appendStringInfo(str, "  ");
!             appendStringInfo(str, "    ->  ");
               explain_outNode(str,
                               exec_subplan_get_plan(es->pstmt, sp),
                               sps->planstate,
--- 1198,1206 ----

               for (i = 0; i < indent; i++)
                   appendStringInfo(str, "  ");
!
!             if (!es->printXML)
!                 appendStringInfo(str, "    ->  ");
               explain_outNode(str,
                               exec_subplan_get_plan(es->pstmt, sp),
                               sps->planstate,
***************
*** 1042,1050 ****
       useprefix = list_length(es->rtable) > 1;

       /* Emit line prefix */
!     for (i = 0; i < indent; i++)
!         appendStringInfo(str, "  ");
!     appendStringInfo(str, "  Output: ");

       /* Deparse each non-junk result column */
       i = 0;
--- 1236,1252 ----
       useprefix = list_length(es->rtable) > 1;

       /* Emit line prefix */
!
!     if (es->printXML)
!     {
!         appendStringInfo(str, "  <output>\n");
!     }
!     else
!     {
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  Output: ");
!     }

       /* Deparse each non-junk result column */
       i = 0;
***************
*** 1054,1067 ****

           if (tle->resjunk)
               continue;
!         if (i++ > 0)
!             appendStringInfo(str, ", ");
!         appendStringInfoString(str,
!                                deparse_expression((Node *) tle->expr, context,
!                                                   useprefix, false));
       }

!     appendStringInfoChar(str, '\n');
   }

   /*
--- 1256,1282 ----

           if (tle->resjunk)
               continue;
!
!         if (es->printXML)
!         {
!             appendStringInfo(str, "   <col name=\"%s\" />\n",
!                 deparse_expression((Node *) tle->expr,
!                 context, useprefix, false));
!         }
!         else
!         {
!             if (i++ > 0)
!                 appendStringInfo(str, ", ");
!             appendStringInfoString(str,
!                 deparse_expression((Node *) tle->expr,
!                 context, useprefix, false));
!         }
       }

!     if (es->printXML)
!         appendStringInfo(str, "  </output>\n");
!     else
!         appendStringInfoChar(str, '\n');
   }

   /*
***************
*** 1099,1107 ****
       exprstr = deparse_expression(node, context, useprefix, false);

       /* And add to str */
!     for (i = 0; i < indent; i++)
!         appendStringInfo(str, "  ");
!     appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
   }

   /*
--- 1314,1329 ----
       exprstr = deparse_expression(node, context, useprefix, false);

       /* And add to str */
!
!     if (es->printXML)
!         appendStringInfo(str,"  <qualifier type=\"%s\" value=\"%s\" />\n",
!             qlabel, exprstr);
!     else
!     {
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
!     }
   }

   /*
***************
*** 1132,1147 ****
       exprstr = deparse_expression(node, context, useprefix, false);

       /* And add to str */
!     for (i = 0; i < indent; i++)
!         appendStringInfo(str, "  ");
!     appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
   }

   /*
    * Show the sort keys for a Sort node.
    */
   static void
! show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
                  const char *qlabel,
                  StringInfo str, int indent, ExplainState *es)
   {
--- 1354,1377 ----
       exprstr = deparse_expression(node, context, useprefix, false);

       /* And add to str */
!
!     if (es->printXML)
!         appendStringInfo(str,"  <qualifier type=\"%s\" value=\"%s\" />\n",
!             qlabel, exprstr);
!
!     else
!     {
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
!     }
   }

   /*
    * Show the sort keys for a Sort node.
    */
   static void
! show_sort_keys(SortState *sortstate, Plan *sortplan, int nkeys,
AttrNumber *keycols,
                  const char *qlabel,
                  StringInfo str, int indent, ExplainState *es)
   {
***************
*** 1150,1162 ****
       int            keyno;
       char       *exprstr;
       int            i;

       if (nkeys <= 0)
           return;

!     for (i = 0; i < indent; i++)
!         appendStringInfo(str, "  ");
!     appendStringInfo(str, "  %s: ", qlabel);

       /* Set up deparsing context */
       context = deparse_context_for_plan((Node *) outerPlan(sortplan),
--- 1380,1430 ----
       int            keyno;
       char       *exprstr;
       int            i;
+     StringInfo    condition;

       if (nkeys <= 0)
           return;

!     if (es->printXML)
!         appendStringInfo(str,"  <sort type=\"%s\"",
!             qlabel);
!
!     /*
!       * If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
!       */
!     Assert(IsA(sortstate, SortState));
!     if (es->printAnalyze && sortstate->sort_Done &&
!         sortstate->tuplesortstate != NULL)
!     {
!         char       *sortinfo;
!         int            i;
!
!         sortinfo = tuplesort_explain((Tuplesortstate *)
sortstate->tuplesortstate);
!
!         if (es->printXML)
!         {
!             appendStringInfo(str, " desc=\"%s\" ", sortinfo);
!         }
!         else
!         {
!             for (i = 0; i < indent; i++)
!                 appendStringInfo(str, "  ");
!             appendStringInfo(str, "%s\n", sortinfo);
!
!         }
!         pfree(sortinfo);
!     }
!
!     if (es->printXML)
!         appendStringInfo(str," />\n");
!     else
!     {
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  %s: ", qlabel);
!     }
!
!

       /* Set up deparsing context */
       context = deparse_context_for_plan((Node *) outerPlan(sortplan),
***************
*** 1164,1169 ****
--- 1432,1439 ----
                                          es->rtable);
       useprefix = list_length(es->rtable) > 1;

+     condition = makeStringInfo();
+
       for (keyno = 0; keyno < nkeys; keyno++)
       {
           /* find key expression in tlist */
***************
*** 1175,1209 ****
           /* Deparse the expression, showing any top-level cast */
           exprstr = deparse_expression((Node *) target->expr, context,
                                        useprefix, true);
!         /* And add to str */
!         if (keyno > 0)
!             appendStringInfo(str, ", ");
!         appendStringInfoString(str, exprstr);
       }

!     appendStringInfo(str, "\n");
! }
!
! /*
!  * If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
!  */
! static void
! show_sort_info(SortState *sortstate,
!                StringInfo str, int indent, ExplainState *es)
! {
!     Assert(IsA(sortstate, SortState));
!     if (es->printAnalyze && sortstate->sort_Done &&
!         sortstate->tuplesortstate != NULL)
!     {
!         char       *sortinfo;
!         int            i;

!         sortinfo = tuplesort_explain((Tuplesortstate *)
sortstate->tuplesortstate);
!         for (i = 0; i < indent; i++)
!             appendStringInfo(str, "  ");
!         appendStringInfo(str, "  %s\n", sortinfo);
!         pfree(sortinfo);
!     }
   }

   /*
--- 1445,1469 ----
           /* Deparse the expression, showing any top-level cast */
           exprstr = deparse_expression((Node *) target->expr, context,
                                        useprefix, true);
!
!         if (es->printXML)
!             appendStringInfo(condition, "    <key number=\"%d\">%s</key>\n",
keyno, exprstr);
!         else
!         {
!             /* And add to str */
!             if (keyno > 0)
!                 appendStringInfo(str, ", ");
!             appendStringInfoString(str, exprstr);
!         }
       }

!     if (es->printXML)
!         appendStringInfo(str,"%s  </sort>\n", condition->data);
!     else
!         appendStringInfo(str, "\n");

!     pfree(condition->data);
!     pfree(condition);
   }

   /*
***************
*** 1231,1233 ****
--- 1491,1552 ----
       }
       return result;
   }
+
+ /*
+  * Outputs the DTD for the EXPLAIN XML output
+  *
+  */
+
+ static void
+ show_dtd(StringInfo str)
+ {
+
+     appendStringInfo(str, "<!DOCTYPE explain\n"
+                   "[\n"
+                               "<!ELEMENT explain (plan+, runtime?) >\n"
+                           "<!ELEMENT plan (table?, index?, cost,
output?, sort?, analyze?, qualifier?) >\n"
+                   "<!ELEMENT table EMPTY >\n"
+                   "<!ELEMENT cost EMPTY >\n"
+                   "<!ELEMENT qualifier EMPTY >\n"
+                   "<!ELEMENT output (col+) >\n"
+                   "<!ELEMENT col EMPTY >\n"
+                   "<!ELEMENT analyze EMPTY >\n"
+                   "<!ELEMENT runtime EMPTY >\n"
+                   "<!ELEMENT index EMPTY >\n"
+                   "<!ELEMENT sort (key+) >\n"
+                   "<!ELEMENT key (#PCDATA) >\n"
+                               "<!ATTLIST explain\n"
+                               "   version CDATA  #REQUIRED >\n"
+                   "<!ATTLIST plan\n"
+                   "   name CDATA     #REQUIRED\n"
+                   "   indent CDATA   #REQUIRED >\n"
+                   "<!ATTLIST cost\n"
+                   "   startup CDATA  #REQUIRED\n"
+                   "   total CDATA    #REQUIRED\n"
+                   "   rows CDATA     #REQUIRED\n"
+                   "   width CDATA    #REQUIRED >\n"
+                   "<!ATTLIST table\n"
+                   "   name CDATA     #REQUIRED\n"
+                    "   alias CDATA    #IMPLIED>\n"
+                   "<!ATTLIST qualifier\n"
+                   "   type CDATA #REQUIRED\n"
+                   "   value CDATA #REQUIRED >\n"
+                   "<!ATTLIST col\n"
+                   "   name CDATA #REQUIRED >\n"
+                   "<!ATTLIST analyze\n"
+                   "   time_start CDATA #REQUIRED\n"
+                   "   time_end CDATA #REQUIRED\n"
+                   "   rows CDATA #REQUIRED\n"
+                   "   loops CDATA #REQUIRED >\n"
+                   "<!ATTLIST runtime\n"
+                   "   ms CDATA #REQUIRED >\n"
+                   "<!ATTLIST index\n"
+                   "   name CDATA #REQUIRED >\n"
+                   "<!ATTLIST sort\n"
+                   "   type CDATA #REQUIRED >\n"
+                   "<!ATTLIST key\n"
+                   "   number CDATA #REQUIRED >\n"
+                   "]>\n\n");
+
+
+ }
*** src/bin/psql/sql_help.h.orig    2008-06-26 18:50:02.000000000 -0700
--- src/bin/psql/sql_help.h    2008-06-20 22:17:37.000000000 -0700
***************
*** 403,409 ****

       { "EXPLAIN",
         N_("show the execution plan of a statement"),
!       N_("EXPLAIN [ ANALYZE ] [ VERBOSE ] statement") },

       { "FETCH",
         N_("retrieve rows from a query using a cursor"),
--- 403,409 ----

       { "EXPLAIN",
         N_("show the execution plan of a statement"),
!       N_("EXPLAIN [ ANALYZE ] [ VERBOSE ] [ XML [ DTD ] ] statement") },

       { "FETCH",
         N_("retrieve rows from a query using a cursor"),
*** src/bin/psql/tab-complete.c.orig    2008-06-10 09:59:14.000000000 -0700
--- src/bin/psql/tab-complete.c    2008-06-26 08:01:25.000000000 -0700
***************
*** 1541,1552 ****
   /* EXPLAIN */

       /*
!      * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
        */
       else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
       {
           static const char *const list_EXPLAIN[] =
!         {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE",
"VERBOSE", NULL};

           COMPLETE_WITH_LIST(list_EXPLAIN);
       }
--- 1541,1552 ----
   /* EXPLAIN */

       /*
!      * Complete EXPLAIN [ANALYZE] [VERBOSE] [XML [DTD]] with list of
EXPLAIN-able commands
        */
       else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0)
       {
           static const char *const list_EXPLAIN[] =
!         {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE",
"VERBOSE", "XML", "DTD", NULL};

           COMPLETE_WITH_LIST(list_EXPLAIN);
       }
***************
*** 1554,1560 ****
                pg_strcasecmp(prev_wd, "ANALYZE") == 0)
       {
           static const char *const list_EXPLAIN[] =
!         {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE", NULL};

           COMPLETE_WITH_LIST(list_EXPLAIN);
       }
--- 1554,1560 ----
                pg_strcasecmp(prev_wd, "ANALYZE") == 0)
       {
           static const char *const list_EXPLAIN[] =
!         {"SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE",
"XML", "DTD", NULL};

           COMPLETE_WITH_LIST(list_EXPLAIN);
       }
*** src/include/nodes/parsenodes.h.orig    2008-06-10 09:59:07.000000000 -0700
--- src/include/nodes/parsenodes.h    2008-06-26 07:28:42.000000000 -0700
***************
*** 1871,1876 ****
--- 1871,1878 ----
       Node       *query;            /* the query (as a raw parse tree) */
       bool        verbose;        /* print plan info */
       bool        analyze;        /* get statistics by executing plan */
+     bool        xml;            /* get the output as XML instead of plain text */
+     bool        dtd;            /* include the DTD for the XML output */
   } ExplainStmt;

   /* ----------------------
*** src/backend/parser/gram.y.orig    2008-06-26 18:59:41.000000000 -0700
--- src/backend/parser/gram.y    2008-06-26 19:16:54.000000000 -0700
***************
*** 282,287 ****
--- 282,288 ----
   %type <boolean> opt_instead opt_analyze
   %type <boolean> index_opt_unique opt_verbose opt_full
   %type <boolean> opt_freeze opt_default opt_recheck
+ %type <boolean> opt_xml opt_dtd
   %type <defelt>    opt_binary opt_oids copy_delimiter

   %type <boolean> copy_from
***************
*** 388,393 ****
--- 389,395 ----
       DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
       DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
       DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
+     DTD

       EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EXCLUDING
       EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
***************
*** 449,454 ****
--- 451,458 ----

       WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE

+     XML
+
       XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
       XMLPI XMLROOT XMLSERIALIZE

***************
*** 5787,5802 ****

/*****************************************************************************
    *
    *        QUERY:
!  *                EXPLAIN [ANALYZE] [VERBOSE] query
    *

*****************************************************************************/

! ExplainStmt: EXPLAIN opt_analyze opt_verbose ExplainableStmt
                   {
                       ExplainStmt *n = makeNode(ExplainStmt);
                       n->analyze = $2;
                       n->verbose = $3;
!                     n->query = $4;
                       $$ = (Node *)n;
                   }
           ;
--- 5791,5808 ----

/*****************************************************************************
    *
    *        QUERY:
!  *                EXPLAIN [ANALYZE] [VERBOSE] [XML [DTD]] query
    *

*****************************************************************************/

! ExplainStmt: EXPLAIN opt_analyze opt_verbose opt_xml opt_dtd ExplainableStmt
                   {
                       ExplainStmt *n = makeNode(ExplainStmt);
                       n->analyze = $2;
                       n->verbose = $3;
!                     n->xml = $4;
!                     n->dtd = $5;
!                     n->query = $6;
                       $$ = (Node *)n;
                   }
           ;
***************
*** 5815,5820 ****
--- 5821,5836 ----
               | /* EMPTY */            { $$ = FALSE; }
           ;

+ opt_xml:
+             XML                { $$ = TRUE; }
+             | /*EMPTY*/            { $$ = FALSE; }
+         ;
+
+ opt_dtd:
+             DTD                { $$ = TRUE; }
+             | /*EMPTY*/            { $$ = FALSE; }
+         ;
+

/*****************************************************************************
    *
    *        QUERY:
***************
*** 9019,9024 ****
--- 9035,9041 ----
               | DOMAIN_P
               | DOUBLE_P
               | DROP
+             | DTD
               | EACH
               | ENABLE_P
               | ENCODING
***************
*** 9186,9191 ****
--- 9203,9209 ----
               | WITHOUT
               | WORK
               | WRITE
+             | XML
               | XML_P
               | YEAR_P
               | YES_P
*** src/backend/parser/keywords.c.orig    2008-06-26 19:00:01.000000000 -0700
--- src/backend/parser/keywords.c    2008-06-20 22:23:28.000000000 -0700
***************
*** 146,151 ****
--- 146,152 ----
       {"domain", DOMAIN_P, UNRESERVED_KEYWORD},
       {"double", DOUBLE_P, UNRESERVED_KEYWORD},
       {"drop", DROP, UNRESERVED_KEYWORD},
+     {"dtd", DTD, UNRESERVED_KEYWORD},
       {"each", EACH, UNRESERVED_KEYWORD},
       {"else", ELSE, RESERVED_KEYWORD},
       {"enable", ENABLE_P, UNRESERVED_KEYWORD},
***************
*** 414,420 ****
       {"without", WITHOUT, UNRESERVED_KEYWORD},
       {"work", WORK, UNRESERVED_KEYWORD},
       {"write", WRITE, UNRESERVED_KEYWORD},
!     {"xml", XML_P, UNRESERVED_KEYWORD},
       {"xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD},
       {"xmlconcat", XMLCONCAT, COL_NAME_KEYWORD},
       {"xmlelement", XMLELEMENT, COL_NAME_KEYWORD},
--- 415,422 ----
       {"without", WITHOUT, UNRESERVED_KEYWORD},
       {"work", WORK, UNRESERVED_KEYWORD},
       {"write", WRITE, UNRESERVED_KEYWORD},
!     {"xml", XML, UNRESERVED_KEYWORD},
!     {"xmlp", XML_P, UNRESERVED_KEYWORD},
       {"xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD},
       {"xmlconcat", XMLCONCAT, COL_NAME_KEYWORD},
       {"xmlelement", XMLELEMENT, COL_NAME_KEYWORD},
*** src/interfaces/ecpg/preproc/preproc.y.orig    2008-06-26
20:20:49.000000000 -0700
--- src/interfaces/ecpg/preproc/preproc.y    2008-06-26 20:21:46.000000000 -0700
***************
*** 434,439 ****
--- 434,440 ----
       DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
       DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
       DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
+     DTD

       EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT
EXCLUSIVE EXCLUDING
       EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
***************
*** 493,498 ****
--- 494,501 ----
       VERBOSE VERSION_P VIEW VOLATILE
       WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE

+     XML
+
       XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
       XMLPI XMLROOT XMLSERIALIZE



pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Fix pg_ctl restart bug
Next
From: Simon Riggs
Date:
Subject: Re: Explain XML patch