Changeset: 57700c6efacb for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=57700c6efacb
Modified Files:
sql/server/rel_bin.c
sql/server/rel_select.c
Branch: Dec2011
Log Message:
fix bug with semijoins. This partialy fixes bug 2933 and bug 2915.
diffs (179 lines):
diff --git a/sql/server/rel_bin.c b/sql/server/rel_bin.c
--- a/sql/server/rel_bin.c
+++ b/sql/server/rel_bin.c
@@ -1026,7 +1026,7 @@ rel2bin_semijoin( mvc *sql, sql_rel *rel
{
list *l;
node *en, *n;
- stmt *left = NULL, *right = NULL, *join = NULL;
+ stmt *left = NULL, *right = NULL, *join = NULL, *jl, *jr;
if (rel->l) /* first construct the left sub relation */
left = subrel_bin(sql, rel->l, refs);
@@ -1036,38 +1036,65 @@ rel2bin_semijoin( mvc *sql, sql_rel *rel
return NULL;
left = row2cols(sql, left);
right = row2cols(sql, right);
+ /*
+ * split in 2 steps,
+ * first cheap join(s) (equality or idx)
+ * second selects/filters
+ */
if (rel->exps) {
+ int idx = 0;
+ list *jns = list_new(sql->sa);
+
for( en = rel->exps->h; en; en = en->next ) {
- stmt *s = exp_bin(sql, en->data, left, right, NULL,
NULL);
-
+ int join_idx = sql->opt_stats[0];
+ sql_exp *e = en->data;
+ stmt *s = NULL;
+
+ /* only handle simple joins here */
+ if (list_length(jns) && (idx || !e->type == e_cmp ||
e->flag != cmp_equal))
+ break;
+
+ s = exp_bin(sql, en->data, left, right, NULL, NULL);
if (!s) {
assert(0);
return NULL;
}
+ if (join_idx != sql->opt_stats[0])
+ idx = 1;
if (!join) {
join = s;
- } else {
- /* break column join */
- stmt *l = stmt_mark(sql->sa,
stmt_reverse(sql->sa, join), 100);
- stmt *r = stmt_mark(sql->sa, join, 100);
- stmt *ld = s->op1;
- stmt *rd = stmt_reverse(sql->sa, s->op2);
- stmt *le = stmt_join(sql->sa, l, ld, cmp_equal);
- stmt *re = stmt_join(sql->sa, r, rd, cmp_equal);
-
- sql_subfunc *f = sql_bind_func(sql->sa,
sql->session->schema, compare_func((comp_type)s->flag), tail_type(le),
tail_type(le), F_FUNC);
- stmt * cmp;
-
- assert(f);
-
- cmp = stmt_binop(sql->sa, le, re, f);
-
- cmp = stmt_uselect(sql->sa, cmp,
stmt_bool(sql->sa, 1), cmp_equal);
-
- l = stmt_semijoin(sql->sa, l, cmp);
- r = stmt_semijoin(sql->sa, r, cmp);
- join = stmt_join(sql->sa, stmt_reverse(sql->sa,
l), r, cmp_equal);
+ /* stop on first non equality join */
+ } else if (s->type != st_join &&
+ s->type != st_join2 &&
+ s->type != st_joinN) {
+ if (s->type == st_reverse) {
+ stmt *rs = s->op1;
+
+ if (rs->type == st_join ||
+ rs->type == st_join2 ||
+ rs->type == st_joinN) {
+ list_append(jns, s);
+ continue;
+ }
+ }
+ /* handle select expressions */
+ /*assert(0);*/
+ /* should be handled by join list (reljoin) */
+ if (s->h == join->h) {
+ join = stmt_semijoin(sql->sa, join,s);
+ } else {
+ join = stmt_reverse(sql->sa, join);
+ join = stmt_semijoin(sql->sa, join,s);
+ join = stmt_reverse(sql->sa, join);
+ }
+ continue;
}
+ list_append(jns, s);
+ }
+ if (list_length(jns) > 1) {
+ join = stmt_releqjoin(sql->sa, jns);
+ } else {
+ join = jns->h->data;
}
} else {
/* TODO: this case could use some optimization */
@@ -1075,6 +1102,52 @@ rel2bin_semijoin( mvc *sql, sql_rel *rel
stmt *r = bin_first_column(sql->sa, right);
join = stmt_join(sql->sa, l, stmt_reverse(sql->sa, r),
cmp_all);
}
+ jl = stmt_reverse(sql->sa, stmt_mark_tail(sql->sa, join,0));
+ jr = stmt_reverse(sql->sa, stmt_mark_tail(sql->sa,
stmt_reverse(sql->sa, join),0));
+ if (en) {
+ stmt *sub, *sel;
+ list *nl;
+
+ /* construct relation */
+ nl = list_new(sql->sa);
+
+ /* first project using equi-joins */
+ for( n = left->op4.lval->h; n; n = n->next ) {
+ stmt *c = n->data;
+ char *rnme = table_name(sql->sa, c);
+ char *nme = column_name(sql->sa, c);
+ stmt *s = stmt_project(sql->sa, jl, column(sql->sa, c)
);
+
+ s = stmt_alias(sql->sa, s, rnme, nme);
+ list_append(nl, s);
+ }
+ for( n = right->op4.lval->h; n; n = n->next ) {
+ stmt *c = n->data;
+ char *rnme = table_name(sql->sa, c);
+ char *nme = column_name(sql->sa, c);
+ stmt *s = stmt_project(sql->sa, jr, column(sql->sa, c)
);
+
+ s = stmt_alias(sql->sa, s, rnme, nme);
+ list_append(nl, s);
+ }
+ sub = stmt_list(sql->sa, nl);
+
+ /* continue with non equi-joins */
+ sel = stmt_relselect_init(sql->sa);
+ for( ; en; en = en->next ) {
+ stmt *s = exp_bin(sql, en->data, sub, NULL, NULL, NULL);
+
+ if (!s) {
+ assert(0);
+ return NULL;
+ }
+ stmt_relselect_fill(sel, s);
+ }
+ /* recreate join output */
+ sel = stmt_reverse(sql->sa, stmt_mark_tail(sql->sa, sel, 0));
+ jl = stmt_project(sql->sa, sel, jl);
+ jr = stmt_project(sql->sa, sel, jr);
+ }
/* construct relation */
l = list_new(sql->sa);
@@ -1083,10 +1156,10 @@ rel2bin_semijoin( mvc *sql, sql_rel *rel
Reduce this using difference and semijoin */
if (rel->op == op_anti) {
stmt *c = left->op4.lval->h->data;
- join = stmt_diff(sql->sa, c, join);
+ join = stmt_diff(sql->sa, c, stmt_reverse(sql->sa, jl));
} else {
stmt *c = left->op4.lval->h->data;
- join = stmt_semijoin(sql->sa, c, join);
+ join = stmt_semijoin(sql->sa, c, stmt_reverse(sql->sa, jl));
}
join = stmt_reverse(sql->sa, stmt_mark_tail(sql->sa, join,0));
diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c
--- a/sql/server/rel_select.c
+++ b/sql/server/rel_select.c
@@ -4953,7 +4953,7 @@ rel_setquery(mvc *sql, sql_rel *rel, sym
sql_rel *t2 = table_ref(sql, NULL, tab_ref2);
assert(n->next->type == type_int);
- (void)rel; /* TODO correlated unions */
+ (void)rel; /* TODO correlated setqueries */
if (!t1 || !t2)
return NULL;
_______________________________________________
Checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list