Changeset: f1998eb01a51 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=f1998eb01a51 Modified Files: sql/server/rel_exp.c sql/server/rel_select.c sql/server/sql_semantic.c sql/test/miscellaneous/Tests/groupby_error.sql sql/test/miscellaneous/Tests/groupby_error.stable.out Branch: linear-hashing Log Message:
Allow quantifier subqueries with prepared statements diffs (243 lines): diff --git a/sql/server/rel_exp.c b/sql/server/rel_exp.c --- a/sql/server/rel_exp.c +++ b/sql/server/rel_exp.c @@ -1708,7 +1708,7 @@ exp_is_atom( sql_exp *e ) int exp_is_rel( sql_exp *e ) { - return (e->type == e_psm && e->flag == PSM_REL && e->l); + return (e && e->type == e_psm && e->flag == PSM_REL && e->l); } int 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 @@ -1252,8 +1252,9 @@ static int rel_set_type_param(mvc *sql, sql_subtype *type, sql_rel *rel, sql_exp *rel_exp, int upcast) { sql_rel *r = rel; - - if (!type || !rel_exp || (rel_exp->type != e_atom && rel_exp->type != e_column && rel_exp->type == e_psm && rel_exp->flag != PSM_REL)) + int is_rel = exp_is_rel(rel_exp); + + if (!type || !rel_exp || (rel_exp->type != e_atom && rel_exp->type != e_column && !is_rel)) return -1; /* use largest numeric types */ @@ -1266,10 +1267,10 @@ rel_set_type_param(mvc *sql, sql_subtype if (upcast && type->type->eclass == EC_FLT) type = sql_bind_localtype("dbl"); - if (rel_exp->type == e_psm) + if (is_rel) r = (sql_rel*) rel_exp->l; - if ((rel_exp->type == e_atom && (rel_exp->l || rel_exp->r || rel_exp->f)) || rel_exp->type == e_column || rel_exp->type == e_psm) { + if ((rel_exp->type == e_atom && (rel_exp->l || rel_exp->r || rel_exp->f)) || rel_exp->type == e_column || is_rel) { /* it's not a parameter set possible parameters below */ const char *relname = exp_relname(rel_exp), *expname = exp_name(rel_exp); if (rel_set_type_recurse(sql, type, r, &relname, &expname) < 0) @@ -1281,6 +1282,24 @@ rel_set_type_param(mvc *sql, sql_subtype return 0; } +static int +rel_binop_check_types(mvc *sql, sql_rel *rel, sql_exp *ls, sql_exp *rs, int upcast) +{ + sql_subtype *t1 = exp_subtype(ls), *t2 = exp_subtype(rs); + + if (!t1 || !t2) { + if (t2 && !t1 && rel_set_type_param(sql, t2, rel, ls, upcast) < 0) + return -1; + if (t1 && !t2 && rel_set_type_param(sql, t1, rel, rs, upcast) < 0) + return -1; + } + if (!exp_subtype(ls) && !exp_subtype(rs)) { + (void) sql_error(sql, 01, SQLSTATE(42000) "Cannot have a parameter (?) on both sides of an expression"); + return -1; + } + return 0; +} + /* try to do an in-place conversion * * in-place conversion is only possible if the exp is a variable. @@ -1619,6 +1638,8 @@ rel_compare_exp_(sql_query *query, sql_r if (anti) set_anti(e); } else { + if (rel_binop_check_types(sql, rel, ls, rs, 0) < 0) + return NULL; e = exp_compare_func(sql, ls, rs, rs2, compare_func((comp_type)type, quantifier?0:anti), quantifier); if (anti && quantifier) e = rel_unop_(sql, NULL, e, NULL, "not", card_value); @@ -1637,8 +1658,6 @@ rel_compare_exp_(sql_query *query, sql_r type = (int)swap_compare((comp_type)type); } - if (!exp_subtype(ls) && !exp_subtype(rs)) - return sql_error(sql, 01, SQLSTATE(42000) "Cannot have a parameter (?) on both sides of an expression"); if (rel_convert_types(sql, rel, rel, &ls, &rs, 1, type_equal_no_any) < 0) return NULL; e = exp_compare(sql->sa, ls, rs, type); @@ -2024,35 +2043,20 @@ rel_in_value_exp(sql_query *query, sql_r values = exp_values(sql->sa, vals); exp_label(sql->sa, values, ++sql->label); if (is_tuple) { - list *le_vals = le->f; - - for (node *m = le_vals->h, *o = vals->h ; m && o ; m = m->next, o = o->next) { + sql_exp *e_rel = (sql_exp *) vals->h->data; + list *le_vals = le->f, *rel_vals = ((sql_rel*)e_rel->l)->exps; + + for (node *m = le_vals->h, *o = rel_vals->h ; m && o ; m = m->next, o = o->next) { sql_exp *e = m->data, *f = o->data; - sql_subtype *t1 = exp_subtype(e), *t2 = exp_subtype(f); - - if (!t1 || !t2) { - if (t2 && !t1 && rel_set_type_param(sql, t2, rel ? *rel : NULL, e, 0) < 0) - return NULL; - if (t1 && !t2 && rel_set_type_param(sql, t1, rel ? *rel : NULL, f, 0) < 0) - return NULL; - } - if (!exp_subtype(e) || !exp_subtype(f)) - return sql_error(sql, 01, SQLSTATE(42000) "Cannot have a parameter (?) on both sides of an expression"); + + if (rel_binop_check_types(sql, rel ? *rel : NULL, e, f, 0) < 0) + return NULL; } } else { /* if it's not a tuple, enforce coersion on the type for every element on the list */ - sql_subtype *t1 = exp_subtype(le), *t2; - values = exp_values_set_supertype(sql, values); - t2 = exp_subtype(values); - - if (!t1 || !t2) { - if (t2 && !t1 && rel_set_type_param(sql, t2, rel ? *rel : NULL, le, 0) < 0) - return NULL; - if (t1 && !t2 && rel_set_type_param(sql, t1, rel ? *rel : NULL, values, 0) < 0) - return NULL; - } - if (!exp_subtype(le) || !exp_subtype(values)) - return sql_error(sql, 01, SQLSTATE(42000) "Cannot have a parameter (?) on both sides of an expression"); + + if (rel_binop_check_types(sql, rel ? *rel : NULL, le, values, 0) < 0) + return NULL; } e = exp_in_func(sql, le, values, (sc->token == SQL_IN), is_tuple); } @@ -2194,6 +2198,9 @@ rel_logical_value_exp(sql_query *query, rs = rel_value_exp(query, rel, ro, f, ek); if (!rs) return NULL; + + if (rel_binop_check_types(sql, rel ? *rel : NULL, ls, rs, 0) < 0) + return NULL; ls = exp_compare_func(sql, ls, rs, NULL, compare_func(compare_str2type(compare_op), quantifier?0:need_not), quantifier); if (need_not && quantifier) ls = rel_unop_(sql, NULL, ls, NULL, "not", card_value); @@ -2830,18 +2837,12 @@ rel_binop_(mvc *sql, sql_rel *rel, sql_e if (!t2) rel_set_type_param(sql, arg_type(f->func->ops->h->next->data), rel, r, 1); f = NULL; - } else { - if (t2 && !t1 && rel_set_type_param(sql, t2, rel, l, 1) < 0) - return NULL; - if (t1 && !t2 && rel_set_type_param(sql, t1, rel, r, 1) < 0) - return NULL; - } - t1 = exp_subtype(l); - t2 = exp_subtype(r); - } - - if (!t1 || !t2) - return sql_error(sql, 01, SQLSTATE(42000) "Cannot have a parameter (?) on both sides of an expression"); + + if (!exp_subtype(l) || !exp_subtype(r)) + return sql_error(sql, 01, SQLSTATE(42000) "Cannot have a parameter (?) on both sides of an expression"); + } else if (rel_binop_check_types(sql, rel, l, r, 1) < 0) + return NULL; + } if (!f && (is_addition(fname) || is_subtraction(fname)) && ((t1->type->eclass == EC_NUM && t2->type->eclass == EC_NUM) || diff --git a/sql/server/sql_semantic.c b/sql/server/sql_semantic.c --- a/sql/server/sql_semantic.c +++ b/sql/server/sql_semantic.c @@ -197,7 +197,6 @@ qname_catalog(dlist *qname) return NULL; } - int set_type_param(mvc *sql, sql_subtype *type, int nr) { diff --git a/sql/test/miscellaneous/Tests/groupby_error.sql b/sql/test/miscellaneous/Tests/groupby_error.sql --- a/sql/test/miscellaneous/Tests/groupby_error.sql +++ b/sql/test/miscellaneous/Tests/groupby_error.sql @@ -6,9 +6,10 @@ SELECT parent."sys_id" FROM "kagami_dump DROP SCHEMA "kagami_dump" CASCADE; -START TRANSACTION; + CREATE TABLE tab0(col0 INTEGER, col1 INTEGER, col2 INTEGER); INSERT INTO tab0 VALUES(97,1,99), (15,81,47), (87,21,10); + SELECT CAST(+ col1 * - col1 AS BIGINT) AS col2 FROM tab0 GROUP BY col2, col0, col1 HAVING + - col0 / - AVG ( ALL + col2 ) - - - AVG ( DISTINCT + col0 ) + col0 IS NULL; SELECT DISTINCT + 40 / + + col0 AS col2 FROM tab0 GROUP BY col0, col0, col2 HAVING NOT ( NOT + - 80 BETWEEN NULL AND + - 73 ) OR NOT ( + col0 >= - COUNT ( * ) + - COUNT ( DISTINCT - col0 ) ); SELECT ALL * FROM tab0 AS cor0 WHERE col2 NOT IN ( 22, 18, CAST ( NULL AS INTEGER ) + - 77 ); @@ -20,6 +21,13 @@ prepare select col0 from tab0 where (col prepare select col0 from tab0 where (col0) in (?); prepare select col0 from tab0 where (col0) in (?,?); +prepare select ? < ANY (select max(col0) from tab0) from tab0 t1; +prepare select col0 = ALL (select ? from tab0) from tab0 t1; + prepare select col0 from tab0 where (?) in (?); --error -ROLLBACK; +CREATE TABLE tab1(col0 INTEGER, col1 STRING); +prepare select 1 from tab1 where (col0,col1) in (select ?,? from tab1); + +drop table tab0; +drop table tab1; diff --git a/sql/test/miscellaneous/Tests/groupby_error.stable.out b/sql/test/miscellaneous/Tests/groupby_error.stable.out --- a/sql/test/miscellaneous/Tests/groupby_error.stable.out +++ b/sql/test/miscellaneous/Tests/groupby_error.stable.out @@ -137,7 +137,33 @@ stdout of test 'groupby_error` in direct [ "int", 32, 0, "", "tab0", "col0" ] [ "int", 32, 0, NULL, NULL, NULL ] [ "int", 32, 0, NULL, NULL, NULL ] -#ROLLBACK; +#prepare select ? < ANY (select max(col0) from tab0) from tab0 t1; +#prepare select ? < ANY (select max(col0) from tab0) from tab0 t1; +% .prepare, .prepare, .prepare, .prepare, .prepare, .prepare # table_name +% type, digits, scale, schema, table, column # name +% varchar, int, int, str, str, str # type +% 7, 2, 1, 0, 2, 2 # length +[ "boolean", 1, 0, "", "%5", "%5" ] +[ "int", 32, 0, NULL, NULL, NULL ] +#prepare select col0 = ALL (select ? from tab0) from tab0 t1; +#prepare select col0 = ALL (select ? from tab0) from tab0 t1; +% .prepare, .prepare, .prepare, .prepare, .prepare, .prepare # table_name +% type, digits, scale, schema, table, column # name +% varchar, int, int, str, str, str # type +% 7, 2, 1, 0, 2, 2 # length +[ "boolean", 1, 0, "", "%5", "%5" ] +[ "int", 32, 0, NULL, NULL, NULL ] +#CREATE TABLE tab1(col0 INTEGER, col1 STRING); +#prepare select 1 from tab1 where (col0,col1) in (select ?,? from tab1); +#prepare select 1 from tab1 where (col0,col1) in (select ?,? from tab1); +% .prepare, .prepare, .prepare, .prepare, .prepare, .prepare # table_name +% type, digits, scale, schema, table, column # name +% varchar, int, int, str, str, str # type +% 7, 2, 1, 0, 0, 0 # length +[ "tinyint", 1, 0, "", "", "" ] +[ "int", 32, 0, NULL, NULL, NULL ] +[ "clob", 0, 0, NULL, NULL, NULL ] +#drop table tab0; # 10:56:47 > # 10:56:47 > "Done." _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list