summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/loaddata.result119
-rw-r--r--mysql-test/t/loaddata.test186
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_load.cc4
5 files changed, 319 insertions, 4 deletions
diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result
index 3a23d9de6b3..a25d9561aba 100644
--- a/mysql-test/r/loaddata.result
+++ b/mysql-test/r/loaddata.result
@@ -337,6 +337,124 @@ DROP VIEW v2;
DROP VIEW v3;
# -- End of Bug#35469.
+Bug#37114
+SET SESSION character_set_client=latin1;
+SET SESSION character_set_server=latin1;
+SET SESSION character_set_connection=latin1;
+SET @OLD_SQL_MODE=@@SESSION.SQL_MODE;
+test LOAD DATA INFILE
+CREATE TABLE t1 (id INT, val1 CHAR(3)) ENGINE=MyISAM;
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' REPLACE INTO TABLE t1 FIELDS TERMINATED BY ' ';
+SELECT * FROM t1;
+id val1
+1 \aa
+SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug37114_out.txt' FIELDS ESCAPED BY '' TERMINATED BY ' ' FROM t1;
+SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug37114_out.txt' FIELDS TERMINATED BY ' ' FROM t1;
+INSERT INTO t1 (id, val1) VALUES (1, '\aa');
+SELECT * FROM t1;
+id val1
+1 \aa
+1 \aa
+SET sql_mode='';
+INSERT INTO t1 (id, val1) VALUES (1, '\aa');
+SELECT * FROM t1;
+id val1
+1 \aa
+1 \aa
+1 aa
+DROP TABLE t1;
+test SELECT INTO OUTFILE
+CREATE TABLE t1 (id INT PRIMARY KEY, val1 CHAR(4));
+CREATE TABLE t2 LIKE t1;
+SET sql_mode = '';
+INSERT INTO t1 (id, val1) VALUES (5, '\ttab');
+INSERT INTO t1 (id, val1) VALUES (4, '\\r');
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+INSERT INTO t1 (id, val1) VALUES (3, '\tx');
+1.1 NO_BACKSLASH_ESCAPES, use defaults for ESCAPED BY
+SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' FIELDS TERMINATED BY ' ' FROM t1 ORDER BY id;
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' INTO TABLE t2 FIELDS TERMINATED BY ' ';
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+t id val1 hex(val1)
+before 3 \tx 5C7478
+after 3 \tx 5C7478
+before 4 \r 5C72
+after 4 \r 5C72
+before 5 tab 09746162
+after 5 tab 09746162
+TRUNCATE t2;
+SELECT LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt");
+LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt")
+3 \tx
+4 \r
+5 tab
+
+1.2 NO_BACKSLASH_ESCAPES, override defaults for ESCAPED BY
+SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' FIELDS ESCAPED BY '\' TERMINATED BY ' ' FROM t1 ORDER BY id;
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' INTO TABLE t2 FIELDS ESCAPED BY '\' TERMINATED BY ' ';
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+t id val1 hex(val1)
+before 3 \tx 5C7478
+after 3 \tx 5C7478
+before 4 \r 5C72
+after 4 \r 5C72
+before 5 tab 09746162
+after 5 tab 09746162
+TRUNCATE t2;
+SELECT LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt");
+LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt")
+3 \\tx
+4 \\r
+5 tab
+
+SET sql_mode = '';
+2.1 !NO_BACKSLASH_ESCAPES, use defaults for ESCAPED BY
+SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' FIELDS TERMINATED BY ' ' FROM t1 ORDER BY id;
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' INTO TABLE t2 FIELDS TERMINATED BY ' ';
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+t id val1 hex(val1)
+before 3 \tx 5C7478
+after 3 \tx 5C7478
+before 4 \r 5C72
+after 4 \r 5C72
+before 5 tab 09746162
+after 5 tab 09746162
+TRUNCATE t2;
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+SELECT LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt");
+LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt")
+3 \\tx
+4 \\r
+5 tab
+
+SET sql_mode = '';
+2.2 !NO_BACKSLASH_ESCAPES, override defaults for ESCAPED BY
+SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' FIELDS ESCAPED BY '' TERMINATED BY ' ' FROM t1 ORDER BY id;
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug37114.txt' INTO TABLE t2 FIELDS ESCAPED BY '' TERMINATED BY ' ';
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+t id val1 hex(val1)
+before 3 \tx 5C7478
+after 3 \tx 5C7478
+before 4 \r 5C72
+after 4 \r 5C72
+before 5 tab 09746162
+after 5 tab 09746162
+TRUNCATE t2;
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+SELECT LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt");
+LOAD_FILE("MYSQLTEST_VARDIR/tmp/bug37114.txt")
+3 \tx
+4 \r
+5 tab
+
+set session sql_mode=@OLD_SQL_MODE;
+DROP TABLE t1,t2;
+End of 5.0 tests
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (1);
SET NAMES latin1;
@@ -364,3 +482,4 @@ SET character_set_filesystem=default;
select @@character_set_filesystem;
@@character_set_filesystem
binary
+End of 5.1 tests
diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test
index affb6c3bac7..9f93bb32d5f 100644
--- a/mysql-test/t/loaddata.test
+++ b/mysql-test/t/loaddata.test
@@ -322,7 +322,187 @@ DROP VIEW v3;
###########################################################################
-# End of 5.0 tests
+
+#
+# Bug#37114: sql_mode NO_BACKSLASH_ESCAPES does not work properly with
+# LOAD DATA INFILE
+#
+
+# - For each plain "SELECT id,...", the 1st pair ("before" SELECT...OUTFILE,
+# LOAD...INFILE) and the 2nd pair of lines ("after") in the result should
+# look the same, otherwise we broke the dumpe/restore cycle!
+#
+# - the \r is always { '\\', 'r' } in memory, but on-disk format changes
+#
+# - the \t is { '\t' } or { '\\', 't' } in memory depending on whether \
+# is magic (that is, NO_BACKSLASH_ESCAPES is not set) at INSERT-time.
+# on-disk format varies.
+#
+# - while INFILE/OUTFILE behaviour changes according to NO_BACKSLASH_ESCAPES,
+# we can override these defaults using ESCAPED BY '...'
+# 1: NO_BACKSLASH_ESCAPES default, \ on-disk: \,t,x,\r
+# 2: NO_BACKSLASH_ESCAPES override, \\ on-disk: \,\,t,x,\,\,r
+# 3: !NO_BACKSLASH_ESCAPES default, \\ on-disk: tab,\,\,r
+# 3: !NO_BACKSLASH_ESCAPES override, \ on-disk: tab,\,r
+
+--echo Bug#37114
+
+SET SESSION character_set_client=latin1;
+SET SESSION character_set_server=latin1;
+SET SESSION character_set_connection=latin1;
+SET @OLD_SQL_MODE=@@SESSION.SQL_MODE;
+
+# 0. test LOAD DATA INFILE first; if that works, all issues in
+# SELECT INTO OUTFILE / LOAD DATA INFILE cycles below are
+# arguably in the saving.
+
+--echo test LOAD DATA INFILE
+
+--let $file=$MYSQLTEST_VARDIR/tmp/bug37114.txt
+--let $file2=$MYSQLTEST_VARDIR/tmp/bug37114_out.txt
+
+--write_file $file
+1 \aa
+EOF
+
+CREATE TABLE t1 (id INT, val1 CHAR(3)) ENGINE=MyISAM;
+
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval LOAD DATA LOCAL INFILE '$file' REPLACE INTO TABLE t1 FIELDS TERMINATED BY ' '
+SELECT * FROM t1;
+
+# show we can write this with OUTFILE, forcing the parameters for now
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT * INTO OUTFILE '$file2' FIELDS ESCAPED BY '' TERMINATED BY ' ' FROM t1
+--diff_files $file $file2
+--remove_file $file2
+
+# now show the OUTFILE defaults are correct with NO_BACKSLASH_ESCAPES
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT * INTO OUTFILE '$file2' FIELDS TERMINATED BY ' ' FROM t1
+--diff_files $file $file2
+--remove_file $file2
+
+INSERT INTO t1 (id, val1) VALUES (1, '\aa');
+SELECT * FROM t1;
+
+SET sql_mode='';
+INSERT INTO t1 (id, val1) VALUES (1, '\aa');
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--remove_file $file
+
+
+
+--echo test SELECT INTO OUTFILE
+
+CREATE TABLE t1 (id INT PRIMARY KEY, val1 CHAR(4));
+CREATE TABLE t2 LIKE t1;
+
+# 1. with NO_BACKSLASH_ESCAPES on
+
+SET sql_mode = '';
+INSERT INTO t1 (id, val1) VALUES (5, '\ttab');
+INSERT INTO t1 (id, val1) VALUES (4, '\\r');
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+INSERT INTO t1 (id, val1) VALUES (3, '\tx');
+
+--echo 1.1 NO_BACKSLASH_ESCAPES, use defaults for ESCAPED BY
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT * INTO OUTFILE '$file' FIELDS TERMINATED BY ' ' FROM t1 ORDER BY id
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval LOAD DATA INFILE '$file' INTO TABLE t2 FIELDS TERMINATED BY ' '
+
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+ SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+
+TRUNCATE t2;
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval SELECT LOAD_FILE("$file");
+--remove_file $file
+
+
+
+--echo 1.2 NO_BACKSLASH_ESCAPES, override defaults for ESCAPED BY
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT * INTO OUTFILE '$file' FIELDS ESCAPED BY '\' TERMINATED BY ' ' FROM t1 ORDER BY id
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval LOAD DATA INFILE '$file' INTO TABLE t2 FIELDS ESCAPED BY '\' TERMINATED BY ' '
+
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+ SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+
+TRUNCATE t2;
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval SELECT LOAD_FILE("$file");
+--remove_file $file
+
+
+
+# 2. with NO_BACKSLASH_ESCAPES off
+
+SET sql_mode = '';
+
+--echo 2.1 !NO_BACKSLASH_ESCAPES, use defaults for ESCAPED BY
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT * INTO OUTFILE '$file' FIELDS TERMINATED BY ' ' FROM t1 ORDER BY id
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval LOAD DATA INFILE '$file' INTO TABLE t2 FIELDS TERMINATED BY ' '
+
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+ SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+
+TRUNCATE t2;
+
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval SELECT LOAD_FILE("$file");
+--remove_file $file
+
+SET sql_mode = '';
+
+
+
+--echo 2.2 !NO_BACKSLASH_ESCAPES, override defaults for ESCAPED BY
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT * INTO OUTFILE '$file' FIELDS ESCAPED BY '' TERMINATED BY ' ' FROM t1 ORDER BY id
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval LOAD DATA INFILE '$file' INTO TABLE t2 FIELDS ESCAPED BY '' TERMINATED BY ' '
+
+SELECT 'before' AS t, id, val1, hex(val1) FROM t1 UNION
+ SELECT 'after' AS t, id, val1, hex(val1) FROM t2 ORDER BY id,t DESC;
+
+TRUNCATE t2;
+
+SET sql_mode = 'NO_BACKSLASH_ESCAPES';
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval SELECT LOAD_FILE("$file");
+--remove_file $file
+
+# clean up
+set session sql_mode=@OLD_SQL_MODE;
+DROP TABLE t1,t2;
+
+
+
+--echo End of 5.0 tests
+
#
@@ -347,3 +527,7 @@ DROP TABLE t1;
remove_file $MYSQLTEST_VARDIR/master-data/test/t@002d1;
SET character_set_filesystem=default;
select @@character_set_filesystem;
+
+
+
+--echo End of 5.1 tests
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6f682368334..c4a4312ad85 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1481,6 +1481,12 @@ sql_exchange::sql_exchange(char *name,bool flag)
cs= NULL;
}
+bool sql_exchange::escaped_given(void)
+{
+ return escaped != &default_escaped;
+}
+
+
bool select_send::send_fields(List<Item> &list, uint flags)
{
bool res;
@@ -1766,8 +1772,11 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
exchange->line_term=exchange->field_term; // Use this if it exists
field_sep_char= (exchange->enclosed->length() ?
(int) (uchar) (*exchange->enclosed)[0] : field_term_char);
- escape_char= (exchange->escaped->length() ?
- (int) (uchar) (*exchange->escaped)[0] : -1);
+ if (exchange->escaped->length() && (exchange->escaped_given() ||
+ !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
+ escape_char= (int) (uchar) (*exchange->escaped)[0];
+ else
+ escape_char= -1;
is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char));
is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char));
line_sep_char= (exchange->line_term->length() ?
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 019699dff5a..60051ed02cc 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2250,6 +2250,7 @@ public:
ulong skip_lines;
CHARSET_INFO *cs;
sql_exchange(char *name,bool dumpfile_flag);
+ bool escaped_given(void);
};
#include "log_event.h"
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 255d8e5813d..239fb1d49f3 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -327,7 +327,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
bzero((char*) &info,sizeof(info));
info.ignore= ignore;
info.handle_duplicates=handle_duplicates;
- info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
+ info.escape_char= (escaped->length() && (ex->escaped_given() ||
+ !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
+ ? (*escaped)[0] : INT_MAX;
READ_INFO read_info(file,tot_length,
ex->cs ? ex->cs : thd->variables.collation_database,