Changeset: f2a4a8f53c71 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f2a4a8f53c71 Modified Files: monetdb5/modules/mal/tablet.h sql/backends/monet5/sql.c sql/backends/monet5/sql_result.c sql/backends/monet5/sql_result.h sql/common/sql_types.c sql/server/rel_updates.c sql/server/sql_parser.y Branch: default Log Message:
Implement DECIMAL thousands separator diffs (251 lines): diff --git a/monetdb5/modules/mal/tablet.h b/monetdb5/modules/mal/tablet.h --- a/monetdb5/modules/mal/tablet.h +++ b/monetdb5/modules/mal/tablet.h @@ -31,6 +31,7 @@ typedef struct Column_t { const char *sep; const char *rsep; char decsep; + char decskip; int seplen; const char *type; int adt; /* type index */ diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c --- a/sql/backends/monet5/sql.c +++ b/sql/backends/monet5/sql.c @@ -3113,6 +3113,7 @@ mvc_import_table_wrap(Client cntxt, MalB int onclient = *getArgReference_int(stk, pci, pci->retc + 10); bool escape = *getArgReference_int(stk, pci, pci->retc + 11); const char *decsep = *getArgReference_str(stk, pci, pci->retc + 12); + const char *decskip = *getArgReference_str(stk, pci, pci->retc + 13); str msg = MAL_SUCCEED; bstream *s = NULL; stream *ss; @@ -3133,7 +3134,7 @@ mvc_import_table_wrap(Client cntxt, MalB if (strNil(fname)) fname = NULL; if (fname == NULL) { - msg = mvc_import_table(cntxt, &b, be->mvc, be->mvc->scanner.rs, t, tsep, rsep, ssep, ns, sz, offset, besteffort, true, escape, decsep); + msg = mvc_import_table(cntxt, &b, be->mvc, be->mvc->scanner.rs, t, tsep, rsep, ssep, ns, sz, offset, besteffort, true, escape, decsep, decskip); } else { if (onclient) { ss = mapi_request_upload(fname, false, be->mvc->scanner.rs, be->mvc->scanner.ws); @@ -3191,7 +3192,7 @@ mvc_import_table_wrap(Client cntxt, MalB close_stream(ss); throw(MAL, "sql.copy_from", SQLSTATE(HY013) MAL_MALLOC_FAIL); } - msg = mvc_import_table(cntxt, &b, be->mvc, s, t, tsep, rsep, ssep, ns, sz, offset, besteffort, false, escape, decsep); + msg = mvc_import_table(cntxt, &b, be->mvc, s, t, tsep, rsep, ssep, ns, sz, offset, besteffort, false, escape, decsep, decskip); // This also closes ss: bstream_destroy(s); } @@ -5289,7 +5290,7 @@ static mel_func sql_init_funcs[] = { pattern("sql", "export_bin_column", mvc_bin_export_column_wrap, true, "export column as binary", args(1, 5, arg("", lng), batargany("col", 1), arg("byteswap", bit), arg("filename", str), arg("onclient", int))), pattern("sql", "export_bin_column", mvc_bin_export_column_wrap, true, "export column as binary", args(1, 5, arg("", lng), argany("val", 1), arg("byteswap", bit), arg("filename", str), arg("onclient", int))), pattern("sql", "affectedRows", mvc_affected_rows_wrap, true, "export the number of affected rows by the current query", args(1,3, arg("",int),arg("mvc",int),arg("nr",lng))), - pattern("sql", "copy_from", mvc_import_table_wrap, true, "Import a table from bstream s with the \ngiven tuple and seperators (sep/rsep)", args(1,14, batvarargany("",0),arg("t",ptr),arg("sep",str),arg("rsep",str),arg("ssep",str),arg("ns",str),arg("fname",str),arg("nr",lng),arg("offset",lng),arg("best",int),arg("fwf",str),arg("onclient",int),arg("escape",int),arg("decsep",str))), + pattern("sql", "copy_from", mvc_import_table_wrap, true, "Import a table from bstream s with the \ngiven tuple and seperators (sep/rsep)", args(1,15, batvarargany("",0),arg("t",ptr),arg("sep",str),arg("rsep",str),arg("ssep",str),arg("ns",str),arg("fname",str),arg("nr",lng),arg("offset",lng),arg("best",int),arg("fwf",str),arg("onclient",int),arg("escape",int),arg("decsep",str),arg("decskip",str))), //we use bat.single now //pattern("sql", "single", CMDBATsingle, false, "", args(1,2, batargany("",2),argany("x",2))), pattern("sql", "importColumn", mvc_bin_import_column_wrap, false, "Import a column from the given file", args(2, 8, batargany("", 0),arg("", oid), arg("method",str),arg("width",int),arg("bswap",bit),arg("path",str),arg("onclient",int),arg("nrows",oid))), diff --git a/sql/backends/monet5/sql_result.c b/sql/backends/monet5/sql_result.c --- a/sql/backends/monet5/sql_result.c +++ b/sql/backends/monet5/sql_result.c @@ -318,6 +318,8 @@ bat_max_length(hge, hge) s++; \ } \ for (i = 0; *s && *s != c->decsep && ((res == 0 && *s == '0') || i < t->digits - t->scale); s++) { \ + if (c->decskip && *s == c->decskip) \ + continue; \ if (!isdigit((unsigned char) *s)) \ break; \ res *= 10; \ @@ -325,12 +327,18 @@ bat_max_length(hge, hge) if (res) \ i++; \ } \ - if (*s == c->decsep) { \ + if (*s == c->decsep) { \ s++; \ - while (*s && isdigit((unsigned char) *s) && scale > 0) { \ - res *= 10; \ - res += *s++ - '0'; \ - scale--; \ + while (*s && scale > 0) { \ + if (isdigit((unsigned char) *s)) { \ + res *= 10; \ + res += *s++ - '0'; \ + scale--; \ + } else if (c->decskip && *s == c->decskip) { \ + s++; \ + } else { \ + break; \ + } \ } \ } \ while(*s && isspace((unsigned char) *s)) \ @@ -534,7 +542,7 @@ has_whitespace(const char *s) } str -mvc_import_table(Client cntxt, BAT ***bats, mvc *m, bstream *bs, sql_table *t, const char *sep, const char *rsep, const char *ssep, const char *ns, lng sz, lng offset, int best, bool from_stdin, bool escape, const char *decsep) +mvc_import_table(Client cntxt, BAT ***bats, mvc *m, bstream *bs, sql_table *t, const char *sep, const char *rsep, const char *ssep, const char *ns, lng sz, lng offset, int best, bool from_stdin, bool escape, const char *decsep, const char *decskip) { int i = 0, j; node *n; @@ -584,6 +592,7 @@ mvc_import_table(Client cntxt, BAT ***ba fmt[i].rsep = rsep; fmt[i].seplen = _strlen(fmt[i].sep); fmt[i].decsep = '\0', + fmt[i].decskip = '\0', fmt[i].type = sql_subtype_string(m->ta, &col->type); fmt[i].adt = ATOMindex(col->type.type->impl); fmt[i].tostr = &_ASCIIadt_toStr; @@ -611,10 +620,12 @@ mvc_import_table(Client cntxt, BAT ***ba fmt[i].tostr = &dec_tostr; fmt[i].frstr = &dec_frstr; fmt[i].decsep = decsep[0]; // apply DECIMAL DELIMITERS clause + fmt[i].decskip = decskip[0]; } else if (col->type.type->eclass == EC_SEC) { fmt[i].tostr = &dec_tostr; fmt[i].frstr = &sec_frstr; fmt[i].decsep = '.'; // not sure if it should be affected by DECIMAL DELIMITERS clause + fmt[i].decskip = '\0'; } fmt[i].size = ATOMsize(fmt[i].adt); } diff --git a/sql/backends/monet5/sql_result.h b/sql/backends/monet5/sql_result.h --- a/sql/backends/monet5/sql_result.h +++ b/sql/backends/monet5/sql_result.h @@ -31,7 +31,7 @@ extern int mvc_export_bin_chunk(backend extern int mvc_export_prepare(backend *b, stream *s); -extern str mvc_import_table(Client cntxt, BAT ***bats, mvc *c, bstream *s, sql_table *t, const char *sep, const char *rsep, const char *ssep, const char *ns, lng nr, lng offset, int best, bool from_stdin, bool escape, const char *decsep); +extern str mvc_import_table(Client cntxt, BAT ***bats, mvc *c, bstream *s, sql_table *t, const char *sep, const char *rsep, const char *ssep, const char *ns, lng nr, lng offset, int best, bool from_stdin, bool escape, const char *decsep, const char *decskip); sql5_export int mvc_result_table(backend *be, oid query_id, int nr_cols, mapi_query_t type); sql5_export int mvc_result_column(backend *be, const char *tn, const char *name, const char *typename, int digits, int scale, BAT *b); 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 @@ -1663,8 +1663,8 @@ sqltypeinit( sql_allocator *sa) sql_create_func(sa, "character_length", "str", "length", FALSE, FALSE, SCALE_NONE, 0, INT, 1, STR); sql_create_func(sa, "octet_length", "str", "nbytes", FALSE, FALSE, SCALE_NONE, 0, INT, 1, STR); - /* copyfrom fname (arg 13) */ - f = sql_create_union(sa, "copyfrom", "sql", "copy_from", TRUE, SCALE_FIX, 0, TABLE, 13, PTR, STR, STR, STR, STR, STR, LNG, LNG, INT, STR, INT, INT, STR); + /* copyfrom fname (arg 15) */ + f = sql_create_union(sa, "copyfrom", "sql", "copy_from", TRUE, SCALE_FIX, 0, TABLE, 14, PTR, STR, STR, STR, STR, STR, LNG, LNG, INT, STR, INT, INT, STR, STR); f->varres = 1; /* bincopyfrom */ diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c --- a/sql/server/rel_updates.c +++ b/sql/server/rel_updates.c @@ -1493,14 +1493,14 @@ table_column_names_and_defaults(sql_allo } static sql_rel * -rel_import(mvc *sql, sql_table *t, const char *tsep, const char *rsep, const char *ssep, const char *ns, const char *filename, lng nr, lng offset, int best_effort, dlist *fwf_widths, int onclient, int escape, const char* decsep) +rel_import(mvc *sql, sql_table *t, const char *tsep, const char *rsep, const char *ssep, const char *ns, const char *filename, lng nr, lng offset, int best_effort, dlist *fwf_widths, int onclient, int escape, const char* decsep, const char *decskip) { sql_rel *res; list *exps, *args; node *n; sql_subtype tpe; sql_exp *import; - sql_subfunc *f = sql_find_func(sql, "sys", "copyfrom", 13, F_UNION, true, NULL); + sql_subfunc *f = sql_find_func(sql, "sys", "copyfrom", 14, F_UNION, true, NULL); char *fwf_string = NULL; assert(f); /* we do expect copyfrom to be there */ @@ -1537,6 +1537,7 @@ rel_import(mvc *sql, sql_table *t, const append(args, exp_atom_int(sql->sa, onclient)); append(args, exp_atom_int(sql->sa, escape)); append(args, exp_atom_str(sql->sa, decsep, &tpe)); + append(args, exp_atom_str(sql->sa, decskip, &tpe)); import = exp_op(sql->sa, args, f); @@ -1550,6 +1551,21 @@ rel_import(mvc *sql, sql_table *t, const return res; } +static bool +valid_decsep(const char *s) +{ + if (strlen(s) != 1) + return false; + int c = s[0]; + if (c <= ' ' || c >= 127) + return false; + if (c == '-' || c == '+') + return false; + if (c >= '0' && c <= '9') + return false; + return true; +} + static sql_rel * copyfrom(sql_query *query, dlist *qname, dlist *columns, dlist *files, dlist *headers, dlist *seps, dlist *nr_offset, str null_string, int best_effort, dlist *fwf_widths, int onclient, int escape, dlist *decimal_seps) { @@ -1567,6 +1583,7 @@ copyfrom(sql_query *query, dlist *qname, list *collist; int reorder = 0; const char *decsep = decimal_seps->h->data.sval; + const char *decskip = decimal_seps->h->next ? decimal_seps->h->next->data.sval: NULL; assert(!nr_offset || nr_offset->h->type == type_lng); assert(!nr_offset || nr_offset->h->next->type == type_lng); @@ -1581,13 +1598,12 @@ copyfrom(sql_query *query, dlist *qname, "that will never match, use '\\n' instead"); } - if (strlen(decsep) != 1 - || decsep[0] <= ' ' - || decsep[0] >= 127 - || decsep[0] == '-' || decsep[0] == '+' - || (decsep[0] >= '0' && decsep[0] <= '9')) { + if (!valid_decsep(decsep)) return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: invalid decimal separator"); - } + if (decskip && !valid_decsep(decskip)) + return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: invalid thousands separator"); + if (decskip && strcmp(decsep, decskip) == 0) + return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: decimal separator and thousands separator must be different"); t = find_table_or_view_on_scope(sql, NULL, sname, tname, "COPY INTO", false); if (insert_allowed(sql, t, tname, "COPY INTO", "copy into") == NULL) @@ -1675,7 +1691,7 @@ copyfrom(sql_query *query, dlist *qname, return NULL; } - nrel = rel_import(sql, nt, tsep, rsep, ssep, ns, fname, nr, offset, best_effort, fwf_widths, onclient, escape, decsep); + nrel = rel_import(sql, nt, tsep, rsep, ssep, ns, fname, nr, offset, best_effort, fwf_widths, onclient, escape, decsep, decskip); if (!rel) rel = nrel; @@ -1688,7 +1704,7 @@ copyfrom(sql_query *query, dlist *qname, } } else { assert(onclient == 0); - rel = rel_import(sql, nt, tsep, rsep, ssep, ns, NULL, nr, offset, best_effort, NULL, onclient, escape, decsep); + rel = rel_import(sql, nt, tsep, rsep, ssep, ns, NULL, nr, offset, best_effort, NULL, onclient, escape, decsep, decskip); } if (headers) { dnode *n; diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y --- a/sql/server/sql_parser.y +++ b/sql/server/sql_parser.y @@ -3063,6 +3063,11 @@ opt_decimal_seps: { dlist *l = L(); append_string(l, $3); $$ = l; } + | sqlDECIMAL DELIMITERS string ',' string + { dlist *l = L(); + append_string(l, $3); + append_string(l, $5); + $$ = l; } ; opt_using: _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org