Changeset: 5df7adacf00d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=5df7adacf00d
Modified Files:
        sql/server/rel_select.c
        sql/server/rel_unnest.c
        sql/server/rel_unnest.h
        sql/test/Tests/hot-snapshot.py
        sql/test/subquery/Tests/subquery3.stable.err
        sql/test/subquery/Tests/subquery5.stable.err
Branch: mbedded
Log Message:

merged with default


diffs (truncated from 329 to 300 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
@@ -1191,7 +1191,7 @@ rel_column_ref(sql_query *query, sql_rel
                                if (exp)
                                        break;
                        }
-                       if (exp && outer && outer->card <= CARD_AGGR && 
exp->card > CARD_AGGR && (!is_sql_aggr(f) || is_sql_farg(f)))
+                       if (exp && outer && outer->card <= CARD_AGGR && 
exp->card > CARD_AGGR && !is_sql_aggr(f))
                                return sql_error(sql, ERR_GROUPBY, 
SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s' in query results 
without an aggregate function", name);
                        if (exp && outer && !is_sql_aggr(f)) {
                                if (query_outer_used_exp( query, i, exp, f)) {
@@ -1257,7 +1257,7 @@ rel_column_ref(sql_query *query, sql_rel
                                if (exp)
                                        break;
                        }
-                       if (exp && outer && outer->card <= CARD_AGGR && 
exp->card > CARD_AGGR && (!is_sql_aggr(f) || is_sql_farg(f)))
+                       if (exp && outer && outer->card <= CARD_AGGR && 
exp->card > CARD_AGGR && !is_sql_aggr(f))
                                return sql_error(sql, ERR_GROUPBY, 
SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s.%s' in query 
results without an aggregate function", tname, cname);
                        if (exp && outer && !is_sql_aggr(f)) {
                                if (query_outer_used_exp( query, i, exp, f)) {
@@ -3349,14 +3349,16 @@ static sql_exp *
 
        exps = sa_list(sql->sa);
        if (args && args->data.sym) {
-               int ungrouped_col = -1, i, all_aggr = query_has_outer(query);
+               int i, all_aggr = query_has_outer(query);
+               bool found_nested_aggr = false;
+               list *ungrouped_cols = NULL;
+
                all_freevar = 1;
-               bool found_nested_aggr = false;
                for (i = 0; args && args->data.sym; args = args->next, i++) {
                        int base = (!groupby || !is_project(groupby->op) || 
is_base(groupby->op) || is_processed(groupby));
-                       bool found_one = false;
-                       sql_rel *outer = NULL, *gl = base?groupby:groupby->l, 
*ogl = gl; /* handle case of subqueries without correlation */
-                       sql_exp *e = rel_value_exp(query, &gl, args->data.sym, 
(f | sql_aggr)& ~sql_farg, ek), *a = NULL;
+                       sql_rel *gl = base?groupby:groupby->l, *ogl = gl; /* 
handle case of subqueries without correlation */
+                       sql_exp *e = rel_value_exp(query, &gl, args->data.sym, 
(f | sql_aggr)& ~sql_farg, ek);
+                       bool found_one_freevar = false;
 
                        has_args = true;
                        if (gl && gl != ogl) {
@@ -3384,38 +3386,15 @@ static sql_exp *
                                return e;
                        }
 
-                       if (is_freevar(e) && e->type == e_column) {
-                               if ((outer = query_fetch_outer(query, 
is_freevar(e)-1))) {
-                                       if ((a = rel_find_exp(outer, e)) && 
is_aggr(a->type))
-                                               return sql_error(sql, 05, 
SQLSTATE(42000) "SELECT: aggregate function calls cannot be nested");
-                               }
-                       }
-
-                       if (all_aggr) {
-                               /* get expression from outer */
-                               int aggr = 0;
-                               if (a)
-                                       aggr = is_aggr(a->type);
-                               else if (outer && outer->grouped)
-                                       ungrouped_col = i;
-                               all_aggr &= aggr;
-                       } else {
-                               all_aggr &= (exp_card(e) <= CARD_AGGR && 
!exp_is_atom(e) && is_aggr(e->type) && !is_func(e->type) && (!groupby || 
!is_groupby(groupby->op) || !groupby->r || !exps_find_exp(groupby->r, e)));
-                       }
-                       all_freevar &= (exp_only_freevar(query, e, &found_one, 
&found_nested_aggr) && found_one);
+                       all_aggr &= (exp_card(e) <= CARD_AGGR && 
!exp_is_atom(e) && is_aggr(e->type) && !is_func(e->type) && (!groupby || 
!is_groupby(groupby->op) || !groupby->r || !exps_find_exp(groupby->r, e)));
+                       exp_only_freevar(query, e, &all_freevar, 
&found_one_freevar, &found_nested_aggr, &ungrouped_cols);
+                       all_freevar &= found_one_freevar; /* no uncorrelated 
variables must be found, plus at least one correlated variable to push this 
aggregate to an outer query */
                        list_append(exps, e);
                }
-               if (all_freevar && (all_aggr || found_nested_aggr))
+               if (all_aggr || (all_freevar && found_nested_aggr))
                        return sql_error(sql, 05, SQLSTATE(42000) "SELECT: 
aggregate function calls cannot be nested");
                if (!all_freevar) {
-                       if (all_aggr) {
-                               char *uaname = GDKmalloc(strlen(aname) + 1);
-                               sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) 
"%s: aggregate functions cannot be nested",
-                                               uaname ? toUpperCopy(uaname, 
aname) : aname);
-                               if (uaname)
-                                       GDKfree(uaname);
-                               return e;
-                       } else if (is_sql_groupby(f)) {
+                       if (is_sql_groupby(f)) {
                                char *uaname = GDKmalloc(strlen(aname) + 1);
                                sql_exp *e = sql_error(sql, 02, SQLSTATE(42000) 
"%s: aggregate function '%s' not allowed in GROUP BY clause",
                                                                uaname ? 
toUpperCopy(uaname, aname) : aname, aname);
@@ -3450,9 +3429,26 @@ static sql_exp *
                                if (uaname)
                                        GDKfree(uaname);
                                return e;
-                       } else if (!all_aggr && ungrouped_col >= 0) {
-                               sql_exp *u = list_fetch(exps, ungrouped_col);
-                               return sql_error(sql, ERR_GROUPBY, 
SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" from outer 
query", exp_relname(u), exp_name(u));
+                       } else if (!all_aggr && ungrouped_cols && 
!list_empty(ungrouped_cols)) {
+                               for (node *n = ungrouped_cols->h ; n ; n = 
n->next) {
+                                       sql_rel *outer;
+                                       sql_exp *e = (sql_exp*) n->data;
+
+                                       if ((outer = query_fetch_outer(query, 
is_freevar(e)-1)) && outer->grouped) {
+                                               bool err = false, was_processed 
= false;
+
+                                               if (is_processed(outer)) {
+                                                       was_processed = true;
+                                                       reset_processed(outer);
+                                               }
+                                               if (!is_groupby_col(outer, e))
+                                                       err = true;
+                                               if (was_processed)
+                                                       set_processed(outer);
+                                               if (err)
+                                                       return sql_error(sql, 
ERR_GROUPBY, SQLSTATE(42000) "SELECT: subquery uses ungrouped column \"%s.%s\" 
from outer query", exp_relname(e), exp_name(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
@@ -171,97 +171,109 @@ rel_has_freevar(mvc *sql, sql_rel *rel)
        return 0;
 }
 
-static int exps_only_freevar(sql_query *query, list *exps, bool *found_one, 
bool *found_aggr);
-static int rel_only_freevar(sql_query *query, sql_rel *rel, bool *found_one, 
bool *found_aggr);
+static void exps_only_freevar(sql_query *query, list *exps, unsigned int 
*all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols);
+static void rel_only_freevar(sql_query *query, sql_rel *rel, unsigned int 
*all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols);
 
-int /* look for expressions with either only freevars or atoms */
-exp_only_freevar(sql_query *query, sql_exp *e, bool *found_one, bool 
*found_aggr)
+void /* look for expressions with either only freevars or atoms */
+exp_only_freevar(sql_query *query, sql_exp *e, unsigned int *all_freevar, bool 
*found_one_freevar, bool *found_aggr, list **ungrouped_cols)
 {
        if (THRhighwater()) {
                (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too 
complex: running out of stack space");
-               return 0;
+               return ;
        }
 
        if (is_freevar(e)) {
                sql_rel *outer;
-               sql_exp *a;
 
-               *found_one = true;
+               *found_one_freevar = true;
                if (e->type == e_column) {
                        if ((outer = query_fetch_outer(query, 
is_freevar(e)-1))) {
-                               if ((a = rel_find_exp(outer, e)) && 
is_aggr(a->type))
+                               sql_exp *a = rel_find_exp(outer, e);
+                               if (a && is_aggr(a->type))
                                        *found_aggr = true;
+                               else {
+                                       if (!*ungrouped_cols)
+                                               *ungrouped_cols = 
new_exp_list(query->sql->sa);
+                                       list_append(*ungrouped_cols, e);
+                               }
                        }
                }
-               return 1;
+               return ;
        }
        switch(e->type) {
        case e_cmp:
                if (e->flag == cmp_or || e->flag == cmp_filter) {
-                       return (exps_only_freevar(query, e->l, found_one, 
found_aggr) && exps_only_freevar(query, e->r, found_one, found_aggr));
+                       exps_only_freevar(query, e->l, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+                       exps_only_freevar(query, e->r, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
                } else if (e->flag == cmp_in || e->flag == cmp_notin) {
-                       return (exp_only_freevar(query, e->l, found_one, 
found_aggr) && exps_only_freevar(query, e->r, found_one, found_aggr));
+                       exp_only_freevar(query, e->l, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+                       exps_only_freevar(query, e->r, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
                } else {
-                       return (exp_only_freevar(query, e->l, found_one, 
found_aggr) && exp_only_freevar(query, e->r, found_one, found_aggr) && 
-                                       (!e->f || (e->f && 
exp_only_freevar(query, e->f, found_one, found_aggr))));
+                       exp_only_freevar(query, e->l, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+                       exp_only_freevar(query, e->r, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+                       if (e->f)
+                               exp_only_freevar(query, e->f, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
                }
+               break;
        case e_convert:
-               return exp_only_freevar(query, e->l, found_one, found_aggr);
+               exp_only_freevar(query, e->l, all_freevar, found_one_freevar, 
found_aggr, ungrouped_cols);
+               break;
        case e_func:
        case e_aggr:
                if (e->l)
-                       return exps_only_freevar(query, e->l, found_one, 
found_aggr);
-               return 1;
+                       exps_only_freevar(query, e->l, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+               break;
        case e_psm:
                if (exp_is_rel(e))
-                       return rel_only_freevar(query, e->l, found_one, 
found_aggr);
-               return 1;
+                       rel_only_freevar(query, e->l, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+               break;
        case e_atom:
-               return 1;
+               break;
        case e_column:
-               return 0;
+               *all_freevar = 0;
+               break;
        }
-       return 0;
 }
 
-int
-exps_only_freevar(sql_query *query, list *exps, bool *found_one, bool 
*found_aggr)
-{
-       int all_freevar = 1;
-
-       if (THRhighwater()) {
-               (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too 
complex: running out of stack space");
-               return 0;
-       }
-       if (!exps)
-               return 0;
-       for (node *n = exps->h; n && all_freevar; n = n->next) {
-               sql_exp *e = n->data;
-               all_freevar &= exp_only_freevar(query, e, found_one, 
found_aggr);
-       }
-       return all_freevar;
-}
-
-int
-rel_only_freevar(sql_query *query, sql_rel *rel, bool *found_one, bool 
*found_aggr)
+void
+exps_only_freevar(sql_query *query, list *exps, unsigned int *all_freevar, 
bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols)
 {
        if (THRhighwater()) {
                (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too 
complex: running out of stack space");
-               return 0;
+               return ;
+       }
+       if (!exps)
+               return ;
+       for (node *n = exps->h; n ; n = n->next)
+               exp_only_freevar(query, n->data, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+}
+
+void
+rel_only_freevar(sql_query *query, sql_rel *rel, unsigned int *all_freevar, 
bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols)
+{
+       if (THRhighwater()) {
+               (void) sql_error(query->sql, 10, SQLSTATE(42000) "Query too 
complex: running out of stack space");
+               return ;
        }
 
        if (is_basetable(rel->op)) {
-               return 0;
+               return ;
        } else if (is_base(rel->op)) {
-               return exps_only_freevar(query, rel->exps, found_one, 
found_aggr) && (!rel->r || (rel->r && rel_only_freevar(query, rel->r, 
found_one, found_aggr)));
+               exps_only_freevar(query, rel->exps, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+               if (rel->r)
+                       rel_only_freevar(query, rel->r, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
        } else if (is_simple_project(rel->op) || is_groupby(rel->op) || 
is_select(rel->op) || is_topn(rel->op) || is_sample(rel->op)) {
-               if ((is_simple_project(rel->op) || is_groupby(rel->op)) && 
(rel->r && !exps_only_freevar(query, rel->r, found_one, found_aggr)))
-                       return 0;
-               return exps_only_freevar(query, rel->exps, found_one, 
found_aggr) && (!rel->l || (rel->l && rel_only_freevar(query, rel->l, 
found_one, found_aggr)));
+               if ((is_simple_project(rel->op) || is_groupby(rel->op)) && 
rel->r)
+                       exps_only_freevar(query, rel->r, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+               exps_only_freevar(query, rel->exps, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+               if (rel->l)
+                       rel_only_freevar(query, rel->l, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
        } else if (is_join(rel->op) || is_set(rel->op) || is_semi(rel->op) || 
is_modify(rel->op)) {
-               return exps_only_freevar(query, rel->exps, found_one, 
found_aggr) && rel_only_freevar(query, rel->l, found_one, found_aggr) && 
rel_only_freevar(query, rel->r, found_one, found_aggr);
+               exps_only_freevar(query, rel->exps, all_freevar, 
found_one_freevar, found_aggr, ungrouped_cols);
+               rel_only_freevar(query, rel->l, all_freevar, found_one_freevar, 
found_aggr, ungrouped_cols);
+               rel_only_freevar(query, rel->r, all_freevar, found_one_freevar, 
found_aggr, ungrouped_cols);
        }
-       return 0;
+       return ;
 }
 
 static int 
diff --git a/sql/server/rel_unnest.h b/sql/server/rel_unnest.h
--- a/sql/server/rel_unnest.h
+++ b/sql/server/rel_unnest.h
@@ -17,7 +17,7 @@ extern int exp_has_freevar(mvc *sql, sql
 extern int exps_have_freevar(mvc *sql, list *exps);
 extern int rel_has_freevar(mvc *sql, sql_rel *r);
 
-extern int exp_only_freevar(sql_query *query, sql_exp *e, bool *found_one, 
bool *found_aggr);
+extern void exp_only_freevar(sql_query *query, sql_exp *e, unsigned int 
*all_freevar, bool *found_one_freevar, bool *found_aggr, list **ungrouped_cols);
 
 extern sql_rel *rel_unnest(mvc *sql, sql_rel *rel);
 extern void exps_set_freevar(mvc *sql, list *exps, sql_rel *r);
diff --git a/sql/test/Tests/hot-snapshot.py b/sql/test/Tests/hot-snapshot.py
--- a/sql/test/Tests/hot-snapshot.py
+++ b/sql/test/Tests/hot-snapshot.py
@@ -108,6 +108,10 @@ def main():
             # uncommitted1 and uncommitted2 should not be present
             assert foo == [('committed1',)]
 
+            cur3.close()
+            conn3.close()
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to