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