aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomas Vondra <tomas.vondra@postgresql.org>2019-07-13 00:12:16 +0200
committerTomas Vondra <tomas.vondra@postgresql.org>2019-07-18 11:30:12 +0200
commit42276976a1437c88fb6176fc1a876fd79a139eb0 (patch)
tree6d9a7f134784361070c3b2900915aef8ddf4c779 /src
parent3944e855bc5bee32d99a9ba2245a026d4bafe282 (diff)
downloadpostgresql-42276976a1437c88fb6176fc1a876fd79a139eb0.tar.gz
postgresql-42276976a1437c88fb6176fc1a876fd79a139eb0.zip
Fix handling of opclauses in extended statistics
We expect opclauses to have exactly one Var and one Const, but the code was checking the Const by calling is_pseudo_constant_clause() which is incorrect - we need a proper constant. Fixed by using plain IsA(x,Const) to check type of the node. We need to do these checks in two places, so move it into a separate function that can be called in both places. Reported by Andreas Seltenreich, based on crash reported by sqlsmith. Backpatch to v12, where this code was introduced. Discussion: https://postgr.es/m/8736jdhbhc.fsf%40ansel.ydns.eu Backpatch-to: 12
Diffstat (limited to 'src')
-rw-r--r--src/backend/statistics/extended_stats.c76
-rw-r--r--src/backend/statistics/mcv.c27
-rw-r--r--src/include/statistics/extended_stats_internal.h2
3 files changed, 73 insertions, 32 deletions
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index c56ed482706..d2346cbe02e 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -796,21 +796,13 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
RangeTblEntry *rte = root->simple_rte_array[relid];
OpExpr *expr = (OpExpr *) clause;
Var *var;
- bool varonleft = true;
- bool ok;
/* Only expressions with two arguments are considered compatible. */
if (list_length(expr->args) != 2)
return false;
- /* see if it actually has the right shape (one Var, one Const) */
- ok = (NumRelids((Node *) expr) == 1) &&
- (is_pseudo_constant_clause(lsecond(expr->args)) ||
- (varonleft = false,
- is_pseudo_constant_clause(linitial(expr->args))));
-
- /* unsupported structure (two variables or so) */
- if (!ok)
+ /* Check if the expression the right shape (one Var, one Const) */
+ if (!examine_opclause_expression(expr, &var, NULL, NULL))
return false;
/*
@@ -850,8 +842,6 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
!get_func_leakproof(get_opcode(expr->opno)))
return false;
- var = (varonleft) ? linitial(expr->args) : lsecond(expr->args);
-
return statext_is_compatible_clause_internal(root, (Node *) var,
relid, attnums);
}
@@ -1196,3 +1186,65 @@ statext_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid,
return sel;
}
+
+/*
+ * examine_operator_expression
+ * Split expression into Var and Const parts.
+ *
+ * Attempts to match the arguments to either (Var op Const) or (Const op Var),
+ * possibly with a RelabelType on top. When the expression matches this form,
+ * returns true, otherwise returns false.
+ *
+ * Optionally returns pointers to the extracted Var/Const nodes, when passed
+ * non-null pointers (varp, cstp and isgtp). The isgt flag specifies whether
+ * the Var node is on the left (false) or right (true) side of the operator.
+ */
+bool
+examine_opclause_expression(OpExpr *expr, Var **varp, Const **cstp, bool *isgtp)
+{
+ Var *var;
+ Const *cst;
+ bool isgt;
+ Node *leftop,
+ *rightop;
+
+ /* enforced by statext_is_compatible_clause_internal */
+ Assert(list_length(expr->args) == 2);
+
+ leftop = linitial(expr->args);
+ rightop = lsecond(expr->args);
+
+ /* strip RelabelType from either side of the expression */
+ if (IsA(leftop, RelabelType))
+ leftop = (Node *) ((RelabelType *) leftop)->arg;
+
+ if (IsA(rightop, RelabelType))
+ rightop = (Node *) ((RelabelType *) rightop)->arg;
+
+ if (IsA(leftop, Var) && IsA(rightop, Const))
+ {
+ var = (Var *) leftop;
+ cst = (Const *) rightop;
+ isgt = false;
+ }
+ else if (IsA(leftop, Const) && IsA(rightop, Var))
+ {
+ var = (Var *) rightop;
+ cst = (Const *) leftop;
+ isgt = true;
+ }
+ else
+ return false;
+
+ /* return pointers to the extracted parts if requested */
+ if (varp)
+ *varp = var;
+
+ if (cstp)
+ *cstp = cst;
+
+ if (isgtp)
+ *isgtp = isgt;
+
+ return true;
+}
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index e62421dfa88..a708a8f6740 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1561,36 +1561,23 @@ mcv_get_match_bitmap(PlannerInfo *root, List *clauses,
if (is_opclause(clause))
{
OpExpr *expr = (OpExpr *) clause;
- bool varonleft = true;
- bool ok;
FmgrInfo opproc;
/* get procedure computing operator selectivity */
RegProcedure oprrest = get_oprrest(expr->opno);
- fmgr_info(get_opcode(expr->opno), &opproc);
+ /* valid only after examine_opclause_expression returns true */
+ Var *var;
+ Const *cst;
+ bool isgt;
- ok = (NumRelids(clause) == 1) &&
- (is_pseudo_constant_clause(lsecond(expr->args)) ||
- (varonleft = false,
- is_pseudo_constant_clause(linitial(expr->args))));
+ fmgr_info(get_opcode(expr->opno), &opproc);
- if (ok)
+ /* extract the var and const from the expression */
+ if (examine_opclause_expression(expr, &var, &cst, &isgt))
{
- Var *var;
- Const *cst;
- bool isgt;
int idx;
- /* extract the var and const from the expression */
- var = (varonleft) ? linitial(expr->args) : lsecond(expr->args);
- cst = (varonleft) ? lsecond(expr->args) : linitial(expr->args);
- isgt = (!varonleft);
-
- /* strip binary-compatible relabeling */
- if (IsA(var, RelabelType))
- var = (Var *) ((RelabelType *) var)->arg;
-
/* match the attribute to a dimension of the statistic */
idx = bms_member_index(keys, var->varattno);
diff --git a/src/include/statistics/extended_stats_internal.h b/src/include/statistics/extended_stats_internal.h
index 8fc541993fa..c7f01d4edc7 100644
--- a/src/include/statistics/extended_stats_internal.h
+++ b/src/include/statistics/extended_stats_internal.h
@@ -97,6 +97,8 @@ extern SortItem *build_sorted_items(int numrows, int *nitems, HeapTuple *rows,
TupleDesc tdesc, MultiSortSupport mss,
int numattrs, AttrNumber *attnums);
+extern bool examine_opclause_expression(OpExpr *expr, Var **varp,
+ Const **cstp, bool *isgtp);
extern Selectivity mcv_clauselist_selectivity(PlannerInfo *root,
StatisticExtInfo *stat,