Changeset: 890beb553c41 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=890beb553c41
Modified Files:
        sql/backends/monet5/sql.c
        sql/server/rel_exp.c
        sql/server/rel_exp.h
        sql/server/rel_optimizer.c
        sql/server/rel_propagate.c
        sql/server/rel_psm.c
        sql/server/rel_schema.c
        sql/server/rel_select.c
        sql/server/rel_select.h
        sql/server/rel_sequence.c
        sql/server/rel_unnest.c
        sql/server/rel_updates.c
        sql/server/rel_xml.c
        sql/server/sql_atom.c
        sql/server/sql_atom.h
        sql/test/SQLancer/Tests/All
        sql/test/SQLancer/Tests/sqlancer02.stable.out
Branch: Jun2020
Log Message:

Fix for bug 6911, ie never call exp_convert on any expression without knowing 
if it will be compatible with the output type.
Removed the superfluous exp_convert calls and moved rel_check_type to rel_exp.h 
and renamed it to exp_check_type to make it more widely available.


diffs (truncated from 1368 to 300 lines):

diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -338,7 +338,7 @@ create_table_or_view(mvc *sql, char* sna
                        _DELETE(typestr);
                        r = rel_parse(sql, s, buf, m_deps);
                        if (!r || !is_project(r->op) || !r->exps || 
list_length(r->exps) != 1 ||
-                               rel_check_type(sql, &c->type, r, 
r->exps->h->data, type_equal) == NULL) {
+                               exp_check_type(sql, &c->type, r, 
r->exps->h->data, type_equal) == NULL) {
                                if (r)
                                        rel_destroy(r);
                                sa_destroy(sql->sa);
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
@@ -497,6 +497,13 @@ exp_null(sql_allocator *sa, sql_subtype 
        return exp_atom(sa, a);
 }
 
+sql_exp *
+exp_zero(sql_allocator *sa, sql_subtype *tpe)
+{
+       atom *a = atom_zero_value(sa, tpe);
+       return exp_atom(sa, a);
+}
+
 atom *
 exp_value(mvc *sql, sql_exp *e, atom **args, int maxarg)
 {
@@ -2626,6 +2633,205 @@ exps_reset_freevar(list *exps)
        }
 }
 
+int
+rel_set_type_param(mvc *sql, sql_subtype *type, sql_rel *rel, sql_exp 
*rel_exp, int upcast)
+{
+       sql_rel *r = 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 */
+       if (upcast && type->type->eclass == EC_NUM)
+#ifdef HAVE_HGE
+               type = sql_bind_localtype(have_hge ? "hge" : "lng");
+#else
+               type = sql_bind_localtype("lng");
+#endif
+       if (upcast && type->type->eclass == EC_FLT)
+               type = sql_bind_localtype("dbl");
+
+       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 || 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)
+                       return -1;
+       } else if (set_type_param(sql, type, rel_exp->flag) != 0)
+               return -1;
+
+       rel_exp->tpe = *type;
+       return 0;
+}
+
+/* try to do an in-place conversion
+ *
+ * in-place conversion is only possible if the exp is a variable.
+ * This is only done to be able to map more cached queries onto the same
+ * interface.
+ */
+
+static void
+convert_atom(atom *a, sql_subtype *rt)
+{
+       if (atom_null(a)) {
+               if (a->data.vtype != rt->type->localtype) {
+                       const void *p;
+
+                       a->data.vtype = rt->type->localtype;
+                       p = ATOMnilptr(a->data.vtype);
+                       VALset(&a->data, a->data.vtype, (ptr) p);
+               }
+       }
+       a->tpe = *rt;
+}
+
+static sql_exp *
+exp_convert_inplace(mvc *sql, sql_subtype *t, sql_exp *exp)
+{
+       atom *a;
+
+       /* exclude named variables and variable lists */
+       if (exp->type != e_atom || exp->r /* named */ || exp->f /* list */ || 
!exp->l /* not direct atom */)
+               return NULL;
+
+       a = exp->l;
+       if (t->scale && t->type->eclass != EC_FLT)
+               return NULL;
+
+       if (a && atom_cast(sql->sa, a, t)) {
+               convert_atom(a, t);
+               exp->tpe = *t;
+               return exp;
+       }
+       return NULL;
+}
+
+sql_exp *
+exp_numeric_supertype(mvc *sql, sql_exp *e )
+{
+       sql_subtype *tp = exp_subtype(e);
+
+       if (tp->type->eclass == EC_DEC) {
+               sql_subtype *dtp = sql_bind_localtype("dbl");
+
+               return exp_check_type(sql, dtp, NULL, e, type_cast);
+       }
+       if (tp->type->eclass == EC_NUM) {
+#ifdef HAVE_HGE
+               sql_subtype *ltp = sql_bind_localtype(have_hge ? "hge" : "lng");
+#else
+               sql_subtype *ltp = sql_bind_localtype("lng");
+#endif
+
+               return exp_check_type(sql, ltp, NULL, e, type_cast);
+       }
+       return e;
+}
+
+sql_exp *
+exp_check_type(mvc *sql, sql_subtype *t, sql_rel *rel, sql_exp *exp, 
check_type tpe)
+{
+       int c, err = 0;
+       sql_exp* nexp = NULL;
+       sql_subtype *fromtype = exp_subtype(exp);
+
+       if ((!fromtype || !fromtype->type) && rel_set_type_param(sql, t, rel, 
exp, 0) == 0)
+               return exp;
+
+       /* first try cheap internal (in-place) conversions ! */
+       if ((nexp = exp_convert_inplace(sql, t, exp)) != NULL)
+               return nexp;
+
+       if (fromtype && subtype_cmp(t, fromtype) != 0) {
+               if (EC_INTERVAL(fromtype->type->eclass) && (t->type->eclass == 
EC_NUM || t->type->eclass == EC_POS) && t->digits < fromtype->digits) {
+                       err = 1; /* conversion from interval to num depends on 
the number of digits */
+               } else {
+                       c = sql_type_convert(fromtype->type->eclass, 
t->type->eclass);
+                       if (!c || (c == 2 && tpe == type_set) || (c == 3 && tpe 
!= type_cast)) {
+                               err = 1;
+                       } else {
+                               exp = exp_convert(sql->sa, exp, fromtype, t);
+                       }
+               }
+       }
+       if (err) {
+               sql_exp *res = sql_error( sql, 03, SQLSTATE(42000) "types 
%s(%u,%u) and %s(%u,%u) are not equal%s%s%s",
+                       fromtype->type->sqlname,
+                       fromtype->digits,
+                       fromtype->scale,
+                       t->type->sqlname,
+                       t->digits,
+                       t->scale,
+                       (exp->type == e_column ? " for column '" : ""),
+                       (exp->type == e_column ? exp_name(exp) : ""),
+                       (exp->type == e_column ? "'" : "")
+               );
+               return res;
+       }
+       return exp;
+}
+
+sql_exp *
+exp_values_set_supertype(mvc *sql, sql_exp *values, sql_subtype *opt_super)
+{
+       assert(is_values(values));
+       list *vals = exp_get_values(values), *nexps;
+       sql_subtype *tpe = opt_super?opt_super:exp_subtype(vals->h->data);
+
+       if (!opt_super && tpe)
+               values->tpe = *tpe;
+
+       for (node *m = vals->h; m; m = m->next) {
+               sql_exp *e = m->data;
+               sql_subtype super, *ttpe;
+
+               /* if the expression is a parameter set its type */
+               if (tpe && e->type == e_atom && !e->l && !e->r && !e->f && 
!e->tpe.type) {
+                       if (set_type_param(sql, tpe, e->flag) == 0)
+                               e->tpe = *tpe;
+                       else
+                               return NULL;
+               }
+               ttpe = exp_subtype(e);
+               if (tpe && ttpe) {
+                       supertype(&super, ttpe, tpe);
+                       values->tpe = super;
+                       tpe = &values->tpe;
+               } else {
+                       tpe = ttpe;
+               }
+       }
+
+       if (tpe) {
+               /* if the expression is a parameter set its type */
+               for (node *m = vals->h; m; m = m->next) {
+                       sql_exp *e = m->data;
+                       if (e->type == e_atom && !e->l && !e->r && !e->f && 
!e->tpe.type) {
+                               if (set_type_param(sql, tpe, e->flag) == 0)
+                                       e->tpe = *tpe;
+                               else
+                                       return NULL;
+                       }
+               }
+               values->tpe = *tpe;
+               nexps = sa_list(sql->sa);
+               for (node *m = vals->h; m; m = m->next) {
+                       sql_exp *e = m->data;
+                       e = exp_check_type(sql, &values->tpe, NULL, e, 
type_equal);
+                       if (!e)
+                               return NULL;
+                       exp_label(sql->sa, e, ++sql->label);
+                       append(nexps, e);
+               }
+               values->f = nexps;
+       }
+       return values;
+}
+
 static int
 exp_set_list_recurse(mvc *sql, sql_subtype *type, sql_exp *e, const char 
**relname, const char** expname)
 {
diff --git a/sql/server/rel_exp.h b/sql/server/rel_exp.h
--- a/sql/server/rel_exp.h
+++ b/sql/server/rel_exp.h
@@ -12,6 +12,7 @@
 #include "sql_relation.h"
 #include "sql_mvc.h"
 #include "sql_atom.h"
+#include "sql_semantic.h"
 
 #define new_exp_list(sa) sa_list(sa)
 #define exp2list(sa,e)   append(sa_list(sa),e)
@@ -74,6 +75,7 @@ extern sql_exp * exp_atom_clob(sql_alloc
 extern sql_exp * exp_atom_ptr(sql_allocator *sa, void *s);
 extern sql_exp * exp_atom_ref(sql_allocator *sa, int i, sql_subtype *tpe);
 extern sql_exp * exp_null(sql_allocator *sa, sql_subtype *tpe);
+extern sql_exp * exp_zero(sql_allocator *sa, sql_subtype *tpe); /* Apply it to 
numeric types only obviously */
 extern sql_exp * exp_param(sql_allocator *sa, const char *name, sql_subtype 
*tpe, int frame);
 extern atom * exp_value(mvc *sql, sql_exp *e, atom **args, int maxarg);
 extern sql_exp * exp_values(sql_allocator *sa, list *exps);
@@ -189,5 +191,10 @@ extern int exp_aggr_is_count(sql_exp *e)
 
 extern void exps_reset_freevar(list *exps);
 
+extern sql_exp *exp_check_type(mvc *sql, sql_subtype *t, sql_rel *rel, sql_exp 
*exp, check_type tpe);
+extern int rel_set_type_param(mvc *sql, sql_subtype *type, sql_rel *rel, 
sql_exp *rel_exp, int upcast);
+extern sql_exp *exp_numeric_supertype(mvc *sql, sql_exp *e);
+extern sql_exp *exp_values_set_supertype(mvc *sql, sql_exp *values, 
sql_subtype *opt_super);
+
 extern int rel_set_type_recurse(mvc *sql, sql_subtype *type, sql_rel *rel, 
const char **relname, const char **expname);
 #endif /* _REL_EXP_H_ */
diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -3067,26 +3067,20 @@ exp_simplify_math( mvc *sql, sql_exp *e,
                                (*changes)++;
                                if (f && f->func && f->func->imp && 
strstr(f->func->imp, "_no_nil") != NULL) {
                                        exp_setname(sql->sa, re, 
exp_relname(e), exp_name(e));
-                                       if (subtype_cmp(et, exp_subtype(re)) != 
0)
-                                               re = exp_convert(sql->sa, re, 
exp_subtype(re), et);
                                        return re;
                                }
+                               le = exp_null(sql->sa, et);
                                exp_setname(sql->sa, le, exp_relname(e), 
exp_name(e));
-                               if (subtype_cmp(et, exp_subtype(le)) != 0)
-                                       le = exp_convert(sql->sa, le, 
exp_subtype(le), et);
                                return le;
                        }
                        if (exp_is_atom(re) && exp_is_null(sql, re)) {
                                (*changes)++;
                                if (f && f->func && f->func->imp && 
strstr(f->func->imp, "_no_nil") != NULL) {
                                        exp_setname(sql->sa, le, 
exp_relname(e), exp_name(e));
-                                       if (subtype_cmp(et, exp_subtype(le)) != 
0)
-                                               le = exp_convert(sql->sa, le, 
exp_subtype(le), et);
                                        return le;
                                }
+                               re = exp_null(sql->sa, et);
                                exp_setname(sql->sa, re, exp_relname(e), 
exp_name(e));
-                               if (subtype_cmp(et, exp_subtype(re)) != 0)
-                                       re = exp_convert(sql->sa, re, 
exp_subtype(re), et);
                                return re;
                        }
                }
@@ -3098,17 +3092,15 @@ exp_simplify_math( mvc *sql, sql_exp *e,
                        /* 0*a = 0 */
                        if (exp_is_atom(le) && exp_is_zero(sql, le) && 
exp_is_atom(re) && exp_is_not_null(sql, re)) {
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to