pg_explaintips.tgz
application/x-compressed-tar
Filename: pg_explaintips.tgz
Type: application/x-compressed-tar
Part: 0
Message:
Re: making EXPLAIN extensible
pg_explaintips/ 0000755 0001750 0001750 00000000000 14761367265 014657 5 ustar guillaume guillaume pg_explaintips/meson.build 0000644 0001750 0001750 00000000741 14761367255 017022 0 ustar guillaume guillaume # Copyright (c) 2022-2025, PostgreSQL Global Development Group
pg_overexplain_sources = files(
'pg_overexplain.c',
)
if host_system == 'windows'
pg_overexplain_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
'--NAME', 'pg_overexplain',
'--FILEDESC', 'pg_overexplain - allow EXPLAIN to dump even more details',])
endif
pg_overexplain = shared_module('pg_overexplain',
pg_overexplain_sources,
kwargs: contrib_mod_args,
)
contrib_targets += pg_overexplain
pg_explaintips/.gitignore 0000644 0001750 0001750 00000000067 14761367255 016651 0 ustar guillaume guillaume # Generated subdirectories
/log/
/results/
/tmp_check/
pg_explaintips/Makefile 0000644 0001750 0001750 00000000625 14761367255 016321 0 ustar guillaume guillaume # contrib/pg_explaintips/Makefile
MODULE_big = pg_explaintips
OBJS = \
$(WIN32RES) \
pg_explaintips.o
PGFILEDESC = "pg_explaintips - add tips to EXPLAIN"
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/pg_explaintips
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
pg_explaintips/pg_explaintips.c 0000644 0001750 0001750 00000006655 14761367255 020064 0 ustar guillaume guillaume /*-------------------------------------------------------------------------
*
* pg_explaintips.c
* allow EXPLAIN to dump even more details
*
* Copyright (c) 2016-2025, PostgreSQL Global Development Group
*
* contrib/pg_explaintips/pg_explaintips.c
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_class.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/explain_format.h"
#include "commands/explain_state.h"
#include "fmgr.h"
#include "parser/parsetree.h"
#include "storage/lock.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
PG_MODULE_MAGIC;
typedef struct
{
bool tips;
} explaintips_options;
static explaintips_options *explaintips_ensure_options(ExplainState *es);
static void explaintips_handler(ExplainState *, DefElem *, ParseState *);
static void explaintips_per_node_hook(PlanState *planstate, List *ancestors,
const char *relationship,
const char *plan_name,
ExplainState *es);
static int es_extension_id;
static explain_per_node_hook_type prev_explain_per_node_hook;
/*
* Initialization we do when this module is loaded.
*/
void
_PG_init(void)
{
/* Get an ID that we can use to cache data in an ExplainState. */
es_extension_id = GetExplainExtensionId("pg_explaintips");
/* Register the new EXPLAIN options implemented by this module. */
RegisterExtensionExplainOption("tips", explaintips_handler);
/* Use the per-node and per-plan hooks to make our options do something. */
prev_explain_per_node_hook = explain_per_node_hook;
explain_per_node_hook = explaintips_per_node_hook;
}
/*
* Get the explaintips_options structure from an ExplainState; if there is
* none, create one, attach it to the ExplainState, and return it.
*/
static explaintips_options *
explaintips_ensure_options(ExplainState *es)
{
explaintips_options *options;
options = GetExplainExtensionState(es, es_extension_id);
if (options == NULL)
{
options = palloc0(sizeof(explaintips_options));
SetExplainExtensionState(es, es_extension_id, options);
}
return options;
}
/*
* Parse handler for EXPLAIN (DEBUG).
*/
static void
explaintips_handler(ExplainState *es, DefElem *opt, ParseState *pstate)
{
explaintips_options *options = explaintips_ensure_options(es);
options->tips = defGetBoolean(opt);
}
/*
* Print out additional per-node information as appropriate. If the user didn't
* specify any of the options we support, do nothing; else, print whatever is
* relevant to the specified options.
*/
static void
explaintips_per_node_hook(PlanState *planstate, List *ancestors,
const char *relationship, const char *plan_name,
ExplainState *es)
{
StringInfoData flags;
explaintips_options *options;
Plan *plan = planstate->plan;
options = GetExplainExtensionState(es, es_extension_id);
if (options == NULL)
return;
/*
* If the "debug" option was given, display miscellaneous fields from the
* "Plan" node that would not otherwise be displayed.
*/
if (options->tips)
{
/* if seqscan and filteredrows/totalsrows>70) --> tips */
if (nodeTag(plan) == T_SeqScan)
{
double rows = planstate->instrument->ntuples;
double nfiltered = planstate->instrument->nfiltered1;
if (100*nfiltered/(nfiltered+rows) > 70)
{
initStringInfo(&flags);
appendStringInfo(&flags, "You should probably add an index!");
ExplainPropertyText("Tips", flags.data, es);
}
}
}
}