Changeset: 138edc282dba for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=138edc282dba Modified Files: sql/common/sql_types.c sql/common/sql_types.h sql/include/sql_catalog.h sql/server/rel_select.c sql/server/sql_semantic.c sql/test/SQLancer/Tests/sqlancer10.test sql/test/pg_regress/Tests/path.test Branch: default Log Message:
When a function is bound by the number of parameters instead of the parameter types, always compute the supertype. Fixed number of digits propagation for char and varchar types on these cases diffs (truncated from 340 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 @@ -87,6 +87,37 @@ unsigned int bits2digits(unsigned int bi #endif } +unsigned int type_digits_to_char_digits(sql_subtype *t) +{ + if (!t) + return 0; + switch (t->type->eclass) { + case EC_BIT: + return 1; + case EC_POS: + case EC_NUM: + case EC_MONTH: + return bits2digits(t->digits) + 1; /* add '-' */ + case EC_FLT: + return bits2digits(t->digits) + 2; /* TODO for floating-points maybe more is needed */ + case EC_DEC: + case EC_SEC: + return t->digits + 2; /* add '-' and '.' */ + case EC_TIMESTAMP: + case EC_TIMESTAMP_TZ: + return 40; /* TODO this needs more tunning */ + case EC_TIME: + case EC_TIME_TZ: + return 20; /* TODO this needs more tunning */ + case EC_DATE: + return 20; /* TODO this needs more tunning */ + case EC_BLOB: + return t->digits * 2; /* TODO BLOBs don't have digits, so this is wrong */ + default: + return t->digits; /* What to do with EC_GEOM? */ + } +} + /* 0 cannot convert */ /* 1 set operations have very limited coersion rules */ /* 2 automatic coersion (could still require dynamic checks for overflow) */ diff --git a/sql/common/sql_types.h b/sql/common/sql_types.h --- a/sql/common/sql_types.h +++ b/sql/common/sql_types.h @@ -23,6 +23,7 @@ extern list *funcs; extern unsigned int bits2digits(unsigned int b); extern unsigned int digits2bits(unsigned int d); +extern unsigned int type_digits_to_char_digits(sql_subtype *t); extern int sql_type_convert(int form, int to); /* return 1, convert possible but it's a down cast, 2 convert possible can be done savely */ extern bool is_commutative(const char *fnm); /* return true if commutative */ diff --git a/sql/include/sql_catalog.h b/sql/include/sql_catalog.h --- a/sql/include/sql_catalog.h +++ b/sql/include/sql_catalog.h @@ -85,7 +85,6 @@ typedef enum sql_dependency { #define DIGITS_ADD 5 /* some types grow under functions (concat) */ #define INOUT 6 /* output type equals input type */ #define SCALE_EQ 7 /* user defined functions need equal scales */ -#define SCALE_DIGITS_FIX 8 /* the geom module requires the types and functions to have the same scale and digits */ /* Warning TR flags is a bitmask */ #define TR_NEW 1 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 @@ -449,7 +449,8 @@ 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; + 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) { @@ -471,10 +472,12 @@ check_arguments_and_find_largest_any_typ 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; + 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->sqlname, "char") || !strcmp(a->type.type->sqlname, "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) { @@ -482,10 +485,28 @@ check_arguments_and_find_largest_any_typ 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->sqlname, "char") || !strcmp(res->type->sqlname, "varchar"))) { + unsigned int tdigits = type_digits_to_char_digits(t); + if (sf->func->fix_scale == DIGITS_ADD) { + rdigits += tdigits; + if (rdigits >= (unsigned int) INT_MAX) + return sql_error(sql, 02, SQLSTATE(42000) "SELECT: output number of digits for %s is too large", sf->func->base.name); + } else if (sf->func->fix_scale == INOUT && 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 && sf->res && atp) - sf->res->h->data = sql_create_subtype(sql->sa, atp->type, atp->digits, atp->scale); + 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->sqlname, "char") || !strcmp(res->type->sqlname, "varchar"))) + res->digits = rdigits; + } return nexps; } @@ -2702,9 +2723,8 @@ rel_op(sql_query *query, sql_rel **rel, dnode *l = se->data.lval->h; char *fname = qname_schema_object(l->data.lval); char *sname = qname_schema(l->data.lval); - sql_subfunc *sf = NULL; - - if ((sf = find_func(sql, sname, fname, 0, F_AGGR, NULL))) + + if (find_func(sql, sname, fname, 0, F_AGGR, NULL)) return _rel_aggr(query, rel, 0, sname, fname, NULL, f); sql->session->status = 0; /* if the function was not found clean the error */ sql->errstr[0] = '\0'; @@ -2759,16 +2779,14 @@ rel_unop_(mvc *sql, sql_rel *rel, sql_ex sql->session->status = 0; /* if the function was not found clean the error */ sql->errstr[0] = '\0'; while ((f = find_func(sql, sname, fname, 1, type, f)) != NULL && check_card(card, f)) { - sql_exp *oe = e; - - if (!f->func->vararg) { - sql_arg *a = f->func->ops->h->data; - - e = exp_check_type(sql, &a->type, rel, e, type_equal); + list *args = list_append(sa_list(sql->sa), e); + + if (!f->func->vararg) + args = check_arguments_and_find_largest_any_type(sql, rel, args, f, card == card_relation && e->card > CARD_ATOM); + if (args) { + e = args->h->data; + break; } - if (e) - break; - e = oe; /* reset error */ sql->session->status = 0; @@ -2781,24 +2799,15 @@ rel_unop_(mvc *sql, sql_rel *rel, sql_ex res->digits = t->digits; res->scale = t->scale; } - if (card == card_relation && 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)); - } return exp_unop(sql->sa, e, f); - } else if (e) { - if (t) { - char *type = t->type->sqlname; - - return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: no such unary operator %s%s%s'%s'(%s)", - sname ? "'":"", sname ? sname : "", sname ? "'.":"", fname, type); - } else { - return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: no such unary operator %s%s%s'%s'(?)", - sname ? "'":"", sname ? sname : "", sname ? "'.":"", fname); - } - } - return NULL; + } + if ((t = exp_subtype(e))) { + char *type = t->type->sqlname; + return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: no such unary operator %s%s%s'%s'(%s)", + sname ? "'":"", sname ? sname : "", sname ? "'.":"", fname, type); + } + return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42000) "SELECT: no such unary operator %s%s%s'%s'(?)", + sname ? "'":"", sname ? sname : "", sname ? "'.":"", fname); } static sql_exp * @@ -2810,9 +2819,8 @@ rel_unop(sql_query *query, sql_rel **rel char *sname = qname_schema(l->data.lval); exp_kind iek = {type_value, card_column, FALSE}; sql_exp *e = NULL; - sql_subfunc *sf = NULL; - - if ((sf = find_func(sql, sname, fname, 1, F_AGGR, NULL))) + + if (find_func(sql, sname, fname, 1, F_AGGR, NULL)) return rel_aggr(query, rel, se, f); sql->session->status = 0; /* if the function was not found clean the error */ @@ -3089,17 +3097,11 @@ rel_binop_(mvc *sql, sql_rel *rel, sql_e r = or; /* everything failed, fall back to bind on function name only */ if ((f = find_func(sql, sname, fname, 2, type, NULL)) != NULL && check_card(card,f)) { - - if (!f->func->vararg) { - node *m = f->func->ops->h; - sql_arg *a = m->data; - - l = exp_check_type(sql, &a->type, rel, l, type_equal); - a = m->next->data; - r = exp_check_type(sql, &a->type, rel, r, type_equal); - } - if (l && r) - return exp_binop(sql->sa, l, r, f); + list *args = list_append(list_append(sa_list(sql->sa), l), r); + if (!f->func->vararg) + args = check_arguments_and_find_largest_any_type(sql, rel, args, f, 0); + if (args) + return exp_op(sql->sa, args, f); } /* reset error */ sql->session->status = 0; @@ -3122,9 +3124,8 @@ rel_binop(sql_query *query, sql_rel **re char *fname = qname_schema_object(dl->data.lval); char *sname = qname_schema(dl->data.lval); exp_kind iek = {type_value, card_column, FALSE}; - sql_subfunc *sf = NULL; - - if ((sf = find_func(sql, sname, fname, 2, F_AGGR, NULL))) + + if (find_func(sql, sname, fname, 2, F_AGGR, NULL)) return rel_aggr(query, rel, se, f); sql->session->status = 0; /* if the function was not found clean the error */ @@ -3165,7 +3166,6 @@ rel_nop(sql_query *query, sql_rel **rel, dnode *l = se->data.lval->h; dnode *ops = l->next->next->data.lval?l->next->next->data.lval->h:NULL; list *exps = sa_list(sql->sa), *tl = sa_list(sql->sa); - sql_subfunc *sf = NULL; exp_kind iek = {type_value, card_column, FALSE}; char buf[ERRSIZE]; @@ -3223,8 +3223,7 @@ rel_nop(sql_query *query, sql_rel **rel, char *sname = qname_schema(l->data.lval); /* first try aggregate */ - sf = find_func(sql, sname, fname, nr_args, F_AGGR, NULL); - if (sf) { /* We have to pas the arguments properly, so skip call to rel_aggr */ + if (find_func(sql, sname, fname, nr_args, F_AGGR, NULL)) { /* We have to pass the arguments properly, so skip call to rel_aggr */ /* reset error */ sql->session->status = 0; sql->errstr[0] = '\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 @@ -1026,7 +1026,6 @@ supertype(sql_subtype *super, sql_subtyp { /* first find super type */ char *tpe = r->type->sqlname; - sql_class eclass = r->type->eclass; unsigned int radix = (unsigned int) r->type->radix; unsigned int digits = 0; unsigned int idigits = i->digits; @@ -1041,14 +1040,11 @@ supertype(sql_subtype *super, sql_subtyp lsuper = *i; radix = i->type->radix; tpe = i->type->sqlname; - eclass = i->type->eclass; } if (EC_VARCHAR(lsuper.type->eclass)) scale = 0; /* strings don't have scale */ - if (!lsuper.type->localtype) { + if (!lsuper.type->localtype) tpe = "smallint"; - eclass = EC_NUM; - } /* * In case of different radix we should change one. */ @@ -1067,27 +1063,16 @@ supertype(sql_subtype *super, sql_subtyp } } /* handle OID horror */ - if (i->type->radix == r->type->radix && i->type->base.id < r->type->base.id && strcmp(i->type->sqlname, "oid") == 0) { + if (i->type->radix == r->type->radix && i->type->base.id < r->type->base.id && strcmp(i->type->sqlname, "oid") == 0) tpe = i->type->sqlname; - eclass = i->type->eclass; - } - if (scale == 0 && (idigits == 0 || rdigits == 0)) { /* clob falls here */ + if (scale == 0 && (idigits == 0 || rdigits == 0 || !strcmp(tpe, "clob"))) { /* clob falls here */ sql_find_subtype(&lsuper, tpe, 0, 0); } else { /* for strings use the max of both */ - if (eclass == EC_CHAR) { - if (i->type->eclass == EC_NUM) - idigits++; /* add '-' */ - else if (i->type->eclass == EC_DEC || i->type->eclass == EC_FLT) _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list