return pgpa_dsa_area;
}
+/*
+ * Was the PLAN_ADVICE option specified and not set to false?
+ */
+bool
+pg_plan_advice_should_explain(ExplainState *es)
+{
+ bool *plan_advice = NULL;
+
+ if (es != NULL)
+ plan_advice = GetExplainExtensionState(es, es_extension_id);
+ return plan_advice != NULL && *plan_advice;
+}
+
/*
* Handler for EXPLAIN (PLAN_ADVICE).
*/
ParamListInfo params,
QueryEnvironment *queryEnv)
{
- bool *plan_advice = GetExplainExtensionState(es, es_extension_id);
+ bool should_explain;
DefElem *pgpa_item;
List *pgpa_list;
prev_explain_per_plan(plannedstmt, into, es, queryString, params,
queryEnv);
+ /* Should an advice string be part of the EXPLAIN output? */
+ should_explain = pg_plan_advice_should_explain(es);
+
/* Find any data pgpa_planner_shutdown stashed in the PlannedStmt. */
pgpa_item = find_defelem_by_defname(plannedstmt->extension_state,
"pg_plan_advice");
* recorded, and therefore this won't be able to show anything.
*/
if (pgpa_list != NULL && (pg_plan_advice_always_explain_supplied_advice ||
- (plan_advice != NULL && *plan_advice)))
+ should_explain))
{
DefElem *feedback;
* If the PLAN_ADVICE option was specified -- and not sent to FALSE --
* show generated advice.
*/
- if (plan_advice != NULL && *plan_advice)
+ if (should_explain)
{
DefElem *advice_string_item;
- char *advice_string;
+ char *advice_string = NULL;
advice_string_item =
find_defelem_by_defname(pgpa_list, "advice_string");
/* Advice has already been generated; we can reuse it. */
advice_string = strVal(advice_string_item->arg);
}
- else
- {
- pgpa_plan_walker_context walker;
- StringInfoData buf;
- pgpa_identifier *rt_identifiers;
-
- /* Advice not yet generated; do that now. */
- pgpa_plan_walker(&walker, plannedstmt);
- rt_identifiers =
- pgpa_create_identifiers_for_planned_stmt(plannedstmt);
- initStringInfo(&buf);
- pgpa_output_advice(&buf, &walker, rt_identifiers);
- advice_string = buf.data;
- }
-
- if (advice_string[0] != '\0')
+ if (advice_string != NULL && advice_string[0] != '\0')
pg_plan_advice_explain_text_multiline(es, "Generated Plan Advice",
advice_string);
}
typedef struct pgpa_planner_state
{
ExplainState *explain_state;
+ bool generate_advice_string;
pgpa_trove *trove;
MemoryContext trove_cxt;
}
/*
- * Prepare advice for use by a query.
+ * Carry out whatever setup work we need to do before planning.
*/
static void
pgpa_planner_setup(PlannerGlobal *glob, Query *parse, const char *query_string,
{
pgpa_trove *trove = NULL;
pgpa_planner_state *pps;
+ bool generate_advice_string = false;
bool needs_pps = false;
+ /*
+ * Decide whether we need to generate an advice string. We must do this if
+ * at least one collector is enabled or if the user has requested it using
+ * the EXPLAIN (PLAN_ADVICE) option.
+ */
+ generate_advice_string = (pg_plan_advice_local_collection_limit > 0 ||
+ pg_plan_advice_shared_collection_limit > 0 ||
+ pg_plan_advice_should_explain(es));
+ if (generate_advice_string)
+ needs_pps = true;
+
/*
* If any advice was provided, build a trove of advice for use during
* planning.
needs_pps = true;
#endif
- /* Initialize and store private state, if required. */
+ /*
+ * We only create and initialize a private state object if it's needed for
+ * some purpose. That could be (1) recording that we will need to generate
+ * an advice string, (2) storing a trove of supplied advice, or (3)
+ * facilitating debugging cross-checks when asserts are enabled.
+ */
if (needs_pps)
{
pps = palloc0_object(pgpa_planner_state);
pps->explain_state = es;
+ pps->generate_advice_string = generate_advice_string;
pps->trove = trove;
#ifdef USE_ASSERT_CHECKING
pps->ri_check_hash =
ExplainState *es = NULL;
pgpa_plan_walker_context walker = {0}; /* placate compiler */
bool do_advice_feedback;
- bool do_collect_advice;
+ bool generate_advice_string = false;
List *pgpa_items = NIL;
pgpa_identifier *rt_identifiers = NULL;
{
trove = pps->trove;
es = pps->explain_state;
+ generate_advice_string = pps->generate_advice_string;
}
- /* If at least one collector is enabled, generate advice. */
- do_collect_advice = (pg_plan_advice_local_collection_limit > 0 ||
- pg_plan_advice_shared_collection_limit > 0);
-
- /* If we applied advice, generate feedback. */
+ /*
+ * If any advice was specified, and if we're running under EXPLAIN, then
+ * we should try try to provide advice feedback.
+ *
+ * If we're trying to generate an advice string or if we're trying to
+ * provide advice feedback, then we will need to create range table
+ * identifiers.
+ */
do_advice_feedback = (trove != NULL && es != NULL);
-
- /* If either of the above apply, analyze the resulting PlannedStmt. */
- if (do_collect_advice || do_advice_feedback)
+ if (generate_advice_string || do_advice_feedback)
{
pgpa_plan_walker(&walker, pstmt);
rt_identifiers = pgpa_create_identifiers_for_planned_stmt(pstmt);
}
- /*
- * If advice collection is enabled, put the advice in string form and send
- * it to the collector.
- */
- if (do_collect_advice)
+ /* Generate the advice string, if we need to do so. */
+ if (generate_advice_string)
{
char *advice_string;
StringInfoData buf;