Changeset: 89b4bf8a943d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/89b4bf8a943d
Added Files:
sql/test/BugTracker-2024/Tests/7045-do-not-push-down-converts.test
Modified Files:
sql/backends/monet5/rel_bin.c
sql/backends/monet5/sql_statement.c
sql/server/rel_exp.c
sql/server/rel_exp.h
sql/server/rel_optimize_others.c
sql/server/rel_optimize_proj.c
sql/server/rel_optimize_sel.c
sql/server/rel_rel.c
sql/server/rel_rel.h
sql/server/rel_statistics.c
sql/server/rel_unnest.c
sql/test/BugTracker-2024/Tests/All
sql/test/BugTracker-2024/Tests/atom_cmp-Bug-7477.test
sql/test/SQLancer/Tests/sqlancer17.test
sql/test/miscellaneous/Tests/select_groupby.stable.err
sql/test/miscellaneous/Tests/select_groupby.stable.out
Branch: Aug2024
Log Message:
improved split of join and select expressions (fixes #7553)
improved (not) push down of expressions (converts mostly) when could potentialy
lead to incorrect errors (fixes #7045).
diffs (truncated from 620 to 300 lines):
diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c
--- a/sql/backends/monet5/rel_bin.c
+++ b/sql/backends/monet5/rel_bin.c
@@ -1605,6 +1605,15 @@ exp_bin(backend *be, sql_exp *e, stmt *l
if (from->type->eclass == EC_SEC && to->type->eclass == EC_SEC)
{
// trivial conversion because EC_SEC is always in
milliseconds
s = l;
+ } else if (depth && sel && l->nrcols == 0 && left &&
left->nrcols && exp_unsafe(e, false, true)) {
+ stmt *rows = bin_find_smallest_column(be, left);
+ l = stmt_const(be, rows, l);
+ s = stmt_convert(be, l, sel, from, to);
+ } else if (depth && l->nrcols == 0 && left && left->nrcols &&
from->type->localtype > to->type->localtype &&
+ exp_unsafe(e, false, true)) {
+ stmt *rows = bin_find_smallest_column(be, left);
+ l = stmt_const(be, rows, l);
+ s = stmt_convert(be, l, sel, from, to);
} else {
s = stmt_convert(be, l, (!push&&l->nrcols==0)?NULL:sel,
from, to);
}
@@ -2829,12 +2838,12 @@ can_join_exp(sql_rel *rel, sql_exp *e, b
sql_exp *l = e->l, *r = e->r, *f = e->f;
if (f) {
- int ll = rel_find_exp(rel->l, l) != NULL;
- int rl = rel_find_exp(rel->r, l) != NULL;
- int lr = rel_find_exp(rel->l, r) != NULL;
- int rr = rel_find_exp(rel->r, r) != NULL;
- int lf = rel_find_exp(rel->l, f) != NULL;
- int rf = rel_find_exp(rel->r, f) != NULL;
+ int ll = rel_has_exp(rel->l, l, true) == 0;
+ int rl = rel_has_exp(rel->r, l, true) == 0;
+ int lr = rel_has_exp(rel->l, r, true) == 0;
+ int rr = rel_has_exp(rel->r, r, true) == 0;
+ int lf = rel_has_exp(rel->l, f, true) == 0;
+ int rf = rel_has_exp(rel->r, f, true) == 0;
int nrcr1 = 0, nrcr2 = 0, nrcl1 = 0, nrcl2 = 0;
if ((ll && !rl &&
@@ -2848,15 +2857,15 @@ can_join_exp(sql_rel *rel, sql_exp *e, b
} else {
int ll = 0, lr = 0, rl = 0, rr = 0, cst = 0;
if (l->card != CARD_ATOM || !exp_is_atom(l)) {
- ll = rel_find_exp(rel->l, l) != NULL;
- rl = rel_find_exp(rel->r, l) != NULL;
+ ll = rel_has_exp(rel->l, l, true) == 0;
+ rl = rel_has_exp(rel->r, l, true) == 0;
} else if (anti) {
ll = 1;
cst = 1;
}
if (r->card != CARD_ATOM || !exp_is_atom(r)) {
- lr = rel_find_exp(rel->l, r) != NULL;
- rr = rel_find_exp(rel->r, r) != NULL;
+ lr = rel_has_exp(rel->l, r, true) == 0;
+ rr = rel_has_exp(rel->r, r, true) == 0;
} else if (anti) {
rr = cst?0:1;
}
@@ -2871,16 +2880,16 @@ can_join_exp(sql_rel *rel, sql_exp *e, b
sql_exp *ee = n->data;
if (ee->card != CARD_ATOM || !exp_is_atom(ee)) {
- ll |= rel_find_exp(rel->l, ee) != NULL;
- rl |= rel_find_exp(rel->r, ee) != NULL;
+ ll |= rel_has_exp(rel->l, ee, true) ==
0;
+ rl |= rel_has_exp(rel->r, ee, true) ==
0;
}
}
for (node *n = r->h ; n ; n = n->next) {
sql_exp *ee = n->data;
if (ee->card != CARD_ATOM || !exp_is_atom(ee)) {
- lr |= rel_find_exp(rel->l, ee) != NULL;
- rr |= rel_find_exp(rel->r, ee) != NULL;
+ lr |= rel_has_exp(rel->l, ee, true) ==
0;
+ rr |= rel_has_exp(rel->r, ee, true) ==
0;
}
}
if ((ll && !lr && !rl && rr) || (!ll && lr && rl &&
!rr))
diff --git a/sql/backends/monet5/sql_statement.c
b/sql/backends/monet5/sql_statement.c
--- a/sql/backends/monet5/sql_statement.c
+++ b/sql/backends/monet5/sql_statement.c
@@ -3785,7 +3785,7 @@ temporal_convert(backend *be, stmt *v, s
MalBlkPtr mb = be->mb;
InstrPtr q = NULL;
const char *convert = t->type->impl, *mod = mtimeRef;
- bool add_tz = false, pushed = (v->cand && v->cand == sel);
+ bool add_tz = false, pushed = (v->cand && v->cand == sel), cand = 0;
if (before) {
if (f->type->eclass == EC_TIMESTAMP_TZ && (t->type->eclass ==
EC_TIMESTAMP || t->type->eclass == EC_TIME)) {
@@ -3816,6 +3816,7 @@ temporal_convert(backend *be, stmt *v, s
convert = "timestamptz";
mod = calcRef;
add_tz = true;
+ cand = 1;
} else {
return v;
}
@@ -3847,17 +3848,28 @@ temporal_convert(backend *be, stmt *v, s
}
q = pushArgument(mb, q, v->nr);
+ if (cand) {
+ if (sel && !pushed && !v->cand) {
+ q = pushArgument(mb, q, sel->nr);
+ pushed = 1;
+ } else if (v->nrcols > 0) {
+ q = pushNilBat(mb, q);
+ }
+ }
+
if (EC_VARCHAR(f->type->eclass))
q = pushInt(mb, q, t->digits);
if (add_tz)
q = pushLng(mb, q, be->mvc->timezone);
- if (sel && !pushed && !v->cand) {
- q = pushArgument(mb, q, sel->nr);
- pushed = 1;
- } else if (v->nrcols > 0) {
- q = pushNilBat(mb, q);
+ if (!cand) {
+ if (sel && !pushed && !v->cand) {
+ q = pushArgument(mb, q, sel->nr);
+ pushed = 1;
+ } else if (v->nrcols > 0) {
+ q = pushNilBat(mb, q);
+ }
}
bool enabled = be->mvc->sa->eb.enabled;
diff --git a/sql/server/rel_exp.c b/sql/server/rel_exp.c
--- a/sql/server/rel_exp.c
+++ b/sql/server/rel_exp.c
@@ -1747,6 +1747,27 @@ exps_find_prop(list *exps, rel_prop kind
return NULL;
}
+/* check is one of the exps can be found in this relation */
+static sql_exp* rel_find_exp_and_corresponding_rel_(sql_rel *rel, sql_exp *e,
bool subexp, sql_rel **res);
+
+static bool
+rel_find_exps_and_corresponding_rel_(sql_rel *rel, list *l, bool subexp,
sql_rel **res)
+{
+ int all = 1;
+
+ if (list_empty(l))
+ return true;
+ for(node *n = l->h; n && (subexp || all); n = n->next) {
+ sql_exp *ne = rel_find_exp_and_corresponding_rel_(rel, n->data,
subexp, res);
+ if (subexp && ne)
+ return true;
+ all &= (ne?1:0);
+ }
+ if (all)
+ return true;
+ return false;
+}
+
static sql_exp *
rel_find_exp_and_corresponding_rel_(sql_rel *rel, sql_exp *e, bool subexp,
sql_rel **res)
{
@@ -1773,22 +1794,28 @@ rel_find_exp_and_corresponding_rel_(sql_
return rel_find_exp_and_corresponding_rel_(rel, e->l, subexp,
res);
case e_aggr:
case e_func:
- if (e->l) {
- list *l = e->l;
- node *n = l->h;
-
- ne = n->data;
- while ((subexp || ne != NULL) && n != NULL) {
- ne = rel_find_exp_and_corresponding_rel_(rel,
n->data, subexp, res);
- if (subexp && ne)
- break;
- n = n->next;
- }
- return ne;
+ if (e->l)
+ if (rel_find_exps_and_corresponding_rel_(rel, e->l,
subexp, res))
+ return e;
+ return NULL;
+ case e_cmp:
+ if (!subexp)
+ return NULL;
+
+ if (e->flag == cmp_or || e->flag == cmp_filter) {
+ if (rel_find_exps_and_corresponding_rel_(rel, e->l,
subexp, res) ||
+ rel_find_exps_and_corresponding_rel_(rel, e->r,
subexp, res))
+ return e;
+ } else if (e->flag == cmp_in || e->flag == cmp_notin) {
+ if (rel_find_exp_and_corresponding_rel_(rel, e->l,
subexp, res) ||
+ rel_find_exps_and_corresponding_rel_(rel, e->r,
subexp, res))
+ return e;
+ } else if (rel_find_exp_and_corresponding_rel_(rel, e->l,
subexp, res) ||
+ rel_find_exp_and_corresponding_rel_(rel, e->r,
subexp, res) ||
+ (!e->f || rel_find_exp_and_corresponding_rel_(rel,
e->f, subexp, res))) {
+ return e;
}
- break;
- /* fall through */
- case e_cmp:
+ return NULL;
case e_psm:
return NULL;
case e_atom:
@@ -2104,10 +2131,8 @@ exp_is_null(sql_exp *e )
return 0;
case e_cmp:
if (!is_semantics(e)) {
- if (e->flag == cmp_or) {
+ if (e->flag == cmp_or || e->flag == cmp_filter) {
return (exps_have_null(e->l) &&
exps_have_null(e->r));
- } else if (e->flag == cmp_filter) {
- return (exps_have_null(e->l) ||
exps_have_null(e->r));
} else if (e->flag == cmp_in || e->flag == cmp_notin) {
return ((e->flag == cmp_in &&
exp_is_null(e->l)) ||
(e->flag == cmp_notin &&
(exp_is_null(e->l) || exps_have_null(e->r))));
@@ -2712,44 +2737,53 @@ exp_has_sideeffect( sql_exp *e )
return 0;
}
-int
-exps_have_unsafe(list *exps, int allow_identity)
+bool
+exps_have_unsafe(list *exps, bool allow_identity, bool card)
{
int unsafe = 0;
if (list_empty(exps))
return 0;
for (node *n = exps->h; n && !unsafe; n = n->next)
- unsafe |= exp_unsafe(n->data, allow_identity);
+ unsafe |= exp_unsafe(n->data, allow_identity, card);
return unsafe;
}
-int
-exp_unsafe(sql_exp *e, int allow_identity)
+bool
+exp_unsafe(sql_exp *e, bool allow_identity, bool card)
{
switch (e->type) {
case e_convert:
- return exp_unsafe(e->l, allow_identity);
+ if (card) {
+ sql_subtype *t = exp_totype(e);
+ sql_subtype *f = exp_fromtype(e);
+ if (t->type->eclass == EC_FLT && (f->type->eclass ==
EC_DEC || f->type->eclass == EC_NUM))
+ return false;
+ if (f->type->localtype > t->type->localtype)
+ return true;
+ return false;
+ }
+ return exp_unsafe(e->l, allow_identity, card);
case e_aggr:
case e_func: {
sql_subfunc *f = e->f;
if (IS_ANALYTIC(f->func) || !LANG_INT_OR_MAL(f->func->lang) ||
f->func->side_effect || (!allow_identity && is_identity(e, NULL)))
return 1;
- return exps_have_unsafe(e->l, allow_identity);
+ return exps_have_unsafe(e->l, allow_identity, card);
} break;
case e_cmp: {
if (e->flag == cmp_in || e->flag == cmp_notin) {
- return exp_unsafe(e->l, allow_identity) ||
exps_have_unsafe(e->r, allow_identity);
+ return exp_unsafe(e->l, allow_identity, card) ||
exps_have_unsafe(e->r, allow_identity, card);
} else if (e->flag == cmp_or || e->flag == cmp_filter) {
- return exps_have_unsafe(e->l, allow_identity) ||
exps_have_unsafe(e->r, allow_identity);
+ return exps_have_unsafe(e->l, allow_identity, card) ||
exps_have_unsafe(e->r, allow_identity, card);
} else {
- return exp_unsafe(e->l, allow_identity) ||
exp_unsafe(e->r, allow_identity) || (e->f && exp_unsafe(e->f, allow_identity));
+ return exp_unsafe(e->l, allow_identity, card) ||
exp_unsafe(e->r, allow_identity, card) || (e->f && exp_unsafe(e->f,
allow_identity, card));
}
} break;
case e_atom: {
if (e->f)
- return exps_have_unsafe(e->f, allow_identity);
+ return exps_have_unsafe(e->f, allow_identity, card);
return 0;
} break;
case e_column:
diff --git a/sql/server/rel_exp.h b/sql/server/rel_exp.h
--- a/sql/server/rel_exp.h
+++ b/sql/server/rel_exp.h
@@ -178,8 +178,9 @@ extern sql_exp *exp_rel_label(mvc *sql,
extern int exp_rel_depth(sql_exp *e);
extern int exps_are_atoms(list *exps);
extern int exp_has_func(sql_exp *e);
-extern int exps_have_unsafe(list *exps, int allow_identity);
-extern int exp_unsafe(sql_exp *e, int allow_identity);
+extern bool exps_have_unsafe(list *exps, bool allow_identity, bool card /* on
true check for possible cardinality related
+
unsafeness
(conversions for example) */);
+extern bool exp_unsafe(sql_exp *e, bool allow_identity, bool card);
extern int exp_has_sideeffect(sql_exp *e);
extern sql_exp *exps_find_prop(list *exps, rel_prop kind);
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]