+static const char *
+RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse,
+ const char *str)
+{
+ HintKeyword hint_keyword = hint->base.hint_keyword;
+ List *name_list = NIL;
+ char *rows_str;
+ char *end_ptr;
+
+ if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
+ return NULL;
+
+ /* Last element must be rows specification */
+ hint->nrels = list_length(name_list) - 1;
+
+ if (hint->nrels > 0)
+ {
+ ListCell *l;
+ int i = 0;
+
+ /*
+ * Transform relation names from list to array to sort them with qsort
+ * after.
+ */
+ hint->relnames = palloc(sizeof(char *) * hint->nrels);
+ foreach (l, name_list)
+ {
+ if (hint->nrels <= i)
+ break;
+ hint->relnames[i] = lfirst(l);
+ i++;
+ }
+ }
+
+ /* Retieve rows estimation */
+ rows_str = list_nth(name_list, hint->nrels);
+ hint->rows_str = rows_str; /* store as-is for error logging */
+ if (rows_str[0] == '#')
+ {
+ hint->value_type = RVT_ABSOLUTE;
+ rows_str++;
+ }
+ else if (rows_str[0] == '+')
+ {
+ hint->value_type = RVT_ADD;
+ rows_str++;
+ }
+ else if (rows_str[0] == '-')
+ {
+ hint->value_type = RVT_SUB;
+ rows_str++;
+ }
+ else if (rows_str[0] == '*')
+ {
+ hint->value_type = RVT_MULTI;
+ rows_str++;
+ }
+ else
+ {
+ hint_ereport(rows_str, ("Unrecognized rows value type notation."));
+ hint->base.state = HINT_STATE_ERROR;
+ return str;
+ }
+ hint->rows = strtod(rows_str, &end_ptr);
+ if (*end_ptr)
+ {
+ hint_ereport(rows_str,
+ ("%s hint requires valid number as rows estimation.",
+ hint->base.keyword));
+ hint->base.state = HINT_STATE_ERROR;
+ return str;
+ }
+
+ /* A join hint requires at least two relations */
+ if (hint->nrels < 2)
+ {
+ hint_ereport(str,
+ ("%s hint requires at least two relations.",
+ hint->base.keyword));
+ hint->base.state = HINT_STATE_ERROR;
+ return str;
+ }
+
+ list_free(name_list);
+
+ /* Sort relnames in alphabetical order. */
+ qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
+
+ return str;
+}
+
+static const char *
+ParallelHintParse(ParallelHint *hint, HintState *hstate, Query *parse,
+ const char *str)
+{
+ HintKeyword hint_keyword = hint->base.hint_keyword;
+ List *name_list = NIL;
+ int length;
+ char *end_ptr;
+ int nworkers;
+ bool force_parallel = false;
+
+ if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
+ return NULL;
+
+ /* Parse relation name and index name(s) if given hint accepts. */
+ length = list_length(name_list);
+
+ if (length < 2 || length > 3)
+ {
+ hint_ereport(")",
+ ("wrong number of arguments (%d): %s",
+ length, hint->base.keyword));
+ hint->base.state = HINT_STATE_ERROR;
+ return str;
+ }
+
+ hint->relname = linitial(name_list);
+
+ /* The second parameter is number of workers */
+ hint->nworkers_str = list_nth(name_list, 1);
+ nworkers = strtod(hint->nworkers_str, &end_ptr);
+ if (*end_ptr || nworkers < 0 || nworkers > max_worker_processes)
+ {
+ if (*end_ptr)
+ hint_ereport(hint->nworkers_str,
+ ("number of workers must be a number: %s",
+ hint->base.keyword));
+ else if (nworkers < 0)
+ hint_ereport(hint->nworkers_str,
+ ("number of workers must be positive: %s",
+ hint->base.keyword));
+ else if (nworkers > max_worker_processes)
+ hint_ereport(hint->nworkers_str,
+ ("number of workers = %d is larger than max_worker_processes(%d): %s",
+ nworkers, max_worker_processes, hint->base.keyword));
+
+ hint->base.state = HINT_STATE_ERROR;
+ }
+
+ hint->nworkers = nworkers;
+
+ /* optional third parameter is specified */
+ if (length == 3)
+ {
+ const char *modeparam = (const char *)list_nth(name_list, 2);
+ if (strcasecmp(modeparam, "hard") == 0)
+ force_parallel = true;
+ else if (strcasecmp(modeparam, "soft") != 0)
+ {
+ hint_ereport(modeparam,
+ ("enforcement must be soft or hard: %s",
+ hint->base.keyword));
+ hint->base.state = HINT_STATE_ERROR;
+ }
+ }
+
+ hint->force_parallel = force_parallel;
+
+ if (hint->base.state != HINT_STATE_ERROR &&
+ nworkers > max_hint_nworkers)
+ max_hint_nworkers = nworkers;
+
+ return str;
+}
+