[prev in list] [next in list] [prev in thread] [next in thread]
List: monetdb-checkins
Subject: MonetDB: scatter - merged with default
From: Niels_Nes <commits+niels=cwi.nl () monetdb ! org>
Date: 2021-05-31 10:52:06
Message-ID: hg.11dd03482987.1622458326.-2133801436980389525 () monetdb-vm0 ! spin-off ! cwi ! nl
[Download RAW message or body]
Changeset: 11dd03482987 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/11dd03482987
Modified Files:
sql/server/rel_optimizer.c
tools/monetdbe/monetdbe.c
Branch: scatter
Log Message:
merged with default
diffs (truncated from 1368 to 300 lines):
diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -5321,15 +5321,16 @@ find_projection_for_join2semi(sql_rel *r
sql_exp *found = NULL;
bool underjoin = false;
- /* if just one groupby column is projected, it will be distinct */
- if ((is_groupby(rel->op) && list_length(rel->r) == 1 && exps_find_exp(rel->r, \
e)) || need_distinct(rel) || find_prop(e->p, PROP_HASHCOL)) + /* if just one \
groupby column is projected or the relation needs distinct values and one column is \
projected or is a primary key, it will be distinct */ + if ((is_groupby(rel->op) \
&& list_length(rel->r) == 1 && exps_find_exp(rel->r, e)) || \
+ (is_simple_project(rel->op) && need_distinct(rel) && list_length(rel->exps) == \
1) || find_prop(e->p, PROP_HASHCOL)) return true;
if ((found = rel_find_exp_and_corresponding_rel(rel->l, e, &res, &underjoin)) && \
!underjoin) { /* grouping column on inner relation */
- if (find_prop(found->p, PROP_HASHCOL)) /* primary key always unique */
+ if ((is_simple_project(res->op) && need_distinct(res) && list_length(res->exps) \
== 1) || find_prop(found->p, PROP_HASHCOL)) return true;
if (found->type == e_column && found->card <= CARD_AGGR) {
- if (!(is_groupby(res->op) || need_distinct(res)) && list_length(res->exps) != \
1) + if (!is_groupby(res->op) && list_length(res->exps) != 1)
return false;
for (node *n = res->exps->h ; n ; n = n->next) { /* must be the single column \
in the group by expression list */ sql_exp *e = n->data;
@@ -8859,9 +8860,9 @@ exp_range_overlap(atom *min, atom *max,
}
static sql_rel *
-rel_rename_part(mvc *sql, sql_rel *p, sql_rel *rel, char *tname, sql_table *mt)
-{
- sql_table *t = rel_base_table(p);
+rel_rename_part(mvc *sql, sql_rel *p, sql_rel *mt_rel, const char *mtalias)
+{
+ sql_table *mt = rel_base_table(mt_rel), *t = rel_base_table(p);
node *n;
assert(!p->exps);
@@ -8869,47 +8870,20 @@ rel_rename_part(mvc *sql, sql_rel *p, sq
const char *pname = t->base.name;
if (isRemote(t))
pname = mapiuri_table(t->query, sql->sa, pname);
- for (n = rel->exps->h; n; n = n->next) {
+ for (n = mt_rel->exps->h; n; n = n->next) {
sql_exp *e = n->data;
if (is_intern(e) || exp_name(e)[0] == '%') /* break on tid/idxs */
break;
sql_column *c = ol_find_name(mt->columns, exp_name(e))->data;
sql_column *rc = ol_fetch(t->columns, c->colnr);
/* with name find column in merge table, with colnr find column in member */
- e = exp_alias(sql->sa, tname, c->base.name, pname, rc->base.name, &rc->type, \
CARD_MULTI, rc->null, 0);
- append(p->exps, e);
+ list_append(p->exps, exp_alias(sql->sa, mtalias, c->base.name, pname, \
rc->base.name, &rc->type, CARD_MULTI, rc->null, 0)); }
if (n) {
sql_exp *e = n->data;
- if (strcmp(exp_name(e), TID) == 0) {
- e = exp_alias(sql->sa, tname, TID, pname, TID, sql_bind_localtype("oid"), \
CARD_MULTI, 0, 1);
- append(p->exps, e);
- }
- }
-#if 0
- node *n, *m;
- for( m = ol_first_node(mt->columns); m; m = m->next) {
- sql_column *c = m->data;
- append(p->exps, exp_alias(sql->sa, tname, c->base.name, pname, c->base.name, \
&c->type, CARD_MULTI, c->null, 0));
- }
- if (n) /* skip TID */
- n = n->next;
- if (mt->idxs) {
- /* also possible index name mismatches */
- for( m = ol_first_node(mt->idxs); n && m; m = m->next) {
- sql_exp *ne = n->data;
- sql_idx *i = m->data;
- char *iname = NULL;
-
- if ((hash_index(i->type) && list_length(i->columns) <= 1) || \
!idx_has_column(i->type))
- continue;
-
- iname = sa_strconcat( sql->sa, "%", i->base.name);
- exp_setname(sql->sa, ne, tname, iname);
- n = n->next;
- }
- }
-#endif
+ if (strcmp(exp_name(e), TID) == 0)
+ list_append(p->exps, exp_alias(sql->sa, mtalias, TID, pname, TID, \
sql_bind_localtype("oid"), CARD_MULTI, 0, 1)); + }
rel_base_set_mergetable(p, mt);
return p;
}
@@ -8923,417 +8897,420 @@ typedef struct {
list *values;
} range_limit;
-/* rewrite merge tables into union of base tables and call optimizer again */
+typedef struct {
+ list *cols;
+ list *ranges;
+ sql_rel *sel;
+} merge_table_prune_info;
+
+static sql_rel *
+merge_table_prune_and_unionize(visitor *v, sql_rel *mt_rel, merge_table_prune_info \
*info) +{
+ sql_rel *nrel = NULL;
+ sql_table *mt = (sql_table*) mt_rel->l;
+ const char *mtalias = exp_relname(mt_rel->exps->h->data);
+ list *tables = sa_list(v->sql->sa);
+
+ if (mvc_highwater(v->sql))
+ return sql_error(v->sql, 10, SQLSTATE(42000) "Query too complex: running out of \
stack space"); +
+ for (node *nt = mt->members->h; nt; nt = nt->next) {
+ sql_part *pd = nt->data;
+ sql_table *pt = find_sql_table_id(v->sql->session->tr, mt->s, pd->member);
+ sqlstore *store = v->sql->session->tr->store;
+ int skip = 0, allowed = 1;
+
+ /* At the moment we throw an error in the optimizer, but later this rewriter \
should move out from the optimizers */ + if ((isMergeTable(pt) || \
isReplicaTable(pt)) && list_empty(pt->members)) + return sql_error(v->sql, 02, \
SQLSTATE(42000) "The %s '%s.%s' should have at least one table associated", + \
TABLE_TYPE_DESCRIPTION(pt->type, pt->properties), pt->s->base.name, pt->base.name); \
+ /* Do not include empty partitions */ + if (isTable(pt) && pt->access == \
TABLE_READONLY && !store->storage_api.count_col(v->sql->session->tr, \
ol_first_node(pt->columns)->data, 0)) + continue;
+
+ if (!table_privs(v->sql, pt, PRIV_SELECT)) /* Test for privileges */
+ allowed = 0;
+
+ for (node *n = mt_rel->exps->h; n && !skip; n = n->next) { /* for each column of \
the child table */ + sql_exp *e = n->data;
+ int i = 0;
+ bool first_attempt = true;
+ atom *cmin = NULL, *cmax = NULL, *rmin = NULL, *rmax = NULL;
+ list *inlist = NULL;
+ const char *cname = e->r;
+ sql_column *mt_col = NULL, *col = NULL;
+
+ if (cname[0] == '%') /* Ignore TID and indexes here */
+ continue;
+
+ mt_col = ol_find_name(mt->columns, exp_name(e))->data;
+ col = ol_fetch(pt->columns, mt_col->colnr);
+ assert(e && e->type == e_column && col);
+ if (!allowed && !column_privs(v->sql, col, PRIV_SELECT))
+ return sql_error(v->sql, 02, SQLSTATE(42000) "The user %s SELECT permissions on \
table '%s.%s' don't match %s '%s.%s'", get_string_global_var(v->sql, "current_user"), \
+ pt->s->base.name, pt->base.name, TABLE_TYPE_DESCRIPTION(mt->type, \
mt->properties), mt->s->base.name, mt->base.name); + if (isTable(pt) && info && \
!list_empty(info->cols) && ATOMlinear(exp_subtype(e)->type->localtype)) { + for \
(node *nn = info->cols->h ; nn && !skip; nn = nn->next) { /* test if it passes all \
predicates around it */ + if (nn->data == e) {
+ range_limit *next = list_fetch(info->ranges, i);
+ atom *lval = next->lval, *hval = next->hval;
+ list *values = next->values;
+
+ /* I don't handle cmp_in or cmp_notin cases with anti or null semantics yet */
+ if (next->flag == cmp_in && (next->anti || next->semantics))
+ continue;
+
+ assert(col && (lval || values));
+ if (!skip && pt->access == TABLE_READONLY) {
+ /* check if the part falls within the bounds of the select expression else \
skip this (keep at least on part-table) */ + if (!cmin && !cmax && \
first_attempt) { + char *min = NULL, *max = NULL;
+ (void) sql_trans_ranges(v->sql->session->tr, col, &min, &max);
+ if (min && max) {
+ cmin = atom_general(v->sql->sa, &col->type, min);
+ cmax = atom_general(v->sql->sa, &col->type, max);
+ }
+ first_attempt = false; /* no more attempts to read from storage */
+ }
+
+ if (cmin && cmax) {
+ if (lval) {
+ if (!next->semantics && ((lval && lval->isnull) || (hval && hval->isnull))) \
{ + skip = 1; /* NULL values don't match, skip them */
+ } else if (!next->semantics) {
+ if (next->flag == cmp_equal) {
+ skip |= next->anti ? exp_range_overlap(cmin, cmax, lval, hval, false, \
false) != 0 : + exp_range_overlap(cmin, cmax, lval, hval, false, \
false) == 0; + } else if (hval != lval) { /* range case */
+ comp_type lower = range2lcompare(next->flag), higher = \
range2rcompare(next->flag); + skip |= next->anti ? exp_range_overlap(cmin, \
cmax, lval, hval, higher == cmp_lt, lower == cmp_gt) != 0 : \
+ exp_range_overlap(cmin, cmax, lval, hval, higher == cmp_lt, lower \
== cmp_gt) == 0; + } else {
+ switch (next->flag) {
+ case cmp_gt:
+ skip |= next->anti ? VALcmp(&(lval->data), &(cmax->data)) < 0 : \
VALcmp(&(lval->data), &(cmax->data)) >= 0; + break;
+ case cmp_gte:
+ skip |= next->anti ? VALcmp(&(lval->data), &(cmax->data)) <= 0 : \
VALcmp(&(lval->data), &(cmax->data)) > 0; + break;
+ case cmp_lt:
+ skip |= next->anti ? VALcmp(&(lval->data), &(cmax->data)) < 0 : \
VALcmp(&(cmin->data), &(lval->data)) >= 0; + break;
+ case cmp_lte:
+ skip |= next->anti ? VALcmp(&(lval->data), &(cmax->data)) <= 0 : \
VALcmp(&(cmin->data), &(lval->data)) > 0; + break;
+ default:
+ break;
+ }
+ }
+ }
+ } else if (next->flag == cmp_in) {
+ int nskip = 1;
+ for (node *m = values->h; m && nskip; m = m->next) {
+ atom *a = m->data;
+
+ if (a->isnull)
+ continue;
+ nskip &= exp_range_overlap(cmin, cmax, a, a, false, false) == 0;
+ }
+ skip |= nskip;
+ }
+ }
+ }
+ if (!skip && isPartitionedByColumnTable(mt) && \
strcmp(mt->part.pcol->base.name, col->base.name) == 0) { + if (!next->semantics \
&& ((lval && lval->isnull) || (hval && hval->isnull))) { + skip = 1; /* NULL \
values don't match, skip them */ + } else if (next->semantics) {
+ /* TODO NOT NULL prunning for partitions that just hold NULL values is still \
missing */ + skip |= next->flag == cmp_equal && !next->anti && lval && \
lval->isnull ? pd->with_nills == 0 : 0; /* *= NULL case */ + } else {
+ if (isRangePartitionTable(mt)) {
+ if (!rmin || !rmax) { /* initialize lazily */
+ rmin = atom_general_ptr(v->sql->sa, &col->type, pd->part.range.minvalue);
+ rmax = atom_general_ptr(v->sql->sa, &col->type, pd->part.range.maxvalue);
+ }
+
+ /* Prune range partitioned tables */
+ if (rmin->isnull && rmax->isnull) {
+ if (pd->with_nills == 1) /* the partition just holds null values, skip it \
*/ + skip = 1;
+ /* otherwise it holds all values in the range, cannot be pruned */
+ } else if (rmin->isnull) { /* MINVALUE to limit */
+ if (lval) {
+ if (hval != lval) { /* range case */
+ /* There's need to call range2lcompare, because the partition's upper \
limit is always exclusive */ + skip |= next->anti ? VALcmp(&(lval->data), \
&(rmax->data)) < 0 : VALcmp(&(lval->data), &(rmax->data)) >= 0; + } else {
+ switch (next->flag) { /* upper limit always exclusive */
+ case cmp_equal:
+ case cmp_gt:
+ case cmp_gte:
+ skip |= next->anti ? VALcmp(&(lval->data), &(rmax->data)) < 0 : \
VALcmp(&(lval->data), &(rmax->data)) >= 0; + break;
+ default:
+ break;
+ }
+ }
+ } else if (next->flag == cmp_in) {
+ int nskip = 1;
+ for (node *m = values->h; m && nskip; m = m->next) {
+ atom *a = m->data;
+
+ if (a->isnull)
+ continue;
+ nskip &= VALcmp(&(a->data), &(rmax->data)) >= 0;
+ }
+ skip |= nskip;
+ }
+ } else if (rmax->isnull) { /* limit to MAXVALUE */
+ if (lval) {
+ if (hval != lval) { /* range case */
+ comp_type higher = range2rcompare(next->flag);
+ if (higher == cmp_lt) {
+ skip |= next->anti ? VALcmp(&(rmin->data), &(hval->data)) < 0 : \
VALcmp(&(rmin->data), &(hval->data)) >= 0; + } else if (higher == cmp_lte) \
{ + skip |= next->anti ? VALcmp(&(rmin->data), &(hval->data)) <= 0 : \
VALcmp(&(rmin->data), &(hval->data)) > 0; + } else {
+ assert(0);
+ }
+ } else {
+ switch (next->flag) {
+ case cmp_lt:
+ skip |= next->anti ? VALcmp(&(rmin->data), &(hval->data)) < 0 : \
VALcmp(&(rmin->data), &(hval->data)) >= 0; + break;
+ case cmp_equal:
+ case cmp_lte:
+ skip |= next->anti ? VALcmp(&(rmin->data), &(hval->data)) <= 0 : \
VALcmp(&(rmin->data), &(hval->data)) > 0; + break;
+ default:
+ break;
+ }
+ }
+ } else if (next->flag == cmp_in) {
+ int nskip = 1;
+ for (node *m = values->h; m && nskip; m = m->next) {
+ atom *a = m->data;
+
+ if (a->isnull)
+ continue;
+ nskip &= VALcmp(&(rmin->data), &(a->data)) > 0;
+ }
+ skip |= nskip;
+ }
+ } else { /* limit1 to limit2 (general case), limit2 is exclusive */
+ bool max_differ_min = ATOMcmp(col->type.type->localtype, &rmin->data.val, \
&rmax->data.val) != 0; +
+ if (lval) {
+ if (next->flag == cmp_equal) {
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic