Here's an updated version of my patch from last night. http://archives.postgresql.org/message-id/603c8f070905292048y804d505wf701214e7b81f...@mail.gmail.com
In addition to the changes mentioned there, this removes a completely unused argument from show_scan_qual() and two redundant ones from show_sort_keys(). I realize this may not be the most glamorous patch that any of you have read in the last year... ...Robert
*** a/src/backend/commands/explain.c --- b/src/backend/commands/explain.c *************** *** 63,78 **** static void explain_outNode(StringInfo str, static void show_plan_tlist(Plan *plan, StringInfo str, int indent, ExplainState *es); static void show_scan_qual(List *qual, const char *qlabel, ! int scanrelid, Plan *scan_plan, Plan *outer_plan, 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); /* --- 63,78 ---- static void show_plan_tlist(Plan *plan, StringInfo str, int indent, ExplainState *es); static void show_scan_qual(List *qual, const char *qlabel, ! Plan *scan_plan, Plan *outer_plan, 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, 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); + static void ExplainScanTarget(StringInfo str, Scan *plan, ExplainState *es); /* *************** *** 668,790 **** explain_outNode(StringInfo str, case T_SeqScan: case T_BitmapHeapScan: case T_TidScan: - if (((Scan *) plan)->scanrelid > 0) - { - RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, - es->rtable); - char *relname; - - /* Assume it's on a real relation */ - Assert(rte->rtekind == RTE_RELATION); - - /* 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) - { - RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, - es->rtable); - - appendStringInfo(str, " %s", - quote_identifier(rte->eref->aliasname)); - } - break; case T_FunctionScan: - if (((Scan *) plan)->scanrelid > 0) - { - RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, - es->rtable); - Node *funcexpr; - char *proname; - - /* Assert it's on a RangeFunction */ - Assert(rte->rtekind == RTE_FUNCTION); - - /* - * If the expression is still a function call, we can get the - * real name of the function. Otherwise, punt (this can - * happen if the optimizer simplified away the function call, - * for example). - */ - funcexpr = ((FunctionScan *) plan)->funcexpr; - if (funcexpr && IsA(funcexpr, FuncExpr)) - { - Oid funcid = ((FuncExpr *) funcexpr)->funcid; - - /* We only show the func name, not schema name */ - proname = get_func_name(funcid); - } - 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: - if (((Scan *) plan)->scanrelid > 0) - { - RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, - es->rtable); - char *valsname; - - /* Assert it's on a values rte */ - Assert(rte->rtekind == RTE_VALUES); - - valsname = rte->eref->aliasname; - - appendStringInfo(str, " on %s", - quote_identifier(valsname)); - } - break; case T_CteScan: - if (((Scan *) plan)->scanrelid > 0) - { - RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, - es->rtable); - - /* Assert it's on a non-self-reference CTE */ - Assert(rte->rtekind == RTE_CTE); - Assert(!rte->self_reference); - - appendStringInfo(str, " on %s", - quote_identifier(rte->ctename)); - if (strcmp(rte->eref->aliasname, rte->ctename) != 0) - appendStringInfo(str, " %s", - quote_identifier(rte->eref->aliasname)); - } - break; case T_WorkTableScan: ! if (((Scan *) plan)->scanrelid > 0) ! { ! RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, ! es->rtable); ! ! /* Assert it's on a self-reference CTE */ ! Assert(rte->rtekind == RTE_CTE); ! Assert(rte->self_reference); ! ! appendStringInfo(str, " on %s", ! quote_identifier(rte->ctename)); ! if (strcmp(rte->eref->aliasname, rte->ctename) != 0) ! appendStringInfo(str, " %s", ! quote_identifier(rte->eref->aliasname)); ! } break; default: break; --- 668,683 ---- case T_SeqScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: case T_FunctionScan: case T_ValuesScan: case T_CteScan: case T_WorkTableScan: ! ExplainScanTarget(str, (Scan *) plan, es); ! break; ! case T_BitmapIndexScan: ! appendStringInfo(str, " on %s", ! explain_get_index_name(((BitmapIndexScan *) plan)->indexid)); break; default: break; *************** *** 825,843 **** explain_outNode(StringInfo str, case T_IndexScan: show_scan_qual(((IndexScan *) plan)->indexqualorig, "Index Cond", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); show_scan_qual(plan->qual, "Filter", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); break; case T_BitmapIndexScan: show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, "Index Cond", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); break; --- 718,733 ---- *************** *** 845,851 **** explain_outNode(StringInfo str, /* XXX do we want to show this in production? */ show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, "Recheck Cond", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); /* FALL THRU */ --- 735,740 ---- *************** *** 854,869 **** explain_outNode(StringInfo str, case T_ValuesScan: case T_CteScan: case T_WorkTableScan: - show_scan_qual(plan->qual, - "Filter", - ((Scan *) plan)->scanrelid, - plan, outer_plan, - str, indent, es); - break; case T_SubqueryScan: show_scan_qual(plan->qual, "Filter", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); break; --- 743,751 ---- *************** *** 879,890 **** explain_outNode(StringInfo str, tidquals = list_make1(make_orclause(tidquals)); show_scan_qual(tidquals, "TID Cond", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); show_scan_qual(plan->qual, "Filter", - ((Scan *) plan)->scanrelid, plan, outer_plan, str, indent, es); } --- 761,770 ---- *************** *** 927,934 **** explain_outNode(StringInfo str, break; case T_Sort: show_sort_keys(plan, - ((Sort *) plan)->numCols, - ((Sort *) plan)->sortColIdx, "Sort Key", str, indent, es); show_sort_info((SortState *) planstate, --- 807,812 ---- *************** *** 1179,1185 **** show_plan_tlist(Plan *plan, */ static void show_scan_qual(List *qual, const char *qlabel, ! int scanrelid, Plan *scan_plan, Plan *outer_plan, StringInfo str, int indent, ExplainState *es) { List *context; --- 1057,1063 ---- */ static void show_scan_qual(List *qual, const char *qlabel, ! Plan *scan_plan, Plan *outer_plan, StringInfo str, int indent, ExplainState *es) { List *context; *************** *** 1249,1256 **** show_upper_qual(List *qual, const char *qlabel, Plan *plan, * 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) { List *context; --- 1127,1133 ---- * Show the sort keys for a Sort node. */ static void ! show_sort_keys(Plan *sortplan, const char *qlabel, StringInfo str, int indent, ExplainState *es) { List *context; *************** *** 1258,1263 **** show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols, --- 1135,1142 ---- int keyno; char *exprstr; int i; + int nkeys = ((Sort *) sortplan)->numCols; + AttrNumber *keycols = ((Sort *) sortplan)->sortColIdx; if (nkeys <= 0) return; *************** *** 1340,1342 **** explain_get_index_name(Oid indexId) --- 1219,1288 ---- } return result; } + + /* + * Explain details for Scan nodes. + */ + static void + ExplainScanTarget(StringInfo str, Scan *plan, ExplainState *es) + { + char *objectname = NULL; + Node *funcexpr; + RangeTblEntry *rte; + + if (plan->scanrelid <= 0) + return; + rte = rt_fetch(plan->scanrelid, es->rtable); + + switch (nodeTag(plan)) + { + case T_IndexScan: + case T_SeqScan: + case T_BitmapHeapScan: + case T_TidScan: + /* Assert it's on a real relation */ + Assert(rte->rtekind == RTE_RELATION); + objectname = get_rel_name(rte->relid); + break; + case T_FunctionScan: + /* Assert it's on a RangeFunction */ + Assert(rte->rtekind == RTE_FUNCTION); + + /* + * If the expression is still a function call, we can get the + * real name of the function. Otherwise, punt (this can + * happen if the optimizer simplified away the function call, + * for example). + */ + funcexpr = ((FunctionScan *) plan)->funcexpr; + if (funcexpr && IsA(funcexpr, FuncExpr)) + { + Oid funcid = ((FuncExpr *) funcexpr)->funcid; + objectname = get_func_name(funcid); + } + break; + case T_ValuesScan: + Assert(rte->rtekind == RTE_VALUES); + break; + case T_CteScan: + /* Assert it's on a non-self-reference CTE */ + Assert(rte->rtekind == RTE_CTE); + Assert(!rte->self_reference); + objectname = rte->ctename; + break; + case T_WorkTableScan: + /* Assert it's on a self-reference CTE */ + Assert(rte->rtekind == RTE_CTE); + Assert(rte->self_reference); + objectname = rte->ctename; + break; + default: + break; + } + + appendStringInfoString(str, " on"); + if (objectname != NULL) + appendStringInfo(str, " %s", quote_identifier(objectname)); + if (objectname == NULL || strcmp(rte->eref->aliasname, objectname) != 0) + appendStringInfo(str, " %s", quote_identifier(rte->eref->aliasname)); + }
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers