Changeset: 14d425f1286f for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=14d425f1286f
Added Files:
        sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.sql
        sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.stable.err
        sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.stable.out
Modified Files:
        clients/Tests/exports.stable.out
        gdk/gdk_atoms.c
        gdk/gdk_atoms.h
        monetdb5/modules/mal/tablet.h
        sql/backends/monet5/sql_result.c
        sql/test/BugTracker-2013/Tests/All
Branch: Jan2014
Log Message:

Propagate quotes and separators down to "tostr" function.
Added test as well.
This fixes bug 3393.


diffs (truncated from 417 to 300 lines):

diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out
--- a/clients/Tests/exports.stable.out
+++ b/clients/Tests/exports.stable.out
@@ -417,8 +417,8 @@ int dlclose(void *handle);
 char *dlerror(void);
 void *dlopen(const char *file, int mode);
 void *dlsym(void *handle, const char *name);
-int escapedStr(char *dst, const char *src, int dstlen);
-int escapedStrlen(const char *src);
+int escapedStr(char *dst, const char *src, int dstlen, const char *sep1, const 
char *sep2, int quote);
+int escapedStrlen(const char *src, const char *sep1, const char *sep2, int 
quote);
 int fltFromStr(const char *src, int *len, flt **dst);
 int fltToStr(str *dst, int *len, const flt *src);
 const flt flt_nil;
diff --git a/gdk/gdk_atoms.c b/gdk/gdk_atoms.c
--- a/gdk/gdk_atoms.c
+++ b/gdk/gdk_atoms.c
@@ -1391,15 +1391,18 @@ strFromStr(const char *src, int *len, ch
 #endif
 
 int
-escapedStrlen(const char *src)
+escapedStrlen(const char *src, const char *sep1, const char *sep2, int quote)
 {
        int end, sz = 0;
+       size_t sep1len, sep2len;
 
+       sep1len = sep1 ? strlen(sep1) : 0;
+       sep2len = sep2 ? strlen(sep2) : 0;
        for (end = 0; src[end]; end++)
-               if (src[end] == '\t' ||
-                   src[end] == '\n' ||
-                   src[end] == '\\' ||
-                   src[end] == '"') {
+               if (src[end] == '\\' ||
+                   src[end] == quote ||
+                   (sep1len && strncmp(src + end, sep1, sep1len) == 0) ||
+                   (sep2len && strncmp(src + end, sep2, sep2len) == 0)) {
                        sz += 2;
 #ifndef ASCII_CHR
                } else if (src[end] == (char) '\302' &&
@@ -1423,36 +1426,50 @@ escapedStrlen(const char *src)
 }
 
 int
-escapedStr(char *dst, const char *src, int dstlen)
+escapedStr(char *dst, const char *src, int dstlen, const char *sep1, const 
char *sep2, int quote)
 {
        int cur = 0, l = 0;
+       size_t sep1len, sep2len;
 
+       sep1len = sep1 ? strlen(sep1) : 0;
+       sep2len = sep2 ? strlen(sep2) : 0;
        for (; src[cur] && l < dstlen; cur++)
-               if (src[cur] == '\t') {
+               if (!printable_chr(src[cur])
+#ifndef ASCII_CHR
+                   || (src[cur] == '\302' &&
+                       0200 <= (src[cur + 1] & 0377) &&
+                       ((int) src[cur + 1] & 0377) <= 0237)
+                   || (cur > 0 &&
+                       src[cur - 1] == '\302' &&
+                       0200 <= (src[cur] & 0377) &&
+                       (src[cur] & 0377) <= 0237)
+#endif
+                       ) {
                        dst[l++] = '\\';
-                       dst[l++] = 't';
-               } else if (src[cur] == '\n') {
+                       switch (src[cur]) {
+                       case '\t':
+                               dst[l++] = 't';
+                               break;
+                       case '\n':
+                               dst[l++] = 'n';
+                               break;
+                       case '\r':
+                               dst[l++] = 'r';
+                               break;
+                       case '\f':
+                               dst[l++] = 'f';
+                               break;
+                       default:
+                               snprintf(dst + l, dstlen - l, "%03o", (unsigned 
char) src[cur]);
+                               l += 3;
+                               break;
+                       }
+               } else if (src[cur] == '\\' ||
+                          src[cur] == quote ||
+                          (sep1len && strncmp(src + cur, sep1, sep1len) == 0) 
||
+                          (sep2len && strncmp(src + cur, sep2, sep2len) == 0)) 
{
                        dst[l++] = '\\';
-                       dst[l++] = 'n';
-               } else if (src[cur] == '\\') {
-                       dst[l++] = '\\';
-                       dst[l++] = '\\';
-               } else if (src[cur] == '"') {
-                       dst[l++] = '\\';
-                       dst[l++] = '"';
-               } else if (!printable_chr(src[cur])
-#ifndef ASCII_CHR
-                          || (src[cur] == '\302' &&
-                              0200 <= (src[cur + 1] & 0377) &&
-                              ((int) src[cur + 1] & 0377) <= 0237)
-                          || (cur > 0 &&
-                              src[cur - 1] == '\302' &&
-                              0200 <= (src[cur] & 0377) &&
-                              (src[cur] & 0377) <= 0237)
-#endif
-                   ) {
-                       snprintf(dst + l, dstlen - l, "\\%03o", (unsigned char) 
src[cur]);
-                       l += 4;
+                       dst[l++] = src[cur];
                } else {
                        dst[l++] = src[cur];
                }
@@ -1472,9 +1489,9 @@ strToStr(char **dst, int *len, const cha
                strncpy(*dst, "nil", *len);
                return 3;
        } else {
-               int sz = escapedStrlen(src);
+               int sz = escapedStrlen(src, NULL, NULL, '"');
                atommem(char, sz + 3);
-               l = escapedStr((*dst) + 1, src, *len - 1);
+               l = escapedStr((*dst) + 1, src, *len - 1, NULL, NULL, '"');
                l++;
                (*dst)[0] = (*dst)[l++] = '"';
                (*dst)[l] = 0;
diff --git a/gdk/gdk_atoms.h b/gdk/gdk_atoms.h
--- a/gdk/gdk_atoms.h
+++ b/gdk/gdk_atoms.h
@@ -105,8 +105,8 @@ gdk_export int strToStr(str *dst, int *l
 gdk_export BUN strHash(const char *s);
 gdk_export int strLen(const char *s);
 gdk_export int strNil(const char *s);
-gdk_export int escapedStrlen(const char *src);
-gdk_export int escapedStr(char *dst, const char *src, int dstlen);
+gdk_export int escapedStrlen(const char *src, const char *sep1, const char 
*sep2, int quote);
+gdk_export int escapedStr(char *dst, const char *src, int dstlen, const char 
*sep1, const char *sep2, int quote);
 /*
  * @- nil values
  * All types have a single value designated as a NIL value. It
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
@@ -50,6 +50,7 @@
 typedef struct Column_t {
        const char *name;                       /* column title */
        const char *sep;
+       const char *rsep;
        int seplen;
        char *type;
        int adt;                                        /* type index */
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
@@ -547,8 +547,12 @@ static int
                Column *c = extra;
                char *dst;
                const char *src = a;
-               int l = (c->quote) ? escapedStrlen(src) : (int) strlen(src), l2 
= 0;
+               int l = escapedStrlen(src, c->sep, c->rsep, c->quote), l2 = 0;
 
+               if (c->quote)
+                       l = escapedStrlen(src, NULL, NULL, c->quote);
+               else
+                       l = escapedStrlen(src, c->sep, c->rsep, 0);
                if (l + 3 > *len) {
                        GDKfree(*buf);
                        *len = 2 * l + 3;
@@ -558,9 +562,9 @@ static int
                if (c->quote) {
                        dst[0] = c->quote;
                        l2 = 1;
-                       l = escapedStr(dst + l2, src, *len - l2);
+                       l = escapedStr(dst + l2, src, *len - l2, NULL, NULL, 
c->quote);
                } else {
-                       strncpy(dst + l2, src, l);
+                       l = escapedStr(dst + l2, src, *len - l2, c->sep, 
c->rsep, 0);
                }
                if (l2) {
                        dst[l + l2] = c->quote;
@@ -648,6 +652,7 @@ mvc_import_table(Client cntxt, mvc *m, b
 
                        fmt[i].name = col->base.name;
                        fmt[i].sep = (n->next) ? sep : rsep;
+                       fmt[i].rsep = rsep;
                        fmt[i].seplen = _strlen(fmt[i].sep);
                        fmt[i].type = sql_subtype_string(&col->type);
                        fmt[i].adt = ATOMindex(col->type.type->base.name);
@@ -726,6 +731,7 @@ mvc_import_table(Client cntxt, mvc *m, b
                        sql_error(m, 500, "%s", as.error);
                for (n = t->columns.set->h, i = 0; n; n = n->next, i++) {
                        fmt[i].sep = NULL;
+                       fmt[i].rsep = NULL;
                        fmt[i].nullstr = NULL;
                }
                TABLETdestroy_format(&as);
@@ -1127,6 +1133,7 @@ mvc_export_table(backend *b, stream *s, 
 
        fmt[0].c = NULL;
        fmt[0].sep = (csv) ? btag : "";
+       fmt[0].rsep = rsep;
        fmt[0].seplen = _strlen(fmt[0].sep);
        fmt[0].ws = 0;
        fmt[0].nullstr = NULL;
@@ -1143,6 +1150,7 @@ mvc_export_table(backend *b, stream *s, 
                if (csv) {
                        fmt[i].sep = ((i - 1) < (t->nr_cols - 1)) ? sep : rsep;
                        fmt[i].seplen = _strlen(fmt[i].sep);
+                       fmt[i].rsep = rsep;
                }
                if (json) {
                        res_col *p = t->cols + (i - 1);
@@ -1156,13 +1164,16 @@ mvc_export_table(backend *b, stream *s, 
                                snprintf(bj, strlen(p->name) + 6, "{ %s , ", 
p->name);
                                fmt[i - 1].sep = bj;
                                fmt[i - 1].seplen = _strlen(fmt[i - 1].sep);
+                               fmt[i - 1].rsep = NULL;
                        } else if (i <= t->nr_cols) {
                                fmt[i - 1].sep = p->name;
                                fmt[i - 1].seplen = _strlen(fmt[i - 1].sep);
+                               fmt[i - 1].rsep = NULL;
                        }
                        if (i == t->nr_cols) {
                                fmt[i].sep = " }\n";
                                fmt[i].seplen = _strlen(fmt[i].sep);
+                               fmt[i].rsep = NULL;
                        }
                }
                fmt[i].type = ATOMname(fmt[i].c->ttype);
@@ -1211,6 +1222,7 @@ mvc_export_table(backend *b, stream *s, 
        }
        for (i = 0; i <= t->nr_cols; i++) {
                fmt[i].sep = NULL;
+               fmt[i].rsep = NULL;
                fmt[i].type = NULL;
                fmt[i].nullstr = NULL;
        }
diff --git a/sql/test/BugTracker-2013/Tests/All 
b/sql/test/BugTracker-2013/Tests/All
--- a/sql/test/BugTracker-2013/Tests/All
+++ b/sql/test/BugTracker-2013/Tests/All
@@ -55,6 +55,7 @@ python-explain.Bug-3380
 case-orderby.Bug-3388
 unop_vs_aggr.Bug-3885
 singleton-median.Bug-3389
+copy-out-quote.Bug-3393
 Cannot_Find_Column_Type.Bug-3394
 case_when.Bug-3395
 udf_error.Bug-3396
diff --git a/sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.sql 
b/sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.sql
new file mode 100644
--- /dev/null
+++ b/sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.sql
@@ -0,0 +1,10 @@
+start transaction;
+create table table3393 (a clob, b clob);
+insert into table3393 values ('one|two', 'three"four');
+insert into table3393 values ('five\tsix', 'seven\neight');
+insert into table3393 values ('nine,ten', 'eleven\\twelve');
+select * from table3393;
+copy select * from table3393 into stdout delimiters ',', '\n', '|';
+copy select * from table3393 into stdout delimiters '|', '\n', ',';
+copy select * from table3393 into stdout;
+rollback;
diff --git a/sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.stable.err 
b/sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.stable.err
new file mode 100644
--- /dev/null
+++ b/sql/test/BugTracker-2013/Tests/copy-out-quote.Bug-3393.stable.err
@@ -0,0 +1,35 @@
+stderr of test 'copy-out-quote.Bug-3393` in directory 
'sql/test/BugTracker-2013` itself:
+
+
+# 10:58:27 >  
+# 10:58:27 >  "mserver5" "--debug=10" "--set" "gdk_nr_threads=0" "--set" 
"mapi_open=true" "--set" "mapi_port=38193" "--set" 
"mapi_usock=/var/tmp/mtest-13320/.s.monetdb.38193" "--set" "monet_prompt=" 
"--forcemito" "--set" "mal_listing=2" 
"--dbpath=/ufs/sjoerd/Monet-candidate/var/MonetDB/mTests_sql_test_BugTracker-2013"
 "--set" "mal_listing=0"
+# 10:58:27 >  
+
+# builtin opt  gdk_dbpath = 
/ufs/sjoerd/Monet-candidate/var/monetdb5/dbfarm/demo
+# builtin opt  gdk_debug = 0
+# builtin opt  gdk_vmtrim = yes
+# builtin opt  monet_prompt = >
+# builtin opt  monet_daemon = no
+# builtin opt  mapi_port = 50000
+# builtin opt  mapi_open = false
+# builtin opt  mapi_autosense = false
+# builtin opt  sql_optimizer = default_pipe
+# builtin opt  sql_debug = 0
+# cmdline opt  gdk_nr_threads = 0
+# cmdline opt  mapi_open = true
+# cmdline opt  mapi_port = 38193
+# cmdline opt  mapi_usock = /var/tmp/mtest-13320/.s.monetdb.38193
+# cmdline opt  monet_prompt = 
+# cmdline opt  mal_listing = 2
+# cmdline opt  gdk_dbpath = 
/ufs/sjoerd/Monet-candidate/var/MonetDB/mTests_sql_test_BugTracker-2013
+# cmdline opt  mal_listing = 0
+
+# 10:58:27 >  
+# 10:58:27 >  "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" 
"--host=/var/tmp/mtest-13320" "--port=38193"
+# 10:58:27 >  
+
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to