HAWQ-1758. Add debug info for udf
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 41f7271..83371d0 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -61,7 +61,6 @@
#include "cdb/cdbpathlocus.h"
#include "cdb/memquota.h"
#include "miscadmin.h"
-#include "cdb/cdbgang.h"
#include "cdb/dispatcher.h"
#ifdef USE_ORCA
@@ -69,26 +68,6 @@
extern StringInfo OptVersion();
#endif
-typedef struct ExplainState
-{
- /* options */
- bool printTList; /* print plan targetlists */
- bool printAnalyze; /* print actual times */
- /* other states */
- PlannedStmt *pstmt; /* top of plan */
- List *rtable; /* range table */
-
- /* CDB */
- int segmentNum;
- struct CdbExplain_ShowStatCtx *showstatctx; /* EXPLAIN ANALYZE info */
- Slice *currentSlice; /* slice whose nodes we are visiting */
- ErrorData *deferredError; /* caught error to be re-thrown */
- MemoryContext explaincxt; /* mem pool for palloc()ing buffers etc. */
- TupOutputState *tupOutputState; /* for sending output to client */
- StringInfoData outbuf; /* the output buffer */
- StringInfoData workbuf; /* a scratch buffer */
-} ExplainState;
-
extern bool Test_print_direct_dispatch_info;
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
@@ -109,7 +88,7 @@
static double elapsed_time(instr_time *starttime);
static ErrorData *explain_defer_error(ExplainState *es);
-static void explain_outNode(StringInfo str,
+void explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
int indent, ExplainState *es, bool isSequential);
@@ -977,7 +956,7 @@
* side of a join with the current node. This is only interesting for
* deciphering runtime keys of an inner indexscan.
*/
-static void
+void
explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 9b6ae9f..5b71869 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -18,6 +18,7 @@
#include "access/xact.h"
#include "catalog/catquery.h"
#include "catalog/heap.h"
+#include "commands/explain.h"
#include "commands/trigger.h"
#include "executor/spi_priv.h"
#include "utils/lsyscache.h"
@@ -503,6 +504,10 @@
SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
bool read_only, long tcount)
{
+ clock_t start, finish;
+ double duration;
+ start = clock();
+
int res;
if (plan == NULL || tcount < 0)
@@ -530,6 +535,10 @@
PG_END_TRY();
_SPI_end_call(true);
+ finish = clock();
+ duration = (double)(finish - start) / CLOCKS_PER_SEC * 1000;
+ if (Debug_udf_plan)
+ elog(LOG, "query:%s; SPI_execute_plan time:%fms", plan->query, duration);
return res;
}
@@ -592,6 +601,10 @@
SPIPlanPtr
SPI_prepare(const char *src, int nargs, Oid *argtypes)
{
+ clock_t start, finish;
+ double duration;
+ start = clock();
+
_SPI_plan plan;
_SPI_plan *result;
@@ -636,6 +649,11 @@
_SPI_end_call(true);
+ finish = clock();
+ duration = (double)(finish - start) / CLOCKS_PER_SEC * 1000;
+ if (Debug_udf_plan)
+ elog(LOG, "query:%s; SPI_prepare time:%fms", src, duration);
+
return result;
}
@@ -680,6 +698,107 @@
return 0;
}
+void Explain_udf_plan(QueryDesc *qdesc)
+{
+ ExplainState explainState;
+ ExplainState *es = &explainState;
+ MemoryContext oldcxt = CurrentMemoryContext;
+ MemoryContext explaincxt;
+ /* Create EXPLAIN memory context. */
+ explaincxt = AllocSetContextCreate(
+ CurrentMemoryContext, "EXPLAIN working storage",
+ ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
+ /* Initialize ExplainState structure. */
+ memset(es, 0, sizeof(*es));
+ es->explaincxt = explaincxt;
+ es->showstatctx = NULL;
+ es->deferredError = NULL;
+ es->pstmt = qdesc->plannedstmt;
+ es->segmentNum = qdesc->plannedstmt->planner_segments;
+
+ /* Allocate output buffer and a scratch buffer. */
+ MemoryContextSwitchTo(explaincxt);
+ initStringInfoOfSize(&es->workbuf, 1000);
+ initStringInfoOfSize(&es->outbuf, 16000);
+ MemoryContextSwitchTo(oldcxt);
+
+ StringInfo buf = &es->outbuf;
+ es->currentSlice = getCurrentSlice(
+ qdesc->estate, LocallyExecutingSliceIndex(qdesc->estate));
+ es->rtable = qdesc->plannedstmt->rtable;
+
+ bool isSequential = false;
+ int indent = 0;
+ if (qdesc->plannedstmt->planTree->dispatch == DISPATCH_SEQUENTIAL) {
+ isSequential=true;
+ }
+
+ CmdType cmd = qdesc->plannedstmt->commandType;
+ Plan *childPlan = qdesc->plannedstmt->planTree;
+
+ if ((cmd == CMD_DELETE || cmd == CMD_INSERT || cmd == CMD_UPDATE) &&
+ qdesc->plannedstmt->planGen == PLANGEN_PLANNER)
+ {
+ /* Set sliceNum to the slice number of the outer-most query plan node */
+ int sliceNum = 0;
+ int numSegments = es->segmentNum;
+ char *cmdName = NULL;
+
+ switch (cmd)
+ {
+ case CMD_DELETE:
+ cmdName = "Delete";
+ break;
+ case CMD_INSERT:
+ cmdName = "Insert";
+ break;
+ case CMD_UPDATE:
+ cmdName = "Update";
+ break;
+ default:
+ /* This should never be reached */
+ Assert(!"Unexpected statement type");
+ break;
+ }
+ appendStringInfo(buf, "%s", cmdName);
+
+ if (IsA(childPlan, Motion))
+ {
+ Motion *pMotion = (Motion *)childPlan;
+ if (pMotion->motionType == MOTIONTYPE_FIXED && pMotion->numOutputSegs != 0)
+ {
+ numSegments = 1;
+ }
+ /* else: other motion nodes execute on all segments */
+ }
+ else if ((childPlan->directDispatch).isDirectDispatch)
+ {
+ numSegments = 1;
+ }
+ appendStringInfo(buf, " (slice%d; segments: %d)", sliceNum, numSegments);
+ appendStringInfo(buf, " (rows=%.0f width=%d)\n", ceil(childPlan->plan_rows / numSegments), childPlan->plan_width);
+ appendStringInfo(buf, " -> ");
+ indent = 3;
+ }
+ explain_outNode(buf, childPlan, qdesc->planstate,
+ NULL, indent, es, isSequential);
+
+ if (qdesc->estate->dispatch_data)
+ dispatcher_print_statistics(buf, qdesc->estate->dispatch_data);
+ appendStringInfo(buf, "Data locality statistics:\n");
+ if (qdesc->plannedstmt->datalocalityInfo ==NULL){
+ appendStringInfo(buf, " no data locality information in this query\n");
+ } else {
+ appendStringInfo(buf, " %s\n", qdesc->plannedstmt->datalocalityInfo->data);
+ }
+
+ elog(LOG, "UDF Plan:\n%s", buf->data);
+ // free memory
+ MemoryContextDelete(explaincxt);
+}
+
HeapTuple
SPI_copytuple(HeapTuple tuple)
{
@@ -1852,6 +1971,14 @@
}
PlannedStmt *stmt = copyObject(originalStmt);
+ if (Debug_udf_plan && originalStmt->datalocalityInfo)
+ {
+ stmt->datalocalityTime = originalStmt->datalocalityTime;
+ stmt->datalocalityInfo = makeStringInfo();
+ stmt->datalocalityInfo->cursor = originalStmt->datalocalityInfo->cursor;
+ appendStringInfoString(stmt->datalocalityInfo,
+ originalStmt->datalocalityInfo->data);
+ }
_SPI_current->processed = 0;
_SPI_current->lastoid = InvalidOid;
@@ -2211,7 +2338,13 @@
ExecutorStart(queryDesc, 0);
ExecutorRun(queryDesc, ForwardScanDirection, tcount);
-
+
+ // print udf plan to pglog
+ if (Debug_udf_plan)
+ {
+ Explain_udf_plan(queryDesc);
+ }
+
_SPI_current->processed = queryDesc->estate->es_processed;
_SPI_current->lastoid = queryDesc->estate->es_lastoid;
@@ -2456,6 +2589,14 @@
if (IsA(node, PlannedStmt))
{
PlannedStmt *ps = (PlannedStmt*) node;
+ if (Debug_udf_plan && ((PlannedStmt*)lfirst(lc))->datalocalityInfo)
+ {
+ ps->datalocalityTime = ((PlannedStmt*)lfirst(lc))->datalocalityTime;
+ ps->datalocalityInfo = makeStringInfo();
+ ps->datalocalityInfo->cursor = ((PlannedStmt*)lfirst(lc))->datalocalityInfo->cursor;
+ appendStringInfoString(ps->datalocalityInfo,
+ ((PlannedStmt*)lfirst(lc))->datalocalityInfo->data);
+ }
ps->qdContext = plancxt;
}
newplan->ptlist = lappend(newplan->ptlist, node);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index b90f1ec..8751f8a 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -279,6 +279,7 @@
#endif
bool log_duration = false;
bool Debug_print_plan = false;
+bool Debug_udf_plan = false;
bool Debug_print_parse = false;
bool Debug_print_rewritten = false;
bool Debug_pretty_print = false;
@@ -1446,6 +1447,14 @@
false, assign_log_stats, NULL
},
{
+ {"debug_udf_plan", PGC_USERSET, LOGGING_WHAT,
+ gettext_noop("Prints the execution plan of udf to server log."),
+ NULL
+ },
+ &Debug_udf_plan,
+ false, NULL, NULL
+ },
+ {
{"log_dispatch_stats", PGC_SUSET, STATS_MONITORING,
gettext_noop("Writes dispatcher performance statistics to the server log."),
NULL,
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index c00653d..1dba363 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -13,8 +13,28 @@
#ifndef EXPLAIN_H
#define EXPLAIN_H
+#include "cdb/cdbgang.h"
#include "executor/executor.h"
+typedef struct ExplainState
+{
+ /* options */
+ bool printTList; /* print plan targetlists */
+ bool printAnalyze; /* print actual times */
+ /* other states */
+ PlannedStmt *pstmt; /* top of plan */
+ List *rtable; /* range table */
+
+ /* CDB */
+ int segmentNum;
+ struct CdbExplain_ShowStatCtx *showstatctx; /* EXPLAIN ANALYZE info */
+ Slice *currentSlice; /* slice whose nodes we are visiting */
+ ErrorData *deferredError; /* caught error to be re-thrown */
+ MemoryContext explaincxt; /* mem pool for palloc()ing buffers etc. */
+ TupOutputState *tupOutputState; /* for sending output to client */
+ StringInfoData outbuf; /* the output buffer */
+ StringInfoData workbuf; /* a scratch buffer */
+} ExplainState;
extern void ExplainQuery(ExplainStmt *stmt, const char *queryString,
ParamListInfo params, DestReceiver *dest);
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 7b4ba1b..74102c6 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -113,6 +113,8 @@
extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan);
extern int SPI_freeplan(SPIPlanPtr plan);
+extern void Explain_udf_plan(QueryDesc *qdesc);
+
extern Oid SPI_getargtypeid(SPIPlanPtr plan, int argIndex);
extern int SPI_getargcount(SPIPlanPtr plan);
extern bool SPI_is_cursor_plan(SPIPlanPtr plan);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index d1698a7..e8c4713 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -133,6 +133,7 @@
/* GUC vars that are actually declared in guc.c, rather than elsewhere */
extern bool log_duration;
extern bool Debug_print_plan;
+extern bool Debug_udf_plan;
extern bool Debug_print_parse;
extern bool Debug_print_rewritten;
extern bool Debug_pretty_print;
diff --git a/src/test/regress/checkinc.py b/src/test/regress/checkinc.py
index 360e9c4..f229dc9 100755
--- a/src/test/regress/checkinc.py
+++ b/src/test/regress/checkinc.py
@@ -102,6 +102,7 @@
'json-c/json.h': [],
'emmintrin.h': [],
'cdb/cdbhash.h': [],
+ 'cdb/cdbgang.h': [],
}