Changeset: d39c09363478 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=d39c09363478
Modified Files:
        sql/server/rel_psm.c
        sql/server/rel_rel.c
        sql/server/rel_rel.h
        sql/server/rel_select.c
        sql/server/rel_unnest.c
        sql/test/subquery/Tests/subquery4.stable.err
Branch: Jun2020
Log Message:

Use rel_zero_or_one at SELECT INTO and SET (multiple variable case). This fixes 
the crashes


diffs (235 lines):

diff --git a/sql/server/rel_psm.c b/sql/server/rel_psm.c
--- a/sql/server/rel_psm.c
+++ b/sql/server/rel_psm.c
@@ -105,8 +105,11 @@ psm_set_exp(sql_query *query, dnode *n)
 
                if (!rel_val)
                        return NULL;
-               if (!is_project(rel_val->op) || dlist_length(vars) != 
list_length(rel_val->exps))
+               if (!is_project(rel_val->op))
+                       return sql_error(sql, 02, SQLSTATE(42000) "SET: The 
subquery is not a projection");
+               if (dlist_length(vars) != list_length(rel_val->exps))
                        return sql_error(sql, 02, SQLSTATE(42000) "SET: Number 
of variables not equal to number of supplied values");
+               rel_val = rel_zero_or_one(sql, rel_val, ek);
 
                b = sa_list(sql->sa);
                append(b, exp_rel(sql, rel_val));
@@ -125,19 +128,10 @@ psm_set_exp(sql_query *query, dnode *n)
                                tpe = stack_find_type(sql, vname);
                        }
 
-                       if (!exp_name(v))
-                               exp_label(sql->sa, v, ++sql->label);
+                       level = stack_find_frame(sql, vname);
                        v = exp_ref(sql->sa, v);
-
-                       level = stack_find_frame(sql, vname);
-                       v = rel_check_type(sql, tpe, rel_val, v, type_cast);
-                       if (!v)
+                       if (!(v = rel_check_type(sql, tpe, rel_val, v, 
type_cast)))
                                return NULL;
-                       if (v->card > CARD_AGGR) {
-                               sql_subfunc *zero_or_one = 
sql_bind_func(sql->sa, sql->session->schema, "zero_or_one", exp_subtype(v), 
NULL, F_AGGR);
-                               assert(zero_or_one);
-                               v = exp_aggr1(sql->sa, v, zero_or_one, 0, 0, 
CARD_ATOM, has_nil(v));
-                       }
                        append(b, exp_set(sql->sa, vname, v, level));
                }
                res = exp_rel(sql, rel_psm_block(sql->sa, b));
@@ -520,8 +514,11 @@ rel_select_into( sql_query *query, symbo
        r = rel_subquery(query, NULL, sq, ek);
        if (!r) 
                return NULL;
+       if (!is_project(r->op))
+               return sql_error(sql, 02, SQLSTATE(42000) "SELECT INTO: The 
subquery is not a projection");
        if (list_length(r->exps) != dlist_length(into))
                return sql_error(sql, 02, SQLSTATE(21S01) "SELECT INTO: number 
of values doesn't match number of variables to set");
+       r = rel_zero_or_one(sql, r, ek);
        nl = sa_list(sql->sa);
        append(nl, exp_rel(sql, r));
        for (m = r->exps->h, n = into->h; m && n; m = m->next, n = n->next) {
@@ -532,15 +529,10 @@ rel_select_into( sql_query *query, symbo
 
                if (!stack_find_var(sql, nme)) 
                        return sql_error(sql, 02, SQLSTATE(42000) "SELECT INTO: 
variable '%s' unknown", nme);
-               /* dynamic check for single values */
-               if (v->card > CARD_AGGR) {
-                       sql_subfunc *zero_or_one = sql_bind_func(sql->sa, 
sql->session->schema, "zero_or_one", exp_subtype(v), NULL, F_AGGR);
-                       assert(zero_or_one);
-                       v = exp_aggr1(sql->sa, v, zero_or_one, 0, 0, CARD_ATOM, 
has_nil(v));
-               }
                tpe = stack_find_type(sql, nme);
                level = stack_find_frame(sql, nme);
-               if (!v || !(v = rel_check_type(sql, tpe, r, v, type_equal)))
+               v = exp_ref(sql->sa, v);
+               if (!(v = rel_check_type(sql, tpe, r, v, type_equal)))
                        return NULL;
                v = exp_set(sql->sa, nme, v, level);
                list_append(nl, v);
diff --git a/sql/server/rel_rel.c b/sql/server/rel_rel.c
--- a/sql/server/rel_rel.c
+++ b/sql/server/rel_rel.c
@@ -1572,6 +1572,55 @@ rel_in_rel(sql_rel *super, sql_rel *sub)
        return 0;
 }
 
+sql_rel*
+rel_parent(sql_rel *rel)
+{
+       if (rel->l && (is_project(rel->op) || rel->op == op_topn || rel->op == 
op_sample)) {
+               sql_rel *l = rel->l;
+               if (is_project(l->op))
+                       return l;
+       }
+       return rel;
+}
+
+sql_exp *
+lastexp(sql_rel *rel) 
+{
+       if (!is_processed(rel) || is_topn(rel->op) || is_sample(rel->op))
+               rel = rel_parent(rel);
+       assert(list_length(rel->exps));
+       assert(is_project(rel->op));
+       return rel->exps->t->data;
+}
+
+sql_rel *
+rel_zero_or_one(mvc *sql, sql_rel *rel, exp_kind ek)
+{
+       if (is_topn(rel->op))
+               rel = rel_project(sql->sa, rel, rel_projections(sql, rel, NULL, 
1, 0));
+       if (ek.card < card_set && rel->card > CARD_ATOM) {
+               assert (is_simple_project(rel->op) || is_set(rel->op));
+               list *exps = rel->exps;
+               rel = rel_groupby(sql, rel, NULL);
+               for(node *n = exps->h; n; n=n->next) {
+                       sql_exp *e = n->data;
+                       if (!has_label(e))
+                               exp_label(sql->sa, e, ++sql->label);
+                       sql_subtype *t = exp_subtype(e); /* parameters don't 
have a type defined, for those use 'void' one */
+                       sql_subfunc *zero_or_one = sql_bind_func(sql->sa, 
sql->session->schema, "zero_or_one", t ? t : sql_bind_localtype("void"), NULL, 
F_AGGR);
+
+                       e = exp_ref(sql->sa, e);
+                       e = exp_aggr1(sql->sa, e, zero_or_one, 0, 0, CARD_ATOM, 
has_nil(e));
+                       (void)rel_groupby_add_aggr(sql, rel, e);
+               }
+       } else {
+               sql_exp *e = lastexp(rel);
+               if (!has_label(e))
+                       exp_label(sql->sa, e, ++sql->label);
+       }
+       return rel;
+}
+
 static sql_rel *
 refs_find_rel(list *refs, sql_rel *rel)
 {
diff --git a/sql/server/rel_rel.h b/sql/server/rel_rel.h
--- a/sql/server/rel_rel.h
+++ b/sql/server/rel_rel.h
@@ -110,6 +110,9 @@ extern sql_rel *rel_add_identity2(mvc *s
 extern sql_exp * rel_find_column( sql_allocator *sa, sql_rel *rel, const char 
*tname, const char *cname );
 
 extern int rel_in_rel(sql_rel *super, sql_rel *sub);
+extern sql_rel *rel_parent(sql_rel *rel);
+extern sql_exp *lastexp(sql_rel *rel);
+extern sql_rel *rel_zero_or_one(mvc *sql, sql_rel *rel, exp_kind ek);
 
 extern list *rel_dependencies(mvc *sql, sql_rel *r);
 extern sql_exp * exps_find_match_exp(list *l, sql_exp *e);
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
@@ -118,27 +118,6 @@ rel_table_projections( mvc *sql, sql_rel
        }
 }
 
-static sql_rel*
-rel_parent( sql_rel *rel )
-{
-       if (rel->l && (is_project(rel->op) || rel->op == op_topn || rel->op == 
op_sample)) {
-               sql_rel *l = rel->l;
-               if (is_project(l->op))
-                       return l;
-       }
-       return rel;
-}
-
-static sql_exp *
-lastexp(sql_rel *rel) 
-{
-       if (!is_processed(rel) || is_topn(rel->op) || is_sample(rel->op))
-               rel = rel_parent(rel);
-       assert(list_length(rel->exps));
-       assert(is_project(rel->op));
-       return rel->exps->t->data;
-}
-
 static sql_exp *
 rel_lastexp(mvc *sql, sql_rel *rel )
 {
@@ -161,34 +140,6 @@ rel_lastexp(mvc *sql, sql_rel *rel )
 }
 
 static sql_rel *
-rel_zero_or_one(mvc *sql, sql_rel *rel, exp_kind ek)
-{
-       if (is_topn(rel->op))
-               rel = rel_project(sql->sa, rel, rel_projections(sql, rel, NULL, 
1, 0));
-       if (ek.card < card_set && rel->card > CARD_ATOM) {
-               assert (is_simple_project(rel->op) || is_set(rel->op));
-               list *exps = rel->exps;
-               rel = rel_groupby(sql, rel, NULL);
-               for(node *n = exps->h; n; n=n->next) {
-                       sql_exp *e = n->data;
-                       if (!has_label(e))
-                               exp_label(sql->sa, e, ++sql->label);
-                       sql_subtype *t = exp_subtype(e); /* parameters don't 
have a type defined, for those use 'void' one */
-                       sql_subfunc *zero_or_one = sql_bind_func(sql->sa, 
sql->session->schema, "zero_or_one", t ? t : sql_bind_localtype("void"), NULL, 
F_AGGR);
-
-                       e = exp_ref(sql->sa, e);
-                       e = exp_aggr1(sql->sa, e, zero_or_one, 0, 0, CARD_ATOM, 
has_nil(e));
-                       (void)rel_groupby_add_aggr(sql, rel, e);
-               }
-       } else {
-               sql_exp *e = lastexp(rel);
-               if (!has_label(e))
-                       exp_label(sql->sa, e, ++sql->label);
-       }
-       return rel;
-}
-
-static sql_rel *
 rel_orderby(mvc *sql, sql_rel *l)
 {
        sql_rel *rel = rel_create(sql->sa);
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
@@ -2664,6 +2664,7 @@ rel_unnest(mvc *sql, sql_rel *rel)
        int changes = 0;
 
        rel = rel_visitor_topdown(sql, rel, &rel_reset_subquery, &changes);
+       changes = 0;
        rel = rel_exp_visitor_bottomup(sql, rel, &rewrite_simplify_exp);
        rel = rel_visitor_bottomup(sql, rel, &rewrite_simplify, &changes);
        rel = rel_visitor_bottomup(sql, rel, &rewrite_or_exp, &changes);
diff --git a/sql/test/subquery/Tests/subquery4.stable.err 
b/sql/test/subquery/Tests/subquery4.stable.err
--- a/sql/test/subquery/Tests/subquery4.stable.err
+++ b/sql/test/subquery/Tests/subquery4.stable.err
@@ -89,6 +89,14 @@ QUERY = SELECT i1.i, i2.i FROM integers 
 ERROR = !SELECT: cannot use non GROUP BY column 'i1.i' in query results 
without an aggregate function
 CODE  = 42000
 MAPI  = (monetdb) /var/tmp/mtest-201361/.s.monetdb.35931
+QUERY = SELECT (SELECT i) INTO myvar FROM integers; --error, one row max
+ERROR = !Cardinality violation, scalar value expected
+CODE  = 21000
+MAPI  = (monetdb) /var/tmp/mtest-260928/.s.monetdb.34607
+QUERY = SET ovar = (SELECT (SELECT i) FROM integers); --error, one row max
+ERROR = !Cardinality violation, scalar value expected
+CODE  = 21000
+MAPI  = (monetdb) /var/tmp/mtest-260928/.s.monetdb.34607
 QUERY = UPDATE another_T SET col1 = MIN(col1); --error, aggregates not allowed 
in update set clause
 ERROR = !MIN: aggregate functions not allowed in SET clause (use subquery)
 CODE  = 42000
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to