*** 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



--
Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches

Reply via email to