Changeset: 38bf565fc89a for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/38bf565fc89a
Modified Files:
        sql/common/sql_types.c
        sql/server/rel_dump.c
        sql/server/rel_exp.c
        sql/server/rel_exp.h
        sql/server/rel_select.c
        sql/test/SQLancer/Tests/sqlancer19.SQL.py
        sql/test/SQLancer/Tests/sqlancer20.SQL.py
Branch: default
Log Message:

Two fixes for remote plans. For functions with more than 2 inputs, compute 
output digits and scale if needed. When binding an inout function make sure the 
result number of digits is equal to the first argument


diffs (240 lines):

diff --git a/sql/common/sql_types.c b/sql/common/sql_types.c
--- a/sql/common/sql_types.c
+++ b/sql/common/sql_types.c
@@ -493,7 +493,7 @@ sql_dup_subfunc(sql_allocator *sa, sql_f
                                        /* same scale as the input */
                                        if (a && a->scale > mscale)
                                                mscale = a->scale;
-                                       if (a && f->fix_scale == INOUT)
+                                       if (a && f->fix_scale == INOUT && tn == 
ops->h)
                                                mdigits = a->digits;
                                }
                        }
diff --git a/sql/server/rel_dump.c b/sql/server/rel_dump.c
--- a/sql/server/rel_dump.c
+++ b/sql/server/rel_dump.c
@@ -1235,7 +1235,7 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re
                                if (f && !execute_priv(sql, f->func))
                                        return sql_error(sql, -1, 
SQLSTATE(42000) "Function: no privilege to call function '%s%s%s %d'\n", tname 
? tname : "", tname ? "." : "", cname, nops);
                                /* apply scale fixes if needed */
-                               if (f && f->func->fix_scale != SCALE_NONE) {
+                               if (f && f->func->type != F_ANALYTIC) {
                                        if (list_length(exps) == 1) {
                                                if (f->func->fix_scale == 
INOUT) {
                                                        sql_subtype *t = 
exp_subtype(exps->h->data);
@@ -1290,6 +1290,9 @@ exp_read(mvc *sql, sql_rel *lrel, sql_re
                                                                res->digits = 0;
                                                        }
                                                }
+                                       } else if (list_length(exps) > 2) {
+                                               if (!f->func->vararg && !(exps 
= check_arguments_and_find_largest_any_type(sql, lrel, exps, f, 0)))
+                                                       return NULL;
                                        }
                                }
                        }
@@ -1859,6 +1862,8 @@ rel_read(mvc *sql, char *r, int *pos, li
                                if (list_length(outputs) != 
list_length(sf->func->res))
                                        return sql_error(sql, -1, 
SQLSTATE(42000) "Table returning function: the number of output parameters 
don't match the table ones relation outputs: %d != function outputs: %d\n",
                                                                         
list_length(outputs), list_length(sf->func->res));
+                               if (!list_empty(outputs) && !(outputs = 
check_arguments_and_find_largest_any_type(sql, lrel, outputs, sf, 0)))
+                                       return NULL;
                                rel = rel_table_func(sql->sa, lrel, tudf, 
outputs, TABLE_FROM_RELATION);
                        } else {
                                if (r[*pos] != ')')
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
@@ -2956,6 +2956,73 @@ exp_sum_scales(sql_subfunc *f, sql_exp *
        }
 }
 
+list *
+check_arguments_and_find_largest_any_type(mvc *sql, sql_rel *rel, list *exps, 
sql_subfunc *sf, int maybe_zero_or_one)
+{
+       list *nexps = new_exp_list(sql->sa);
+       sql_subtype *atp = NULL, super, *res = !list_empty(sf->res) ? 
sf->res->h->data: NULL;
+       unsigned int rdigits = 0; /* used for res of type char and varchar */
+
+       /* find largest any type argument */
+       for (node *n = exps->h, *m = sf->func->ops->h; n && m; n = n->next, m = 
m->next) {
+               sql_arg *a = m->data;
+               sql_exp *e = n->data;
+               sql_subtype *t = exp_subtype(e);
+
+               if (a->type.type->eclass == EC_ANY) {
+                       if (t && atp) {
+                               result_datatype(&super, t, atp);
+                               atp = &super;
+                       } else if (t) {
+                               atp = t;
+                       }
+               }
+       }
+       if (atp && atp->type->localtype == TYPE_void) /* NULL */
+               atp = sql_bind_localtype("str");
+       for (node *n = exps->h, *m = sf->func->ops->h; n && m; n = n->next, m = 
m->next) {
+               sql_arg *a = m->data;
+               sql_exp *e = n->data;
+               sql_subtype *ntp = &a->type, *t = exp_subtype(e);
+
+               if (a->type.type->eclass == EC_ANY && atp)
+                       ntp = sql_create_subtype(sql->sa, atp->type, 
atp->digits, atp->scale);
+               else if (t && ntp->digits == 0 && 
(!strcmp(a->type.type->base.name, "char") || !strcmp(a->type.type->base.name, 
"varchar")))
+                       ntp = sql_create_subtype(sql->sa, a->type.type, 
type_digits_to_char_digits(t), 0);
+               if (!(e = exp_check_type(sql, ntp, rel, e, type_equal)))
+                       return NULL;
+               if (maybe_zero_or_one && e->card > CARD_ATOM) {
+                       sql_subfunc *zero_or_one = sql_bind_func(sql, "sys", 
"zero_or_one", exp_subtype(e), NULL, F_AGGR);
+                       e = exp_aggr1(sql->sa, e, zero_or_one, 0, 0, CARD_ATOM, 
has_nil(e));
+               }
+               append(nexps, e);
+
+               /* for (var)char returning functions the output type will be 
the biggest string found except for fix_scale cases */
+               if (res && res->digits == 0 && (t = exp_subtype(e)) && 
(!strcmp(res->type->base.name, "char") || !strcmp(res->type->base.name, 
"varchar"))) {
+                       unsigned int tdigits = type_digits_to_char_digits(t);
+                       if (sf->func->fix_scale == DIGITS_ADD) {
+                               unsigned int nvalue = rdigits + tdigits;
+                               if (nvalue < rdigits || nvalue >= (unsigned 
int) INT32_MAX)
+                                       return sql_error(sql, 02, 
SQLSTATE(42000) "SELECT: output number of digits for %s is too large", 
sf->func->base.name);
+                               rdigits = nvalue;
+                       } else if (sf->func->fix_scale == INOUT) {
+                               if (n == exps->h)
+                                       rdigits = tdigits;
+                       } else {
+                               rdigits = sql_max(rdigits, tdigits);
+                       }
+               }
+       }
+       /* dirty hack */
+       if (sf->func->type != F_PROC && sf->func->type != F_UNION && 
sf->func->type != F_LOADER && res) {
+               if (res->type->eclass == EC_ANY && atp)
+                       sf->res->h->data = sql_create_subtype(sql->sa, 
atp->type, atp->digits, atp->scale);
+               else if (res->digits == 0 && (!strcmp(res->type->base.name, 
"char") || !strcmp(res->type->base.name, "varchar")))
+                       res->digits = rdigits;
+       }
+       return nexps;
+}
+
 int
 exp_aggr_is_count(sql_exp *e)
 {
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
@@ -196,6 +196,7 @@ extern atom *exp_flatten(mvc *sql, sql_e
 
 extern sql_exp *exp_scale_algebra(mvc *sql, sql_subfunc *f, sql_rel *rel, 
sql_exp *l, sql_exp *r);
 extern void exp_sum_scales(sql_subfunc *f, sql_exp *l, sql_exp *r);
+extern list *check_arguments_and_find_largest_any_type(mvc *sql, sql_rel *rel, 
list *exps, sql_subfunc *sf, int maybe_zero_or_one);
 
 extern int exp_aggr_is_count(sql_exp *e);
 extern list *check_distinct_exp_names(mvc *sql, list *exps);
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
@@ -452,73 +452,6 @@ score_func( sql_subfunc *sf, list *tl)
        return score;
 }
 
-static list *
-check_arguments_and_find_largest_any_type(mvc *sql, sql_rel *rel, list *exps, 
sql_subfunc *sf, int maybe_zero_or_one)
-{
-       list *nexps = new_exp_list(sql->sa);
-       sql_subtype *atp = NULL, super, *res = !list_empty(sf->res) ? 
sf->res->h->data: NULL;
-       unsigned int rdigits = 0; /* used for res of type char and varchar */
-
-       /* find largest any type argument */
-       for (node *n = exps->h, *m = sf->func->ops->h; n && m; n = n->next, m = 
m->next) {
-               sql_arg *a = m->data;
-               sql_exp *e = n->data;
-               sql_subtype *t = exp_subtype(e);
-
-               if (a->type.type->eclass == EC_ANY) {
-                       if (t && atp) {
-                               result_datatype(&super, t, atp);
-                               atp = &super;
-                       } else if (t) {
-                               atp = t;
-                       }
-               }
-       }
-       if (atp && atp->type->localtype == TYPE_void) /* NULL */
-               atp = sql_bind_localtype("str");
-       for (node *n = exps->h, *m = sf->func->ops->h; n && m; n = n->next, m = 
m->next) {
-               sql_arg *a = m->data;
-               sql_exp *e = n->data;
-               sql_subtype *ntp = &a->type, *t = exp_subtype(e);
-
-               if (a->type.type->eclass == EC_ANY && atp)
-                       ntp = sql_create_subtype(sql->sa, atp->type, 
atp->digits, atp->scale);
-               else if (t && ntp->digits == 0 && 
(!strcmp(a->type.type->base.name, "char") || !strcmp(a->type.type->base.name, 
"varchar")))
-                       ntp = sql_create_subtype(sql->sa, a->type.type, 
type_digits_to_char_digits(t), 0);
-               if (!(e = exp_check_type(sql, ntp, rel, e, type_equal)))
-                       return NULL;
-               if (maybe_zero_or_one && e->card > CARD_ATOM) {
-                       sql_subfunc *zero_or_one = sql_bind_func(sql, "sys", 
"zero_or_one", exp_subtype(e), NULL, F_AGGR);
-                       e = exp_aggr1(sql->sa, e, zero_or_one, 0, 0, CARD_ATOM, 
has_nil(e));
-               }
-               append(nexps, e);
-
-               /* for (var)char returning functions the output type will be 
the biggest string found except for fix_scale cases */
-               if (res && res->digits == 0 && (t = exp_subtype(e)) && 
(!strcmp(res->type->base.name, "char") || !strcmp(res->type->base.name, 
"varchar"))) {
-                       unsigned int tdigits = type_digits_to_char_digits(t);
-                       if (sf->func->fix_scale == DIGITS_ADD) {
-                               unsigned int nvalue = rdigits + tdigits;
-                               if (nvalue < rdigits || nvalue >= (unsigned 
int) INT32_MAX)
-                                       return sql_error(sql, 02, 
SQLSTATE(42000) "SELECT: output number of digits for %s is too large", 
sf->func->base.name);
-                               rdigits = nvalue;
-                       } else if (sf->func->fix_scale == INOUT) {
-                               if (n == exps->h)
-                                       rdigits = tdigits;
-                       } else {
-                               rdigits = sql_max(rdigits, tdigits);
-                       }
-               }
-       }
-       /* dirty hack */
-       if (sf->func->type != F_PROC && sf->func->type != F_UNION && 
sf->func->type != F_LOADER && res) {
-               if (res->type->eclass == EC_ANY && atp)
-                       sf->res->h->data = sql_create_subtype(sql->sa, 
atp->type, atp->digits, atp->scale);
-               else if (res->digits == 0 && (!strcmp(res->type->base.name, 
"char") || !strcmp(res->type->base.name, "varchar")))
-                       res->digits = rdigits;
-       }
-       return nexps;
-}
-
 static char *
 nary_function_arg_types_2str(mvc *sql, list* types, int N)
 {
diff --git a/sql/test/SQLancer/Tests/sqlancer19.SQL.py 
b/sql/test/SQLancer/Tests/sqlancer19.SQL.py
--- a/sql/test/SQLancer/Tests/sqlancer19.SQL.py
+++ b/sql/test/SQLancer/Tests/sqlancer19.SQL.py
@@ -95,6 +95,14 @@ with SQLTestCase() as cli:
         .assertSucceeded().assertDataResultMatch([(Decimal('0.02000'),)])
     cli.execute("SELECT CAST(2 AS DECIMAL) * 0.010 FROM rt3 where rt3.c0 = 
1;") \
         .assertSucceeded().assertDataResultMatch([(Decimal('0.02000'),)])
+    cli.execute("SELECT \"insert\"('99', 5, 8, '10S') FROM t3 where t3.c0 = 
1;") \
+        .assertSucceeded().assertDataResultMatch([("9910S",)])
+    cli.execute("SELECT \"insert\"('99', 5, 8, '10S') FROM rt3 where rt3.c0 = 
1;") \
+        .assertSucceeded().assertDataResultMatch([("9910S",)])
+    cli.execute("SELECT greatest('69', splitpart('', '191', 2)) FROM t3 where 
t3.c0 = 1;") \
+        .assertSucceeded().assertDataResultMatch([('69',)])
+    cli.execute("SELECT greatest('69', splitpart('', '191', 2)) FROM rt3 where 
rt3.c0 = 1;") \
+        .assertSucceeded().assertDataResultMatch([('69',)])
     cli.execute("SELECT t3.c0 FROM t3 where (t3.c0) NOT IN (0.07564294, 211.0, 
1, 2) ORDER BY t3.c0;") \
         .assertSucceeded().assertDataResultMatch([(5,),(5,),(7,)])
     cli.execute("SELECT rt3.c0 FROM rt3 where (rt3.c0) NOT IN (0.07564294, 
211.0, 1, 2) ORDER BY rt3.c0;") \
diff --git a/sql/test/SQLancer/Tests/sqlancer20.SQL.py 
b/sql/test/SQLancer/Tests/sqlancer20.SQL.py
--- a/sql/test/SQLancer/Tests/sqlancer20.SQL.py
+++ b/sql/test/SQLancer/Tests/sqlancer20.SQL.py
@@ -23,10 +23,6 @@ with SQLTestCase() as cli:
         .assertSucceeded().assertDataResultMatch([(Decimal('0.002'),)])
     cli.execute("SELECT CAST(2 AS DECIMAL) & CAST(3 AS DOUBLE) FROM rt1 where 
rt1.c0 = 1;") \
         .assertSucceeded().assertDataResultMatch([(Decimal('0.002'),)])
-    cli.execute("SELECT greatest('69', splitpart('', '191', 2)) FROM t1 where 
t1.c0 = 1;") \
-        .assertSucceeded().assertDataResultMatch([('69',)])
-    cli.execute("SELECT greatest('69', splitpart('', '191', 2)) FROM rt1 where 
rt1.c0 = 1;") \
-        .assertSucceeded().assertDataResultMatch([('69',)])
 
     # Issues related to comparisons not being correctly delimited on plans, 
which causes ambiguity
     cli.execute("SELECT TRUE BETWEEN (TRUE BETWEEN FALSE AND FALSE) AND TRUE 
FROM t1 where t1.c0 = 1;") \
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to