Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Typedefs | Enumerations | Functions | Variables

explain.h File Reference

#include "executor/executor.h"
#include "lib/stringinfo.h"
Include dependency graph for explain.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ExplainState

Typedefs

typedef enum ExplainFormat ExplainFormat
typedef struct ExplainState ExplainState
typedef void(* ExplainOneQuery_hook_type )(Query *query, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
typedef const char *(* explain_get_index_name_hook_type )(Oid indexId)

Enumerations

enum  ExplainFormat { EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_YAML }

Functions

void ExplainQuery (ExplainStmt *stmt, const char *queryString, ParamListInfo params, DestReceiver *dest)
void ExplainInitState (ExplainState *es)
TupleDesc ExplainResultDesc (ExplainStmt *stmt)
void ExplainOneUtility (Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
void ExplainOnePlan (PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
void ExplainPrintPlan (ExplainState *es, QueryDesc *queryDesc)
void ExplainQueryText (ExplainState *es, QueryDesc *queryDesc)
void ExplainBeginOutput (ExplainState *es)
void ExplainEndOutput (ExplainState *es)
void ExplainSeparatePlans (ExplainState *es)
void ExplainPropertyList (const char *qlabel, List *data, ExplainState *es)
void ExplainPropertyText (const char *qlabel, const char *value, ExplainState *es)
void ExplainPropertyInteger (const char *qlabel, int value, ExplainState *es)
void ExplainPropertyLong (const char *qlabel, long value, ExplainState *es)
void ExplainPropertyFloat (const char *qlabel, double value, int ndigits, ExplainState *es)

Variables

PGDLLIMPORT
ExplainOneQuery_hook_type 
ExplainOneQuery_hook
PGDLLIMPORT
explain_get_index_name_hook_type 
explain_get_index_name_hook

Typedef Documentation

typedef const char*(* explain_get_index_name_hook_type)(Oid indexId)

Definition at line 54 of file explain.h.

typedef void(* ExplainOneQuery_hook_type)(Query *query, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)

Definition at line 46 of file explain.h.

typedef struct ExplainState ExplainState

Enumeration Type Documentation

Enumerator:
EXPLAIN_FORMAT_TEXT 
EXPLAIN_FORMAT_XML 
EXPLAIN_FORMAT_JSON 
EXPLAIN_FORMAT_YAML 

Definition at line 19 of file explain.h.

{
    EXPLAIN_FORMAT_TEXT,
    EXPLAIN_FORMAT_XML,
    EXPLAIN_FORMAT_JSON,
    EXPLAIN_FORMAT_YAML
} ExplainFormat;


Function Documentation

void ExplainBeginOutput ( ExplainState es  ) 

Definition at line 2449 of file explain.c.

References appendStringInfoChar(), appendStringInfoString(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainState::format, ExplainState::grouping_stack, ExplainState::indent, lcons_int(), and ExplainState::str.

Referenced by explain_ExecutorEnd(), and ExplainQuery().

{
    switch (es->format)
    {
        case EXPLAIN_FORMAT_TEXT:
            /* nothing to do */
            break;

        case EXPLAIN_FORMAT_XML:
            appendStringInfoString(es->str,
             "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
            es->indent++;
            break;

        case EXPLAIN_FORMAT_JSON:
            /* top-level structure is an array of plans */
            appendStringInfoChar(es->str, '[');
            es->grouping_stack = lcons_int(0, es->grouping_stack);
            es->indent++;
            break;

        case EXPLAIN_FORMAT_YAML:
            es->grouping_stack = lcons_int(0, es->grouping_stack);
            break;
    }
}

void ExplainEndOutput ( ExplainState es  ) 
void ExplainInitState ( ExplainState es  ) 

Definition at line 249 of file explain.c.

References ExplainState::costs, makeStringInfo(), and ExplainState::str.

Referenced by explain_ExecutorEnd(), and ExplainQuery().

{
    /* Set default options. */
    memset(es, 0, sizeof(ExplainState));
    es->costs = true;
    /* Prepare output buffer. */
    es->str = makeStringInfo();
}

void ExplainOnePlan ( PlannedStmt plannedstmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params 
)

Definition at line 399 of file explain.c.

References ExplainState::analyze, appendStringInfo(), ExplainState::buffers, CommandCounterIncrement(), CreateIntoRelDestReceiver(), CreateQueryDesc(), elapsed_time(), EState::es_num_result_relations, EState::es_result_relations, EState::es_trig_target_relations, QueryDesc::estate, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), EXPLAIN_FORMAT_TEXT, ExplainCloseGroup(), ExplainOpenGroup(), ExplainPrintPlan(), ExplainPropertyFloat(), ExplainState::format, FreeQueryDesc(), GetActiveSnapshot(), GetIntoRelEFlags(), INSTR_TIME_SET_CURRENT, InvalidSnapshot, lfirst, None_Receiver, NULL, PopActiveSnapshot(), PushCopiedSnapshot(), report_triggers(), IntoClause::skipData, ExplainState::str, ExplainState::timing, and UpdateActiveSnapshotCommandId().

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

{
    DestReceiver *dest;
    QueryDesc  *queryDesc;
    instr_time  starttime;
    double      totaltime = 0;
    int         eflags;
    int         instrument_option = 0;

    if (es->analyze && es->timing)
        instrument_option |= INSTRUMENT_TIMER;
    else if (es->analyze)
        instrument_option |= INSTRUMENT_ROWS;

    if (es->buffers)
        instrument_option |= INSTRUMENT_BUFFERS;

    INSTR_TIME_SET_CURRENT(starttime);

    /*
     * Use a snapshot with an updated command ID to ensure this query sees
     * results of any previously executed queries.
     */
    PushCopiedSnapshot(GetActiveSnapshot());
    UpdateActiveSnapshotCommandId();

    /*
     * Normally we discard the query's output, but if explaining CREATE TABLE
     * AS, we'd better use the appropriate tuple receiver.
     */
    if (into)
        dest = CreateIntoRelDestReceiver(into);
    else
        dest = None_Receiver;

    /* Create a QueryDesc for the query */
    queryDesc = CreateQueryDesc(plannedstmt, queryString,
                                GetActiveSnapshot(), InvalidSnapshot,
                                dest, params, instrument_option);

    /* Select execution options */
    if (es->analyze)
        eflags = 0;             /* default run-to-completion flags */
    else
        eflags = EXEC_FLAG_EXPLAIN_ONLY;
    if (into)
        eflags |= GetIntoRelEFlags(into);

    /* call ExecutorStart to prepare the plan for execution */
    ExecutorStart(queryDesc, eflags);

    /* Execute the plan for statistics if asked for */
    if (es->analyze)
    {
        ScanDirection dir;

        /* EXPLAIN ANALYZE CREATE TABLE AS WITH NO DATA is weird */
        if (into && into->skipData)
            dir = NoMovementScanDirection;
        else
            dir = ForwardScanDirection;

        /* run the plan */
        ExecutorRun(queryDesc, dir, 0L);

        /* run cleanup too */
        ExecutorFinish(queryDesc);

        /* We can't run ExecutorEnd 'till we're done printing the stats... */
        totaltime += elapsed_time(&starttime);
    }

    ExplainOpenGroup("Query", NULL, true, es);

    /* Create textual dump of plan tree */
    ExplainPrintPlan(es, queryDesc);

    /* Print info about runtime of triggers */
    if (es->analyze)
    {
        ResultRelInfo *rInfo;
        bool        show_relname;
        int         numrels = queryDesc->estate->es_num_result_relations;
        List       *targrels = queryDesc->estate->es_trig_target_relations;
        int         nr;
        ListCell   *l;

        ExplainOpenGroup("Triggers", "Triggers", false, es);

        show_relname = (numrels > 1 || targrels != NIL);
        rInfo = queryDesc->estate->es_result_relations;
        for (nr = 0; nr < numrels; rInfo++, nr++)
            report_triggers(rInfo, show_relname, es);

        foreach(l, targrels)
        {
            rInfo = (ResultRelInfo *) lfirst(l);
            report_triggers(rInfo, show_relname, es);
        }

        ExplainCloseGroup("Triggers", "Triggers", false, es);
    }

    /*
     * Close down the query and free resources.  Include time for this in the
     * total runtime (although it should be pretty minimal).
     */
    INSTR_TIME_SET_CURRENT(starttime);

    ExecutorEnd(queryDesc);

    FreeQueryDesc(queryDesc);

    PopActiveSnapshot();

    /* We need a CCI just in case query expanded to multiple plans */
    if (es->analyze)
        CommandCounterIncrement();

    totaltime += elapsed_time(&starttime);

    if (es->analyze)
    {
        if (es->format == EXPLAIN_FORMAT_TEXT)
            appendStringInfo(es->str, "Total runtime: %.3f ms\n",
                             1000.0 * totaltime);
        else
            ExplainPropertyFloat("Total Runtime", 1000.0 * totaltime,
                                 3, es);
    }

    ExplainCloseGroup("Query", NULL, true, es);
}

void ExplainOneUtility ( Node utilityStmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params 
)

Definition at line 339 of file explain.c.

References appendStringInfoString(), Assert, copyObject(), EXPLAIN_FORMAT_TEXT, ExplainDummyGroup(), ExplainExecuteQuery(), ExplainOneQuery(), ExplainState::format, CreateTableAsStmt::into, IsA, linitial, list_length(), NULL, CreateTableAsStmt::query, QueryRewrite(), and ExplainState::str.

Referenced by ExplainExecuteQuery(), and ExplainOneQuery().

{
    if (utilityStmt == NULL)
        return;

    if (IsA(utilityStmt, CreateTableAsStmt))
    {
        /*
         * We have to rewrite the contained SELECT and then pass it back to
         * ExplainOneQuery.  It's probably not really necessary to copy the
         * contained parsetree another time, but let's be safe.
         */
        CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
        List       *rewritten;

        Assert(IsA(ctas->query, Query));
        rewritten = QueryRewrite((Query *) copyObject(ctas->query));
        Assert(list_length(rewritten) == 1);
        ExplainOneQuery((Query *) linitial(rewritten), ctas->into, es,
                        queryString, params);
    }
    else if (IsA(utilityStmt, ExecuteStmt))
        ExplainExecuteQuery((ExecuteStmt *) utilityStmt, into, es,
                            queryString, params);
    else if (IsA(utilityStmt, NotifyStmt))
    {
        if (es->format == EXPLAIN_FORMAT_TEXT)
            appendStringInfoString(es->str, "NOTIFY\n");
        else
            ExplainDummyGroup("Notify", NULL, es);
    }
    else
    {
        if (es->format == EXPLAIN_FORMAT_TEXT)
            appendStringInfoString(es->str,
                              "Utility statements have no plan structure\n");
        else
            ExplainDummyGroup("Utility Statement", NULL, es);
    }
}

void ExplainPrintPlan ( ExplainState es,
QueryDesc queryDesc 
)
void ExplainPropertyFloat ( const char *  qlabel,
double  value,
int  ndigits,
ExplainState es 
)

Definition at line 2285 of file explain.c.

References buf, ExplainProperty(), and snprintf().

Referenced by ExplainNode(), ExplainOnePlan(), report_triggers(), and show_instrumentation_count().

{
    char        buf[256];

    snprintf(buf, sizeof(buf), "%.*f", ndigits, value);
    ExplainProperty(qlabel, buf, true, es);
}

void ExplainPropertyInteger ( const char *  qlabel,
int  value,
ExplainState es 
)

Definition at line 2260 of file explain.c.

References buf, ExplainProperty(), and snprintf().

Referenced by ExplainNode().

{
    char        buf[32];

    snprintf(buf, sizeof(buf), "%d", value);
    ExplainProperty(qlabel, buf, true, es);
}

void ExplainPropertyList ( const char *  qlabel,
List data,
ExplainState es 
)

Definition at line 2126 of file explain.c.

References appendStringInfo(), appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoString(), escape_json(), escape_xml(), escape_yaml(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainJSONLineEnding(), ExplainXMLTag(), ExplainYAMLLineStarting(), ExplainState::format, ExplainState::indent, lfirst, pfree(), ExplainState::str, X_CLOSING, and X_OPENING.

Referenced by show_plan_tlist(), and show_sort_keys_common().

{
    ListCell   *lc;
    bool        first = true;

    switch (es->format)
    {
        case EXPLAIN_FORMAT_TEXT:
            appendStringInfoSpaces(es->str, es->indent * 2);
            appendStringInfo(es->str, "%s: ", qlabel);
            foreach(lc, data)
            {
                if (!first)
                    appendStringInfoString(es->str, ", ");
                appendStringInfoString(es->str, (const char *) lfirst(lc));
                first = false;
            }
            appendStringInfoChar(es->str, '\n');
            break;

        case EXPLAIN_FORMAT_XML:
            ExplainXMLTag(qlabel, X_OPENING, es);
            foreach(lc, data)
            {
                char       *str;

                appendStringInfoSpaces(es->str, es->indent * 2 + 2);
                appendStringInfoString(es->str, "<Item>");
                str = escape_xml((const char *) lfirst(lc));
                appendStringInfoString(es->str, str);
                pfree(str);
                appendStringInfoString(es->str, "</Item>\n");
            }
            ExplainXMLTag(qlabel, X_CLOSING, es);
            break;

        case EXPLAIN_FORMAT_JSON:
            ExplainJSONLineEnding(es);
            appendStringInfoSpaces(es->str, es->indent * 2);
            escape_json(es->str, qlabel);
            appendStringInfoString(es->str, ": [");
            foreach(lc, data)
            {
                if (!first)
                    appendStringInfoString(es->str, ", ");
                escape_json(es->str, (const char *) lfirst(lc));
                first = false;
            }
            appendStringInfoChar(es->str, ']');
            break;

        case EXPLAIN_FORMAT_YAML:
            ExplainYAMLLineStarting(es);
            appendStringInfo(es->str, "%s: ", qlabel);
            foreach(lc, data)
            {
                appendStringInfoChar(es->str, '\n');
                appendStringInfoSpaces(es->str, es->indent * 2 + 2);
                appendStringInfoString(es->str, "- ");
                escape_yaml(es->str, (const char *) lfirst(lc));
            }
            break;
    }
}

void ExplainPropertyLong ( const char *  qlabel,
long  value,
ExplainState es 
)

Definition at line 2272 of file explain.c.

References buf, ExplainProperty(), and snprintf().

Referenced by ExplainNode(), fileExplainForeignScan(), show_hash_info(), and show_sort_info().

{
    char        buf[32];

    snprintf(buf, sizeof(buf), "%ld", value);
    ExplainProperty(qlabel, buf, true, es);
}

void ExplainPropertyText ( const char *  qlabel,
const char *  value,
ExplainState es 
)
void ExplainQuery ( ExplainStmt stmt,
const char *  queryString,
ParamListInfo  params,
DestReceiver dest 
)

Definition at line 118 of file explain.c.

References ExplainState::analyze, appendStringInfoString(), Assert, begin_tup_output_tupdesc(), ExplainState::buffers, copyObject(), ExplainState::costs, StringInfoData::data, defGetBoolean(), defGetString(), DefElem::defname, do_text_output_multiline(), do_text_output_oneline, end_tup_output(), ereport, errcode(), errmsg(), ERROR, EXPLAIN_FORMAT_TEXT, ExplainBeginOutput(), ExplainEndOutput(), ExplainInitState(), ExplainOneQuery(), ExplainResultDesc(), ExplainSeparatePlans(), ExplainState::format, ExplainState::indent, IsA, lfirst, lnext, NIL, NULL, ExplainStmt::options, pfree(), ExplainStmt::query, QueryRewrite(), ExplainState::str, ExplainState::timing, and ExplainState::verbose.

Referenced by standard_ProcessUtility().

{
    ExplainState es;
    TupOutputState *tstate;
    List       *rewritten;
    ListCell   *lc;
    bool        timing_set = false;

    /* Initialize ExplainState. */
    ExplainInitState(&es);

    /* Parse options list. */
    foreach(lc, stmt->options)
    {
        DefElem    *opt = (DefElem *) lfirst(lc);

        if (strcmp(opt->defname, "analyze") == 0)
            es.analyze = defGetBoolean(opt);
        else if (strcmp(opt->defname, "verbose") == 0)
            es.verbose = defGetBoolean(opt);
        else if (strcmp(opt->defname, "costs") == 0)
            es.costs = defGetBoolean(opt);
        else if (strcmp(opt->defname, "buffers") == 0)
            es.buffers = defGetBoolean(opt);
        else if (strcmp(opt->defname, "timing") == 0)
        {
            timing_set = true;
            es.timing = defGetBoolean(opt);
        }
        else if (strcmp(opt->defname, "format") == 0)
        {
            char       *p = defGetString(opt);

            if (strcmp(p, "text") == 0)
                es.format = EXPLAIN_FORMAT_TEXT;
            else if (strcmp(p, "xml") == 0)
                es.format = EXPLAIN_FORMAT_XML;
            else if (strcmp(p, "json") == 0)
                es.format = EXPLAIN_FORMAT_JSON;
            else if (strcmp(p, "yaml") == 0)
                es.format = EXPLAIN_FORMAT_YAML;
            else
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                errmsg("unrecognized value for EXPLAIN option \"%s\": \"%s\"",
                       opt->defname, p)));
        }
        else
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("unrecognized EXPLAIN option \"%s\"",
                            opt->defname)));
    }

    if (es.buffers && !es.analyze)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("EXPLAIN option BUFFERS requires ANALYZE")));

    /* if the timing was not set explicitly, set default value */
    es.timing = (timing_set) ? es.timing : es.analyze;

    /* check that timing is used with EXPLAIN ANALYZE */
    if (es.timing && !es.analyze)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("EXPLAIN option TIMING requires ANALYZE")));

    /*
     * Parse analysis was done already, but we still have to run the rule
     * rewriter.  We do not do AcquireRewriteLocks: we assume the query either
     * came straight from the parser, or suitable locks were acquired by
     * plancache.c.
     *
     * Because the rewriter and planner tend to scribble on the input, we make
     * a preliminary copy of the source querytree.  This prevents problems in
     * the case that the EXPLAIN is in a portal or plpgsql function and is
     * executed repeatedly.  (See also the same hack in DECLARE CURSOR and
     * PREPARE.)  XXX FIXME someday.
     */
    Assert(IsA(stmt->query, Query));
    rewritten = QueryRewrite((Query *) copyObject(stmt->query));

    /* emit opening boilerplate */
    ExplainBeginOutput(&es);

    if (rewritten == NIL)
    {
        /*
         * In the case of an INSTEAD NOTHING, tell at least that.  But in
         * non-text format, the output is delimited, so this isn't necessary.
         */
        if (es.format == EXPLAIN_FORMAT_TEXT)
            appendStringInfoString(es.str, "Query rewrites to nothing\n");
    }
    else
    {
        ListCell   *l;

        /* Explain every plan */
        foreach(l, rewritten)
        {
            ExplainOneQuery((Query *) lfirst(l), NULL, &es,
                            queryString, params);

            /* Separate plans with an appropriate separator */
            if (lnext(l) != NULL)
                ExplainSeparatePlans(&es);
        }
    }

    /* emit closing boilerplate */
    ExplainEndOutput(&es);
    Assert(es.indent == 0);

    /* output tuples */
    tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
    if (es.format == EXPLAIN_FORMAT_TEXT)
        do_text_output_multiline(tstate, es.str->data);
    else
        do_text_output_oneline(tstate, es.str->data);
    end_tup_output(tstate);

    pfree(es.str->data);
}

void ExplainQueryText ( ExplainState es,
QueryDesc queryDesc 
)

Definition at line 566 of file explain.c.

References ExplainPropertyText(), and QueryDesc::sourceText.

Referenced by explain_ExecutorEnd().

{
    if (queryDesc->sourceText)
        ExplainPropertyText("Query Text", queryDesc->sourceText, es);
}

TupleDesc ExplainResultDesc ( ExplainStmt stmt  ) 

Definition at line 263 of file explain.c.

References CreateTemplateTupleDesc(), defGetString(), DefElem::defname, lfirst, ExplainStmt::options, and TupleDescInitEntry().

Referenced by ExplainQuery(), and UtilityTupleDescriptor().

{
    TupleDesc   tupdesc;
    ListCell   *lc;
    Oid         result_type = TEXTOID;

    /* Check for XML format option */
    foreach(lc, stmt->options)
    {
        DefElem    *opt = (DefElem *) lfirst(lc);

        if (strcmp(opt->defname, "format") == 0)
        {
            char       *p = defGetString(opt);

            if (strcmp(p, "xml") == 0)
                result_type = XMLOID;
            else if (strcmp(p, "json") == 0)
                result_type = JSONOID;
            else
                result_type = TEXTOID;
            /* don't "break", as ExplainQuery will use the last value */
        }
    }

    /* Need a tuple descriptor representing a single TEXT or XML column */
    tupdesc = CreateTemplateTupleDesc(1, false);
    TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
                       result_type, -1, 0);
    return tupdesc;
}

void ExplainSeparatePlans ( ExplainState es  ) 

Definition at line 2509 of file explain.c.

References appendStringInfoChar(), EXPLAIN_FORMAT_JSON, EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, EXPLAIN_FORMAT_YAML, ExplainState::format, and ExplainState::str.

Referenced by ExplainExecuteQuery(), and ExplainQuery().

{
    switch (es->format)
    {
        case EXPLAIN_FORMAT_TEXT:
            /* add a blank line */
            appendStringInfoChar(es->str, '\n');
            break;

        case EXPLAIN_FORMAT_XML:
        case EXPLAIN_FORMAT_JSON:
        case EXPLAIN_FORMAT_YAML:
            /* nothing to do */
            break;
    }
}


Variable Documentation

Definition at line 40 of file explain.c.

Referenced by explain_get_index_name().

Definition at line 37 of file explain.c.

Referenced by ExplainOneQuery().