[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