+ * Force number of wokers if instructed by hint
+ */
+void
+pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
+ Index rti, RangeTblEntry *rte)
+{
+ ParallelHint *phint;
+ ListCell *l;
+ int found_hints;
+
+ /* call the previous hook */
+ if (prev_set_rel_pathlist)
+ prev_set_rel_pathlist(root, rel, rti, rte);
+
+ /* Nothing to do if no hint available */
+ if (current_hint_state == NULL)
+ return;
+
+ /* Don't touch dummy rels. */
+ if (IS_DUMMY_REL(rel))
+ return;
+
+ /*
+ * We can accept only plain relations, foreign tables and table saples are
+ * also unacceptable. See set_rel_pathlist.
+ */
+ if ((rel->rtekind != RTE_RELATION &&
+ rel->rtekind != RTE_SUBQUERY)||
+ rte->relkind == RELKIND_FOREIGN_TABLE ||
+ rte->tablesample != NULL)
+ return;
+
+ /*
+ * Even though UNION ALL node doesn't have particular name so usually it is
+ * unhintable, turn on parallel when it contains parallel nodes.
+ */
+ if (rel->rtekind == RTE_SUBQUERY)
+ {
+ ListCell *lc;
+ bool inhibit_nonparallel = false;
+
+ if (rel->partial_pathlist == NIL)
+ return;
+
+ foreach(lc, rel->partial_pathlist)
+ {
+ ListCell *lcp;
+ AppendPath *apath = (AppendPath *) lfirst(lc);
+ int parallel_workers = 0;
+
+ if (!IsA(apath, AppendPath))
+ continue;
+
+ foreach (lcp, apath->subpaths)
+ {
+ Path *spath = (Path *) lfirst(lcp);
+
+ if (spath->parallel_aware &&
+ parallel_workers < spath->parallel_workers)
+ parallel_workers = spath->parallel_workers;
+ }
+
+ apath->path.parallel_workers = parallel_workers;
+ inhibit_nonparallel = true;
+ }
+
+ if (inhibit_nonparallel)
+ {
+ ListCell *lc;
+
+ foreach(lc, rel->pathlist)
+ {
+ Path *path = (Path *) lfirst(lc);
+
+ if (path->startup_cost < disable_cost)
+ {
+ path->startup_cost += disable_cost;
+ path->total_cost += disable_cost;
+ }
+ }
+ }
+
+ return;
+ }
+
+ /* We cannot handle if this requires an outer */
+ if (rel->lateral_relids)
+ return;
+
+ /* Return if this relation gets no enfocement */
+ if ((found_hints = setup_hint_enforcement(root, rel, NULL, &phint)) == 0)
+ return;
+
+ /* Here, we regenerate paths with the current hint restriction */
+ if (found_hints & HINT_BM_SCAN_METHOD || found_hints & HINT_BM_PARALLEL)
+ {
+ /*
+ * When hint is specified on non-parent relations, discard existing
+ * paths and regenerate based on the hint considered. Otherwise we
+ * already have hinted childx paths then just adjust the number of
+ * planned number of workers.
+ */
+ if (root->simple_rte_array[rel->relid]->inh)
+ {
+ /* enforce number of workers if requested */
+ if (phint && phint->force_parallel)
+ {
+ if (phint->nworkers == 0)
+ {
+ list_free_deep(rel->partial_pathlist);
+ rel->partial_pathlist = NIL;
+ }
+ else
+ {
+ /* prioritize partial paths */
+ foreach (l, rel->partial_pathlist)
+ {
+ Path *ppath = (Path *) lfirst(l);
+
+ if (ppath->parallel_safe)
+ {
+ ppath->parallel_workers = phint->nworkers;
+ ppath->startup_cost = 0;
+ ppath->total_cost = 0;
+ }
+ }
+
+ /* disable non-partial paths */
+ foreach (l, rel->pathlist)
+ {
+ Path *ppath = (Path *) lfirst(l);
+
+ if (ppath->startup_cost < disable_cost)
+ {
+ ppath->startup_cost += disable_cost;
+ ppath->total_cost += disable_cost;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Just discard all the paths considered so far */
+ list_free_deep(rel->pathlist);
+ rel->pathlist = NIL;
+ list_free_deep(rel->partial_pathlist);
+ rel->partial_pathlist = NIL;
+
+ /* Regenerate paths with the current enforcement */
+ set_plain_rel_pathlist(root, rel, rte);
+
+ /* Additional work to enforce parallel query execution */
+ if (phint && phint->nworkers > 0)
+ {
+ /*
+ * For Parallel Append to be planned properly, we shouldn't set
+ * the costs of non-partial paths to disable-value. Lower the
+ * priority of non-parallel paths by setting partial path costs
+ * to 0 instead.
+ */
+ foreach (l, rel->partial_pathlist)
+ {
+ Path *path = (Path *) lfirst(l);
+
+ path->startup_cost = 0;
+ path->total_cost = 0;
+ }
+
+ /* enforce number of workers if requested */
+ if (phint->force_parallel)
+ {
+ foreach (l, rel->partial_pathlist)
+ {
+ Path *ppath = (Path *) lfirst(l);
+
+ if (ppath->parallel_safe)
+ ppath->parallel_workers = phint->nworkers;
+ }
+ }
+
+ /* Generate gather paths */
+ if (rel->reloptkind == RELOPT_BASEREL &&
+ bms_membership(root->all_baserels) != BMS_SINGLETON)
+ generate_gather_paths(root, rel, false);
+ }
+ }
+ }
+
+ reset_hint_enforcement();
+}
+
+/*