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