Changeset: c366d197e95d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=c366d197e95d
Modified Files:
        sql/common/sql_types.c
        sql/server/rel_optimizer.c
        sql/storage/store.c
        sql/test/BugTracker-2016/Tests/case-column-when-null-Bug-6124.stable.out
        
sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
        sql/test/BugTracker-2019/Tests/count-distinct.Bug-6790.stable.out
        sql/test/miscellaneous/Tests/simple_selects.stable.out
Branch: oscar
Log Message:

Revising NULL semantics functions.

=,<>,between,avg,sql_neg,not_(i)like functions don't have NULL semantics, ie if 
one their arguments is a NULL constant, their ouput is NULL.
least,greatest,and functions have NULL semantics, as they may not produce NULL 
on certain ocasions: and(false,NULL) -> false, least(1,null) -> 1

Also make sure the "semantics" flag is propagated at func_dup and func_reset.

Added optimization when one of the paramenters for a functions without NULL 
semantics is NULL, replace it with a NULL constant.


diffs (truncated from 310 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
@@ -1273,15 +1273,15 @@ sqltypeinit( sql_allocator *sa)
        /* functions needed for all types */
        sql_create_func(sa, "hash", "mkey", "hash", TRUE, FALSE, SCALE_FIX, 0, 
LNG, 1, ANY);
        sql_create_func(sa, "rotate_xor_hash", "calc", "rotate_xor_hash", TRUE, 
FALSE, SCALE_NONE, 0, LNG, 3, LNG, INT, ANY);
-       sql_create_func(sa, "=", "calc", "=", TRUE, FALSE, SCALE_FIX, 0, BIT, 
2, ANY, ANY);
-       sql_create_func(sa, "<>", "calc", "!=", TRUE, FALSE, SCALE_FIX, 0, BIT, 
2, ANY, ANY);
+       sql_create_func(sa, "=", "calc", "=", FALSE, FALSE, SCALE_FIX, 0, BIT, 
2, ANY, ANY);
+       sql_create_func(sa, "<>", "calc", "!=", FALSE, FALSE, SCALE_FIX, 0, 
BIT, 2, ANY, ANY);
        sql_create_func(sa, "isnull", "calc", "isnil", TRUE, FALSE, SCALE_FIX, 
0, BIT, 1, ANY);
        sql_create_func(sa, "isnotnull", "calc", "isnotnil", TRUE, FALSE, 
SCALE_FIX, 0, BIT, 1, ANY);
        sql_create_func(sa, ">", "calc", ">", FALSE, FALSE, SCALE_FIX, 0, BIT, 
2, ANY, ANY);
        sql_create_func(sa, ">=", "calc", ">=", FALSE, FALSE, SCALE_FIX, 0, 
BIT, 2, ANY, ANY);
        sql_create_func(sa, "<", "calc", "<", FALSE, FALSE, SCALE_FIX, 0, BIT, 
2, ANY, ANY);
        sql_create_func(sa, "<=", "calc", "<=", FALSE, FALSE, SCALE_FIX, 0, 
BIT, 2, ANY, ANY);
-       sql_create_func(sa, "between", "calc", "between", TRUE, FALSE, 
SCALE_FIX, 0, BIT, 8, ANY, ANY, ANY, BIT, BIT, BIT, BIT, BIT);
+       sql_create_func(sa, "between", "calc", "between", FALSE, FALSE, 
SCALE_FIX, 0, BIT, 8, ANY, ANY, ANY, BIT, BIT, BIT, BIT, BIT);
        sql_create_aggr(sa, "zero_or_one", "aggr", "zero_or_one", TRUE, ANY, 1, 
ANY);
        sql_create_aggr(sa, "all", "aggr", "all", TRUE, ANY, 1, ANY);
        sql_create_aggr(sa, "null", "aggr", "null", TRUE, BIT, 1, ANY);
@@ -1304,8 +1304,8 @@ sqltypeinit( sql_allocator *sa)
        sql_create_aggr(sa, "max", "aggr", "max", FALSE, ANY, 1, ANY);
        sql_create_func(sa, "sql_min", "calc", "min", FALSE, FALSE, SCALE_FIX, 
0, ANY, 2, ANY, ANY);
        sql_create_func(sa, "sql_max", "calc", "max", FALSE, FALSE, SCALE_FIX, 
0, ANY, 2, ANY, ANY);
-       sql_create_func(sa, "least", "calc", "min_no_nil", FALSE, FALSE, 
SCALE_FIX, 0, ANY, 2, ANY, ANY);
-       sql_create_func(sa, "greatest", "calc", "max_no_nil", FALSE, FALSE, 
SCALE_FIX, 0, ANY, 2, ANY, ANY);
+       sql_create_func(sa, "least", "calc", "min_no_nil", TRUE, FALSE, 
SCALE_FIX, 0, ANY, 2, ANY, ANY);
+       sql_create_func(sa, "greatest", "calc", "max_no_nil", TRUE, FALSE, 
SCALE_FIX, 0, ANY, 2, ANY, ANY);
        sql_create_func(sa, "ifthenelse", "calc", "ifthenelse", TRUE, FALSE, 
SCALE_FIX, 0, ANY, 3, BIT, ANY, ANY);
        /* nullif and coalesce don't have a backend implementation */
        sql_create_func(sa, "nullif", "", "", TRUE, FALSE, SCALE_FIX, 0, ANY, 
2, ANY, ANY);
@@ -1346,16 +1346,16 @@ sqltypeinit( sql_allocator *sa)
 #if 0
        /* prod for decimals introduce errors in the output scales */
        t = decimals; /* BTE */
-       sql_create_aggr(sa, "prod", "aggr", "prod", TRUE, LargestDEC, 1, *(t));
+       sql_create_aggr(sa, "prod", "aggr", "prod", FALSE, LargestDEC, 1, *(t));
        t++; /* SHT */
-       sql_create_aggr(sa, "prod", "aggr", "prod", TRUE, LargestDEC, 1, *(t));
+       sql_create_aggr(sa, "prod", "aggr", "prod", FALSE, LargestDEC, 1, *(t));
        t++; /* INT */
-       sql_create_aggr(sa, "prod", "aggr", "prod", TRUE, LargestDEC, 1, *(t));
+       sql_create_aggr(sa, "prod", "aggr", "prod", FALSE, LargestDEC, 1, *(t));
        t++; /* LNG */
-       sql_create_aggr(sa, "prod", "aggr", "prod", TRUE, LargestDEC, 1, *(t));
+       sql_create_aggr(sa, "prod", "aggr", "prod", FALSE, LargestDEC, 1, *(t));
 #ifdef HAVE_HGE
        t++; /* HGE */
-       sql_create_aggr(sa, "prod", "aggr", "prod", TRUE, LargestDEC, 1, *(t));
+       sql_create_aggr(sa, "prod", "aggr", "prod", FALSE, LargestDEC, 1, *(t));
 #endif
 #endif
 
@@ -1371,31 +1371,31 @@ sqltypeinit( sql_allocator *sa)
        sql_create_aggr(sa, "sum", "aggr", "sum", FALSE, SECINT, 1, SECINT);
        /* do DBL first so that it is chosen as cast destination for
         * unknown types */
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, DBL);
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, BTE);
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, SHT);
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, INT);
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, LNG);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, DBL);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, BTE);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, SHT);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, INT);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, LNG);
 #ifdef HAVE_HGE
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, HGE);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, HGE);
 #endif
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, DBL, 1, FLT);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, DBL, 1, FLT);
 
        t = decimals; /* BTE */
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, *(t), 1, *(t));
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, *(t), 1, *(t));
        t++; /* SHT */
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, *(t), 1, *(t));
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, *(t), 1, *(t));
        t++; /* INT */
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, *(t), 1, *(t));
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, *(t), 1, *(t));
        t++; /* LNG */
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, *(t), 1, *(t));
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, *(t), 1, *(t));
 #ifdef HAVE_HGE
        t++; /* HGE */
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, *(t), 1, *(t));
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, *(t), 1, *(t));
 #endif
 
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, MONINT, 1, MONINT);
-       sql_create_aggr(sa, "avg", "aggr", "avg", TRUE, SECINT, 1, SECINT);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, MONINT, 1, MONINT);
+       sql_create_aggr(sa, "avg", "aggr", "avg", FALSE, SECINT, 1, SECINT);
 
        sql_create_aggr(sa, "count_no_nil", "aggr", "count_no_nil", TRUE, LNG, 
0);
        sql_create_aggr(sa, "count", "aggr", "count", TRUE, LNG, 1, ANY);
@@ -1591,11 +1591,10 @@ sqltypeinit( sql_allocator *sa)
        sql_create_analytic(sa, "avg", "sql", "avg", SCALE_NONE, MONINT, 1, 
MONINT);
        sql_create_analytic(sa, "avg", "sql", "avg", SCALE_NONE, SECINT, 1, 
SECINT);
 
-
        sql_create_analytic(sa, "listagg", "sql", "str_group_concat", 
SCALE_NONE, STR, 1, STR);
        sql_create_analytic(sa, "listagg", "sql", "str_group_concat", 
SCALE_NONE, STR, 2, STR, STR);
 
-       sql_create_func(sa, "and", "calc", "and", FALSE, FALSE, SCALE_FIX, 0, 
BIT, 2, BIT, BIT);
+       sql_create_func(sa, "and", "calc", "and", TRUE, FALSE, SCALE_FIX, 0, 
BIT, 2, BIT, BIT);
        sql_create_func(sa, "or",  "calc",  "or", TRUE, FALSE, SCALE_FIX, 0, 
BIT, 2, BIT, BIT);
        sql_create_func(sa, "xor", "calc", "xor", FALSE, FALSE, SCALE_FIX, 0, 
BIT, 2, BIT, BIT);
        sql_create_func(sa, "not", "calc", "not", FALSE, FALSE, SCALE_FIX, 0, 
BIT, 1, BIT);
@@ -1640,7 +1639,7 @@ sqltypeinit( sql_allocator *sa)
                        sql_create_func(sa, "left_shift", "calc", "<<", FALSE, 
FALSE, SCALE_FIX, 0, *t, 2, *t, INT);
                        sql_create_func(sa, "right_shift", "calc", ">>", FALSE, 
FALSE, SCALE_FIX, 0, *t, 2, *t, INT);
                }
-               sql_create_func(sa, "sql_neg", "calc", "-", TRUE, FALSE, INOUT, 
0, *t, 1, *t);
+               sql_create_func(sa, "sql_neg", "calc", "-", FALSE, FALSE, 
INOUT, 0, *t, 1, *t);
                sql_create_func(sa, "abs", "calc", "abs", FALSE, FALSE, 
SCALE_FIX, 0, *t, 1, *t);
                sql_create_func(sa, "sign", "calc", "sign", FALSE, FALSE, 
SCALE_NONE, 0, BTE, 1, *t);
                /* scale fixing for all numbers */
@@ -1814,12 +1813,12 @@ sqltypeinit( sql_allocator *sa)
                sql_create_func(sa, "ilike", "algebra", "ilike", FALSE, 
SCALE_NONE, 0, BIT, 2, *t, *t);
                sql_create_func3(sa, "ilike", "algebra", "ilike", FALSE, 
SCALE_NONE, 0, BIT, 3, *t, *t, *t);
                */
-               sql_create_func(sa, "not_like", "algebra", "not_like", TRUE, 
FALSE, SCALE_NONE, 0, BIT, 2, *t, *t);
-               sql_create_func(sa, "not_like", "algebra", "not_like", TRUE, 
FALSE, SCALE_NONE, 0, BIT, 3, *t, *t, *t);
-               sql_create_func(sa, "not_ilike", "algebra", "not_ilike", TRUE, 
FALSE, SCALE_NONE, 0, BIT, 2, *t, *t);
-               sql_create_func(sa, "not_ilike", "algebra", "not_ilike", TRUE, 
FALSE, SCALE_NONE, 0, BIT, 3, *t, *t, *t);
+               sql_create_func(sa, "not_like", "algebra", "not_like", FALSE, 
FALSE, SCALE_NONE, 0, BIT, 2, *t, *t);
+               sql_create_func(sa, "not_like", "algebra", "not_like", FALSE, 
FALSE, SCALE_NONE, 0, BIT, 3, *t, *t, *t);
+               sql_create_func(sa, "not_ilike", "algebra", "not_ilike", FALSE, 
FALSE, SCALE_NONE, 0, BIT, 2, *t, *t);
+               sql_create_func(sa, "not_ilike", "algebra", "not_ilike", FALSE, 
FALSE, SCALE_NONE, 0, BIT, 3, *t, *t, *t);
 
-               sql_create_func(sa, "patindex", "pcre", "patindex", TRUE, 
FALSE, SCALE_NONE, 0, INT, 2, *t, *t);
+               sql_create_func(sa, "patindex", "pcre", "patindex", FALSE, 
FALSE, SCALE_NONE, 0, INT, 2, *t, *t);
                sql_create_func(sa, "truncate", "str", "stringleft", FALSE, 
FALSE, SCALE_NONE, 0, *t, 2, *t, INT);
                sql_create_func(sa, "concat", "calc", "+", FALSE, FALSE, 
DIGITS_ADD, 0, *t, 2, *t, *t);
                sql_create_func(sa, "ascii", "str", "ascii", FALSE, FALSE, 
SCALE_NONE, 0, INT, 1, *t);
diff --git a/sql/server/rel_optimizer.c b/sql/server/rel_optimizer.c
--- a/sql/server/rel_optimizer.c
+++ b/sql/server/rel_optimizer.c
@@ -2899,51 +2899,47 @@ exp_simplify_math( mvc *sql, sql_exp *e,
                if (list_length(l) < 1)
                        return e;
 
-               le = l->h->data;
-               if (!exp_subtype(le) || 
(!EC_COMPUTE(exp_subtype(le)->type->eclass) && exp_subtype(le)->type->eclass != 
EC_DEC))
-                       return e;
-
-               if (!f->func->s && list_length(l) == 2) {
+               /* if the function has no null semantics we can return NULL if 
one of the arguments is NULL */
+               if (!f->func->semantics && f->func->type != F_PROC) {
+                       for (node *n = l->h ; n ; n = n->next) {
+                               sql_exp *arg = n->data;
+
+                               if (exp_is_atom(arg) && exp_is_null(sql, arg)) {
+                                       sql_exp *ne = exp_null(sql->sa, 
exp_subtype(e));
+                                       (*changes)++;
+                                       if (exp_name(e))
+                                               exp_prop_alias(sql->sa, ne, e);
+                                       return ne;
+                               }
+                       }
+               }
+               if (!f->func->s && list_length(l) == 2 && strstr(f->func->imp, 
"_no_nil") != NULL) {
                        sql_exp *le = l->h->data;
                        sql_exp *re = l->h->next->data;
-                       sql_subtype *et = exp_subtype(e);
-
-                       /* if one argument is NULL, return it, EXCEPT
-                        * if "_no_nil" is in the name of the
+
+                       /* if "_no_nil" is in the name of the
                         * implementation function (currently either
                         * min_no_nil or max_no_nil), in which case we
-                        * ignore the NULL and return the other
-                        * value */
-
-                       /* for both nullif and coalesce don't rewrite the NULL 
handling */
-                       if (f && f->func && f->func->imp && 
strcmp(f->func->imp, "") == 0)
-                               return e;
+                        * ignore the NULL and return the other value */
 
                        if (exp_is_atom(le) && exp_is_null(sql, le)) {
                                (*changes)++;
-                               if (f && f->func && f->func->imp && 
strstr(f->func->imp, "_no_nil") != NULL) {
-                                       if (exp_name(e))
-                                               exp_prop_alias(sql->sa, re, e);
-                                       return re;
-                               }
-                               le = exp_null(sql->sa, et);
                                if (exp_name(e))
-                                       exp_prop_alias(sql->sa, le, e);
-                               return le;
+                                       exp_prop_alias(sql->sa, re, e);
+                               return re;
                        }
                        if (exp_is_atom(re) && exp_is_null(sql, re)) {
                                (*changes)++;
-                               if (f && f->func && f->func->imp && 
strstr(f->func->imp, "_no_nil") != NULL) {
-                                       if (exp_name(e))
-                                               exp_prop_alias(sql->sa, le, e);
-                                       return le;
-                               }
-                               re = exp_null(sql->sa, et);
                                if (exp_name(e))
-                                       exp_prop_alias(sql->sa, re, e);
-                               return re;
-                       }
-               }
+                                       exp_prop_alias(sql->sa, le, e);
+                               return le;
+                       }
+               }
+
+               le = l->h->data;
+               if (!EC_COMPUTE(exp_subtype(le)->type->eclass) && 
exp_subtype(le)->type->eclass != EC_DEC)
+                       return e;
+
                if (!f->func->s && !strcmp(f->func->base.name, "sql_mul") && 
list_length(l) == 2) {
                        sql_exp *le = l->h->data;
                        sql_exp *re = l->h->next->data;
diff --git a/sql/storage/store.c b/sql/storage/store.c
--- a/sql/storage/store.c
+++ b/sql/storage/store.c
@@ -3660,6 +3660,7 @@ func_dup(sql_trans *tr, int flags, sql_f
        f->ops = list_new(sa, of->ops->destroy);
        f->fix_scale = of->fix_scale;
        f->system = of->system;
+       f->semantics = of->semantics;
        for (n=of->ops->h; n; n = n->next)
                list_append(f->ops, arg_dup(newFlagSet(flags)?tr->parent:tr, s, 
n->data));
        if (of->res) {
@@ -4782,7 +4783,7 @@ reset_func(sql_trans *tr, sql_func *ff, 
                ff->res = pff->res;
                ff->fix_scale = pff->fix_scale;
                ff->system = pff->system;
-               ff->ops = pff->ops;
+               ff->semantics = pff->semantics;
                ff->s = find_sql_schema(tr, pff->s->base.name);
                ff->sa = tr->sa;
        }
diff --git 
a/sql/test/BugTracker-2016/Tests/case-column-when-null-Bug-6124.stable.out 
b/sql/test/BugTracker-2016/Tests/case-column-when-null-Bug-6124.stable.out
--- a/sql/test/BugTracker-2016/Tests/case-column-when-null-Bug-6124.stable.out
+++ b/sql/test/BugTracker-2016/Tests/case-column-when-null-Bug-6124.stable.out
@@ -88,7 +88,7 @@ stdout of test 'case-column-when-null-Bu
 [ 2,   1       ]
 [ NULL,        0       ]
 #SELECT this_column, (CASE this_column WHEN NULL THEN 0 ELSE 1 END) AS 
new_column FROM table_two;
-% sys.table_two,       sys. # table_name
+% sys.table_two,       . # table_name
 % this_column, new_column # name
 % int, tinyint # type
 % 1,   1 # length
diff --git 
a/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
 
b/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
--- 
a/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
+++ 
b/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
@@ -73,7 +73,7 @@ stdout of test 'sqlitelogictest-cast-nul
 [ NULL ]
 #SELECT ALL CAST ( col1 / - - ( + CAST ( NULL AS INTEGER ) ) AS BIGINT ) col0,
 #           CAST ( 39 + + + CAST ( NULL AS INTEGER ) + + - 10 + col1 / - col0 
AS BIGINT ) AS col1 FROM tab2;
-% sys.,        . # table_name
+% .,   . # table_name
 % col0,        col1 # name
 % bigint,      bigint # type
 % 1,   1 # length
diff --git a/sql/test/BugTracker-2019/Tests/count-distinct.Bug-6790.stable.out 
b/sql/test/BugTracker-2019/Tests/count-distinct.Bug-6790.stable.out
--- a/sql/test/BugTracker-2019/Tests/count-distinct.Bug-6790.stable.out
+++ b/sql/test/BugTracker-2019/Tests/count-distinct.Bug-6790.stable.out
@@ -90,14 +90,14 @@ stdout of test 'count-distinct.Bug-6790`
 % 4 # length
 [ 3823 ]
 #SELECT CAST(72 + - + COUNT ( * ) - - - COUNT ( DISTINCT + ( - 2 ) ) * + + 57 
AS BIGINT) FROM tab2;
-% . # table_name
+% .%3 # table_name
 % %3 # name
 % bigint # type
 % 2 # length
 [ 12   ]
 #SELECT DISTINCT - 37, - COUNT ( DISTINCT - + 96 ) col1 FROM tab2;
 % .,   . # table_name
-% %2,  col1 # name
+% %3,  col1 # name
 % tinyint,     bigint # type
 % 3,   2 # length
 [ -37, -1      ]
@@ -118,7 +118,7 @@ stdout of test 'count-distinct.Bug-6790`
 [ NULL,        3886    ]
 [ NULL,        1173    ]
 #SELECT DISTINCT + 14 AS col2, + col0 - - CAST ( NULL AS INTEGER ) AS col2 
FROM tab2 AS cor0;
-% .,   sys. # table_name
+% .,   . # table_name
 % col2,        col2 # name
 % tinyint,     bigint # type
 % 2,   1 # length
diff --git a/sql/test/miscellaneous/Tests/simple_selects.stable.out 
b/sql/test/miscellaneous/Tests/simple_selects.stable.out
--- a/sql/test/miscellaneous/Tests/simple_selects.stable.out
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to