Changeset: b1a3906fd3b0 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=b1a3906fd3b0 Modified Files: sql/backends/monet5/rel_bin.c sql/common/sql_types.c sql/include/sql_catalog.h Branch: unlock Log Message:
merged with default diffs (truncated from 630 to 300 lines): diff --git a/sql/backends/monet5/rel_bin.c b/sql/backends/monet5/rel_bin.c --- a/sql/backends/monet5/rel_bin.c +++ b/sql/backends/monet5/rel_bin.c @@ -636,6 +636,7 @@ exp2bin_case(backend *be, sql_exp *fe, s } list *exps = fe->l; + /* * left - isel: calls down need id's from the range of left * res - rsel: updates too res need id's in the range from res @@ -750,6 +751,166 @@ exp2bin_case(backend *be, sql_exp *fe, s return res; } +static stmt * +exp2bin_casewhen(backend *be, sql_exp *fe, stmt *left, stmt *right, stmt *isel, int depth) +{ + stmt *res = NULL, *ires = NULL, *rsel = NULL, *osel = NULL, *ncond = NULL, *ocond = NULL, *cond = NULL; + int next_cond = 1, single_value = (fe->card <= CARD_ATOM && (!left || !left->nrcols)); + char name[16], *nme = NULL; + sql_subtype *bt = sql_bind_localtype("bit"); + sql_subfunc *not = sql_bind_func(be->mvc, "sys", "not", bt, NULL, F_FUNC); + sql_subfunc *or = sql_bind_func(be->mvc, "sys", "or", bt, bt, F_FUNC); + sql_subfunc *and = sql_bind_func(be->mvc, "sys", "and", bt, bt, F_FUNC); + sql_subfunc *cmp; + + if (single_value) { + /* var_x = nil; */ + nme = number2name(name, sizeof(name), ++be->mvc->label); + (void)stmt_var(be, NULL, nme, exp_subtype(fe), 1, 2); + } + + list *exps = fe->l; + node *en = exps->h; + sql_exp *e = en->data; + + stmt *nsel = !single_value?isel:NULL; + stmt *case_when = exp_bin(be, e, left, right, NULL, NULL, NULL, nsel, depth+1, 0, 1); + if (!case_when) + return NULL; + cmp = sql_bind_func(be->mvc, "sys", "=", exp_subtype(e), exp_subtype(e), F_FUNC); + if (!cmp) + return NULL; + if (!single_value && !case_when->nrcols) { + stmt *l = isel; + if (!l) + l = bin_first_column(be, left); + case_when = stmt_const(be, l, case_when); + case_when->cand = isel; + } + + /* + * left - isel: calls down need id's from the range of left + * res - rsel: updates too res need id's in the range from res + */ + for (en = en->next; en; en = en->next) { + sql_exp *e = en->data; + + next_cond = next_cond && en->next; /* last else is only a value */ + + stmt *nsel = rsel; + if (!single_value) { + if (/*!next_cond &&*/ rsel && isel) { + /* back into left range */ + nsel = stmt_project(be, rsel, isel); + } else if (isel && !rsel) + nsel = isel; + } + stmt *es = exp_bin(be, e, left, right, NULL, NULL, NULL, nsel, depth+1, 0, 1); + + if (!es) + return NULL; + if (next_cond) { + stmt *l = case_when; + assert(!es->cand || !l->cand || es->cand == l->cand); + if (es->cand && !l->cand) + l = stmt_project(be, es->cand, case_when); + else if (l->cand && !es->cand) + es = stmt_project(be, l->cand, es); + es = stmt_binop(be, l, es, NULL, cmp); + } + if (!single_value) { + /* create result */ + if (!res) { + stmt *l = isel; + if (!l) + l = bin_first_column(be, left); + res = stmt_const(be, l, stmt_atom(be, atom_general(be->mvc->sa, exp_subtype(fe), NULL))); + ires = l; + if (res) + res->cand = isel; + } else if (res && !next_cond) { /* use result too update column */ + stmt *val = es; + stmt *pos = rsel; + + if (val->nrcols == 0) + val = stmt_const(be, pos, val); + else if (!val->cand && nsel) + val = stmt_project(be, nsel, val); + res = stmt_replace(be, res, pos, val); + + assert(cond); + + if (en->next) { + /* osel - rsel */ + if (!osel) + osel = stmt_mirror(be, ires); + stmt *d = stmt_tdiff(be, osel, rsel, NULL); + osel = rsel = stmt_project(be, d, osel); + } + } + if (next_cond) { + ncond = cond = es; + if (!ncond->nrcols) { + if (osel) { + ncond = stmt_const(be, nsel, ncond); + ncond->cand = nsel; + } else if (isel) { + ncond = stmt_const(be, isel, ncond); + ncond->cand = isel; + } else + ncond = stmt_const(be, bin_first_column(be, left), ncond); + } + if (isel && !ncond->cand) + ncond = stmt_project(be, nsel, ncond); + stmt *s = stmt_uselect(be, ncond, stmt_bool(be, 1), cmp_equal, !ncond->cand?rsel:NULL, 0/*anti*/, 0); + if (rsel && ncond->cand) + rsel = stmt_project(be, s, rsel); + else + rsel = s; + } + } else { + if (!res) { + /* if_barrier ... */ + assert(next_cond); + if (next_cond) { + if (cond) { + ncond = stmt_binop(be, cond, es, nsel, and); + } else { + ncond = es; + } + cond = es; + } + } else { + /* var_x = s */ + (void)stmt_assign(be, NULL, nme, es, 2); + /* endif_barrier */ + (void)stmt_control_end(be, res); + res = NULL; + + if (en->next) { + cond = stmt_unop(be, cond, nsel, not); + + sql_subfunc *isnull = sql_bind_func(be->mvc, "sys", "isnull", bt, NULL, F_FUNC); + cond = stmt_binop(be, cond, stmt_unop(be, cond, nsel, isnull), nsel, or); + if (ocond) + cond = stmt_binop(be, ocond, cond, nsel, and); + ocond = cond; + if (!en->next->next) + ncond = cond; + } + } + if (ncond && (next_cond || (en->next && !en->next->next))) { + /* if_barrier ... */ + res = stmt_cond(be, ncond, NULL, 0, 0); + } + } + next_cond = !next_cond; + } + if (single_value) + return stmt_var(be, NULL, nme, exp_subtype(fe), 0, 2); + return res; +} + static stmt* exp2bin_coalesce(backend *be, sql_exp *fe, stmt *left, stmt *right, stmt *isel, int depth) { @@ -1027,6 +1188,8 @@ exp_bin(backend *be, sql_exp *e, stmt *l if (strcmp(sql_func_mod(f->func), "calc") == 0 && strcmp(sql_func_imp(f->func), "ifthenelse") == 0) return exp2bin_case(be, e, left, right, sel, depth); + if (strcmp(sql_func_mod(f->func), "") == 0 && strcmp(sql_func_imp(f->func), "") == 0 && strcmp(f->func->base.name, "casewhen") == 0) + return exp2bin_casewhen(be, e, left, right, sel, depth); if (strcmp(sql_func_mod(f->func), "") == 0 && strcmp(sql_func_imp(f->func), "") == 0 && strcmp(f->func->base.name, "coalesce") == 0) return exp2bin_coalesce(be, e, left, right, sel, depth); 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) */ @@ -919,9 +950,10 @@ sqltypeinit( sql_allocator *sa) 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 */ + /* nullif, coalesce and casewhen don't have a backend implementation */ sql_create_func(sa, "nullif", "", "", TRUE, FALSE, SCALE_FIX, 0, ANY, 2, ANY, ANY); sql_create_func(sa, "coalesce", "", "", TRUE, FALSE, SCALE_FIX, 0, ANY, 2, ANY, ANY); + sql_create_func(sa, "casewhen", "", "", TRUE, FALSE, SCALE_FIX, 0, ANY, 2, ANY, ANY); /* needed for count(*) and window functions without input col */ sql_create_func(sa, "star", "", "", TRUE, FALSE, SCALE_FIX, 0, ANY, 0); 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) _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list