Merge lp:~laurynas-biveinis/percona-server/csv-engine-ietf-quotes-5.6 into lp:percona-server/5.6

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Sergei Glushchenko
Approved revision: no longer in the source branch.
Merged at revision: 677
Proposed branch: lp:~laurynas-biveinis/percona-server/csv-engine-ietf-quotes-5.6
Merge into: lp:percona-server/5.6
Diff against target: 353 lines (+236/-8)
6 files modified
mysql-test/r/csv.result (+44/-0)
mysql-test/r/mysqld--help-notwin.result (+3/-0)
mysql-test/suite/sys_vars/r/csv_mode_basic.result (+55/-0)
mysql-test/suite/sys_vars/t/csv_mode_basic.test (+47/-0)
mysql-test/t/csv.test (+44/-0)
storage/csv/ha_tina.cc (+43/-8)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/csv-engine-ietf-quotes-5.6
Reviewer Review Type Date Requested Status
Sergei Glushchenko (community) g2 Approve
Review via email: mp+236839@code.launchpad.net

Description of the change

Merge csv-engine-ietf-quotes blueprint implementation / bug 1316042
fix from 5.5, implementing
https://blueprints.launchpad.net/percona-server/+spec/csv-engine-ietf-quotes-5.6.

An automerge, with an exception of percona_server_variables_debug and
percona_server_variables_release null merge.

    http://jenkins.percona.com/job/percona-server-5.6-param/725/

To post a comment you must log in.
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Approve

review: Approve (g2)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mysql-test/r/csv.result'
2--- mysql-test/r/csv.result 2012-08-22 01:40:20 +0000
3+++ mysql-test/r/csv.result 2014-10-02 09:29:18 +0000
4@@ -5470,3 +5470,47 @@
5 ERROR HY000: Table 't1' is marked as crashed and should be repaired
6 DROP TABLE t1;
7 End of 5.1 tests
8+SET @old_csv_mode = @@SESSION.csv_mode;
9+SET @@SESSION.csv_mode='ietf_quotes';
10+CREATE TABLE t1(c1 TEXT NOT NULL, c2 TEXT NOT NULL) ENGINE=CSV;
11+INSERT INTO t1 VALUES("a\"b,c","d");
12+INSERT INTO t1 VALUES("d","a\"b,c");
13+INSERT INTO t1 VALUES(",\"a","e");
14+INSERT INTO t1 VALUES("e",",\"a");
15+INSERT INTO t1 VALUES("\"","f");
16+INSERT INTO t1 VALUES("f","\"");
17+INSERT INTO t1 VALUES(",","g");
18+INSERT INTO t1 VALUES("g",",");
19+SELECT * FROM t1;
20+c1 c2
21+a"b,c d
22+d a"b,c
23+,"a e
24+e ,"a
25+" f
26+f "
27+, g
28+g ,
29+CSV file contents:
30+"a""b,c","d"
31+"d","a""b,c"
32+",""a","e"
33+"e",",""a"
34+"""","f"
35+"f",""""
36+",","g"
37+"g",","
38+DROP TABLE t1;
39+CREATE TABLE t1(c1 TEXT NOT NULL, c2 TEXT NOT NULL) ENGINE=CSV;
40+Replacing t1.CSV
41+SELECT * FROM t1;
42+c1 c2
43+a b
44+a b
45+a"b,c d
46+d ,"a
47+a", e
48+e "
49+, f
50+DROP TABLE t1;
51+SET @@SESSION.csv_mode=@old_csv_mode;
52
53=== modified file 'mysql-test/r/mysqld--help-notwin.result'
54--- mysql-test/r/mysqld--help-notwin.result 2014-09-26 04:43:24 +0000
55+++ mysql-test/r/mysqld--help-notwin.result 2014-10-02 09:29:18 +0000
56@@ -137,6 +137,8 @@
57 --console Write error output on screen; don't remove the console
58 window on windows.
59 --core-file Write core on errors.
60+ --csv-mode=name Control CSV parser mode: []: default, ietf_quotes:
61+ standards-compatible embedded quote and comma parsing
62 -h, --datadir=name Path to the database root directory
63 --date-format=name The DATE format (ignored)
64 --datetime-format=name
65@@ -1139,6 +1141,7 @@
66 concurrent-insert AUTO
67 connect-timeout 10
68 console FALSE
69+csv-mode
70 date-format %Y-%m-%d
71 datetime-format %Y-%m-%d %H:%i:%s
72 default-storage-engine InnoDB
73
74=== added file 'mysql-test/suite/sys_vars/r/csv_mode_basic.result'
75--- mysql-test/suite/sys_vars/r/csv_mode_basic.result 1970-01-01 00:00:00 +0000
76+++ mysql-test/suite/sys_vars/r/csv_mode_basic.result 2014-10-02 09:29:18 +0000
77@@ -0,0 +1,55 @@
78+SET @saved_csv_mode = @@SESSION.csv_mode;
79+SET @@SESSION.csv_mode = 'ietf_quotes';
80+SELECT @@SESSION.csv_mode;
81+@@SESSION.csv_mode
82+IETF_QUOTES
83+SET @@SESSION.csv_mode = 'IETF_QUOTES';
84+SELECT @@SESSION.csv_mode;
85+@@SESSION.csv_mode
86+IETF_QUOTES
87+SET @@SESSION.csv_mode = IETF_QUOTES;
88+SELECT @@SESSION.csv_mode;
89+@@SESSION.csv_mode
90+IETF_QUOTES
91+SET @@SESSION.csv_mode = '';
92+SELECT @@SESSION.csv_mode;
93+@@SESSION.csv_mode
94+
95+SET @@SESSION.csv_mode = 0;
96+SELECT @@SESSION.csv_mode;
97+@@SESSION.csv_mode
98+
99+SET @@SESSION.csv_mode = 1;
100+SELECT @@SESSION.csv_mode;
101+@@SESSION.csv_mode
102+IETF_QUOTES
103+SET @@SESSION.csv_mode = NULL;
104+ERROR 42000: Variable 'csv_mode' can't be set to the value of 'NULL'
105+SET @@SESSION.csv_mode = FOO;
106+ERROR 42000: Variable 'csv_mode' can't be set to the value of 'FOO'
107+SET @@SESSION.csv_mode = 'foo';
108+ERROR 42000: Variable 'csv_mode' can't be set to the value of 'foo'
109+SELECT @@SESSION.csv_mode;
110+@@SESSION.csv_mode
111+IETF_QUOTES
112+SET @@SESSION.csv_mode = 0;
113+SELECT @@SESSION.csv_mode;
114+@@SESSION.csv_mode
115+
116+SET @@SESSION.csv_mode = -1;
117+ERROR 42000: Variable 'csv_mode' can't be set to the value of '-1'
118+SET @@SESSION.csv_mode = 2;
119+ERROR 42000: Variable 'csv_mode' can't be set to the value of '2'
120+SET @@SESSION.csv_mode = @saved_csv_mode;
121+SET @saved_csv_mode = @@GLOBAL.csv_mode;
122+SET @@GLOBAL.csv_mode = '';
123+SELECT @@GLOBAL.csv_mode;
124+@@GLOBAL.csv_mode
125+
126+SET @@GLOBAL.csv_mode = IETF_QUOTES;
127+SELECT @@GLOBAL.csv_mode;
128+@@GLOBAL.csv_mode
129+IETF_QUOTES
130+SET @@GLOBAL.csv_mode = FOO;
131+ERROR 42000: Variable 'csv_mode' can't be set to the value of 'FOO'
132+SET @@GLOBAL.csv_mode = @saved_csv_mode;
133
134=== added file 'mysql-test/suite/sys_vars/t/csv_mode_basic.test'
135--- mysql-test/suite/sys_vars/t/csv_mode_basic.test 1970-01-01 00:00:00 +0000
136+++ mysql-test/suite/sys_vars/t/csv_mode_basic.test 2014-10-02 09:29:18 +0000
137@@ -0,0 +1,47 @@
138+# Basic sys_vars test for csv_mode variable
139+
140+SET @saved_csv_mode = @@SESSION.csv_mode;
141+
142+# Valid values
143+SET @@SESSION.csv_mode = 'ietf_quotes';
144+SELECT @@SESSION.csv_mode;
145+SET @@SESSION.csv_mode = 'IETF_QUOTES';
146+SELECT @@SESSION.csv_mode;
147+SET @@SESSION.csv_mode = IETF_QUOTES;
148+SELECT @@SESSION.csv_mode;
149+SET @@SESSION.csv_mode = '';
150+SELECT @@SESSION.csv_mode;
151+SET @@SESSION.csv_mode = 0;
152+SELECT @@SESSION.csv_mode;
153+SET @@SESSION.csv_mode = 1;
154+SELECT @@SESSION.csv_mode;
155+
156+# Invalid values
157+--error ER_WRONG_VALUE_FOR_VAR
158+SET @@SESSION.csv_mode = NULL;
159+--error ER_WRONG_VALUE_FOR_VAR
160+SET @@SESSION.csv_mode = FOO;
161+--error ER_WRONG_VALUE_FOR_VAR
162+SET @@SESSION.csv_mode = 'foo';
163+SELECT @@SESSION.csv_mode;
164+SET @@SESSION.csv_mode = 0;
165+SELECT @@SESSION.csv_mode;
166+--error ER_WRONG_VALUE_FOR_VAR
167+SET @@SESSION.csv_mode = -1;
168+--error ER_WRONG_VALUE_FOR_VAR
169+SET @@SESSION.csv_mode = 2;
170+
171+SET @@SESSION.csv_mode = @saved_csv_mode;
172+
173+# Test GLOBAL variable
174+
175+SET @saved_csv_mode = @@GLOBAL.csv_mode;
176+
177+SET @@GLOBAL.csv_mode = '';
178+SELECT @@GLOBAL.csv_mode;
179+SET @@GLOBAL.csv_mode = IETF_QUOTES;
180+SELECT @@GLOBAL.csv_mode;
181+--error ER_WRONG_VALUE_FOR_VAR
182+SET @@GLOBAL.csv_mode = FOO;
183+
184+SET @@GLOBAL.csv_mode = @saved_csv_mode;
185
186=== modified file 'mysql-test/t/csv.test'
187--- mysql-test/t/csv.test 2011-12-04 19:11:16 +0000
188+++ mysql-test/t/csv.test 2014-10-02 09:29:18 +0000
189@@ -1895,3 +1895,47 @@
190
191 DROP TABLE t1;
192 --echo End of 5.1 tests
193+
194+#
195+# Bug #71091 CSV engine does not properly process "", in quotes
196+#
197+
198+SET @old_csv_mode = @@SESSION.csv_mode;
199+SET @@SESSION.csv_mode='ietf_quotes';
200+CREATE TABLE t1(c1 TEXT NOT NULL, c2 TEXT NOT NULL) ENGINE=CSV;
201+
202+INSERT INTO t1 VALUES("a\"b,c","d");
203+INSERT INTO t1 VALUES("d","a\"b,c");
204+INSERT INTO t1 VALUES(",\"a","e");
205+INSERT INTO t1 VALUES("e",",\"a");
206+INSERT INTO t1 VALUES("\"","f");
207+INSERT INTO t1 VALUES("f","\"");
208+INSERT INTO t1 VALUES(",","g");
209+INSERT INTO t1 VALUES("g",",");
210+
211+SELECT * FROM t1;
212+
213+--echo CSV file contents:
214+--cat_file $MYSQLD_DATADIR/test/t1.CSV
215+
216+DROP TABLE t1;
217+
218+CREATE TABLE t1(c1 TEXT NOT NULL, c2 TEXT NOT NULL) ENGINE=CSV;
219+
220+--echo Replacing t1.CSV
221+--remove_file $MYSQLD_DATADIR/test/t1.CSV
222+--write_file $MYSQLD_DATADIR/test/t1.CSV
223+a,b
224+"a","b"
225+"a""b,c","d"
226+"d",",""a"
227+"a"",",e
228+e,""""
229+",",f
230+EOF
231+
232+SELECT * FROM t1;
233+
234+DROP TABLE t1;
235+
236+SET @@SESSION.csv_mode=@old_csv_mode;
237
238=== modified file 'storage/csv/ha_tina.cc'
239--- storage/csv/ha_tina.cc 2012-08-22 01:40:20 +0000
240+++ storage/csv/ha_tina.cc 2014-10-02 09:29:18 +0000
241@@ -67,6 +67,23 @@
242 #define CSN_EXT ".CSN" // Files used during repair and update
243 #define CSM_EXT ".CSM" // Meta file
244
245+enum csv_mode_enum { csv_mode_none= 0, csv_mode_ietf_quotes= 1 };
246+
247+static const char *csv_mode_names[]=
248+{
249+ "IETF_QUOTES", NullS
250+};
251+
252+static TYPELIB csv_mode_typelib=
253+{
254+ array_elements(csv_mode_names) - 1, "",
255+ csv_mode_names, NULL
256+};
257+
258+static MYSQL_THDVAR_SET(mode, PLUGIN_VAR_RQCMDARG,
259+ "Control CSV parser mode: []: default, ietf_quotes: "
260+ "standards-compatible embedded quote and comma parsing",
261+ NULL, NULL, 0, &csv_mode_typelib);
262
263 static TINA_SHARE *get_share(const char *table_name, TABLE *table);
264 static int free_share(TINA_SHARE *share);
265@@ -507,7 +524,7 @@
266 char attribute_buffer[1024];
267 String attribute(attribute_buffer, sizeof(attribute_buffer),
268 &my_charset_bin);
269-
270+ bool ietf_quotes= THDVAR(current_thd, mode) & csv_mode_ietf_quotes;
271 my_bitmap_map *org_bitmap= dbug_tmp_use_all_columns(table, table->read_set);
272 buffer.length(0);
273
274@@ -543,7 +560,7 @@
275 {
276 if (*ptr == '"')
277 {
278- buffer.append('\\');
279+ buffer.append(ietf_quotes ? '"' : '\\');
280 buffer.append('"');
281 }
282 else if (*ptr == '\r')
283@@ -635,6 +652,7 @@
284 my_bitmap_map *org_bitmap;
285 int error;
286 bool read_all;
287+ bool ietf_quotes= THDVAR(current_thd, mode) & csv_mode_ietf_quotes;
288 DBUG_ENTER("ha_tina::find_current_row");
289
290 free_root(&blobroot, MYF(0));
291@@ -668,8 +686,10 @@
292 a) If end of current field is reached, move
293 to next field and jump to step 2.3
294 b) If current character is a \\ handle
295- \\n, \\r, \\, \\"
296- c) else append the current character into the buffer
297+ \\n, \\r, \\, and \\" if not in ietf_quotes mode
298+ c) if in ietf_quotes mode and the current character is
299+ a ", handle ""
300+ d) else append the current character into the buffer
301 before checking that EOL has not been reached.
302 2.2) If the current character does not begin with a quote
303 2.2.1) Until EOL has not been reached
304@@ -710,15 +730,25 @@
305 curr_offset+= 2;
306 break;
307 }
308- if (curr_char == '\\' && curr_offset != (end_offset - 1))
309- {
310+ if (ietf_quotes && curr_char == '"'
311+ && file_buff->get_value(curr_offset + 1) == '"')
312+ {
313+ /* Embedded IETF quote */
314+ curr_offset++;
315+ buffer.append('"');
316+ }
317+ else if (curr_char == '\\' && curr_offset != (end_offset - 1))
318+ {
319+ /* A quote followed by something else than a comma, end of line, or
320+ (in IETF mode) another quote will be handled as a regular
321+ character. */
322 curr_offset++;
323 curr_char= file_buff->get_value(curr_offset);
324 if (curr_char == 'r')
325 buffer.append('\r');
326 else if (curr_char == 'n' )
327 buffer.append('\n');
328- else if (curr_char == '\\' || curr_char == '"')
329+ else if (curr_char == '\\' || (!ietf_quotes && curr_char == '"'))
330 buffer.append(curr_char);
331 else /* This could only happed with an externally created file */
332 {
333@@ -1740,6 +1770,11 @@
334 return COMPATIBLE_DATA_YES;
335 }
336
337+static struct st_mysql_sys_var* csv_system_variables[]= {
338+ MYSQL_SYSVAR(mode),
339+ NULL
340+};
341+
342 struct st_mysql_storage_engine csv_storage_engine=
343 { MYSQL_HANDLERTON_INTERFACE_VERSION };
344
345@@ -1755,7 +1790,7 @@
346 tina_done_func, /* Plugin Deinit */
347 0x0100 /* 1.0 */,
348 NULL, /* status variables */
349- NULL, /* system variables */
350+ csv_system_variables,
351 NULL, /* config options */
352 0, /* flags */
353 }

Subscribers

People subscribed via source and target branches