/*
* Get client-supplied query string. Addtion to that the jumbled query is
* supplied if the caller requested. From the restriction of JumbleQuery, some
- * kind of query needs special amendments. Reutrns NULL if the current hint
- * string is still valid.
+ * kind of query needs special amendments. Reutrns NULL if this query doesn't
+ * change the current hint. This function returns NULL also when something
+ * wrong has happend and let the caller continue using the current hints.
*/
static const char *
get_query_string(ParseState *pstate, Query *query, Query **jumblequery)
if (query->commandType == CMD_UTILITY)
{
- Query *target_query = query;
+ Query *target_query = (Query *)query->utilityStmt;
- /* Use the target query if EXPLAIN */
- if (IsA(query->utilityStmt, ExplainStmt))
+ /*
+ * Some CMD_UTILITY statements have a subquery that we can hint on.
+ * Since EXPLAIN can be placed before other kind of utility statements
+ * and EXECUTE can be contained other kind of utility statements, these
+ * conditions are not mutually exclusive and should be considered in
+ * this order.
+ */
+ if (IsA(target_query, ExplainStmt))
{
- ExplainStmt *stmt = (ExplainStmt *)(query->utilityStmt);
-
+ ExplainStmt *stmt = (ExplainStmt *)target_query;
+
Assert(IsA(stmt->query, Query));
target_query = (Query *)stmt->query;
target_query = (Query *)target_query->utilityStmt;
}
+ if (IsA(target_query, DeclareCursorStmt))
+ {
+ DeclareCursorStmt *stmt = (DeclareCursorStmt *)target_query;
+ Query *query = (Query *)stmt->query;
+
+ /* the target must be CMD_SELECT in this case */
+ Assert(IsA(query, Query) && query->commandType == CMD_SELECT);
+ target_query = query;
+ }
+
if (IsA(target_query, CreateTableAsStmt))
{
- /*
- * Use the the body query for CREATE AS. The Query for jumble also
- * replaced with the corresponding one.
- */
CreateTableAsStmt *stmt = (CreateTableAsStmt *) target_query;
- PreparedStatement *entry;
- Query *tmp_query;
Assert(IsA(stmt->query, Query));
- tmp_query = (Query *) stmt->query;
+ target_query = (Query *) stmt->query;
- if (tmp_query->commandType == CMD_UTILITY &&
- IsA(tmp_query->utilityStmt, ExecuteStmt))
- {
- ExecuteStmt *estmt = (ExecuteStmt *) tmp_query->utilityStmt;
- entry = FetchPreparedStatement(estmt->name, true);
- p = entry->plansource->query_string;
- target_query = (Query *) linitial (entry->plansource->query_list);
- }
+ /* strip out the top-level query for further processing */
+ if (target_query->commandType == CMD_UTILITY &&
+ target_query->utilityStmt != NULL)
+ target_query = (Query *)target_query->utilityStmt;
}
- else
+
if (IsA(target_query, ExecuteStmt))
{
/*
- * Use the prepared query for EXECUTE. The Query for jumble also
- * replaced with the corresponding one.
+ * Use the prepared query for EXECUTE. The Query for jumble
+ * also replaced with the corresponding one.
*/
ExecuteStmt *stmt = (ExecuteStmt *)target_query;
PreparedStatement *entry;
p = entry->plansource->query_string;
target_query = (Query *) linitial (entry->plansource->query_list);
}
-
- /* We don't accept other than a Query other than a CMD_UTILITY */
+
+ /* JumbleQuery accespts only a non-utility Query */
if (!IsA(target_query, Query) ||
- target_query->commandType == CMD_UTILITY)
+ target_query->utilityStmt != NULL)
target_query = NULL;
if (jumblequery)
}
}
- /* retrun if we have hint here*/
+ /* retrun if we have hint here */
if (current_hint_str)
return;
}
return;
/* Here, we regenerate paths with the current hint restriction */
-
- if (found_hints & HINT_BM_SCAN_METHOD)
+ if (found_hints & HINT_BM_SCAN_METHOD || found_hints & HINT_BM_PARALLEL)
{
- /*
- * With scan hints, we regenerate paths for this relation from the
- * first under the restricion.
- */
+ /* Just discard all the paths considered so far */
list_free_deep(rel->pathlist);
rel->pathlist = NIL;
- set_plain_rel_pathlist(root, rel, rte);
- }
-
- if (found_hints & HINT_BM_PARALLEL)
- {
- Assert (phint);
-
- /* the partial_pathlist may be for different parameters, discard it */
- if (rel->partial_pathlist)
+ /* Remove all the partial paths if Parallel hint is specfied */
+ if ((found_hints & HINT_BM_PARALLEL) && rel->partial_pathlist)
{
list_free_deep(rel->partial_pathlist);
rel->partial_pathlist = NIL;
}
- /* also remove gather path */
- if (rel->pathlist)
- {
- ListCell *cell, *prev = NULL, *next;
-
- for (cell = list_head(rel->pathlist) ; cell; cell = next)
- {
- Path *path = (Path *) lfirst(cell);
-
- next = lnext(cell);
- if (IsA(path, GatherPath))
- rel->pathlist = list_delete_cell(rel->pathlist,
- cell, prev);
- else
- prev = cell;
- }
- }
+ /* Regenerate paths with the current enforcement */
+ set_plain_rel_pathlist(root, rel, rte);
- /* then generate new paths if needed */
- if (phint->nworkers > 0)
+ /* Additional work to enforce parallel query execution */
+ if (phint && phint->nworkers > 0)
{
/* Lower the priorities of non-parallel paths */
foreach (l, rel->pathlist)
}
}
- /*
- * generate partial paths with enforcement, this is affected by
- * scan method enforcement. Specifically, the cost of this partial
- * seqscan path will be disabled_cost if seqscan is inhibited by
- * hint or GUC parameters.
- */
- Assert (rel->partial_pathlist == NIL);
- create_plain_partial_paths(root, rel);
-
/* enforce number of workers if requested */
if (phint->force_parallel)
{