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

Reply via email to