Explain XML patch

[email protected]
Newsgroups gmane.comp.db.postgresql.devel.patches
Message-ID <[email protected]>
*** 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.