Changeset: 3af76395e12f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=3af76395e12f Added Files: sql/test/SQLancer/Tests/sqlancer02.sql sql/test/SQLancer/Tests/sqlancer02.stable.err sql/test/SQLancer/Tests/sqlancer02.stable.out Modified Files: monetdb5/optimizer/opt_emptybind.c sql/backends/monet5/rel_bin.c sql/server/rel_optimizer.c sql/server/rel_rel.c sql/server/rel_select.c sql/storage/bat/bat_storage.c sql/storage/bat/bat_storage.h sql/test/SQLancer/Tests/All sql/test/SQLancer/Tests/sqlancer01.stable.out sql/test/subquery/Tests/subquery6.sql Branch: unlock Log Message:
merged 43197e85a61b diffs (truncated from 1345 to 300 lines): diff --git a/monetdb5/optimizer/opt_emptybind.c b/monetdb5/optimizer/opt_emptybind.c --- a/monetdb5/optimizer/opt_emptybind.c +++ b/monetdb5/optimizer/opt_emptybind.c @@ -55,11 +55,11 @@ OPTemptybindImplementation(Client cntxt, //if ( optimizerIsApplied(mb,"emptybind") ) //return 0; // use an instruction reference table to keep - + for( i=0; i< mb->stop; i++) if( getFunctionId(getInstrPtr(mb,i)) == emptybindRef || getFunctionId(getInstrPtr(mb,i)) == emptybindidxRef) extras += getInstrPtr(mb,i)->argc; - if( extras == 0) + if (extras == 0) goto wrapup; // track of where 'emptybind' results are produced @@ -74,7 +74,7 @@ OPTemptybindImplementation(Client cntxt, return 0; } - if ( newMalBlkStmt(mb, mb->ssize) < 0) { + if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(empty); GDKfree(updated); throw(MAL,"optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL); @@ -95,12 +95,12 @@ OPTemptybindImplementation(Client cntxt, /* * The bulk of the intelligence lies in inspecting calling - * sequences to filter and replace results + * sequences to filter and replace results */ if ( getModuleId(p) == batRef && getFunctionId(p) == newRef){ empty[getArg(p,0)] = i; continue; - } + } // any of these instructions leave a non-empty BAT behind if(p && getModuleId(p) == sqlRef && isUpdateInstruction(p)){ @@ -116,7 +116,7 @@ OPTemptybindImplementation(Client cntxt, updated[etop++]= p; } - /* restore the naming, dropping the runtime property 'empty' + /* restore the naming, dropping the runtime property 'empty' * Keep the bind operation, because it is cheap, rather focus on their re-use */ @@ -127,7 +127,7 @@ OPTemptybindImplementation(Client cntxt, if( p->retc == 2){ empty[getArg(p,1)] = i; } - // replace the call into a empty bat creation unless the table was updated already in the same query + // replace the call into a empty bat creation unless the table was updated already in the same query sch = getVarConstant(mb,getArg(p,2 + (p->retc==2))).val.sval; tbl = getVarConstant(mb,getArg(p,3 + (p->retc==2))).val.sval; for(j= 0; j< etop; j++){ @@ -159,7 +159,7 @@ OPTemptybindImplementation(Client cntxt, setFunctionId(p,bindidxRef); p->typechk= TYPE_UNKNOWN; empty[getArg(p,0)] = i; - // replace the call into a empty bat creation unless the table was updated already in the same query + // replace the call into a empty bat creation unless the table was updated already in the same query sch = getVarConstant(mb,getArg(p,2 + (p->retc==2))).val.sval; tbl = getVarConstant(mb,getArg(p,3 + (p->retc==2))).val.sval; for(j= 0; j< etop; j++){ @@ -198,7 +198,7 @@ OPTemptybindImplementation(Client cntxt, } if (getModuleId(p)== sqlRef && getFunctionId(p) == projectdeltaRef) { - if (empty[getArg(p,3)] && empty[getArg(p,4)]){ + if( empty[getArg(p,3)] && empty[getArg(p,4)] ){ actions++; setModuleId(p,algebraRef); setFunctionId(p,projectionRef); @@ -230,17 +230,16 @@ OPTemptybindImplementation(Client cntxt, if (getModuleId(p)== batRef && isUpdateInstruction(p)){ if( empty[getArg(p,1)] && empty[getArg(p,2)]){ emptyresult(0); - } else - if( empty[getArg(p,2)]){ + } else if (empty[getArg(p,2)]){ actions++; - clrFunction(p); + clrFunction(p); p->argc = 2; } } } for(; i<slimit; i++) - if( old[i]) + if (old[i]) freeInstruction(old[i]); GDKfree(old); GDKfree(empty); 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 @@ -2181,6 +2181,89 @@ releqjoin( backend *be, list *l1, list * return res; } +static void +split_join_exps(sql_rel *rel, list *joinable, list *not_joinable) +{ + if (!list_empty(rel->exps)) { + for (node *n = rel->exps->h; n; n = n->next) { + sql_exp *e = n->data; + int left_reference = 0, right_reference = 0; + + /* we can handle thetajoins, rangejoins and filter joins (like) */ + /* ToDo how about mark_exists/not_exists and atom expressions? */ + if (e->type == e_cmp) { + int flag = e->flag & ~CMP_BETWEEN; + /* check if its a select or join expression, ie use only expressions of one relation left and of the other right (than join) */ + if (flag < cmp_filter || flag == mark_in || flag == mark_notin) { /* theta and range joins */ + /* join or select ? */ + sql_exp *l = e->l, *r = e->r, *f = e->f; + + if (l->card != CARD_ATOM) { + left_reference += rel_find_exp(rel->l, l) != NULL; + right_reference += rel_find_exp(rel->r, l) != NULL; + } + if (r->card != CARD_ATOM) { + left_reference += rel_find_exp(rel->l, r) != NULL; + right_reference += rel_find_exp(rel->r, r) != NULL; + } + if (f && f->card != CARD_ATOM) { + left_reference += rel_find_exp(rel->l, f) != NULL; + right_reference += rel_find_exp(rel->r, f) != NULL; + } + } else if (flag == cmp_filter) { + list *l = e->l, *r = e->r; + + for (node *n = l->h ; n ; n = n->next) { + sql_exp *ee = n->data; + + if (ee->card != CARD_ATOM) { + left_reference += rel_find_exp(rel->l, ee) != NULL; + right_reference += rel_find_exp(rel->r, ee) != NULL; + } + } + for (node *n = r->h ; n ; n = n->next) { + sql_exp *ee = n->data; + + if (ee->card != CARD_ATOM) { + left_reference += rel_find_exp(rel->l, ee) != NULL; + right_reference += rel_find_exp(rel->r, ee) != NULL; + } + } + } + } + if (left_reference && right_reference) { + append(joinable, e); + } else { + append(not_joinable, e); + } + } + } +} + +#define is_priority_exp(e) ((e)->type == e_cmp && (e)->flag == cmp_equal) + +static list * +get_equi_joins_first(mvc *sql, list *exps, int *equality_only) +{ + list *new_exps = sa_list(sql->sa); + + for( node *n = exps->h; n; n = n->next ) { + sql_exp *e = n->data; + if (is_priority_exp(e)) { + list_append(new_exps, e); + *equality_only &= (e->flag == cmp_equal); + } + } + for( node *n = exps->h; n; n = n->next ) { + sql_exp *e = n->data; + if (!is_priority_exp(e)) { + list_append(new_exps, e); + *equality_only &= (e->flag == mark_in || e->flag == mark_notin); + } + } + return new_exps; +} + static stmt * rel2bin_join(backend *be, sql_rel *rel, list *refs) { @@ -2207,129 +2290,75 @@ rel2bin_join(backend *be, sql_rel *rel, * second selects/filters */ if (!list_empty(rel->exps)) { - int used_hash = 0; - int idx = 0, i; list *jexps = sa_list(sql->sa); - list *lje = sa_list(sql->sa); - list *rje = sa_list(sql->sa); - list *exps = sa_list(sql->sa); sexps = sa_list(sql->sa); - /* stage one split join and select expressions (include complex expressions which physical layer cannot handle without a crossproduct first) */ - if (!list_empty(rel->exps)) { - for( en = rel->exps->h, i=0; en; en = en->next, i++) { - sql_exp *e = en->data; - int left_reference = 0, right_reference = 0; - - /* we can handle thetajoins, rangejoins and filter joins (like) */ - /* ToDo how about in/notin, mark_in/notin, mark_exists/not_exists and atom expressions? */ - if (e->type == e_cmp) { - int flag = e->flag & ~CMP_BETWEEN; - /* check if its a select or join expression, ie use only expressions of one relation left and of the other right (than join) */ - if (flag < cmp_filter) { /* theta and range joins */ - /* join or select ? */ - sql_exp *l = e->l, *r = e->r, *f = e->f; - - if (l->card != CARD_ATOM) { - left_reference += rel_find_exp(rel->l, l) != NULL; - right_reference += rel_find_exp(rel->r, l) != NULL; - } - if (r->card != CARD_ATOM) { - left_reference += rel_find_exp(rel->l, r) != NULL; - right_reference += rel_find_exp(rel->r, r) != NULL; - } - if (f && f->card != CARD_ATOM) { - left_reference += rel_find_exp(rel->l, f) != NULL; - right_reference += rel_find_exp(rel->r, f) != NULL; - } - } else if (flag == cmp_filter) { - list *l = e->l, *r = e->r; - - for (node *n = l->h ; n ; n = n->next) { - sql_exp *ee = n->data; - - if (ee->card != CARD_ATOM) { - left_reference += rel_find_exp(rel->l, ee) != NULL; - right_reference += rel_find_exp(rel->r, ee) != NULL; - } - } - for (node *n = r->h ; n ; n = n->next) { - sql_exp *ee = n->data; - - if (ee->card != CARD_ATOM) { - left_reference += rel_find_exp(rel->l, ee) != NULL; - right_reference += rel_find_exp(rel->r, ee) != NULL; - } - } - } - } - if (left_reference && right_reference) { - append(jexps, e); - } else { - append(sexps, e); - } - } - } - + split_join_exps(rel, jexps, sexps); if (list_empty(jexps)) { /* cross product and continue after project */ stmt *l = bin_first_column(be, left); stmt *r = bin_first_column(be, right); join = stmt_join(be, l, r, 0, cmp_all, 0, false); } - if (join) + if (join) { en = rel->exps->h; - else + } else { + list *lje = sa_list(sql->sa), *rje = sa_list(sql->sa), *exps = sa_list(sql->sa); + int used_hash = 0, idx = 0, equality_only = 1; + + (void) equality_only; + jexps = get_equi_joins_first(sql, jexps, &equality_only); /* generate a relational join (releqjoin) which does a multi attribute (equi) join */ - for( en = jexps->h; en; en = en->next ) { - int join_idx = sql->opt_stats[0]; - sql_exp *e = en->data; - stmt *s = NULL; - prop *p; - - /* stop search for equi joins on first non equi */ - if (list_length(lje) && (idx || e->type != e_cmp || e->flag != cmp_equal)) - break; - - /* handle possible index lookups, expressions are in index order! */ - if (!join && - (p=find_prop(e->p, PROP_HASHCOL)) != NULL) { - sql_idx *i = p->value; - - join = s = rel2bin_hash_lookup(be, rel, left, right, i, en); - if (s) { - list_append(lje, s->op1); - list_append(rje, s->op2); - list_append(exps, NULL); - used_hash = 1; + for( en = jexps->h; en; en = en->next ) { + int join_idx = sql->opt_stats[0]; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list