static bool pg_hint_plan_enable_hint_table = false;
static int plpgsql_recurse_level = 0; /* PLpgSQL recursion level */
+static int recurse_level = 0; /* recursion level incl. direct SPI calls */
static int hint_inhibit_level = 0; /* Inhibit hinting if this is above 0 */
/* (This could not be above 1) */
static int max_hint_nworkers = -1; /* Maximum nworkers of Workers hints */
{
ParallelHint *hint;
- hint = palloc(sizeof(ScanMethodHint));
+ hint = palloc(sizeof(ParallelHint));
hint->base.hint_str = hint_str;
hint->base.keyword = keyword;
hint->base.hint_keyword = hint_keyword;
* case of DESCRIBE message handling or EXECUTE command. We may still see a
* candidate top-level query in pstate in the case.
*/
- if (!p && pstate)
+ if (pstate && pstate->p_sourcetext)
p = pstate->p_sourcetext;
/* We don't see a query string, return NULL */
PreparedStatement *entry;
entry = FetchPreparedStatement(stmt->name, true);
- p = entry->plansource->query_string;
- target_query = (Query *) linitial (entry->plansource->query_list);
+
+ if (entry->plansource->is_valid)
+ {
+ p = entry->plansource->query_string;
+ target_query = (Query *) linitial (entry->plansource->query_list);
+ }
+ else
+ {
+ /* igonre the hint for EXECUTE if invalidated */
+ p = NULL;
+ target_query = NULL;
+ }
}
/* JumbleQuery accespts only a non-utility Query */
- if (!IsA(target_query, Query) ||
- target_query->utilityStmt != NULL)
+ if (target_query &&
+ (!IsA(target_query, Query) ||
+ target_query->utilityStmt != NULL))
target_query = NULL;
if (jumblequery)
*/
query_len = strlen(query_str) + 1;
normalized_query =
- generate_normalized_query(&jstate, query_str,
- query->stmt_location,
- &query_len,
+ generate_normalized_query(&jstate, query_str, 0, &query_len,
GetDatabaseEncoding());
/*
current_hint_str = get_hints_from_comment(query_str);
MemoryContextSwitchTo(oldcontext);
}
+ else
+ {
+ /*
+ * Failed to get query. We would be in fetching invalidated
+ * plancache. Try the next chance.
+ */
+ current_hint_retrieved = false;
+ }
if (debug_level > 1)
{
int save_nestlevel;
PlannedStmt *result;
HintState *hstate;
+ const char *prev_hint_str = NULL;
/*
* Use standard planner if pg_hint_plan is disabled or current nesting
* Support for nested plpgsql functions. This is quite ugly but this is the
* only point I could find where I can get the query string.
*/
- if (plpgsql_recurse_level > 0)
+ if (plpgsql_recurse_level > 0 &&
+ error_context_stack && error_context_stack->arg)
{
MemoryContext oldcontext;
- if (current_hint_str)
- pfree((void *)current_hint_str);
-
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
current_hint_str =
get_hints_from_comment((char *)error_context_stack->arg);
}
/*
+ * The planner call below may replace current_hint_str. Store and restore
+ * it so that the subsequent planning in the upper level doesn't get
+ * confused.
+ */
+ recurse_level++;
+ prev_hint_str = current_hint_str;
+ current_hint_str = NULL;
+
+ /*
* Use PG_TRY mechanism to recover GUC parameters and current_hint_state to
* the state when this planner started when error occurred in planner.
*/
result = (*prev_planner) (parse, cursorOptions, boundParams);
else
result = standard_planner(parse, cursorOptions, boundParams);
+
+ current_hint_str = prev_hint_str;
+ recurse_level--;
}
PG_CATCH();
{
* Rollback changes of GUC parameters, and pop current hint context
* from hint stack to rewind the state.
*/
+ current_hint_str = prev_hint_str;
+ recurse_level--;
AtEOXact_GUC(true, save_nestlevel);
pop_hint();
PG_RE_THROW();
/*
* current_hint_str is useless after planning of the top-level query.
*/
- if (plpgsql_recurse_level < 1 && current_hint_str)
+ if (recurse_level < 1 && current_hint_str)
{
pfree((void *)current_hint_str);
current_hint_str = NULL;
return 0;
}
- /* Forget about the parent of another subquery */
- if (root != current_hint_state->current_root)
- current_hint_state->parent_relid = 0;
-
- /* Find the parent for this relation other than the registered parent */
- foreach (l, root->append_rel_list)
+ /*
+ * Forget about the parent of another subquery, but don't forget if the
+ * inhTargetkind of the root is not INHKIND_NONE, which signals the root
+ * contains only appendrel members. See inheritance_planner for details.
+ *
+ * (PG12.0) 428b260f87 added one more planning cycle for updates on
+ * partitioned tables and hints set up in the cycle are overriden by the
+ * second cycle. Since I didn't find no apparent distinction between the
+ * PlannerRoot of the cycle and that of ordinary CMD_SELECT, pg_hint_plan
+ * accepts both cycles and the later one wins. In the second cycle root
+ * doesn't have inheritance information at all so use the parent_relid set
+ * in the first cycle.
+ */
+ if (root->inhTargetKind == INHKIND_NONE)
{
- AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
+ if (root != current_hint_state->current_root)
+ current_hint_state->parent_relid = 0;
- if (appinfo->child_relid == rel->relid)
+ /* Find the parent for this relation other than the registered parent */
+ foreach (l, root->append_rel_list)
{
- if (current_hint_state->parent_relid != appinfo->parent_relid)
+ AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
+
+ if (appinfo->child_relid == rel->relid)
{
- new_parent_relid = appinfo->parent_relid;
- current_hint_state->current_root = root;
+ if (current_hint_state->parent_relid != appinfo->parent_relid)
+ {
+ new_parent_relid = appinfo->parent_relid;
+ current_hint_state->current_root = root;
+ }
+ break;
}
- break;
}
- }
- if (!l)
- {
- /* This relation doesn't have a parent. Cancel current_hint_state. */
- current_hint_state->parent_relid = 0;
- current_hint_state->parent_scan_hint = NULL;
- current_hint_state->parent_parallel_hint = NULL;
+ if (!l)
+ {
+ /*
+ * This relation doesn't have a parent. Cancel
+ * current_hint_state.
+ */
+ current_hint_state->parent_relid = 0;
+ current_hint_state->parent_scan_hint = NULL;
+ current_hint_state->parent_parallel_hint = NULL;
+ }
}
if (new_parent_relid > 0)