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

Reply via email to