Changeset: b7bddbe022ca for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/b7bddbe022ca
Modified Files:
        clients/Tests/MAL-signatures-hge.test
        clients/Tests/MAL-signatures.test
        monetdb5/modules/mal/pp_algebra.c
        sql/backends/monet5/bin_partition_by_slice.c
        sql/backends/monet5/rel_bin.c
        sql/backends/monet5/rel_physical.c
        sql/include/sql_relation.h
        sql/server/rel_optimize_sel.c
        sql/server/rel_optimizer_private.h
        sql/server/rel_prop.c
        sql/server/rel_statistics.c
        sql/server/rel_statistics_functions.c
        sql/server/rel_unnest.c
        sql/test/BugTracker-2026/Tests/7975-cleanup-join-exps.test
Branch: pp_hashjoin
Log Message:

(for now only) in case of count(distinct) skip nils
detect duplicate sub-trees (for now only duplicate hash builds) and
rewrite them into a single case.
some cleanup


diffs (truncated from 897 to 300 lines):

diff --git a/clients/Tests/MAL-signatures-hge.test 
b/clients/Tests/MAL-signatures-hge.test
--- a/clients/Tests/MAL-signatures-hge.test
+++ b/clients/Tests/MAL-signatures-hge.test
@@ -48390,13 +48390,23 @@ LALGprojection
 Project.
 ialgebra
 unique
-command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bat[:oid]) 
(X_3:bat[:oid], X_4:bat[:any_1])
+command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bat[:oid], 
X_3:bit) (X_4:bat[:oid], X_5:bat[:any_1])
 LALGgroup_unique
 Unique rows per group.
 ialgebra
 unique
+command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bat[:oid]) 
(X_3:bat[:oid], X_4:bat[:any_1])
+LALGgroup_unique_keepnil
+Unique rows per group.
+ialgebra
+unique
+command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bit) 
(X_3:bat[:oid], X_4:bat[:any_1])
+LALGunique
+Unique rows.
+ialgebra
+unique
 command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid]) (X_2:bat[:oid], 
X_3:bat[:any_1])
-LALGunique
+LALGunique_keepnil
 Unique rows.
 igroup
 group
diff --git a/clients/Tests/MAL-signatures.test 
b/clients/Tests/MAL-signatures.test
--- a/clients/Tests/MAL-signatures.test
+++ b/clients/Tests/MAL-signatures.test
@@ -36595,13 +36595,23 @@ LALGprojection
 Project.
 ialgebra
 unique
-command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bat[:oid]) 
(X_3:bat[:oid], X_4:bat[:any_1])
+command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bat[:oid], 
X_3:bit) (X_4:bat[:oid], X_5:bat[:any_1])
 LALGgroup_unique
 Unique rows per group.
 ialgebra
 unique
+command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bat[:oid]) 
(X_3:bat[:oid], X_4:bat[:any_1])
+LALGgroup_unique_keepnil
+Unique rows per group.
+ialgebra
+unique
+command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid], X_2:bit) 
(X_3:bat[:oid], X_4:bat[:any_1])
+LALGunique
+Unique rows.
+ialgebra
+unique
 command ialgebra.unique(X_0:bat[:any_1], X_1:bat[:oid]) (X_2:bat[:oid], 
X_3:bat[:any_1])
-LALGunique
+LALGunique_keepnil
 Unique rows.
 igroup
 group
diff --git a/monetdb5/modules/mal/pp_algebra.c 
b/monetdb5/modules/mal/pp_algebra.c
--- a/monetdb5/modules/mal/pp_algebra.c
+++ b/monetdb5/modules/mal/pp_algebra.c
@@ -928,7 +928,7 @@ LOCKEDAGGRnull(Client ctx, bat *result, 
                INIT_ALLOCATOR;                                                 
                                                \
                TIMEOUT_LOOP_IDX_DECL(i, cnt, qry_ctx) {                        
                        \
                        bool new = 0, fnd = 0;                                  
                                        \
-                       if(IS_NIL)                                              
                                                        \
+                       if (skip_nil && IS_NIL)                                 
                                        \
                                continue;                                       
                                                        \
                        for(; !fnd; ) {                                         
                                                \
                                NEW_VAL;                                        
                                                        \
@@ -1039,7 +1039,7 @@ LOCKEDAGGRnull(Client ctx, bat *result, 
                )
 
 static str
-LALGunique(Client ctx, bat *rid, bat *uid, bat *bid, bat *sid)
+LALGunique(Client ctx, bat *rid, bat *uid, bat *bid, bat *sid, bit *Skip_nil)
 {
        /* TODO add skip nil (or not) */
        (void)ctx;
@@ -1049,6 +1049,7 @@ LALGunique(Client ctx, bat *rid, bat *ui
        assert(is_bat_nil(*sid)); /* no cands jet */
        (void)sid;
        bool local_storage = false;
+       bit skip_nil = *Skip_nil;
 
        BAT *u = BATdescriptor(*uid);
        BAT *b = BATdescriptor(*bid);
@@ -1176,6 +1177,13 @@ error:
        return err;
 }
 
+static str
+LALGunique_keepnil(Client ctx, bat *rid, bat *uid, bat *bid, bat *sid)
+{
+       bit f = false;
+       return LALGunique(ctx, rid, uid, bid, sid, &f);
+}
+
 #define gunique_(Type, BaseType, INIT_ALLOCATOR, INIT_ITER, IS_NIL, NEW_VAL, 
HASH_VAL, VAL_NOT_EQUAL, VAL_ASSIGN, ITER_DONE, NEXTK) \
        if (tt == TYPE_##Type) {                                                
                                        \
                int slots = 0;                                                  
                                                \
@@ -1185,7 +1193,7 @@ error:
                INIT_ALLOCATOR;                                                 
                                                \
                TIMEOUT_LOOP_IDX_DECL(i, cnt, qry_ctx) {                        
                        \
                        bool new = 0, fnd = 0;                                  
                                        \
-                       if(IS_NIL)                                              
                                                        \
+                       if (skip_nil && IS_NIL)                                 
                                        \
                                continue;                                       
                                                        \
                        for(; !fnd;) {                                          
                                                \
                                NEW_VAL;                                        
                                                        \
@@ -1299,7 +1307,7 @@ error:
                )
 
 static str
-LALGgroup_unique(Client ctx, bat *rid, bat *uid, bat *bid, bat *sid, bat *Gid)
+LALGgroup_unique(Client ctx, bat *rid, bat *uid, bat *bid, bat *sid, bat *Gid, 
bit *Skip_nil)
 {
        (void)ctx;
        Pipeline *p = pipeline_get_thread_private_pipeline();
@@ -1308,6 +1316,7 @@ LALGgroup_unique(Client ctx, bat *rid, b
        assert(is_bat_nil(*sid)); /* no cands jet */
        (void)sid;
        bool local_storage = false;
+       bit skip_nil = *Skip_nil;
 
        BAT *u = BATdescriptor(*uid);
        BAT *G = BATdescriptor(*Gid);
@@ -1439,6 +1448,13 @@ error:
        return err;
 }
 
+static str
+LALGgroup_unique_keepnil(Client ctx, bat *rid, bat *uid, bat *bid, bat *sid, 
bat *Gid)
+{
+       bit f = false;
+       return LALGgroup_unique(ctx, rid, uid, bid, sid, Gid, &f);
+}
+
 #define group_(Type, BaseType, INIT_ALLOCATOR, INIT_ITER, NEW_VAL, HASH_VAL, 
VAL_NOT_EQUAL, VAL_ASSIGN, ITER_NEXT, NEXTK) \
        int slots = 0;                                                          
                                                \
        gid slot = 0;                                                           
                                                \
@@ -4905,8 +4921,10 @@ static mel_func pp_algebra_init_funcs[] 
        command("ialgebra", "projection", LALGprojection, false, "Project.", 
args(1,3, batargany("",1), batarg("gid", oid), batargany("b",1))),
 
        /* COUNT DISTINCT: globle / grouped */
-       command("ialgebra", "unique", LALGunique, false, "Unique rows.", 
args(2,4, batarg("gid", oid), batargany("",1), batargany("b",1), 
batarg("s",oid))),
-       command("ialgebra", "unique", LALGgroup_unique, false, "Unique rows per 
group.", args(2,5, batarg("ngid", oid), batargany("",1), batargany("b",1), 
batarg("s",oid), batarg("gid",oid))),
+       command("ialgebra", "unique", LALGunique_keepnil, false, "Unique 
rows.", args(2,4, batarg("gid", oid), batargany("",1), batargany("b",1), 
batarg("s",oid))),
+       command("ialgebra", "unique", LALGgroup_unique_keepnil, false, "Unique 
rows per group.", args(2,5, batarg("ngid", oid), batargany("",1), 
batargany("b",1), batarg("s",oid), batarg("gid",oid))),
+       command("ialgebra", "unique", LALGunique, false, "Unique rows.", 
args(2,5, batarg("gid", oid), batargany("",1), batargany("b",1), 
batarg("s",oid), arg("skip_nil",bit))),
+       command("ialgebra", "unique", LALGgroup_unique, false, "Unique rows per 
group.", args(2,6, batarg("ngid", oid), batargany("",1), batargany("b",1), 
batarg("s",oid), batarg("gid",oid), arg("skip_nil",bit))),
 
        /********** Grouped aggregates **********/
        command("ilockedaggr", "min", LALGmin, false, "Min per group.", 
args(1,4, batargany("",1), batarg("gid", oid), batargany("", 1), batarg("pid", 
oid))),
diff --git a/sql/backends/monet5/bin_partition_by_slice.c 
b/sql/backends/monet5/bin_partition_by_slice.c
--- a/sql/backends/monet5/bin_partition_by_slice.c
+++ b/sql/backends/monet5/bin_partition_by_slice.c
@@ -43,11 +43,16 @@ exp_getcard(mvc *sql, sql_rel *rel, sql_
        BUN est = BUN_NONE;
        lng cnt;
        sql_subtype *t = exp_subtype(e);
-       prop *p;
+       prop *p, *min = NULL, *max = NULL;
 
        if ((p = find_prop(e->p, PROP_NUNIQUES)) != NULL)
                est = (BUN)p->value.dval;
-       else
+       else if (t->type->eclass == EC_NUM &&
+                       (min = find_prop(e->p, PROP_MIN)) != NULL &&
+                       (max = find_prop(e->p, PROP_MAX)) != NULL) {
+               atom *uniques = atom_sub(sql->sa, max->value.pval, 
min->value.pval);
+               est = atom_get_int(uniques);
+       } else
                est = get_rel_count(rel);
 
        if (est == BUN_NONE
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
@@ -1918,9 +1918,10 @@ exp_bin(backend *be, sql_exp *e, stmt *l
                                        return NULL;
                                if (be->pipeline && grp)
                                        grp = stmt_project(be, u, grp);
-                               if (be->pipeline && exp_aggr_is_count(e))
+                               if (be->pipeline && exp_aggr_is_count(e)) {
                                        append(l, u);
-                               else
+                                       u->q = pushBit(be->mb, u->q, true); /* 
skip nils */
+                               } else
                                        append(l, stmt_project(be, u, a));
                        }
                        if (r) { /* check new ordered aggregation */
@@ -8368,6 +8369,155 @@ rel_find_refs(mvc *sql, list *refs, sql_
        return refs;
 }
 
+/* todo change into simple nid1 -> nid2 */
+static bool
+exp_pair_match(list *exps, int nid1, int nid2)
+{
+       if (list_empty(exps))
+               return false;
+       for(node *n = exps->h; n; n = n->next->next) {
+               sql_exp *e = n->data;
+               if (e->alias.label == nid1) {
+                       sql_exp *e2 = n->next->data;
+                       if (e2->alias.label == nid2)
+                               return true;
+               }
+       }
+       return false;
+}
+
+static int exps_remap(list *lexps, list *rexps, list *remapped);
+static int
+exp_remap(sql_exp *le, sql_exp *re, list *remapped)
+{
+       list *ll, *rl;
+       if (!le || !re || le->type != re->type)
+               return -1;
+       switch(le->type) {
+       case e_column:
+               if (exp_pair_match(remapped, le->nid, re->nid))
+                       return 0;
+               break;
+       case e_convert:
+               ll = le->r;
+               rl = re->r;
+               return (subtype_cmp(ll->h->data, rl->h->data) == 0 &&
+                           subtype_cmp(ll->h->next->data, rl->h->next->data) 
== 0 &&
+                               exp_remap(le->l , re->l, remapped) == 0)?0:-1;
+       case e_cmp:
+               if (le->flag != re->flag)
+                       return -1;
+               if (le->flag <= cmp_notequal) {
+                       return (exp_remap(le->l, re->l, remapped) == 0 &&
+                               exp_remap(le->r, re->r, remapped) == 0 &&
+                          ((!le->f && !re->f) || exp_remap(le->f, re->f, 
remapped) == 0))?0:-1;
+               } else if (le->flag == cmp_in || le->flag == cmp_notin) {
+                       return (exp_remap(le->l, re->l, remapped) == 0 &&
+                                   exps_remap(le->r, re->r, remapped) == 
0)?0:-1;
+               }
+               return -1;
+       case e_atom:
+               if (le->l && re->l)
+                       return atom_cmp(le->l, re->l);
+               return -1;
+       default:
+               return -1;
+       }
+       (void)remapped;
+       return 0;
+}
+
+static int
+exps_remap(list *lexps, list *rexps, list *remapped)
+{
+       if (list_length(lexps) != list_length(rexps))
+               return -1;
+       if (list_empty(lexps))
+               return 0;
+       for(node *n = lexps->h, *m = rexps->h; n && m; n = n->next, m = 
m->next) {
+               sql_exp *le = n->data, *re = m->data;
+               if (exp_remap(le, re, remapped) != 0)
+                       return -1;
+       }
+       return 0;
+}
+
+static int
+rel_remap(mvc *sql, allocator *ta, sql_rel *l, sql_rel *r, list *remapped)
+{
+       if (!l || !r || l->op != r->op)
+               return -1;
+       switch(l->op) {
+       case op_project:
+       case op_select:
+       case op_buildhash:
+               if (l->op == op_project && (l->r || r->r)) /* don't match 
orderings */
+                       return -1;
+               if (rel_remap(sql, ta, l->l, r->l, remapped) == 0)
+                       return (exps_remap(l->attr, r->attr, remapped) == 0 &&
+                                       exps_remap(l->exps, r->exps, remapped) 
== 0)?0:-1;
+               break;
+       case op_basetable:
+               if (l->l == r->l) {
+                       if (list_length(l->exps) == list_length(r->exps)) {
+                               list *lexps = l->exps, *rexps = r->exps;
+                               for(node *n = lexps->h, *m = rexps->h; n && m; 
n = n->next, m = m->next) {
+                                       sql_exp *le = n->data, *re = m->data;
+                                       assert(le->type == e_column && re->type 
== e_column);
+                                       if (strcmp(le->r, re->r) == 0) {
+                                               append(remapped, le);
+                                               append(remapped, re);
+                                       } else {
+                                               return -1;
+                                       }
+                               }
+                               return 0;
+                       }
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to