Changeset: d26e6d779b5c for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/d26e6d779b5c
Modified Files:
        sql/server/rel_select.c
        sql/server/rel_unnest.c
        sql/test/BugTracker-2026/Tests/7862-rel_has_freevar-crash.test
        sql/test/BugTracker-2026/Tests/All
Branch: Dec2025
Log Message:

fixes for issue #7862
recursive finding of freevars should be limited to not search within the same
relation multiple times
in group by search current relation and outer relations directly, before
using the selection clause.


diffs (200 lines):

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
@@ -4350,10 +4350,9 @@ symbol_get_identifier(symbol *sym)
 static sql_exp*
 rel_group_column(sql_query *query, sql_rel **rel, symbol *grp, dlist 
*selection, list *exps, int f)
 {
-       sql_query *lquery = query_create(query->sql);
        mvc *sql = query->sql;
        exp_kind ek = {type_value, card_value, TRUE};
-       sql_exp *e = rel_value_exp2(lquery, rel, grp, f, ek);
+       sql_exp *e = rel_value_exp2(query, rel, grp, f, ek);
 
        if (e && exp_is_atom(e)) {
                sql_subtype *tpe = exp_subtype(e);
diff --git a/sql/server/rel_unnest.c b/sql/server/rel_unnest.c
--- a/sql/server/rel_unnest.c
+++ b/sql/server/rel_unnest.c
@@ -330,7 +330,7 @@ merge_freevar(list *l, list *r, bool all
 }
 
 static list * exps_freevar(mvc *sql, list *exps, bool all);
-static list * rel_freevar(mvc *sql, sql_rel *rel);
+static list * rel_freevar(mvc *sql, sql_rel *rel, sql_rel *ref);
 
 static list *
 exp_freevar(mvc *sql, sql_exp *e, bool all)
@@ -375,7 +375,7 @@ exp_freevar(mvc *sql, sql_exp *e, bool a
        case e_psm:
                if (exp_is_rel(e))
                        if (rel_has_freevar(sql, e->l))
-                               return rel_freevar(sql, e->l);
+                               return rel_freevar(sql, e->l, NULL);
                return NULL;
        case e_atom:
                if (e->f)
@@ -407,13 +407,13 @@ exps_freevar(mvc *sql, list *exps, bool 
 }
 
 static list *
-rel_freevar(mvc *sql, sql_rel *rel)
+rel_freevar(mvc *sql, sql_rel *rel, sql_rel *ref)
 {
        list *lexps = NULL, *rexps = NULL, *exps = NULL;
 
        if (mvc_highwater(sql))
                return sql_error(sql, 10, SQLSTATE(42000) "Query too complex: 
running out of stack space");
-       if (!rel)
+       if (!rel || rel == ref)
                return NULL;
        if (is_independent(rel->used))
                return NULL;
@@ -423,8 +423,8 @@ rel_freevar(mvc *sql, sql_rel *rel)
        case op_right:
        case op_full:
                exps = exps_freevar(sql, rel->exps, false);
-               lexps = rel_freevar(sql, rel->l);
-               rexps = rel_freevar(sql, rel->r);
+               lexps = rel_freevar(sql, rel->l, ref);
+               rexps = rel_freevar(sql, rel->r, ref);
                lexps = merge_freevar(lexps, rexps, false);
                exps = merge_freevar(exps, lexps, false);
                return exps;
@@ -434,22 +434,22 @@ rel_freevar(mvc *sql, sql_rel *rel)
        case op_table: {
                sql_exp *call = rel->r;
                if (rel->flag != TRIGGER_WRAPPER && rel->l)
-                       lexps = rel_freevar(sql, rel->l);
+                       lexps = rel_freevar(sql, rel->l, ref);
                exps = (rel->flag != TRIGGER_WRAPPER && call)?exps_freevar(sql, 
call->l, false):NULL;
                return merge_freevar(exps, lexps, false);
        }
        case op_except:
        case op_inter:
                exps = exps_freevar(sql, rel->exps, false);
-               lexps = rel_freevar(sql, rel->l);
-               rexps = rel_freevar(sql, rel->r);
+               lexps = rel_freevar(sql, rel->l, ref);
+               rexps = rel_freevar(sql, rel->r, ref);
                lexps = merge_freevar(lexps, rexps, false);
                exps = merge_freevar(exps, lexps, false);
                return exps;
        case op_munion:
                exps = exps_freevar(sql, rel->exps, false);
                for (node *n = ((list*)rel->l)->h; n; n = n->next) {
-                       lexps = rel_freevar(sql, n->data);
+                       lexps = rel_freevar(sql, n->data, ref);
                        exps = merge_freevar(exps, lexps, false);
                }
                return exps;
@@ -464,12 +464,12 @@ rel_freevar(mvc *sql, sql_rel *rel)
        case op_groupby:
        case op_project:
                exps = exps_freevar(sql, rel->exps, false);
-               lexps = rel_freevar(sql, rel->l);
+               lexps = rel_freevar(sql, rel->l, ref);
                if (rel->r) {
                        if (is_groupby(rel->op) || is_simple_project(rel->op))
                                rexps = exps_freevar(sql, rel->r, false);
                        else
-                               rexps = rel_freevar(sql, rel->r);
+                               rexps = rel_freevar(sql, rel->r, ref);
                        lexps = merge_freevar(lexps, rexps, false);
                }
                exps = merge_freevar(exps, lexps, false);
@@ -486,7 +486,7 @@ rel_dependent_var(mvc *sql, sql_rel *l, 
        list *res = NULL;
 
        if (rel_has_freevar(sql, r)){
-               list *freevar = rel_freevar(sql, r);
+               list *freevar = rel_freevar(sql, r, l);
                if (freevar) {
                        node *n;
                        list *boundvar = rel_projections(sql, l, NULL, 1, 0);
@@ -1739,7 +1739,8 @@ push_up_munion(mvc *sql, sql_rel *rel, l
                                set_has_freevar(sl);
                                if (!is_simple_project(sl->op))
                                        sl = rel_inplace_project(sql->sa, sl, 
NULL, rel_projections(sql, sl, NULL, 1, 1));
-                               list *exps = exps_copy(sql, ad);
+                               list *exps = NULL;
+                               exps = rel_projections(sql, d, NULL, 1, 1);
                                for(node *n = exps->h; n; n = n->next) {
                                        sql_exp *e = n->data;
                                        set_freevar(e, 0);
@@ -1889,11 +1890,11 @@ rel_unnest_dependent(mvc *sql, sql_rel *
                l = rel->l;
                r = rel->r;
 
+               /*
                if (rel_has_freevar(sql, l)) {
-                       rel->l = rel_unnest_dependent(sql, rel->l);
+                        rel->l = rel_unnest_dependent(sql, rel->l);
                        if (rel_has_freevar(sql, rel->l)) {
                                if (rel->op == op_left && list_empty(rel->attr) 
&& !rel_has_freevar(sql, rel->r) && rel_dependent_var(sql, rel->r, rel->l)) {
-assert(0);
                                        sql_rel *l = rel->l;
 
                                        rel->l = rel->r;
@@ -1903,6 +1904,7 @@ assert(0);
                                }
                        }
                }
+               */
 
                if (!rel_has_freevar(sql, r)) {
                        if (rel_has_freevar(sql, l) && is_innerjoin(rel->op) && 
!rel->exps) {
@@ -1912,6 +1914,8 @@ assert(0);
                                r = rel->r;
                        } else {
                                reset_dependent(rel);
+                               if (is_join(rel->op))
+                                       rel_bind_vars(sql, rel->l, rel->exps);
                                return rel;
                        }
                }
@@ -2334,7 +2338,7 @@ rewrite_inner(mvc *sql, sql_rel *rel, sq
        assert(d);
        if (rel_has_freevar(sql, inner)) {
                list *dv = rel_dependent_var(sql, d, inner);
-               list *fv = rel_freevar(sql, inner);
+               list *fv = rel_freevar(sql, inner, d);
                /* check if the inner depends on the new join (d) or one level 
up */
                if (list_length(dv))
                        set_dependent(d);
diff --git a/sql/test/BugTracker-2026/Tests/7862-rel_has_freevar-crash.test 
b/sql/test/BugTracker-2026/Tests/7862-rel_has_freevar-crash.test
--- a/sql/test/BugTracker-2026/Tests/7862-rel_has_freevar-crash.test
+++ b/sql/test/BugTracker-2026/Tests/7862-rel_has_freevar-crash.test
@@ -14,8 +14,18 @@ NULL
 0
 
 -- Segmentation fault. in rel_has_freevar (sql=0x7f0a081844e0, rel=0x0) at 
sql/server/rel_unnest.c:170    if (is_basetable(rel->op)) {  -- cause of seg 
fault: rel=0x0
-statement error 42000!Query too complex: running out of stack space
+query II rowsort
 SELECT x , CASE WHEN x > 12 THEN 1 ELSE 0 END AS x
   FROM ( SELECT 10 AS x UNION SELECT 11 AS x GROUP BY CUBE ( x , x ) UNION 
SELECT 12 AS x UNION SELECT 13 AS x )
  WHERE x IN ( WITH RECURSIVE x ( row_number ) AS ( SELECT 1 UNION SELECT x + 1 
FROM x WHERE x < 20 ) SELECT x AS x FROM x WHERE x NOT IN ( 8 , 12 , CAST( 
0.000000 AS FLOAT ) , 24 , 32 ) OR x = 512 GROUP BY x HAVING NOT x < ANY ( CASE 
WHEN NULLIF ( ( WITH RECURSIVE x ( x ) AS ( SELECT 1 UNION SELECT x + 1 FROM ( 
WITH RECURSIVE x ( x ) AS ( SELECT CASE WHEN x < - 13 * - ( 0 ) + 39 * - ( 
SELECT '1' ) + 0.100000 + 0.100000 THEN CAST( '-0' AS DOUBLE ) END UNION SELECT 
ROUND ( 70 , 2 ) FROM x ) SELECT * FROM ( SELECT 'b' AS x FROM x ) WHERE x NOT 
IN ( 'a' ) ) WHERE x < 8 ) SELECT - COUNT ( * ) FROM x AS x WHERE NOT ( - x ) 
BETWEEN - x AND NULL ) , NULL ) IS NULL THEN 1 ELSE 0 END AND 6 IN ( SELECT MAX 
( x ) , x < -1234567 , MAX ( x ) , MIN ( x ) , MAX ( x ) , MIN ( x ) ORDER BY 1 
, 2 LIMIT 0 OFFSET 0 ) ) )
-
+----
+10
+0
+11
+0
+12
+0
+13
+1
+NULL
+0
diff --git a/sql/test/BugTracker-2026/Tests/All 
b/sql/test/BugTracker-2026/Tests/All
--- a/sql/test/BugTracker-2026/Tests/All
+++ b/sql/test/BugTracker-2026/Tests/All
@@ -59,7 +59,7 @@ KNOWNFAIL?7774-insert-into-renamed-table
 7855-ntile
 7856-crash-exp-match
 7857-rollup-crash
-KNOWNFAIL?7862-rel_has_freevar-crash
+7862-rel_has_freevar-crash
 7865-unnest-cte-crash
 7867-push-groupby-down
 7872-exp-type-check-failed
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to