Commit 725b4971 authored by unknown's avatar unknown

Fixed bug #29442.

The SELECT INTO OUTFILE FIELDS ENCLOSED BY digit or minus sign,
followed by the same LOAD DATA INFILE statement, used wrond encoding
of non-string fields contained the enclosed character in their text
representation.

Example:
  SELECT 15, 9 INTO OUTFILE 'text' FIELDS ENCLOSED BY '5';

Old encoded result in the text file:
  5155 595
         ^ was decoded as the 1st enclosing character of the 2nd field;
        ^ was skipped as garbage;
  ^    ^ was decoded as a pair of englosing characters of the 1st field;
      ^   was decoded as traling space of the first field;
    ^^ was decoded as a doubled enclosed character.

New encoded result in the text file:
  51\55 595
  ^   ^ pair of enclosing characters of the 1st field;
    ^^ escaped enclosed character.



sql/sql_class.h:
  Fixed bug #29442.
  The NUMERIC_CHARS macro constant has been defined to enumerate
  all possible characters of a numeric value text representation.
  The select_export::is_unsafe_field_sep boolean flag has been added
  to apply the encoding algorithm to non-string values when it is
  necessary.
sql/sql_class.cc:
  Fixed bug #29442.
  The select_export::send_data method has been modified to encode text
  representation of fields of all data types like string fields.
mysql-test/t/loaddata.test:
  Updated test case for bug #29442.
mysql-test/r/loaddata.result:
  Updated test case for bug #29442.
parent e0f93ca8
......@@ -238,3 +238,17 @@ f1
1
2
drop table t1,t2;
CREATE TABLE t1 (c1 INT, c2 TIMESTAMP, c3 REAL, c4 DOUBLE);
INSERT INTO t1 (c1, c2, c3, c4) VALUES (10, '1970-02-01 01:02:03', 1.1E-100, 1.1E+100);
SELECT * FROM t1;
c1 c2 c3 c4
10 1970-02-01 01:02:03 1.1e-100 1.1e+100
SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/t1' FIELDS ENCLOSED BY '-' FROM t1;
-10- -1970\-02\-01 01:02:03- -1.1e\-100- -1.1e+100-
EOF
TRUNCATE t1;
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1' INTO TABLE t1 FIELDS ENCLOSED BY '-';
SELECT * FROM t1;
c1 c2 c3 c4
10 1970-02-01 01:02:03 1.1e-100 1.1e+100
DROP TABLE t1;
......@@ -213,4 +213,29 @@ select f1 from t1 where f2 <> '0000-00-00 00:00:00' order by f1;
--exec rm $MYSQLTEST_VARDIR/tmp/t2
drop table t1,t2;
#
# Bug#29442: SELECT INTO OUTFILE FIELDS ENCLOSED BY digit, minus sign etc
# corrupts non-string fields containing this character.
#
CREATE TABLE t1 (c1 INT, c2 TIMESTAMP, c3 REAL, c4 DOUBLE);
INSERT INTO t1 (c1, c2, c3, c4) VALUES (10, '1970-02-01 01:02:03', 1.1E-100, 1.1E+100);
SELECT * FROM t1;
--exec rm -f $MYSQLTEST_VARDIR/tmp/t1
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/t1' FIELDS ENCLOSED BY '-' FROM t1;
--exec cat $MYSQLTEST_VARDIR/tmp/t1
--exec echo EOF
TRUNCATE t1;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/t1' INTO TABLE t1 FIELDS ENCLOSED BY '-';
SELECT * FROM t1;
--exec rm $MYSQLTEST_VARDIR/tmp/t1
DROP TABLE t1;
# End of 5.0 tests
......@@ -1210,6 +1210,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
field_term_length ? (*exchange->field_term)[0] : INT_MAX);
escape_char= (exchange->escaped->length() ? (*exchange->escaped)[0] : -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() ?
(*exchange->line_term)[0] : INT_MAX);
if (!field_term_length)
......@@ -1284,7 +1285,8 @@ bool select_export::send_data(List<Item> &items)
used_length=min(res->length(),item->max_length);
else
used_length=res->length();
if (result_type == STRING_RESULT && escape_char != -1)
if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
escape_char != -1)
{
char *pos, *start, *end;
CHARSET_INFO *res_charset= res->charset();
......
......@@ -1929,6 +1929,12 @@ public:
#define ESCAPE_CHARS "ntrb0ZN" // keep synchronous with READ_INFO::unescape
/*
List of all possible characters of a numeric value text representation.
*/
#define NUMERIC_CHARS ".0123456789e+-"
class select_export :public select_to_file {
uint field_term_length;
int field_sep_char,escape_char,line_sep_char;
......@@ -1938,6 +1944,12 @@ class select_export :public select_to_file {
(see the READ_INFO::unescape method and the ESCAPE_CHARS constant value).
*/
bool is_ambiguous_field_sep;
/*
The is_unsafe_field_sep field is true if a value of the field_sep_char
field is one of the '0'..'9', '+', '-', '.' and 'e' characters
(see the NUMERIC_CHARS constant value).
*/
bool is_unsafe_field_sep;
bool fixed_row_size;
public:
select_export(sql_exchange *ex) :select_to_file(ex) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment