Explain XML patch

From: raneyt(at)cecs(dot)pdx(dot)edu
To: pgsql-patches(at)postgresql(dot)org
Subject: Explain XML patch
Date: 2008-06-27 04:48:39
Message-ID: 20080626214839.xbfsvm8740gsswos@webmail.cecs.pdx.edu
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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

Responses

Browse pgsql-patches by date

  From Date Subject
Next Message Abhijit Menon-Sen 2008-06-27 05:43:10 Re: Removal of the patches email list
Previous Message Bruce Momjian 2008-06-27 01:54:46 Re: Fix pg_ctl restart bug