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