Changeset: 8ee17e5ea37c for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/8ee17e5ea37c
Modified Files:
        sql/common/sql_types.c
        sql/server/rel_dump.c
        sql/server/sql_semantic.c
        sql/test/SQLancer/Tests/sqlancer19.SQL.py
        sql/test/emptydb/Tests/check.stable.out
        sql/test/emptydb/Tests/check.stable.out.32bit
        sql/test/emptydb/Tests/check.stable.out.int128
        sql/test/prepare/Tests/sqlancer_prepare.stable.err
        sql/test/prepare/Tests/sqlancer_prepare.stable.err.int128
        sql/test/prepare/Tests/sqlancer_prepare.stable.out
        sql/test/prepare/Tests/sqlancer_prepare.stable.out.int128
Branch: Jul2021
Log Message:

When binding a SQL function, give preference to the function version with most 
identical types compared to the input ones. Added missing type set at exp_read 
and approved output


diffs (truncated from 500 to 300 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
@@ -377,8 +377,10 @@ is_subtype(sql_subtype *sub, sql_subtype
                return 0;
        if (super->digits > 0 && sub->digits > super->digits)
                return 0;
-       if (super->digits == 0 && super->type->eclass == EC_STRING &&
-           (sub->type->eclass == EC_STRING || sub->type->eclass == EC_CHAR))
+       /* while binding a function, 'char' types match each other */
+       if (super->digits == 0 && 
+               ((super->type->eclass == EC_STRING && 
EC_VARCHAR(sub->type->eclass)) ||
+                (super->type->eclass == EC_CHAR && sub->type->eclass == 
EC_CHAR)))
                return 1;
        if (super->digits != sub->digits && sub->type->eclass == EC_CHAR)
                return 0;
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
@@ -1204,25 +1204,36 @@ 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 && 
list_length(exps) == 2) {
-                                       sql_exp *l = exps->h->data;
-                                       sql_exp *r = exps->h->next->data;
-                                       sql_subtype *t1 = ops->h->data;
-                                       sql_subtype *t2 = ops->h->next->data;
+                               if (f && f->func->fix_scale != SCALE_NONE) {
+                                       if (list_length(exps) == 1) {
+                                               if (f->func->fix_scale == 
INOUT) {
+                                                       sql_subtype *t = 
exp_subtype(exps->h->data);
+                                                       sql_subtype *res = 
f->res->h->data;
+
+                                                       res->digits = t->digits;
+                                                       res->scale = t->scale;
+                                               }
+                                       } else if (list_length(exps) == 2) {
+                                               sql_exp *l = exps->h->data;
+                                               sql_exp *r = 
exps->h->next->data;
 
-                                       if (f->func->fix_scale == SCALE_DIV) {
-                                               if (!(exps->h->data = 
exp_scale_algebra(sql, f, NULL, l, r)))
-                                                       return NULL;
-                                       } else if (f->func->fix_scale == 
SCALE_MUL) {
-                                               exp_sum_scales(f, l, r);
-                                       } else if (f->func->fix_scale == 
DIGITS_ADD) {
-                                               sql_subtype *res = 
f->res->h->data;
-                                               if (t1->digits && t2->digits) {
-                                                       res->digits = 
t1->digits + t2->digits;
-                                                       if (res->digits < 
t1->digits || res->digits < t2->digits || res->digits >= (unsigned int) 
INT32_MAX)
-                                                               return 
sql_error(sql, -1, SQLSTATE(42000) "Output number of digits for %s%s%s is too 
large\n", tname ? tname : "", tname ? "." : "", cname);
-                                               } else {
-                                                       res->digits = 0;
+                                               if (f->func->fix_scale == 
SCALE_DIV) {
+                                                       if (!(exps->h->data = 
exp_scale_algebra(sql, f, NULL, l, r)))
+                                                               return NULL;
+                                               } else if (f->func->fix_scale 
== SCALE_MUL) {
+                                                       exp_sum_scales(f, l, r);
+                                               } else if (f->func->fix_scale 
== DIGITS_ADD) {
+                                                       sql_subtype *t1 = 
exp_subtype(l);
+                                                       sql_subtype *t2 = 
exp_subtype(r);
+                                                       sql_subtype *res = 
f->res->h->data;
+
+                                                       if (t1->digits && 
t2->digits) {
+                                                               res->digits = 
t1->digits + t2->digits;
+                                                               if (res->digits 
< t1->digits || res->digits < t2->digits || res->digits >= (unsigned int) 
INT32_MAX)
+                                                                       return 
sql_error(sql, -1, SQLSTATE(42000) "Output number of digits for %s%s%s is too 
large\n", tname ? tname : "", tname ? "." : "", cname);
+                                                       } else {
+                                                               res->digits = 0;
+                                                       }
                                                }
                                        }
                                }
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
@@ -398,8 +398,10 @@ is_subtypeof(sql_subtype *sub, sql_subty
                return 0;
        if (super->digits > 0 && sub->digits > super->digits)
                return 0;
-       if (super->digits == 0 && super->type->eclass == EC_STRING &&
-           (sub->type->eclass == EC_STRING || sub->type->eclass == EC_CHAR))
+       /* while binding a function, 'char' types match each other */
+       if (super->digits == 0 && 
+               ((super->type->eclass == EC_STRING && 
EC_VARCHAR(sub->type->eclass)) ||
+                (super->type->eclass == EC_CHAR && sub->type->eclass == 
EC_CHAR)))
                return 1;
        if (super->type->eclass == sub->type->eclass)
                return 1;
@@ -412,7 +414,8 @@ is_subtypeof(sql_subtype *sub, sql_subty
 static sql_subfunc *
 sql_bind_member_internal(mvc *sql, list *ff, const char *fname, sql_subtype 
*tp, sql_ftype type, int nrargs, sql_subfunc *prev)
 {
-       int found = 1;
+       sql_func *cand = NULL;
+       int points = 0, npoints = 0, found = 1;
 
        assert(nrargs);
        if (ff) {
@@ -430,17 +433,29 @@ sql_bind_member_internal(mvc *sql, list 
                                continue;
                        if (strcmp(f->base.name, fname) == 0 && f->type == type 
&& list_length(f->ops) == nrargs) {
                                sql_subtype *ft = &((sql_arg *) 
f->ops->h->data)->type;
-                               if ((f->fix_scale == INOUT && 
type_cmp(tp->type, ft->type) == 0) || (f->fix_scale != INOUT && 
is_subtypeof(tp, ft)))
-                                       return (type == F_AGGR) ? 
_dup_subaggr(sql->sa, f, NULL) : sql_dup_subfunc(sql->sa, f, NULL, tp);
+                               if ((f->fix_scale == INOUT && 
type_cmp(tp->type, ft->type) == 0) || (f->fix_scale != INOUT && 
is_subtypeof(tp, ft))) {
+                                       if (!cand) {
+                                               cand = f;
+                                               points = tp->type->eclass == 
ft->type->eclass;
+                                       } else if ((npoints = tp->type->eclass 
== ft->type->eclass) > points) {
+                                               cand = f;
+                                               points = npoints;
+                                       }
+                               }
                        }
                }
        }
+       if (cand)
+               return (type == F_AGGR) ? _dup_subaggr(sql->sa, cand, NULL) : 
sql_dup_subfunc(sql->sa, cand, NULL, tp);
        return NULL;
 }
 
 static sql_subfunc *
 os_bind_member_internal(mvc *sql, struct objectset *ff, const char *fname, 
sql_subtype *tp, sql_ftype type, int nrargs, sql_subfunc *prev)
 {
+       sql_func *cand = NULL;
+       int points = 0, npoints = 0;
+
        assert(nrargs);
        if (ff) {
                struct os_iter oi;
@@ -458,11 +473,20 @@ os_bind_member_internal(mvc *sql, struct
                                continue;
                        if (strcmp(f->base.name, fname) == 0 && f->type == type 
&& list_length(f->ops) == nrargs) {
                                sql_subtype *ft = &((sql_arg *) 
f->ops->h->data)->type;
-                               if ((f->fix_scale == INOUT && 
type_cmp(tp->type, ft->type) == 0) || (f->fix_scale != INOUT && 
is_subtypeof(tp, ft)))
-                                       return (type == F_AGGR) ? 
_dup_subaggr(sql->sa, f, NULL) : sql_dup_subfunc(sql->sa, f, NULL, tp);
+                               if ((f->fix_scale == INOUT && 
type_cmp(tp->type, ft->type) == 0) || (f->fix_scale != INOUT && 
is_subtypeof(tp, ft))) {
+                                       if (!cand) {
+                                               cand = f;
+                                               points = tp->type->eclass == 
ft->type->eclass;
+                                       } else if ((npoints = tp->type->eclass 
== ft->type->eclass) > points) {
+                                               cand = f;
+                                               points = npoints;
+                                       }
+                               }
                        }
                }
        }
+       if (cand)
+               return (type == F_AGGR) ? _dup_subaggr(sql->sa, cand, NULL) : 
sql_dup_subfunc(sql->sa, cand, NULL, tp);
        return NULL;
 }
 
@@ -513,26 +537,53 @@ sql_bind_func3(mvc *sql, const char *sna
        return sql_bind_func_(sql, sname, fname, l, type);
 }
 
+static int /* bind the function version with more identical type matches */
+next_cand_points(list *args, list *ops)
+{
+       int res = 0;
+
+       if (!list_empty(args) && !list_empty(ops))
+       for (node *n = args->h, *m = ops->h; n && m ; n = n->next, m = m->next) 
{
+               sql_arg *a = n->data;
+               sql_subtype *t = m->data;
+
+               if (t)
+                       res += a->type.type->base.id == t->type->base.id;
+       }
+       return res;
+}
+
 static sql_subfunc *
 sql_bind_func__(mvc *sql, list *ff, const char *fname, list *ops, sql_ftype 
type)
 {
        sql_ftype filt = (type == F_FUNC)?F_FILT:type;
        sql_subtype *input_type = NULL;
+       sql_func *cand = NULL;
+       int points = 0, npoints = 0;
 
        if (ops && ops->h)
                input_type = ops->h->data;
 
        if (ff) {
                node *n;
-               sql_base_loop( ff, n) {
+               sql_base_loop(ff, n) {
                        sql_func *f = n->data;
 
                        if (f->type != type && f->type != filt)
                                continue;
-                       if (strcmp(f->base.name, fname) == 0 && 
list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0)
-                               return (type == F_AGGR) ? _dup_subaggr(sql->sa, 
f, input_type) : sql_dup_subfunc(sql->sa, f, ops, NULL);
+                       if (strcmp(f->base.name, fname) == 0 && 
list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0) {
+                               if (!cand) {
+                                       cand = f;
+                                       points = next_cand_points(f->ops, ops);
+                               } else if ((npoints = next_cand_points(f->ops, 
ops)) > points) {
+                                       cand = f;
+                                       points = npoints;
+                               }
+                       }
                }
        }
+       if (cand)
+               return (type == F_AGGR) ? _dup_subaggr(sql->sa, cand, 
input_type) : sql_dup_subfunc(sql->sa, cand, ops, NULL);
        return NULL;
 }
 
@@ -541,6 +592,8 @@ os_bind_func__(mvc *sql, struct objectse
 {
        sql_ftype filt = (type == F_FUNC)?F_FILT:type;
        sql_subtype *input_type = NULL;
+       sql_func *cand = NULL;
+       int points = 0, npoints = 0;
 
        if (ops && ops->h)
                input_type = ops->h->data;
@@ -553,10 +606,19 @@ os_bind_func__(mvc *sql, struct objectse
 
                        if (f->type != type && f->type != filt)
                                continue;
-                       if (strcmp(f->base.name, fname) == 0 && 
list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0)
-                               return (type == F_AGGR) ? _dup_subaggr(sql->sa, 
f, input_type) : sql_dup_subfunc(sql->sa, f, ops, NULL);
+                       if (strcmp(f->base.name, fname) == 0 && 
list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0) {
+                               if (!cand) {
+                                       cand = f;
+                                       points = next_cand_points(f->ops, ops);
+                               } else if ((npoints = next_cand_points(f->ops, 
ops)) > points) {
+                                       cand = f;
+                                       points = npoints;
+                               }
+                       }
                }
        }
+       if (cand)
+               return (type == F_AGGR) ? _dup_subaggr(sql->sa, cand, 
input_type) : sql_dup_subfunc(sql->sa, cand, ops, NULL);
        return NULL;
 }
 
@@ -584,6 +646,8 @@ static sql_subfunc *
 sql_bind_func_result_internal(mvc *sql, list *ff, const char *fname, sql_ftype 
type, list *ops, sql_subtype *res)
 {
        sql_subtype *tp = sql_bind_localtype("bit");
+       sql_func *cand = NULL;
+       int points = 0, npoints = 0;
 
        if (ff) {
                node *n;
@@ -594,10 +658,19 @@ sql_bind_func_result_internal(mvc *sql, 
                        if (!f->res && !IS_FILT(f))
                                continue;
                        firstres = IS_FILT(f)?tp->type:f->res->h->data;
-                       if (strcmp(f->base.name, fname) == 0 && f->type == type 
&& (is_subtype(&firstres->type, res) || firstres->type.type->eclass == EC_ANY) 
&& list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0)
-                               return (type == F_AGGR) ? _dup_subaggr(sql->sa, 
f, NULL) : sql_dup_subfunc(sql->sa, f, ops, NULL);
+                       if (strcmp(f->base.name, fname) == 0 && f->type == type 
&& (is_subtype(&firstres->type, res) || firstres->type.type->eclass == EC_ANY) 
&& list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0) {
+                               if (!cand) {
+                                       cand = f;
+                                       points = next_cand_points(f->ops, ops);
+                               } else if ((npoints = next_cand_points(f->ops, 
ops)) > points) {
+                                       cand = f;
+                                       points = npoints;
+                               }
+                       }
                }
        }
+       if (cand)
+               return (type == F_AGGR) ? _dup_subaggr(sql->sa, cand, NULL) : 
sql_dup_subfunc(sql->sa, cand, ops, NULL);
        return NULL;
 }
 
@@ -605,6 +678,8 @@ static sql_subfunc *
 os_bind_func_result_internal(mvc *sql, struct objectset *ff, const char 
*fname, sql_ftype type, list *ops, sql_subtype *res)
 {
        sql_subtype *tp = sql_bind_localtype("bit");
+       sql_func *cand = NULL;
+       int points = 0, npoints = 0;
 
        if (ff) {
                struct os_iter oi;
@@ -616,10 +691,19 @@ os_bind_func_result_internal(mvc *sql, s
                        if (!f->res && !IS_FILT(f))
                                continue;
                        firstres = IS_FILT(f)?tp->type:f->res->h->data;
-                       if (strcmp(f->base.name, fname) == 0 && f->type == type 
&& (is_subtype(&firstres->type, res) || firstres->type.type->eclass == EC_ANY) 
&& list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0)
-                               return (type == F_AGGR) ? _dup_subaggr(sql->sa, 
f, NULL) : sql_dup_subfunc(sql->sa, f, ops, NULL);
+                       if (strcmp(f->base.name, fname) == 0 && f->type == type 
&& (is_subtype(&firstres->type, res) || firstres->type.type->eclass == EC_ANY) 
&& list_cmp(f->ops, ops, (fcmp) &arg_subtype_cmp) == 0) {
+                               if (!cand) {
+                                       cand = f;
+                                       points = next_cand_points(f->ops, ops);
+                               } else if ((npoints = next_cand_points(f->ops, 
ops)) > points) {
+                                       cand = f;
+                                       points = npoints;
+                               }
+                       }
                }
        }
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to