1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-15 05:46:52 +03:00

Add ExplainState argument to pg_plan_query() and planner().

This allows extensions to have access to any data they've stored
in the ExplainState during planning. Unfortunately, it won't help
with EXPLAIN EXECUTE is used, but since that case is less common,
this still seems like an improvement.

Since planner() has quite a few arguments now, also add some
documentation of those arguments and the return value.

Author: Robert Haas <rhaas@postgresql.org>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrei Lepikhov <lepihov@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: http://postgr.es/m/CA+TgmoYWKHU2hKr62Toyzh-kTDEnMDeLw7gkOOnjL-TnOUq0kQ@mail.gmail.com
This commit is contained in:
Robert Haas
2025-10-08 08:33:29 -04:00
parent 8e11859102
commit c83ac02ec7
12 changed files with 58 additions and 25 deletions

View File

@@ -338,7 +338,8 @@ static void pgss_post_parse_analyze(ParseState *pstate, Query *query,
static PlannedStmt *pgss_planner(Query *parse,
const char *query_string,
int cursorOptions,
ParamListInfo boundParams);
ParamListInfo boundParams,
ExplainState *es);
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
static void pgss_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction,
@@ -894,7 +895,8 @@ static PlannedStmt *
pgss_planner(Query *parse,
const char *query_string,
int cursorOptions,
ParamListInfo boundParams)
ParamListInfo boundParams,
ExplainState *es)
{
PlannedStmt *result;
@@ -929,10 +931,10 @@ pgss_planner(Query *parse,
{
if (prev_planner_hook)
result = prev_planner_hook(parse, query_string, cursorOptions,
boundParams);
boundParams, es);
else
result = standard_planner(parse, query_string, cursorOptions,
boundParams);
boundParams, es);
}
PG_FINALLY();
{
@@ -978,10 +980,10 @@ pgss_planner(Query *parse,
{
if (prev_planner_hook)
result = prev_planner_hook(parse, query_string, cursorOptions,
boundParams);
boundParams, es);
else
result = standard_planner(parse, query_string, cursorOptions,
boundParams);
boundParams, es);
}
PG_FINALLY();
{

View File

@@ -796,7 +796,7 @@ BeginCopyTo(ParseState *pstate,
/* plan the query */
plan = pg_plan_query(query, pstate->p_sourcetext,
CURSOR_OPT_PARALLEL_OK, NULL);
CURSOR_OPT_PARALLEL_OK, NULL, NULL);
/*
* With row-level security and a user using "COPY relation TO", we

View File

@@ -321,7 +321,7 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
/* plan the query */
plan = pg_plan_query(query, pstate->p_sourcetext,
CURSOR_OPT_PARALLEL_OK, params);
CURSOR_OPT_PARALLEL_OK, params, NULL);
/*
* Use a snapshot with an updated command ID to ensure this query sees

View File

@@ -351,7 +351,7 @@ standard_ExplainOneQuery(Query *query, int cursorOptions,
INSTR_TIME_SET_CURRENT(planstart);
/* plan the query */
plan = pg_plan_query(query, queryString, cursorOptions, params);
plan = pg_plan_query(query, queryString, cursorOptions, params, es);
INSTR_TIME_SET_CURRENT(planduration);
INSTR_TIME_SUBTRACT(planduration, planstart);

View File

@@ -426,7 +426,7 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
CHECK_FOR_INTERRUPTS();
/* Plan the query which will generate data for the refresh. */
plan = pg_plan_query(query, queryString, CURSOR_OPT_PARALLEL_OK, NULL);
plan = pg_plan_query(query, queryString, CURSOR_OPT_PARALLEL_OK, NULL, NULL);
/*
* Use a snapshot with an updated command ID to ensure this query sees

View File

@@ -99,7 +99,8 @@ PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo pa
elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
/* Plan the query, applying the specified options */
plan = pg_plan_query(query, pstate->p_sourcetext, cstmt->options, params);
plan = pg_plan_query(query, pstate->p_sourcetext, cstmt->options, params,
NULL);
/*
* Create a portal and copy the plan and query string into its memory.

View File

@@ -279,6 +279,23 @@ static void create_partial_unique_paths(PlannerInfo *root, RelOptInfo *input_rel
*
* Query optimizer entry point
*
* Inputs:
* parse: an analyzed-and-rewritten query tree for an optimizable statement
* query_string: source text for the query tree (used for error reports)
* cursorOptions: bitmask of CURSOR_OPT_XXX flags, see parsenodes.h
* boundParams: passed-in parameter values, or NULL if none
* es: ExplainState if being called from EXPLAIN, else NULL
*
* The result is a PlannedStmt tree.
*
* PARAM_EXTERN Param nodes within the parse tree can be replaced by Consts
* using values from boundParams, if those values are marked PARAM_FLAG_CONST.
* Parameter values not so marked are still relied on for estimation purposes.
*
* The ExplainState pointer is not currently used by the core planner, but it
* is passed through to some planner hooks so that they can report information
* back to EXPLAIN extension hooks.
*
* To support loadable plugins that monitor or modify planner behavior,
* we provide a hook variable that lets a plugin get control before and
* after the standard planning process. The plugin would normally call
@@ -290,14 +307,16 @@ static void create_partial_unique_paths(PlannerInfo *root, RelOptInfo *input_rel
*****************************************************************************/
PlannedStmt *
planner(Query *parse, const char *query_string, int cursorOptions,
ParamListInfo boundParams)
ParamListInfo boundParams, ExplainState *es)
{
PlannedStmt *result;
if (planner_hook)
result = (*planner_hook) (parse, query_string, cursorOptions, boundParams);
result = (*planner_hook) (parse, query_string, cursorOptions,
boundParams, es);
else
result = standard_planner(parse, query_string, cursorOptions, boundParams);
result = standard_planner(parse, query_string, cursorOptions,
boundParams, es);
pgstat_report_plan_id(result->planId, false);
@@ -306,7 +325,7 @@ planner(Query *parse, const char *query_string, int cursorOptions,
PlannedStmt *
standard_planner(Query *parse, const char *query_string, int cursorOptions,
ParamListInfo boundParams)
ParamListInfo boundParams, ExplainState *es)
{
PlannedStmt *result;
PlannerGlobal *glob;

View File

@@ -37,6 +37,7 @@
#include "catalog/pg_type.h"
#include "commands/async.h"
#include "commands/event_trigger.h"
#include "commands/explain_state.h"
#include "commands/prepare.h"
#include "common/pg_prng.h"
#include "jit/jit.h"
@@ -884,7 +885,7 @@ pg_rewrite_query(Query *query)
*/
PlannedStmt *
pg_plan_query(Query *querytree, const char *query_string, int cursorOptions,
ParamListInfo boundParams)
ParamListInfo boundParams, ExplainState *es)
{
PlannedStmt *plan;
@@ -901,7 +902,7 @@ pg_plan_query(Query *querytree, const char *query_string, int cursorOptions,
ResetUsage();
/* call the optimizer */
plan = planner(querytree, query_string, cursorOptions, boundParams);
plan = planner(querytree, query_string, cursorOptions, boundParams, es);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
@@ -997,7 +998,7 @@ pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions,
else
{
stmt = pg_plan_query(query, query_string, cursorOptions,
boundParams);
boundParams, NULL);
}
stmt_list = lappend(stmt_list, stmt);

View File

@@ -24,6 +24,8 @@
#include "nodes/parsenodes.h"
typedef struct ExplainState ExplainState; /* defined in explain_state.h */
/*
* We don't want to include nodes/pathnodes.h here, because non-planner
* code should generally treat PlannerInfo as an opaque typedef.
@@ -104,7 +106,8 @@ extern PGDLLIMPORT bool enable_distinct_reordering;
extern PlannedStmt *planner(Query *parse, const char *query_string,
int cursorOptions,
ParamListInfo boundParams);
ParamListInfo boundParams,
ExplainState *es);
extern Expr *expression_planner(Expr *expr);
extern Expr *expression_planner_with_deps(Expr *expr,

View File

@@ -22,11 +22,14 @@
#include "nodes/plannodes.h"
typedef struct ExplainState ExplainState; /* defined in explain_state.h */
/* Hook for plugins to get control in planner() */
typedef PlannedStmt *(*planner_hook_type) (Query *parse,
const char *query_string,
int cursorOptions,
ParamListInfo boundParams);
ParamListInfo boundParams,
ExplainState *es);
extern PGDLLIMPORT planner_hook_type planner_hook;
/* Hook for plugins to get control when grouping_planner() plans upper rels */
@@ -40,7 +43,8 @@ extern PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook;
extern PlannedStmt *standard_planner(Query *parse, const char *query_string,
int cursorOptions,
ParamListInfo boundParams);
ParamListInfo boundParams,
ExplainState *es);
extern PlannerInfo *subquery_planner(PlannerGlobal *glob, Query *parse,
char *plan_name,

View File

@@ -20,6 +20,7 @@
#include "utils/guc.h"
#include "utils/queryenvironment.h"
typedef struct ExplainState ExplainState; /* defined in explain_state.h */
extern PGDLLIMPORT CommandDest whereToSendOutput;
extern PGDLLIMPORT const char *debug_query_string;
@@ -63,7 +64,8 @@ extern List *pg_analyze_and_rewrite_withcb(RawStmt *parsetree,
QueryEnvironment *queryEnv);
extern PlannedStmt *pg_plan_query(Query *querytree, const char *query_string,
int cursorOptions,
ParamListInfo boundParams);
ParamListInfo boundParams,
ExplainState *es);
extern List *pg_plan_queries(List *querytrees, const char *query_string,
int cursorOptions,
ParamListInfo boundParams);

View File

@@ -40,17 +40,18 @@ static planner_hook_type prev_planner_hook = NULL;
/* planner_hook function to provide the desired delay */
static PlannedStmt *
delay_execution_planner(Query *parse, const char *query_string,
int cursorOptions, ParamListInfo boundParams)
int cursorOptions, ParamListInfo boundParams,
ExplainState *es)
{
PlannedStmt *result;
/* Invoke the planner, possibly via a previous hook user */
if (prev_planner_hook)
result = prev_planner_hook(parse, query_string, cursorOptions,
boundParams);
boundParams, es);
else
result = standard_planner(parse, query_string, cursorOptions,
boundParams);
boundParams, es);
/* If enabled, delay by taking and releasing the specified lock */
if (post_planning_lock_id != 0)