0002-PoC-Planner-part-refactoring-of-mv-stats-facility.patch
text/x-patch
Filename: 0002-PoC-Planner-part-refactoring-of-mv-stats-facility.patch
Type: text/x-patch
Part: 1
Patch
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| src/backend/catalog/pg_operator.c | 6 | 0 |
| src/backend/nodes/nodeFuncs.c | 1 | 1 |
| src/backend/optimizer/path/clausesel.c | 816 | 3291 |
| src/backend/utils/cache/lsyscache.c | 40 | 0 |
| src/include/catalog/pg_operator.h | 777 | 773 |
| src/include/nodes/nodes.h | 1 | 0 |
| src/include/nodes/relation.h | 21 | 1 |
| src/include/optimizer/cost.h | 2 | 4 |
| src/include/utils/lsyscache.h | 1 | 0 |
| src/include/utils/mvstats.h | 3 | 0 |
>From 77ccd9c8d455a365b2ad6eb779ed76da0d431e3f Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Thu, 16 Jul 2015 13:56:58 +0900
Subject: [PATCH 2/2] PoC: Planner part refactoring of mv stats facility
---
src/backend/catalog/pg_operator.c | 6 +
src/backend/nodes/nodeFuncs.c | 2 +-
src/backend/optimizer/path/clausesel.c | 4107 +++++++-------------------------
src/backend/utils/cache/lsyscache.c | 40 +
src/include/catalog/pg_operator.h | 1550 ++++++------
src/include/nodes/nodes.h | 1 +
src/include/nodes/relation.h | 22 +-
src/include/optimizer/cost.h | 6 +-
src/include/utils/lsyscache.h | 1 +
src/include/utils/mvstats.h | 3 +
10 files changed, 1668 insertions(+), 4070 deletions(-)
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 072f530..dea39d3 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -251,6 +251,9 @@ OperatorShellMake(const char *operatorName,
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
+ /* XXXX: How this should be implemented? */
+ values[Anum_pg_operator_oprmvstat - 1] = CStringGetTextDatum("---");
+
/*
* open pg_operator
*/
@@ -508,6 +511,9 @@ OperatorCreate(const char *operatorName,
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
+ /* XXXX: How this should be implemented? */
+ values[Anum_pg_operator_oprmvstat - 1] = CStringGetTextDatum("---");
+
pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
/*
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 115ff98..00ef04b 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1996,7 +1996,7 @@ expression_tree_walker(Node *node,
case T_RangeTblFunction:
return walker(((RangeTblFunction *) node)->funcexpr, context);
case T_RestrictInfo:
- elog(LOG, "HOGEEEEE: RestrictInfo");
+// elog(LOG, "HOGEEEEE: RestrictInfo");
return walker(((RestrictInfo *) node)->clause, context);
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index fce77ec..61f3cd8 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -46,13 +46,6 @@ typedef struct RangeQueryClause
Selectivity hibound; /* Selectivity of a var < something clause */
} RangeQueryClause;
-static Selectivity clauselist_selectivity_or(PlannerInfo *root,
- List *clauses,
- int varRelid,
- JoinType jointype,
- SpecialJoinInfo *sjinfo,
- List *conditions);
-
static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
bool varonleft, bool isLTsel, Selectivity s2);
@@ -60,38 +53,6 @@ static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
#define MV_CLAUSE_TYPE_MCV 0x02
#define MV_CLAUSE_TYPE_HIST 0x04
-static bool clause_is_mv_compatible(PlannerInfo *root, Node *clause, Oid varRelid,
- Index *relid, Bitmapset **attnums, SpecialJoinInfo *sjinfo,
- int type);
-
-static Bitmapset *collect_mv_attnums(PlannerInfo *root, List *clauses,
- Oid varRelid, Index *relid, SpecialJoinInfo *sjinfo,
- int type);
-
-static Bitmapset *clause_mv_get_attnums(PlannerInfo *root, Node *clause);
-
-static List *clauselist_apply_dependencies(PlannerInfo *root, List *clauses,
- Oid varRelid, List *stats,
- SpecialJoinInfo *sjinfo);
-
-static List *clauselist_mv_split(PlannerInfo *root, SpecialJoinInfo *sjinfo,
- List *clauses, Oid varRelid,
- List **mvclauses, MVStatisticInfo *mvstats, int types);
-
-static Selectivity clauselist_mv_selectivity(PlannerInfo *root,
- MVStatisticInfo *mvstats, List *clauses,
- List *conditions, bool is_or);
-
-static Selectivity clauselist_mv_selectivity_mcvlist(PlannerInfo *root,
- MVStatisticInfo *mvstats,
- List *clauses, List *conditions,
- bool is_or, bool *fullmatch,
- Selectivity *lowsel);
-static Selectivity clauselist_mv_selectivity_histogram(PlannerInfo *root,
- MVStatisticInfo *mvstats,
- List *clauses, List *conditions,
- bool is_or);
-
static int update_match_bitmap_mcvlist(PlannerInfo *root, List *clauses,
int2vector *stakeys, MCVList mcvlist,
int nmatches, char * matches,
@@ -104,79 +65,11 @@ static int update_match_bitmap_histogram(PlannerInfo *root, List *clauses,
int nmatches, char * matches,
bool is_or);
-/*
- * Describes a combination of multiple statistics to cover attributes
- * referenced by the clauses. The array 'stats' (with nstats elements)
- * lists attributes (in the order as they are applied), and number of
- * clause attributes covered by this solution.
- *
- * choose_mv_statistics_exhaustive() uses this to track both the current
- * and the best solutions, while walking through the state of possible
- * combination.
- */
-typedef struct mv_solution_t {
- int nclauses; /* number of clauses covered */
- int nconditions; /* number of conditions covered */
- int nstats; /* number of stats applied */
- int *stats; /* stats (in the apply order) */
-} mv_solution_t;
-
-static List *choose_mv_statistics(PlannerInfo *root,
- List *mvstats,
- List *clauses, List *conditions,
- Oid varRelid,
- SpecialJoinInfo *sjinfo);
-
-static List *filter_clauses(PlannerInfo *root, Oid varRelid,
- SpecialJoinInfo *sjinfo, int type,
- List *stats, List *clauses,
- Bitmapset **attnums);
-
-static List *filter_stats(List *stats, Bitmapset *new_attnums,
- Bitmapset *all_attnums);
-
-static Bitmapset **make_stats_attnums(MVStatisticInfo *mvstats,
- int nmvstats);
-
-static MVStatisticInfo *make_stats_array(List *stats, int *nmvstats);
-
-static List* filter_redundant_stats(List *stats,
- List *clauses, List *conditions);
-
-static Node** make_clauses_array(List *clauses, int *nclauses);
-
-static Bitmapset ** make_clauses_attnums(PlannerInfo *root, Oid varRelid,
- SpecialJoinInfo *sjinfo, int type,
- Node **clauses, int nclauses);
-
-static bool* make_cover_map(Bitmapset **stats_attnums, int nmvstats,
- Bitmapset **clauses_attnums, int nclauses);
-
-static bool has_stats(List *stats, int type);
-
-static List * find_stats(PlannerInfo *root, List *clauses,
- Oid varRelid, Index *relid);
-
-static Bitmapset* fdeps_collect_attnums(List *stats);
-
-static int *make_idx_to_attnum_mapping(Bitmapset *attnums);
-static int *make_attnum_to_idx_mapping(Bitmapset *attnums);
-
-static bool *build_adjacency_matrix(List *stats, Bitmapset *attnums,
- int *idx_to_attnum, int *attnum_to_idx);
-
-static void multiply_adjacency_matrix(bool *matrix, int natts);
-
static List* fdeps_reduce_clauses(List *clauses,
Bitmapset *attnums, bool *matrix,
int *idx_to_attnum, int *attnum_to_idx,
Index relid);
-static Bitmapset *fdeps_filter_clauses(PlannerInfo *root,
- List *clauses, Bitmapset *deps_attnums,
- List **reduced_clauses, List **deps_clauses,
- Oid varRelid, Index *relid, SpecialJoinInfo *sjinfo);
-
static Bitmapset * get_varattnos(Node * node, Index relid);
int mvstat_search_type = MVSTAT_SEARCH_GREEDY;
@@ -188,397 +81,41 @@ int mvstat_search_type = MVSTAT_SEARCH_GREEDY;
#define UPDATE_RESULT(m,r,isor) \
(m) = (isor) ? (MAX(m,r)) : (MIN(m,r))
+typedef enum mv_selec_status
+{
+ NORMAL,
+ FULL_MATCH,
+ FAILURE
+} mv_selec_status;
+
/****************************************************************************
* ROUTINES TO COMPUTE SELECTIVITIES
****************************************************************************/
+/***************/
+RestrictStatData *
+transformRestrictInfoForEstimate(PlannerInfo *root, List *clauses, int varRelid, SpecialJoinInfo *sjinfo);
/*
- * clauselist_selectivity -
- * Compute the selectivity of an implicitly-ANDed list of boolean
- * expression clauses. The list can be empty, in which case 1.0
- * must be returned. List elements may be either RestrictInfos
- * or bare expression clauses --- the former is preferred since
- * it allows caching of results.
- *
- * See clause_selectivity() for the meaning of the additional parameters.
- *
- * Our basic approach is to take the product of the selectivities of the
- * subclauses. However, that's only right if the subclauses have independent
- * probabilities, and in reality they are often NOT independent. So,
- * we want to be smarter where we can.
- *
- * Currently, the only extra smarts we have is to recognize "range queries",
- * such as "x > 34 AND x < 42". Clauses are recognized as possible range
- * query components if they are restriction opclauses whose operators have
- * scalarltsel() or scalargtsel() as their restriction selectivity estimator.
- * We pair up clauses of this form that refer to the same variable. An
- * unpairable clause of this kind is simply multiplied into the selectivity
- * product in the normal way. But when we find a pair, we know that the
- * selectivities represent the relative positions of the low and high bounds
- * within the column's range, so instead of figuring the selectivity as
- * hisel * losel, we can figure it as hisel + losel - 1. (To visualize this,
- * see that hisel is the fraction of the range below the high bound, while
- * losel is the fraction above the low bound; so hisel can be interpreted
- * directly as a 0..1 value but we need to convert losel to 1-losel before
- * interpreting it as a value. Then the available range is 1-losel to hisel.
- * However, this calculation double-excludes nulls, so really we need
- * hisel + losel + null_frac - 1.)
- *
- * If either selectivity is exactly DEFAULT_INEQ_SEL, we forget this equation
- * and instead use DEFAULT_RANGE_INEQ_SEL. The same applies if the equation
- * yields an impossible (negative) result.
- *
- * A free side-effect is that we can recognize redundant inequalities such
- * as "x < 4 AND x < 5"; only the tighter constraint will be counted.
- *
- * Of course this is all very dependent on the behavior of
- * scalarltsel/scalargtsel; perhaps some day we can generalize the approach.
- *
- *
- * Multivariate statististics
- * --------------------------
- * This also uses multivariate stats to estimate combinations of
- * conditions, in a way (a) maximizing the estimate accuracy by using
- * as many stats as possible, and (b) minimizing the overhead,
- * especially when there are no suitable multivariate stats (so if you
- * are not using multivariate stats, there's no additional overhead).
- *
- * The following checks are performed (in this order), and the optimizer
- * falls back to regular stats on the first 'false'.
- *
- * NOTE: This explains how this works with all the patches applied, not
- * just the functional dependencies.
- *
- * (0) check if there are multivariate stats on the relation
- *
- * If no, just skip all the following steps (directly to the
- * original code).
- *
- * (1) check how many attributes are there in conditions compatible
- * with functional dependencies
- *
- * Only simple equality clauses are considered compatible with
- * functional dependencies (and that's unlikely to change, because
- * that's the only case when functional dependencies are useful).
- *
- * If there are no conditions that might be handled by multivariate
- * stats, or if the conditions reference just a single column, it
- * makes no sense to use functional dependencies, so skip to (4).
- *
- * (2) reduce the clauses using functional dependencies
- *
- * This simply attempts to 'reduce' the clauses by applying functional
- * dependencies. For example if there are two clauses:
- *
- * WHERE (a = 1) AND (b = 2)
- *
- * and we know that 'a' determines the value of 'b', we may remove
- * the second condition (b = 2) when computing the selectivity.
- * This is of course tricky - see mvstats/dependencies.c for details.
- *
- * After the reduction, step (1) is to be repeated.
- *
- * (3) check how many attributes are there in conditions compatible
- * with MCV lists and histograms
- *
- * What conditions are compatible with multivariate stats is decided
- * by clause_is_mv_compatible(). At this moment, only conditions
- * of the form "column operator constant" (for simple comparison
- * operators), IS [NOT] NULL and some AND/OR clauses are considered
- * compatible with multivariate statistics.
- *
- * Again, see clause_is_mv_compatible() for details.
- *
- * (4) check how many attributes are there in conditions compatible
- * with MCV lists and histograms
- *
- * If there are no conditions that might be handled by MCV lists
- * or histograms, or if the conditions reference just a single
- * column, it makes no sense to continue, so just skip to (7).
- *
- * (5) choose the stats matching the most columns
- *
- * If there are multiple instances of multivariate statistics (e.g.
- * built on different sets of columns), we choose the stats covering
- * the most columns from step (1). It may happen that all available
- * stats match just a single column - for example with conditions
- *
- * WHERE a = 1 AND b = 2
- *
- * and statistics built on (a,c) and (b,c). In such case just fall
- * back to the regular stats because it makes no sense to use the
- * multivariate statistics.
- *
- * For more details about how exactly we choose the stats, see
- * choose_mv_statistics().
- *
- * (6) use the multivariate stats to estimate matching clauses
- *
- * (7) estimate the remaining clauses using the regular statistics
+ * boolop_selectivity -
*/
-Selectivity
-clauselist_selectivity(PlannerInfo *root,
+static Selectivity
+and_clause_selectivity(PlannerInfo *root,
List *clauses,
int varRelid,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- List *conditions)
+ SpecialJoinInfo *sjinfo)
{
Selectivity s1 = 1.0;
RangeQueryClause *rqlist = NULL;
ListCell *l;
- /* processing mv stats */
- Index relid = InvalidOid;
-
- /* attributes in mv-compatible clauses */
- Bitmapset *mvattnums = NULL;
- List *stats = NIL;
-
- /* use clauses (not conditions), because those are always non-empty */
- stats = find_stats(root, clauses, varRelid, &relid);
-
- /*
- * If there's exactly one clause, then no use in trying to match up
- * pairs, or matching multivariate statistics, so just go directly
- * to clause_selectivity().
- */
- if (list_length(clauses) == 1)
- return clause_selectivity(root, (Node *) linitial(clauses),
- varRelid, jointype, sjinfo, conditions);
-
- /*
- * Check that there are some stats with functional dependencies
- * built (by walking the stats list). We're going to find that
- * anyway when trying to apply the functional dependencies, but
- * this is probably a tad faster.
- */
- if (has_stats(stats, MV_CLAUSE_TYPE_FDEP))
- {
- /*
- * Collect attributes referenced by mv-compatible clauses (looking
- * for clauses compatible with functional dependencies for now).
- */
- mvattnums = collect_mv_attnums(root, clauses, varRelid, &relid, sjinfo,
- MV_CLAUSE_TYPE_FDEP);
-
- /*
- * If there are mv-compatible clauses, referencing at least two
- * different columns (otherwise it makes no sense to use mv stats),
- * try to reduce the clauses using functional dependencies, and
- * recollect the attributes from the reduced list.
- *
- * We don't need to select a single statistics for this - we can
- * apply all the functional dependencies we have.
- */
- if (bms_num_members(mvattnums) >= 2)
- clauses = clauselist_apply_dependencies(root, clauses, varRelid,
- stats, sjinfo);
- }
-
- /*
- * Check that there are statistics with MCV list or histogram.
- * If not, we don't need to waste time with the optimization.
- */
- if (has_stats(stats, MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST))
- {
- /*
- * Recollect attributes from mv-compatible clauses (maybe we've
- * removed so many clauses we have a single mv-compatible attnum).
- * From now on we're only interested in MCV-compatible clauses.
- */
- mvattnums = collect_mv_attnums(root, clauses, varRelid, &relid, sjinfo,
- (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
-
- /*
- * If there still are at least two columns, we'll try to select
- * a suitable combination of multivariate stats. If there are
- * multiple combinations, we'll try to choose the best one.
- * See choose_mv_statistics for more details.
- */
- if (bms_num_members(mvattnums) >= 2)
- {
- int k;
- ListCell *s;
-
- /*
- * Copy the list of conditions, so that we can build a list
- * of local conditions (and keep the original intact, for
- * the other clauses at the same level).
- */
- List *conditions_local = list_copy(conditions);
-
- /* find the best combination of statistics */
- List *solution = choose_mv_statistics(root, stats,
- clauses, conditions,
- varRelid, sjinfo);
-
- /* we have a good solution (list of stats) */
- foreach (s, solution)
- {
- MVStatisticInfo *mvstat = (MVStatisticInfo *)lfirst(s);
-
- /* clauses compatible with multi-variate stats */
- List *mvclauses = NIL;
- List *mvclauses_new = NIL;
- List *mvclauses_conditions = NIL;
- Bitmapset *stat_attnums = NULL;
-
- /* build attnum bitmapset for this statistics */
- for (k = 0; k < mvstat->stakeys->dim1; k++)
- stat_attnums = bms_add_member(stat_attnums,
- mvstat->stakeys->values[k]);
-
- /*
- * Append the compatible conditions (passed from above)
- * to mvclauses_conditions.
- */
- foreach (l, conditions)
- {
- Node *c = (Node*)lfirst(l);
- Bitmapset *tmp = clause_mv_get_attnums(root, c);
-
- if (bms_is_subset(tmp, stat_attnums))
- mvclauses_conditions
- = lappend(mvclauses_conditions, c);
-
- bms_free(tmp);
- }
-
- /* split the clauselist into regular and mv-clauses
- *
- * We keep the list of clauses (we don't remove the
- * clauses yet, because we want to use the clauses
- * as conditions of other clauses).
- *
- * FIXME Do this only once, i.e. filter the clauses
- * once (selecting clauses covered by at least
- * one statistics) and then convert them into
- * smaller per-statistics lists of conditions
- * and estimated clauses.
- */
- clauselist_mv_split(root, sjinfo, clauses,
- varRelid, &mvclauses, mvstat,
- (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
-
- /*
- * We've chosen the statistics to match the clauses, so
- * each statistics from the solution should have at least
- * one new clause (not covered by the previous stats).
- */
- Assert(mvclauses != NIL);
-
- /*
- * Mvclauses now contains only clauses compatible
- * with the currently selected stats, but we have to
- * split that into conditions (already matched by
- * the previous stats), and the new clauses we need
- * to estimate using this stats.
- */
- foreach (l, mvclauses)
- {
- ListCell *p;
- bool covered = false;
- Node *clause = (Node *) lfirst(l);
- Bitmapset *clause_attnums = clause_mv_get_attnums(root, clause);
-
- /*
- * If already covered by previous stats, add it to
- * conditions.
- *
- * TODO Maybe this could be relaxed a bit? Because
- * with complex and/or clauses, this might
- * mean no statistics actually covers such
- * complex clause.
- */
- foreach (p, solution)
- {
- int k;
- Bitmapset *stat_attnums = NULL;
-
- MVStatisticInfo *prev_stat
- = (MVStatisticInfo *)lfirst(p);
-
- /* break if we've ran into current statistic */
- if (prev_stat == mvstat)
- break;
-
- for (k = 0; k < prev_stat->stakeys->dim1; k++)
- stat_attnums = bms_add_member(stat_attnums,
- prev_stat->stakeys->values[k]);
-
- covered = bms_is_subset(clause_attnums, stat_attnums);
-
- bms_free(stat_attnums);
-
- if (covered)
- break;
- }
-
- if (covered)
- mvclauses_conditions
- = lappend(mvclauses_conditions, clause);
- else
- mvclauses_new
- = lappend(mvclauses_new, clause);
- }
-
- /*
- * We need at least one new clause (not just conditions).
- */
- Assert(mvclauses_new != NIL);
-
- /* compute the multivariate stats */
- s1 *= clauselist_mv_selectivity(root, mvstat,
- mvclauses_new,
- mvclauses_conditions,
- false); /* AND */
- }
-
- /*
- * And now finally remove all the mv-compatible clauses.
- *
- * This only repeats the same split as above, but this
- * time we actually use the result list (and feed it to
- * the next call).
- */
- foreach (s, solution)
- {
- /* clauses compatible with multi-variate stats */
- List *mvclauses = NIL;
-
- MVStatisticInfo *mvstat = (MVStatisticInfo *)lfirst(s);
-
- /* split the list into regular and mv-clauses */
- clauses = clauselist_mv_split(root, sjinfo, clauses,
- varRelid, &mvclauses, mvstat,
- (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
-
- /*
- * Add the clauses to the conditions (to be passed
- * to regular clauses), irrespectedly whether it
- * will be used as a condition or a clause here.
- *
- * We only keep the remaining conditions in the
- * clauses (we keep what clauselist_mv_split returns)
- * so we add each MV condition exactly once.
- */
- conditions_local = list_concat(conditions_local, mvclauses);
- }
-
- /* from now on, work with the 'local' list of conditions */
- conditions = conditions_local;
- }
- }
-
/*
* If there's exactly one clause, then no use in trying to match up
* pairs, so just go directly to clause_selectivity().
*/
if (list_length(clauses) == 1)
return clause_selectivity(root, (Node *) linitial(clauses),
- varRelid, jointype, sjinfo, conditions);
-
+ varRelid, jointype, sjinfo);
/*
* Initial scan over clauses. Anything that doesn't look like a potential
* rangequery clause gets multiplied into s1 and forgotten. Anything that
@@ -591,8 +128,7 @@ clauselist_selectivity(PlannerInfo *root,
Selectivity s2;
/* Always compute the selectivity using clause_selectivity */
- s2 = clause_selectivity(root, clause, varRelid, jointype, sjinfo,
- conditions);
+ s2 = clause_selectivity(root, clause, varRelid, jointype, sjinfo);
/*
* Check for being passed a RestrictInfo.
@@ -750,250 +286,334 @@ clauselist_selectivity(PlannerInfo *root,
return s1;
}
-/*
- * Similar to clauselist_selectivity(), but for clauses connected by OR.
- *
- * That means a few differences:
- *
- * - functional dependencies don't apply to OR-clauses
- *
- * - we can't add the previous clauses to conditions
- *
- * - combined selectivities are combined using (s1+s2 - s1*s2)
- * and not as a multiplication (s1*s2)
- *
- * Another way to evaluate this might be turning
- *
- * (a OR b OR c)
- *
- * into
- *
- * NOT ((NOT a) AND (NOT b) AND (NOT c))
- *
- * and computing selectivity of that using clauselist_selectivity().
- * That would allow (a) using the clauselist_selectivity directly and
- * (b) using the previous clauses as conditions. Not sure if it's
- * worth the additional complexity, though.
- */
static Selectivity
-clauselist_selectivity_or(PlannerInfo *root,
- List *clauses,
- int varRelid,
- JoinType jointype,
- SpecialJoinInfo *sjinfo,
- List *conditions)
+clause_mcv_selectivity(PlannerInfo *root, MVStatisticInfo *stats,
+ Node *clause, int *status)
{
- Selectivity s1 = 0.0;
- ListCell *l;
-
- /* processing mv stats */
- Index relid = InvalidOid;
-
- /* attributes in mv-compatible clauses */
- Bitmapset *mvattnums = NULL;
- List *stats = NIL;
-
- /* use clauses (not conditions), because those are always non-empty */
- stats = find_stats(root, clauses, varRelid, &relid);
+ MCVList mcvlist = NULL;
+ int nmatches = 0;
+ int nconditions = 0;
+ char *matches = NULL;
+ char *condition_matches = NULL;
+ Selectivity s = 0.0;
+ Selectivity t = 0.0;
+ Selectivity u = 0.0;
+ BoolExpr *expr = (BoolExpr*) clause;
+ bool is_or = or_clause(clause);
+ int i;
+ bool fullmatch;
+ Selectivity lowsel;
- /* OR-clauses do not work with functional dependencies */
- if (has_stats(stats, MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST))
+ Assert(IsA(expr, BoolExpr));
+
+ if (!expr || not_clause(clause)) /* For now!! */
{
- /*
- * Recollect attributes from mv-compatible clauses (maybe we've
- * removed so many clauses we have a single mv-compatible attnum).
- * From now on we're only interested in MCV-compatible clauses.
- */
- mvattnums = collect_mv_attnums(root, clauses, varRelid, &relid, sjinfo,
- (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
-
- /*
- * If there still are at least two columns, we'll try to select
- * a suitable multivariate stats.
- */
- if (bms_num_members(mvattnums) >= 2)
- {
- int k;
- ListCell *s;
+ *status = FAILURE;
+ return 0.0;
+ }
+ if (!stats->mcv_built)
+ {
+ *status = FAILURE;
+ return 0.0;
+ }
+
+ mcvlist = load_mv_mcvlist(stats->mvoid);
+ Assert (mcvlist != NULL);
+ Assert (mcvlist->nitems > 0);
- List *solution
- = choose_mv_statistics(root, stats,
- clauses, conditions,
- varRelid, sjinfo);
+ nmatches = mcvlist->nitems;
+ nconditions = mcvlist->nitems;
- /* we have a good solution stats */
- foreach (s, solution)
- {
- Selectivity s2;
- MVStatisticInfo *mvstat = (MVStatisticInfo *)lfirst(s);
+ matches = palloc0(sizeof(char) * nmatches);
- /* clauses compatible with multi-variate stats */
- List *mvclauses = NIL;
- List *mvclauses_new = NIL;
- List *mvclauses_conditions = NIL;
- Bitmapset *stat_attnums = NULL;
+ if (!is_or) /* AND-clause */
+ memset(matches, MVSTATS_MATCH_FULL, sizeof(char)*nmatches);
- /* build attnum bitmapset for this statistics */
- for (k = 0; k < mvstat->stakeys->dim1; k++)
- stat_attnums = bms_add_member(stat_attnums,
- mvstat->stakeys->values[k]);
+ /* Conditions are treated as AND clause, so match by default. */
+ condition_matches = palloc0(sizeof(char)*nconditions);
+ memset(condition_matches, MVSTATS_MATCH_FULL, sizeof(char)*nconditions);
- /*
- * Append the compatible conditions (passed from above)
- * to mvclauses_conditions.
- */
- foreach (l, conditions)
- {
- Node *c = (Node*)lfirst(l);
- Bitmapset *tmp = clause_mv_get_attnums(root, c);
+ nmatches = update_match_bitmap_mcvlist(root, expr->args,
+ stats->stakeys, mcvlist,
+ (is_or ? 0 : nmatches), matches,
+ &lowsel, &fullmatch, is_or);
- if (bms_is_subset(tmp, stat_attnums))
- mvclauses_conditions
- = lappend(mvclauses_conditions, c);
-
- bms_free(tmp);
- }
+ for (i = 0; i < mcvlist->nitems; i++)
+ {
+ u += mcvlist->items[i]->frequency;
+
+ if (condition_matches[i] == MVSTATS_MATCH_NONE)
+ continue;
- /* split the clauselist into regular and mv-clauses
- *
- * We keep the list of clauses (we don't remove the
- * clauses yet, because we want to use the clauses
- * as conditions of other clauses).
- *
- * FIXME Do this only once, i.e. filter the clauses
- * once (selecting clauses covered by at least
- * one statistics) and then convert them into
- * smaller per-statistics lists of conditions
- * and estimated clauses.
- */
- clauselist_mv_split(root, sjinfo, clauses,
- varRelid, &mvclauses, mvstat,
- (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
+ if (matches[i] != MVSTATS_MATCH_NONE)
+ s += mcvlist->items[i]->frequency;
- /*
- * We've chosen the statistics to match the clauses, so
- * each statistics from the solution should have at least
- * one new clause (not covered by the previous stats).
- */
- Assert(mvclauses != NIL);
+ t += mcvlist->items[i]->frequency;
+ }
- /*
- * Mvclauses now contains only clauses compatible
- * with the currently selected stats, but we have to
- * split that into conditions (already matched by
- * the previous stats), and the new clauses we need
- * to estimate using this stats.
- *
- * XXX We'll only use the new clauses, but maybe we
- * should use the conditions too, somehow. We can't
- * use that directly in conditional probability, but
- * maybe we might use them in a different way?
- *
- * If we have a clause (a OR b OR c), then knowing
- * that 'a' is TRUE means (b OR c) can't make the
- * whole clause FALSE.
- *
- * This is pretty much what
- *
- * (a OR b) == NOT ((NOT a) AND (NOT b))
- *
- * implies.
- */
- foreach (l, mvclauses)
- {
- ListCell *p;
- bool covered = false;
- Node *clause = (Node *) lfirst(l);
- Bitmapset *clause_attnums = clause_mv_get_attnums(root, clause);
+ pfree(matches);
+ pfree(condition_matches);
+ pfree(mcvlist);
- /*
- * If already covered by previous stats, add it to
- * conditions.
- *
- * TODO Maybe this could be relaxed a bit? Because
- * with complex and/or clauses, this might
- * mean no statistics actually covers such
- * complex clause.
- */
- foreach (p, solution)
- {
- int k;
- Bitmapset *stat_attnums = NULL;
+ if (fullmatch)
+ *status = FULL_MATCH;
- MVStatisticInfo *prev_stat
- = (MVStatisticInfo *)lfirst(p);
+ /* mcv_low is omitted for now */
- /* break if we've ran into current statistic */
- if (prev_stat == mvstat)
- break;
+ /* no condition matches */
+ if (t == 0.0)
+ return (Selectivity)0.0;
- for (k = 0; k < prev_stat->stakeys->dim1; k++)
- stat_attnums = bms_add_member(stat_attnums,
- prev_stat->stakeys->values[k]);
+ return (s / t) * u;
+}
- covered = bms_is_subset(clause_attnums, stat_attnums);
+static Selectivity
+clause_hist_selectivity(PlannerInfo *root, MVStatisticInfo *stats,
+ Node *clause, int *status)
+{
+ MVSerializedHistogram mvhist = NULL;
+ int nmatches = 0;
+ int nconditions = 0;
+ char *matches = NULL;
+ char *condition_matches = NULL;
+ Selectivity s = 0.0;
+ Selectivity t = 0.0;
+ Selectivity u = 0.0;
+ BoolExpr *expr = (BoolExpr*) clause;
+ bool is_or = or_clause(clause);
+ int i;
- bms_free(stat_attnums);
+ Assert(IsA(expr, BoolExpr));
- if (covered)
- break;
- }
+ if (!expr || not_clause(clause)) /* for now */
+ {
+ *status = 0;
+ return 0.0;
+ }
+ if (!stats->hist_built)
+ {
+ *status = 1;
+ return 0.0;
+ }
+ mvhist = load_mv_histogram(stats->mvoid);
+ Assert (mvhist != NULL);
+ Assert (clause != NULL);
- if (! covered)
- mvclauses_new = lappend(mvclauses_new, clause);
- }
+ nmatches = mvhist->nbuckets;
+ nconditions = mvhist->nbuckets;
+ matches = palloc0(sizeof(char) * nmatches);
+ if (!is_or) /* AND-clause */
+ memset(matches, MVSTATS_MATCH_FULL, sizeof(char)*nmatches);
- /*
- * We need at least one new clause (not just conditions).
- */
- Assert(mvclauses_new != NIL);
+ /* Conditions are treated as AND clause, so match by default. */
+ condition_matches = palloc0(sizeof(char)*nconditions);
+ memset(condition_matches, MVSTATS_MATCH_FULL, sizeof(char)*nconditions);
- /* compute the multivariate stats */
- s2 = clauselist_mv_selectivity(root, mvstat,
- mvclauses_new,
- mvclauses_conditions,
- true); /* OR */
+ update_match_bitmap_histogram(root, expr->args, stats->stakeys, mvhist,
+ (is_or ? 0 : nmatches), matches, is_or);
- s1 = s1 + s2 - s1 * s2;
- }
+ for (i = 0; i < mvhist->nbuckets; i++)
+ {
+ float coeff = 1.0;
+ u += mvhist->buckets[i]->ntuples;
- /*
- * And now finally remove all the mv-compatible clauses.
- *
- * This only repeats the same split as above, but this
- * time we actually use the result list (and feed it to
- * the next call).
- */
- foreach (s, solution)
- {
- /* clauses compatible with multi-variate stats */
- List *mvclauses = NIL;
+ if (condition_matches[i] == MVSTATS_MATCH_NONE)
+ continue;
+ else if (condition_matches[i] == MVSTATS_MATCH_PARTIAL)
+ coeff = 0.5;
- MVStatisticInfo *mvstat = (MVStatisticInfo *)lfirst(s);
+ t += coeff * mvhist->buckets[i]->ntuples;
- /* split the list into regular and mv-clauses */
- clauses = clauselist_mv_split(root, sjinfo, clauses,
- varRelid, &mvclauses, mvstat,
- (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
- }
- }
+ if (matches[i] == MVSTATS_MATCH_FULL)
+ s += coeff * mvhist->buckets[i]->ntuples;
+ else if (matches[i] == MVSTATS_MATCH_PARTIAL)
+ s += coeff * 0.5 * mvhist->buckets[i]->ntuples;
}
- /*
- * Handle the remaining clauses (either using regular statistics,
- * or by multivariate stats at the next level).
- */
- foreach(l, clauses)
+ pfree(matches);
+ pfree(condition_matches);
+ pfree(mvhist);
+
+ /* no condition matches */
+ if (t == 0.0)
+ return (Selectivity)0.0;
+
+ return (s / t) * u;
+}
+
+static Selectivity
+apply_mvstats(PlannerInfo *root, Node *clause, bm_mvstat *statent)
+{
+ Selectivity s1 = 0.0;
+ int status;
+
+ if (statent->mvkind & MVSTATISTIC_MCV)
{
- Selectivity s2 = clause_selectivity(root,
- (Node *) lfirst(l),
- varRelid,
- jointype,
- sjinfo,
- conditions);
+ s1 = clause_mcv_selectivity(root, statent->stats, clause, &status);
+ if (status == FULL_MATCH && s1 > 0.0)
+ return s1;
+ }
+
+ if (statent->mvkind & MVSTATISTIC_HIST)
+ s1 = s1 + clause_hist_selectivity(root, statent->stats,
+ clause, &status);
+
+ return s1;
+}
+
+static inline Selectivity
+merge_selectivity(Selectivity s1, Selectivity s2, BoolExprType op)
+{
+ if (op == AND_EXPR)
+ s1 = s1 * s2;
+ else
s1 = s1 + s2 - s1 * s2;
+
+ return s1;
+}
+/*
+ * mvclause_selectivity -
+ */
+static Selectivity
+mvclause_selectivity(PlannerInfo *root,
+ RestrictStatData *rstat,
+ int varRelid,
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo)
+{
+ Selectivity s1;
+ ListCell *lc;
+
+ if (!rstat->mvclause && !rstat->nonmvclause && !rstat->children)
+ return clause_selectivity(root, rstat->clause, varRelid, jointype,
+ sjinfo);
+
+ if (rstat->boolop == NOT_EXPR)
+ {
+ RestrictStatData *clause =
+ (RestrictStatData *)linitial(rstat->children);
+
+ s1 = 1.0 - mvclause_selectivity(root, clause, varRelid,
+ jointype, sjinfo);
+ return s1;
+ }
+
+ s1 = (rstat->boolop == AND_EXPR ? 1.0 : 0.0);
+
+ if (rstat->nonmvclause)
+ s1 = merge_selectivity(s1,
+ clause_selectivity(root, rstat->nonmvclause,
+ varRelid, jointype, sjinfo),
+ rstat->boolop);
+
+ if (rstat->mvclause)
+ {
+ bm_mvstat *mvs = (bm_mvstat*)linitial(rstat->mvstats);
+ Selectivity s2 = apply_mvstats(root, rstat->mvclause, mvs);
+
+ /* Fall back to ordinary calculation */
+ if (s2 < 0)
+ s2 = clause_selectivity(root, rstat->mvclause, varRelid,
+ jointype, sjinfo);
+ s1 = merge_selectivity(s1, s2, rstat->boolop);
+ }
+
+ foreach(lc, rstat->children)
+ {
+ RestrictStatData *rsd = (RestrictStatData *) lfirst(lc);
+ Assert(IsA(rsd, RestrictStatData));
+
+ s1 = merge_selectivity(s1,
+ mvclause_selectivity(root, rsd, varRelid,
+ jointype, sjinfo),
+ rstat->boolop);
+ }
+
+ return s1;
+}
+
+
+/*
+ * clauselist_selectivity -
+ * Compute the selectivity of an implicitly-ANDed list of boolean
+ * expression clauses. The list can be empty, in which case 1.0
+ * must be returned. List elements may be either RestrictInfos
+ * or bare expression clauses --- the former is preferred since
+ * it allows caching of results.
+ *
+ * See clause_selectivity() for the meaning of the additional parameters.
+ *
+ * Our basic approach is to take the product of the selectivities of the
+ * subclauses. However, that's only right if the subclauses have independent
+ * probabilities, and in reality they are often NOT independent. So,
+ * we want to be smarter where we can.
+ *
+ * Currently, the only extra smarts we have is to recognize "range queries",
+ * such as "x > 34 AND x < 42". Clauses are recognized as possible range
+ * query components if they are restriction opclauses whose operators have
+ * scalarltsel() or scalargtsel() as their restriction selectivity estimator.
+ * We pair up clauses of this form that refer to the same variable. An
+ * unpairable clause of this kind is simply multiplied into the selectivity
+ * product in the normal way. But when we find a pair, we know that the
+ * selectivities represent the relative positions of the low and high bounds
+ * within the column's range, so instead of figuring the selectivity as
+ * hisel * losel, we can figure it as hisel + losel - 1. (To visualize this,
+ * see that hisel is the fraction of the range below the high bound, while
+ * losel is the fraction above the low bound; so hisel can be interpreted
+ * directly as a 0..1 value but we need to convert losel to 1-losel before
+ * interpreting it as a value. Then the available range is 1-losel to hisel.
+ * However, this calculation double-excludes nulls, so really we need
+ * hisel + losel + null_frac - 1.)
+ *
+ * If either selectivity is exactly DEFAULT_INEQ_SEL, we forget this equation
+ * and instead use DEFAULT_RANGE_INEQ_SEL. The same applies if the equation
+ * yields an impossible (negative) result.
+ *
+ * A free side-effect is that we can recognize redundant inequalities such
+ * as "x < 4 AND x < 5"; only the tighter constraint will be counted.
+ *
+ * Of course this is all very dependent on the behavior of
+ * scalarltsel/scalargtsel; perhaps some day we can generalize the approach.
+ *
+ *
+ * Multivariate statististics
+ * --------------------------
+ * This also uses multivariate stats to estimate combinations of
+ * conditions, in a way (a) maximizing the estimate accuracy by using
+ * as many stats as possible, and (b) minimizing the overhead,
+ * especially when there are no suitable multivariate stats (so if you
+ * are not using multivariate stats, there's no additional overhead).
+ *
+ * The following checks are performed (in this order), and the optimizer
+ * falls back to regular stats on the first 'false'.
+ *
+ * NOTE: This explains how this works with all the patches applied, not
+ * just the functional dependencies.
+ *
+ */
+Selectivity
+clauselist_selectivity(PlannerInfo *root,
+ List *clauses,
+ int varRelid,
+ JoinType jointype,
+ SpecialJoinInfo *sjinfo)
+{
+ Selectivity s1 = 1.0;
+ RestrictStatData *rstat;
+ List *rinfos = clauses;
+
+ /* Reconstruct clauses so that multivariate statistics can be applied */
+ rstat = transformRestrictInfoForEstimate(root, clauses, varRelid, sjinfo);
+
+ if (rstat)
+ {
+ rinfos = rstat->unusedrinfos;
+
+ s1 = mvclause_selectivity(root, rstat, varRelid, jointype, sjinfo);
}
+ s1 = s1 * and_clause_selectivity(root, rinfos, varRelid, jointype, sjinfo);
+
return s1;
}
@@ -1204,8 +824,7 @@ clause_selectivity(PlannerInfo *root,
Node *clause,
int varRelid,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- List *conditions)
+ SpecialJoinInfo *sjinfo)
{
Selectivity s1 = 0.5; /* default for any unhandled clause type */
RestrictInfo *rinfo = NULL;
@@ -1335,28 +954,37 @@ clause_selectivity(PlannerInfo *root,
(Node *) get_notclausearg((Expr *) clause),
varRelid,
jointype,
- sjinfo,
- conditions);
+ sjinfo);
}
else if (and_clause(clause))
{
- /* share code with clauselist_selectivity() */
- s1 = clauselist_selectivity(root,
+ s1 = and_clause_selectivity(root,
((BoolExpr *) clause)->args,
varRelid,
jointype,
- sjinfo,
- conditions);
+ sjinfo);
}
else if (or_clause(clause))
{
- /* just call to clauselist_selectivity_or() */
- s1 = clauselist_selectivity_or(root,
- ((BoolExpr *) clause)->args,
- varRelid,
- jointype,
- sjinfo,
- conditions);
+ /*
+ * Selectivities for an OR clause are computed as s1+s2 - s1*s2 to
+ * account for the probable overlap of selected tuple sets.
+ *
+ * XXX is this too conservative?
+ */
+ ListCell *arg;
+
+ s1 = 0.0;
+ foreach(arg, ((BoolExpr *) clause)->args)
+ {
+ Selectivity s2 = clause_selectivity(root,
+ (Node *) lfirst(arg),
+ varRelid,
+ jointype,
+ sjinfo);
+
+ s1 = s1 + s2 - s1 * s2;
+ }
}
else if (is_opclause(clause) || IsA(clause, DistinctExpr))
{
@@ -1445,1899 +1073,55 @@ clause_selectivity(PlannerInfo *root,
s1 = booltestsel(root,
((BooleanTest *) clause)->booltesttype,
(Node *) ((BooleanTest *) clause)->arg,
- varRelid,
- jointype,
- sjinfo);
- }
- else if (IsA(clause, CurrentOfExpr))
- {
- /* CURRENT OF selects at most one row of its table */
- CurrentOfExpr *cexpr = (CurrentOfExpr *) clause;
- RelOptInfo *crel = find_base_rel(root, cexpr->cvarno);
-
- if (crel->tuples > 0)
- s1 = 1.0 / crel->tuples;
- }
- else if (IsA(clause, RelabelType))
- {
- /* Not sure this case is needed, but it can't hurt */
- s1 = clause_selectivity(root,
- (Node *) ((RelabelType *) clause)->arg,
- varRelid,
- jointype,
- sjinfo,
- conditions);
- }
- else if (IsA(clause, CoerceToDomain))
- {
- /* Not sure this case is needed, but it can't hurt */
- s1 = clause_selectivity(root,
- (Node *) ((CoerceToDomain *) clause)->arg,
- varRelid,
- jointype,
- sjinfo,
- conditions);
- }
-
- /* Cache the result if possible */
- if (cacheable)
- {
- if (jointype == JOIN_INNER)
- rinfo->norm_selec = s1;
- else
- rinfo->outer_selec = s1;
- }
-
-#ifdef SELECTIVITY_DEBUG
- elog(DEBUG4, "clause_selectivity: s1 %f", s1);
-#endif /* SELECTIVITY_DEBUG */
-
- return s1;
-}
-
-
-/*
- * Estimate selectivity for the list of MV-compatible clauses, using
- * using a MV statistics (combining a histogram and MCV list).
- *
- * This simply passes the estimation to the MCV list and then to the
- * histogram, if available.
- *
- * TODO Clamp the selectivity by min of the per-clause selectivities
- * (i.e. the selectivity of the most restrictive clause), because
- * that's the maximum we can ever get from ANDed list of clauses.
- * This may probably prevent issues with hitting too many buckets
- * and low precision histograms.
- *
- * TODO We may support some additional conditions, most importantly
- * those matching multiple columns (e.g. "a = b" or "a < b").
- * Ultimately we could track multi-table histograms for join
- * cardinality estimation.
- *
- * TODO Further thoughts on processing equality clauses: Maybe it'd be
- * better to look for stats (with MCV) covered by the equality
- * clauses, because then we have a chance to find an exact match
- * in the MCV list, which is pretty much the best we can do. We may
- * also look at the least frequent MCV item, and use it as a upper
- * boundary for the selectivity (had there been a more frequent
- * item, it'd be in the MCV list).
- *
- * TODO There are several options for 'sanity clamping' the estimates.
- *
- * First, if we have selectivities for each condition, then
- *
- * P(A,B) <= MIN(P(A), P(B))
- *
- * Because additional conditions (connected by AND) can only lower
- * the probability.
- *
- * So we can do some basic sanity checks using the single-variate
- * stats (the ones we have right now).
- *
- * Second, when we have multivariate stats with a MCV list, then
- *
- * (a) if we have a full equality condition (one equality condition
- * on each column) and we found a match in the MCV list, this is
- * the selectivity (and it's supposed to be exact)
- *
- * (b) if we have a full equality condition and we haven't found a
- * match in the MCV list, then the selectivity is below the
- * lowest selectivity in the MCV list
- *
- * (c) if we have a equality condition (not full), we can still
- * search the MCV for matches and use the sum of probabilities
- * as a lower boundary for the histogram (if there are no
- * matches in the MCV list, then we have no boundary)
- *
- * Third, if there are multiple (combinations of) multivariate
- * stats for a set of clauses, we may compute all of them and then
- * somehow aggregate them - e.g. by choosing the minimum, median or
- * average. The stats are susceptible to overestimation (because
- * we take 50% of the bucket for partial matches). Some stats may
- * give better estimates than others, but it's very difficult to
- * say that in advance which one is the best (it depends on the
- * number of buckets, number of additional columns not referenced
- * in the clauses, type of condition etc.).
- *
- * So we may compute them all and then choose a sane aggregation
- * (minimum seems like a good approach). Of course, this may result
- * in longer / more expensive estimation (CPU-wise), but it may be
- * worth it.
- *
- * It's possible to add a GUC choosing whether to do a 'simple'
- * (using a single stats expected to give the best estimate) and
- * 'complex' (combining the multiple estimates).
- *
- * multivariate_estimates = (simple|full)
- *
- * Also, this might be enabled at a table level, by something like
- *
- * ALTER TABLE ... SET STATISTICS (simple|full)
- *
- * Which would make it possible to use this only for the tables
- * where the simple approach does not work.
- *
- * Also, there are ways to optimize this algorithmically. E.g. we
- * may try to get an estimate from a matching MCV list first, and
- * if we happen to get a "full equality match" we may stop computing
- * the estimates from other stats (for this condition) because
- * that's probably the best estimate we can really get.
- *
- * TODO When applying the clauses to the histogram/MCV list, we can do
- * that from the most selective clauses first, because that'll
- * eliminate the buckets/items sooner (so we'll be able to skip
- * them without inspection, which is more expensive). But this
- * requires really knowing the per-clause selectivities in advance,
- * and that's not what we do now.
- *
- * TODO All this is based on the assumption that the statistics represent
- * the necessary dependencies, i.e. that if two colunms are not in
- * the same statistics, there's no dependency. If that's not the
- * case, we may get misestimates, just like before. For example
- * assume we have a table with three columns [a,b,c] with exactly
- * the same values, and statistics on [a,b] and [b,c]. So somthing
- * like this:
- *
- * CREATE TABLE test AS SELECT i, i, i
- FROM generate_series(1,1000);
- *
- * ALTER TABLE test ADD STATISTICS (mcv) ON (a,b);
- * ALTER TABLE test ADD STATISTICS (mcv) ON (b,c);
- *
- * ANALYZE test;
- *
- * EXPLAIN ANALYZE SELECT * FROM test
- * WHERE (a < 10) AND (b < 20) AND (c < 10);
- *
- * The problem here is that the only shared column between the two
- * statistics is 'b' so the probability will be computed like this
- *
- * P[(a < 10) & (b < 20) & (c < 10)]
- * = P[(a < 10) & (b < 20)] * P[(c < 10) | (a < 10) & (b < 20)]
- * = P[(a < 10) & (b < 20)] * P[(c < 10) | (b < 20)]
- *
- * or like this
- *
- * P[(a < 10) & (b < 20) & (c < 10)]
- * = P[(b < 20) & (c < 10)] * P[(a < 10) | (b < 20) & (c < 10)]
- * = P[(b < 20) & (c < 10)] * P[(a < 10) | (b < 20)]
- *
- * In both cases the conditional probabilities will be evaluated as
- * 0.5, because they lack the other column (which would make it 1.0).
- *
- * Theoretically it might be possible to transfer the dependency,
- * e.g. by building bitmap for [a,b] and then combine it with [b,c]
- * by doing something like this:
- *
- * 1) build bitmap on [a,b] using [(a<10) & (b < 20)]
- * 2) for each element in [b,c] check the bitmap
- *
- * But that's certainly nontrivial - for example the statistics may
- * be different (MCV list vs. histogram) and/or the items may not
- * match (e.g. MCV items or histogram buckets will be built
- * differently). Also, for one value of 'b' there might be multiple
- * MCV items (because of the other column values) with different
- * bitmap values (some will match, some won't) - so it's not exactly
- * bitmap but a partial match.
- *
- * Maybe a hash table with number of matches and mismatches (or
- * maybe sums of frequencies) would work? The step (2) would then
- * lookup the values and use that to weight the item somehow.
- *
- * Currently the only solution is to build statistics on all three
- * columns.
- */
-static Selectivity
-clauselist_mv_selectivity(PlannerInfo *root, MVStatisticInfo *mvstats,
- List *clauses, List *conditions, bool is_or)
-{
- bool fullmatch = false;
- Selectivity s1 = 0.0, s2 = 0.0;
-
- /*
- * Lowest frequency in the MCV list (may be used as an upper bound
- * for full equality conditions that did not match any MCV item).
- */
- Selectivity mcv_low = 0.0;
-
- /* TODO Evaluate simple 1D selectivities, use the smallest one as
- * an upper bound, product as lower bound, and sort the
- * clauses in ascending order by selectivity (to optimize the
- * MCV/histogram evaluation).
- */
-
- /* Evaluate the MCV first. */
- s1 = clauselist_mv_selectivity_mcvlist(root, mvstats,
- clauses, conditions, is_or,
- &fullmatch, &mcv_low);
-
- /*
- * If we got a full equality match on the MCV list, we're done (and
- * the estimate is pretty good).
- */
- if (fullmatch && (s1 > 0.0))
- return s1;
-
- /* FIXME if (fullmatch) without matching MCV item, use the mcv_low
- * selectivity as upper bound */
-
- s2 = clauselist_mv_selectivity_histogram(root, mvstats,
- clauses, conditions, is_or);
-
- /* TODO clamp to <= 1.0 (or more strictly, when possible) */
- return s1 + s2;
-}
-
-/*
- * Collect attributes from mv-compatible clauses.
- */
-static Bitmapset *
-collect_mv_attnums(PlannerInfo *root, List *clauses, Oid varRelid,
- Index *relid, SpecialJoinInfo *sjinfo, int types)
-{
- Bitmapset *attnums = NULL;
- ListCell *l;
-
- /*
- * Walk through the clauses and identify the ones we can estimate
- * using multivariate stats, and remember the relid/columns. We'll
- * then cross-check if we have suitable stats, and only if needed
- * we'll split the clauses into multivariate and regular lists.
- *
- * For now we're only interested in RestrictInfo nodes with nested
- * OpExpr, using either a range or equality.
- */
- foreach (l, clauses)
- {
- Node *clause = (Node *) lfirst(l);
-
- /* ignore the result here - we only need the attnums */
- clause_is_mv_compatible(root, clause, varRelid, relid, &attnums,
- sjinfo, types);
- }
-
- /*
- * If there are not at least two attributes referenced by the clause(s),
- * we can throw everything out (as we'll revert to simple stats).
- */
- if (bms_num_members(attnums) <= 1)
- {
- bms_free(attnums);
- attnums = NULL;
- *relid = InvalidOid;
- }
-
- return attnums;
-}
-
-/*
- * Selects the best combination of multivariate statistics, in an
- * exhaustive way, where 'best' means:
- *
- * (a) covering the most attributes (referenced by clauses)
- * (b) using the least number of multivariate stats
- * (c) using the most conditions to exploit dependency
- *
- * There may be other optimality criteria, not considered in the initial
- * implementation (more on that 'weaknesses' section).
- *
- * This pretty much splits the probability of clauses (aka selectivity)
- * into a sequence of conditional probabilities, like this
- *
- * P(A,B,C,D) = P(A,B) * P(C|A,B) * P(D|A,B,C)
- *
- * and removing the attributes not referenced by the existing stats,
- * under the assumption that there's no dependency (otherwise the DBA
- * would create the stats).
- *
- * The last criteria means that when we have the choice to compute like
- * this
- *
- * P(A,B,C,D) = P(A,B,C) * P(D|B,C)
- *
- * or like this
- *
- * P(A,B,C,D) = P(A,B,C) * P(D|C)
- *
- * we should use the first option, as that exploits more dependencies.
- *
- * The order of statistics in the solution implicitly determines the
- * order of estimation of clauses, because as we apply a statistics,
- * we always use it to estimate all the clauses covered by it (and
- * then we use those clauses as conditions for the next statistics).
- *
- * Don't call this directly but through choose_mv_statistics().
- *
- *
- * Algorithm
- * ---------
- * The algorithm is a recursive implementation of backtracking, with
- * maximum 'depth' equal to the number of multi-variate statistics
- * available on the table.
- *
- * It explores all the possible permutations of the stats.
- *
- * Whenever it considers adding the next statistics, the clauses it
- * matches are divided into 'conditions' (clauses already matched by at
- * least one previous statistics) and clauses that are estimated.
- *
- * Then several checks are performed:
- *
- * (a) The statistics covers at least 2 columns, referenced in the
- * estimated clauses (otherwise multi-variate stats are useless).
- *
- * (b) The statistics covers at least 1 new column, i.e. column not
- * refefenced by the already used stats (and the new column has
- * to be referenced by the clauses, of couse). Otherwise the
- * statistics would not add any new information.
- *
- * There are some other sanity checks (e.g. that the stats must not be
- * used twice etc.).
- *
- * Finally the new solution is compared to the currently best one, and
- * if it's considered better, it's used instead.
- *
- *
- * Weaknesses
- * ----------
- * The current implemetation uses a somewhat simple optimality criteria,
- * suffering by the following weaknesses.
- *
- * (a) There may be multiple solutions with the same number of covered
- * attributes and number of statistics (e.g. the same solution but
- * with statistics in a different order). It's unclear which solution
- * is the best one - in a sense all of them are equal.
- *
- * TODO It might be possible to compute estimate for each of those
- * solutions, and then combine them to get the final estimate
- * (e.g. by using average or median).
- *
- * (b) Does not consider that some types of stats are a better match for
- * some types of clauses (e.g. MCV list is a good match for equality
- * than a histogram).
- *
- * XXX Maybe MCV is almost always better / more accurate?
- *
- * But maybe this is pointless - generally, each column is either
- * a label (it's not important whether because of the data type or
- * how it's used), or a value with ordering that makes sense. So
- * either a MCV list is more appropriate (labels) or a histogram
- * (values with orderings).
- *
- * Now sure what to do with statistics on columns mixing columns of
- * both types - maybe it'd be beeter to invent a new type of stats
- * combining MCV list and histogram (keeping a small histogram for
- * each MCV item, and a separate histogram for values not on the
- * MCV list). But that's not implemented at this moment.
- *
- * TODO The algorithm should probably count number of Vars (not just
- * attnums) when computing the 'score' of each solution. Computing
- * the ratio of (num of all vars) / (num of condition vars) as a
- * measure of how well the solution uses conditions might be
- * useful.
- */
-static void
-choose_mv_statistics_exhaustive(PlannerInfo *root, int step,
- int nmvstats, MVStatisticInfo *mvstats, Bitmapset ** stats_attnums,
- int nclauses, Node ** clauses, Bitmapset ** clauses_attnums,
- int nconditions, Node ** conditions, Bitmapset ** conditions_attnums,
- bool *cover_map, bool *condition_map, int *ruled_out,
- mv_solution_t *current, mv_solution_t **best)
-{
- int i, j;
-
- Assert(best != NULL);
- Assert((step == 0 && current == NULL) || (step > 0 && current != NULL));
-
- CHECK_FOR_INTERRUPTS();
-
- if (current == NULL)
- {
- current = (mv_solution_t*)palloc0(sizeof(mv_solution_t));
- current->stats = (int*)palloc0(sizeof(int)*nmvstats);
- current->nstats = 0;
- current->nclauses = 0;
- current->nconditions = 0;
- }
-
- /*
- * Now try to apply each statistics, matching at least two attributes,
- * unless it's already used in one of the previous steps.
- */
- for (i = 0; i < nmvstats; i++)
- {
- int c;
-
- int ncovered_clauses = 0; /* number of covered clauses */
- int ncovered_conditions = 0; /* number of covered conditions */
- int nattnums = 0; /* number of covered attributes */
-
- Bitmapset *all_attnums = NULL;
- Bitmapset *new_attnums = NULL;
-
- /* skip statistics that were already used or eliminated */
- if (ruled_out[i] != -1)
- continue;
-
- /*
- * See if we have clauses covered by this statistics, but not
- * yet covered by any of the preceding onces.
- */
- for (c = 0; c < nclauses; c++)
- {
- bool covered = false;
- Bitmapset *clause_attnums = clauses_attnums[c];
- Bitmapset *tmp = NULL;
-
- /*
- * If this clause is not covered by this stats, we can't
- * use the stats to estimate that at all.
- */
- if (! cover_map[i * nclauses + c])
- continue;
-
- /*
- * Now we know we'll use this clause - either as a condition
- * or as a new clause (the estimated one). So let's add the
- * attributes to the attnums from all the clauses usable with
- * this statistics.
- */
- tmp = bms_union(all_attnums, clause_attnums);
-
- /* free the old bitmap */
- bms_free(all_attnums);
- all_attnums = tmp;
-
- /* let's see if it's covered by any of the previous stats */
- for (j = 0; j < step; j++)
- {
- /* already covered by the previous stats */
- if (cover_map[current->stats[j] * nclauses + c])
- covered = true;
-
- if (covered)
- break;
- }
-
- /* if already covered, continue with the next clause */
- if (covered)
- {
- ncovered_conditions += 1;
- continue;
- }
-
- /*
- * OK, this clause is covered by this statistics (and not by
- * any of the previous ones)
- */
- ncovered_clauses += 1;
-
- /* add the attnums into attnums from 'new clauses' */
- // new_attnums = bms_union(new_attnums, clause_attnums);
- }
-
- /* can't have more new clauses than original clauses */
- Assert(nclauses >= ncovered_clauses);
- Assert(ncovered_clauses >= 0); /* mostly paranoia */
-
- nattnums = bms_num_members(all_attnums);
-
- /* free all the bitmapsets - we don't need them anymore */
- bms_free(all_attnums);
- bms_free(new_attnums);
-
- all_attnums = NULL;
- new_attnums = NULL;
-
- /*
- * See if we have clauses covered by this statistics, but not
- * yet covered by any of the preceding onces.
- */
- for (c = 0; c < nconditions; c++)
- {
- Bitmapset *clause_attnums = conditions_attnums[c];
- Bitmapset *tmp = NULL;
-
- /*
- * If this clause is not covered by this stats, we can't
- * use the stats to estimate that at all.
- */
- if (! condition_map[i * nconditions + c])
- continue;
-
- /* count this as a condition */
- ncovered_conditions += 1;
-
- /*
- * Now we know we'll use this clause - either as a condition
- * or as a new clause (the estimated one). So let's add the
- * attributes to the attnums from all the clauses usable with
- * this statistics.
- */
- tmp = bms_union(all_attnums, clause_attnums);
-
- /* free the old bitmap */
- bms_free(all_attnums);
- all_attnums = tmp;
- }
-
- /*
- * Let's mark the statistics as 'ruled out' - either we'll use
- * it (and proceed to the next step), or it's incompatible.
- */
- ruled_out[i] = step;
-
- /*
- * There are no clauses usable with this statistics (not already
- * covered by aome of the previous stats).
- *
- * Similarly, if the clauses only use a single attribute, we
- * can't really use that.
- */
- if ((ncovered_clauses == 0) || (nattnums < 2))
- continue;
-
- /*
- * TODO Not sure if it's possible to add a clause referencing
- * only attributes already covered by previous stats?
- * Introducing only some new dependency, not a new
- * attribute. Couldn't come up with an example, though.
- * Might be worth adding some assert.
- */
-
- /*
- * got a suitable statistics - let's update the current solution,
- * maybe use it as the best solution
- */
- current->nclauses += ncovered_clauses;
- current->nconditions += ncovered_conditions;
- current->nstats += 1;
- current->stats[step] = i;
-
- /*
- * We can never cover more clauses, or use more stats that we
- * actually have at the beginning.
- */
- Assert(nclauses >= current->nclauses);
- Assert(nmvstats >= current->nstats);
- Assert(step < nmvstats);
-
- /* we can't get more conditions that clauses and conditions combined
- *
- * FIXME This assert does not work because we count the conditions
- * repeatedly (once for each statistics covering it).
- */
- /* Assert((nconditions + nclauses) >= current->nconditions); */
-
- if (*best == NULL)
- {
- *best = (mv_solution_t*)palloc0(sizeof(mv_solution_t));
- (*best)->stats = (int*)palloc0(sizeof(int)*nmvstats);
- (*best)->nstats = 0;
- (*best)->nclauses = 0;
- (*best)->nconditions = 0;
- }
-
- /* see if it's better than the current 'best' solution */
- if ((current->nclauses > (*best)->nclauses) ||
- ((current->nclauses == (*best)->nclauses) &&
- ((current->nstats > (*best)->nstats))))
- {
- (*best)->nstats = current->nstats;
- (*best)->nclauses = current->nclauses;
- (*best)->nconditions = current->nconditions;
- memcpy((*best)->stats, current->stats, nmvstats * sizeof(int));
- }
-
- /*
- * The recursion only makes sense if we haven't covered all the
- * attributes (then adding stats is not really possible).
- */
- if ((step + 1) < nmvstats)
- choose_mv_statistics_exhaustive(root, step+1,
- nmvstats, mvstats, stats_attnums,
- nclauses, clauses, clauses_attnums,
- nconditions, conditions, conditions_attnums,
- cover_map, condition_map, ruled_out,
- current, best);
-
- /* reset the last step */
- current->nclauses -= ncovered_clauses;
- current->nconditions -= ncovered_conditions;
- current->nstats -= 1;
- current->stats[step] = 0;
-
- /* mark the statistics as usable again */
- ruled_out[i] = -1;
-
- Assert(current->nclauses >= 0);
- Assert(current->nstats >= 0);
- }
-
- /* reset all statistics as 'incompatible' in this step */
- for (i = 0; i < nmvstats; i++)
- if (ruled_out[i] == step)
- ruled_out[i] = -1;
-
-}
-
-/*
- * Greedy search for a multivariate solution - a sequence of statistics
- * covering the clauses. This chooses the "best" statistics at each step,
- * so the resulting solution may not be the best solution globally, but
- * this produces the solution in only N steps (where N is the number of
- * statistics), while the exhaustive approach may have to walk through
- * ~N! combinations (although some of those are terminated early).
- *
- * See the comments at choose_mv_statistics_exhaustive() as this does
- * the same thing (but in a different way).
- *
- * Don't call this directly, but through choose_mv_statistics().
- *
- * TODO There are probably other metrics we might use - e.g. using
- * number of columns (num_cond_columns / num_cov_columns), which
- * might work better with a mix of simple and complex clauses.
- *
- * TODO Also the choice at the very first step should be handled
- * in a special way, because there will be 0 conditions at that
- * moment, so there needs to be some other criteria - e.g. using
- * the simplest (or most complex?) clause might be a good idea.
- *
- * TODO We might also select multiple stats using different criteria,
- * and branch the search. This is however tricky, because if we
- * choose k statistics at each step, we get k^N branches to
- * walk through (with N steps). That's not really good with
- * large number of stats (yet better than exhaustive search).
- */
-static void
-choose_mv_statistics_greedy(PlannerInfo *root, int step,
- int nmvstats, MVStatisticInfo *mvstats, Bitmapset ** stats_attnums,
- int nclauses, Node ** clauses, Bitmapset ** clauses_attnums,
- int nconditions, Node ** conditions, Bitmapset ** conditions_attnums,
- bool *cover_map, bool *condition_map, int *ruled_out,
- mv_solution_t *current, mv_solution_t **best)
-{
- int i, j;
- int best_stat = -1;
- double gain, max_gain = -1.0;
-
- /*
- * Bitmap tracking which clauses are already covered (by the previous
- * statistics) and may thus serve only as a condition in this step.
- */
- bool *covered_clauses = (bool*)palloc0(nclauses);
-
- /*
- * Number of clauses and columns covered by each statistics - this
- * includes both conditions and clauses covered by the statistics for
- * the first time. The number of columns may count some columns
- * repeatedly - if a column is shared by multiple clauses, it will
- * be counted once for each clause (covered by the statistics).
- * So with two clauses [(a=1 OR b=2),(a<2 OR c>1)] the column "a"
- * will be counted twice (if both clauses are covered).
- *
- * The values for reduded statistics (that can't be applied) are
- * not computed, because that'd be pointless.
- */
- int *num_cov_clauses = (int*)palloc0(sizeof(int) * nmvstats);
- int *num_cov_columns = (int*)palloc0(sizeof(int) * nmvstats);
-
- /*
- * Same as above, but this only includes clauses that are already
- * covered by the previous stats (and the current one).
- */
- int *num_cond_clauses = (int*)palloc0(sizeof(int) * nmvstats);
- int *num_cond_columns = (int*)palloc0(sizeof(int) * nmvstats);
-
- /*
- * Number of attributes for each clause.
- *
- * TODO Might be computed in choose_mv_statistics() and then passed
- * here, but then the function would not have the same signature
- * as _exhaustive().
- */
- int *attnum_counts = (int*)palloc0(sizeof(int) * nclauses);
- int *attnum_cond_counts = (int*)palloc0(sizeof(int) * nconditions);
-
- CHECK_FOR_INTERRUPTS();
-
- Assert(best != NULL);
- Assert((step == 0 && current == NULL) || (step > 0 && current != NULL));
-
- /* compute attributes (columns) for each clause */
- for (i = 0; i < nclauses; i++)
- attnum_counts[i] = bms_num_members(clauses_attnums[i]);
-
- /* compute attributes (columns) for each condition */
- for (i = 0; i < nconditions; i++)
- attnum_cond_counts[i] = bms_num_members(conditions_attnums[i]);
-
- /* see which clauses are already covered at this point (by previous stats) */
- for (i = 0; i < step; i++)
- for (j = 0; j < nclauses; j++)
- covered_clauses[j] |= (cover_map[current->stats[i] * nclauses + j]);
-
- /* which remaining statistics covers most clauses / uses most conditions? */
- for (i = 0; i < nmvstats; i++)
- {
- Bitmapset *attnums_covered = NULL;
- Bitmapset *attnums_conditions = NULL;
-
- /* skip stats that are already ruled out (either used or inapplicable) */
- if (ruled_out[i] != -1)
- continue;
-
- /* count covered clauses and conditions (for the statistics) */
- for (j = 0; j < nclauses; j++)
- {
- if (cover_map[i * nclauses + j])
- {
- Bitmapset *attnums_new
- = bms_union(attnums_covered, clauses_attnums[j]);
-
- /* get rid of the old bitmap and keep the unified result */
- bms_free(attnums_covered);
- attnums_covered = attnums_new;
-
- num_cov_clauses[i] += 1;
- num_cov_columns[i] += attnum_counts[j];
-
- /* is the clause already covered (i.e. a condition)? */
- if (covered_clauses[j])
- {
- num_cond_clauses[i] += 1;
- num_cond_columns[i] += attnum_counts[j];
- attnums_new = bms_union(attnums_conditions,
- clauses_attnums[j]);
-
- bms_free(attnums_conditions);
- attnums_conditions = attnums_new;
- }
- }
- }
-
- /* if all covered clauses are covered by prev stats (thus conditions) */
- if (num_cov_clauses[i] == num_cond_clauses[i])
- ruled_out[i] = step;
-
- /* same if there are no new attributes */
- else if (bms_num_members(attnums_conditions) == bms_num_members(attnums_covered))
- ruled_out[i] = step;
-
- bms_free(attnums_covered);
- bms_free(attnums_conditions);
-
- /* if the statistics is inapplicable, try the next one */
- if (ruled_out[i] != -1)
- continue;
-
- /* now let's walk through conditions and count the covered */
- for (j = 0; j < nconditions; j++)
- {
- if (condition_map[i * nconditions + j])
- {
- num_cond_clauses[i] += 1;
- num_cond_columns[i] += attnum_cond_counts[j];
- }
- }
-
- /* otherwise see if this improves the interesting metrics */
- gain = num_cond_columns[i] / (double)num_cov_columns[i];
-
- if (gain > max_gain)
- {
- max_gain = gain;
- best_stat = i;
- }
- }
-
- /*
- * Have we found a suitable statistics? Add it to the solution and
- * try next step.
- */
- if (best_stat != -1)
- {
- /* mark the statistics, so that we skip it in next steps */
- ruled_out[best_stat] = step;
-
- /* allocate current solution if necessary */
- if (current == NULL)
- {
- current = (mv_solution_t*)palloc0(sizeof(mv_solution_t));
- current->stats = (int*)palloc0(sizeof(int)*nmvstats);
- current->nstats = 0;
- current->nclauses = 0;
- current->nconditions = 0;
- }
-
- current->nclauses += num_cov_clauses[best_stat];
- current->nconditions += num_cond_clauses[best_stat];
- current->stats[step] = best_stat;
- current->nstats++;
-
- if (*best == NULL)
- {
- (*best) = (mv_solution_t*)palloc0(sizeof(mv_solution_t));
- (*best)->nstats = current->nstats;
- (*best)->nclauses = current->nclauses;
- (*best)->nconditions = current->nconditions;
-
- (*best)->stats = (int*)palloc0(sizeof(int)*nmvstats);
- memcpy((*best)->stats, current->stats, nmvstats * sizeof(int));
- }
- else
- {
- /* see if this is a better solution */
- double current_gain = (double)current->nconditions / current->nclauses;
- double best_gain = (double)(*best)->nconditions / (*best)->nclauses;
-
- if ((current_gain > best_gain) ||
- ((current_gain == best_gain) && (current->nstats < (*best)->nstats)))
- {
- (*best)->nstats = current->nstats;
- (*best)->nclauses = current->nclauses;
- (*best)->nconditions = current->nconditions;
- memcpy((*best)->stats, current->stats, nmvstats * sizeof(int));
- }
- }
-
- /*
- * The recursion only makes sense if we haven't covered all the
- * attributes (then adding stats is not really possible).
- */
- if ((step + 1) < nmvstats)
- choose_mv_statistics_greedy(root, step+1,
- nmvstats, mvstats, stats_attnums,
- nclauses, clauses, clauses_attnums,
- nconditions, conditions, conditions_attnums,
- cover_map, condition_map, ruled_out,
- current, best);
-
- /* reset the last step */
- current->nclauses -= num_cov_clauses[best_stat];
- current->nconditions -= num_cond_clauses[best_stat];
- current->nstats -= 1;
- current->stats[step] = 0;
-
- /* mark the statistics as usable again */
- ruled_out[best_stat] = -1;
- }
-
- /* reset all statistics eliminated in this step */
- for (i = 0; i < nmvstats; i++)
- if (ruled_out[i] == step)
- ruled_out[i] = -1;
-
- /* free everything allocated in this step */
- pfree(covered_clauses);
- pfree(attnum_counts);
- pfree(num_cov_clauses);
- pfree(num_cov_columns);
- pfree(num_cond_clauses);
- pfree(num_cond_columns);
-}
-
-/*
- * Chooses the combination of statistics, optimal for estimation of
- * a particular clause list.
- *
- * This only handles a 'preparation' shared by the exhaustive and greedy
- * implementations (see the previous methods), mostly trying to reduce
- * the size of the problem (eliminate clauses/statistics that can't be
- * really used in the solution).
- *
- * It also precomputes bitmaps for attributes covered by clauses and
- * statistics, so that we don't need to do that over and over in the
- * actual optimizations (as it's both CPU and memory intensive).
- *
- * TODO This will probably have to consider compatibility of clauses,
- * because 'dependencies' will probably work only with equality
- * clauses.
- *
- * TODO Another way to make the optimization problems smaller might
- * be splitting the statistics into several disjoint subsets, i.e.
- * if we can split the graph of statistics (after the elimination)
- * into multiple components (so that stats in different components
- * share no attributes), we can do the optimization for each
- * component separately.
- *
- * TODO If we could compute what is a "perfect solution" maybe we could
- * terminate the search after reaching ~90% of it? Say, if we knew
- * that we can cover 10 clauses and reuse 8 dependencies, maybe
- * covering 9 clauses and 7 dependencies would be OK?
- */
-static List*
-choose_mv_statistics(PlannerInfo *root, List *stats,
- List *clauses, List *conditions,
- Oid varRelid, SpecialJoinInfo *sjinfo)
-{
- int i;
- mv_solution_t *best = NULL;
- List *result = NIL;
-
- int nmvstats;
- MVStatisticInfo *mvstats;
-
- /* we only work with MCV lists and histograms here */
- int type = (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST);
-
- bool *clause_cover_map = NULL,
- *condition_cover_map = NULL;
- int *ruled_out = NULL;
-
- /* build bitmapsets for all stats and clauses */
- Bitmapset **stats_attnums;
- Bitmapset **clauses_attnums;
- Bitmapset **conditions_attnums;
-
- int nclauses, nconditions;
- Node ** clauses_array;
- Node ** conditions_array;
-
- /* copy lists, so that we can free them during elimination easily */
- clauses = list_copy(clauses);
- conditions = list_copy(conditions);
- stats = list_copy(stats);
-
- /*
- * Reduce the optimization problem size as much as possible.
- *
- * Eliminate clauses and conditions not covered by any statistics,
- * or statistics not matching at least two attributes (one of them
- * has to be in a regular clause).
- *
- * It's possible that removing a statistics in one iteration
- * eliminates clause in the next one, so we'll repeat this until we
- * eliminate no clauses/stats in that iteration.
- *
- * This can only happen after eliminating a statistics - clauses are
- * eliminated first, so statistics always reflect that.
- */
- while (true)
- {
- List *tmp;
-
- Bitmapset *compatible_attnums = NULL;
- Bitmapset *condition_attnums = NULL;
- Bitmapset *all_attnums = NULL;
-
- /*
- * Clauses
- *
- * Walk through clauses and keep only those covered by at least
- * one of the statistics we still have. We'll also keep info
- * about attnums in clauses (without conditions) so that we can
- * ignore stats covering just conditions (which is pointless).
- */
- tmp = filter_clauses(root, varRelid, sjinfo, type,
- stats, clauses, &compatible_attnums);
-
- /* discard the original list */
- list_free(clauses);
- clauses = tmp;
-
- /*
- * Conditions
- *
- * Walk through clauses and keep only those covered by at least
- * one of the statistics we still have. Also, collect bitmap of
- * attributes so that we can make sure we add at least one new
- * attribute (by comparing with clauses).
- */
- if (conditions != NIL)
- {
- tmp = filter_clauses(root, varRelid, sjinfo, type,
- stats, conditions, &condition_attnums);
-
- /* discard the original list */
- list_free(conditions);
- conditions = tmp;
- }
-
- /* get a union of attnums (from conditions and new clauses) */
- all_attnums = bms_union(compatible_attnums, condition_attnums);
-
- /*
- * Statisitics
- *
- * Walk through statistics and only keep those covering at least
- * one new attribute (excluding conditions) and at two attributes
- * in both clauses and conditions.
- */
- tmp = filter_stats(stats, compatible_attnums, all_attnums);
-
- /* if we've not eliminated anything, terminate */
- if (list_length(stats) == list_length(tmp))
- break;
-
- /* work only with filtered statistics from now */
- list_free(stats);
- stats = tmp;
- }
-
- /* only do the optimization if we have clauses/statistics */
- if ((list_length(stats) == 0) || (list_length(clauses) == 0))
- return NULL;
-
- /* remove redundant stats (stats covered by another stats) */
- stats = filter_redundant_stats(stats, clauses, conditions);
-
- /*
- * TODO We should sort the stats to make the order deterministic,
- * otherwise we may get different estimates on different
- * executions - if there are multiple "equally good" solutions,
- * we'll keep the first solution we see.
- *
- * Sorting by OID probably is not the right solution though,
- * because we'd like it to be somehow reproducible,
- * irrespectedly of the order of ADD STATISTICS commands.
- * So maybe statkeys?
- */
- mvstats = make_stats_array(stats, &nmvstats);
- stats_attnums = make_stats_attnums(mvstats, nmvstats);
-
- /* collect clauses an bitmap of attnums */
- clauses_array = make_clauses_array(clauses, &nclauses);
- clauses_attnums = make_clauses_attnums(root, varRelid, sjinfo, type,
- clauses_array, nclauses);
-
- /* collect conditions and bitmap of attnums */
- conditions_array = make_clauses_array(conditions, &nconditions);
- conditions_attnums = make_clauses_attnums(root, varRelid, sjinfo, type,
- conditions_array, nconditions);
-
- /*
- * Build bitmaps with info about which clauses/conditions are
- * covered by each statistics (so that we don't need to call the
- * bms_is_subset over and over again).
- */
- clause_cover_map = make_cover_map(stats_attnums, nmvstats,
- clauses_attnums, nclauses);
-
- condition_cover_map = make_cover_map(stats_attnums, nmvstats,
- conditions_attnums, nconditions);
-
- ruled_out = (int*)palloc0(nmvstats * sizeof(int));
-
- /* no stats are ruled out by default */
- for (i = 0; i < nmvstats; i++)
- ruled_out[i] = -1;
-
- /* do the optimization itself */
- if (mvstat_search_type == MVSTAT_SEARCH_EXHAUSTIVE)
- choose_mv_statistics_exhaustive(root, 0,
- nmvstats, mvstats, stats_attnums,
- nclauses, clauses_array, clauses_attnums,
- nconditions, conditions_array, conditions_attnums,
- clause_cover_map, condition_cover_map,
- ruled_out, NULL, &best);
- else
- choose_mv_statistics_greedy(root, 0,
- nmvstats, mvstats, stats_attnums,
- nclauses, clauses_array, clauses_attnums,
- nconditions, conditions_array, conditions_attnums,
- clause_cover_map, condition_cover_map,
- ruled_out, NULL, &best);
-
- /* create a list of statistics from the array */
- if (best != NULL)
- {
- for (i = 0; i < best->nstats; i++)
- {
- MVStatisticInfo *info = makeNode(MVStatisticInfo);
- memcpy(info, &mvstats[best->stats[i]], sizeof(MVStatisticInfo));
- result = lappend(result, info);
- }
- pfree(best);
- }
-
- /* cleanup (maybe leave it up to the memory context?) */
- for (i = 0; i < nmvstats; i++)
- bms_free(stats_attnums[i]);
-
- for (i = 0; i < nclauses; i++)
- bms_free(clauses_attnums[i]);
-
- for (i = 0; i < nconditions; i++)
- bms_free(conditions_attnums[i]);
-
- pfree(stats_attnums);
- pfree(clauses_attnums);
- pfree(conditions_attnums);
-
- pfree(clauses_array);
- pfree(conditions_array);
- pfree(clause_cover_map);
- pfree(condition_cover_map);
- pfree(ruled_out);
- pfree(mvstats);
-
- list_free(clauses);
- list_free(conditions);
- list_free(stats);
-
- return result;
-}
-
-
-/*
- * This splits the clauses list into two parts - one containing clauses
- * that will be evaluated using the chosen statistics, and the remaining
- * clauses (either non-mvcompatible, or not related to the histogram).
- */
-static List *
-clauselist_mv_split(PlannerInfo *root, SpecialJoinInfo *sjinfo,
- List *clauses, Oid varRelid, List **mvclauses,
- MVStatisticInfo *mvstats, int types)
-{
- int i;
- ListCell *l;
- List *non_mvclauses = NIL;
-
- /* FIXME is there a better way to get info on int2vector? */
- int2vector * attrs = mvstats->stakeys;
- int numattrs = mvstats->stakeys->dim1;
-
- Bitmapset *mvattnums = NULL;
-
- /* build bitmap of attributes covered by the stats, so we can
- * do bms_is_subset later */
- for (i = 0; i < numattrs; i++)
- mvattnums = bms_add_member(mvattnums, attrs->values[i]);
-
- /* erase the list of mv-compatible clauses */
- *mvclauses = NIL;
-
- foreach (l, clauses)
- {
- bool match = false; /* by default not mv-compatible */
- Bitmapset *attnums = NULL;
- Node *clause = (Node *) lfirst(l);
-
- if (clause_is_mv_compatible(root, clause, varRelid, NULL,
- &attnums, sjinfo, types))
- {
- /* are all the attributes part of the selected stats? */
- if (bms_is_subset(attnums, mvattnums))
- match = true;
- }
-
- /*
- * The clause matches the selected stats, so put it to the list
- * of mv-compatible clauses. Otherwise, keep it in the list of
- * 'regular' clauses (that may be selected later).
- */
- if (match)
- *mvclauses = lappend(*mvclauses, clause);
- else
- non_mvclauses = lappend(non_mvclauses, clause);
- }
-
- /*
- * Perform regular estimation using the clauses incompatible
- * with the chosen histogram (or MV stats in general).
- */
- return non_mvclauses;
-
-}
-
-/*
- * Determines whether the clause is compatible with multivariate stats,
- * and if it is, returns some additional information - varno (index
- * into simple_rte_array) and a bitmap of attributes. This is then
- * used to fetch related multivariate statistics.
- *
- * At this moment we only support basic conditions of the form
- *
- * variable OP constant
- *
- * where OP is one of [=,<,<=,>=,>] (which is however determined by
- * looking at the associated function for estimating selectivity, just
- * like with the single-dimensional case).
- *
- * TODO Support 'OR clauses' - shouldn't be all that difficult to
- * evaluate them using multivariate stats.
- */
-static bool
-clause_is_mv_compatible(PlannerInfo *root, Node *clause, Oid varRelid,
- Index *relid, Bitmapset **attnums, SpecialJoinInfo *sjinfo,
- int types)
-{
- Relids clause_relids;
- Relids left_relids;
- Relids right_relids;
-
- if (IsA(clause, RestrictInfo))
- {
- RestrictInfo *rinfo = (RestrictInfo *) clause;
-
- /* Pseudoconstants are not really interesting here. */
- if (rinfo->pseudoconstant)
- return false;
-
- /* get the actual clause from the RestrictInfo (it's not an OR clause) */
- clause = (Node*)rinfo->clause;
-
- /* we don't support join conditions at this moment */
- if (treat_as_join_clause(clause, rinfo, varRelid, sjinfo))
- return false;
-
- clause_relids = rinfo->clause_relids;
- left_relids = rinfo->left_relids;
- right_relids = rinfo->right_relids;
- }
- else if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
- {
- left_relids = pull_varnos(get_leftop((Expr*)clause));
- right_relids = pull_varnos(get_rightop((Expr*)clause));
-
- clause_relids = bms_union(left_relids,
- right_relids);
- }
- else
- {
- /* Not a binary opclause, so mark left/right relid sets as empty */
- left_relids = NULL;
- right_relids = NULL;
- /* and get the total relid set the hard way */
- clause_relids = pull_varnos((Node *) clause);
- }
-
- /*
- * Only simple opclauses and IS NULL tests are compatible with
- * multivariate stats at this point.
- */
- if ((is_opclause(clause))
- && (list_length(((OpExpr *) clause)->args) == 2))
- {
- OpExpr *expr = (OpExpr *) clause;
- bool varonleft = true;
- bool ok;
-
- /* is it 'variable op constant' ? */
- ok = (bms_membership(clause_relids) == BMS_SINGLETON) &&
- (is_pseudo_constant_clause_relids(lsecond(expr->args),
- right_relids) ||
- (varonleft = false,
- is_pseudo_constant_clause_relids(linitial(expr->args),
- left_relids)));
-
- if (ok)
- {
- Var * var = (varonleft) ? linitial(expr->args) : lsecond(expr->args);
-
- /*
- * Simple variables only - otherwise the planner_rt_fetch seems to fail
- * (return NULL).
- *
- * TODO Maybe use examine_variable() would fix that?
- */
- if (! (IsA(var, Var) && (varRelid == 0 || varRelid == var->varno)))
- return false;
-
- /*
- * Only consider this variable if (varRelid == 0) or when the varno
- * matches varRelid (see explanation at clause_selectivity).
- *
- * FIXME I suspect this may not be really necessary. The (varRelid == 0)
- * part seems to be enforced by treat_as_join_clause().
- */
- if (! ((varRelid == 0) || (varRelid == var->varno)))
- return false;
-
- /* Also skip special varno values, and system attributes ... */
- if ((IS_SPECIAL_VARNO(var->varno)) || (! AttrNumberIsForUserDefinedAttr(var->varattno)))
- return false;
-
- /* Lookup info about the base relation (we need to pass the OID out) */
- if (relid != NULL)
- *relid = var->varno;
-
- /*
- * If it's not a "<" or ">" or "=" operator, just ignore the
- * clause. Otherwise note the relid and attnum for the variable.
- * This uses the function for estimating selectivity, ont the
- * operator directly (a bit awkward, but well ...).
- */
- switch (get_oprrest(expr->opno))
- {
- case F_SCALARLTSEL:
- case F_SCALARGTSEL:
- /* not compatible with functional dependencies */
- if (types & (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST))
- {
- *attnums = bms_add_member(*attnums, var->varattno);
- return (types & (MV_CLAUSE_TYPE_MCV | MV_CLAUSE_TYPE_HIST));
- }
- return false;
-
- case F_EQSEL:
- *attnums = bms_add_member(*attnums, var->varattno);
- return true;
- }
- }
- }
- else if (IsA(clause, NullTest)
- && IsA(((NullTest*)clause)->arg, Var))
- {
- Var * var = (Var*)((NullTest*)clause)->arg;
-
- /*
- * Simple variables only - otherwise the planner_rt_fetch seems to fail
- * (return NULL).
- *
- * TODO Maybe use examine_variable() would fix that?
- */
- if (! (IsA(var, Var) && (varRelid == 0 || varRelid == var->varno)))
- return false;
-
- /*
- * Only consider this variable if (varRelid == 0) or when the varno
- * matches varRelid (see explanation at clause_selectivity).
- *
- * FIXME I suspect this may not be really necessary. The (varRelid == 0)
- * part seems to be enforced by treat_as_join_clause().
- */
- if (! ((varRelid == 0) || (varRelid == var->varno)))
- return false;
-
- /* Also skip special varno values, and system attributes ... */
- if ((IS_SPECIAL_VARNO(var->varno)) || (! AttrNumberIsForUserDefinedAttr(var->varattno)))
- return false;
-
- /* Lookup info about the base relation (we need to pass the OID out) */
- if (relid != NULL)
- *relid = var->varno;
-
- *attnums = bms_add_member(*attnums, var->varattno);
-
- return true;
- }
- else if (or_clause(clause) || and_clause(clause))
- {
- /*
- * AND/OR-clauses are supported if all sub-clauses are supported
- *
- * TODO We might support mixed case, where some of the clauses
- * are supported and some are not, and treat all supported
- * subclauses as a single clause, compute it's selectivity
- * using mv stats, and compute the total selectivity using
- * the current algorithm.
- *
- * TODO For RestrictInfo above an OR-clause, we might use the
- * orclause with nested RestrictInfo - we won't have to
- * call pull_varnos() for each clause, saving time.
- */
- Bitmapset *tmp = NULL;
- ListCell *l;
- foreach (l, ((BoolExpr*)clause)->args)
- {
- if (! clause_is_mv_compatible(root, (Node*)lfirst(l),
- varRelid, relid, &tmp, sjinfo, types))
- return false;
- }
-
- /* add the attnums from the OR-clause to the set of attnums */
- *attnums = bms_join(*attnums, tmp);
-
- return true;
- }
-
- return false;
-}
-
-
-static Bitmapset *
-clause_mv_get_attnums(PlannerInfo *root, Node *clause)
-{
- Bitmapset * attnums = NULL;
-
- /* Extract clause from restrict info, if needed. */
- if (IsA(clause, RestrictInfo))
- clause = (Node*)((RestrictInfo*)clause)->clause;
-
- /*
- * Only simple opclauses and IS NULL tests are compatible with
- * multivariate stats at this point.
- */
- if ((is_opclause(clause))
- && (list_length(((OpExpr *) clause)->args) == 2))
- {
- OpExpr *expr = (OpExpr *) clause;
-
- if (IsA(linitial(expr->args), Var))
- attnums = bms_add_member(attnums,
- ((Var*)linitial(expr->args))->varattno);
- else
- attnums = bms_add_member(attnums,
- ((Var*)lsecond(expr->args))->varattno);
- }
- else if (IsA(clause, NullTest)
- && IsA(((NullTest*)clause)->arg, Var))
- {
- attnums = bms_add_member(attnums,
- ((Var*)((NullTest*)clause)->arg)->varattno);
- }
- else if (or_clause(clause) || and_clause(clause))
- {
- ListCell *l;
- foreach (l, ((BoolExpr*)clause)->args)
- {
- attnums = bms_join(attnums,
- clause_mv_get_attnums(root, (Node*)lfirst(l)));
- }
- }
-
- return attnums;
-}
-
-/*
- * Performs reduction of clauses using functional dependencies, i.e.
- * removes clauses that are considered redundant. It simply walks
- * through dependencies, and checks whether the dependency 'matches'
- * the clauses, i.e. if there's a clause matching the condition. If yes,
- * all clauses matching the implied part of the dependency are removed
- * from the list.
- *
- * This simply looks at attnums references by the clauses, not at the
- * type of the operator (equality, inequality, ...). This may not be the
- * right way to do - it certainly works best for equalities, which is
- * naturally consistent with functional dependencies (implications).
- * It's not clear that other operators are handled sensibly - for
- * example for inequalities, like
- *
- * WHERE (A >= 10) AND (B <= 20)
- *
- * and a trivial case where [A == B], resulting in symmetric pair of
- * rules [A => B], [B => A], it's rather clear we can't remove either of
- * those clauses.
- *
- * That only highlights that functional dependencies are most suitable
- * for label-like data, where using non-equality operators is very rare.
- * Using the common city/zipcode example, clauses like
- *
- * (zipcode <= 12345)
- *
- * or
- *
- * (cityname >= 'Washington')
- *
- * are rare. So restricting the reduction to equality should not harm
- * the usefulness / applicability.
- *
- * The other assumption is that this assumes 'compatible' clauses. For
- * example by using mismatching zip code and city name, this is unable
- * to identify the discrepancy and eliminates one of the clauses. The
- * usual approach (multiplying both selectivities) thus produces a more
- * accurate estimate, although mostly by luck - the multiplication
- * comes from assumption of statistical independence of the two
- * conditions (which is not not valid in this case), but moves the
- * estimate in the right direction (towards 0%).
- *
- * This might be somewhat improved by cross-checking the selectivities
- * against MCV and/or histogram.
- *
- * The implementation needs to be careful about cyclic rules, i.e. rules
- * like [A => B] and [B => A] at the same time. This must not reduce
- * clauses on both attributes at the same time.
- *
- * Technically we might consider selectivities here too, somehow. E.g.
- * when (A => B) and (B => A), we might use the clauses with minimum
- * selectivity.
- *
- * TODO Consider restricting the reduction to equality clauses. Or maybe
- * use equality classes somehow?
- *
- * TODO Merge this docs to dependencies.c, as it's saying mostly the
- * same things as the comments there.
- *
- * TODO Currently this is applied only to the top-level clauses, but
- * maybe we could apply it to lists at subtrees too, e.g. to the
- * two AND-clauses in
- *
- * (x=1 AND y=2) OR (z=3 AND q=10)
- *
- */
-static List *
-clauselist_apply_dependencies(PlannerInfo *root, List *clauses,
- Oid varRelid, List *stats,
- SpecialJoinInfo *sjinfo)
-{
- List *reduced_clauses = NIL;
- Index relid;
-
- /*
- * matrix of (natts x natts), 1 means x=>y
- *
- * This serves two purposes - first, it merges dependencies from all
- * the statistics, second it makes generating all the transitive
- * dependencies easier.
- *
- * We need to build this only for attributes from the dependencies,
- * not for all attributes in the table.
- *
- * We can't do that only for attributes from the clauses, because we
- * want to build transitive dependencies (including those going
- * through attributes not listed in the stats).
- *
- * This only works for A=>B dependencies, not sure how to do that
- * for complex dependencies.
- */
- bool *deps_matrix;
- int deps_natts; /* size of the matric */
-
- /* mapping attnum <=> matrix index */
- int *deps_idx_to_attnum;
- int *deps_attnum_to_idx;
-
- /* attnums in dependencies and clauses (and intersection) */
- List *deps_clauses = NIL;
- Bitmapset *deps_attnums = NULL;
- Bitmapset *clause_attnums = NULL;
- Bitmapset *intersect_attnums = NULL;
-
- /*
- * Is there at least one statistics with functional dependencies?
- * If not, return the original clauses right away.
- *
- * XXX Isn't this pointless, thanks to exactly the same check in
- * clauselist_selectivity()? Can we trigger the condition here?
- */
- if (! has_stats(stats, MV_CLAUSE_TYPE_FDEP))
- return clauses;
-
- /*
- * Build the dependency matrix, i.e. attribute adjacency matrix,
- * where 1 means (a=>b). Once we have the adjacency matrix, we'll
- * multiply it by itself, to get transitive dependencies.
- *
- * Note: This is pretty much transitive closure from graph theory.
- *
- * First, let's see what attributes are covered by functional
- * dependencies (sides of the adjacency matrix), and also a maximum
- * attribute (size of mapping to simple integer indexes);
- */
- deps_attnums = fdeps_collect_attnums(stats);
-
- /*
- * Walk through the clauses - clauses that are (one of)
- *
- * (a) not mv-compatible
- * (b) are using more than a single attnum
- * (c) using attnum not covered by functional depencencies
- *
- * may be copied directly to the result. The interesting clauses are
- * kept in 'deps_clauses' and will be processed later.
- */
- clause_attnums = fdeps_filter_clauses(root, clauses, deps_attnums,
- &reduced_clauses, &deps_clauses,
- varRelid, &relid, sjinfo);
-
- /*
- * we need at least two clauses referencing two different attributes
- * referencing to do the reduction
- */
- if ((list_length(deps_clauses) < 2) || (bms_num_members(clause_attnums) < 2))
- {
- bms_free(clause_attnums);
- list_free(reduced_clauses);
- list_free(deps_clauses);
-
- return clauses;
- }
-
-
- /*
- * We need at least two matching attributes in the clauses and
- * dependencies, otherwise we can't really reduce anything.
- */
- intersect_attnums = bms_intersect(clause_attnums, deps_attnums);
- if (bms_num_members(intersect_attnums) < 2)
- {
- bms_free(clause_attnums);
- bms_free(deps_attnums);
- bms_free(intersect_attnums);
-
- list_free(deps_clauses);
- list_free(reduced_clauses);
-
- return clauses;
- }
-
- /*
- * Build mapping between matrix indexes and attnums, and then the
- * adjacency matrix itself.
- */
- deps_idx_to_attnum = make_idx_to_attnum_mapping(deps_attnums);
- deps_attnum_to_idx = make_attnum_to_idx_mapping(deps_attnums);
-
- /* build the adjacency matrix */
- deps_matrix = build_adjacency_matrix(stats, deps_attnums,
- deps_idx_to_attnum,
- deps_attnum_to_idx);
-
- deps_natts = bms_num_members(deps_attnums);
-
- /*
- * Multiply the matrix N-times (N = size of the matrix), so that we
- * get all the transitive dependencies. That makes the next step
- * much easier and faster.
- *
- * This is essentially an adjacency matrix from graph theory, and
- * by multiplying it we get transitive edges. We don't really care
- * about the exact number (number of paths between vertices) though,
- * so we can do the multiplication in-place (we don't care whether
- * we found the dependency in this round or in the previous one).
- *
- * Track how many new dependencies were added, and stop when 0, but
- * we can't multiply more than N-times (longest path in the graph).
- */
- multiply_adjacency_matrix(deps_matrix, deps_natts);
-
- /*
- * Walk through the clauses, and see which other clauses we may
- * reduce. The matrix contains all transitive dependencies, which
- * makes this very fast.
- *
- * We have to be careful not to reduce the clause using itself, or
- * reducing all clauses forming a cycle (so we have to skip already
- * eliminated clauses).
- *
- * I'm not sure whether this guarantees finding the best solution,
- * i.e. reducing the most clauses, but it probably does (thanks to
- * having all the transitive dependencies).
- */
- deps_clauses = fdeps_reduce_clauses(deps_clauses,
- deps_attnums, deps_matrix,
- deps_idx_to_attnum,
- deps_attnum_to_idx, relid);
-
- /* join the two lists of clauses */
- reduced_clauses = list_union(reduced_clauses, deps_clauses);
-
- pfree(deps_matrix);
- pfree(deps_idx_to_attnum);
- pfree(deps_attnum_to_idx);
-
- bms_free(deps_attnums);
- bms_free(clause_attnums);
- bms_free(intersect_attnums);
-
- return reduced_clauses;
-}
-
-static bool
-has_stats(List *stats, int type)
-{
- ListCell *s;
-
- foreach (s, stats)
- {
- MVStatisticInfo *stat = (MVStatisticInfo *)lfirst(s);
-
- if ((type & MV_CLAUSE_TYPE_FDEP) && stat->deps_built)
- return true;
-
- if ((type & MV_CLAUSE_TYPE_MCV) && stat->mcv_built)
- return true;
-
- if ((type & MV_CLAUSE_TYPE_HIST) && stat->hist_built)
- return true;
- }
-
- return false;
-}
-
-/*
- * Determing relid (either from varRelid or from clauses) and then
- * lookup stats using the relid.
- */
-static List *
-find_stats(PlannerInfo *root, List *clauses, Oid varRelid, Index *relid)
-{
- /* unknown relid by default */
- *relid = InvalidOid;
-
- /*
- * First we need to find the relid (index info simple_rel_array).
- * If varRelid is not 0, we already have it, otherwise we have to
- * look it up from the clauses.
- */
- if (varRelid != 0)
- *relid = varRelid;
- else
- {
- Relids relids = pull_varnos((Node*)clauses);
-
- /*
- * We only expect 0 or 1 members in the bitmapset. If there are
- * no vars, we'll get empty bitmapset, otherwise we'll get the
- * relid as the single member.
- *
- * FIXME For some reason we can get 2 relids here (e.g. \d in
- * psql does that).
- */
- if (bms_num_members(relids) == 1)
- *relid = bms_singleton_member(relids);
-
- bms_free(relids);
- }
-
- /*
- * if we found the relid, we can get the stats from simple_rel_array
- *
- * This only gets stats that are already built, because that's how
- * we load it into RelOptInfo (see get_relation_info), but we don't
- * detoast the whole stats yet. That'll be done later, after we
- * decide which stats to use.
- */
- if (*relid != InvalidOid)
- return root->simple_rel_array[*relid]->mvstatlist;
-
- return NIL;
-}
-
-static Bitmapset*
-fdeps_collect_attnums(List *stats)
-{
- ListCell *lc;
- Bitmapset *attnums = NULL;
-
- foreach (lc, stats)
- {
- int j;
- MVStatisticInfo *info = (MVStatisticInfo *)lfirst(lc);
-
- int2vector *stakeys = info->stakeys;
-
- /* skip stats without functional dependencies built */
- if (! info->deps_built)
- continue;
-
- for (j = 0; j < stakeys->dim1; j++)
- attnums = bms_add_member(attnums, stakeys->values[j]);
- }
-
- return attnums;
-}
-
-
-static int*
-make_idx_to_attnum_mapping(Bitmapset *attnums)
-{
- int attidx = 0;
- int attnum = -1;
-
- int *mapping = (int*)palloc0(bms_num_members(attnums) * sizeof(int));
-
- while ((attnum = bms_next_member(attnums, attnum)) >= 0)
- mapping[attidx++] = attnum;
-
- Assert(attidx == bms_num_members(attnums));
-
- return mapping;
-}
-
-static int*
-make_attnum_to_idx_mapping(Bitmapset *attnums)
-{
- int attidx = 0;
- int attnum = -1;
- int maxattnum = -1;
- int *mapping;
-
- while ((attnum = bms_next_member(attnums, attnum)) >= 0)
- maxattnum = attnum;
-
- mapping = (int*)palloc0((maxattnum+1) * sizeof(int));
-
- attnum = -1;
- while ((attnum = bms_next_member(attnums, attnum)) >= 0)
- mapping[attnum] = attidx++;
-
- Assert(attidx == bms_num_members(attnums));
-
- return mapping;
-}
-
-static bool*
-build_adjacency_matrix(List *stats, Bitmapset *attnums,
- int *idx_to_attnum, int *attnum_to_idx)
-{
- ListCell *lc;
- int natts = bms_num_members(attnums);
- bool *matrix = (bool*)palloc0(natts * natts * sizeof(bool));
-
- foreach (lc, stats)
- {
- int j;
- MVStatisticInfo *stat = (MVStatisticInfo *)lfirst(lc);
- MVDependencies dependencies = NULL;
-
- /* skip stats without functional dependencies built */
- if (! stat->deps_built)
- continue;
-
- /* fetch and deserialize dependencies */
- dependencies = load_mv_dependencies(stat->mvoid);
- if (dependencies == NULL)
- {
- elog(WARNING, "failed to deserialize func deps %d", stat->mvoid);
- continue;
- }
-
- /* set matrix[a,b] to 'true' if 'a=>b' */
- for (j = 0; j < dependencies->ndeps; j++)
- {
- int aidx = attnum_to_idx[dependencies->deps[j]->a];
- int bidx = attnum_to_idx[dependencies->deps[j]->b];
-
- /* a=> b */
- matrix[aidx * natts + bidx] = true;
- }
+ varRelid,
+ jointype,
+ sjinfo);
}
+ else if (IsA(clause, CurrentOfExpr))
+ {
+ /* CURRENT OF selects at most one row of its table */
+ CurrentOfExpr *cexpr = (CurrentOfExpr *) clause;
+ RelOptInfo *crel = find_base_rel(root, cexpr->cvarno);
- return matrix;
-}
-
-static void
-multiply_adjacency_matrix(bool *matrix, int natts)
-{
- int i;
-
- for (i = 0; i < natts; i++)
+ if (crel->tuples > 0)
+ s1 = 1.0 / crel->tuples;
+ }
+ else if (IsA(clause, RelabelType))
+ {
+ /* Not sure this case is needed, but it can't hurt */
+ s1 = clause_selectivity(root,
+ (Node *) ((RelabelType *) clause)->arg,
+ varRelid,
+ jointype,
+ sjinfo);
+ }
+ else if (IsA(clause, CoerceToDomain))
{
- int k, l, m;
- int nchanges = 0;
+ /* Not sure this case is needed, but it can't hurt */
+ s1 = clause_selectivity(root,
+ (Node *) ((CoerceToDomain *) clause)->arg,
+ varRelid,
+ jointype,
+ sjinfo);
+ }
- /* k => l */
- for (k = 0; k < natts; k++)
- {
- for (l = 0; l < natts; l++)
- {
- /* we already have this dependency */
- if (matrix[k * natts + l])
- continue;
+ /* Cache the result if possible */
+ if (cacheable)
+ {
+ if (jointype == JOIN_INNER)
+ rinfo->norm_selec = s1;
+ else
+ rinfo->outer_selec = s1;
+ }
- /* we don't really care about the exact value, just 0/1 */
- for (m = 0; m < natts; m++)
- {
- if (matrix[k * natts + m] * matrix[m * natts + l])
- {
- matrix[k * natts + l] = true;
- nchanges += 1;
- break;
- }
- }
- }
- }
+#ifdef SELECTIVITY_DEBUG
+ elog(DEBUG4, "clause_selectivity: s1 %f", s1);
+#endif /* SELECTIVITY_DEBUG */
- /* no transitive dependency added here, so terminate */
- if (nchanges == 0)
- break;
- }
+ return s1;
}
+
static List*
fdeps_reduce_clauses(List *clauses, Bitmapset *attnums, bool *matrix,
int *idx_to_attnum, int *attnum_to_idx, Index relid)
@@ -3427,55 +1211,6 @@ fdeps_reduce_clauses(List *clauses, Bitmapset *attnums, bool *matrix,
}
-static Bitmapset *
-fdeps_filter_clauses(PlannerInfo *root,
- List *clauses, Bitmapset *deps_attnums,
- List **reduced_clauses, List **deps_clauses,
- Oid varRelid, Index *relid, SpecialJoinInfo *sjinfo)
-{
- ListCell *lc;
- Bitmapset *clause_attnums = NULL;
-
- foreach (lc, clauses)
- {
- Bitmapset *attnums = NULL;
- Node *clause = (Node *) lfirst(lc);
-
- if (! clause_is_mv_compatible(root, clause, varRelid, relid, &attnums,
- sjinfo, MV_CLAUSE_TYPE_FDEP))
-
- /* clause incompatible with functional dependencies */
- *reduced_clauses = lappend(*reduced_clauses, clause);
-
- else if (bms_num_members(attnums) > 1)
-
- /*
- * clause referencing multiple attributes (strange, should
- * this be handled by clause_is_mv_compatible directly)
- */
- *reduced_clauses = lappend(*reduced_clauses, clause);
-
- else if (! bms_is_member(bms_singleton_member(attnums), deps_attnums))
-
- /* clause not covered by the dependencies */
- *reduced_clauses = lappend(*reduced_clauses, clause);
-
- else
- {
- /* ok, clause compatible with existing dependencies */
- Assert(bms_num_members(attnums) == 1);
-
- *deps_clauses = lappend(*deps_clauses, clause);
- clause_attnums = bms_add_member(clause_attnums,
- bms_singleton_member(attnums));
- }
-
- bms_free(attnums);
- }
-
- return clause_attnums;
-}
-
/*
* Pull varattnos from the clauses, similarly to pull_varattnos() but:
*
@@ -3509,162 +1244,6 @@ get_varattnos(Node * node, Index relid)
return result;
}
-/*
- * Estimate selectivity of clauses using a MCV list.
- *
- * If there's no MCV list for the stats, the function returns 0.0.
- *
- * While computing the estimate, the function checks whether all the
- * columns were matched with an equality condition. If that's the case,
- * we can skip processing the histogram, as there can be no rows in
- * it with the same values - all the rows matching the condition are
- * represented by the MCV item. This can only happen with equality
- * on all the attributes.
- *
- * The algorithm works like this:
- *
- * 1) mark all items as 'match'
- * 2) walk through all the clauses
- * 3) for a particular clause, walk through all the items
- * 4) skip items that are already 'no match'
- * 5) check clause for items that still match
- * 6) sum frequencies for items to get selectivity
- *
- * The function also returns the frequency of the least frequent item
- * on the MCV list, which may be useful for clamping estimate from the
- * histogram (all items not present in the MCV list are less frequent).
- * This however seems useful only for cases with conditions on all
- * attributes.
- *
- * TODO This only handles AND-ed clauses, but it might work for OR-ed
- * lists too - it just needs to reverse the logic a bit. I.e. start
- * with 'no match' for all items, and mark the items as a match
- * as the clauses are processed (and skip items that are 'match').
- */
-static Selectivity
-clauselist_mv_selectivity_mcvlist(PlannerInfo *root, MVStatisticInfo *mvstats,
- List *clauses, List *conditions, bool is_or,
- bool *fullmatch, Selectivity *lowsel)
-{
- int i;
- Selectivity s = 0.0;
- Selectivity t = 0.0;
- Selectivity u = 0.0;
-
- MCVList mcvlist = NULL;
-
- int nmatches = 0;
- int nconditions = 0;
-
- /* match/mismatch bitmap for each MCV item */
- char * matches = NULL;
- char * condition_matches = NULL;
-
- Assert(clauses != NIL);
- Assert(list_length(clauses) >= 1);
-
- /* there's no MCV list built yet */
- if (! mvstats->mcv_built)
- return 0.0;
-
- mcvlist = load_mv_mcvlist(mvstats->mvoid);
-
- Assert(mcvlist != NULL);
- Assert(mcvlist->nitems > 0);
-
- /* number of matching MCV items */
- nmatches = mcvlist->nitems;
- nconditions = mcvlist->nitems;
-
- /*
- * Bitmap of bucket matches (mismatch, partial, full).
- *
- * For AND clauses all buckets match (and we'll eliminate them).
- * For OR clauses no buckets match (and we'll add them).
- *
- * We only need to do the memset for AND clauses (for OR clauses
- * it's already set correctly by the palloc0).
- */
- matches = palloc0(sizeof(char) * nmatches);
-
- if (! is_or) /* AND-clause */
- memset(matches, MVSTATS_MATCH_FULL, sizeof(char)*nmatches);
-
- /* Conditions are treated as AND clause, so match by default. */
- condition_matches = palloc0(sizeof(char) * nconditions);
- memset(condition_matches, MVSTATS_MATCH_FULL, sizeof(char)*nconditions);
-
- /*
- * build the match bitmap for the conditions (conditions are always
- * connected by AND)
- */
- if (conditions != NIL)
- nconditions = update_match_bitmap_mcvlist(root, conditions,
- mvstats->stakeys, mcvlist,
- nconditions, condition_matches,
- lowsel, fullmatch, false);
-
- /*
- * build the match bitmap for the estimated clauses
- *
- * TODO This evaluates the clauses for all MCV items, even those
- * ruled out by the conditions. The final result should be the
- * same, but it might be faster.
- */
- nmatches = update_match_bitmap_mcvlist(root, clauses,
- mvstats->stakeys, mcvlist,
- ((is_or) ? 0 : nmatches), matches,
- lowsel, fullmatch, is_or);
-
- /* sum frequencies for all the matching MCV items */
- for (i = 0; i < mcvlist->nitems; i++)
- {
- /*
- * Find out what part of the data is covered by the MCV list,
- * so that we can 'scale' the selectivity properly (e.g. when
- * only 50% of the sample items got into the MCV, and the rest
- * is either in a histogram, or not covered by stats).
- *
- * TODO This might be handled by keeping a global "frequency"
- * for the whole list, which might save us a bit of time
- * spent on accessing the not-matching part of the MCV list.
- * Although it's likely in a cache, so it's very fast.
- */
- u += mcvlist->items[i]->frequency;
-
- /* skit MCV items not matching the conditions */
- if (condition_matches[i] == MVSTATS_MATCH_NONE)
- continue;
-
- if (matches[i] != MVSTATS_MATCH_NONE)
- s += mcvlist->items[i]->frequency;
-
- t += mcvlist->items[i]->frequency;
- }
-
- pfree(matches);
- pfree(condition_matches);
- pfree(mcvlist);
-
- /* no condition matches */
- if (t == 0.0)
- return (Selectivity)0.0;
-
- return (s / t) * u;
-}
-
-/*
- * Evaluate clauses using the MCV list, and update the match bitmap.
- *
- * The bitmap may be already partially set, so this is really a way to
- * combine results of several clause lists - either when computing
- * conditional probability P(A|B) or a combination of AND/OR clauses.
- *
- * TODO This works with 'bitmap' where each bit is represented as a char,
- * which is slightly wasteful. Instead, we could use a regular
- * bitmap, reducing the size to ~1/8. Another thing is merging the
- * bitmaps using & and |, which might be faster than min/max.
- */
static int
update_match_bitmap_mcvlist(PlannerInfo *root, List *clauses,
int2vector *stakeys, MCVList mcvlist,
@@ -3952,213 +1531,58 @@ update_match_bitmap_mcvlist(PlannerInfo *root, List *clauses,
/* match/mismatch bitmap for each MCV item */
int tmp_nmatches = 0;
- char * tmp_matches = NULL;
-
- Assert(tmp_clauses != NIL);
- Assert(list_length(tmp_clauses) >= 2);
-
- /* number of matching MCV items */
- tmp_nmatches = (or_clause(clause)) ? 0 : mcvlist->nitems;
-
- /* by default none of the MCV items matches the clauses */
- tmp_matches = palloc0(sizeof(char) * mcvlist->nitems);
-
- /* AND clauses assume everything matches, initially */
- if (! or_clause(clause))
- memset(tmp_matches, MVSTATS_MATCH_FULL, sizeof(char)*mcvlist->nitems);
-
- /* build the match bitmap for the OR-clauses */
- tmp_nmatches = update_match_bitmap_mcvlist(root, tmp_clauses,
- stakeys, mcvlist,
- tmp_nmatches, tmp_matches,
- lowsel, fullmatch, or_clause(clause));
-
- /* merge the bitmap into the existing one*/
- for (i = 0; i < mcvlist->nitems; i++)
- {
- /*
- * To AND-merge the bitmaps, a MIN() semantics is used.
- * For OR-merge, use MAX().
- *
- * FIXME this does not decrease the number of matches
- */
- UPDATE_RESULT(matches[i], tmp_matches[i], is_or);
- }
-
- pfree(tmp_matches);
-
- }
- else
- elog(ERROR, "unknown clause type: %d", clause->type);
- }
-
- /*
- * If all the columns were matched by equality, it's a full match.
- * In this case there can be just a single MCV item, matching the
- * clause (if there were two, both would match the other one).
- */
- *fullmatch = (bms_num_members(eqmatches) == mcvlist->ndimensions);
-
- /* free the allocated pieces */
- if (eqmatches)
- pfree(eqmatches);
-
- return nmatches;
-}
-
-/*
- * Estimate selectivity of clauses using a histogram.
- *
- * If there's no histogram for the stats, the function returns 0.0.
- *
- * The general idea of this method is similar to how MCV lists are
- * processed, except that this introduces the concept of a partial
- * match (MCV only works with full match / mismatch).
- *
- * The algorithm works like this:
- *
- * 1) mark all buckets as 'full match'
- * 2) walk through all the clauses
- * 3) for a particular clause, walk through all the buckets
- * 4) skip buckets that are already 'no match'
- * 5) check clause for buckets that still match (at least partially)
- * 6) sum frequencies for buckets to get selectivity
- *
- * Unlike MCV lists, histograms have a concept of a partial match. In
- * that case we use 1/2 the bucket, to minimize the average error. The
- * MV histograms are usually less detailed than the per-column ones,
- * meaning the sum is often quite high (thanks to combining a lot of
- * "partially hit" buckets).
- *
- * Maybe we could use per-bucket information with number of distinct
- * values it contains (for each dimension), and then use that to correct
- * the estimate (so with 10 distinct values, we'd use 1/10 of the bucket
- * frequency). We might also scale the value depending on the actual
- * ndistinct estimate (not just the values observed in the sample).
- *
- * Another option would be to multiply the selectivities, i.e. if we get
- * 'partial match' for a bucket for multiple conditions, we might use
- * 0.5^k (where k is the number of conditions), instead of 0.5. This
- * probably does not minimize the average error, though.
- *
- * TODO This might use a similar shortcut to MCV lists - count buckets
- * marked as partial/full match, and terminate once this drop to 0.
- * Not sure if it's really worth it - for MCV lists a situation like
- * this is not uncommon, but for histograms it's not that clear.
- */
-static Selectivity
-clauselist_mv_selectivity_histogram(PlannerInfo *root, MVStatisticInfo *mvstats,
- List *clauses, List *conditions, bool is_or)
-{
- int i;
- Selectivity s = 0.0;
- Selectivity t = 0.0;
- Selectivity u = 0.0;
-
- int nmatches = 0;
- int nconditions = 0;
- char *matches = NULL;
- char *condition_matches = NULL;
-
- MVSerializedHistogram mvhist = NULL;
-
- /* there's no histogram */
- if (! mvstats->hist_built)
- return 0.0;
-
- /* There may be no histogram in the stats (check hist_built flag) */
- mvhist = load_mv_histogram(mvstats->mvoid);
-
- Assert (mvhist != NULL);
- Assert (clauses != NIL);
- Assert (list_length(clauses) >= 1);
-
- nmatches = mvhist->nbuckets;
- nconditions = mvhist->nbuckets;
-
- /*
- * Bitmap of bucket matches (mismatch, partial, full).
- *
- * For AND clauses all buckets match (and we'll eliminate them).
- * For OR clauses no buckets match (and we'll add them).
- *
- * We only need to do the memset for AND clauses (for OR clauses
- * it's already set correctly by the palloc0).
- */
- matches = palloc0(sizeof(char) * nmatches);
-
- if (! is_or) /* AND-clause */
- memset(matches, MVSTATS_MATCH_FULL, sizeof(char)*nmatches);
+ char * tmp_matches = NULL;
- /* Conditions are treated as AND clause, so match by default. */
- condition_matches = palloc0(sizeof(char)*nconditions);
- memset(condition_matches, MVSTATS_MATCH_FULL, sizeof(char)*nconditions);
+ Assert(tmp_clauses != NIL);
+ Assert(list_length(tmp_clauses) >= 2);
- /* build the match bitmap for the conditions */
- if (conditions != NIL)
- update_match_bitmap_histogram(root, conditions,
- mvstats->stakeys, mvhist,
- nconditions, condition_matches, is_or);
+ /* number of matching MCV items */
+ tmp_nmatches = (or_clause(clause)) ? 0 : mcvlist->nitems;
- /*
- * build the match bitmap for the estimated clauses
- *
- * TODO This evaluates the clauses for all buckets, even those
- * ruled out by the conditions. The final result should be
- * the same, but it might be faster.
- */
- update_match_bitmap_histogram(root, clauses,
- mvstats->stakeys, mvhist,
- ((is_or) ? 0 : nmatches), matches,
- is_or);
+ /* by default none of the MCV items matches the clauses */
+ tmp_matches = palloc0(sizeof(char) * mcvlist->nitems);
- /* now, walk through the buckets and sum the selectivities */
- for (i = 0; i < mvhist->nbuckets; i++)
- {
- float coeff = 1.0;
+ /* AND clauses assume everything matches, initially */
+ if (! or_clause(clause))
+ memset(tmp_matches, MVSTATS_MATCH_FULL, sizeof(char)*mcvlist->nitems);
- /*
- * Find out what part of the data is covered by the histogram,
- * so that we can 'scale' the selectivity properly (e.g. when
- * only 50% of the sample got into the histogram, and the rest
- * is in a MCV list).
- *
- * TODO This might be handled by keeping a global "frequency"
- * for the whole histogram, which might save us some time
- * spent accessing the not-matching part of the histogram.
- * Although it's likely in a cache, so it's very fast.
- */
- u += mvhist->buckets[i]->ntuples;
+ /* build the match bitmap for the OR-clauses */
+ tmp_nmatches = update_match_bitmap_mcvlist(root, tmp_clauses,
+ stakeys, mcvlist,
+ tmp_nmatches, tmp_matches,
+ lowsel, fullmatch, or_clause(clause));
- /* skip buckets not matching the conditions */
- if (condition_matches[i] == MVSTATS_MATCH_NONE)
- continue;
- else if (condition_matches[i] == MVSTATS_MATCH_PARTIAL)
- coeff = 0.5;
+ /* merge the bitmap into the existing one*/
+ for (i = 0; i < mcvlist->nitems; i++)
+ {
+ /*
+ * To AND-merge the bitmaps, a MIN() semantics is used.
+ * For OR-merge, use MAX().
+ *
+ * FIXME this does not decrease the number of matches
+ */
+ UPDATE_RESULT(matches[i], tmp_matches[i], is_or);
+ }
- t += coeff * mvhist->buckets[i]->ntuples;
+ pfree(tmp_matches);
- if (matches[i] == MVSTATS_MATCH_FULL)
- s += coeff * mvhist->buckets[i]->ntuples;
- else if (matches[i] == MVSTATS_MATCH_PARTIAL)
- /*
- * TODO If both conditions and clauses match partially, this
- * will use 0.25 match - not sure if that's the right
- * thing solution, but seems about right.
- */
- s += coeff * 0.5 * mvhist->buckets[i]->ntuples;
+ }
+ else
+ elog(ERROR, "unknown clause type: %d", clause->type);
}
- /* release the allocated bitmap and deserialized histogram */
- pfree(matches);
- pfree(condition_matches);
- pfree(mvhist);
+ /*
+ * If all the columns were matched by equality, it's a full match.
+ * In this case there can be just a single MCV item, matching the
+ * clause (if there were two, both would match the other one).
+ */
+ *fullmatch = (bms_num_members(eqmatches) == mcvlist->ndimensions);
- /* no condition matches */
- if (t == 0.0)
- return (Selectivity)0.0;
+ /* free the allocated pieces */
+ if (eqmatches)
+ pfree(eqmatches);
- return (s / t) * u;
+ return nmatches;
}
/*
@@ -4715,362 +2139,463 @@ update_match_bitmap_histogram(PlannerInfo *root, List *clauses,
return nmatches;
}
-/*
- * Walk through clauses and keep only those covered by at least
- * one of the statistics.
- */
-static List *
-filter_clauses(PlannerInfo *root, Oid varRelid, SpecialJoinInfo *sjinfo,
- int type, List *stats, List *clauses, Bitmapset **attnums)
+static Node *
+stripRestrictStatData(List *clauses, BoolExprType boolop, Bitmapset **attrs)
{
- ListCell *c;
- ListCell *s;
-
- /* results (list of compatible clauses, attnums) */
- List *rclauses = NIL;
+ Expr *newexpr;
+ ListCell *lc;
- foreach (c, clauses)
+ if (attrs) *attrs = NULL;
+
+ if (list_length(clauses) == 0)
+ newexpr = NULL;
+ else if (list_length(clauses) == 1)
{
- Node *clause = (Node*)lfirst(c);
- Bitmapset *clause_attnums = NULL;
- Index relid;
+ RestrictStatData *rsd = (RestrictStatData *) linitial(clauses);
+ Assert(IsA(rsd, RestrictStatData));
- /*
- * The clause has to be mv-compatible (suitable operators etc.).
- */
- if (! clause_is_mv_compatible(root, clause, varRelid,
- &relid, &clause_attnums, sjinfo, type))
- elog(ERROR, "should not get non-mv-compatible cluase");
+ newexpr = (Expr*)(rsd->clause);
+ if (attrs) *attrs = rsd->mvattrs;
+ }
+ else
+ {
+ BoolExpr *newboolexpr;
+ newboolexpr = makeNode(BoolExpr);
+ newboolexpr->boolop = boolop;
- /* is there a statistics covering this clause? */
- foreach (s, stats)
+ foreach (lc, clauses)
{
- int k, matches = 0;
- MVStatisticInfo *stat = (MVStatisticInfo *)lfirst(s);
-
- for (k = 0; k < stat->stakeys->dim1; k++)
- {
- if (bms_is_member(stat->stakeys->values[k],
- clause_attnums))
- matches += 1;
- }
-
- /*
- * The clause is compatible if all attributes it references
- * are covered by the statistics.
- */
- if (bms_num_members(clause_attnums) == matches)
- {
- *attnums = bms_union(*attnums, clause_attnums);
- rclauses = lappend(rclauses, clause);
- break;
- }
+ RestrictStatData *rsd = (RestrictStatData *) lfirst(lc);
+ Assert(IsA(rsd, RestrictStatData));
+ newboolexpr->args =
+ lappend(newboolexpr->args, rsd->clause);
+ if (attrs)
+ *attrs = bms_add_members(*attrs, rsd->mvattrs);
}
-
- bms_free(clause_attnums);
+ newexpr = (Expr*) newboolexpr;
}
- /* we can't have more compatible conditions than source conditions */
- Assert(list_length(clauses) >= list_length(rclauses));
-
- return rclauses;
+ return (Node*)newexpr;
}
-
-/*
- * Walk through statistics and only keep those covering at least
- * one new attribute (excluding conditions) and at two attributes
- * in both clauses and conditions.
- *
- * This check might be made more strict by checking against individual
- * clauses, because by using the bitmapsets of all attnums we may
- * actually use attnums from clauses that are not covered by the
- * statistics. For example, we may have a condition
- *
- * (a=1 AND b=2)
- *
- * and a new clause
- *
- * (c=1 AND d=1)
- *
- * With only bitmapsets, statistics on [b,c] will pass through this
- * (assuming there are some statistics covering both clases).
- *
- * TODO Do the more strict check.
- */
-static List *
-filter_stats(List *stats, Bitmapset *new_attnums, Bitmapset *all_attnums)
+RestrictStatData *
+transformRestrictInfoForEstimate(PlannerInfo *root, List *clauses,
+ int relid, SpecialJoinInfo *sjinfo)
{
- ListCell *s;
- List *stats_filtered = NIL;
+ static int level = 0;
+ int i = -1;
+ char head[100];
+ RestrictStatData *rdata = makeNode(RestrictStatData);
+ Node *clause;
- foreach (s, stats)
+ memset(head, '.', 100);
+ head[level] = 0;
+
+ if (list_length(clauses) == 1 &&
+ !IsA((Node*)linitial(clauses), RestrictInfo))
{
- int k;
- int matches_new = 0,
- matches_all = 0;
-
- MVStatisticInfo *stat = (MVStatisticInfo *)lfirst(s);
-
- /* see how many attributes the statistics covers */
- for (k = 0; k < stat->stakeys->dim1; k++)
- {
- /* attributes from new clauses */
- if (bms_is_member(stat->stakeys->values[k], new_attnums))
- matches_new += 1;
-
- /* attributes from onditions */
- if (bms_is_member(stat->stakeys->values[k], all_attnums))
- matches_all += 1;
- }
-
- /* check we have enough attributes for this statistics */
- if ((matches_new >= 1) && (matches_all >= 2))
- stats_filtered = lappend(stats_filtered, stat);
+ Assert(relid > 0);
+ clause = (Node*)linitial(clauses);
}
+ else
+ {
+ /* This is top level clauselist. Convert it to and expression */
+ ListCell *lc;
+ Index clauserelid = 0;
+ Relids relids = pull_varnos((Node*)clauses);
- /* we can't have more useful stats than we had originally */
- Assert(list_length(stats) >= list_length(stats_filtered));
-
- return stats_filtered;
-}
+ if (bms_num_members(relids) != 1)
+ return NULL;
-static MVStatisticInfo *
-make_stats_array(List *stats, int *nmvstats)
-{
- int i;
- ListCell *l;
+ clauserelid = bms_singleton_member(relids);
+ if (relid != 0 && relid != clauserelid)
+ return NULL;
- MVStatisticInfo *mvstats = NULL;
- *nmvstats = list_length(stats);
+ relid = clauserelid;
- mvstats
- = (MVStatisticInfo*)palloc0((*nmvstats) * sizeof(MVStatisticInfo));
+ if (list_length(clauses) == 1)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) linitial(clauses);
+ Assert(IsA(rinfo, RestrictInfo));
+
+ clause = (Node*) rinfo->clause;
+ }
+ else
+ {
+ BoolExpr *andexpr = makeNode(BoolExpr);
+ andexpr->boolop = AND_EXPR;
+ foreach (lc, clauses)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+
+ Assert(IsA(rinfo, RestrictInfo));
+ if (rinfo->pseudoconstant ||
+ treat_as_join_clause((Node*)rinfo->clause,
+ rinfo, 0, sjinfo))
+ rdata->unusedrinfos = lappend(rdata->unusedrinfos,
+ rinfo);
+ else
+ andexpr->args = lappend(andexpr->args, rinfo->clause);
+ }
+ clause = (Node*)andexpr;
+ }
- i = 0;
- foreach (l, stats)
- {
- MVStatisticInfo *stat = (MVStatisticInfo *)lfirst(l);
- memcpy(&mvstats[i++], stat, sizeof(MVStatisticInfo));
}
- return mvstats;
-}
-
-static Bitmapset **
-make_stats_attnums(MVStatisticInfo *mvstats, int nmvstats)
-{
- int i, j;
- Bitmapset **stats_attnums = NULL;
-
- Assert(nmvstats > 0);
+ Assert(!IsA(clause, RestrictInfo));
- /* build bitmaps of attnums for the stats (easier to compare) */
- stats_attnums = (Bitmapset **)palloc0(nmvstats * sizeof(Bitmapset*));
+ rdata->clause = clause;
+ rdata->boolop = AND_EXPR;
- for (i = 0; i < nmvstats; i++)
- for (j = 0; j < mvstats[i].stakeys->dim1; j++)
- stats_attnums[i]
- = bms_add_member(stats_attnums[i],
- mvstats[i].stakeys->values[j]);
+ if (and_clause(clause) || or_clause(clause))
+ {
+ BoolExpr *boolexpr = (BoolExpr *)clause;
+ ListCell *lc;
+ List *mvclauses = NIL;
+ List *nonmvclauses = NIL;
+ List *partialclauses = NIL;
+ Bitmapset *resultattrs = NULL;
+ List *resultstats = NIL;
- return stats_attnums;
-}
+ rdata->boolop = boolexpr->boolop;
+ ereport(DEBUG1,
+ (errmsg ("%s%s[%d][%d](%d)",
+ head,
+ and_clause(clause)?"AND":
+ (or_clause(clause)?"OR":"NOT"),
+ level, i, list_length(boolexpr->args)),
+ errhidestmt(level)));
+ /* Recursively process the subexpressions */
+ level++;
+ foreach (lc, (boolexpr->args))
+ {
+ Node *nd = (Node*) lfirst(lc);
+ RestrictStatData *tmpsd;
-/*
- * Now let's remove redundant statistics, covering the same columns
- * as some other stats, when restricted to the attributes from
- * remaining clauses.
- *
- * If statistics S1 covers S2 (covers S2 attributes and possibly
- * some more), we can probably remove S2. What actually matters are
- * attributes from covered clauses (not all the attributes). This
- * might however prefer larger, and thus less accurate, statistics.
- *
- * When a redundancy is detected, we simply keep the smaller
- * statistics (less number of columns), on the assumption that it's
- * more accurate and faster to process. That might be incorrect for
- * two reasons - first, the accuracy really depends on number of
- * buckets/MCV items, not the number of columns. Second, we might
- * prefer MCV lists over histograms or something like that.
- */
-static List*
-filter_redundant_stats(List *stats, List *clauses, List *conditions)
-{
- int i, j, nmvstats;
+ tmpsd = transformRestrictInfoForEstimate(root,
+ list_make1(nd),
+ relid, sjinfo);
+ /*
+ * mvclauses is to hold the child RestrictStatData that
+ * potentially can be pulled-up to this node's mvclause, which is
+ * to be estimated using multivariate statistics.
+ *
+ * partialclauses is to hold the child RestrictStatData that
+ * cannot be pulled-up.
+ *
+ * nonmvclauses is to hold the child RestrictStatData to be
+ * pulled-up into the clause to be estimated in the normal way.
+ */
+ if (tmpsd->mvattrs)
+ mvclauses = lappend(mvclauses, tmpsd);
+ else if (tmpsd->mvclause)
+ partialclauses = lappend(partialclauses, tmpsd);
+ else
+ nonmvclauses = lappend(nonmvclauses, tmpsd);
+ }
+ level--;
- MVStatisticInfo *mvstats;
- bool *redundant;
- Bitmapset **stats_attnums;
- Bitmapset *varattnos;
- Index relid;
- Assert(list_length(stats) > 0);
- Assert(list_length(clauses) > 0);
+ if (list_length(mvclauses) == 1)
+ {
+ /*
+ * If this boolean clause has only one mv clause, pull it up for
+ * now.
+ */
+ RestrictStatData *rsd = (RestrictStatData *) linitial(mvclauses);
+ resultattrs = rsd->mvattrs;
+ resultstats = rsd->mvstats;
+ }
+ if (list_length(mvclauses) > 1)
+ {
+ /*
+ * Pick up the smallest mv-stats that covers as large part as
+ * possible of the attrutes appeard in the subclauses, then remove
+ * clauses that is not covered by the selected mv-stats.
+ */
+ int nmvstats = 0;
+ ListCell *lc;
+ bm_mvstat *mvstatslist[16];
+ int maxnattrs = 0;
+ int candidatestats;
+ int i;
+
+ /* Check functional dependency first, maybe.. */
+// if (list_length(mvclauses) == 2)
+// {
+// RestrictStatData *rsd1 =
+// (RestrictStatData *) linitial(mvclauses);
+// RestrictStatData *rsd2 =
+// (RestrictStatData *) lsecond(mvclauses);
+// /* To do more...*/
+// }
- /*
- * We'll convert the list of statistics into an array now, because
- * the reduction of redundant statistics is easier to do that way
- * (we can mark previous stats as redundant, etc.).
- */
- mvstats = make_stats_array(stats, &nmvstats);
- stats_attnums = make_stats_attnums(mvstats, nmvstats);
+ /*
+ * Collect all mvstats from all subclauses. Attribute set should
+ * be unique so use it as key. There should be not so many stats.
+ */
+ foreach (lc, mvclauses)
+ {
+ RestrictStatData *rsd = (RestrictStatData *) lfirst(lc);
+ Bitmapset *mvattrs = rsd->mvattrs;
+ ListCell *lcs;
- /* by default, none of the stats is redundant (so palloc0) */
- redundant = palloc0(nmvstats * sizeof(bool));
+ /* make a covering attribute set of all cluases */
+ resultattrs = bms_add_members(resultattrs, mvattrs);
- /*
- * We only expect a single relid here, and also we should get the
- * same relid from clauses and conditions (but we get it from
- * clauses, because those are certainly non-empty).
- */
- relid = bms_singleton_member(pull_varnos((Node*)clauses));
+ /* pick up new mv stats */
+ foreach (lcs, rsd->mvstats)
+ {
+ bm_mvstat *mvs = (bm_mvstat*) lfirst(lcs);
+ bool found = false;
- /*
- * Get the varattnos from both conditions and clauses.
- *
- * This skips system attributes, although that should be impossible
- * thanks to previous filtering out of incompatible clauses.
- *
- * XXX Is that really true?
- */
- varattnos = bms_union(get_varattnos((Node*)clauses, relid),
- get_varattnos((Node*)conditions, relid));
+ for (i = 0 ; !found && i < nmvstats ; i++)
+ {
+ if(bms_equal(mvstatslist[i]->attrs, mvs->attrs))
+ found = true;
+ }
+ if (!found)
+ {
+ mvstatslist[nmvstats] = mvs;
+ nmvstats++;
+ }
- for (i = 1; i < nmvstats; i++)
- {
- /* intersect with current statistics */
- Bitmapset *curr = bms_intersect(stats_attnums[i], varattnos);
+ /* ignore more than 15(!) stats for a clause */
+ if (nmvstats > 15)
+ break;
+ }
+ }
- /* walk through 'previous' stats and check redundancy */
- for (j = 0; j < i; j++)
- {
- /* intersect with current statistics */
- Bitmapset *prev;
+ /* we try functional dependency first? */
+ //if (clauseboolop == AND_EXPR && ...
+
+ /*
+ * find a mv stats covers the largest number of attribute used in
+ * the cluases and having the smallest attrubute set.
+ */
+ maxnattrs = 0;
+ candidatestats = -1;
+ for (i = 0 ; i < nmvstats ; i++)
+ {
+ Bitmapset *matchattr =
+ bms_intersect(resultattrs, mvstatslist[i]->attrs);
+ int nmatchattrs = bms_num_members(matchattr);
- /* skip stats already identified as redundant */
- if (redundant[j])
- continue;
+ if (maxnattrs < nmatchattrs)
+ {
+ candidatestats = i;
+ maxnattrs = nmatchattrs;
+ }
+ else if (maxnattrs > 0 && maxnattrs == nmatchattrs)
+ {
+ if (bms_num_members(mvstatslist[i]->attrs) <
+ bms_num_members(mvstatslist[candidatestats]->attrs))
+ candidatestats = i;
+ }
+ }
- prev = bms_intersect(stats_attnums[j], varattnos);
+ Assert(candidatestats >= 0);
- switch (bms_subset_compare(curr, prev))
+ if (maxnattrs == 1)
{
- case BMS_EQUAL:
+ /*
+ * No two of mvclauses share a mv statistics. Make this node
+ * non-mv.
+ */
+ mvclauses = NIL;
+ nonmvclauses = NIL;
+ resultattrs = NULL;
+ resultstats = NIL;
+ }
+ else
+ {
+ if (!bms_is_subset(resultattrs,
+ mvstatslist[candidatestats]->attrs))
+ {
/*
- * Use the smaller one (hopefully more accurate).
- * If both have the same size, use the first one.
+ * move out the clauses that is not covered by the
+ * candidate stats
*/
- if (mvstats[i].stakeys->dim1 >= mvstats[j].stakeys->dim1)
- redundant[i] = TRUE;
- else
- redundant[j] = TRUE;
-
- break;
-
- case BMS_SUBSET1: /* curr is subset of prev */
- redundant[i] = TRUE;
- break;
+ List *old_mvclauses = mvclauses;
+ ListCell *lc;
+ Bitmapset *statsattrs =
+ mvstatslist[candidatestats]->attrs;
+ mvclauses = NIL;
- case BMS_SUBSET2: /* prev is subset of curr */
- redundant[j] = TRUE;
- break;
+ foreach(lc, old_mvclauses)
+ {
+ RestrictStatData *rsd = (RestrictStatData *) lfirst(lc);
+ Assert(IsA(rsd, RestrictStatData));
- case BMS_DIFFERENT:
- /* do nothing - keep both stats */
- break;
+ if (bms_is_subset(rsd->mvattrs, statsattrs))
+ mvclauses = lappend(mvclauses, rsd);
+ else
+ nonmvclauses = lappend(nonmvclauses, rsd);
+ }
+ resultattrs = bms_intersect(resultattrs,
+ mvstatslist[candidatestats]->attrs);
+ }
+ resultstats = list_make1(mvstatslist[candidatestats]);
}
-
- bms_free(prev);
}
- bms_free(curr);
- }
-
- /* can't reduce all statistics (at least one has to remain) */
- Assert(nmvstats > 0);
+ if (bms_num_members(resultattrs) < 2)
+ {
+ /*
+ * make this non-mv if mvclause covers only one mv-attribute.
+ */
+ nonmvclauses = list_concat(nonmvclauses, mvclauses);
+ mvclauses = NULL;
+ resultattrs = NULL;
+ resultstats = NIL;
+ }
- /* now, let's remove the reduced statistics from the arrays */
- list_free(stats);
- stats = NIL;
+ /*
+ * All mvclauses are covered by the candidate stats here.
+ */
+ rdata->mvclause =
+ stripRestrictStatData(mvclauses, rdata->boolop, NULL);
+ rdata->children = partialclauses;
+ rdata->mvattrs = resultattrs;
+ rdata->nonmvclause =
+ stripRestrictStatData(nonmvclauses, rdata->boolop, NULL);
+ rdata->mvstats = resultstats;
- for (i = 0; i < nmvstats; i++)
+ }
+ else if (not_clause(clause))
{
- MVStatisticInfo *info;
-
- pfree(stats_attnums[i]);
+ Node *nd = (Node *) linitial(((BoolExpr*)clause)->args);
+ RestrictStatData *tmpsd;
- if (redundant[i])
- continue;
-
- info = makeNode(MVStatisticInfo);
- memcpy(info, &mvstats[i], sizeof(MVStatisticInfo));
-
- stats = lappend(stats, info);
+ tmpsd = transformRestrictInfoForEstimate(root, list_make1(nd),
+ relid, sjinfo);
+ rdata->children = list_make1(tmpsd);
}
-
- pfree(mvstats);
- pfree(stats_attnums);
- pfree(redundant);
-
- return stats;
-}
-
-static Node**
-make_clauses_array(List *clauses, int *nclauses)
-{
- int i;
- ListCell *l;
-
- Node** clauses_array;
-
- *nclauses = list_length(clauses);
- clauses_array = (Node **)palloc0((*nclauses) * sizeof(Node *));
-
- i = 0;
- foreach (l, clauses)
- clauses_array[i++] = (Node *)lfirst(l);
-
- *nclauses = i;
-
- return clauses_array;
-}
-
-static Bitmapset **
-make_clauses_attnums(PlannerInfo *root, Oid varRelid, SpecialJoinInfo *sjinfo,
- int type, Node **clauses, int nclauses)
-{
- int i;
- Index relid;
- Bitmapset **clauses_attnums
- = (Bitmapset **)palloc0(nclauses * sizeof(Bitmapset *));
-
- for (i = 0; i < nclauses; i++)
+ else if (is_opclause(clause) &&
+ list_length(((OpExpr *) clause)->args) == 2)
{
- Bitmapset * attnums = NULL;
+ Node *varnode = get_leftop((Expr*)clause);
+ Node *nonvarnode = get_rightop((Expr*)clause);
- if (! clause_is_mv_compatible(root, clauses[i], varRelid,
- &relid, &attnums, sjinfo, type))
- elog(ERROR, "should not get non-mv-compatible cluase");
+ /* Place var on vernode if any */
+ if (!IsA(varnode, Var))
+ {
+ Node *tmp = nonvarnode;
+ nonvarnode = varnode;
+ varnode = tmp;
+ }
+
+ if (IsA(varnode, Var) && is_pseudo_constant_clause(nonvarnode))
+ {
+ Var *var = (Var *)varnode;
+ List *statslist = root->simple_rel_array[relid]->mvstatlist;
+ Oid opno = ((OpExpr*)clause)->opno;
+ int varmvbitmap = get_oprmvstat(opno);
+
+ if (varmvbitmap &&
+ !IS_SPECIAL_VARNO(var->varno) &&
+ AttrNumberIsForUserDefinedAttr(var->varattno))
+ {
+ List *mvstats = NIL;
+ ListCell *lc;
+ Bitmapset *varattrs = bms_make_singleton(var->varattno);
- clauses_attnums[i] = attnums;
+ /*
+ * Add mv statistics if it is applicable on this expression
+ */
+ foreach (lc, statslist)
+ {
+ int k;
+ MVStatisticInfo *stats = (MVStatisticInfo *) lfirst(lc);
+ Bitmapset *statsattrs = NULL;
+ int statsmvbitmap =
+ (stats->mcv_built ? MVSTATISTIC_MCV : 0) |
+ (stats->hist_built ? MVSTATISTIC_HIST : 0) |
+ (stats->deps_built ? MVSTATISTIC_FDEP : 0);
+
+ for (k = 0 ; k < stats->stakeys->dim1 ; k++)
+ statsattrs = bms_add_member(statsattrs,
+ stats->stakeys->values[k]);
+ /* XXX: Does this work as expected? */
+ if (bms_is_subset(varattrs, statsattrs) &&
+ (statsmvbitmap & varmvbitmap))
+ {
+ bm_mvstat *mvstatsent = palloc0(sizeof(bm_mvstat));
+ mvstatsent->attrs = statsattrs;
+ mvstatsent->stats = stats;
+ mvstatsent->mvkind = statsmvbitmap;
+ mvstats = lappend(mvstats, mvstatsent);
+ }
+ }
+ if (mvstats)
+ {
+ /* MV stats is potentially applicable on this expression */
+ ereport(DEBUG1,
+ (errmsg ("%sMATCH[%d][%d](varno = %d, attno = %d)",
+ head, level, i,
+ var->varno, var->varattno),
+ errhidestmt(level)));
+
+ rdata->mvstats = mvstats;
+ rdata->mvattrs = varattrs;
+ }
+ }
+ }
+ else
+ {
+ ereport(DEBUG1,
+ (errmsg ("%sno match BinOp[%d][%d]: r=%d, l=%d",
+ head, level, i,
+ varnode->type, nonvarnode->type),
+ errhidestmt(level)));
+ }
}
+ else if (IsA(clause, NullTest))
+ {
+ NullTest *expr = (NullTest*)clause;
+ Var *var = (Var *)(expr->arg);
- return clauses_attnums;
-}
-
-static bool*
-make_cover_map(Bitmapset **stats_attnums, int nmvstats,
- Bitmapset **clauses_attnums, int nclauses)
-{
- int i, j;
- bool *cover_map = (bool*)palloc0(nclauses * nmvstats);
+ if (IsA(var, Var) &&
+ !IS_SPECIAL_VARNO(var->varno) &&
+ AttrNumberIsForUserDefinedAttr(var->varattno))
+ {
+ Bitmapset *varattrs = bms_make_singleton(var->varattno);
+ List *mvstats = NIL;
+ ListCell *lc;
- for (i = 0; i < nmvstats; i++)
- for (j = 0; j < nclauses; j++)
- cover_map[i * nclauses + j]
- = bms_is_subset(clauses_attnums[j], stats_attnums[i]);
+ foreach(lc, root->simple_rel_array[relid]->mvstatlist)
+ {
+ MVStatisticInfo *stats = (MVStatisticInfo *) lfirst(lc);
+ Bitmapset *statsattrs = NULL;
+ int k;
+
+ for (k = 0 ; k < stats->stakeys->dim1 ; k++)
+ statsattrs = bms_add_member(statsattrs,
+ stats->stakeys->values[k]);
+ if (bms_is_subset(varattrs, statsattrs))
+ {
+ bm_mvstat *mvstatsent = palloc0(sizeof(bm_mvstat));
+ mvstatsent->stats = stats;
+ mvstatsent->attrs = statsattrs;
+ mvstatsent->mvkind = (MVSTATISTIC_MCV |MVSTATISTIC_HIST);
+ mvstats = lappend(mvstats, mvstatsent);
+ }
+ }
+ if (mvstats)
+ {
+ rdata->mvstats = mvstats;
+ rdata->mvattrs = varattrs;
+ }
+ }
+ }
+ else
+ {
+ ereport(DEBUG1,
+ (errmsg ("%sno match node(%d)[%d][%d]",
+ head, clause->type, level, i),
+ errhidestmt(level)));
+ }
- return cover_map;
+ return rdata;
}
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 7b32247..61e578f 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -45,6 +45,7 @@
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
+#include "utils/mvstats.h"
/* Hook for plugins to get control in get_attavgwidth() */
get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
@@ -1345,6 +1346,45 @@ get_oprjoin(Oid opno)
return (RegProcedure) InvalidOid;
}
+/*
+ * get_oprmvstat
+ *
+ * Returns mv stats compatibility for computing selectivity
+ * Return valueis bitwise or of MVSTATISTIC_* symbols
+ */
+int
+get_oprmvstat(Oid opno)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
+ if (HeapTupleIsValid(tp))
+ {
+ Datum tmp;
+ bool isnull;
+ char *str;
+ int result = 0;
+
+ tmp = SysCacheGetAttr(OPEROID, tp,
+ Anum_pg_operator_oprmvstat, &isnull);
+ if (!isnull)
+ {
+ str = TextDatumGetCString(tmp);
+ if (strlen(str) == 3)
+ {
+ if (str[0] != '-') result |= MVSTATISTIC_MCV;
+ if (str[1] != '-') result |= MVSTATISTIC_HIST;
+ if (str[2] != '-') result |= MVSTATISTIC_FDEP;
+ }
+ }
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return 0;
+}
+
+
/* ---------- FUNCTION CACHE ---------- */
/*
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 26c9d4e..c75ac72 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -49,6 +49,9 @@ CATALOG(pg_operator,2617)
regproc oprcode; /* OID of underlying function */
regproc oprrest; /* OID of restriction estimator, or 0 */
regproc oprjoin; /* OID of join estimator, or 0 */
+#ifdef CATALOG_VARLEN /* variable-length fields start here */
+ text oprmvstat; /* MV stat compatibility in '[m-][h-][f-]' */
+#endif
} FormData_pg_operator;
/* ----------------
@@ -63,7 +66,7 @@ typedef FormData_pg_operator *Form_pg_operator;
* ----------------
*/
-#define Natts_pg_operator 14
+#define Natts_pg_operator 15
#define Anum_pg_operator_oprname 1
#define Anum_pg_operator_oprnamespace 2
#define Anum_pg_operator_oprowner 3
@@ -78,6 +81,7 @@ typedef FormData_pg_operator *Form_pg_operator;
#define Anum_pg_operator_oprcode 12
#define Anum_pg_operator_oprrest 13
#define Anum_pg_operator_oprjoin 14
+#define Anum_pg_operator_oprmvstat 15
/* ----------------
* initial contents of pg_operator
@@ -91,1735 +95,1735 @@ typedef FormData_pg_operator *Form_pg_operator;
* for the underlying function.
*/
-DATA(insert OID = 15 ( "=" PGNSP PGUID b t t 23 20 16 416 36 int48eq eqsel eqjoinsel ));
+DATA(insert OID = 15 ( "=" PGNSP PGUID b t t 23 20 16 416 36 int48eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 36 ( "<>" PGNSP PGUID b f f 23 20 16 417 15 int48ne neqsel neqjoinsel ));
+DATA(insert OID = 36 ( "<>" PGNSP PGUID b f f 23 20 16 417 15 int48ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 37 ( "<" PGNSP PGUID b f f 23 20 16 419 82 int48lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 37 ( "<" PGNSP PGUID b f f 23 20 16 419 82 int48lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 76 ( ">" PGNSP PGUID b f f 23 20 16 418 80 int48gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 76 ( ">" PGNSP PGUID b f f 23 20 16 418 80 int48gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 80 ( "<=" PGNSP PGUID b f f 23 20 16 430 76 int48le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 80 ( "<=" PGNSP PGUID b f f 23 20 16 430 76 int48le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 82 ( ">=" PGNSP PGUID b f f 23 20 16 420 37 int48ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 82 ( ">=" PGNSP PGUID b f f 23 20 16 420 37 int48ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 58 ( "<" PGNSP PGUID b f f 16 16 16 59 1695 boollt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 58 ( "<" PGNSP PGUID b f f 16 16 16 59 1695 boollt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 59 ( ">" PGNSP PGUID b f f 16 16 16 58 1694 boolgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 59 ( ">" PGNSP PGUID b f f 16 16 16 58 1694 boolgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 85 ( "<>" PGNSP PGUID b f f 16 16 16 85 91 boolne neqsel neqjoinsel ));
+DATA(insert OID = 85 ( "<>" PGNSP PGUID b f f 16 16 16 85 91 boolne neqsel neqjoinsel "mhf"));
DESCR("not equal");
#define BooleanNotEqualOperator 85
-DATA(insert OID = 91 ( "=" PGNSP PGUID b t t 16 16 16 91 85 booleq eqsel eqjoinsel ));
+DATA(insert OID = 91 ( "=" PGNSP PGUID b t t 16 16 16 91 85 booleq eqsel eqjoinsel "mhf"));
DESCR("equal");
#define BooleanEqualOperator 91
-DATA(insert OID = 1694 ( "<=" PGNSP PGUID b f f 16 16 16 1695 59 boolle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1694 ( "<=" PGNSP PGUID b f f 16 16 16 1695 59 boolle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1695 ( ">=" PGNSP PGUID b f f 16 16 16 1694 58 boolge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1695 ( ">=" PGNSP PGUID b f f 16 16 16 1694 58 boolge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 92 ( "=" PGNSP PGUID b t t 18 18 16 92 630 chareq eqsel eqjoinsel ));
+DATA(insert OID = 92 ( "=" PGNSP PGUID b t t 18 18 16 92 630 chareq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 93 ( "=" PGNSP PGUID b t t 19 19 16 93 643 nameeq eqsel eqjoinsel ));
+DATA(insert OID = 93 ( "=" PGNSP PGUID b t t 19 19 16 93 643 nameeq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 94 ( "=" PGNSP PGUID b t t 21 21 16 94 519 int2eq eqsel eqjoinsel ));
+DATA(insert OID = 94 ( "=" PGNSP PGUID b t t 21 21 16 94 519 int2eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 95 ( "<" PGNSP PGUID b f f 21 21 16 520 524 int2lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 95 ( "<" PGNSP PGUID b f f 21 21 16 520 524 int2lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 96 ( "=" PGNSP PGUID b t t 23 23 16 96 518 int4eq eqsel eqjoinsel ));
+DATA(insert OID = 96 ( "=" PGNSP PGUID b t t 23 23 16 96 518 int4eq eqsel eqjoinsel "mhf"));
DESCR("equal");
#define Int4EqualOperator 96
-DATA(insert OID = 97 ( "<" PGNSP PGUID b f f 23 23 16 521 525 int4lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 97 ( "<" PGNSP PGUID b f f 23 23 16 521 525 int4lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
#define Int4LessOperator 97
-DATA(insert OID = 98 ( "=" PGNSP PGUID b t t 25 25 16 98 531 texteq eqsel eqjoinsel ));
+DATA(insert OID = 98 ( "=" PGNSP PGUID b t t 25 25 16 98 531 texteq eqsel eqjoinsel "mhf"));
DESCR("equal");
#define TextEqualOperator 98
-DATA(insert OID = 349 ( "||" PGNSP PGUID b f f 2277 2283 2277 0 0 array_append - - ));
+DATA(insert OID = 349 ( "||" PGNSP PGUID b f f 2277 2283 2277 0 0 array_append - - "---"));
DESCR("append element onto end of array");
-DATA(insert OID = 374 ( "||" PGNSP PGUID b f f 2283 2277 2277 0 0 array_prepend - - ));
+DATA(insert OID = 374 ( "||" PGNSP PGUID b f f 2283 2277 2277 0 0 array_prepend - - "---"));
DESCR("prepend element onto front of array");
-DATA(insert OID = 375 ( "||" PGNSP PGUID b f f 2277 2277 2277 0 0 array_cat - - ));
+DATA(insert OID = 375 ( "||" PGNSP PGUID b f f 2277 2277 2277 0 0 array_cat - - "---"));
DESCR("concatenate");
-DATA(insert OID = 352 ( "=" PGNSP PGUID b f t 28 28 16 352 0 xideq eqsel eqjoinsel ));
+DATA(insert OID = 352 ( "=" PGNSP PGUID b f t 28 28 16 352 0 xideq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 353 ( "=" PGNSP PGUID b f f 28 23 16 0 0 xideqint4 eqsel eqjoinsel ));
+DATA(insert OID = 353 ( "=" PGNSP PGUID b f f 28 23 16 0 0 xideqint4 eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 388 ( "!" PGNSP PGUID r f f 20 0 1700 0 0 numeric_fac - - ));
+DATA(insert OID = 388 ( "!" PGNSP PGUID r f f 20 0 1700 0 0 numeric_fac - - "---"));
DESCR("factorial");
-DATA(insert OID = 389 ( "!!" PGNSP PGUID l f f 0 20 1700 0 0 numeric_fac - - ));
+DATA(insert OID = 389 ( "!!" PGNSP PGUID l f f 0 20 1700 0 0 numeric_fac - - "---"));
DESCR("deprecated, use ! instead");
-DATA(insert OID = 385 ( "=" PGNSP PGUID b f t 29 29 16 385 0 cideq eqsel eqjoinsel ));
+DATA(insert OID = 385 ( "=" PGNSP PGUID b f t 29 29 16 385 0 cideq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 386 ( "=" PGNSP PGUID b f t 22 22 16 386 0 int2vectoreq eqsel eqjoinsel ));
+DATA(insert OID = 386 ( "=" PGNSP PGUID b f t 22 22 16 386 0 int2vectoreq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 387 ( "=" PGNSP PGUID b t f 27 27 16 387 402 tideq eqsel eqjoinsel ));
+DATA(insert OID = 387 ( "=" PGNSP PGUID b t f 27 27 16 387 402 tideq eqsel eqjoinsel "mhf"));
DESCR("equal");
#define TIDEqualOperator 387
-DATA(insert OID = 402 ( "<>" PGNSP PGUID b f f 27 27 16 402 387 tidne neqsel neqjoinsel ));
+DATA(insert OID = 402 ( "<>" PGNSP PGUID b f f 27 27 16 402 387 tidne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2799 ( "<" PGNSP PGUID b f f 27 27 16 2800 2802 tidlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2799 ( "<" PGNSP PGUID b f f 27 27 16 2800 2802 tidlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
#define TIDLessOperator 2799
-DATA(insert OID = 2800 ( ">" PGNSP PGUID b f f 27 27 16 2799 2801 tidgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2800 ( ">" PGNSP PGUID b f f 27 27 16 2799 2801 tidgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2801 ( "<=" PGNSP PGUID b f f 27 27 16 2802 2800 tidle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2801 ( "<=" PGNSP PGUID b f f 27 27 16 2802 2800 tidle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2802 ( ">=" PGNSP PGUID b f f 27 27 16 2801 2799 tidge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2802 ( ">=" PGNSP PGUID b f f 27 27 16 2801 2799 tidge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 410 ( "=" PGNSP PGUID b t t 20 20 16 410 411 int8eq eqsel eqjoinsel ));
+DATA(insert OID = 410 ( "=" PGNSP PGUID b t t 20 20 16 410 411 int8eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 411 ( "<>" PGNSP PGUID b f f 20 20 16 411 410 int8ne neqsel neqjoinsel ));
+DATA(insert OID = 411 ( "<>" PGNSP PGUID b f f 20 20 16 411 410 int8ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 412 ( "<" PGNSP PGUID b f f 20 20 16 413 415 int8lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 412 ( "<" PGNSP PGUID b f f 20 20 16 413 415 int8lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
#define Int8LessOperator 412
-DATA(insert OID = 413 ( ">" PGNSP PGUID b f f 20 20 16 412 414 int8gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 413 ( ">" PGNSP PGUID b f f 20 20 16 412 414 int8gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 414 ( "<=" PGNSP PGUID b f f 20 20 16 415 413 int8le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 414 ( "<=" PGNSP PGUID b f f 20 20 16 415 413 int8le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 415 ( ">=" PGNSP PGUID b f f 20 20 16 414 412 int8ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 415 ( ">=" PGNSP PGUID b f f 20 20 16 414 412 int8ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 416 ( "=" PGNSP PGUID b t t 20 23 16 15 417 int84eq eqsel eqjoinsel ));
+DATA(insert OID = 416 ( "=" PGNSP PGUID b t t 20 23 16 15 417 int84eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 417 ( "<>" PGNSP PGUID b f f 20 23 16 36 416 int84ne neqsel neqjoinsel ));
+DATA(insert OID = 417 ( "<>" PGNSP PGUID b f f 20 23 16 36 416 int84ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 418 ( "<" PGNSP PGUID b f f 20 23 16 76 430 int84lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 418 ( "<" PGNSP PGUID b f f 20 23 16 76 430 int84lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 419 ( ">" PGNSP PGUID b f f 20 23 16 37 420 int84gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 419 ( ">" PGNSP PGUID b f f 20 23 16 37 420 int84gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 420 ( "<=" PGNSP PGUID b f f 20 23 16 82 419 int84le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 420 ( "<=" PGNSP PGUID b f f 20 23 16 82 419 int84le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 430 ( ">=" PGNSP PGUID b f f 20 23 16 80 418 int84ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 430 ( ">=" PGNSP PGUID b f f 20 23 16 80 418 int84ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 439 ( "%" PGNSP PGUID b f f 20 20 20 0 0 int8mod - - ));
+DATA(insert OID = 439 ( "%" PGNSP PGUID b f f 20 20 20 0 0 int8mod - - "---"));
DESCR("modulus");
-DATA(insert OID = 473 ( "@" PGNSP PGUID l f f 0 20 20 0 0 int8abs - - ));
+DATA(insert OID = 473 ( "@" PGNSP PGUID l f f 0 20 20 0 0 int8abs - - "---"));
DESCR("absolute value");
-DATA(insert OID = 484 ( "-" PGNSP PGUID l f f 0 20 20 0 0 int8um - - ));
+DATA(insert OID = 484 ( "-" PGNSP PGUID l f f 0 20 20 0 0 int8um - - "---"));
DESCR("negate");
-DATA(insert OID = 485 ( "<<" PGNSP PGUID b f f 604 604 16 0 0 poly_left positionsel positionjoinsel ));
+DATA(insert OID = 485 ( "<<" PGNSP PGUID b f f 604 604 16 0 0 poly_left positionsel positionjoinsel "---"));
DESCR("is left of");
-DATA(insert OID = 486 ( "&<" PGNSP PGUID b f f 604 604 16 0 0 poly_overleft positionsel positionjoinsel ));
+DATA(insert OID = 486 ( "&<" PGNSP PGUID b f f 604 604 16 0 0 poly_overleft positionsel positionjoinsel "---"));
DESCR("overlaps or is left of");
-DATA(insert OID = 487 ( "&>" PGNSP PGUID b f f 604 604 16 0 0 poly_overright positionsel positionjoinsel ));
+DATA(insert OID = 487 ( "&>" PGNSP PGUID b f f 604 604 16 0 0 poly_overright positionsel positionjoinsel "---"));
DESCR("overlaps or is right of");
-DATA(insert OID = 488 ( ">>" PGNSP PGUID b f f 604 604 16 0 0 poly_right positionsel positionjoinsel ));
+DATA(insert OID = 488 ( ">>" PGNSP PGUID b f f 604 604 16 0 0 poly_right positionsel positionjoinsel "---"));
DESCR("is right of");
-DATA(insert OID = 489 ( "<@" PGNSP PGUID b f f 604 604 16 490 0 poly_contained contsel contjoinsel ));
+DATA(insert OID = 489 ( "<@" PGNSP PGUID b f f 604 604 16 490 0 poly_contained contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 490 ( "@>" PGNSP PGUID b f f 604 604 16 489 0 poly_contain contsel contjoinsel ));
+DATA(insert OID = 490 ( "@>" PGNSP PGUID b f f 604 604 16 489 0 poly_contain contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 491 ( "~=" PGNSP PGUID b f f 604 604 16 491 0 poly_same eqsel eqjoinsel ));
+DATA(insert OID = 491 ( "~=" PGNSP PGUID b f f 604 604 16 491 0 poly_same eqsel eqjoinsel "mhf"));
DESCR("same as");
-DATA(insert OID = 492 ( "&&" PGNSP PGUID b f f 604 604 16 492 0 poly_overlap areasel areajoinsel ));
+DATA(insert OID = 492 ( "&&" PGNSP PGUID b f f 604 604 16 492 0 poly_overlap areasel areajoinsel "---"));
DESCR("overlaps");
-DATA(insert OID = 493 ( "<<" PGNSP PGUID b f f 603 603 16 0 0 box_left positionsel positionjoinsel ));
+DATA(insert OID = 493 ( "<<" PGNSP PGUID b f f 603 603 16 0 0 box_left positionsel positionjoinsel "---"));
DESCR("is left of");
-DATA(insert OID = 494 ( "&<" PGNSP PGUID b f f 603 603 16 0 0 box_overleft positionsel positionjoinsel ));
+DATA(insert OID = 494 ( "&<" PGNSP PGUID b f f 603 603 16 0 0 box_overleft positionsel positionjoinsel "---"));
DESCR("overlaps or is left of");
-DATA(insert OID = 495 ( "&>" PGNSP PGUID b f f 603 603 16 0 0 box_overright positionsel positionjoinsel ));
+DATA(insert OID = 495 ( "&>" PGNSP PGUID b f f 603 603 16 0 0 box_overright positionsel positionjoinsel "---"));
DESCR("overlaps or is right of");
-DATA(insert OID = 496 ( ">>" PGNSP PGUID b f f 603 603 16 0 0 box_right positionsel positionjoinsel ));
+DATA(insert OID = 496 ( ">>" PGNSP PGUID b f f 603 603 16 0 0 box_right positionsel positionjoinsel "---"));
DESCR("is right of");
-DATA(insert OID = 497 ( "<@" PGNSP PGUID b f f 603 603 16 498 0 box_contained contsel contjoinsel ));
+DATA(insert OID = 497 ( "<@" PGNSP PGUID b f f 603 603 16 498 0 box_contained contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 498 ( "@>" PGNSP PGUID b f f 603 603 16 497 0 box_contain contsel contjoinsel ));
+DATA(insert OID = 498 ( "@>" PGNSP PGUID b f f 603 603 16 497 0 box_contain contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 499 ( "~=" PGNSP PGUID b f f 603 603 16 499 0 box_same eqsel eqjoinsel ));
+DATA(insert OID = 499 ( "~=" PGNSP PGUID b f f 603 603 16 499 0 box_same eqsel eqjoinsel "mhf"));
DESCR("same as");
-DATA(insert OID = 500 ( "&&" PGNSP PGUID b f f 603 603 16 500 0 box_overlap areasel areajoinsel ));
+DATA(insert OID = 500 ( "&&" PGNSP PGUID b f f 603 603 16 500 0 box_overlap areasel areajoinsel "---"));
DESCR("overlaps");
-DATA(insert OID = 501 ( ">=" PGNSP PGUID b f f 603 603 16 505 504 box_ge areasel areajoinsel ));
+DATA(insert OID = 501 ( ">=" PGNSP PGUID b f f 603 603 16 505 504 box_ge areasel areajoinsel "---"));
DESCR("greater than or equal by area");
-DATA(insert OID = 502 ( ">" PGNSP PGUID b f f 603 603 16 504 505 box_gt areasel areajoinsel ));
+DATA(insert OID = 502 ( ">" PGNSP PGUID b f f 603 603 16 504 505 box_gt areasel areajoinsel "---"));
DESCR("greater than by area");
-DATA(insert OID = 503 ( "=" PGNSP PGUID b f f 603 603 16 503 0 box_eq eqsel eqjoinsel ));
+DATA(insert OID = 503 ( "=" PGNSP PGUID b f f 603 603 16 503 0 box_eq eqsel eqjoinsel "mhf"));
DESCR("equal by area");
-DATA(insert OID = 504 ( "<" PGNSP PGUID b f f 603 603 16 502 501 box_lt areasel areajoinsel ));
+DATA(insert OID = 504 ( "<" PGNSP PGUID b f f 603 603 16 502 501 box_lt areasel areajoinsel "---"));
DESCR("less than by area");
-DATA(insert OID = 505 ( "<=" PGNSP PGUID b f f 603 603 16 501 502 box_le areasel areajoinsel ));
+DATA(insert OID = 505 ( "<=" PGNSP PGUID b f f 603 603 16 501 502 box_le areasel areajoinsel "---"));
DESCR("less than or equal by area");
-DATA(insert OID = 506 ( ">^" PGNSP PGUID b f f 600 600 16 0 0 point_above positionsel positionjoinsel ));
+DATA(insert OID = 506 ( ">^" PGNSP PGUID b f f 600 600 16 0 0 point_above positionsel positionjoinsel "---"));
DESCR("is above");
-DATA(insert OID = 507 ( "<<" PGNSP PGUID b f f 600 600 16 0 0 point_left positionsel positionjoinsel ));
+DATA(insert OID = 507 ( "<<" PGNSP PGUID b f f 600 600 16 0 0 point_left positionsel positionjoinsel "---"));
DESCR("is left of");
-DATA(insert OID = 508 ( ">>" PGNSP PGUID b f f 600 600 16 0 0 point_right positionsel positionjoinsel ));
+DATA(insert OID = 508 ( ">>" PGNSP PGUID b f f 600 600 16 0 0 point_right positionsel positionjoinsel "---"));
DESCR("is right of");
-DATA(insert OID = 509 ( "<^" PGNSP PGUID b f f 600 600 16 0 0 point_below positionsel positionjoinsel ));
+DATA(insert OID = 509 ( "<^" PGNSP PGUID b f f 600 600 16 0 0 point_below positionsel positionjoinsel "---"));
DESCR("is below");
-DATA(insert OID = 510 ( "~=" PGNSP PGUID b f f 600 600 16 510 713 point_eq eqsel eqjoinsel ));
+DATA(insert OID = 510 ( "~=" PGNSP PGUID b f f 600 600 16 510 713 point_eq eqsel eqjoinsel "mhf"));
DESCR("same as");
-DATA(insert OID = 511 ( "<@" PGNSP PGUID b f f 600 603 16 433 0 on_pb contsel contjoinsel ));
+DATA(insert OID = 511 ( "<@" PGNSP PGUID b f f 600 603 16 433 0 on_pb contsel contjoinsel "---"));
DESCR("point inside box");
-DATA(insert OID = 433 ( "@>" PGNSP PGUID b f f 603 600 16 511 0 box_contain_pt contsel contjoinsel ));
+DATA(insert OID = 433 ( "@>" PGNSP PGUID b f f 603 600 16 511 0 box_contain_pt contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 512 ( "<@" PGNSP PGUID b f f 600 602 16 755 0 on_ppath - - ));
+DATA(insert OID = 512 ( "<@" PGNSP PGUID b f f 600 602 16 755 0 on_ppath - - "---"));
DESCR("point within closed path, or point on open path");
-DATA(insert OID = 513 ( "@@" PGNSP PGUID l f f 0 603 600 0 0 box_center - - ));
+DATA(insert OID = 513 ( "@@" PGNSP PGUID l f f 0 603 600 0 0 box_center - - "---"));
DESCR("center of");
-DATA(insert OID = 514 ( "*" PGNSP PGUID b f f 23 23 23 514 0 int4mul - - ));
+DATA(insert OID = 514 ( "*" PGNSP PGUID b f f 23 23 23 514 0 int4mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 517 ( "<->" PGNSP PGUID b f f 600 600 701 517 0 point_distance - - ));
+DATA(insert OID = 517 ( "<->" PGNSP PGUID b f f 600 600 701 517 0 point_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 518 ( "<>" PGNSP PGUID b f f 23 23 16 518 96 int4ne neqsel neqjoinsel ));
+DATA(insert OID = 518 ( "<>" PGNSP PGUID b f f 23 23 16 518 96 int4ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 519 ( "<>" PGNSP PGUID b f f 21 21 16 519 94 int2ne neqsel neqjoinsel ));
+DATA(insert OID = 519 ( "<>" PGNSP PGUID b f f 21 21 16 519 94 int2ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 520 ( ">" PGNSP PGUID b f f 21 21 16 95 522 int2gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 520 ( ">" PGNSP PGUID b f f 21 21 16 95 522 int2gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 521 ( ">" PGNSP PGUID b f f 23 23 16 97 523 int4gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 521 ( ">" PGNSP PGUID b f f 23 23 16 97 523 int4gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 522 ( "<=" PGNSP PGUID b f f 21 21 16 524 520 int2le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 522 ( "<=" PGNSP PGUID b f f 21 21 16 524 520 int2le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 523 ( "<=" PGNSP PGUID b f f 23 23 16 525 521 int4le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 523 ( "<=" PGNSP PGUID b f f 23 23 16 525 521 int4le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 524 ( ">=" PGNSP PGUID b f f 21 21 16 522 95 int2ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 524 ( ">=" PGNSP PGUID b f f 21 21 16 522 95 int2ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 525 ( ">=" PGNSP PGUID b f f 23 23 16 523 97 int4ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 525 ( ">=" PGNSP PGUID b f f 23 23 16 523 97 int4ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 526 ( "*" PGNSP PGUID b f f 21 21 21 526 0 int2mul - - ));
+DATA(insert OID = 526 ( "*" PGNSP PGUID b f f 21 21 21 526 0 int2mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 527 ( "/" PGNSP PGUID b f f 21 21 21 0 0 int2div - - ));
+DATA(insert OID = 527 ( "/" PGNSP PGUID b f f 21 21 21 0 0 int2div - - "---"));
DESCR("divide");
-DATA(insert OID = 528 ( "/" PGNSP PGUID b f f 23 23 23 0 0 int4div - - ));
+DATA(insert OID = 528 ( "/" PGNSP PGUID b f f 23 23 23 0 0 int4div - - "---"));
DESCR("divide");
-DATA(insert OID = 529 ( "%" PGNSP PGUID b f f 21 21 21 0 0 int2mod - - ));
+DATA(insert OID = 529 ( "%" PGNSP PGUID b f f 21 21 21 0 0 int2mod - - "---"));
DESCR("modulus");
-DATA(insert OID = 530 ( "%" PGNSP PGUID b f f 23 23 23 0 0 int4mod - - ));
+DATA(insert OID = 530 ( "%" PGNSP PGUID b f f 23 23 23 0 0 int4mod - - "---"));
DESCR("modulus");
-DATA(insert OID = 531 ( "<>" PGNSP PGUID b f f 25 25 16 531 98 textne neqsel neqjoinsel ));
+DATA(insert OID = 531 ( "<>" PGNSP PGUID b f f 25 25 16 531 98 textne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 532 ( "=" PGNSP PGUID b t t 21 23 16 533 538 int24eq eqsel eqjoinsel ));
+DATA(insert OID = 532 ( "=" PGNSP PGUID b t t 21 23 16 533 538 int24eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 533 ( "=" PGNSP PGUID b t t 23 21 16 532 539 int42eq eqsel eqjoinsel ));
+DATA(insert OID = 533 ( "=" PGNSP PGUID b t t 23 21 16 532 539 int42eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 534 ( "<" PGNSP PGUID b f f 21 23 16 537 542 int24lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 534 ( "<" PGNSP PGUID b f f 21 23 16 537 542 int24lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 535 ( "<" PGNSP PGUID b f f 23 21 16 536 543 int42lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 535 ( "<" PGNSP PGUID b f f 23 21 16 536 543 int42lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 536 ( ">" PGNSP PGUID b f f 21 23 16 535 540 int24gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 536 ( ">" PGNSP PGUID b f f 21 23 16 535 540 int24gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 537 ( ">" PGNSP PGUID b f f 23 21 16 534 541 int42gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 537 ( ">" PGNSP PGUID b f f 23 21 16 534 541 int42gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 538 ( "<>" PGNSP PGUID b f f 21 23 16 539 532 int24ne neqsel neqjoinsel ));
+DATA(insert OID = 538 ( "<>" PGNSP PGUID b f f 21 23 16 539 532 int24ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 539 ( "<>" PGNSP PGUID b f f 23 21 16 538 533 int42ne neqsel neqjoinsel ));
+DATA(insert OID = 539 ( "<>" PGNSP PGUID b f f 23 21 16 538 533 int42ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 540 ( "<=" PGNSP PGUID b f f 21 23 16 543 536 int24le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 540 ( "<=" PGNSP PGUID b f f 21 23 16 543 536 int24le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 541 ( "<=" PGNSP PGUID b f f 23 21 16 542 537 int42le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 541 ( "<=" PGNSP PGUID b f f 23 21 16 542 537 int42le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 542 ( ">=" PGNSP PGUID b f f 21 23 16 541 534 int24ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 542 ( ">=" PGNSP PGUID b f f 21 23 16 541 534 int24ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 543 ( ">=" PGNSP PGUID b f f 23 21 16 540 535 int42ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 543 ( ">=" PGNSP PGUID b f f 23 21 16 540 535 int42ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 544 ( "*" PGNSP PGUID b f f 21 23 23 545 0 int24mul - - ));
+DATA(insert OID = 544 ( "*" PGNSP PGUID b f f 21 23 23 545 0 int24mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 545 ( "*" PGNSP PGUID b f f 23 21 23 544 0 int42mul - - ));
+DATA(insert OID = 545 ( "*" PGNSP PGUID b f f 23 21 23 544 0 int42mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 546 ( "/" PGNSP PGUID b f f 21 23 23 0 0 int24div - - ));
+DATA(insert OID = 546 ( "/" PGNSP PGUID b f f 21 23 23 0 0 int24div - - "---"));
DESCR("divide");
-DATA(insert OID = 547 ( "/" PGNSP PGUID b f f 23 21 23 0 0 int42div - - ));
+DATA(insert OID = 547 ( "/" PGNSP PGUID b f f 23 21 23 0 0 int42div - - "---"));
DESCR("divide");
-DATA(insert OID = 550 ( "+" PGNSP PGUID b f f 21 21 21 550 0 int2pl - - ));
+DATA(insert OID = 550 ( "+" PGNSP PGUID b f f 21 21 21 550 0 int2pl - - "---"));
DESCR("add");
-DATA(insert OID = 551 ( "+" PGNSP PGUID b f f 23 23 23 551 0 int4pl - - ));
+DATA(insert OID = 551 ( "+" PGNSP PGUID b f f 23 23 23 551 0 int4pl - - "---"));
DESCR("add");
-DATA(insert OID = 552 ( "+" PGNSP PGUID b f f 21 23 23 553 0 int24pl - - ));
+DATA(insert OID = 552 ( "+" PGNSP PGUID b f f 21 23 23 553 0 int24pl - - "---"));
DESCR("add");
-DATA(insert OID = 553 ( "+" PGNSP PGUID b f f 23 21 23 552 0 int42pl - - ));
+DATA(insert OID = 553 ( "+" PGNSP PGUID b f f 23 21 23 552 0 int42pl - - "---"));
DESCR("add");
-DATA(insert OID = 554 ( "-" PGNSP PGUID b f f 21 21 21 0 0 int2mi - - ));
+DATA(insert OID = 554 ( "-" PGNSP PGUID b f f 21 21 21 0 0 int2mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 555 ( "-" PGNSP PGUID b f f 23 23 23 0 0 int4mi - - ));
+DATA(insert OID = 555 ( "-" PGNSP PGUID b f f 23 23 23 0 0 int4mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 556 ( "-" PGNSP PGUID b f f 21 23 23 0 0 int24mi - - ));
+DATA(insert OID = 556 ( "-" PGNSP PGUID b f f 21 23 23 0 0 int24mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 557 ( "-" PGNSP PGUID b f f 23 21 23 0 0 int42mi - - ));
+DATA(insert OID = 557 ( "-" PGNSP PGUID b f f 23 21 23 0 0 int42mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 558 ( "-" PGNSP PGUID l f f 0 23 23 0 0 int4um - - ));
+DATA(insert OID = 558 ( "-" PGNSP PGUID l f f 0 23 23 0 0 int4um - - "---"));
DESCR("negate");
-DATA(insert OID = 559 ( "-" PGNSP PGUID l f f 0 21 21 0 0 int2um - - ));
+DATA(insert OID = 559 ( "-" PGNSP PGUID l f f 0 21 21 0 0 int2um - - "---"));
DESCR("negate");
-DATA(insert OID = 560 ( "=" PGNSP PGUID b t t 702 702 16 560 561 abstimeeq eqsel eqjoinsel ));
+DATA(insert OID = 560 ( "=" PGNSP PGUID b t t 702 702 16 560 561 abstimeeq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 561 ( "<>" PGNSP PGUID b f f 702 702 16 561 560 abstimene neqsel neqjoinsel ));
+DATA(insert OID = 561 ( "<>" PGNSP PGUID b f f 702 702 16 561 560 abstimene neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 562 ( "<" PGNSP PGUID b f f 702 702 16 563 565 abstimelt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 562 ( "<" PGNSP PGUID b f f 702 702 16 563 565 abstimelt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 563 ( ">" PGNSP PGUID b f f 702 702 16 562 564 abstimegt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 563 ( ">" PGNSP PGUID b f f 702 702 16 562 564 abstimegt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 564 ( "<=" PGNSP PGUID b f f 702 702 16 565 563 abstimele scalarltsel scalarltjoinsel ));
+DATA(insert OID = 564 ( "<=" PGNSP PGUID b f f 702 702 16 565 563 abstimele scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 565 ( ">=" PGNSP PGUID b f f 702 702 16 564 562 abstimege scalargtsel scalargtjoinsel ));
+DATA(insert OID = 565 ( ">=" PGNSP PGUID b f f 702 702 16 564 562 abstimege scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 566 ( "=" PGNSP PGUID b t t 703 703 16 566 567 reltimeeq eqsel eqjoinsel ));
+DATA(insert OID = 566 ( "=" PGNSP PGUID b t t 703 703 16 566 567 reltimeeq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 567 ( "<>" PGNSP PGUID b f f 703 703 16 567 566 reltimene neqsel neqjoinsel ));
+DATA(insert OID = 567 ( "<>" PGNSP PGUID b f f 703 703 16 567 566 reltimene neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 568 ( "<" PGNSP PGUID b f f 703 703 16 569 571 reltimelt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 568 ( "<" PGNSP PGUID b f f 703 703 16 569 571 reltimelt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 569 ( ">" PGNSP PGUID b f f 703 703 16 568 570 reltimegt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 569 ( ">" PGNSP PGUID b f f 703 703 16 568 570 reltimegt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 570 ( "<=" PGNSP PGUID b f f 703 703 16 571 569 reltimele scalarltsel scalarltjoinsel ));
+DATA(insert OID = 570 ( "<=" PGNSP PGUID b f f 703 703 16 571 569 reltimele scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 571 ( ">=" PGNSP PGUID b f f 703 703 16 570 568 reltimege scalargtsel scalargtjoinsel ));
+DATA(insert OID = 571 ( ">=" PGNSP PGUID b f f 703 703 16 570 568 reltimege scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 572 ( "~=" PGNSP PGUID b f f 704 704 16 572 0 tintervalsame eqsel eqjoinsel ));
+DATA(insert OID = 572 ( "~=" PGNSP PGUID b f f 704 704 16 572 0 tintervalsame eqsel eqjoinsel "mhf"));
DESCR("same as");
-DATA(insert OID = 573 ( "<<" PGNSP PGUID b f f 704 704 16 0 0 tintervalct - - ));
+DATA(insert OID = 573 ( "<<" PGNSP PGUID b f f 704 704 16 0 0 tintervalct - - "---"));
DESCR("contains");
-DATA(insert OID = 574 ( "&&" PGNSP PGUID b f f 704 704 16 574 0 tintervalov - - ));
+DATA(insert OID = 574 ( "&&" PGNSP PGUID b f f 704 704 16 574 0 tintervalov - - "---"));
DESCR("overlaps");
-DATA(insert OID = 575 ( "#=" PGNSP PGUID b f f 704 703 16 0 576 tintervalleneq - - ));
+DATA(insert OID = 575 ( "#=" PGNSP PGUID b f f 704 703 16 0 576 tintervalleneq - - "---"));
DESCR("equal by length");
-DATA(insert OID = 576 ( "#<>" PGNSP PGUID b f f 704 703 16 0 575 tintervallenne - - ));
+DATA(insert OID = 576 ( "#<>" PGNSP PGUID b f f 704 703 16 0 575 tintervallenne - - "---"));
DESCR("not equal by length");
-DATA(insert OID = 577 ( "#<" PGNSP PGUID b f f 704 703 16 0 580 tintervallenlt - - ));
+DATA(insert OID = 577 ( "#<" PGNSP PGUID b f f 704 703 16 0 580 tintervallenlt - - "---"));
DESCR("less than by length");
-DATA(insert OID = 578 ( "#>" PGNSP PGUID b f f 704 703 16 0 579 tintervallengt - - ));
+DATA(insert OID = 578 ( "#>" PGNSP PGUID b f f 704 703 16 0 579 tintervallengt - - "---"));
DESCR("greater than by length");
-DATA(insert OID = 579 ( "#<=" PGNSP PGUID b f f 704 703 16 0 578 tintervallenle - - ));
+DATA(insert OID = 579 ( "#<=" PGNSP PGUID b f f 704 703 16 0 578 tintervallenle - - "---"));
DESCR("less than or equal by length");
-DATA(insert OID = 580 ( "#>=" PGNSP PGUID b f f 704 703 16 0 577 tintervallenge - - ));
+DATA(insert OID = 580 ( "#>=" PGNSP PGUID b f f 704 703 16 0 577 tintervallenge - - "---"));
DESCR("greater than or equal by length");
-DATA(insert OID = 581 ( "+" PGNSP PGUID b f f 702 703 702 0 0 timepl - - ));
+DATA(insert OID = 581 ( "+" PGNSP PGUID b f f 702 703 702 0 0 timepl - - "---"));
DESCR("add");
-DATA(insert OID = 582 ( "-" PGNSP PGUID b f f 702 703 702 0 0 timemi - - ));
+DATA(insert OID = 582 ( "-" PGNSP PGUID b f f 702 703 702 0 0 timemi - - "---"));
DESCR("subtract");
-DATA(insert OID = 583 ( "<?>" PGNSP PGUID b f f 702 704 16 0 0 intinterval - - ));
+DATA(insert OID = 583 ( "<?>" PGNSP PGUID b f f 702 704 16 0 0 intinterval - - "---"));
DESCR("is contained by");
-DATA(insert OID = 584 ( "-" PGNSP PGUID l f f 0 700 700 0 0 float4um - - ));
+DATA(insert OID = 584 ( "-" PGNSP PGUID l f f 0 700 700 0 0 float4um - - "---"));
DESCR("negate");
-DATA(insert OID = 585 ( "-" PGNSP PGUID l f f 0 701 701 0 0 float8um - - ));
+DATA(insert OID = 585 ( "-" PGNSP PGUID l f f 0 701 701 0 0 float8um - - "---"));
DESCR("negate");
-DATA(insert OID = 586 ( "+" PGNSP PGUID b f f 700 700 700 586 0 float4pl - - ));
+DATA(insert OID = 586 ( "+" PGNSP PGUID b f f 700 700 700 586 0 float4pl - - "---"));
DESCR("add");
-DATA(insert OID = 587 ( "-" PGNSP PGUID b f f 700 700 700 0 0 float4mi - - ));
+DATA(insert OID = 587 ( "-" PGNSP PGUID b f f 700 700 700 0 0 float4mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 588 ( "/" PGNSP PGUID b f f 700 700 700 0 0 float4div - - ));
+DATA(insert OID = 588 ( "/" PGNSP PGUID b f f 700 700 700 0 0 float4div - - "---"));
DESCR("divide");
-DATA(insert OID = 589 ( "*" PGNSP PGUID b f f 700 700 700 589 0 float4mul - - ));
+DATA(insert OID = 589 ( "*" PGNSP PGUID b f f 700 700 700 589 0 float4mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 590 ( "@" PGNSP PGUID l f f 0 700 700 0 0 float4abs - - ));
+DATA(insert OID = 590 ( "@" PGNSP PGUID l f f 0 700 700 0 0 float4abs - - "---"));
DESCR("absolute value");
-DATA(insert OID = 591 ( "+" PGNSP PGUID b f f 701 701 701 591 0 float8pl - - ));
+DATA(insert OID = 591 ( "+" PGNSP PGUID b f f 701 701 701 591 0 float8pl - - "---"));
DESCR("add");
-DATA(insert OID = 592 ( "-" PGNSP PGUID b f f 701 701 701 0 0 float8mi - - ));
+DATA(insert OID = 592 ( "-" PGNSP PGUID b f f 701 701 701 0 0 float8mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 593 ( "/" PGNSP PGUID b f f 701 701 701 0 0 float8div - - ));
+DATA(insert OID = 593 ( "/" PGNSP PGUID b f f 701 701 701 0 0 float8div - - "---"));
DESCR("divide");
-DATA(insert OID = 594 ( "*" PGNSP PGUID b f f 701 701 701 594 0 float8mul - - ));
+DATA(insert OID = 594 ( "*" PGNSP PGUID b f f 701 701 701 594 0 float8mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 595 ( "@" PGNSP PGUID l f f 0 701 701 0 0 float8abs - - ));
+DATA(insert OID = 595 ( "@" PGNSP PGUID l f f 0 701 701 0 0 float8abs - - "---"));
DESCR("absolute value");
-DATA(insert OID = 596 ( "|/" PGNSP PGUID l f f 0 701 701 0 0 dsqrt - - ));
+DATA(insert OID = 596 ( "|/" PGNSP PGUID l f f 0 701 701 0 0 dsqrt - - "---"));
DESCR("square root");
-DATA(insert OID = 597 ( "||/" PGNSP PGUID l f f 0 701 701 0 0 dcbrt - - ));
+DATA(insert OID = 597 ( "||/" PGNSP PGUID l f f 0 701 701 0 0 dcbrt - - "---"));
DESCR("cube root");
-DATA(insert OID = 1284 ( "|" PGNSP PGUID l f f 0 704 702 0 0 tintervalstart - - ));
+DATA(insert OID = 1284 ( "|" PGNSP PGUID l f f 0 704 702 0 0 tintervalstart - - "---"));
DESCR("start of interval");
-DATA(insert OID = 606 ( "<#>" PGNSP PGUID b f f 702 702 704 0 0 mktinterval - - ));
+DATA(insert OID = 606 ( "<#>" PGNSP PGUID b f f 702 702 704 0 0 mktinterval - - "---"));
DESCR("convert to tinterval");
-DATA(insert OID = 607 ( "=" PGNSP PGUID b t t 26 26 16 607 608 oideq eqsel eqjoinsel ));
+DATA(insert OID = 607 ( "=" PGNSP PGUID b t t 26 26 16 607 608 oideq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 608 ( "<>" PGNSP PGUID b f f 26 26 16 608 607 oidne neqsel neqjoinsel ));
+DATA(insert OID = 608 ( "<>" PGNSP PGUID b f f 26 26 16 608 607 oidne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 609 ( "<" PGNSP PGUID b f f 26 26 16 610 612 oidlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 609 ( "<" PGNSP PGUID b f f 26 26 16 610 612 oidlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 610 ( ">" PGNSP PGUID b f f 26 26 16 609 611 oidgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 610 ( ">" PGNSP PGUID b f f 26 26 16 609 611 oidgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 611 ( "<=" PGNSP PGUID b f f 26 26 16 612 610 oidle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 611 ( "<=" PGNSP PGUID b f f 26 26 16 612 610 oidle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 612 ( ">=" PGNSP PGUID b f f 26 26 16 611 609 oidge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 612 ( ">=" PGNSP PGUID b f f 26 26 16 611 609 oidge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 644 ( "<>" PGNSP PGUID b f f 30 30 16 644 649 oidvectorne neqsel neqjoinsel ));
+DATA(insert OID = 644 ( "<>" PGNSP PGUID b f f 30 30 16 644 649 oidvectorne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 645 ( "<" PGNSP PGUID b f f 30 30 16 646 648 oidvectorlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 645 ( "<" PGNSP PGUID b f f 30 30 16 646 648 oidvectorlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 646 ( ">" PGNSP PGUID b f f 30 30 16 645 647 oidvectorgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 646 ( ">" PGNSP PGUID b f f 30 30 16 645 647 oidvectorgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 647 ( "<=" PGNSP PGUID b f f 30 30 16 648 646 oidvectorle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 647 ( "<=" PGNSP PGUID b f f 30 30 16 648 646 oidvectorle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 648 ( ">=" PGNSP PGUID b f f 30 30 16 647 645 oidvectorge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 648 ( ">=" PGNSP PGUID b f f 30 30 16 647 645 oidvectorge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 649 ( "=" PGNSP PGUID b t t 30 30 16 649 644 oidvectoreq eqsel eqjoinsel ));
+DATA(insert OID = 649 ( "=" PGNSP PGUID b t t 30 30 16 649 644 oidvectoreq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 613 ( "<->" PGNSP PGUID b f f 600 628 701 0 0 dist_pl - - ));
+DATA(insert OID = 613 ( "<->" PGNSP PGUID b f f 600 628 701 0 0 dist_pl - - "---"));
DESCR("distance between");
-DATA(insert OID = 614 ( "<->" PGNSP PGUID b f f 600 601 701 0 0 dist_ps - - ));
+DATA(insert OID = 614 ( "<->" PGNSP PGUID b f f 600 601 701 0 0 dist_ps - - "---"));
DESCR("distance between");
-DATA(insert OID = 615 ( "<->" PGNSP PGUID b f f 600 603 701 0 0 dist_pb - - ));
+DATA(insert OID = 615 ( "<->" PGNSP PGUID b f f 600 603 701 0 0 dist_pb - - "---"));
DESCR("distance between");
-DATA(insert OID = 616 ( "<->" PGNSP PGUID b f f 601 628 701 0 0 dist_sl - - ));
+DATA(insert OID = 616 ( "<->" PGNSP PGUID b f f 601 628 701 0 0 dist_sl - - "---"));
DESCR("distance between");
-DATA(insert OID = 617 ( "<->" PGNSP PGUID b f f 601 603 701 0 0 dist_sb - - ));
+DATA(insert OID = 617 ( "<->" PGNSP PGUID b f f 601 603 701 0 0 dist_sb - - "---"));
DESCR("distance between");
-DATA(insert OID = 618 ( "<->" PGNSP PGUID b f f 600 602 701 0 0 dist_ppath - - ));
+DATA(insert OID = 618 ( "<->" PGNSP PGUID b f f 600 602 701 0 0 dist_ppath - - "---"));
DESCR("distance between");
-DATA(insert OID = 620 ( "=" PGNSP PGUID b t t 700 700 16 620 621 float4eq eqsel eqjoinsel ));
+DATA(insert OID = 620 ( "=" PGNSP PGUID b t t 700 700 16 620 621 float4eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 621 ( "<>" PGNSP PGUID b f f 700 700 16 621 620 float4ne neqsel neqjoinsel ));
+DATA(insert OID = 621 ( "<>" PGNSP PGUID b f f 700 700 16 621 620 float4ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 622 ( "<" PGNSP PGUID b f f 700 700 16 623 625 float4lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 622 ( "<" PGNSP PGUID b f f 700 700 16 623 625 float4lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 623 ( ">" PGNSP PGUID b f f 700 700 16 622 624 float4gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 623 ( ">" PGNSP PGUID b f f 700 700 16 622 624 float4gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 624 ( "<=" PGNSP PGUID b f f 700 700 16 625 623 float4le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 624 ( "<=" PGNSP PGUID b f f 700 700 16 625 623 float4le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 625 ( ">=" PGNSP PGUID b f f 700 700 16 624 622 float4ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 625 ( ">=" PGNSP PGUID b f f 700 700 16 624 622 float4ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 630 ( "<>" PGNSP PGUID b f f 18 18 16 630 92 charne neqsel neqjoinsel ));
+DATA(insert OID = 630 ( "<>" PGNSP PGUID b f f 18 18 16 630 92 charne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 631 ( "<" PGNSP PGUID b f f 18 18 16 633 634 charlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 631 ( "<" PGNSP PGUID b f f 18 18 16 633 634 charlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 632 ( "<=" PGNSP PGUID b f f 18 18 16 634 633 charle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 632 ( "<=" PGNSP PGUID b f f 18 18 16 634 633 charle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 633 ( ">" PGNSP PGUID b f f 18 18 16 631 632 chargt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 633 ( ">" PGNSP PGUID b f f 18 18 16 631 632 chargt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 634 ( ">=" PGNSP PGUID b f f 18 18 16 632 631 charge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 634 ( ">=" PGNSP PGUID b f f 18 18 16 632 631 charge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 639 ( "~" PGNSP PGUID b f f 19 25 16 0 640 nameregexeq regexeqsel regexeqjoinsel ));
+DATA(insert OID = 639 ( "~" PGNSP PGUID b f f 19 25 16 0 640 nameregexeq regexeqsel regexeqjoinsel "mhf"));
DESCR("matches regular expression, case-sensitive");
#define OID_NAME_REGEXEQ_OP 639
-DATA(insert OID = 640 ( "!~" PGNSP PGUID b f f 19 25 16 0 639 nameregexne regexnesel regexnejoinsel ));
+DATA(insert OID = 640 ( "!~" PGNSP PGUID b f f 19 25 16 0 639 nameregexne regexnesel regexnejoinsel "---"));
DESCR("does not match regular expression, case-sensitive");
-DATA(insert OID = 641 ( "~" PGNSP PGUID b f f 25 25 16 0 642 textregexeq regexeqsel regexeqjoinsel ));
+DATA(insert OID = 641 ( "~" PGNSP PGUID b f f 25 25 16 0 642 textregexeq regexeqsel regexeqjoinsel "mhf"));
DESCR("matches regular expression, case-sensitive");
#define OID_TEXT_REGEXEQ_OP 641
-DATA(insert OID = 642 ( "!~" PGNSP PGUID b f f 25 25 16 0 641 textregexne regexnesel regexnejoinsel ));
+DATA(insert OID = 642 ( "!~" PGNSP PGUID b f f 25 25 16 0 641 textregexne regexnesel regexnejoinsel "---"));
DESCR("does not match regular expression, case-sensitive");
-DATA(insert OID = 643 ( "<>" PGNSP PGUID b f f 19 19 16 643 93 namene neqsel neqjoinsel ));
+DATA(insert OID = 643 ( "<>" PGNSP PGUID b f f 19 19 16 643 93 namene neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 654 ( "||" PGNSP PGUID b f f 25 25 25 0 0 textcat - - ));
+DATA(insert OID = 654 ( "||" PGNSP PGUID b f f 25 25 25 0 0 textcat - - "---"));
DESCR("concatenate");
-DATA(insert OID = 660 ( "<" PGNSP PGUID b f f 19 19 16 662 663 namelt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 660 ( "<" PGNSP PGUID b f f 19 19 16 662 663 namelt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 661 ( "<=" PGNSP PGUID b f f 19 19 16 663 662 namele scalarltsel scalarltjoinsel ));
+DATA(insert OID = 661 ( "<=" PGNSP PGUID b f f 19 19 16 663 662 namele scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 662 ( ">" PGNSP PGUID b f f 19 19 16 660 661 namegt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 662 ( ">" PGNSP PGUID b f f 19 19 16 660 661 namegt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 663 ( ">=" PGNSP PGUID b f f 19 19 16 661 660 namege scalargtsel scalargtjoinsel ));
+DATA(insert OID = 663 ( ">=" PGNSP PGUID b f f 19 19 16 661 660 namege scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 664 ( "<" PGNSP PGUID b f f 25 25 16 666 667 text_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 664 ( "<" PGNSP PGUID b f f 25 25 16 666 667 text_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 665 ( "<=" PGNSP PGUID b f f 25 25 16 667 666 text_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 665 ( "<=" PGNSP PGUID b f f 25 25 16 667 666 text_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 666 ( ">" PGNSP PGUID b f f 25 25 16 664 665 text_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 666 ( ">" PGNSP PGUID b f f 25 25 16 664 665 text_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 667 ( ">=" PGNSP PGUID b f f 25 25 16 665 664 text_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 667 ( ">=" PGNSP PGUID b f f 25 25 16 665 664 text_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 670 ( "=" PGNSP PGUID b t t 701 701 16 670 671 float8eq eqsel eqjoinsel ));
+DATA(insert OID = 670 ( "=" PGNSP PGUID b t t 701 701 16 670 671 float8eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 671 ( "<>" PGNSP PGUID b f f 701 701 16 671 670 float8ne neqsel neqjoinsel ));
+DATA(insert OID = 671 ( "<>" PGNSP PGUID b f f 701 701 16 671 670 float8ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 672 ( "<" PGNSP PGUID b f f 701 701 16 674 675 float8lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 672 ( "<" PGNSP PGUID b f f 701 701 16 674 675 float8lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
#define Float8LessOperator 672
-DATA(insert OID = 673 ( "<=" PGNSP PGUID b f f 701 701 16 675 674 float8le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 673 ( "<=" PGNSP PGUID b f f 701 701 16 675 674 float8le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 674 ( ">" PGNSP PGUID b f f 701 701 16 672 673 float8gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 674 ( ">" PGNSP PGUID b f f 701 701 16 672 673 float8gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 675 ( ">=" PGNSP PGUID b f f 701 701 16 673 672 float8ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 675 ( ">=" PGNSP PGUID b f f 701 701 16 673 672 float8ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 682 ( "@" PGNSP PGUID l f f 0 21 21 0 0 int2abs - - ));
+DATA(insert OID = 682 ( "@" PGNSP PGUID l f f 0 21 21 0 0 int2abs - - "---"));
DESCR("absolute value");
-DATA(insert OID = 684 ( "+" PGNSP PGUID b f f 20 20 20 684 0 int8pl - - ));
+DATA(insert OID = 684 ( "+" PGNSP PGUID b f f 20 20 20 684 0 int8pl - - "---"));
DESCR("add");
-DATA(insert OID = 685 ( "-" PGNSP PGUID b f f 20 20 20 0 0 int8mi - - ));
+DATA(insert OID = 685 ( "-" PGNSP PGUID b f f 20 20 20 0 0 int8mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 686 ( "*" PGNSP PGUID b f f 20 20 20 686 0 int8mul - - ));
+DATA(insert OID = 686 ( "*" PGNSP PGUID b f f 20 20 20 686 0 int8mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 687 ( "/" PGNSP PGUID b f f 20 20 20 0 0 int8div - - ));
+DATA(insert OID = 687 ( "/" PGNSP PGUID b f f 20 20 20 0 0 int8div - - "---"));
DESCR("divide");
-DATA(insert OID = 688 ( "+" PGNSP PGUID b f f 20 23 20 692 0 int84pl - - ));
+DATA(insert OID = 688 ( "+" PGNSP PGUID b f f 20 23 20 692 0 int84pl - - "---"));
DESCR("add");
-DATA(insert OID = 689 ( "-" PGNSP PGUID b f f 20 23 20 0 0 int84mi - - ));
+DATA(insert OID = 689 ( "-" PGNSP PGUID b f f 20 23 20 0 0 int84mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 690 ( "*" PGNSP PGUID b f f 20 23 20 694 0 int84mul - - ));
+DATA(insert OID = 690 ( "*" PGNSP PGUID b f f 20 23 20 694 0 int84mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 691 ( "/" PGNSP PGUID b f f 20 23 20 0 0 int84div - - ));
+DATA(insert OID = 691 ( "/" PGNSP PGUID b f f 20 23 20 0 0 int84div - - "---"));
DESCR("divide");
-DATA(insert OID = 692 ( "+" PGNSP PGUID b f f 23 20 20 688 0 int48pl - - ));
+DATA(insert OID = 692 ( "+" PGNSP PGUID b f f 23 20 20 688 0 int48pl - - "---"));
DESCR("add");
-DATA(insert OID = 693 ( "-" PGNSP PGUID b f f 23 20 20 0 0 int48mi - - ));
+DATA(insert OID = 693 ( "-" PGNSP PGUID b f f 23 20 20 0 0 int48mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 694 ( "*" PGNSP PGUID b f f 23 20 20 690 0 int48mul - - ));
+DATA(insert OID = 694 ( "*" PGNSP PGUID b f f 23 20 20 690 0 int48mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 695 ( "/" PGNSP PGUID b f f 23 20 20 0 0 int48div - - ));
+DATA(insert OID = 695 ( "/" PGNSP PGUID b f f 23 20 20 0 0 int48div - - "---"));
DESCR("divide");
-DATA(insert OID = 818 ( "+" PGNSP PGUID b f f 20 21 20 822 0 int82pl - - ));
+DATA(insert OID = 818 ( "+" PGNSP PGUID b f f 20 21 20 822 0 int82pl - - "---"));
DESCR("add");
-DATA(insert OID = 819 ( "-" PGNSP PGUID b f f 20 21 20 0 0 int82mi - - ));
+DATA(insert OID = 819 ( "-" PGNSP PGUID b f f 20 21 20 0 0 int82mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 820 ( "*" PGNSP PGUID b f f 20 21 20 824 0 int82mul - - ));
+DATA(insert OID = 820 ( "*" PGNSP PGUID b f f 20 21 20 824 0 int82mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 821 ( "/" PGNSP PGUID b f f 20 21 20 0 0 int82div - - ));
+DATA(insert OID = 821 ( "/" PGNSP PGUID b f f 20 21 20 0 0 int82div - - "---"));
DESCR("divide");
-DATA(insert OID = 822 ( "+" PGNSP PGUID b f f 21 20 20 818 0 int28pl - - ));
+DATA(insert OID = 822 ( "+" PGNSP PGUID b f f 21 20 20 818 0 int28pl - - "---"));
DESCR("add");
-DATA(insert OID = 823 ( "-" PGNSP PGUID b f f 21 20 20 0 0 int28mi - - ));
+DATA(insert OID = 823 ( "-" PGNSP PGUID b f f 21 20 20 0 0 int28mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 824 ( "*" PGNSP PGUID b f f 21 20 20 820 0 int28mul - - ));
+DATA(insert OID = 824 ( "*" PGNSP PGUID b f f 21 20 20 820 0 int28mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 825 ( "/" PGNSP PGUID b f f 21 20 20 0 0 int28div - - ));
+DATA(insert OID = 825 ( "/" PGNSP PGUID b f f 21 20 20 0 0 int28div - - "---"));
DESCR("divide");
-DATA(insert OID = 706 ( "<->" PGNSP PGUID b f f 603 603 701 706 0 box_distance - - ));
+DATA(insert OID = 706 ( "<->" PGNSP PGUID b f f 603 603 701 706 0 box_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 707 ( "<->" PGNSP PGUID b f f 602 602 701 707 0 path_distance - - ));
+DATA(insert OID = 707 ( "<->" PGNSP PGUID b f f 602 602 701 707 0 path_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 708 ( "<->" PGNSP PGUID b f f 628 628 701 708 0 line_distance - - ));
+DATA(insert OID = 708 ( "<->" PGNSP PGUID b f f 628 628 701 708 0 line_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 709 ( "<->" PGNSP PGUID b f f 601 601 701 709 0 lseg_distance - - ));
+DATA(insert OID = 709 ( "<->" PGNSP PGUID b f f 601 601 701 709 0 lseg_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 712 ( "<->" PGNSP PGUID b f f 604 604 701 712 0 poly_distance - - ));
+DATA(insert OID = 712 ( "<->" PGNSP PGUID b f f 604 604 701 712 0 poly_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 713 ( "<>" PGNSP PGUID b f f 600 600 16 713 510 point_ne neqsel neqjoinsel ));
+DATA(insert OID = 713 ( "<>" PGNSP PGUID b f f 600 600 16 713 510 point_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
/* add translation/rotation/scaling operators for geometric types. - thomas 97/05/10 */
-DATA(insert OID = 731 ( "+" PGNSP PGUID b f f 600 600 600 731 0 point_add - - ));
+DATA(insert OID = 731 ( "+" PGNSP PGUID b f f 600 600 600 731 0 point_add - - "---"));
DESCR("add points (translate)");
-DATA(insert OID = 732 ( "-" PGNSP PGUID b f f 600 600 600 0 0 point_sub - - ));
+DATA(insert OID = 732 ( "-" PGNSP PGUID b f f 600 600 600 0 0 point_sub - - "---"));
DESCR("subtract points (translate)");
-DATA(insert OID = 733 ( "*" PGNSP PGUID b f f 600 600 600 733 0 point_mul - - ));
+DATA(insert OID = 733 ( "*" PGNSP PGUID b f f 600 600 600 733 0 point_mul - - "---"));
DESCR("multiply points (scale/rotate)");
-DATA(insert OID = 734 ( "/" PGNSP PGUID b f f 600 600 600 0 0 point_div - - ));
+DATA(insert OID = 734 ( "/" PGNSP PGUID b f f 600 600 600 0 0 point_div - - "---"));
DESCR("divide points (scale/rotate)");
-DATA(insert OID = 735 ( "+" PGNSP PGUID b f f 602 602 602 735 0 path_add - - ));
+DATA(insert OID = 735 ( "+" PGNSP PGUID b f f 602 602 602 735 0 path_add - - "---"));
DESCR("concatenate");
-DATA(insert OID = 736 ( "+" PGNSP PGUID b f f 602 600 602 0 0 path_add_pt - - ));
+DATA(insert OID = 736 ( "+" PGNSP PGUID b f f 602 600 602 0 0 path_add_pt - - "---"));
DESCR("add (translate path)");
-DATA(insert OID = 737 ( "-" PGNSP PGUID b f f 602 600 602 0 0 path_sub_pt - - ));
+DATA(insert OID = 737 ( "-" PGNSP PGUID b f f 602 600 602 0 0 path_sub_pt - - "---"));
DESCR("subtract (translate path)");
-DATA(insert OID = 738 ( "*" PGNSP PGUID b f f 602 600 602 0 0 path_mul_pt - - ));
+DATA(insert OID = 738 ( "*" PGNSP PGUID b f f 602 600 602 0 0 path_mul_pt - - "---"));
DESCR("multiply (rotate/scale path)");
-DATA(insert OID = 739 ( "/" PGNSP PGUID b f f 602 600 602 0 0 path_div_pt - - ));
+DATA(insert OID = 739 ( "/" PGNSP PGUID b f f 602 600 602 0 0 path_div_pt - - "---"));
DESCR("divide (rotate/scale path)");
-DATA(insert OID = 755 ( "@>" PGNSP PGUID b f f 602 600 16 512 0 path_contain_pt - - ));
+DATA(insert OID = 755 ( "@>" PGNSP PGUID b f f 602 600 16 512 0 path_contain_pt - - "---"));
DESCR("contains");
-DATA(insert OID = 756 ( "<@" PGNSP PGUID b f f 600 604 16 757 0 pt_contained_poly contsel contjoinsel ));
+DATA(insert OID = 756 ( "<@" PGNSP PGUID b f f 600 604 16 757 0 pt_contained_poly contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 757 ( "@>" PGNSP PGUID b f f 604 600 16 756 0 poly_contain_pt contsel contjoinsel ));
+DATA(insert OID = 757 ( "@>" PGNSP PGUID b f f 604 600 16 756 0 poly_contain_pt contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 758 ( "<@" PGNSP PGUID b f f 600 718 16 759 0 pt_contained_circle contsel contjoinsel ));
+DATA(insert OID = 758 ( "<@" PGNSP PGUID b f f 600 718 16 759 0 pt_contained_circle contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 759 ( "@>" PGNSP PGUID b f f 718 600 16 758 0 circle_contain_pt contsel contjoinsel ));
+DATA(insert OID = 759 ( "@>" PGNSP PGUID b f f 718 600 16 758 0 circle_contain_pt contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 773 ( "@" PGNSP PGUID l f f 0 23 23 0 0 int4abs - - ));
+DATA(insert OID = 773 ( "@" PGNSP PGUID l f f 0 23 23 0 0 int4abs - - "---"));
DESCR("absolute value");
/* additional operators for geometric types - thomas 1997-07-09 */
-DATA(insert OID = 792 ( "=" PGNSP PGUID b f f 602 602 16 792 0 path_n_eq eqsel eqjoinsel ));
+DATA(insert OID = 792 ( "=" PGNSP PGUID b f f 602 602 16 792 0 path_n_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 793 ( "<" PGNSP PGUID b f f 602 602 16 794 0 path_n_lt - - ));
+DATA(insert OID = 793 ( "<" PGNSP PGUID b f f 602 602 16 794 0 path_n_lt - - "---"));
DESCR("less than");
-DATA(insert OID = 794 ( ">" PGNSP PGUID b f f 602 602 16 793 0 path_n_gt - - ));
+DATA(insert OID = 794 ( ">" PGNSP PGUID b f f 602 602 16 793 0 path_n_gt - - "---"));
DESCR("greater than");
-DATA(insert OID = 795 ( "<=" PGNSP PGUID b f f 602 602 16 796 0 path_n_le - - ));
+DATA(insert OID = 795 ( "<=" PGNSP PGUID b f f 602 602 16 796 0 path_n_le - - "---"));
DESCR("less than or equal");
-DATA(insert OID = 796 ( ">=" PGNSP PGUID b f f 602 602 16 795 0 path_n_ge - - ));
+DATA(insert OID = 796 ( ">=" PGNSP PGUID b f f 602 602 16 795 0 path_n_ge - - "---"));
DESCR("greater than or equal");
-DATA(insert OID = 797 ( "#" PGNSP PGUID l f f 0 602 23 0 0 path_npoints - - ));
+DATA(insert OID = 797 ( "#" PGNSP PGUID l f f 0 602 23 0 0 path_npoints - - "---"));
DESCR("number of points");
-DATA(insert OID = 798 ( "?#" PGNSP PGUID b f f 602 602 16 0 0 path_inter - - ));
+DATA(insert OID = 798 ( "?#" PGNSP PGUID b f f 602 602 16 0 0 path_inter - - "---"));
DESCR("intersect");
-DATA(insert OID = 799 ( "@-@" PGNSP PGUID l f f 0 602 701 0 0 path_length - - ));
+DATA(insert OID = 799 ( "@-@" PGNSP PGUID l f f 0 602 701 0 0 path_length - - "---"));
DESCR("sum of path segment lengths");
-DATA(insert OID = 800 ( ">^" PGNSP PGUID b f f 603 603 16 0 0 box_above_eq positionsel positionjoinsel ));
+DATA(insert OID = 800 ( ">^" PGNSP PGUID b f f 603 603 16 0 0 box_above_eq positionsel positionjoinsel "---"));
DESCR("is above (allows touching)");
-DATA(insert OID = 801 ( "<^" PGNSP PGUID b f f 603 603 16 0 0 box_below_eq positionsel positionjoinsel ));
+DATA(insert OID = 801 ( "<^" PGNSP PGUID b f f 603 603 16 0 0 box_below_eq positionsel positionjoinsel "---"));
DESCR("is below (allows touching)");
-DATA(insert OID = 802 ( "?#" PGNSP PGUID b f f 603 603 16 0 0 box_overlap areasel areajoinsel ));
+DATA(insert OID = 802 ( "?#" PGNSP PGUID b f f 603 603 16 0 0 box_overlap areasel areajoinsel "---"));
DESCR("deprecated, use && instead");
-DATA(insert OID = 803 ( "#" PGNSP PGUID b f f 603 603 603 0 0 box_intersect - - ));
+DATA(insert OID = 803 ( "#" PGNSP PGUID b f f 603 603 603 0 0 box_intersect - - "---"));
DESCR("box intersection");
-DATA(insert OID = 804 ( "+" PGNSP PGUID b f f 603 600 603 0 0 box_add - - ));
+DATA(insert OID = 804 ( "+" PGNSP PGUID b f f 603 600 603 0 0 box_add - - "---"));
DESCR("add point to box (translate)");
-DATA(insert OID = 805 ( "-" PGNSP PGUID b f f 603 600 603 0 0 box_sub - - ));
+DATA(insert OID = 805 ( "-" PGNSP PGUID b f f 603 600 603 0 0 box_sub - - "---"));
DESCR("subtract point from box (translate)");
-DATA(insert OID = 806 ( "*" PGNSP PGUID b f f 603 600 603 0 0 box_mul - - ));
+DATA(insert OID = 806 ( "*" PGNSP PGUID b f f 603 600 603 0 0 box_mul - - "---"));
DESCR("multiply box by point (scale)");
-DATA(insert OID = 807 ( "/" PGNSP PGUID b f f 603 600 603 0 0 box_div - - ));
+DATA(insert OID = 807 ( "/" PGNSP PGUID b f f 603 600 603 0 0 box_div - - "---"));
DESCR("divide box by point (scale)");
-DATA(insert OID = 808 ( "?-" PGNSP PGUID b f f 600 600 16 808 0 point_horiz - - ));
+DATA(insert OID = 808 ( "?-" PGNSP PGUID b f f 600 600 16 808 0 point_horiz - - "---"));
DESCR("horizontally aligned");
-DATA(insert OID = 809 ( "?|" PGNSP PGUID b f f 600 600 16 809 0 point_vert - - ));
+DATA(insert OID = 809 ( "?|" PGNSP PGUID b f f 600 600 16 809 0 point_vert - - "---"));
DESCR("vertically aligned");
-DATA(insert OID = 811 ( "=" PGNSP PGUID b t f 704 704 16 811 812 tintervaleq eqsel eqjoinsel ));
+DATA(insert OID = 811 ( "=" PGNSP PGUID b t f 704 704 16 811 812 tintervaleq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 812 ( "<>" PGNSP PGUID b f f 704 704 16 812 811 tintervalne neqsel neqjoinsel ));
+DATA(insert OID = 812 ( "<>" PGNSP PGUID b f f 704 704 16 812 811 tintervalne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 813 ( "<" PGNSP PGUID b f f 704 704 16 814 816 tintervallt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 813 ( "<" PGNSP PGUID b f f 704 704 16 814 816 tintervallt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 814 ( ">" PGNSP PGUID b f f 704 704 16 813 815 tintervalgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 814 ( ">" PGNSP PGUID b f f 704 704 16 813 815 tintervalgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 815 ( "<=" PGNSP PGUID b f f 704 704 16 816 814 tintervalle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 815 ( "<=" PGNSP PGUID b f f 704 704 16 816 814 tintervalle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 816 ( ">=" PGNSP PGUID b f f 704 704 16 815 813 tintervalge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 816 ( ">=" PGNSP PGUID b f f 704 704 16 815 813 tintervalge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 843 ( "*" PGNSP PGUID b f f 790 700 790 845 0 cash_mul_flt4 - - ));
+DATA(insert OID = 843 ( "*" PGNSP PGUID b f f 790 700 790 845 0 cash_mul_flt4 - - "---"));
DESCR("multiply");
-DATA(insert OID = 844 ( "/" PGNSP PGUID b f f 790 700 790 0 0 cash_div_flt4 - - ));
+DATA(insert OID = 844 ( "/" PGNSP PGUID b f f 790 700 790 0 0 cash_div_flt4 - - "---"));
DESCR("divide");
-DATA(insert OID = 845 ( "*" PGNSP PGUID b f f 700 790 790 843 0 flt4_mul_cash - - ));
+DATA(insert OID = 845 ( "*" PGNSP PGUID b f f 700 790 790 843 0 flt4_mul_cash - - "---"));
DESCR("multiply");
-DATA(insert OID = 900 ( "=" PGNSP PGUID b t f 790 790 16 900 901 cash_eq eqsel eqjoinsel ));
+DATA(insert OID = 900 ( "=" PGNSP PGUID b t f 790 790 16 900 901 cash_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 901 ( "<>" PGNSP PGUID b f f 790 790 16 901 900 cash_ne neqsel neqjoinsel ));
+DATA(insert OID = 901 ( "<>" PGNSP PGUID b f f 790 790 16 901 900 cash_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 902 ( "<" PGNSP PGUID b f f 790 790 16 903 905 cash_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 902 ( "<" PGNSP PGUID b f f 790 790 16 903 905 cash_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 903 ( ">" PGNSP PGUID b f f 790 790 16 902 904 cash_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 903 ( ">" PGNSP PGUID b f f 790 790 16 902 904 cash_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 904 ( "<=" PGNSP PGUID b f f 790 790 16 905 903 cash_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 904 ( "<=" PGNSP PGUID b f f 790 790 16 905 903 cash_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 905 ( ">=" PGNSP PGUID b f f 790 790 16 904 902 cash_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 905 ( ">=" PGNSP PGUID b f f 790 790 16 904 902 cash_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 906 ( "+" PGNSP PGUID b f f 790 790 790 906 0 cash_pl - - ));
+DATA(insert OID = 906 ( "+" PGNSP PGUID b f f 790 790 790 906 0 cash_pl - - "---"));
DESCR("add");
-DATA(insert OID = 907 ( "-" PGNSP PGUID b f f 790 790 790 0 0 cash_mi - - ));
+DATA(insert OID = 907 ( "-" PGNSP PGUID b f f 790 790 790 0 0 cash_mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 908 ( "*" PGNSP PGUID b f f 790 701 790 916 0 cash_mul_flt8 - - ));
+DATA(insert OID = 908 ( "*" PGNSP PGUID b f f 790 701 790 916 0 cash_mul_flt8 - - "---"));
DESCR("multiply");
-DATA(insert OID = 909 ( "/" PGNSP PGUID b f f 790 701 790 0 0 cash_div_flt8 - - ));
+DATA(insert OID = 909 ( "/" PGNSP PGUID b f f 790 701 790 0 0 cash_div_flt8 - - "---"));
DESCR("divide");
-DATA(insert OID = 912 ( "*" PGNSP PGUID b f f 790 23 790 917 0 cash_mul_int4 - - ));
+DATA(insert OID = 912 ( "*" PGNSP PGUID b f f 790 23 790 917 0 cash_mul_int4 - - "---"));
DESCR("multiply");
-DATA(insert OID = 913 ( "/" PGNSP PGUID b f f 790 23 790 0 0 cash_div_int4 - - ));
+DATA(insert OID = 913 ( "/" PGNSP PGUID b f f 790 23 790 0 0 cash_div_int4 - - "---"));
DESCR("divide");
-DATA(insert OID = 914 ( "*" PGNSP PGUID b f f 790 21 790 918 0 cash_mul_int2 - - ));
+DATA(insert OID = 914 ( "*" PGNSP PGUID b f f 790 21 790 918 0 cash_mul_int2 - - "---"));
DESCR("multiply");
-DATA(insert OID = 915 ( "/" PGNSP PGUID b f f 790 21 790 0 0 cash_div_int2 - - ));
+DATA(insert OID = 915 ( "/" PGNSP PGUID b f f 790 21 790 0 0 cash_div_int2 - - "---"));
DESCR("divide");
-DATA(insert OID = 916 ( "*" PGNSP PGUID b f f 701 790 790 908 0 flt8_mul_cash - - ));
+DATA(insert OID = 916 ( "*" PGNSP PGUID b f f 701 790 790 908 0 flt8_mul_cash - - "---"));
DESCR("multiply");
-DATA(insert OID = 917 ( "*" PGNSP PGUID b f f 23 790 790 912 0 int4_mul_cash - - ));
+DATA(insert OID = 917 ( "*" PGNSP PGUID b f f 23 790 790 912 0 int4_mul_cash - - "---"));
DESCR("multiply");
-DATA(insert OID = 918 ( "*" PGNSP PGUID b f f 21 790 790 914 0 int2_mul_cash - - ));
+DATA(insert OID = 918 ( "*" PGNSP PGUID b f f 21 790 790 914 0 int2_mul_cash - - "---"));
DESCR("multiply");
-DATA(insert OID = 3825 ( "/" PGNSP PGUID b f f 790 790 701 0 0 cash_div_cash - - ));
+DATA(insert OID = 3825 ( "/" PGNSP PGUID b f f 790 790 701 0 0 cash_div_cash - - "---"));
DESCR("divide");
-DATA(insert OID = 965 ( "^" PGNSP PGUID b f f 701 701 701 0 0 dpow - - ));
+DATA(insert OID = 965 ( "^" PGNSP PGUID b f f 701 701 701 0 0 dpow - - "---"));
DESCR("exponentiation");
-DATA(insert OID = 966 ( "+" PGNSP PGUID b f f 1034 1033 1034 0 0 aclinsert - - ));
+DATA(insert OID = 966 ( "+" PGNSP PGUID b f f 1034 1033 1034 0 0 aclinsert - - "---"));
DESCR("add/update ACL item");
-DATA(insert OID = 967 ( "-" PGNSP PGUID b f f 1034 1033 1034 0 0 aclremove - - ));
+DATA(insert OID = 967 ( "-" PGNSP PGUID b f f 1034 1033 1034 0 0 aclremove - - "---"));
DESCR("remove ACL item");
-DATA(insert OID = 968 ( "@>" PGNSP PGUID b f f 1034 1033 16 0 0 aclcontains - - ));
+DATA(insert OID = 968 ( "@>" PGNSP PGUID b f f 1034 1033 16 0 0 aclcontains - - "---"));
DESCR("contains");
-DATA(insert OID = 974 ( "=" PGNSP PGUID b f t 1033 1033 16 974 0 aclitemeq eqsel eqjoinsel ));
+DATA(insert OID = 974 ( "=" PGNSP PGUID b f t 1033 1033 16 974 0 aclitemeq eqsel eqjoinsel "mhf"));
DESCR("equal");
/* additional geometric operators - thomas 1997-07-09 */
-DATA(insert OID = 969 ( "@@" PGNSP PGUID l f f 0 601 600 0 0 lseg_center - - ));
+DATA(insert OID = 969 ( "@@" PGNSP PGUID l f f 0 601 600 0 0 lseg_center - - "---"));
DESCR("center of");
-DATA(insert OID = 970 ( "@@" PGNSP PGUID l f f 0 602 600 0 0 path_center - - ));
+DATA(insert OID = 970 ( "@@" PGNSP PGUID l f f 0 602 600 0 0 path_center - - "---"));
DESCR("center of");
-DATA(insert OID = 971 ( "@@" PGNSP PGUID l f f 0 604 600 0 0 poly_center - - ));
+DATA(insert OID = 971 ( "@@" PGNSP PGUID l f f 0 604 600 0 0 poly_center - - "---"));
DESCR("center of");
-DATA(insert OID = 1054 ( "=" PGNSP PGUID b t t 1042 1042 16 1054 1057 bpchareq eqsel eqjoinsel ));
+DATA(insert OID = 1054 ( "=" PGNSP PGUID b t t 1042 1042 16 1054 1057 bpchareq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1055 ( "~" PGNSP PGUID b f f 1042 25 16 0 1056 bpcharregexeq regexeqsel regexeqjoinsel ));
+DATA(insert OID = 1055 ( "~" PGNSP PGUID b f f 1042 25 16 0 1056 bpcharregexeq regexeqsel regexeqjoinsel "mhf"));
DESCR("matches regular expression, case-sensitive");
#define OID_BPCHAR_REGEXEQ_OP 1055
-DATA(insert OID = 1056 ( "!~" PGNSP PGUID b f f 1042 25 16 0 1055 bpcharregexne regexnesel regexnejoinsel ));
+DATA(insert OID = 1056 ( "!~" PGNSP PGUID b f f 1042 25 16 0 1055 bpcharregexne regexnesel regexnejoinsel "---"));
DESCR("does not match regular expression, case-sensitive");
-DATA(insert OID = 1057 ( "<>" PGNSP PGUID b f f 1042 1042 16 1057 1054 bpcharne neqsel neqjoinsel ));
+DATA(insert OID = 1057 ( "<>" PGNSP PGUID b f f 1042 1042 16 1057 1054 bpcharne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1058 ( "<" PGNSP PGUID b f f 1042 1042 16 1060 1061 bpcharlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1058 ( "<" PGNSP PGUID b f f 1042 1042 16 1060 1061 bpcharlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1059 ( "<=" PGNSP PGUID b f f 1042 1042 16 1061 1060 bpcharle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1059 ( "<=" PGNSP PGUID b f f 1042 1042 16 1061 1060 bpcharle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1060 ( ">" PGNSP PGUID b f f 1042 1042 16 1058 1059 bpchargt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1060 ( ">" PGNSP PGUID b f f 1042 1042 16 1058 1059 bpchargt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1061 ( ">=" PGNSP PGUID b f f 1042 1042 16 1059 1058 bpcharge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1061 ( ">=" PGNSP PGUID b f f 1042 1042 16 1059 1058 bpcharge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* generic array comparison operators */
-DATA(insert OID = 1070 ( "=" PGNSP PGUID b t t 2277 2277 16 1070 1071 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 1070 ( "=" PGNSP PGUID b t t 2277 2277 16 1070 1071 array_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
#define ARRAY_EQ_OP 1070
-DATA(insert OID = 1071 ( "<>" PGNSP PGUID b f f 2277 2277 16 1071 1070 array_ne neqsel neqjoinsel ));
+DATA(insert OID = 1071 ( "<>" PGNSP PGUID b f f 2277 2277 16 1071 1070 array_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1072 ( "<" PGNSP PGUID b f f 2277 2277 16 1073 1075 array_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1072 ( "<" PGNSP PGUID b f f 2277 2277 16 1073 1075 array_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
#define ARRAY_LT_OP 1072
-DATA(insert OID = 1073 ( ">" PGNSP PGUID b f f 2277 2277 16 1072 1074 array_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1073 ( ">" PGNSP PGUID b f f 2277 2277 16 1072 1074 array_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
#define ARRAY_GT_OP 1073
-DATA(insert OID = 1074 ( "<=" PGNSP PGUID b f f 2277 2277 16 1075 1073 array_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1074 ( "<=" PGNSP PGUID b f f 2277 2277 16 1075 1073 array_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1075 ( ">=" PGNSP PGUID b f f 2277 2277 16 1074 1072 array_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1075 ( ">=" PGNSP PGUID b f f 2277 2277 16 1074 1072 array_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* date operators */
-DATA(insert OID = 1076 ( "+" PGNSP PGUID b f f 1082 1186 1114 2551 0 date_pl_interval - - ));
+DATA(insert OID = 1076 ( "+" PGNSP PGUID b f f 1082 1186 1114 2551 0 date_pl_interval - - "---"));
DESCR("add");
-DATA(insert OID = 1077 ( "-" PGNSP PGUID b f f 1082 1186 1114 0 0 date_mi_interval - - ));
+DATA(insert OID = 1077 ( "-" PGNSP PGUID b f f 1082 1186 1114 0 0 date_mi_interval - - "---"));
DESCR("subtract");
-DATA(insert OID = 1093 ( "=" PGNSP PGUID b t t 1082 1082 16 1093 1094 date_eq eqsel eqjoinsel ));
+DATA(insert OID = 1093 ( "=" PGNSP PGUID b t t 1082 1082 16 1093 1094 date_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1094 ( "<>" PGNSP PGUID b f f 1082 1082 16 1094 1093 date_ne neqsel neqjoinsel ));
+DATA(insert OID = 1094 ( "<>" PGNSP PGUID b f f 1082 1082 16 1094 1093 date_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1095 ( "<" PGNSP PGUID b f f 1082 1082 16 1097 1098 date_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1095 ( "<" PGNSP PGUID b f f 1082 1082 16 1097 1098 date_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1096 ( "<=" PGNSP PGUID b f f 1082 1082 16 1098 1097 date_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1096 ( "<=" PGNSP PGUID b f f 1082 1082 16 1098 1097 date_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1097 ( ">" PGNSP PGUID b f f 1082 1082 16 1095 1096 date_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1097 ( ">" PGNSP PGUID b f f 1082 1082 16 1095 1096 date_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1098 ( ">=" PGNSP PGUID b f f 1082 1082 16 1096 1095 date_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1098 ( ">=" PGNSP PGUID b f f 1082 1082 16 1096 1095 date_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1099 ( "-" PGNSP PGUID b f f 1082 1082 23 0 0 date_mi - - ));
+DATA(insert OID = 1099 ( "-" PGNSP PGUID b f f 1082 1082 23 0 0 date_mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 1100 ( "+" PGNSP PGUID b f f 1082 23 1082 2555 0 date_pli - - ));
+DATA(insert OID = 1100 ( "+" PGNSP PGUID b f f 1082 23 1082 2555 0 date_pli - - "---"));
DESCR("add");
-DATA(insert OID = 1101 ( "-" PGNSP PGUID b f f 1082 23 1082 0 0 date_mii - - ));
+DATA(insert OID = 1101 ( "-" PGNSP PGUID b f f 1082 23 1082 0 0 date_mii - - "---"));
DESCR("subtract");
/* time operators */
-DATA(insert OID = 1108 ( "=" PGNSP PGUID b t t 1083 1083 16 1108 1109 time_eq eqsel eqjoinsel ));
+DATA(insert OID = 1108 ( "=" PGNSP PGUID b t t 1083 1083 16 1108 1109 time_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1109 ( "<>" PGNSP PGUID b f f 1083 1083 16 1109 1108 time_ne neqsel neqjoinsel ));
+DATA(insert OID = 1109 ( "<>" PGNSP PGUID b f f 1083 1083 16 1109 1108 time_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1110 ( "<" PGNSP PGUID b f f 1083 1083 16 1112 1113 time_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1110 ( "<" PGNSP PGUID b f f 1083 1083 16 1112 1113 time_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1111 ( "<=" PGNSP PGUID b f f 1083 1083 16 1113 1112 time_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1111 ( "<=" PGNSP PGUID b f f 1083 1083 16 1113 1112 time_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1112 ( ">" PGNSP PGUID b f f 1083 1083 16 1110 1111 time_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1112 ( ">" PGNSP PGUID b f f 1083 1083 16 1110 1111 time_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1113 ( ">=" PGNSP PGUID b f f 1083 1083 16 1111 1110 time_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1113 ( ">=" PGNSP PGUID b f f 1083 1083 16 1111 1110 time_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* timetz operators */
-DATA(insert OID = 1550 ( "=" PGNSP PGUID b t t 1266 1266 16 1550 1551 timetz_eq eqsel eqjoinsel ));
+DATA(insert OID = 1550 ( "=" PGNSP PGUID b t t 1266 1266 16 1550 1551 timetz_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1551 ( "<>" PGNSP PGUID b f f 1266 1266 16 1551 1550 timetz_ne neqsel neqjoinsel ));
+DATA(insert OID = 1551 ( "<>" PGNSP PGUID b f f 1266 1266 16 1551 1550 timetz_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1552 ( "<" PGNSP PGUID b f f 1266 1266 16 1554 1555 timetz_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1552 ( "<" PGNSP PGUID b f f 1266 1266 16 1554 1555 timetz_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1553 ( "<=" PGNSP PGUID b f f 1266 1266 16 1555 1554 timetz_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1553 ( "<=" PGNSP PGUID b f f 1266 1266 16 1555 1554 timetz_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1554 ( ">" PGNSP PGUID b f f 1266 1266 16 1552 1553 timetz_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1554 ( ">" PGNSP PGUID b f f 1266 1266 16 1552 1553 timetz_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1555 ( ">=" PGNSP PGUID b f f 1266 1266 16 1553 1552 timetz_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1555 ( ">=" PGNSP PGUID b f f 1266 1266 16 1553 1552 timetz_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* float48 operators */
-DATA(insert OID = 1116 ( "+" PGNSP PGUID b f f 700 701 701 1126 0 float48pl - - ));
+DATA(insert OID = 1116 ( "+" PGNSP PGUID b f f 700 701 701 1126 0 float48pl - - "---"));
DESCR("add");
-DATA(insert OID = 1117 ( "-" PGNSP PGUID b f f 700 701 701 0 0 float48mi - - ));
+DATA(insert OID = 1117 ( "-" PGNSP PGUID b f f 700 701 701 0 0 float48mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 1118 ( "/" PGNSP PGUID b f f 700 701 701 0 0 float48div - - ));
+DATA(insert OID = 1118 ( "/" PGNSP PGUID b f f 700 701 701 0 0 float48div - - "---"));
DESCR("divide");
-DATA(insert OID = 1119 ( "*" PGNSP PGUID b f f 700 701 701 1129 0 float48mul - - ));
+DATA(insert OID = 1119 ( "*" PGNSP PGUID b f f 700 701 701 1129 0 float48mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 1120 ( "=" PGNSP PGUID b t t 700 701 16 1130 1121 float48eq eqsel eqjoinsel ));
+DATA(insert OID = 1120 ( "=" PGNSP PGUID b t t 700 701 16 1130 1121 float48eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1121 ( "<>" PGNSP PGUID b f f 700 701 16 1131 1120 float48ne neqsel neqjoinsel ));
+DATA(insert OID = 1121 ( "<>" PGNSP PGUID b f f 700 701 16 1131 1120 float48ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1122 ( "<" PGNSP PGUID b f f 700 701 16 1133 1125 float48lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1122 ( "<" PGNSP PGUID b f f 700 701 16 1133 1125 float48lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1123 ( ">" PGNSP PGUID b f f 700 701 16 1132 1124 float48gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1123 ( ">" PGNSP PGUID b f f 700 701 16 1132 1124 float48gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1124 ( "<=" PGNSP PGUID b f f 700 701 16 1135 1123 float48le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1124 ( "<=" PGNSP PGUID b f f 700 701 16 1135 1123 float48le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1125 ( ">=" PGNSP PGUID b f f 700 701 16 1134 1122 float48ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1125 ( ">=" PGNSP PGUID b f f 700 701 16 1134 1122 float48ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* float84 operators */
-DATA(insert OID = 1126 ( "+" PGNSP PGUID b f f 701 700 701 1116 0 float84pl - - ));
+DATA(insert OID = 1126 ( "+" PGNSP PGUID b f f 701 700 701 1116 0 float84pl - - "---"));
DESCR("add");
-DATA(insert OID = 1127 ( "-" PGNSP PGUID b f f 701 700 701 0 0 float84mi - - ));
+DATA(insert OID = 1127 ( "-" PGNSP PGUID b f f 701 700 701 0 0 float84mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 1128 ( "/" PGNSP PGUID b f f 701 700 701 0 0 float84div - - ));
+DATA(insert OID = 1128 ( "/" PGNSP PGUID b f f 701 700 701 0 0 float84div - - "---"));
DESCR("divide");
-DATA(insert OID = 1129 ( "*" PGNSP PGUID b f f 701 700 701 1119 0 float84mul - - ));
+DATA(insert OID = 1129 ( "*" PGNSP PGUID b f f 701 700 701 1119 0 float84mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 1130 ( "=" PGNSP PGUID b t t 701 700 16 1120 1131 float84eq eqsel eqjoinsel ));
+DATA(insert OID = 1130 ( "=" PGNSP PGUID b t t 701 700 16 1120 1131 float84eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1131 ( "<>" PGNSP PGUID b f f 701 700 16 1121 1130 float84ne neqsel neqjoinsel ));
+DATA(insert OID = 1131 ( "<>" PGNSP PGUID b f f 701 700 16 1121 1130 float84ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1132 ( "<" PGNSP PGUID b f f 701 700 16 1123 1135 float84lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1132 ( "<" PGNSP PGUID b f f 701 700 16 1123 1135 float84lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1133 ( ">" PGNSP PGUID b f f 701 700 16 1122 1134 float84gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1133 ( ">" PGNSP PGUID b f f 701 700 16 1122 1134 float84gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1134 ( "<=" PGNSP PGUID b f f 701 700 16 1125 1133 float84le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1134 ( "<=" PGNSP PGUID b f f 701 700 16 1125 1133 float84le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1135 ( ">=" PGNSP PGUID b f f 701 700 16 1124 1132 float84ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1135 ( ">=" PGNSP PGUID b f f 701 700 16 1124 1132 float84ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* LIKE hacks by Keith Parks. */
-DATA(insert OID = 1207 ( "~~" PGNSP PGUID b f f 19 25 16 0 1208 namelike likesel likejoinsel ));
+DATA(insert OID = 1207 ( "~~" PGNSP PGUID b f f 19 25 16 0 1208 namelike likesel likejoinsel "---"));
DESCR("matches LIKE expression");
#define OID_NAME_LIKE_OP 1207
-DATA(insert OID = 1208 ( "!~~" PGNSP PGUID b f f 19 25 16 0 1207 namenlike nlikesel nlikejoinsel ));
+DATA(insert OID = 1208 ( "!~~" PGNSP PGUID b f f 19 25 16 0 1207 namenlike nlikesel nlikejoinsel "---"));
DESCR("does not match LIKE expression");
-DATA(insert OID = 1209 ( "~~" PGNSP PGUID b f f 25 25 16 0 1210 textlike likesel likejoinsel ));
+DATA(insert OID = 1209 ( "~~" PGNSP PGUID b f f 25 25 16 0 1210 textlike likesel likejoinsel "---"));
DESCR("matches LIKE expression");
#define OID_TEXT_LIKE_OP 1209
-DATA(insert OID = 1210 ( "!~~" PGNSP PGUID b f f 25 25 16 0 1209 textnlike nlikesel nlikejoinsel ));
+DATA(insert OID = 1210 ( "!~~" PGNSP PGUID b f f 25 25 16 0 1209 textnlike nlikesel nlikejoinsel "---"));
DESCR("does not match LIKE expression");
-DATA(insert OID = 1211 ( "~~" PGNSP PGUID b f f 1042 25 16 0 1212 bpcharlike likesel likejoinsel ));
+DATA(insert OID = 1211 ( "~~" PGNSP PGUID b f f 1042 25 16 0 1212 bpcharlike likesel likejoinsel "---"));
DESCR("matches LIKE expression");
#define OID_BPCHAR_LIKE_OP 1211
-DATA(insert OID = 1212 ( "!~~" PGNSP PGUID b f f 1042 25 16 0 1211 bpcharnlike nlikesel nlikejoinsel ));
+DATA(insert OID = 1212 ( "!~~" PGNSP PGUID b f f 1042 25 16 0 1211 bpcharnlike nlikesel nlikejoinsel "---"));
DESCR("does not match LIKE expression");
/* case-insensitive regex hacks */
-DATA(insert OID = 1226 ( "~*" PGNSP PGUID b f f 19 25 16 0 1227 nameicregexeq icregexeqsel icregexeqjoinsel ));
+DATA(insert OID = 1226 ( "~*" PGNSP PGUID b f f 19 25 16 0 1227 nameicregexeq icregexeqsel icregexeqjoinsel "mhf"));
DESCR("matches regular expression, case-insensitive");
#define OID_NAME_ICREGEXEQ_OP 1226
-DATA(insert OID = 1227 ( "!~*" PGNSP PGUID b f f 19 25 16 0 1226 nameicregexne icregexnesel icregexnejoinsel ));
+DATA(insert OID = 1227 ( "!~*" PGNSP PGUID b f f 19 25 16 0 1226 nameicregexne icregexnesel icregexnejoinsel "---"));
DESCR("does not match regular expression, case-insensitive");
-DATA(insert OID = 1228 ( "~*" PGNSP PGUID b f f 25 25 16 0 1229 texticregexeq icregexeqsel icregexeqjoinsel ));
+DATA(insert OID = 1228 ( "~*" PGNSP PGUID b f f 25 25 16 0 1229 texticregexeq icregexeqsel icregexeqjoinsel "mhf"));
DESCR("matches regular expression, case-insensitive");
#define OID_TEXT_ICREGEXEQ_OP 1228
-DATA(insert OID = 1229 ( "!~*" PGNSP PGUID b f f 25 25 16 0 1228 texticregexne icregexnesel icregexnejoinsel ));
+DATA(insert OID = 1229 ( "!~*" PGNSP PGUID b f f 25 25 16 0 1228 texticregexne icregexnesel icregexnejoinsel "---"));
DESCR("does not match regular expression, case-insensitive");
-DATA(insert OID = 1234 ( "~*" PGNSP PGUID b f f 1042 25 16 0 1235 bpcharicregexeq icregexeqsel icregexeqjoinsel ));
+DATA(insert OID = 1234 ( "~*" PGNSP PGUID b f f 1042 25 16 0 1235 bpcharicregexeq icregexeqsel icregexeqjoinsel "mhf"));
DESCR("matches regular expression, case-insensitive");
#define OID_BPCHAR_ICREGEXEQ_OP 1234
-DATA(insert OID = 1235 ( "!~*" PGNSP PGUID b f f 1042 25 16 0 1234 bpcharicregexne icregexnesel icregexnejoinsel ));
+DATA(insert OID = 1235 ( "!~*" PGNSP PGUID b f f 1042 25 16 0 1234 bpcharicregexne icregexnesel icregexnejoinsel "---"));
DESCR("does not match regular expression, case-insensitive");
/* timestamptz operators */
-DATA(insert OID = 1320 ( "=" PGNSP PGUID b t t 1184 1184 16 1320 1321 timestamptz_eq eqsel eqjoinsel ));
+DATA(insert OID = 1320 ( "=" PGNSP PGUID b t t 1184 1184 16 1320 1321 timestamptz_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1321 ( "<>" PGNSP PGUID b f f 1184 1184 16 1321 1320 timestamptz_ne neqsel neqjoinsel ));
+DATA(insert OID = 1321 ( "<>" PGNSP PGUID b f f 1184 1184 16 1321 1320 timestamptz_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1322 ( "<" PGNSP PGUID b f f 1184 1184 16 1324 1325 timestamptz_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1322 ( "<" PGNSP PGUID b f f 1184 1184 16 1324 1325 timestamptz_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1323 ( "<=" PGNSP PGUID b f f 1184 1184 16 1325 1324 timestamptz_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1323 ( "<=" PGNSP PGUID b f f 1184 1184 16 1325 1324 timestamptz_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1324 ( ">" PGNSP PGUID b f f 1184 1184 16 1322 1323 timestamptz_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1324 ( ">" PGNSP PGUID b f f 1184 1184 16 1322 1323 timestamptz_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1325 ( ">=" PGNSP PGUID b f f 1184 1184 16 1323 1322 timestamptz_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1325 ( ">=" PGNSP PGUID b f f 1184 1184 16 1323 1322 timestamptz_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1327 ( "+" PGNSP PGUID b f f 1184 1186 1184 2554 0 timestamptz_pl_interval - - ));
+DATA(insert OID = 1327 ( "+" PGNSP PGUID b f f 1184 1186 1184 2554 0 timestamptz_pl_interval - - "---"));
DESCR("add");
-DATA(insert OID = 1328 ( "-" PGNSP PGUID b f f 1184 1184 1186 0 0 timestamptz_mi - - ));
+DATA(insert OID = 1328 ( "-" PGNSP PGUID b f f 1184 1184 1186 0 0 timestamptz_mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 1329 ( "-" PGNSP PGUID b f f 1184 1186 1184 0 0 timestamptz_mi_interval - - ));
+DATA(insert OID = 1329 ( "-" PGNSP PGUID b f f 1184 1186 1184 0 0 timestamptz_mi_interval - - "---"));
DESCR("subtract");
/* interval operators */
-DATA(insert OID = 1330 ( "=" PGNSP PGUID b t t 1186 1186 16 1330 1331 interval_eq eqsel eqjoinsel ));
+DATA(insert OID = 1330 ( "=" PGNSP PGUID b t t 1186 1186 16 1330 1331 interval_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1331 ( "<>" PGNSP PGUID b f f 1186 1186 16 1331 1330 interval_ne neqsel neqjoinsel ));
+DATA(insert OID = 1331 ( "<>" PGNSP PGUID b f f 1186 1186 16 1331 1330 interval_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1332 ( "<" PGNSP PGUID b f f 1186 1186 16 1334 1335 interval_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1332 ( "<" PGNSP PGUID b f f 1186 1186 16 1334 1335 interval_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1333 ( "<=" PGNSP PGUID b f f 1186 1186 16 1335 1334 interval_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1333 ( "<=" PGNSP PGUID b f f 1186 1186 16 1335 1334 interval_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1334 ( ">" PGNSP PGUID b f f 1186 1186 16 1332 1333 interval_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1334 ( ">" PGNSP PGUID b f f 1186 1186 16 1332 1333 interval_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1335 ( ">=" PGNSP PGUID b f f 1186 1186 16 1333 1332 interval_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1335 ( ">=" PGNSP PGUID b f f 1186 1186 16 1333 1332 interval_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1336 ( "-" PGNSP PGUID l f f 0 1186 1186 0 0 interval_um - - ));
+DATA(insert OID = 1336 ( "-" PGNSP PGUID l f f 0 1186 1186 0 0 interval_um - - "---"));
DESCR("negate");
-DATA(insert OID = 1337 ( "+" PGNSP PGUID b f f 1186 1186 1186 1337 0 interval_pl - - ));
+DATA(insert OID = 1337 ( "+" PGNSP PGUID b f f 1186 1186 1186 1337 0 interval_pl - - "---"));
DESCR("add");
-DATA(insert OID = 1338 ( "-" PGNSP PGUID b f f 1186 1186 1186 0 0 interval_mi - - ));
+DATA(insert OID = 1338 ( "-" PGNSP PGUID b f f 1186 1186 1186 0 0 interval_mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 1360 ( "+" PGNSP PGUID b f f 1082 1083 1114 1363 0 datetime_pl - - ));
+DATA(insert OID = 1360 ( "+" PGNSP PGUID b f f 1082 1083 1114 1363 0 datetime_pl - - "---"));
DESCR("convert date and time to timestamp");
-DATA(insert OID = 1361 ( "+" PGNSP PGUID b f f 1082 1266 1184 1366 0 datetimetz_pl - - ));
+DATA(insert OID = 1361 ( "+" PGNSP PGUID b f f 1082 1266 1184 1366 0 datetimetz_pl - - "---"));
DESCR("convert date and time with time zone to timestamp with time zone");
-DATA(insert OID = 1363 ( "+" PGNSP PGUID b f f 1083 1082 1114 1360 0 timedate_pl - - ));
+DATA(insert OID = 1363 ( "+" PGNSP PGUID b f f 1083 1082 1114 1360 0 timedate_pl - - "---"));
DESCR("convert time and date to timestamp");
-DATA(insert OID = 1366 ( "+" PGNSP PGUID b f f 1266 1082 1184 1361 0 timetzdate_pl - - ));
+DATA(insert OID = 1366 ( "+" PGNSP PGUID b f f 1266 1082 1184 1361 0 timetzdate_pl - - "---"));
DESCR("convert time with time zone and date to timestamp with time zone");
-DATA(insert OID = 1399 ( "-" PGNSP PGUID b f f 1083 1083 1186 0 0 time_mi_time - - ));
+DATA(insert OID = 1399 ( "-" PGNSP PGUID b f f 1083 1083 1186 0 0 time_mi_time - - "---"));
DESCR("subtract");
/* additional geometric operators - thomas 97/04/18 */
-DATA(insert OID = 1420 ( "@@" PGNSP PGUID l f f 0 718 600 0 0 circle_center - - ));
+DATA(insert OID = 1420 ( "@@" PGNSP PGUID l f f 0 718 600 0 0 circle_center - - "---"));
DESCR("center of");
-DATA(insert OID = 1500 ( "=" PGNSP PGUID b f f 718 718 16 1500 1501 circle_eq eqsel eqjoinsel ));
+DATA(insert OID = 1500 ( "=" PGNSP PGUID b f f 718 718 16 1500 1501 circle_eq eqsel eqjoinsel "mhf"));
DESCR("equal by area");
-DATA(insert OID = 1501 ( "<>" PGNSP PGUID b f f 718 718 16 1501 1500 circle_ne neqsel neqjoinsel ));
+DATA(insert OID = 1501 ( "<>" PGNSP PGUID b f f 718 718 16 1501 1500 circle_ne neqsel neqjoinsel "mhf"));
DESCR("not equal by area");
-DATA(insert OID = 1502 ( "<" PGNSP PGUID b f f 718 718 16 1503 1505 circle_lt areasel areajoinsel ));
+DATA(insert OID = 1502 ( "<" PGNSP PGUID b f f 718 718 16 1503 1505 circle_lt areasel areajoinsel "---"));
DESCR("less than by area");
-DATA(insert OID = 1503 ( ">" PGNSP PGUID b f f 718 718 16 1502 1504 circle_gt areasel areajoinsel ));
+DATA(insert OID = 1503 ( ">" PGNSP PGUID b f f 718 718 16 1502 1504 circle_gt areasel areajoinsel "---"));
DESCR("greater than by area");
-DATA(insert OID = 1504 ( "<=" PGNSP PGUID b f f 718 718 16 1505 1503 circle_le areasel areajoinsel ));
+DATA(insert OID = 1504 ( "<=" PGNSP PGUID b f f 718 718 16 1505 1503 circle_le areasel areajoinsel "---"));
DESCR("less than or equal by area");
-DATA(insert OID = 1505 ( ">=" PGNSP PGUID b f f 718 718 16 1504 1502 circle_ge areasel areajoinsel ));
+DATA(insert OID = 1505 ( ">=" PGNSP PGUID b f f 718 718 16 1504 1502 circle_ge areasel areajoinsel "---"));
DESCR("greater than or equal by area");
-DATA(insert OID = 1506 ( "<<" PGNSP PGUID b f f 718 718 16 0 0 circle_left positionsel positionjoinsel ));
+DATA(insert OID = 1506 ( "<<" PGNSP PGUID b f f 718 718 16 0 0 circle_left positionsel positionjoinsel "---"));
DESCR("is left of");
-DATA(insert OID = 1507 ( "&<" PGNSP PGUID b f f 718 718 16 0 0 circle_overleft positionsel positionjoinsel ));
+DATA(insert OID = 1507 ( "&<" PGNSP PGUID b f f 718 718 16 0 0 circle_overleft positionsel positionjoinsel "---"));
DESCR("overlaps or is left of");
-DATA(insert OID = 1508 ( "&>" PGNSP PGUID b f f 718 718 16 0 0 circle_overright positionsel positionjoinsel ));
+DATA(insert OID = 1508 ( "&>" PGNSP PGUID b f f 718 718 16 0 0 circle_overright positionsel positionjoinsel "---"));
DESCR("overlaps or is right of");
-DATA(insert OID = 1509 ( ">>" PGNSP PGUID b f f 718 718 16 0 0 circle_right positionsel positionjoinsel ));
+DATA(insert OID = 1509 ( ">>" PGNSP PGUID b f f 718 718 16 0 0 circle_right positionsel positionjoinsel "---"));
DESCR("is right of");
-DATA(insert OID = 1510 ( "<@" PGNSP PGUID b f f 718 718 16 1511 0 circle_contained contsel contjoinsel ));
+DATA(insert OID = 1510 ( "<@" PGNSP PGUID b f f 718 718 16 1511 0 circle_contained contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 1511 ( "@>" PGNSP PGUID b f f 718 718 16 1510 0 circle_contain contsel contjoinsel ));
+DATA(insert OID = 1511 ( "@>" PGNSP PGUID b f f 718 718 16 1510 0 circle_contain contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 1512 ( "~=" PGNSP PGUID b f f 718 718 16 1512 0 circle_same eqsel eqjoinsel ));
+DATA(insert OID = 1512 ( "~=" PGNSP PGUID b f f 718 718 16 1512 0 circle_same eqsel eqjoinsel "mhf"));
DESCR("same as");
-DATA(insert OID = 1513 ( "&&" PGNSP PGUID b f f 718 718 16 1513 0 circle_overlap areasel areajoinsel ));
+DATA(insert OID = 1513 ( "&&" PGNSP PGUID b f f 718 718 16 1513 0 circle_overlap areasel areajoinsel "---"));
DESCR("overlaps");
-DATA(insert OID = 1514 ( "|>>" PGNSP PGUID b f f 718 718 16 0 0 circle_above positionsel positionjoinsel ));
+DATA(insert OID = 1514 ( "|>>" PGNSP PGUID b f f 718 718 16 0 0 circle_above positionsel positionjoinsel "---"));
DESCR("is above");
-DATA(insert OID = 1515 ( "<<|" PGNSP PGUID b f f 718 718 16 0 0 circle_below positionsel positionjoinsel ));
+DATA(insert OID = 1515 ( "<<|" PGNSP PGUID b f f 718 718 16 0 0 circle_below positionsel positionjoinsel "---"));
DESCR("is below");
-DATA(insert OID = 1516 ( "+" PGNSP PGUID b f f 718 600 718 0 0 circle_add_pt - - ));
+DATA(insert OID = 1516 ( "+" PGNSP PGUID b f f 718 600 718 0 0 circle_add_pt - - "---"));
DESCR("add");
-DATA(insert OID = 1517 ( "-" PGNSP PGUID b f f 718 600 718 0 0 circle_sub_pt - - ));
+DATA(insert OID = 1517 ( "-" PGNSP PGUID b f f 718 600 718 0 0 circle_sub_pt - - "---"));
DESCR("subtract");
-DATA(insert OID = 1518 ( "*" PGNSP PGUID b f f 718 600 718 0 0 circle_mul_pt - - ));
+DATA(insert OID = 1518 ( "*" PGNSP PGUID b f f 718 600 718 0 0 circle_mul_pt - - "---"));
DESCR("multiply");
-DATA(insert OID = 1519 ( "/" PGNSP PGUID b f f 718 600 718 0 0 circle_div_pt - - ));
+DATA(insert OID = 1519 ( "/" PGNSP PGUID b f f 718 600 718 0 0 circle_div_pt - - "---"));
DESCR("divide");
-DATA(insert OID = 1520 ( "<->" PGNSP PGUID b f f 718 718 701 1520 0 circle_distance - - ));
+DATA(insert OID = 1520 ( "<->" PGNSP PGUID b f f 718 718 701 1520 0 circle_distance - - "---"));
DESCR("distance between");
-DATA(insert OID = 1521 ( "#" PGNSP PGUID l f f 0 604 23 0 0 poly_npoints - - ));
+DATA(insert OID = 1521 ( "#" PGNSP PGUID l f f 0 604 23 0 0 poly_npoints - - "---"));
DESCR("number of points");
-DATA(insert OID = 1522 ( "<->" PGNSP PGUID b f f 600 718 701 3291 0 dist_pc - - ));
+DATA(insert OID = 1522 ( "<->" PGNSP PGUID b f f 600 718 701 3291 0 dist_pc - - "---"));
DESCR("distance between");
-DATA(insert OID = 3291 ( "<->" PGNSP PGUID b f f 718 600 701 1522 0 dist_cpoint - - ));
+DATA(insert OID = 3291 ( "<->" PGNSP PGUID b f f 718 600 701 1522 0 dist_cpoint - - "---"));
DESCR("distance between");
-DATA(insert OID = 3276 ( "<->" PGNSP PGUID b f f 600 604 701 3289 0 dist_ppoly - - ));
+DATA(insert OID = 3276 ( "<->" PGNSP PGUID b f f 600 604 701 3289 0 dist_ppoly - - "---"));
DESCR("distance between");
-DATA(insert OID = 3289 ( "<->" PGNSP PGUID b f f 604 600 701 3276 0 dist_polyp - - ));
+DATA(insert OID = 3289 ( "<->" PGNSP PGUID b f f 604 600 701 3276 0 dist_polyp - - "---"));
DESCR("distance between");
-DATA(insert OID = 1523 ( "<->" PGNSP PGUID b f f 718 604 701 0 0 dist_cpoly - - ));
+DATA(insert OID = 1523 ( "<->" PGNSP PGUID b f f 718 604 701 0 0 dist_cpoly - - "---"));
DESCR("distance between");
/* additional geometric operators - thomas 1997-07-09 */
-DATA(insert OID = 1524 ( "<->" PGNSP PGUID b f f 628 603 701 0 0 dist_lb - - ));
+DATA(insert OID = 1524 ( "<->" PGNSP PGUID b f f 628 603 701 0 0 dist_lb - - "---"));
DESCR("distance between");
-DATA(insert OID = 1525 ( "?#" PGNSP PGUID b f f 601 601 16 1525 0 lseg_intersect - - ));
+DATA(insert OID = 1525 ( "?#" PGNSP PGUID b f f 601 601 16 1525 0 lseg_intersect - - "---"));
DESCR("intersect");
-DATA(insert OID = 1526 ( "?||" PGNSP PGUID b f f 601 601 16 1526 0 lseg_parallel - - ));
+DATA(insert OID = 1526 ( "?||" PGNSP PGUID b f f 601 601 16 1526 0 lseg_parallel - - "---"));
DESCR("parallel");
-DATA(insert OID = 1527 ( "?-|" PGNSP PGUID b f f 601 601 16 1527 0 lseg_perp - - ));
+DATA(insert OID = 1527 ( "?-|" PGNSP PGUID b f f 601 601 16 1527 0 lseg_perp - - "---"));
DESCR("perpendicular");
-DATA(insert OID = 1528 ( "?-" PGNSP PGUID l f f 0 601 16 0 0 lseg_horizontal - - ));
+DATA(insert OID = 1528 ( "?-" PGNSP PGUID l f f 0 601 16 0 0 lseg_horizontal - - "---"));
DESCR("horizontal");
-DATA(insert OID = 1529 ( "?|" PGNSP PGUID l f f 0 601 16 0 0 lseg_vertical - - ));
+DATA(insert OID = 1529 ( "?|" PGNSP PGUID l f f 0 601 16 0 0 lseg_vertical - - "---"));
DESCR("vertical");
-DATA(insert OID = 1535 ( "=" PGNSP PGUID b f f 601 601 16 1535 1586 lseg_eq eqsel eqjoinsel ));
+DATA(insert OID = 1535 ( "=" PGNSP PGUID b f f 601 601 16 1535 1586 lseg_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1536 ( "#" PGNSP PGUID b f f 601 601 600 1536 0 lseg_interpt - - ));
+DATA(insert OID = 1536 ( "#" PGNSP PGUID b f f 601 601 600 1536 0 lseg_interpt - - "---"));
DESCR("intersection point");
-DATA(insert OID = 1537 ( "?#" PGNSP PGUID b f f 601 628 16 0 0 inter_sl - - ));
+DATA(insert OID = 1537 ( "?#" PGNSP PGUID b f f 601 628 16 0 0 inter_sl - - "---"));
DESCR("intersect");
-DATA(insert OID = 1538 ( "?#" PGNSP PGUID b f f 601 603 16 0 0 inter_sb - - ));
+DATA(insert OID = 1538 ( "?#" PGNSP PGUID b f f 601 603 16 0 0 inter_sb - - "---"));
DESCR("intersect");
-DATA(insert OID = 1539 ( "?#" PGNSP PGUID b f f 628 603 16 0 0 inter_lb - - ));
+DATA(insert OID = 1539 ( "?#" PGNSP PGUID b f f 628 603 16 0 0 inter_lb - - "---"));
DESCR("intersect");
-DATA(insert OID = 1546 ( "<@" PGNSP PGUID b f f 600 628 16 0 0 on_pl - - ));
+DATA(insert OID = 1546 ( "<@" PGNSP PGUID b f f 600 628 16 0 0 on_pl - - "---"));
DESCR("point on line");
-DATA(insert OID = 1547 ( "<@" PGNSP PGUID b f f 600 601 16 0 0 on_ps - - ));
+DATA(insert OID = 1547 ( "<@" PGNSP PGUID b f f 600 601 16 0 0 on_ps - - "---"));
DESCR("is contained by");
-DATA(insert OID = 1548 ( "<@" PGNSP PGUID b f f 601 628 16 0 0 on_sl - - ));
+DATA(insert OID = 1548 ( "<@" PGNSP PGUID b f f 601 628 16 0 0 on_sl - - "---"));
DESCR("lseg on line");
-DATA(insert OID = 1549 ( "<@" PGNSP PGUID b f f 601 603 16 0 0 on_sb - - ));
+DATA(insert OID = 1549 ( "<@" PGNSP PGUID b f f 601 603 16 0 0 on_sb - - "---"));
DESCR("is contained by");
-DATA(insert OID = 1557 ( "##" PGNSP PGUID b f f 600 628 600 0 0 close_pl - - ));
+DATA(insert OID = 1557 ( "##" PGNSP PGUID b f f 600 628 600 0 0 close_pl - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1558 ( "##" PGNSP PGUID b f f 600 601 600 0 0 close_ps - - ));
+DATA(insert OID = 1558 ( "##" PGNSP PGUID b f f 600 601 600 0 0 close_ps - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1559 ( "##" PGNSP PGUID b f f 600 603 600 0 0 close_pb - - ));
+DATA(insert OID = 1559 ( "##" PGNSP PGUID b f f 600 603 600 0 0 close_pb - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1566 ( "##" PGNSP PGUID b f f 601 628 600 0 0 close_sl - - ));
+DATA(insert OID = 1566 ( "##" PGNSP PGUID b f f 601 628 600 0 0 close_sl - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1567 ( "##" PGNSP PGUID b f f 601 603 600 0 0 close_sb - - ));
+DATA(insert OID = 1567 ( "##" PGNSP PGUID b f f 601 603 600 0 0 close_sb - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1568 ( "##" PGNSP PGUID b f f 628 603 600 0 0 close_lb - - ));
+DATA(insert OID = 1568 ( "##" PGNSP PGUID b f f 628 603 600 0 0 close_lb - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1577 ( "##" PGNSP PGUID b f f 628 601 600 0 0 close_ls - - ));
+DATA(insert OID = 1577 ( "##" PGNSP PGUID b f f 628 601 600 0 0 close_ls - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1578 ( "##" PGNSP PGUID b f f 601 601 600 0 0 close_lseg - - ));
+DATA(insert OID = 1578 ( "##" PGNSP PGUID b f f 601 601 600 0 0 close_lseg - - "---"));
DESCR("closest point to A on B");
-DATA(insert OID = 1583 ( "*" PGNSP PGUID b f f 1186 701 1186 1584 0 interval_mul - - ));
+DATA(insert OID = 1583 ( "*" PGNSP PGUID b f f 1186 701 1186 1584 0 interval_mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 1584 ( "*" PGNSP PGUID b f f 701 1186 1186 1583 0 mul_d_interval - - ));
+DATA(insert OID = 1584 ( "*" PGNSP PGUID b f f 701 1186 1186 1583 0 mul_d_interval - - "---"));
DESCR("multiply");
-DATA(insert OID = 1585 ( "/" PGNSP PGUID b f f 1186 701 1186 0 0 interval_div - - ));
+DATA(insert OID = 1585 ( "/" PGNSP PGUID b f f 1186 701 1186 0 0 interval_div - - "---"));
DESCR("divide");
-DATA(insert OID = 1586 ( "<>" PGNSP PGUID b f f 601 601 16 1586 1535 lseg_ne neqsel neqjoinsel ));
+DATA(insert OID = 1586 ( "<>" PGNSP PGUID b f f 601 601 16 1586 1535 lseg_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1587 ( "<" PGNSP PGUID b f f 601 601 16 1589 1590 lseg_lt - - ));
+DATA(insert OID = 1587 ( "<" PGNSP PGUID b f f 601 601 16 1589 1590 lseg_lt - - "---"));
DESCR("less than by length");
-DATA(insert OID = 1588 ( "<=" PGNSP PGUID b f f 601 601 16 1590 1589 lseg_le - - ));
+DATA(insert OID = 1588 ( "<=" PGNSP PGUID b f f 601 601 16 1590 1589 lseg_le - - "---"));
DESCR("less than or equal by length");
-DATA(insert OID = 1589 ( ">" PGNSP PGUID b f f 601 601 16 1587 1588 lseg_gt - - ));
+DATA(insert OID = 1589 ( ">" PGNSP PGUID b f f 601 601 16 1587 1588 lseg_gt - - "---"));
DESCR("greater than by length");
-DATA(insert OID = 1590 ( ">=" PGNSP PGUID b f f 601 601 16 1588 1587 lseg_ge - - ));
+DATA(insert OID = 1590 ( ">=" PGNSP PGUID b f f 601 601 16 1588 1587 lseg_ge - - "---"));
DESCR("greater than or equal by length");
-DATA(insert OID = 1591 ( "@-@" PGNSP PGUID l f f 0 601 701 0 0 lseg_length - - ));
+DATA(insert OID = 1591 ( "@-@" PGNSP PGUID l f f 0 601 701 0 0 lseg_length - - "---"));
DESCR("distance between endpoints");
-DATA(insert OID = 1611 ( "?#" PGNSP PGUID b f f 628 628 16 1611 0 line_intersect - - ));
+DATA(insert OID = 1611 ( "?#" PGNSP PGUID b f f 628 628 16 1611 0 line_intersect - - "---"));
DESCR("intersect");
-DATA(insert OID = 1612 ( "?||" PGNSP PGUID b f f 628 628 16 1612 0 line_parallel - - ));
+DATA(insert OID = 1612 ( "?||" PGNSP PGUID b f f 628 628 16 1612 0 line_parallel - - "---"));
DESCR("parallel");
-DATA(insert OID = 1613 ( "?-|" PGNSP PGUID b f f 628 628 16 1613 0 line_perp - - ));
+DATA(insert OID = 1613 ( "?-|" PGNSP PGUID b f f 628 628 16 1613 0 line_perp - - "---"));
DESCR("perpendicular");
-DATA(insert OID = 1614 ( "?-" PGNSP PGUID l f f 0 628 16 0 0 line_horizontal - - ));
+DATA(insert OID = 1614 ( "?-" PGNSP PGUID l f f 0 628 16 0 0 line_horizontal - - "---"));
DESCR("horizontal");
-DATA(insert OID = 1615 ( "?|" PGNSP PGUID l f f 0 628 16 0 0 line_vertical - - ));
+DATA(insert OID = 1615 ( "?|" PGNSP PGUID l f f 0 628 16 0 0 line_vertical - - "---"));
DESCR("vertical");
-DATA(insert OID = 1616 ( "=" PGNSP PGUID b f f 628 628 16 1616 0 line_eq eqsel eqjoinsel ));
+DATA(insert OID = 1616 ( "=" PGNSP PGUID b f f 628 628 16 1616 0 line_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1617 ( "#" PGNSP PGUID b f f 628 628 600 1617 0 line_interpt - - ));
+DATA(insert OID = 1617 ( "#" PGNSP PGUID b f f 628 628 600 1617 0 line_interpt - - "---"));
DESCR("intersection point");
/* MAC type */
-DATA(insert OID = 1220 ( "=" PGNSP PGUID b t t 829 829 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
+DATA(insert OID = 1220 ( "=" PGNSP PGUID b t t 829 829 16 1220 1221 macaddr_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1221 ( "<>" PGNSP PGUID b f f 829 829 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
+DATA(insert OID = 1221 ( "<>" PGNSP PGUID b f f 829 829 16 1221 1220 macaddr_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1222 ( "<" PGNSP PGUID b f f 829 829 16 1224 1225 macaddr_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1222 ( "<" PGNSP PGUID b f f 829 829 16 1224 1225 macaddr_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1223 ( "<=" PGNSP PGUID b f f 829 829 16 1225 1224 macaddr_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1223 ( "<=" PGNSP PGUID b f f 829 829 16 1225 1224 macaddr_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1224 ( ">" PGNSP PGUID b f f 829 829 16 1222 1223 macaddr_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1224 ( ">" PGNSP PGUID b f f 829 829 16 1222 1223 macaddr_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1225 ( ">=" PGNSP PGUID b f f 829 829 16 1223 1222 macaddr_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1225 ( ">=" PGNSP PGUID b f f 829 829 16 1223 1222 macaddr_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 3147 ( "~" PGNSP PGUID l f f 0 829 829 0 0 macaddr_not - - ));
+DATA(insert OID = 3147 ( "~" PGNSP PGUID l f f 0 829 829 0 0 macaddr_not - - "---"));
DESCR("bitwise not");
-DATA(insert OID = 3148 ( "&" PGNSP PGUID b f f 829 829 829 0 0 macaddr_and - - ));
+DATA(insert OID = 3148 ( "&" PGNSP PGUID b f f 829 829 829 0 0 macaddr_and - - "---"));
DESCR("bitwise and");
-DATA(insert OID = 3149 ( "|" PGNSP PGUID b f f 829 829 829 0 0 macaddr_or - - ));
+DATA(insert OID = 3149 ( "|" PGNSP PGUID b f f 829 829 829 0 0 macaddr_or - - "---"));
DESCR("bitwise or");
/* INET type (these also support CIDR via implicit cast) */
-DATA(insert OID = 1201 ( "=" PGNSP PGUID b t t 869 869 16 1201 1202 network_eq eqsel eqjoinsel ));
+DATA(insert OID = 1201 ( "=" PGNSP PGUID b t t 869 869 16 1201 1202 network_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1202 ( "<>" PGNSP PGUID b f f 869 869 16 1202 1201 network_ne neqsel neqjoinsel ));
+DATA(insert OID = 1202 ( "<>" PGNSP PGUID b f f 869 869 16 1202 1201 network_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1203 ( "<" PGNSP PGUID b f f 869 869 16 1205 1206 network_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1203 ( "<" PGNSP PGUID b f f 869 869 16 1205 1206 network_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1204 ( "<=" PGNSP PGUID b f f 869 869 16 1206 1205 network_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1204 ( "<=" PGNSP PGUID b f f 869 869 16 1206 1205 network_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1205 ( ">" PGNSP PGUID b f f 869 869 16 1203 1204 network_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1205 ( ">" PGNSP PGUID b f f 869 869 16 1203 1204 network_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1206 ( ">=" PGNSP PGUID b f f 869 869 16 1204 1203 network_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1206 ( ">=" PGNSP PGUID b f f 869 869 16 1204 1203 network_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 931 ( "<<" PGNSP PGUID b f f 869 869 16 933 0 network_sub networksel networkjoinsel ));
+DATA(insert OID = 931 ( "<<" PGNSP PGUID b f f 869 869 16 933 0 network_sub networksel networkjoinsel "---"));
DESCR("is subnet");
#define OID_INET_SUB_OP 931
-DATA(insert OID = 932 ( "<<=" PGNSP PGUID b f f 869 869 16 934 0 network_subeq networksel networkjoinsel ));
+DATA(insert OID = 932 ( "<<=" PGNSP PGUID b f f 869 869 16 934 0 network_subeq networksel networkjoinsel "---"));
DESCR("is subnet or equal");
#define OID_INET_SUBEQ_OP 932
-DATA(insert OID = 933 ( ">>" PGNSP PGUID b f f 869 869 16 931 0 network_sup networksel networkjoinsel ));
+DATA(insert OID = 933 ( ">>" PGNSP PGUID b f f 869 869 16 931 0 network_sup networksel networkjoinsel "---"));
DESCR("is supernet");
#define OID_INET_SUP_OP 933
-DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq networksel networkjoinsel ));
+DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq networksel networkjoinsel "---"));
DESCR("is supernet or equal");
#define OID_INET_SUPEQ_OP 934
-DATA(insert OID = 3552 ( "&&" PGNSP PGUID b f f 869 869 16 3552 0 network_overlap networksel networkjoinsel ));
+DATA(insert OID = 3552 ( "&&" PGNSP PGUID b f f 869 869 16 3552 0 network_overlap networksel networkjoinsel "---"));
DESCR("overlaps (is subnet or supernet)");
#define OID_INET_OVERLAP_OP 3552
-DATA(insert OID = 2634 ( "~" PGNSP PGUID l f f 0 869 869 0 0 inetnot - - ));
+DATA(insert OID = 2634 ( "~" PGNSP PGUID l f f 0 869 869 0 0 inetnot - - "---"));
DESCR("bitwise not");
-DATA(insert OID = 2635 ( "&" PGNSP PGUID b f f 869 869 869 0 0 inetand - - ));
+DATA(insert OID = 2635 ( "&" PGNSP PGUID b f f 869 869 869 0 0 inetand - - "---"));
DESCR("bitwise and");
-DATA(insert OID = 2636 ( "|" PGNSP PGUID b f f 869 869 869 0 0 inetor - - ));
+DATA(insert OID = 2636 ( "|" PGNSP PGUID b f f 869 869 869 0 0 inetor - - "---"));
DESCR("bitwise or");
-DATA(insert OID = 2637 ( "+" PGNSP PGUID b f f 869 20 869 2638 0 inetpl - - ));
+DATA(insert OID = 2637 ( "+" PGNSP PGUID b f f 869 20 869 2638 0 inetpl - - "---"));
DESCR("add");
-DATA(insert OID = 2638 ( "+" PGNSP PGUID b f f 20 869 869 2637 0 int8pl_inet - - ));
+DATA(insert OID = 2638 ( "+" PGNSP PGUID b f f 20 869 869 2637 0 int8pl_inet - - "---"));
DESCR("add");
-DATA(insert OID = 2639 ( "-" PGNSP PGUID b f f 869 20 869 0 0 inetmi_int8 - - ));
+DATA(insert OID = 2639 ( "-" PGNSP PGUID b f f 869 20 869 0 0 inetmi_int8 - - "---"));
DESCR("subtract");
-DATA(insert OID = 2640 ( "-" PGNSP PGUID b f f 869 869 20 0 0 inetmi - - ));
+DATA(insert OID = 2640 ( "-" PGNSP PGUID b f f 869 869 20 0 0 inetmi - - "---"));
DESCR("subtract");
/* case-insensitive LIKE hacks */
-DATA(insert OID = 1625 ( "~~*" PGNSP PGUID b f f 19 25 16 0 1626 nameiclike iclikesel iclikejoinsel ));
+DATA(insert OID = 1625 ( "~~*" PGNSP PGUID b f f 19 25 16 0 1626 nameiclike iclikesel iclikejoinsel "---"));
DESCR("matches LIKE expression, case-insensitive");
#define OID_NAME_ICLIKE_OP 1625
-DATA(insert OID = 1626 ( "!~~*" PGNSP PGUID b f f 19 25 16 0 1625 nameicnlike icnlikesel icnlikejoinsel ));
+DATA(insert OID = 1626 ( "!~~*" PGNSP PGUID b f f 19 25 16 0 1625 nameicnlike icnlikesel icnlikejoinsel "---"));
DESCR("does not match LIKE expression, case-insensitive");
-DATA(insert OID = 1627 ( "~~*" PGNSP PGUID b f f 25 25 16 0 1628 texticlike iclikesel iclikejoinsel ));
+DATA(insert OID = 1627 ( "~~*" PGNSP PGUID b f f 25 25 16 0 1628 texticlike iclikesel iclikejoinsel "---"));
DESCR("matches LIKE expression, case-insensitive");
#define OID_TEXT_ICLIKE_OP 1627
-DATA(insert OID = 1628 ( "!~~*" PGNSP PGUID b f f 25 25 16 0 1627 texticnlike icnlikesel icnlikejoinsel ));
+DATA(insert OID = 1628 ( "!~~*" PGNSP PGUID b f f 25 25 16 0 1627 texticnlike icnlikesel icnlikejoinsel "---"));
DESCR("does not match LIKE expression, case-insensitive");
-DATA(insert OID = 1629 ( "~~*" PGNSP PGUID b f f 1042 25 16 0 1630 bpchariclike iclikesel iclikejoinsel ));
+DATA(insert OID = 1629 ( "~~*" PGNSP PGUID b f f 1042 25 16 0 1630 bpchariclike iclikesel iclikejoinsel "---"));
DESCR("matches LIKE expression, case-insensitive");
#define OID_BPCHAR_ICLIKE_OP 1629
-DATA(insert OID = 1630 ( "!~~*" PGNSP PGUID b f f 1042 25 16 0 1629 bpcharicnlike icnlikesel icnlikejoinsel ));
+DATA(insert OID = 1630 ( "!~~*" PGNSP PGUID b f f 1042 25 16 0 1629 bpcharicnlike icnlikesel icnlikejoinsel "---"));
DESCR("does not match LIKE expression, case-insensitive");
/* NUMERIC type - OID's 1700-1799 */
-DATA(insert OID = 1751 ( "-" PGNSP PGUID l f f 0 1700 1700 0 0 numeric_uminus - - ));
+DATA(insert OID = 1751 ( "-" PGNSP PGUID l f f 0 1700 1700 0 0 numeric_uminus - - "---"));
DESCR("negate");
-DATA(insert OID = 1752 ( "=" PGNSP PGUID b t t 1700 1700 16 1752 1753 numeric_eq eqsel eqjoinsel ));
+DATA(insert OID = 1752 ( "=" PGNSP PGUID b t t 1700 1700 16 1752 1753 numeric_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1753 ( "<>" PGNSP PGUID b f f 1700 1700 16 1753 1752 numeric_ne neqsel neqjoinsel ));
+DATA(insert OID = 1753 ( "<>" PGNSP PGUID b f f 1700 1700 16 1753 1752 numeric_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1754 ( "<" PGNSP PGUID b f f 1700 1700 16 1756 1757 numeric_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1754 ( "<" PGNSP PGUID b f f 1700 1700 16 1756 1757 numeric_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1755 ( "<=" PGNSP PGUID b f f 1700 1700 16 1757 1756 numeric_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1755 ( "<=" PGNSP PGUID b f f 1700 1700 16 1757 1756 numeric_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1756 ( ">" PGNSP PGUID b f f 1700 1700 16 1754 1755 numeric_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1756 ( ">" PGNSP PGUID b f f 1700 1700 16 1754 1755 numeric_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1757 ( ">=" PGNSP PGUID b f f 1700 1700 16 1755 1754 numeric_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1757 ( ">=" PGNSP PGUID b f f 1700 1700 16 1755 1754 numeric_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1758 ( "+" PGNSP PGUID b f f 1700 1700 1700 1758 0 numeric_add - - ));
+DATA(insert OID = 1758 ( "+" PGNSP PGUID b f f 1700 1700 1700 1758 0 numeric_add - - "---"));
DESCR("add");
-DATA(insert OID = 1759 ( "-" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_sub - - ));
+DATA(insert OID = 1759 ( "-" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_sub - - "---"));
DESCR("subtract");
-DATA(insert OID = 1760 ( "*" PGNSP PGUID b f f 1700 1700 1700 1760 0 numeric_mul - - ));
+DATA(insert OID = 1760 ( "*" PGNSP PGUID b f f 1700 1700 1700 1760 0 numeric_mul - - "---"));
DESCR("multiply");
-DATA(insert OID = 1761 ( "/" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_div - - ));
+DATA(insert OID = 1761 ( "/" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_div - - "---"));
DESCR("divide");
-DATA(insert OID = 1762 ( "%" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_mod - - ));
+DATA(insert OID = 1762 ( "%" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_mod - - "---"));
DESCR("modulus");
-DATA(insert OID = 1038 ( "^" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_power - - ));
+DATA(insert OID = 1038 ( "^" PGNSP PGUID b f f 1700 1700 1700 0 0 numeric_power - - "---"));
DESCR("exponentiation");
-DATA(insert OID = 1763 ( "@" PGNSP PGUID l f f 0 1700 1700 0 0 numeric_abs - - ));
+DATA(insert OID = 1763 ( "@" PGNSP PGUID l f f 0 1700 1700 0 0 numeric_abs - - "---"));
DESCR("absolute value");
-DATA(insert OID = 1784 ( "=" PGNSP PGUID b t f 1560 1560 16 1784 1785 biteq eqsel eqjoinsel ));
+DATA(insert OID = 1784 ( "=" PGNSP PGUID b t f 1560 1560 16 1784 1785 biteq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1785 ( "<>" PGNSP PGUID b f f 1560 1560 16 1785 1784 bitne neqsel neqjoinsel ));
+DATA(insert OID = 1785 ( "<>" PGNSP PGUID b f f 1560 1560 16 1785 1784 bitne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1786 ( "<" PGNSP PGUID b f f 1560 1560 16 1787 1789 bitlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1786 ( "<" PGNSP PGUID b f f 1560 1560 16 1787 1789 bitlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1787 ( ">" PGNSP PGUID b f f 1560 1560 16 1786 1788 bitgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1787 ( ">" PGNSP PGUID b f f 1560 1560 16 1786 1788 bitgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1788 ( "<=" PGNSP PGUID b f f 1560 1560 16 1789 1787 bitle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1788 ( "<=" PGNSP PGUID b f f 1560 1560 16 1789 1787 bitle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1789 ( ">=" PGNSP PGUID b f f 1560 1560 16 1788 1786 bitge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1789 ( ">=" PGNSP PGUID b f f 1560 1560 16 1788 1786 bitge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1791 ( "&" PGNSP PGUID b f f 1560 1560 1560 1791 0 bitand - - ));
+DATA(insert OID = 1791 ( "&" PGNSP PGUID b f f 1560 1560 1560 1791 0 bitand - - "---"));
DESCR("bitwise and");
-DATA(insert OID = 1792 ( "|" PGNSP PGUID b f f 1560 1560 1560 1792 0 bitor - - ));
+DATA(insert OID = 1792 ( "|" PGNSP PGUID b f f 1560 1560 1560 1792 0 bitor - - "---"));
DESCR("bitwise or");
-DATA(insert OID = 1793 ( "#" PGNSP PGUID b f f 1560 1560 1560 1793 0 bitxor - - ));
+DATA(insert OID = 1793 ( "#" PGNSP PGUID b f f 1560 1560 1560 1793 0 bitxor - - "---"));
DESCR("bitwise exclusive or");
-DATA(insert OID = 1794 ( "~" PGNSP PGUID l f f 0 1560 1560 0 0 bitnot - - ));
+DATA(insert OID = 1794 ( "~" PGNSP PGUID l f f 0 1560 1560 0 0 bitnot - - "---"));
DESCR("bitwise not");
-DATA(insert OID = 1795 ( "<<" PGNSP PGUID b f f 1560 23 1560 0 0 bitshiftleft - - ));
+DATA(insert OID = 1795 ( "<<" PGNSP PGUID b f f 1560 23 1560 0 0 bitshiftleft - - "---"));
DESCR("bitwise shift left");
-DATA(insert OID = 1796 ( ">>" PGNSP PGUID b f f 1560 23 1560 0 0 bitshiftright - - ));
+DATA(insert OID = 1796 ( ">>" PGNSP PGUID b f f 1560 23 1560 0 0 bitshiftright - - "---"));
DESCR("bitwise shift right");
-DATA(insert OID = 1797 ( "||" PGNSP PGUID b f f 1562 1562 1562 0 0 bitcat - - ));
+DATA(insert OID = 1797 ( "||" PGNSP PGUID b f f 1562 1562 1562 0 0 bitcat - - "---"));
DESCR("concatenate");
-DATA(insert OID = 1800 ( "+" PGNSP PGUID b f f 1083 1186 1083 1849 0 time_pl_interval - - ));
+DATA(insert OID = 1800 ( "+" PGNSP PGUID b f f 1083 1186 1083 1849 0 time_pl_interval - - "---"));
DESCR("add");
-DATA(insert OID = 1801 ( "-" PGNSP PGUID b f f 1083 1186 1083 0 0 time_mi_interval - - ));
+DATA(insert OID = 1801 ( "-" PGNSP PGUID b f f 1083 1186 1083 0 0 time_mi_interval - - "---"));
DESCR("subtract");
-DATA(insert OID = 1802 ( "+" PGNSP PGUID b f f 1266 1186 1266 2552 0 timetz_pl_interval - - ));
+DATA(insert OID = 1802 ( "+" PGNSP PGUID b f f 1266 1186 1266 2552 0 timetz_pl_interval - - "---"));
DESCR("add");
-DATA(insert OID = 1803 ( "-" PGNSP PGUID b f f 1266 1186 1266 0 0 timetz_mi_interval - - ));
+DATA(insert OID = 1803 ( "-" PGNSP PGUID b f f 1266 1186 1266 0 0 timetz_mi_interval - - "---"));
DESCR("subtract");
-DATA(insert OID = 1804 ( "=" PGNSP PGUID b t f 1562 1562 16 1804 1805 varbiteq eqsel eqjoinsel ));
+DATA(insert OID = 1804 ( "=" PGNSP PGUID b t f 1562 1562 16 1804 1805 varbiteq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1805 ( "<>" PGNSP PGUID b f f 1562 1562 16 1805 1804 varbitne neqsel neqjoinsel ));
+DATA(insert OID = 1805 ( "<>" PGNSP PGUID b f f 1562 1562 16 1805 1804 varbitne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1806 ( "<" PGNSP PGUID b f f 1562 1562 16 1807 1809 varbitlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1806 ( "<" PGNSP PGUID b f f 1562 1562 16 1807 1809 varbitlt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1807 ( ">" PGNSP PGUID b f f 1562 1562 16 1806 1808 varbitgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1807 ( ">" PGNSP PGUID b f f 1562 1562 16 1806 1808 varbitgt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1808 ( "<=" PGNSP PGUID b f f 1562 1562 16 1809 1807 varbitle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1808 ( "<=" PGNSP PGUID b f f 1562 1562 16 1809 1807 varbitle scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1809 ( ">=" PGNSP PGUID b f f 1562 1562 16 1808 1806 varbitge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1809 ( ">=" PGNSP PGUID b f f 1562 1562 16 1808 1806 varbitge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1849 ( "+" PGNSP PGUID b f f 1186 1083 1083 1800 0 interval_pl_time - - ));
+DATA(insert OID = 1849 ( "+" PGNSP PGUID b f f 1186 1083 1083 1800 0 interval_pl_time - - "---"));
DESCR("add");
-DATA(insert OID = 1862 ( "=" PGNSP PGUID b t t 21 20 16 1868 1863 int28eq eqsel eqjoinsel ));
+DATA(insert OID = 1862 ( "=" PGNSP PGUID b t t 21 20 16 1868 1863 int28eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1863 ( "<>" PGNSP PGUID b f f 21 20 16 1869 1862 int28ne neqsel neqjoinsel ));
+DATA(insert OID = 1863 ( "<>" PGNSP PGUID b f f 21 20 16 1869 1862 int28ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1864 ( "<" PGNSP PGUID b f f 21 20 16 1871 1867 int28lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1864 ( "<" PGNSP PGUID b f f 21 20 16 1871 1867 int28lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1865 ( ">" PGNSP PGUID b f f 21 20 16 1870 1866 int28gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1865 ( ">" PGNSP PGUID b f f 21 20 16 1870 1866 int28gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1866 ( "<=" PGNSP PGUID b f f 21 20 16 1873 1865 int28le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1866 ( "<=" PGNSP PGUID b f f 21 20 16 1873 1865 int28le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1867 ( ">=" PGNSP PGUID b f f 21 20 16 1872 1864 int28ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1867 ( ">=" PGNSP PGUID b f f 21 20 16 1872 1864 int28ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1868 ( "=" PGNSP PGUID b t t 20 21 16 1862 1869 int82eq eqsel eqjoinsel ));
+DATA(insert OID = 1868 ( "=" PGNSP PGUID b t t 20 21 16 1862 1869 int82eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1869 ( "<>" PGNSP PGUID b f f 20 21 16 1863 1868 int82ne neqsel neqjoinsel ));
+DATA(insert OID = 1869 ( "<>" PGNSP PGUID b f f 20 21 16 1863 1868 int82ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1870 ( "<" PGNSP PGUID b f f 20 21 16 1865 1873 int82lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1870 ( "<" PGNSP PGUID b f f 20 21 16 1865 1873 int82lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1871 ( ">" PGNSP PGUID b f f 20 21 16 1864 1872 int82gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1871 ( ">" PGNSP PGUID b f f 20 21 16 1864 1872 int82gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1872 ( "<=" PGNSP PGUID b f f 20 21 16 1867 1871 int82le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1872 ( "<=" PGNSP PGUID b f f 20 21 16 1867 1871 int82le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1873 ( ">=" PGNSP PGUID b f f 20 21 16 1866 1870 int82ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1873 ( ">=" PGNSP PGUID b f f 20 21 16 1866 1870 int82ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 1874 ( "&" PGNSP PGUID b f f 21 21 21 1874 0 int2and - - ));
+DATA(insert OID = 1874 ( "&" PGNSP PGUID b f f 21 21 21 1874 0 int2and - - "---"));
DESCR("bitwise and");
-DATA(insert OID = 1875 ( "|" PGNSP PGUID b f f 21 21 21 1875 0 int2or - - ));
+DATA(insert OID = 1875 ( "|" PGNSP PGUID b f f 21 21 21 1875 0 int2or - - "---"));
DESCR("bitwise or");
-DATA(insert OID = 1876 ( "#" PGNSP PGUID b f f 21 21 21 1876 0 int2xor - - ));
+DATA(insert OID = 1876 ( "#" PGNSP PGUID b f f 21 21 21 1876 0 int2xor - - "---"));
DESCR("bitwise exclusive or");
-DATA(insert OID = 1877 ( "~" PGNSP PGUID l f f 0 21 21 0 0 int2not - - ));
+DATA(insert OID = 1877 ( "~" PGNSP PGUID l f f 0 21 21 0 0 int2not - - "---"));
DESCR("bitwise not");
-DATA(insert OID = 1878 ( "<<" PGNSP PGUID b f f 21 23 21 0 0 int2shl - - ));
+DATA(insert OID = 1878 ( "<<" PGNSP PGUID b f f 21 23 21 0 0 int2shl - - "---"));
DESCR("bitwise shift left");
-DATA(insert OID = 1879 ( ">>" PGNSP PGUID b f f 21 23 21 0 0 int2shr - - ));
+DATA(insert OID = 1879 ( ">>" PGNSP PGUID b f f 21 23 21 0 0 int2shr - - "---"));
DESCR("bitwise shift right");
-DATA(insert OID = 1880 ( "&" PGNSP PGUID b f f 23 23 23 1880 0 int4and - - ));
+DATA(insert OID = 1880 ( "&" PGNSP PGUID b f f 23 23 23 1880 0 int4and - - "---"));
DESCR("bitwise and");
-DATA(insert OID = 1881 ( "|" PGNSP PGUID b f f 23 23 23 1881 0 int4or - - ));
+DATA(insert OID = 1881 ( "|" PGNSP PGUID b f f 23 23 23 1881 0 int4or - - "---"));
DESCR("bitwise or");
-DATA(insert OID = 1882 ( "#" PGNSP PGUID b f f 23 23 23 1882 0 int4xor - - ));
+DATA(insert OID = 1882 ( "#" PGNSP PGUID b f f 23 23 23 1882 0 int4xor - - "---"));
DESCR("bitwise exclusive or");
-DATA(insert OID = 1883 ( "~" PGNSP PGUID l f f 0 23 23 0 0 int4not - - ));
+DATA(insert OID = 1883 ( "~" PGNSP PGUID l f f 0 23 23 0 0 int4not - - "---"));
DESCR("bitwise not");
-DATA(insert OID = 1884 ( "<<" PGNSP PGUID b f f 23 23 23 0 0 int4shl - - ));
+DATA(insert OID = 1884 ( "<<" PGNSP PGUID b f f 23 23 23 0 0 int4shl - - "---"));
DESCR("bitwise shift left");
-DATA(insert OID = 1885 ( ">>" PGNSP PGUID b f f 23 23 23 0 0 int4shr - - ));
+DATA(insert OID = 1885 ( ">>" PGNSP PGUID b f f 23 23 23 0 0 int4shr - - "---"));
DESCR("bitwise shift right");
-DATA(insert OID = 1886 ( "&" PGNSP PGUID b f f 20 20 20 1886 0 int8and - - ));
+DATA(insert OID = 1886 ( "&" PGNSP PGUID b f f 20 20 20 1886 0 int8and - - "---"));
DESCR("bitwise and");
-DATA(insert OID = 1887 ( "|" PGNSP PGUID b f f 20 20 20 1887 0 int8or - - ));
+DATA(insert OID = 1887 ( "|" PGNSP PGUID b f f 20 20 20 1887 0 int8or - - "---"));
DESCR("bitwise or");
-DATA(insert OID = 1888 ( "#" PGNSP PGUID b f f 20 20 20 1888 0 int8xor - - ));
+DATA(insert OID = 1888 ( "#" PGNSP PGUID b f f 20 20 20 1888 0 int8xor - - "---"));
DESCR("bitwise exclusive or");
-DATA(insert OID = 1889 ( "~" PGNSP PGUID l f f 0 20 20 0 0 int8not - - ));
+DATA(insert OID = 1889 ( "~" PGNSP PGUID l f f 0 20 20 0 0 int8not - - "---"));
DESCR("bitwise not");
-DATA(insert OID = 1890 ( "<<" PGNSP PGUID b f f 20 23 20 0 0 int8shl - - ));
+DATA(insert OID = 1890 ( "<<" PGNSP PGUID b f f 20 23 20 0 0 int8shl - - "---"));
DESCR("bitwise shift left");
-DATA(insert OID = 1891 ( ">>" PGNSP PGUID b f f 20 23 20 0 0 int8shr - - ));
+DATA(insert OID = 1891 ( ">>" PGNSP PGUID b f f 20 23 20 0 0 int8shr - - "---"));
DESCR("bitwise shift right");
-DATA(insert OID = 1916 ( "+" PGNSP PGUID l f f 0 20 20 0 0 int8up - - ));
+DATA(insert OID = 1916 ( "+" PGNSP PGUID l f f 0 20 20 0 0 int8up - - "---"));
DESCR("unary plus");
-DATA(insert OID = 1917 ( "+" PGNSP PGUID l f f 0 21 21 0 0 int2up - - ));
+DATA(insert OID = 1917 ( "+" PGNSP PGUID l f f 0 21 21 0 0 int2up - - "---"));
DESCR("unary plus");
-DATA(insert OID = 1918 ( "+" PGNSP PGUID l f f 0 23 23 0 0 int4up - - ));
+DATA(insert OID = 1918 ( "+" PGNSP PGUID l f f 0 23 23 0 0 int4up - - "---"));
DESCR("unary plus");
-DATA(insert OID = 1919 ( "+" PGNSP PGUID l f f 0 700 700 0 0 float4up - - ));
+DATA(insert OID = 1919 ( "+" PGNSP PGUID l f f 0 700 700 0 0 float4up - - "---"));
DESCR("unary plus");
-DATA(insert OID = 1920 ( "+" PGNSP PGUID l f f 0 701 701 0 0 float8up - - ));
+DATA(insert OID = 1920 ( "+" PGNSP PGUID l f f 0 701 701 0 0 float8up - - "---"));
DESCR("unary plus");
-DATA(insert OID = 1921 ( "+" PGNSP PGUID l f f 0 1700 1700 0 0 numeric_uplus - - ));
+DATA(insert OID = 1921 ( "+" PGNSP PGUID l f f 0 1700 1700 0 0 numeric_uplus - - "---"));
DESCR("unary plus");
/* bytea operators */
-DATA(insert OID = 1955 ( "=" PGNSP PGUID b t t 17 17 16 1955 1956 byteaeq eqsel eqjoinsel ));
+DATA(insert OID = 1955 ( "=" PGNSP PGUID b t t 17 17 16 1955 1956 byteaeq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 1956 ( "<>" PGNSP PGUID b f f 17 17 16 1956 1955 byteane neqsel neqjoinsel ));
+DATA(insert OID = 1956 ( "<>" PGNSP PGUID b f f 17 17 16 1956 1955 byteane neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 1957 ( "<" PGNSP PGUID b f f 17 17 16 1959 1960 bytealt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1957 ( "<" PGNSP PGUID b f f 17 17 16 1959 1960 bytealt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 1958 ( "<=" PGNSP PGUID b f f 17 17 16 1960 1959 byteale scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1958 ( "<=" PGNSP PGUID b f f 17 17 16 1960 1959 byteale scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 1959 ( ">" PGNSP PGUID b f f 17 17 16 1957 1958 byteagt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1959 ( ">" PGNSP PGUID b f f 17 17 16 1957 1958 byteagt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 1960 ( ">=" PGNSP PGUID b f f 17 17 16 1958 1957 byteage scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1960 ( ">=" PGNSP PGUID b f f 17 17 16 1958 1957 byteage scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2016 ( "~~" PGNSP PGUID b f f 17 17 16 0 2017 bytealike likesel likejoinsel ));
+DATA(insert OID = 2016 ( "~~" PGNSP PGUID b f f 17 17 16 0 2017 bytealike likesel likejoinsel "---"));
DESCR("matches LIKE expression");
#define OID_BYTEA_LIKE_OP 2016
-DATA(insert OID = 2017 ( "!~~" PGNSP PGUID b f f 17 17 16 0 2016 byteanlike nlikesel nlikejoinsel ));
+DATA(insert OID = 2017 ( "!~~" PGNSP PGUID b f f 17 17 16 0 2016 byteanlike nlikesel nlikejoinsel "---"));
DESCR("does not match LIKE expression");
-DATA(insert OID = 2018 ( "||" PGNSP PGUID b f f 17 17 17 0 0 byteacat - - ));
+DATA(insert OID = 2018 ( "||" PGNSP PGUID b f f 17 17 17 0 0 byteacat - - "---"));
DESCR("concatenate");
/* timestamp operators */
-DATA(insert OID = 2060 ( "=" PGNSP PGUID b t t 1114 1114 16 2060 2061 timestamp_eq eqsel eqjoinsel ));
+DATA(insert OID = 2060 ( "=" PGNSP PGUID b t t 1114 1114 16 2060 2061 timestamp_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2061 ( "<>" PGNSP PGUID b f f 1114 1114 16 2061 2060 timestamp_ne neqsel neqjoinsel ));
+DATA(insert OID = 2061 ( "<>" PGNSP PGUID b f f 1114 1114 16 2061 2060 timestamp_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2062 ( "<" PGNSP PGUID b f f 1114 1114 16 2064 2065 timestamp_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2062 ( "<" PGNSP PGUID b f f 1114 1114 16 2064 2065 timestamp_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2063 ( "<=" PGNSP PGUID b f f 1114 1114 16 2065 2064 timestamp_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2063 ( "<=" PGNSP PGUID b f f 1114 1114 16 2065 2064 timestamp_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2064 ( ">" PGNSP PGUID b f f 1114 1114 16 2062 2063 timestamp_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2064 ( ">" PGNSP PGUID b f f 1114 1114 16 2062 2063 timestamp_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2065 ( ">=" PGNSP PGUID b f f 1114 1114 16 2063 2062 timestamp_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2065 ( ">=" PGNSP PGUID b f f 1114 1114 16 2063 2062 timestamp_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2066 ( "+" PGNSP PGUID b f f 1114 1186 1114 2553 0 timestamp_pl_interval - - ));
+DATA(insert OID = 2066 ( "+" PGNSP PGUID b f f 1114 1186 1114 2553 0 timestamp_pl_interval - - "---"));
DESCR("add");
-DATA(insert OID = 2067 ( "-" PGNSP PGUID b f f 1114 1114 1186 0 0 timestamp_mi - - ));
+DATA(insert OID = 2067 ( "-" PGNSP PGUID b f f 1114 1114 1186 0 0 timestamp_mi - - "---"));
DESCR("subtract");
-DATA(insert OID = 2068 ( "-" PGNSP PGUID b f f 1114 1186 1114 0 0 timestamp_mi_interval - - ));
+DATA(insert OID = 2068 ( "-" PGNSP PGUID b f f 1114 1186 1114 0 0 timestamp_mi_interval - - "---"));
DESCR("subtract");
/* character-by-character (not collation order) comparison operators for character types */
-DATA(insert OID = 2314 ( "~<~" PGNSP PGUID b f f 25 25 16 2318 2317 text_pattern_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2314 ( "~<~" PGNSP PGUID b f f 25 25 16 2318 2317 text_pattern_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2315 ( "~<=~" PGNSP PGUID b f f 25 25 16 2317 2318 text_pattern_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2315 ( "~<=~" PGNSP PGUID b f f 25 25 16 2317 2318 text_pattern_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2317 ( "~>=~" PGNSP PGUID b f f 25 25 16 2315 2314 text_pattern_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2317 ( "~>=~" PGNSP PGUID b f f 25 25 16 2315 2314 text_pattern_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2318 ( "~>~" PGNSP PGUID b f f 25 25 16 2314 2315 text_pattern_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2318 ( "~>~" PGNSP PGUID b f f 25 25 16 2314 2315 text_pattern_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2326 ( "~<~" PGNSP PGUID b f f 1042 1042 16 2330 2329 bpchar_pattern_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2326 ( "~<~" PGNSP PGUID b f f 1042 1042 16 2330 2329 bpchar_pattern_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2327 ( "~<=~" PGNSP PGUID b f f 1042 1042 16 2329 2330 bpchar_pattern_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2327 ( "~<=~" PGNSP PGUID b f f 1042 1042 16 2329 2330 bpchar_pattern_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2329 ( "~>=~" PGNSP PGUID b f f 1042 1042 16 2327 2326 bpchar_pattern_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2329 ( "~>=~" PGNSP PGUID b f f 1042 1042 16 2327 2326 bpchar_pattern_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2330 ( "~>~" PGNSP PGUID b f f 1042 1042 16 2326 2327 bpchar_pattern_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2330 ( "~>~" PGNSP PGUID b f f 1042 1042 16 2326 2327 bpchar_pattern_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
/* crosstype operations for date vs. timestamp and timestamptz */
-DATA(insert OID = 2345 ( "<" PGNSP PGUID b f f 1082 1114 16 2375 2348 date_lt_timestamp scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2345 ( "<" PGNSP PGUID b f f 1082 1114 16 2375 2348 date_lt_timestamp scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2346 ( "<=" PGNSP PGUID b f f 1082 1114 16 2374 2349 date_le_timestamp scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2346 ( "<=" PGNSP PGUID b f f 1082 1114 16 2374 2349 date_le_timestamp scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2347 ( "=" PGNSP PGUID b t f 1082 1114 16 2373 2350 date_eq_timestamp eqsel eqjoinsel ));
+DATA(insert OID = 2347 ( "=" PGNSP PGUID b t f 1082 1114 16 2373 2350 date_eq_timestamp eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2348 ( ">=" PGNSP PGUID b f f 1082 1114 16 2372 2345 date_ge_timestamp scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2348 ( ">=" PGNSP PGUID b f f 1082 1114 16 2372 2345 date_ge_timestamp scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2349 ( ">" PGNSP PGUID b f f 1082 1114 16 2371 2346 date_gt_timestamp scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2349 ( ">" PGNSP PGUID b f f 1082 1114 16 2371 2346 date_gt_timestamp scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2350 ( "<>" PGNSP PGUID b f f 1082 1114 16 2376 2347 date_ne_timestamp neqsel neqjoinsel ));
+DATA(insert OID = 2350 ( "<>" PGNSP PGUID b f f 1082 1114 16 2376 2347 date_ne_timestamp neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2358 ( "<" PGNSP PGUID b f f 1082 1184 16 2388 2361 date_lt_timestamptz scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2358 ( "<" PGNSP PGUID b f f 1082 1184 16 2388 2361 date_lt_timestamptz scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2359 ( "<=" PGNSP PGUID b f f 1082 1184 16 2387 2362 date_le_timestamptz scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2359 ( "<=" PGNSP PGUID b f f 1082 1184 16 2387 2362 date_le_timestamptz scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2360 ( "=" PGNSP PGUID b t f 1082 1184 16 2386 2363 date_eq_timestamptz eqsel eqjoinsel ));
+DATA(insert OID = 2360 ( "=" PGNSP PGUID b t f 1082 1184 16 2386 2363 date_eq_timestamptz eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2361 ( ">=" PGNSP PGUID b f f 1082 1184 16 2385 2358 date_ge_timestamptz scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2361 ( ">=" PGNSP PGUID b f f 1082 1184 16 2385 2358 date_ge_timestamptz scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2362 ( ">" PGNSP PGUID b f f 1082 1184 16 2384 2359 date_gt_timestamptz scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2362 ( ">" PGNSP PGUID b f f 1082 1184 16 2384 2359 date_gt_timestamptz scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2363 ( "<>" PGNSP PGUID b f f 1082 1184 16 2389 2360 date_ne_timestamptz neqsel neqjoinsel ));
+DATA(insert OID = 2363 ( "<>" PGNSP PGUID b f f 1082 1184 16 2389 2360 date_ne_timestamptz neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2371 ( "<" PGNSP PGUID b f f 1114 1082 16 2349 2374 timestamp_lt_date scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2371 ( "<" PGNSP PGUID b f f 1114 1082 16 2349 2374 timestamp_lt_date scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2372 ( "<=" PGNSP PGUID b f f 1114 1082 16 2348 2375 timestamp_le_date scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2372 ( "<=" PGNSP PGUID b f f 1114 1082 16 2348 2375 timestamp_le_date scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2373 ( "=" PGNSP PGUID b t f 1114 1082 16 2347 2376 timestamp_eq_date eqsel eqjoinsel ));
+DATA(insert OID = 2373 ( "=" PGNSP PGUID b t f 1114 1082 16 2347 2376 timestamp_eq_date eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2374 ( ">=" PGNSP PGUID b f f 1114 1082 16 2346 2371 timestamp_ge_date scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2374 ( ">=" PGNSP PGUID b f f 1114 1082 16 2346 2371 timestamp_ge_date scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2375 ( ">" PGNSP PGUID b f f 1114 1082 16 2345 2372 timestamp_gt_date scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2375 ( ">" PGNSP PGUID b f f 1114 1082 16 2345 2372 timestamp_gt_date scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2376 ( "<>" PGNSP PGUID b f f 1114 1082 16 2350 2373 timestamp_ne_date neqsel neqjoinsel ));
+DATA(insert OID = 2376 ( "<>" PGNSP PGUID b f f 1114 1082 16 2350 2373 timestamp_ne_date neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2384 ( "<" PGNSP PGUID b f f 1184 1082 16 2362 2387 timestamptz_lt_date scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2384 ( "<" PGNSP PGUID b f f 1184 1082 16 2362 2387 timestamptz_lt_date scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2385 ( "<=" PGNSP PGUID b f f 1184 1082 16 2361 2388 timestamptz_le_date scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2385 ( "<=" PGNSP PGUID b f f 1184 1082 16 2361 2388 timestamptz_le_date scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2386 ( "=" PGNSP PGUID b t f 1184 1082 16 2360 2389 timestamptz_eq_date eqsel eqjoinsel ));
+DATA(insert OID = 2386 ( "=" PGNSP PGUID b t f 1184 1082 16 2360 2389 timestamptz_eq_date eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2387 ( ">=" PGNSP PGUID b f f 1184 1082 16 2359 2384 timestamptz_ge_date scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2387 ( ">=" PGNSP PGUID b f f 1184 1082 16 2359 2384 timestamptz_ge_date scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2388 ( ">" PGNSP PGUID b f f 1184 1082 16 2358 2385 timestamptz_gt_date scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2388 ( ">" PGNSP PGUID b f f 1184 1082 16 2358 2385 timestamptz_gt_date scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2389 ( "<>" PGNSP PGUID b f f 1184 1082 16 2363 2386 timestamptz_ne_date neqsel neqjoinsel ));
+DATA(insert OID = 2389 ( "<>" PGNSP PGUID b f f 1184 1082 16 2363 2386 timestamptz_ne_date neqsel neqjoinsel "mhf"));
DESCR("not equal");
/* crosstype operations for timestamp vs. timestamptz */
-DATA(insert OID = 2534 ( "<" PGNSP PGUID b f f 1114 1184 16 2544 2537 timestamp_lt_timestamptz scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2534 ( "<" PGNSP PGUID b f f 1114 1184 16 2544 2537 timestamp_lt_timestamptz scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2535 ( "<=" PGNSP PGUID b f f 1114 1184 16 2543 2538 timestamp_le_timestamptz scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2535 ( "<=" PGNSP PGUID b f f 1114 1184 16 2543 2538 timestamp_le_timestamptz scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2536 ( "=" PGNSP PGUID b t f 1114 1184 16 2542 2539 timestamp_eq_timestamptz eqsel eqjoinsel ));
+DATA(insert OID = 2536 ( "=" PGNSP PGUID b t f 1114 1184 16 2542 2539 timestamp_eq_timestamptz eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2537 ( ">=" PGNSP PGUID b f f 1114 1184 16 2541 2534 timestamp_ge_timestamptz scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2537 ( ">=" PGNSP PGUID b f f 1114 1184 16 2541 2534 timestamp_ge_timestamptz scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2538 ( ">" PGNSP PGUID b f f 1114 1184 16 2540 2535 timestamp_gt_timestamptz scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2538 ( ">" PGNSP PGUID b f f 1114 1184 16 2540 2535 timestamp_gt_timestamptz scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2539 ( "<>" PGNSP PGUID b f f 1114 1184 16 2545 2536 timestamp_ne_timestamptz neqsel neqjoinsel ));
+DATA(insert OID = 2539 ( "<>" PGNSP PGUID b f f 1114 1184 16 2545 2536 timestamp_ne_timestamptz neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2540 ( "<" PGNSP PGUID b f f 1184 1114 16 2538 2543 timestamptz_lt_timestamp scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2540 ( "<" PGNSP PGUID b f f 1184 1114 16 2538 2543 timestamptz_lt_timestamp scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2541 ( "<=" PGNSP PGUID b f f 1184 1114 16 2537 2544 timestamptz_le_timestamp scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2541 ( "<=" PGNSP PGUID b f f 1184 1114 16 2537 2544 timestamptz_le_timestamp scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2542 ( "=" PGNSP PGUID b t f 1184 1114 16 2536 2545 timestamptz_eq_timestamp eqsel eqjoinsel ));
+DATA(insert OID = 2542 ( "=" PGNSP PGUID b t f 1184 1114 16 2536 2545 timestamptz_eq_timestamp eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2543 ( ">=" PGNSP PGUID b f f 1184 1114 16 2535 2540 timestamptz_ge_timestamp scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2543 ( ">=" PGNSP PGUID b f f 1184 1114 16 2535 2540 timestamptz_ge_timestamp scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 2544 ( ">" PGNSP PGUID b f f 1184 1114 16 2534 2541 timestamptz_gt_timestamp scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2544 ( ">" PGNSP PGUID b f f 1184 1114 16 2534 2541 timestamptz_gt_timestamp scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2545 ( "<>" PGNSP PGUID b f f 1184 1114 16 2539 2542 timestamptz_ne_timestamp neqsel neqjoinsel ));
+DATA(insert OID = 2545 ( "<>" PGNSP PGUID b f f 1184 1114 16 2539 2542 timestamptz_ne_timestamp neqsel neqjoinsel "mhf"));
DESCR("not equal");
/* formerly-missing interval + datetime operators */
-DATA(insert OID = 2551 ( "+" PGNSP PGUID b f f 1186 1082 1114 1076 0 interval_pl_date - - ));
+DATA(insert OID = 2551 ( "+" PGNSP PGUID b f f 1186 1082 1114 1076 0 interval_pl_date - - "---"));
DESCR("add");
-DATA(insert OID = 2552 ( "+" PGNSP PGUID b f f 1186 1266 1266 1802 0 interval_pl_timetz - - ));
+DATA(insert OID = 2552 ( "+" PGNSP PGUID b f f 1186 1266 1266 1802 0 interval_pl_timetz - - "---"));
DESCR("add");
-DATA(insert OID = 2553 ( "+" PGNSP PGUID b f f 1186 1114 1114 2066 0 interval_pl_timestamp - - ));
+DATA(insert OID = 2553 ( "+" PGNSP PGUID b f f 1186 1114 1114 2066 0 interval_pl_timestamp - - "---"));
DESCR("add");
-DATA(insert OID = 2554 ( "+" PGNSP PGUID b f f 1186 1184 1184 1327 0 interval_pl_timestamptz - - ));
+DATA(insert OID = 2554 ( "+" PGNSP PGUID b f f 1186 1184 1184 1327 0 interval_pl_timestamptz - - "---"));
DESCR("add");
-DATA(insert OID = 2555 ( "+" PGNSP PGUID b f f 23 1082 1082 1100 0 integer_pl_date - - ));
+DATA(insert OID = 2555 ( "+" PGNSP PGUID b f f 23 1082 1082 1100 0 integer_pl_date - - "---"));
DESCR("add");
/* new operators for Y-direction rtree opfamilies */
-DATA(insert OID = 2570 ( "<<|" PGNSP PGUID b f f 603 603 16 0 0 box_below positionsel positionjoinsel ));
+DATA(insert OID = 2570 ( "<<|" PGNSP PGUID b f f 603 603 16 0 0 box_below positionsel positionjoinsel "---"));
DESCR("is below");
-DATA(insert OID = 2571 ( "&<|" PGNSP PGUID b f f 603 603 16 0 0 box_overbelow positionsel positionjoinsel ));
+DATA(insert OID = 2571 ( "&<|" PGNSP PGUID b f f 603 603 16 0 0 box_overbelow positionsel positionjoinsel "---"));
DESCR("overlaps or is below");
-DATA(insert OID = 2572 ( "|&>" PGNSP PGUID b f f 603 603 16 0 0 box_overabove positionsel positionjoinsel ));
+DATA(insert OID = 2572 ( "|&>" PGNSP PGUID b f f 603 603 16 0 0 box_overabove positionsel positionjoinsel "---"));
DESCR("overlaps or is above");
-DATA(insert OID = 2573 ( "|>>" PGNSP PGUID b f f 603 603 16 0 0 box_above positionsel positionjoinsel ));
+DATA(insert OID = 2573 ( "|>>" PGNSP PGUID b f f 603 603 16 0 0 box_above positionsel positionjoinsel "---"));
DESCR("is above");
-DATA(insert OID = 2574 ( "<<|" PGNSP PGUID b f f 604 604 16 0 0 poly_below positionsel positionjoinsel ));
+DATA(insert OID = 2574 ( "<<|" PGNSP PGUID b f f 604 604 16 0 0 poly_below positionsel positionjoinsel "---"));
DESCR("is below");
-DATA(insert OID = 2575 ( "&<|" PGNSP PGUID b f f 604 604 16 0 0 poly_overbelow positionsel positionjoinsel ));
+DATA(insert OID = 2575 ( "&<|" PGNSP PGUID b f f 604 604 16 0 0 poly_overbelow positionsel positionjoinsel "---"));
DESCR("overlaps or is below");
-DATA(insert OID = 2576 ( "|&>" PGNSP PGUID b f f 604 604 16 0 0 poly_overabove positionsel positionjoinsel ));
+DATA(insert OID = 2576 ( "|&>" PGNSP PGUID b f f 604 604 16 0 0 poly_overabove positionsel positionjoinsel "---"));
DESCR("overlaps or is above");
-DATA(insert OID = 2577 ( "|>>" PGNSP PGUID b f f 604 604 16 0 0 poly_above positionsel positionjoinsel ));
+DATA(insert OID = 2577 ( "|>>" PGNSP PGUID b f f 604 604 16 0 0 poly_above positionsel positionjoinsel "---"));
DESCR("is above");
-DATA(insert OID = 2589 ( "&<|" PGNSP PGUID b f f 718 718 16 0 0 circle_overbelow positionsel positionjoinsel ));
+DATA(insert OID = 2589 ( "&<|" PGNSP PGUID b f f 718 718 16 0 0 circle_overbelow positionsel positionjoinsel "---"));
DESCR("overlaps or is below");
-DATA(insert OID = 2590 ( "|&>" PGNSP PGUID b f f 718 718 16 0 0 circle_overabove positionsel positionjoinsel ));
+DATA(insert OID = 2590 ( "|&>" PGNSP PGUID b f f 718 718 16 0 0 circle_overabove positionsel positionjoinsel "---"));
DESCR("overlaps or is above");
/* overlap/contains/contained for arrays */
-DATA(insert OID = 2750 ( "&&" PGNSP PGUID b f f 2277 2277 16 2750 0 arrayoverlap arraycontsel arraycontjoinsel ));
+DATA(insert OID = 2750 ( "&&" PGNSP PGUID b f f 2277 2277 16 2750 0 arrayoverlap arraycontsel arraycontjoinsel "---"));
DESCR("overlaps");
#define OID_ARRAY_OVERLAP_OP 2750
-DATA(insert OID = 2751 ( "@>" PGNSP PGUID b f f 2277 2277 16 2752 0 arraycontains arraycontsel arraycontjoinsel ));
+DATA(insert OID = 2751 ( "@>" PGNSP PGUID b f f 2277 2277 16 2752 0 arraycontains arraycontsel arraycontjoinsel "---"));
DESCR("contains");
#define OID_ARRAY_CONTAINS_OP 2751
-DATA(insert OID = 2752 ( "<@" PGNSP PGUID b f f 2277 2277 16 2751 0 arraycontained arraycontsel arraycontjoinsel ));
+DATA(insert OID = 2752 ( "<@" PGNSP PGUID b f f 2277 2277 16 2751 0 arraycontained arraycontsel arraycontjoinsel "---"));
DESCR("is contained by");
#define OID_ARRAY_CONTAINED_OP 2752
/* capturing operators to preserve pre-8.3 behavior of text concatenation */
-DATA(insert OID = 2779 ( "||" PGNSP PGUID b f f 25 2776 25 0 0 textanycat - - ));
+DATA(insert OID = 2779 ( "||" PGNSP PGUID b f f 25 2776 25 0 0 textanycat - - "---"));
DESCR("concatenate");
-DATA(insert OID = 2780 ( "||" PGNSP PGUID b f f 2776 25 25 0 0 anytextcat - - ));
+DATA(insert OID = 2780 ( "||" PGNSP PGUID b f f 2776 25 25 0 0 anytextcat - - "---"));
DESCR("concatenate");
/* obsolete names for contains/contained-by operators; remove these someday */
-DATA(insert OID = 2860 ( "@" PGNSP PGUID b f f 604 604 16 2861 0 poly_contained contsel contjoinsel ));
+DATA(insert OID = 2860 ( "@" PGNSP PGUID b f f 604 604 16 2861 0 poly_contained contsel contjoinsel "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2861 ( "~" PGNSP PGUID b f f 604 604 16 2860 0 poly_contain contsel contjoinsel ));
+DATA(insert OID = 2861 ( "~" PGNSP PGUID b f f 604 604 16 2860 0 poly_contain contsel contjoinsel "---"));
DESCR("deprecated, use @> instead");
-DATA(insert OID = 2862 ( "@" PGNSP PGUID b f f 603 603 16 2863 0 box_contained contsel contjoinsel ));
+DATA(insert OID = 2862 ( "@" PGNSP PGUID b f f 603 603 16 2863 0 box_contained contsel contjoinsel "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2863 ( "~" PGNSP PGUID b f f 603 603 16 2862 0 box_contain contsel contjoinsel ));
+DATA(insert OID = 2863 ( "~" PGNSP PGUID b f f 603 603 16 2862 0 box_contain contsel contjoinsel "---"));
DESCR("deprecated, use @> instead");
-DATA(insert OID = 2864 ( "@" PGNSP PGUID b f f 718 718 16 2865 0 circle_contained contsel contjoinsel ));
+DATA(insert OID = 2864 ( "@" PGNSP PGUID b f f 718 718 16 2865 0 circle_contained contsel contjoinsel "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2865 ( "~" PGNSP PGUID b f f 718 718 16 2864 0 circle_contain contsel contjoinsel ));
+DATA(insert OID = 2865 ( "~" PGNSP PGUID b f f 718 718 16 2864 0 circle_contain contsel contjoinsel "---"));
DESCR("deprecated, use @> instead");
-DATA(insert OID = 2866 ( "@" PGNSP PGUID b f f 600 603 16 0 0 on_pb - - ));
+DATA(insert OID = 2866 ( "@" PGNSP PGUID b f f 600 603 16 0 0 on_pb - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2867 ( "@" PGNSP PGUID b f f 600 602 16 2868 0 on_ppath - - ));
+DATA(insert OID = 2867 ( "@" PGNSP PGUID b f f 600 602 16 2868 0 on_ppath - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2868 ( "~" PGNSP PGUID b f f 602 600 16 2867 0 path_contain_pt - - ));
+DATA(insert OID = 2868 ( "~" PGNSP PGUID b f f 602 600 16 2867 0 path_contain_pt - - "---"));
DESCR("deprecated, use @> instead");
-DATA(insert OID = 2869 ( "@" PGNSP PGUID b f f 600 604 16 2870 0 pt_contained_poly - - ));
+DATA(insert OID = 2869 ( "@" PGNSP PGUID b f f 600 604 16 2870 0 pt_contained_poly - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2870 ( "~" PGNSP PGUID b f f 604 600 16 2869 0 poly_contain_pt - - ));
+DATA(insert OID = 2870 ( "~" PGNSP PGUID b f f 604 600 16 2869 0 poly_contain_pt - - "---"));
DESCR("deprecated, use @> instead");
-DATA(insert OID = 2871 ( "@" PGNSP PGUID b f f 600 718 16 2872 0 pt_contained_circle - - ));
+DATA(insert OID = 2871 ( "@" PGNSP PGUID b f f 600 718 16 2872 0 pt_contained_circle - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2872 ( "~" PGNSP PGUID b f f 718 600 16 2871 0 circle_contain_pt - - ));
+DATA(insert OID = 2872 ( "~" PGNSP PGUID b f f 718 600 16 2871 0 circle_contain_pt - - "---"));
DESCR("deprecated, use @> instead");
-DATA(insert OID = 2873 ( "@" PGNSP PGUID b f f 600 628 16 0 0 on_pl - - ));
+DATA(insert OID = 2873 ( "@" PGNSP PGUID b f f 600 628 16 0 0 on_pl - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2874 ( "@" PGNSP PGUID b f f 600 601 16 0 0 on_ps - - ));
+DATA(insert OID = 2874 ( "@" PGNSP PGUID b f f 600 601 16 0 0 on_ps - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2875 ( "@" PGNSP PGUID b f f 601 628 16 0 0 on_sl - - ));
+DATA(insert OID = 2875 ( "@" PGNSP PGUID b f f 601 628 16 0 0 on_sl - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2876 ( "@" PGNSP PGUID b f f 601 603 16 0 0 on_sb - - ));
+DATA(insert OID = 2876 ( "@" PGNSP PGUID b f f 601 603 16 0 0 on_sb - - "---"));
DESCR("deprecated, use <@ instead");
-DATA(insert OID = 2877 ( "~" PGNSP PGUID b f f 1034 1033 16 0 0 aclcontains - - ));
+DATA(insert OID = 2877 ( "~" PGNSP PGUID b f f 1034 1033 16 0 0 aclcontains - - "---"));
DESCR("deprecated, use @> instead");
/* uuid operators */
-DATA(insert OID = 2972 ( "=" PGNSP PGUID b t t 2950 2950 16 2972 2973 uuid_eq eqsel eqjoinsel ));
+DATA(insert OID = 2972 ( "=" PGNSP PGUID b t t 2950 2950 16 2972 2973 uuid_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 2973 ( "<>" PGNSP PGUID b f f 2950 2950 16 2973 2972 uuid_ne neqsel neqjoinsel ));
+DATA(insert OID = 2973 ( "<>" PGNSP PGUID b f f 2950 2950 16 2973 2972 uuid_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2974 ( "<" PGNSP PGUID b f f 2950 2950 16 2975 2977 uuid_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2974 ( "<" PGNSP PGUID b f f 2950 2950 16 2975 2977 uuid_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 2975 ( ">" PGNSP PGUID b f f 2950 2950 16 2974 2976 uuid_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2975 ( ">" PGNSP PGUID b f f 2950 2950 16 2974 2976 uuid_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 2976 ( "<=" PGNSP PGUID b f f 2950 2950 16 2977 2975 uuid_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2976 ( "<=" PGNSP PGUID b f f 2950 2950 16 2977 2975 uuid_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* pg_lsn operators */
-DATA(insert OID = 3222 ( "=" PGNSP PGUID b t t 3220 3220 16 3222 3223 pg_lsn_eq eqsel eqjoinsel ));
+DATA(insert OID = 3222 ( "=" PGNSP PGUID b t t 3220 3220 16 3222 3223 pg_lsn_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 3223 ( "<>" PGNSP PGUID b f f 3220 3220 16 3223 3222 pg_lsn_ne neqsel neqjoinsel ));
+DATA(insert OID = 3223 ( "<>" PGNSP PGUID b f f 3220 3220 16 3223 3222 pg_lsn_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 3224 ( "<" PGNSP PGUID b f f 3220 3220 16 3225 3227 pg_lsn_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3224 ( "<" PGNSP PGUID b f f 3220 3220 16 3225 3227 pg_lsn_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 3225 ( ">" PGNSP PGUID b f f 3220 3220 16 3224 3226 pg_lsn_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3225 ( ">" PGNSP PGUID b f f 3220 3220 16 3224 3226 pg_lsn_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 3226 ( "<=" PGNSP PGUID b f f 3220 3220 16 3227 3225 pg_lsn_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3226 ( "<=" PGNSP PGUID b f f 3220 3220 16 3227 3225 pg_lsn_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 3227 ( ">=" PGNSP PGUID b f f 3220 3220 16 3226 3224 pg_lsn_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3227 ( ">=" PGNSP PGUID b f f 3220 3220 16 3226 3224 pg_lsn_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 3228 ( "-" PGNSP PGUID b f f 3220 3220 1700 0 0 pg_lsn_mi - - ));
+DATA(insert OID = 3228 ( "-" PGNSP PGUID b f f 3220 3220 1700 0 0 pg_lsn_mi - - "---"));
DESCR("minus");
/* enum operators */
-DATA(insert OID = 3516 ( "=" PGNSP PGUID b t t 3500 3500 16 3516 3517 enum_eq eqsel eqjoinsel ));
+DATA(insert OID = 3516 ( "=" PGNSP PGUID b t t 3500 3500 16 3516 3517 enum_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 3517 ( "<>" PGNSP PGUID b f f 3500 3500 16 3517 3516 enum_ne neqsel neqjoinsel ));
+DATA(insert OID = 3517 ( "<>" PGNSP PGUID b f f 3500 3500 16 3517 3516 enum_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 3518 ( "<" PGNSP PGUID b f f 3500 3500 16 3519 3521 enum_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3518 ( "<" PGNSP PGUID b f f 3500 3500 16 3519 3521 enum_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 3519 ( ">" PGNSP PGUID b f f 3500 3500 16 3518 3520 enum_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3519 ( ">" PGNSP PGUID b f f 3500 3500 16 3518 3520 enum_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 3520 ( "<=" PGNSP PGUID b f f 3500 3500 16 3521 3519 enum_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3520 ( "<=" PGNSP PGUID b f f 3500 3500 16 3521 3519 enum_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 3521 ( ">=" PGNSP PGUID b f f 3500 3500 16 3520 3518 enum_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3521 ( ">=" PGNSP PGUID b f f 3500 3500 16 3520 3518 enum_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/*
* tsearch operations
*/
-DATA(insert OID = 3627 ( "<" PGNSP PGUID b f f 3614 3614 16 3632 3631 tsvector_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3627 ( "<" PGNSP PGUID b f f 3614 3614 16 3632 3631 tsvector_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 3628 ( "<=" PGNSP PGUID b f f 3614 3614 16 3631 3632 tsvector_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3628 ( "<=" PGNSP PGUID b f f 3614 3614 16 3631 3632 tsvector_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 3629 ( "=" PGNSP PGUID b t f 3614 3614 16 3629 3630 tsvector_eq eqsel eqjoinsel ));
+DATA(insert OID = 3629 ( "=" PGNSP PGUID b t f 3614 3614 16 3629 3630 tsvector_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 3630 ( "<>" PGNSP PGUID b f f 3614 3614 16 3630 3629 tsvector_ne neqsel neqjoinsel ));
+DATA(insert OID = 3630 ( "<>" PGNSP PGUID b f f 3614 3614 16 3630 3629 tsvector_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 3631 ( ">=" PGNSP PGUID b f f 3614 3614 16 3628 3627 tsvector_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3631 ( ">=" PGNSP PGUID b f f 3614 3614 16 3628 3627 tsvector_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 3632 ( ">" PGNSP PGUID b f f 3614 3614 16 3627 3628 tsvector_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3632 ( ">" PGNSP PGUID b f f 3614 3614 16 3627 3628 tsvector_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 3633 ( "||" PGNSP PGUID b f f 3614 3614 3614 0 0 tsvector_concat - - ));
+DATA(insert OID = 3633 ( "||" PGNSP PGUID b f f 3614 3614 3614 0 0 tsvector_concat - - "---"));
DESCR("concatenate");
-DATA(insert OID = 3636 ( "@@" PGNSP PGUID b f f 3614 3615 16 3637 0 ts_match_vq tsmatchsel tsmatchjoinsel ));
+DATA(insert OID = 3636 ( "@@" PGNSP PGUID b f f 3614 3615 16 3637 0 ts_match_vq tsmatchsel tsmatchjoinsel "---"));
DESCR("text search match");
-DATA(insert OID = 3637 ( "@@" PGNSP PGUID b f f 3615 3614 16 3636 0 ts_match_qv tsmatchsel tsmatchjoinsel ));
+DATA(insert OID = 3637 ( "@@" PGNSP PGUID b f f 3615 3614 16 3636 0 ts_match_qv tsmatchsel tsmatchjoinsel "---"));
DESCR("text search match");
-DATA(insert OID = 3660 ( "@@@" PGNSP PGUID b f f 3614 3615 16 3661 0 ts_match_vq tsmatchsel tsmatchjoinsel ));
+DATA(insert OID = 3660 ( "@@@" PGNSP PGUID b f f 3614 3615 16 3661 0 ts_match_vq tsmatchsel tsmatchjoinsel "---"));
DESCR("deprecated, use @@ instead");
-DATA(insert OID = 3661 ( "@@@" PGNSP PGUID b f f 3615 3614 16 3660 0 ts_match_qv tsmatchsel tsmatchjoinsel ));
+DATA(insert OID = 3661 ( "@@@" PGNSP PGUID b f f 3615 3614 16 3660 0 ts_match_qv tsmatchsel tsmatchjoinsel "---"));
DESCR("deprecated, use @@ instead");
-DATA(insert OID = 3674 ( "<" PGNSP PGUID b f f 3615 3615 16 3679 3678 tsquery_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3674 ( "<" PGNSP PGUID b f f 3615 3615 16 3679 3678 tsquery_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 3675 ( "<=" PGNSP PGUID b f f 3615 3615 16 3678 3679 tsquery_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3675 ( "<=" PGNSP PGUID b f f 3615 3615 16 3678 3679 tsquery_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 3676 ( "=" PGNSP PGUID b t f 3615 3615 16 3676 3677 tsquery_eq eqsel eqjoinsel ));
+DATA(insert OID = 3676 ( "=" PGNSP PGUID b t f 3615 3615 16 3676 3677 tsquery_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 3677 ( "<>" PGNSP PGUID b f f 3615 3615 16 3677 3676 tsquery_ne neqsel neqjoinsel ));
+DATA(insert OID = 3677 ( "<>" PGNSP PGUID b f f 3615 3615 16 3677 3676 tsquery_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 3678 ( ">=" PGNSP PGUID b f f 3615 3615 16 3675 3674 tsquery_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3678 ( ">=" PGNSP PGUID b f f 3615 3615 16 3675 3674 tsquery_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 3679 ( ">" PGNSP PGUID b f f 3615 3615 16 3674 3675 tsquery_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3679 ( ">" PGNSP PGUID b f f 3615 3615 16 3674 3675 tsquery_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 3680 ( "&&" PGNSP PGUID b f f 3615 3615 3615 0 0 tsquery_and - - ));
+DATA(insert OID = 3680 ( "&&" PGNSP PGUID b f f 3615 3615 3615 0 0 tsquery_and - - "---"));
DESCR("AND-concatenate");
-DATA(insert OID = 3681 ( "||" PGNSP PGUID b f f 3615 3615 3615 0 0 tsquery_or - - ));
+DATA(insert OID = 3681 ( "||" PGNSP PGUID b f f 3615 3615 3615 0 0 tsquery_or - - "---"));
DESCR("OR-concatenate");
-DATA(insert OID = 3682 ( "!!" PGNSP PGUID l f f 0 3615 3615 0 0 tsquery_not - - ));
+DATA(insert OID = 3682 ( "!!" PGNSP PGUID l f f 0 3615 3615 0 0 tsquery_not - - "---"));
DESCR("NOT tsquery");
-DATA(insert OID = 3693 ( "@>" PGNSP PGUID b f f 3615 3615 16 3694 0 tsq_mcontains contsel contjoinsel ));
+DATA(insert OID = 3693 ( "@>" PGNSP PGUID b f f 3615 3615 16 3694 0 tsq_mcontains contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 3694 ( "<@" PGNSP PGUID b f f 3615 3615 16 3693 0 tsq_mcontained contsel contjoinsel ));
+DATA(insert OID = 3694 ( "<@" PGNSP PGUID b f f 3615 3615 16 3693 0 tsq_mcontained contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 3762 ( "@@" PGNSP PGUID b f f 25 25 16 0 0 ts_match_tt contsel contjoinsel ));
+DATA(insert OID = 3762 ( "@@" PGNSP PGUID b f f 25 25 16 0 0 ts_match_tt contsel contjoinsel "---"));
DESCR("text search match");
-DATA(insert OID = 3763 ( "@@" PGNSP PGUID b f f 25 3615 16 0 0 ts_match_tq contsel contjoinsel ));
+DATA(insert OID = 3763 ( "@@" PGNSP PGUID b f f 25 3615 16 0 0 ts_match_tq contsel contjoinsel "---"));
DESCR("text search match");
/* generic record comparison operators */
-DATA(insert OID = 2988 ( "=" PGNSP PGUID b t f 2249 2249 16 2988 2989 record_eq eqsel eqjoinsel ));
+DATA(insert OID = 2988 ( "=" PGNSP PGUID b t f 2249 2249 16 2988 2989 record_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
#define RECORD_EQ_OP 2988
-DATA(insert OID = 2989 ( "<>" PGNSP PGUID b f f 2249 2249 16 2989 2988 record_ne neqsel neqjoinsel ));
+DATA(insert OID = 2989 ( "<>" PGNSP PGUID b f f 2249 2249 16 2989 2988 record_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 2990 ( "<" PGNSP PGUID b f f 2249 2249 16 2991 2993 record_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2990 ( "<" PGNSP PGUID b f f 2249 2249 16 2991 2993 record_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
#define RECORD_LT_OP 2990
-DATA(insert OID = 2991 ( ">" PGNSP PGUID b f f 2249 2249 16 2990 2992 record_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2991 ( ">" PGNSP PGUID b f f 2249 2249 16 2990 2992 record_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
#define RECORD_GT_OP 2991
-DATA(insert OID = 2992 ( "<=" PGNSP PGUID b f f 2249 2249 16 2993 2991 record_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 2992 ( "<=" PGNSP PGUID b f f 2249 2249 16 2993 2991 record_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 2993 ( ">=" PGNSP PGUID b f f 2249 2249 16 2992 2990 record_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 2993 ( ">=" PGNSP PGUID b f f 2249 2249 16 2992 2990 record_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* byte-oriented tests for identical rows and fast sorting */
-DATA(insert OID = 3188 ( "*=" PGNSP PGUID b t f 2249 2249 16 3188 3189 record_image_eq eqsel eqjoinsel ));
+DATA(insert OID = 3188 ( "*=" PGNSP PGUID b t f 2249 2249 16 3188 3189 record_image_eq eqsel eqjoinsel "mhf"));
DESCR("identical");
-DATA(insert OID = 3189 ( "*<>" PGNSP PGUID b f f 2249 2249 16 3189 3188 record_image_ne neqsel neqjoinsel ));
+DATA(insert OID = 3189 ( "*<>" PGNSP PGUID b f f 2249 2249 16 3189 3188 record_image_ne neqsel neqjoinsel "mhf"));
DESCR("not identical");
-DATA(insert OID = 3190 ( "*<" PGNSP PGUID b f f 2249 2249 16 3191 3193 record_image_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3190 ( "*<" PGNSP PGUID b f f 2249 2249 16 3191 3193 record_image_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 3191 ( "*>" PGNSP PGUID b f f 2249 2249 16 3190 3192 record_image_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3191 ( "*>" PGNSP PGUID b f f 2249 2249 16 3190 3192 record_image_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 3192 ( "*<=" PGNSP PGUID b f f 2249 2249 16 3193 3191 record_image_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3192 ( "*<=" PGNSP PGUID b f f 2249 2249 16 3193 3191 record_image_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 3193 ( "*>=" PGNSP PGUID b f f 2249 2249 16 3192 3190 record_image_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3193 ( "*>=" PGNSP PGUID b f f 2249 2249 16 3192 3190 record_image_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
/* generic range type operators */
-DATA(insert OID = 3882 ( "=" PGNSP PGUID b t t 3831 3831 16 3882 3883 range_eq eqsel eqjoinsel ));
+DATA(insert OID = 3882 ( "=" PGNSP PGUID b t t 3831 3831 16 3882 3883 range_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 3883 ( "<>" PGNSP PGUID b f f 3831 3831 16 3883 3882 range_ne neqsel neqjoinsel ));
+DATA(insert OID = 3883 ( "<>" PGNSP PGUID b f f 3831 3831 16 3883 3882 range_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 3884 ( "<" PGNSP PGUID b f f 3831 3831 16 3887 3886 range_lt rangesel scalarltjoinsel ));
+DATA(insert OID = 3884 ( "<" PGNSP PGUID b f f 3831 3831 16 3887 3886 range_lt rangesel scalarltjoinsel "---"));
DESCR("less than");
#define OID_RANGE_LESS_OP 3884
-DATA(insert OID = 3885 ( "<=" PGNSP PGUID b f f 3831 3831 16 3886 3887 range_le rangesel scalarltjoinsel ));
+DATA(insert OID = 3885 ( "<=" PGNSP PGUID b f f 3831 3831 16 3886 3887 range_le rangesel scalarltjoinsel "---"));
DESCR("less than or equal");
#define OID_RANGE_LESS_EQUAL_OP 3885
-DATA(insert OID = 3886 ( ">=" PGNSP PGUID b f f 3831 3831 16 3885 3884 range_ge rangesel scalargtjoinsel ));
+DATA(insert OID = 3886 ( ">=" PGNSP PGUID b f f 3831 3831 16 3885 3884 range_ge rangesel scalargtjoinsel "---"));
DESCR("greater than or equal");
#define OID_RANGE_GREATER_EQUAL_OP 3886
-DATA(insert OID = 3887 ( ">" PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt rangesel scalargtjoinsel ));
+DATA(insert OID = 3887 ( ">" PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt rangesel scalargtjoinsel "---"));
DESCR("greater than");
#define OID_RANGE_GREATER_OP 3887
-DATA(insert OID = 3888 ( "&&" PGNSP PGUID b f f 3831 3831 16 3888 0 range_overlaps rangesel areajoinsel ));
+DATA(insert OID = 3888 ( "&&" PGNSP PGUID b f f 3831 3831 16 3888 0 range_overlaps rangesel areajoinsel "---"));
DESCR("overlaps");
#define OID_RANGE_OVERLAP_OP 3888
-DATA(insert OID = 3889 ( "@>" PGNSP PGUID b f f 3831 2283 16 3891 0 range_contains_elem rangesel contjoinsel ));
+DATA(insert OID = 3889 ( "@>" PGNSP PGUID b f f 3831 2283 16 3891 0 range_contains_elem rangesel contjoinsel "---"));
DESCR("contains");
#define OID_RANGE_CONTAINS_ELEM_OP 3889
-DATA(insert OID = 3890 ( "@>" PGNSP PGUID b f f 3831 3831 16 3892 0 range_contains rangesel contjoinsel ));
+DATA(insert OID = 3890 ( "@>" PGNSP PGUID b f f 3831 3831 16 3892 0 range_contains rangesel contjoinsel "---"));
DESCR("contains");
#define OID_RANGE_CONTAINS_OP 3890
-DATA(insert OID = 3891 ( "<@" PGNSP PGUID b f f 2283 3831 16 3889 0 elem_contained_by_range rangesel contjoinsel ));
+DATA(insert OID = 3891 ( "<@" PGNSP PGUID b f f 2283 3831 16 3889 0 elem_contained_by_range rangesel contjoinsel "---"));
DESCR("is contained by");
#define OID_RANGE_ELEM_CONTAINED_OP 3891
-DATA(insert OID = 3892 ( "<@" PGNSP PGUID b f f 3831 3831 16 3890 0 range_contained_by rangesel contjoinsel ));
+DATA(insert OID = 3892 ( "<@" PGNSP PGUID b f f 3831 3831 16 3890 0 range_contained_by rangesel contjoinsel "---"));
DESCR("is contained by");
#define OID_RANGE_CONTAINED_OP 3892
-DATA(insert OID = 3893 ( "<<" PGNSP PGUID b f f 3831 3831 16 3894 0 range_before rangesel scalarltjoinsel ));
+DATA(insert OID = 3893 ( "<<" PGNSP PGUID b f f 3831 3831 16 3894 0 range_before rangesel scalarltjoinsel "---"));
DESCR("is left of");
#define OID_RANGE_LEFT_OP 3893
-DATA(insert OID = 3894 ( ">>" PGNSP PGUID b f f 3831 3831 16 3893 0 range_after rangesel scalargtjoinsel ));
+DATA(insert OID = 3894 ( ">>" PGNSP PGUID b f f 3831 3831 16 3893 0 range_after rangesel scalargtjoinsel "---"));
DESCR("is right of");
#define OID_RANGE_RIGHT_OP 3894
-DATA(insert OID = 3895 ( "&<" PGNSP PGUID b f f 3831 3831 16 0 0 range_overleft rangesel scalarltjoinsel ));
+DATA(insert OID = 3895 ( "&<" PGNSP PGUID b f f 3831 3831 16 0 0 range_overleft rangesel scalarltjoinsel "---"));
DESCR("overlaps or is left of");
#define OID_RANGE_OVERLAPS_LEFT_OP 3895
-DATA(insert OID = 3896 ( "&>" PGNSP PGUID b f f 3831 3831 16 0 0 range_overright rangesel scalargtjoinsel ));
+DATA(insert OID = 3896 ( "&>" PGNSP PGUID b f f 3831 3831 16 0 0 range_overright rangesel scalargtjoinsel "---"));
DESCR("overlaps or is right of");
#define OID_RANGE_OVERLAPS_RIGHT_OP 3896
-DATA(insert OID = 3897 ( "-|-" PGNSP PGUID b f f 3831 3831 16 3897 0 range_adjacent contsel contjoinsel ));
+DATA(insert OID = 3897 ( "-|-" PGNSP PGUID b f f 3831 3831 16 3897 0 range_adjacent contsel contjoinsel "---"));
DESCR("is adjacent to");
-DATA(insert OID = 3898 ( "+" PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - ));
+DATA(insert OID = 3898 ( "+" PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - "---"));
DESCR("range union");
-DATA(insert OID = 3899 ( "-" PGNSP PGUID b f f 3831 3831 3831 0 0 range_minus - - ));
+DATA(insert OID = 3899 ( "-" PGNSP PGUID b f f 3831 3831 3831 0 0 range_minus - - "---"));
DESCR("range difference");
-DATA(insert OID = 3900 ( "*" PGNSP PGUID b f f 3831 3831 3831 3900 0 range_intersect - - ));
+DATA(insert OID = 3900 ( "*" PGNSP PGUID b f f 3831 3831 3831 3900 0 range_intersect - - "---"));
DESCR("range intersection");
-DATA(insert OID = 3962 ( "->" PGNSP PGUID b f f 114 25 114 0 0 json_object_field - - ));
+DATA(insert OID = 3962 ( "->" PGNSP PGUID b f f 114 25 114 0 0 json_object_field - - "---"));
DESCR("get json object field");
-DATA(insert OID = 3963 ( "->>" PGNSP PGUID b f f 114 25 25 0 0 json_object_field_text - - ));
+DATA(insert OID = 3963 ( "->>" PGNSP PGUID b f f 114 25 25 0 0 json_object_field_text - - "---"));
DESCR("get json object field as text");
-DATA(insert OID = 3964 ( "->" PGNSP PGUID b f f 114 23 114 0 0 json_array_element - - ));
+DATA(insert OID = 3964 ( "->" PGNSP PGUID b f f 114 23 114 0 0 json_array_element - - "---"));
DESCR("get json array element");
-DATA(insert OID = 3965 ( "->>" PGNSP PGUID b f f 114 23 25 0 0 json_array_element_text - - ));
+DATA(insert OID = 3965 ( "->>" PGNSP PGUID b f f 114 23 25 0 0 json_array_element_text - - "---"));
DESCR("get json array element as text");
-DATA(insert OID = 3966 ( "#>" PGNSP PGUID b f f 114 1009 114 0 0 json_extract_path - - ));
+DATA(insert OID = 3966 ( "#>" PGNSP PGUID b f f 114 1009 114 0 0 json_extract_path - - "---"));
DESCR("get value from json with path elements");
-DATA(insert OID = 3967 ( "#>>" PGNSP PGUID b f f 114 1009 25 0 0 json_extract_path_text - - ));
+DATA(insert OID = 3967 ( "#>>" PGNSP PGUID b f f 114 1009 25 0 0 json_extract_path_text - - "---"));
DESCR("get value from json as text with path elements");
-DATA(insert OID = 3211 ( "->" PGNSP PGUID b f f 3802 25 3802 0 0 jsonb_object_field - - ));
+DATA(insert OID = 3211 ( "->" PGNSP PGUID b f f 3802 25 3802 0 0 jsonb_object_field - - "---"));
DESCR("get jsonb object field");
-DATA(insert OID = 3477 ( "->>" PGNSP PGUID b f f 3802 25 25 0 0 jsonb_object_field_text - - ));
+DATA(insert OID = 3477 ( "->>" PGNSP PGUID b f f 3802 25 25 0 0 jsonb_object_field_text - - "---"));
DESCR("get jsonb object field as text");
-DATA(insert OID = 3212 ( "->" PGNSP PGUID b f f 3802 23 3802 0 0 jsonb_array_element - - ));
+DATA(insert OID = 3212 ( "->" PGNSP PGUID b f f 3802 23 3802 0 0 jsonb_array_element - - "---"));
DESCR("get jsonb array element");
-DATA(insert OID = 3481 ( "->>" PGNSP PGUID b f f 3802 23 25 0 0 jsonb_array_element_text - - ));
+DATA(insert OID = 3481 ( "->>" PGNSP PGUID b f f 3802 23 25 0 0 jsonb_array_element_text - - "---"));
DESCR("get jsonb array element as text");
-DATA(insert OID = 3213 ( "#>" PGNSP PGUID b f f 3802 1009 3802 0 0 jsonb_extract_path - - ));
+DATA(insert OID = 3213 ( "#>" PGNSP PGUID b f f 3802 1009 3802 0 0 jsonb_extract_path - - "---"));
DESCR("get value from jsonb with path elements");
-DATA(insert OID = 3206 ( "#>>" PGNSP PGUID b f f 3802 1009 25 0 0 jsonb_extract_path_text - - ));
+DATA(insert OID = 3206 ( "#>>" PGNSP PGUID b f f 3802 1009 25 0 0 jsonb_extract_path_text - - "---"));
DESCR("get value from jsonb as text with path elements");
-DATA(insert OID = 3240 ( "=" PGNSP PGUID b t t 3802 3802 16 3240 3241 jsonb_eq eqsel eqjoinsel ));
+DATA(insert OID = 3240 ( "=" PGNSP PGUID b t t 3802 3802 16 3240 3241 jsonb_eq eqsel eqjoinsel "mhf"));
DESCR("equal");
-DATA(insert OID = 3241 ( "<>" PGNSP PGUID b f f 3802 3802 16 3241 3240 jsonb_ne neqsel neqjoinsel ));
+DATA(insert OID = 3241 ( "<>" PGNSP PGUID b f f 3802 3802 16 3241 3240 jsonb_ne neqsel neqjoinsel "mhf"));
DESCR("not equal");
-DATA(insert OID = 3242 ( "<" PGNSP PGUID b f f 3802 3802 16 3243 3245 jsonb_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3242 ( "<" PGNSP PGUID b f f 3802 3802 16 3243 3245 jsonb_lt scalarltsel scalarltjoinsel "mh-"));
DESCR("less than");
-DATA(insert OID = 3243 ( ">" PGNSP PGUID b f f 3802 3802 16 3242 3244 jsonb_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3243 ( ">" PGNSP PGUID b f f 3802 3802 16 3242 3244 jsonb_gt scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than");
-DATA(insert OID = 3244 ( "<=" PGNSP PGUID b f f 3802 3802 16 3245 3243 jsonb_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3244 ( "<=" PGNSP PGUID b f f 3802 3802 16 3245 3243 jsonb_le scalarltsel scalarltjoinsel "mh-"));
DESCR("less than or equal");
-DATA(insert OID = 3245 ( ">=" PGNSP PGUID b f f 3802 3802 16 3244 3242 jsonb_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3245 ( ">=" PGNSP PGUID b f f 3802 3802 16 3244 3242 jsonb_ge scalargtsel scalargtjoinsel "mh-"));
DESCR("greater than or equal");
-DATA(insert OID = 3246 ( "@>" PGNSP PGUID b f f 3802 3802 16 3250 0 jsonb_contains contsel contjoinsel ));
+DATA(insert OID = 3246 ( "@>" PGNSP PGUID b f f 3802 3802 16 3250 0 jsonb_contains contsel contjoinsel "---"));
DESCR("contains");
-DATA(insert OID = 3247 ( "?" PGNSP PGUID b f f 3802 25 16 0 0 jsonb_exists contsel contjoinsel ));
+DATA(insert OID = 3247 ( "?" PGNSP PGUID b f f 3802 25 16 0 0 jsonb_exists contsel contjoinsel "---"));
DESCR("exists");
-DATA(insert OID = 3248 ( "?|" PGNSP PGUID b f f 3802 1009 16 0 0 jsonb_exists_any contsel contjoinsel ));
+DATA(insert OID = 3248 ( "?|" PGNSP PGUID b f f 3802 1009 16 0 0 jsonb_exists_any contsel contjoinsel "---"));
DESCR("exists any");
-DATA(insert OID = 3249 ( "?&" PGNSP PGUID b f f 3802 1009 16 0 0 jsonb_exists_all contsel contjoinsel ));
+DATA(insert OID = 3249 ( "?&" PGNSP PGUID b f f 3802 1009 16 0 0 jsonb_exists_all contsel contjoinsel "---"));
DESCR("exists all");
-DATA(insert OID = 3250 ( "<@" PGNSP PGUID b f f 3802 3802 16 3246 0 jsonb_contained contsel contjoinsel ));
+DATA(insert OID = 3250 ( "<@" PGNSP PGUID b f f 3802 3802 16 3246 0 jsonb_contained contsel contjoinsel "---"));
DESCR("is contained by");
-DATA(insert OID = 3284 ( "||" PGNSP PGUID b f f 3802 3802 3802 0 0 jsonb_concat - - ));
+DATA(insert OID = 3284 ( "||" PGNSP PGUID b f f 3802 3802 3802 0 0 jsonb_concat - - "---"));
DESCR("concatenate");
-DATA(insert OID = 3285 ( "-" PGNSP PGUID b f f 3802 25 3802 0 0 3302 - - ));
+DATA(insert OID = 3285 ( "-" PGNSP PGUID b f f 3802 25 3802 0 0 3302 - - "---"));
DESCR("delete object field");
-DATA(insert OID = 3286 ( "-" PGNSP PGUID b f f 3802 23 3802 0 0 3303 - - ));
+DATA(insert OID = 3286 ( "-" PGNSP PGUID b f f 3802 23 3802 0 0 3303 - - "---"));
DESCR("delete array element");
-DATA(insert OID = 3287 ( "#-" PGNSP PGUID b f f 3802 1009 3802 0 0 jsonb_delete_path - - ));
+DATA(insert OID = 3287 ( "#-" PGNSP PGUID b f f 3802 1009 3802 0 0 jsonb_delete_path - - "---"));
DESCR("delete path");
/*
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 9254f85..9865a9c 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -250,6 +250,7 @@ typedef enum NodeTag
T_MinMaxAggInfo,
T_PlannerParamItem,
T_MVStatisticInfo,
+ T_RestrictStatData,
/*
* TAGS FOR MEMORY NODES (memnodes.h)
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 1979cdf..b78ee5d 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -15,12 +15,12 @@
#define RELATION_H
#include "access/sdir.h"
+#include "access/htup.h"
#include "lib/stringinfo.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "storage/block.h"
-
/*
* Relids
* Set of relation identifiers (indexes into the rangetable).
@@ -1341,6 +1341,26 @@ typedef struct RestrictInfo
Selectivity right_bucketsize; /* avg bucketsize of right side */
} RestrictInfo;
+typedef struct bm_mvstat
+{
+ Bitmapset *attrs;
+ MVStatisticInfo *stats;
+ int mvkind;
+} bm_mvstat;
+
+typedef struct RestrictStatData
+{
+ NodeTag type;
+ BoolExprType boolop;
+ Node *clause;
+ Node *mvclause;
+ Node *nonmvclause;
+ List *children;
+ List *mvstats;
+ Bitmapset *mvattrs;
+ List *unusedrinfos;
+} RestrictStatData;
+
/*
* Since mergejoinscansel() is a relatively expensive function, and would
* otherwise be invoked many times while planning a large join tree,
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 6bfd338..24003ae 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -183,13 +183,11 @@ extern Selectivity clauselist_selectivity(PlannerInfo *root,
List *clauses,
int varRelid,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- List *conditions);
+ SpecialJoinInfo *sjinfo);
extern Selectivity clause_selectivity(PlannerInfo *root,
Node *clause,
int varRelid,
JoinType jointype,
- SpecialJoinInfo *sjinfo,
- List *conditions);
+ SpecialJoinInfo *sjinfo);
#endif /* COST_H */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index a40c9b1..bb9d68b 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -84,6 +84,7 @@ extern Oid get_commutator(Oid opno);
extern Oid get_negator(Oid opno);
extern RegProcedure get_oprrest(Oid opno);
extern RegProcedure get_oprjoin(Oid opno);
+extern int get_oprmvstat(Oid opno);
extern char *get_func_name(Oid funcid);
extern Oid get_func_namespace(Oid funcid);
extern Oid get_func_rettype(Oid funcid);
diff --git a/src/include/utils/mvstats.h b/src/include/utils/mvstats.h
index f2fbc11..a08fd58 100644
--- a/src/include/utils/mvstats.h
+++ b/src/include/utils/mvstats.h
@@ -34,6 +34,9 @@ extern int mvstat_search_type;
#define MVSTATS_MAX_DIMENSIONS 8 /* max number of attributes */
+#define MVSTATISTIC_MCV 1
+#define MVSTATISTIC_HIST 2
+#define MVSTATISTIC_FDEP 4
/*
* Functional dependencies, tracking column-level relationships (values
--
1.8.3.1