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

Reply via email to