#include "commands/explain_state.h"
#include "nodes/pathnodes.h"
+/*
+ * Flags used in plan advice feedback.
+ *
+ * PGPA_FB_MATCH_PARTIAL means that we found some part of the query that at
+ * least partially matched the target; e.g. given JOIN_ORDER(a b), this would
+ * be set if we ever saw any joinrel including either "a" or "b".
+ *
+ * PGPA_FB_MATCH_FULL means that we found an exact match for the target; e.g.
+ * given JOIN_ORDER(a b), this would be set if we saw a joinrel containing
+ * exactly "a" and "b" and nothing else.
+ *
+ * PGPA_FB_INAPPLICABLE means that the advice doesn't properly apply to the
+ * target; e.g. INDEX_SCAN(foo bar_idx) would be so marked if bar_idx does not
+ * exist on foo. The fact that this bit has been set does not mean that the
+ * advice had no effect.
+ *
+ * PGPA_FB_CONFLICTING means that a conflict was detected between what this
+ * advice wants and what some other plan advice wants; e.g. JOIN_ORDER(a b)
+ * would conflict with HASH_JOIN(a), because the former requires "a" to be the
+ * outer table while the latter requires it to be the inner table.
+ *
+ * PGPA_FB_FAILED means that the resulting plan did not conform to the advice.
+ */
+#define PGPA_FB_MATCH_PARTIAL 0x0001
+#define PGPA_FB_MATCH_FULL 0x0002
+#define PGPA_FB_INAPPLICABLE 0x0004
+#define PGPA_FB_CONFLICTING 0x0008
+#define PGPA_FB_FAILED 0x0010
+
/* Hook for other plugins to supply advice strings */
typedef char *(*pg_plan_advice_advisor_hook) (PlannerGlobal *glob,
Query *parse,
pgpa_trove_lookup_type type,
pgpa_identifier *rt_identifiers,
pgpa_plan_walker_context *walker);
-static void pgpa_planner_feedback_warning(List *feedback);
static pgpa_planner_info *pgpa_planner_get_proot(pgpa_planner_state *pps,
PlannerInfo *root);
* the set of targets exactly matched this relation, fully matched. If
* there was a conflict, mark them all as conflicting.
*/
- flags = PGPA_TE_MATCH_PARTIAL;
+ flags = PGPA_FB_MATCH_PARTIAL;
if (gather_conflict)
- flags |= PGPA_TE_CONFLICTING;
+ flags |= PGPA_FB_CONFLICTING;
pgpa_trove_set_flags(pjs->rel_entries, gather_partial_match, flags);
- flags |= PGPA_TE_MATCH_FULL;
+ flags |= PGPA_FB_MATCH_FULL;
pgpa_trove_set_flags(pjs->rel_entries, gather_full_match, flags);
/* Likewise for partitionwise advice. */
- flags = PGPA_TE_MATCH_PARTIAL;
+ flags = PGPA_FB_MATCH_PARTIAL;
if (partitionwise_conflict)
- flags |= PGPA_TE_CONFLICTING;
+ flags |= PGPA_FB_CONFLICTING;
pgpa_trove_set_flags(pjs->rel_entries, partitionwise_partial_match, flags);
- flags |= PGPA_TE_MATCH_FULL;
+ flags |= PGPA_FB_MATCH_FULL;
pgpa_trove_set_flags(pjs->rel_entries, partitionwise_full_match, flags);
/*
* This doesn't seem to be a semijoin to which SJ_UNIQUE
* or SJ_NON_UNIQUE can be applied.
*/
- entry->flags |= PGPA_TE_INAPPLICABLE;
+ entry->flags |= PGPA_FB_INAPPLICABLE;
}
else if (advice_unique != jt_unique)
sj_deny_indexes = bms_add_member(sj_deny_indexes, i);
(jo_deny_indexes != NULL || jo_deny_rel_indexes != NULL))
{
pgpa_trove_set_flags(pjs->join_entries, jo_permit_indexes,
- PGPA_TE_CONFLICTING);
+ PGPA_FB_CONFLICTING);
pgpa_trove_set_flags(pjs->join_entries, jo_deny_indexes,
- PGPA_TE_CONFLICTING);
+ PGPA_FB_CONFLICTING);
pgpa_trove_set_flags(pjs->rel_entries, jo_deny_rel_indexes,
- PGPA_TE_CONFLICTING);
+ PGPA_FB_CONFLICTING);
}
/*
*/
if (jm_conflict)
pgpa_trove_set_flags(pjs->join_entries, jm_indexes,
- PGPA_TE_CONFLICTING);
+ PGPA_FB_CONFLICTING);
/* If semijoin advice says both yes and no, mark it all as conflicting. */
if (sj_permit_indexes != NULL && sj_deny_indexes != NULL)
{
pgpa_trove_set_flags(pjs->join_entries, sj_permit_indexes,
- PGPA_TE_CONFLICTING);
+ PGPA_FB_CONFLICTING);
pgpa_trove_set_flags(pjs->join_entries, sj_deny_indexes,
- PGPA_TE_CONFLICTING);
+ PGPA_FB_CONFLICTING);
}
/*
pgpa_advice_target *prefix_target;
/* We definitely have at least a partial match for this trove entry. */
- entry->flags |= PGPA_TE_MATCH_PARTIAL;
+ entry->flags |= PGPA_FB_MATCH_PARTIAL;
/*
* Find the innermost sublist that contains all keys; if no sublist does,
* answer is yes.
*/
if (!sublist && outer_length + 1 == length && itm == PGPA_ITM_EQUAL)
- entry->flags |= PGPA_TE_MATCH_FULL;
+ entry->flags |= PGPA_FB_MATCH_FULL;
return (itm == PGPA_ITM_EQUAL) ? PGPA_JO_PERMITTED : PGPA_JO_DENIED;
}
* joining t1-t2 to the result would still be rejected.
*/
if (!sublist)
- entry->flags |= PGPA_TE_MATCH_FULL;
+ entry->flags |= PGPA_FB_MATCH_FULL;
return sublist ? PGPA_JO_DENIED : PGPA_JO_PERMITTED;
}
pgpa_itm_type join_itm;
/* We definitely have at least a partial match for this trove entry. */
- entry->flags |= PGPA_TE_MATCH_PARTIAL;
+ entry->flags |= PGPA_FB_MATCH_PARTIAL;
*restrict_method = false;
target);
if (inner_itm == PGPA_ITM_EQUAL)
{
- entry->flags |= PGPA_TE_MATCH_FULL;
+ entry->flags |= PGPA_FB_MATCH_FULL;
*restrict_method = true;
return true;
}
pgpa_itm_type join_itm;
/* We definitely have at least a partial match for this trove entry. */
- entry->flags |= PGPA_TE_MATCH_PARTIAL;
+ entry->flags |= PGPA_FB_MATCH_PARTIAL;
*restrict_method = false;
* We have an exact match, and should therefore allow the join and
* enforce the use of the relevant opaque join method.
*/
- entry->flags |= PGPA_TE_MATCH_FULL;
+ entry->flags |= PGPA_FB_MATCH_FULL;
*restrict_method = true;
return true;
}
*restrict_method = false;
/* We definitely have at least a partial match for this trove entry. */
- entry->flags |= PGPA_TE_MATCH_PARTIAL;
+ entry->flags |= PGPA_FB_MATCH_PARTIAL;
/*
* If outer rel is the nullable side and contains exactly the same
rids, target);
if (outer_itm == PGPA_ITM_EQUAL)
{
- entry->flags |= PGPA_TE_MATCH_FULL;
+ entry->flags |= PGPA_FB_MATCH_FULL;
if (outer_is_nullable)
{
*restrict_method = true;
target);
if (inner_itm == PGPA_ITM_EQUAL)
{
- entry->flags |= PGPA_TE_MATCH_FULL;
+ entry->flags |= PGPA_FB_MATCH_FULL;
if (!outer_is_nullable)
{
*restrict_method = true;
/* Mark advice as inapplicable. */
pgpa_trove_set_flags(scan_entries, scan_type_indexes,
- PGPA_TE_INAPPLICABLE);
+ PGPA_FB_INAPPLICABLE);
}
else
{
* Mark all the scan method entries as fully matched; and if they specify
* different things, mark them all as conflicting.
*/
- flags = PGPA_TE_MATCH_PARTIAL | PGPA_TE_MATCH_FULL;
+ flags = PGPA_FB_MATCH_PARTIAL | PGPA_FB_MATCH_FULL;
if (scan_type_conflict)
- flags |= PGPA_TE_CONFLICTING;
+ flags |= PGPA_FB_CONFLICTING;
pgpa_trove_set_flags(scan_entries, scan_type_indexes, flags);
pgpa_trove_set_flags(rel_entries, scan_type_rel_indexes, flags);
* the ones that included this relation as a target by itself as fully
* matched. If there was a conflict, mark them all as conflicting.
*/
- flags = PGPA_TE_MATCH_PARTIAL;
+ flags = PGPA_FB_MATCH_PARTIAL;
if (gather_conflict)
- flags |= PGPA_TE_CONFLICTING;
+ flags |= PGPA_FB_CONFLICTING;
pgpa_trove_set_flags(rel_entries, gather_partial_match, flags);
- flags |= PGPA_TE_MATCH_FULL;
+ flags |= PGPA_FB_MATCH_FULL;
pgpa_trove_set_flags(rel_entries, gather_full_match, flags);
/*
*
* Feedback entries are generated from the trove entry's flags. It's assumed
* that the caller has already set all relevant flags with the exception of
- * PGPA_TE_FAILED. We set that flag here if appropriate.
+ * PGPA_FB_FAILED. We set that flag here if appropriate.
*/
static List *
pgpa_planner_append_feedback(List *list, pgpa_trove *trove,
* from this plan would produce such an entry. If not, label the entry
* as failed.
*/
- if ((entry->flags & PGPA_TE_MATCH_FULL) != 0 &&
+ if ((entry->flags & PGPA_FB_MATCH_FULL) != 0 &&
!pgpa_walker_would_advise(walker, rt_identifiers,
entry->tag, entry->target))
- entry->flags |= PGPA_TE_FAILED;
+ entry->flags |= PGPA_FB_FAILED;
item = makeDefElem(pgpa_cstring_trove_entry(entry),
(Node *) makeInteger(entry->flags), -1);
* Emit a WARNING to tell the user about a problem with the supplied plan
* advice.
*/
-static void
+void
pgpa_planner_feedback_warning(List *feedback)
{
StringInfoData detailbuf;
* NB: Feedback should never be marked fully matched without also
* being marked partially matched.
*/
- if (flags == (PGPA_TE_MATCH_PARTIAL | PGPA_TE_MATCH_FULL))
+ if (flags == (PGPA_FB_MATCH_PARTIAL | PGPA_FB_MATCH_FULL))
continue;
/*
*/
#include "postgres.h"
+#include "pg_plan_advice.h"
#include "pgpa_trove.h"
#include "common/hashfn_unstable.h"
}
/*
- * Set PGPA_TE_* flags on a set of trove entries.
+ * Set PGPA_FB_* flags on a set of trove entries.
*/
void
pgpa_trove_set_flags(pgpa_trove_entry *entries, Bitmapset *indexes, int flags)
}
/*
- * Append a string representation of the specified PGPA_TE_* flags to the
+ * Append a string representation of the specified PGPA_FB_* flags to the
* given StringInfo.
*/
void
pgpa_trove_append_flags(StringInfo buf, int flags)
{
- if ((flags & PGPA_TE_MATCH_FULL) != 0)
+ if ((flags & PGPA_FB_MATCH_FULL) != 0)
{
- Assert((flags & PGPA_TE_MATCH_PARTIAL) != 0);
+ Assert((flags & PGPA_FB_MATCH_PARTIAL) != 0);
appendStringInfoString(buf, "matched");
}
- else if ((flags & PGPA_TE_MATCH_PARTIAL) != 0)
+ else if ((flags & PGPA_FB_MATCH_PARTIAL) != 0)
appendStringInfoString(buf, "partially matched");
else
appendStringInfoString(buf, "not matched");
- if ((flags & PGPA_TE_INAPPLICABLE) != 0)
+ if ((flags & PGPA_FB_INAPPLICABLE) != 0)
appendStringInfoString(buf, ", inapplicable");
- if ((flags & PGPA_TE_CONFLICTING) != 0)
+ if ((flags & PGPA_FB_CONFLICTING) != 0)
appendStringInfoString(buf, ", conflicting");
- if ((flags & PGPA_TE_FAILED) != 0)
+ if ((flags & PGPA_FB_FAILED) != 0)
appendStringInfoString(buf, ", failed");
}