Changeset: 7298a3b335b8 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=7298a3b335b8
Modified Files:
        sql/backends/monet5/sql_gencode.c
        sql/backends/monet5/sql_statement.c
        sql/common/sql_types.c
        sql/server/rel_optimizer.c
        sql/server/rel_select.c
        
sql/test/BugDay_2005-11-09_2.9.3/Tests/sql_server_crash.SF-1080024.stable.out
        
sql/test/BugTracker-2012/Tests/case_evaluated_too_early.Bug-3186.stable.out
        
sql/test/BugTracker-2018/Tests/sqlitelogictest-complex-case-nullif-coalesce.Bug-6565.stable.out
        
sql/test/BugTracker-2018/Tests/sqlitelogictest-select-errors.Bug-6600.stable.out
        sql/test/SQLancer/Tests/sqlancer03.stable.out
        sql/test/Tests/coalesce.stable.out
        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/sys-schema/Tests/systemfunctions.stable.out
        sql/test/sys-schema/Tests/systemfunctions.stable.out.int128
Branch: Jun2020
Log Message:

moved coalesce and nullif into 'virtual' functions. They are now rewritten into
binary statements (mal) during code generation. Solves crash of sqlancer.


diffs (truncated from 907 to 300 lines):

diff --git a/sql/backends/monet5/sql_gencode.c 
b/sql/backends/monet5/sql_gencode.c
--- a/sql/backends/monet5/sql_gencode.c
+++ b/sql/backends/monet5/sql_gencode.c
@@ -1005,9 +1005,16 @@ monet5_resolve_function(ptr M, sql_func 
        int clientID = *(int*) M;
        str mname = getName(f->mod), fname = getName(f->imp);
 
+       /* sql.internal doesn't exist */
+       if (!fname && mname == sqlRef && f->imp && strcmp(f->imp, "internal") 
== 0)
+               return 1;
+
        if (!mname || !fname)
                return 0;
 
+       /* sql.internal doesn't exist */
+       if (strcmp(mname, "sql") == 0 && strcmp(fname,"internal") == 0)
+               return 1;
        /* Some SQL functions MAL mapping such as count(*) aggregate, the 
number of arguments don't match */
        if (mname == calcRef && fname == getName("="))
                return 1;
diff --git a/sql/backends/monet5/sql_statement.c 
b/sql/backends/monet5/sql_statement.c
--- a/sql/backends/monet5/sql_statement.c
+++ b/sql/backends/monet5/sql_statement.c
@@ -3070,77 +3070,120 @@ stmt_Nop(backend *be, stmt *ops, sql_sub
                }
        }
 
-       if (backend_create_subfunc(be, f, ops->op4.lval) < 0)
-               return NULL;
-       mod = sql_func_mod(f->func);
-       fimp = sql_func_imp(f->func);
-       if (o && o->nrcols > 0 && f->func->type != F_LOADER && f->func->type != 
F_PROC) {
-               sql_subtype *res = f->res->h->data;
-               fimp = convertMultiplexFcn(fimp);
-               q = NULL;
-               if (strcmp(fimp, "rotate_xor_hash") == 0 &&
-                   strcmp(mod, calcRef) == 0 &&
-                   (q = newStmt(mb, mkeyRef, bulk_rotate_xor_hashRef)) == NULL)
-                       return NULL;
-               if (!q) {
-                       if (f->func->type == F_UNION)
-                               q = newStmt(mb, batmalRef, multiplexRef);
-                       else
-                               q = newStmt(mb, malRef, multiplexRef);
-                       if (q == NULL)
-                               return NULL;
-                       setVarType(mb, getArg(q, 0), 
newBatType(res->type->localtype));
-                       setVarUDFtype(mb, getArg(q, 0));
-                       q = pushStr(mb, q, mod);
-                       q = pushStr(mb, q, fimp);
-               } else {
-                       setVarType(mb, getArg(q, 0), 
newBatType(res->type->localtype));
-                       setVarUDFtype(mb, getArg(q, 0));
+       /* handle coalesce and nullif */
+       if (list_length(ops->op4.lval) == 2 &&
+               f->func->mod && strcmp(f->func->mod, "sql") == 0 && 
f->func->imp && strcmp(f->func->imp, "internal") == 0) {
+               stmt *e1 = ops->op4.lval->h->data;
+               stmt *e2 = ops->op4.lval->h->next->data;
+               int nrcols = 0;
+
+               nrcols = e1->nrcols>e2->nrcols ? e1->nrcols:e2->nrcols;
+               /* nrcols */
+               //coalesce(e1,e2) -> ifthenelse(not(isnil(e1)),e1,e2)
+               if (strcmp(f->func->base.name, "coalesce") == 0) {
+                       str mod = (!nrcols)?calcRef:batcalcRef;
+                       q = newStmt(mb, e1->nrcols?mod:calcRef, "isnil");
+                       q = pushArgument(mb, q, e1->nr);
+                       int nr = getDestVar(q);
+
+                       q = newStmt(mb, e1->nrcols?mod:calcRef, "not");
+                       q = pushArgument(mb, q, nr);
+                       nr = getDestVar(q);
+
+                       q = newStmt(mb, mod, "ifthenelse");
+                       q = pushArgument(mb, q, nr);
+                       q = pushArgument(mb, q, e1->nr);
+                       q = pushArgument(mb, q, e2->nr);
                }
-       } else {
-               fimp = convertOperator(fimp);
-               q = newStmt(mb, mod, fimp);
-
-               if (f->res && list_length(f->res)) {
-                       sql_subtype *res = f->res->h->data;
-
-                       setVarType(mb, getArg(q, 0), res->type->localtype);
-                       setVarUDFtype(mb, getArg(q, 0));
+               //nullif(e1,e2) -> ifthenelse(e1==e2),NULL,e1)
+               if (strcmp(f->func->base.name, "nullif") == 0) {
+                       str mod = (!nrcols)?calcRef:batcalcRef;
+                       sql_subtype *t = tail_type(e1);
+                       int tt = t->type->localtype;
+                       q = newStmt(mb, mod, "==");
+                       q = pushArgument(mb, q, e1->nr);
+                       q = pushArgument(mb, q, e2->nr);
+                       int nr = getDestVar(q);
+
+                       q = newStmt(mb, mod, "ifthenelse");
+                       q = pushArgument(mb, q, nr);
+                       q = pushNil(mb, q, tt);
+                       q = pushArgument(mb, q, e1->nr);
                }
        }
-       if (LANG_EXT(f->func->lang))
-               q = pushPtr(mb, q, f);
-       if (f->func->lang == FUNC_LANG_C) {
-               q = pushBit(mb, q, 0);
-       } else if (f->func->lang == FUNC_LANG_CPP) {
-               q = pushBit(mb, q, 1);
-       }
-       if (f->func->lang == FUNC_LANG_R || f->func->lang >= FUNC_LANG_PY ||
-               f->func->lang == FUNC_LANG_C || f->func->lang == FUNC_LANG_CPP) 
{
-               q = pushStr(mb, q, f->func->query);
-       }
-       /* first dynamic output of copy* functions */
-       if (f->func->type == F_UNION || (f->func->type == F_LOADER && f->res != 
NULL))
-               q = table_func_create_result(mb, q, f->func, f->res);
-       if (list_length(ops->op4.lval))
-               tpe = tail_type(ops->op4.lval->h->data);
-       if (strcmp(fimp, "round") == 0 && tpe && tpe->type->eclass == EC_DEC)
-               special = 1;
-
-       for (n = ops->op4.lval->h; n; n = n->next) {
-               stmt *op = n->data;
-
-               if (!op)
-                       q = pushNil(mb, q, TYPE_bat);
-               else
-                       q = pushArgument(mb, q, op->nr);
-               if (op && special) {
-                       q = pushInt(mb, q, tpe->digits);
-                       setVarUDFtype(mb, getArg(q, q->argc-1));
-                       q = pushInt(mb, q, tpe->scale);
-                       setVarUDFtype(mb, getArg(q, q->argc-1));
+       if (!q) {
+               if (backend_create_subfunc(be, f, ops->op4.lval) < 0)
+                       return NULL;
+               mod = sql_func_mod(f->func);
+               fimp = sql_func_imp(f->func);
+               if (o && o->nrcols > 0 && f->func->type != F_LOADER && 
f->func->type != F_PROC) {
+                       sql_subtype *res = f->res->h->data;
+                       fimp = convertMultiplexFcn(fimp);
+                       q = NULL;
+                       if (strcmp(fimp, "rotate_xor_hash") == 0 &&
+                               strcmp(mod, calcRef) == 0 &&
+                               (q = newStmt(mb, mkeyRef, 
bulk_rotate_xor_hashRef)) == NULL)
+                               return NULL;
+                       if (!q) {
+                               if (f->func->type == F_UNION)
+                                       q = newStmt(mb, batmalRef, 
multiplexRef);
+                               else
+                                       q = newStmt(mb, malRef, multiplexRef);
+                               if (q == NULL)
+                                       return NULL;
+                               setVarType(mb, getArg(q, 0), 
newBatType(res->type->localtype));
+                               setVarUDFtype(mb, getArg(q, 0));
+                               q = pushStr(mb, q, mod);
+                               q = pushStr(mb, q, fimp);
+                       } else {
+                               setVarType(mb, getArg(q, 0), 
newBatType(res->type->localtype));
+                               setVarUDFtype(mb, getArg(q, 0));
+                       }
+               } else {
+                       fimp = convertOperator(fimp);
+                       q = newStmt(mb, mod, fimp);
+
+                       if (f->res && list_length(f->res)) {
+                               sql_subtype *res = f->res->h->data;
+
+                               setVarType(mb, getArg(q, 0), 
res->type->localtype);
+                               setVarUDFtype(mb, getArg(q, 0));
+                       }
                }
-               special = 0;
+               if (LANG_EXT(f->func->lang))
+                       q = pushPtr(mb, q, f);
+               if (f->func->lang == FUNC_LANG_C) {
+                       q = pushBit(mb, q, 0);
+               } else if (f->func->lang == FUNC_LANG_CPP) {
+                       q = pushBit(mb, q, 1);
+               }
+               if (f->func->lang == FUNC_LANG_R || f->func->lang >= 
FUNC_LANG_PY ||
+                       f->func->lang == FUNC_LANG_C || f->func->lang == 
FUNC_LANG_CPP) {
+                       q = pushStr(mb, q, f->func->query);
+               }
+               /* first dynamic output of copy* functions */
+               if (f->func->type == F_UNION || (f->func->type == F_LOADER && 
f->res != NULL))
+                       q = table_func_create_result(mb, q, f->func, f->res);
+               if (list_length(ops->op4.lval))
+                       tpe = tail_type(ops->op4.lval->h->data);
+               if (strcmp(fimp, "round") == 0 && tpe && tpe->type->eclass == 
EC_DEC)
+                       special = 1;
+
+               for (n = ops->op4.lval->h; n; n = n->next) {
+                       stmt *op = n->data;
+
+                       if (!op)
+                               q = pushNil(mb, q, TYPE_bat);
+                       else
+                               q = pushArgument(mb, q, op->nr);
+                       if (op && special) {
+                               q = pushInt(mb, q, tpe->digits);
+                               setVarUDFtype(mb, getArg(q, q->argc-1));
+                               q = pushInt(mb, q, tpe->scale);
+                               setVarUDFtype(mb, getArg(q, q->argc-1));
+                       }
+                       special = 0;
+               }
        }
 
        if (q) {
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
@@ -1314,6 +1314,8 @@ sqltypeinit( sql_allocator *sa)
        sql_create_func(sa, "least", "calc", "min_no_nil", FALSE, SCALE_FIX, 0, 
ANY, 2, ANY, ANY);
        sql_create_func(sa, "greatest", "calc", "max_no_nil", FALSE, SCALE_FIX, 
0, ANY, 2, ANY, ANY);
        sql_create_func(sa, "ifthenelse", "calc", "ifthenelse", FALSE, 
SCALE_FIX, 0, ANY, 3, BIT, ANY, ANY);
+       sql_create_func(sa, "nullif", "sql", "internal", FALSE, SCALE_FIX, 0, 
ANY, 2, ANY, ANY);
+       sql_create_func(sa, "coalesce", "sql", "internal", FALSE, SCALE_FIX, 0, 
ANY, 2, ANY, ANY);
 
        /* sum for numerical and decimals */
        sql_create_aggr(sa, "sum", "aggr", "sum", LargestINT, 1, BTE);
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
@@ -3067,6 +3067,11 @@ exp_simplify_math( mvc *sql, sql_exp *e,
                         * 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, "internal") == 0)
+                               return e;
+
                        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) {
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
@@ -3772,7 +3772,7 @@ rel_aggr(sql_query *query, sql_rel **rel
 }
 
 static sql_exp *
-rel_case(sql_query *query, sql_rel **rel, tokens token, symbol *opt_cond, 
dlist *when_search_list, symbol *opt_else, int f)
+rel_case(sql_query *query, sql_rel **rel, symbol *opt_cond, dlist 
*when_search_list, symbol *opt_else, int f)
 {
        mvc *sql = query->sql;
        sql_subtype *tpe = NULL;
@@ -3785,107 +3785,27 @@ rel_case(sql_query *query, sql_rel **rel
        exp_kind ek = {type_value, card_column, FALSE};
 
        sql_find_subtype(&bt, "boolean", 0, 0);
-       if (dn) {
+       for (dn = when_search_list->h; dn; dn = dn->next) {
                sql_exp *cond = NULL, *result = NULL;
 
-               /* NULLIF(e1,e2) == CASE WHEN e1=e2 THEN NULL ELSE e1 END */
-               if (token == SQL_NULLIF) {
-                       sql_exp *e1, *e2;
-
-                       if (!(e1 = rel_value_exp(query, rel, dn->data.sym, f, 
ek)))
-                               return NULL;
-                       if (!(e2 = rel_value_exp(query, rel, 
dn->next->data.sym, f, ek)))
-                               return NULL;
-
-                       cond = rel_binop_(sql, rel ? *rel : NULL, e1, e2, NULL, 
"=", card_value);
-                       result = exp_null(sql->sa, exp_subtype(e1));
-                       else_exp = exp_ref_save(sql, e1);       /* ELSE case */
-                       /* COALESCE(e1,e2) == CASE WHEN e1
-                          IS NOT NULL THEN e1 ELSE e2 END */
-               } else if (token == SQL_COALESCE) {
-                       cond = rel_value_exp(query, rel, dn->data.sym, f, ek);
-
-                       if (cond) {
-                               sql_exp *le;
-
-                               result = exp_ref_save(sql, cond);
-                               if (!(le = rel_unop_(sql, rel ? *rel : NULL, 
cond, NULL, "isnull", card_value)))
-                                       return NULL;
-                               set_has_no_nil(le);
-                               if (!(cond = rel_unop_(sql, rel ? *rel : NULL, 
le, NULL, "not", card_value)))
-                                       return NULL;
-                               set_has_no_nil(cond);
-                       }
-               } else {
-                       dlist *when = dn->data.sym->data.lval;
-
-                       if (opt_cond) {
-                               sql_exp *l, *r;
-
-                               if (!(l = rel_value_exp(query, rel, opt_cond, 
f, ek)))
-                                       return NULL;
-                               if (!(r = rel_value_exp(query, rel, 
when->h->data.sym, f, ek)))
-                                       return NULL;
-                               if (rel_convert_types(sql, rel ? *rel : NULL, 
rel ? *rel : NULL, &l, &r, 1, type_equal) < 0)
-                                       return NULL;
-                               cond = rel_binop_(sql, rel ? *rel : NULL, l, r, 
NULL, "=", card_value);
-                       } else {
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to