Changeset: e1032bcf624e for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/e1032bcf624e
Modified Files:
        sql/server/rel_select.c
        sql/server/rel_updates.c
        sql/server/sql_query.c
        sql/server/sql_query.h
        sql/test/BugTracker-2021/Tests/distinct-union.Bug-7148.test
        sql/test/BugTracker-2021/Tests/sum-union.Bug-7147.test
        sql/test/subquery/Tests/correlated.test
        sql/test/subquery/Tests/subquery3.test
        sql/test/subquery/Tests/subquery5.test
        sql/test/subquery/Tests/subquery6.test
Branch: default
Log Message:

improved query context/stack, handles more errors with incorrect combination of 
grouped/aggregated columns vs non aggregated cols.


diffs (truncated from 508 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
@@ -27,13 +27,6 @@
 #define VALUE_FUNC(f) (f->func->type == F_FUNC || f->func->type == F_FILT)
 #define check_card(card,f) ((card == card_none && !f->res) || 
(CARD_VALUE(card) && f->res && VALUE_FUNC(f)) || card == card_loader || (card 
== card_relation && f->func->type == F_UNION))
 
-static void
-query_processed(sql_query *query )
-{
-       query -> last_exp = NULL;
-       query -> last_state = 0;
-}
-
 /* return all expressions, with table name == tname */
 static list *
 rel_table_projections( mvc *sql, sql_rel *rel, char *tname, int level )
@@ -1138,7 +1131,7 @@ rel_column_ref(sql_query *query, sql_rel
        mvc *sql = query->sql;
        sql_exp *exp = NULL;
        dlist *l = NULL;
-       sql_rel *inner = rel?*rel:NULL;
+       sql_rel *inner = rel?*rel:NULL, *outer = NULL;
        int used_lower_after_processed = 0;
 
        assert((column_r->token == SQL_COLUMN || column_r->token == SQL_IDENT) 
&& column_r->type == type_list);
@@ -1155,7 +1148,6 @@ rel_column_ref(sql_query *query, sql_rel
                                return NULL;
                if (!exp && query && query_has_outer(query)) {
                        int i;
-                       sql_rel *outer;
 
                        for (i=query_has_outer(query)-1; i>= 0 && !exp && 
(outer = query_fetch_outer(query,i)); i--) {
                                if (!(exp = rel_bind_column(sql, outer, name, 
f, 0)) && sql->session->status == -ERR_AMBIGUOUS)
@@ -1175,7 +1167,7 @@ rel_column_ref(sql_query *query, sql_rel
                                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 && 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 (exp && outer && !is_sql_aggr(f) && 
!is_sql_aggr(query_fetch_outer_state(query, i))) {
                                if (used_lower_after_processed || 
query_outer_used_exp( query, i, exp, f)) {
                                        sql_exp *lu = 
used_lower_after_processed?exp:query_outer_last_used(query, i);
                                        if (exp_name(lu) && exp_relname(lu) && 
!has_label(lu))
@@ -1241,7 +1233,6 @@ rel_column_ref(sql_query *query, sql_rel
                                return NULL;
                if (!exp && query && query_has_outer(query)) {
                        int i;
-                       sql_rel *outer;
 
                        for (i=query_has_outer(query)-1; i>= 0 && !exp && 
(outer = query_fetch_outer(query,i)); i--) {
                                if (!(exp = rel_bind_column2(sql, outer, tname, 
cname, f | sql_outer)) && sql->session->status == -ERR_AMBIGUOUS)
@@ -1326,10 +1317,16 @@ rel_column_ref(sql_query *query, sql_rel
        } else if (dlist_length(l) >= 3) {
                return sql_error(sql, 02, SQLSTATE(42000) "TODO: column names 
of level >= 3");
        }
-       if (exp && !exp_is_atom(exp)) {
-               query->last_exp = exp;
-               query->last_state = f;
-       }
+       if (exp && !exp_is_atom(exp) && rel && !outer) {
+               if (query->last_exp && query->last_rel == *rel && 
!is_sql_aggr(query->last_state) && is_sql_aggr(f)) {
+                       if (!is_groupby(query->last_rel->op) || 
list_empty(query->last_rel->r) || !exps_find_exp(query->last_rel->r, 
query->last_exp))
+                               return sql_error(sql, ERR_NOTFOUND, 
SQLSTATE(42000) "SELECT: cannot use non GROUP BY column '%s.%s' in query 
results without an aggregate function", exp_relname(query->last_exp), 
exp_name(query->last_exp));
+               }
+               query->prev = query->last_exp;
+               query->last_exp = exp;
+               query->last_state = f;
+               query->last_rel = *rel;
+       }
        return exp;
 }
 
@@ -1899,8 +1896,10 @@ rel_exists_exp(sql_query *query, sql_rel
 
        if (is_psm_call(f) || is_sql_merge(f))
                return sql_error(sql, 02, SQLSTATE(42000) "%s: subqueries not 
supported inside %s", is_psm_call(f) ? "CALL" : "MERGE", is_psm_call(f) ? "CALL 
statements" : "MERGE conditions");
-       if (rel)
+       if (rel) {
+               query_processed(query);
                query_push_outer(query, rel, f);
+       }
        sq = rel_subquery(query, NULL, sc->data.sym, ek);
        if (rel)
                rel = query_pop_outer(query);
@@ -2772,6 +2771,8 @@ rel_logical_exp(sql_query *query, sql_re
                if (!sq)
                        return NULL;
                assert(ek.type == type_value); /* I don't expect IN tuple 
matching calls to land here */
+               if (is_sql_where(f) && is_groupby(rel->op))
+                       assert(0);
                if (ek.card <= card_set && is_project(sq->op) && 
list_length(sq->exps) > 1)
                        return sql_error(sql, 02, SQLSTATE(42000) "SELECT: 
subquery must return only one column");
                if (!rel)
@@ -3490,6 +3491,10 @@ static sql_exp *
                                else
                                        groupby = subquery = gl;
                        }
+                       /*
+                       if (!subquery && exp_has_rel(e))
+                               subquery = gl;
+                               */
                        if (!exp_subtype(e)) { /* we also do not expect 
parameters here */
                                char *uaname = SA_NEW_ARRAY(sql->ta, char, 
strlen(aname) + 1);
                                return sql_error(sql, 02, SQLSTATE(42000) "%s: 
parameters not allowed as arguments to aggregate functions", 
toUpperCopy(uaname, aname));
@@ -3580,7 +3585,7 @@ static sql_exp *
                        if (exp && !is_groupby_col(res, exp)) {
                                if (is_sql_groupby(sql_state))
                                        return sql_error(sql, 05, 
SQLSTATE(42000) "SELECT: aggregate function '%s' not allowed in GROUP BY 
clause", aname);
-                               if (is_sql_aggr(sql_state))
+                               if (0 && is_sql_aggr(sql_state))
                                        return sql_error(sql, 05, 
SQLSTATE(42000) "SELECT: aggregate function calls cannot be nested");
                                if (is_sql_values(sql_state))
                                        return sql_error(sql, 05, 
SQLSTATE(42000) "SELECT: aggregate functions not allowed on an unique value");
@@ -3648,7 +3653,7 @@ static sql_exp *
        }
 
        if (!subquery && groupby && groupby->op != op_groupby) {                
/* implicit groupby */
-               if (query->last_exp && !is_sql_aggr(query->last_state)) {
+               if (!all_freevar && query->last_exp && 
!is_sql_aggr(query->last_state)) {
                        return sql_error(sql, ERR_GROUPBY, SQLSTATE(42000) 
"SELECT: cannot use non GROUP BY column '%s.%s' in query results without an 
aggregate function", exp_relname(query->last_exp), exp_name(query->last_exp));
                }
                res = groupby = rel_groupby(sql, groupby, NULL);
@@ -3671,6 +3676,10 @@ static sql_exp *
                query_update_outer(query, res, all_freevar-1);
        } else if (rel) {
                *rel = res;
+               if (query->last_rel != res) {
+                       query->last_rel = res;
+                       query->last_state |= sql_aggr;
+               }
        }
 
        if (!has_args) {        /* count(*) case */
@@ -5174,8 +5183,16 @@ rel_value_exp2(sql_query *query, sql_rel
                        assert(se->token == SQL_SELECT);
                        r = rel_subquery(query, NULL, se, ek);
                }
-               if (rel && *rel)
+               if (rel && *rel) {
                        *rel = query_pop_outer(query);
+                       if (is_sql_join(f) && is_groupby((*rel)->op)) {
+                               return sql_error(sql, 05, SQLSTATE(42000) 
"SELECT: aggregate functions not allowed in JOIN conditions");
+                       } else if (is_sql_where(f) && is_groupby((*rel)->op)) {
+                               return sql_error(sql, 02, SQLSTATE(42000) 
"SELECT: aggregate functions not allowed in WHERE clause");
+                       } else if ((is_sql_update_set(f) || is_sql_psm(f)) && 
is_groupby((*rel)->op)) {
+                               return sql_error(sql, 02, SQLSTATE(42000) 
"SELECT: aggregate functions not allowed in SET, WHILE, IF, ELSE, CASE, WHEN, 
RETURN, ANALYZE clauses");
+                       }
+               }
                if (!r)
                        return NULL;
                if (ek.type == type_value && ek.card <= card_set && 
is_project(r->op) && list_length(r->exps) > 1)
@@ -5295,10 +5312,15 @@ rel_value_exp(sql_query *query, sql_rel 
                                if (rel && *rel && !exp_has_rel(ne)) {
                                        e = ne;
                                        rel_bind_var(query->sql, *rel, e);
-                                       if (exp_has_freevar(query->sql, e) && 
is_sql_aggr(f)) {
-                                               sql_rel *outer = 
query_fetch_outer(query, exp_has_freevar(query->sql, e)-1);
-                                               
query_outer_pop_last_used(query, exp_has_freevar(query->sql, e)-1);
-                                               reset_outer(outer);
+                                       unsigned int fv = 
exp_has_freevar(query->sql, e);
+                                       if (fv && is_sql_aggr(f)) {
+                                               if (fv <= 
query_has_outer(query)) {
+                                                       sql_rel *outer = 
query_fetch_outer(query, fv-1);
+                                                       
query_outer_pop_last_used(query, fv-1);
+                                                       reset_outer(outer);
+                                               } else {
+                                                       e->freevar = 0;
+                                               }
                                        }
                                }
                        }
@@ -5939,12 +5961,9 @@ rel_joinquery_(sql_query *query, sql_rel
                t1 = table_ref(query, NULL, tab1, 0, refs);
        }
        if (t1) {
-               t2 = table_ref(query, NULL, tab2, 0, refs);
-               if (lateral && !t2 && sql->session->status != -ERR_AMBIGUOUS) {
-                       /* reset error */
-                       sql->session->status = 0;
-                       sql->errstr[0] = 0;
-
+               if (!lateral)
+                       t2 = table_ref(query, NULL, tab2, 0, refs);
+               else if (lateral && !t2) {
                        query_push_outer(query, t1, sql_from);
                        t2 = table_ref(query, NULL, tab2, 0, refs);
                        t1 = query_pop_outer(query);
@@ -5955,6 +5974,7 @@ rel_joinquery_(sql_query *query, sql_rel
        if (!t1 || !t2)
                return NULL;
 
+       query_processed(query);
        inner = rel = rel_crossproduct(sql->sa, t1, t2, op_join);
        inner->op = op;
        if (lateral)
@@ -6071,22 +6091,15 @@ sql_rel *
 rel_subquery(sql_query *query, sql_rel *rel, symbol *sq, exp_kind ek)
 {
        mvc *sql = query->sql;
-       sql_exp *last_exp = query->last_exp;
-       int last_state = query->last_state;
+       int toplevel = (!rel || (rel->op == op_project && (!rel->exps || 
list_length(rel->exps) == 0)));
+
        query_processed(query);
-       int toplevel = 0;
-
        if (!stack_push_frame(sql, NULL))
                return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
-
-       if (!rel || (rel->op == op_project &&
-               (!rel->exps || list_length(rel->exps) == 0)))
-               toplevel = 1;
-
        rel = rel_query(query, rel, sq, toplevel, ek);
        stack_pop_frame(sql);
-       query->last_exp = last_exp;
-       query->last_state = last_state;
+       if (toplevel)
+               query_processed(query);
        if (rel && ek.type == type_relation && ek.card < card_set && rel->card 
>= CARD_AGGR)
                return rel_zero_or_one(sql, rel, ek);
        return rel;
diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c
--- a/sql/server/rel_updates.c
+++ b/sql/server/rel_updates.c
@@ -1050,8 +1050,11 @@ update_generate_assignments(sql_query *q
                                if (r)
                                        query_push_outer(query, r, sql_sel | 
sql_update_set);
                                rel_val = rel_subquery(query, NULL, a, ek);
-                               if (r)
+                               if (r) {
                                        r = query_pop_outer(query);
+                                       if (r && is_groupby(r->op))
+                                               return sql_error(sql, 02, 
SQLSTATE(42000) "SELECT: aggregate functions not allowed in SET, WHILE, IF, 
ELSE, CASE, WHEN, RETURN, ANALYZE clauses");
+                               }
                                outer = 1;
                        }
                        if ((single && !v) || (!single && !rel_val))
@@ -2102,5 +2105,6 @@ rel_updates(sql_query *query, symbol *s)
        default:
                return sql_error(sql, 01, SQLSTATE(42000) "Updates statement 
unknown Symbol(%p)->token = %s", s, token2string(s->token));
        }
+       query_processed(query);
        return ret;
 }
diff --git a/sql/server/sql_query.c b/sql/server/sql_query.c
--- a/sql/server/sql_query.c
+++ b/sql/server/sql_query.c
@@ -10,15 +10,27 @@
 #include "sql_query.h"
 #include "rel_rel.h"
 
+void
+query_processed(sql_query *query )
+{
+       query -> last_rel = NULL;
+       query -> last_exp = NULL;
+       query -> last_state = 0;
+       query -> last_card = 0;
+}
+
 static stacked_query *
-sq_create( sql_allocator *sa, sql_rel *rel, int sql_state)
+sq_create( sql_allocator *sa, sql_rel *rel, sql_exp *exp, sql_exp *prev, int 
sql_state, int card)
 {
        stacked_query *q = SA_NEW(sa, stacked_query);
 
        assert(rel);
        *q = (stacked_query) {
                .rel = rel,
+               .last_used = exp,
                .sql_state = sql_state,
+               .prev = prev,
+               .used_card = card,
                .grouped = is_groupby(rel->op)|rel->grouped,
                .groupby = 0, /* not used for groupby of inner */
        };
@@ -28,7 +40,7 @@ sq_create( sql_allocator *sa, sql_rel *r
 sql_query *
 query_create( mvc *sql)
 {
-       sql_query *q = SA_NEW(sql->sa, sql_query);
+       sql_query *q = SA_ZNEW(sql->sa, sql_query);
 
        q->sql = sql;
        q->outer = sql_stack_new(sql->sa, 32);
@@ -38,7 +50,18 @@ query_create( mvc *sql)
 void
 query_push_outer(sql_query *q, sql_rel *r, int sql_state)
 {
-       stacked_query *sq = sq_create(q->sql->sa, r, sql_state);
+       if (!q->last_rel)
+               q->last_rel = r;
+       if (r != q->last_rel) {
+               assert((q->last_rel->l == r && (is_groupby(q->last_rel->op) || 
is_select(q->last_rel->op))) || (r->l == q->last_rel && (is_select(r->op) || 
is_join(r->op))));
+               r->grouped = is_groupby(q->last_rel->op);
+               q->last_rel = r;
+               q->last_exp = q->prev = NULL;
+               q->last_state = 0;
+               q->last_card = 0;
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to