From 39385ff7b253302723a94c896d199a83adb8622f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Jun 2017 13:25:50 +0200 Subject: [PATCH 1/2] MDEV-13187 incorrect backslash parsing in clients don't do backslash escapes inside backticks --- client/mysql.cc | 4 ++-- client/mysqltest.cc | 4 ++-- mysql-test/r/mysql.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/mysql.test | 15 +++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 57cb0a918a7..6a800e407a3 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2287,8 +2287,8 @@ static bool add_line(String &buffer, char *line, ulong line_length, continue; } #endif - if (!*ml_comment && inchar == '\\' && - !(*in_string && + if (!*ml_comment && inchar == '\\' && *in_string != '`' && + !(*in_string && (mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES))) { // Found possbile one character command like \c diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 4de40953f7d..ee636c9401d 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -6594,7 +6594,7 @@ int read_line(char *buf, int size) state= R_Q; } } - have_slash= (c == '\\'); + have_slash= (c == '\\' && last_quote != '`'); break; case R_COMMENT: @@ -6664,7 +6664,7 @@ int read_line(char *buf, int size) case R_Q: if (c == last_quote) state= R_NORMAL; - else if (c == '\\') + else if (c == '\\' && last_quote != '`') state= R_SLASH_IN_Q; break; diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index dd0129df0d9..dad8b3a701c 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -529,3 +529,31 @@ a +-------------------+ End of tests +create table `a1\``b1` (a int); +show tables; +Tables_in_test +a1\`b1 +insert `a1\``b1` values (1),(2); +show create table `a1\``b1`; +Table Create Table +a1\`b1 CREATE TABLE `a1\``b1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `a1\``b1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; +INSERT INTO `a1\``b1` VALUES (1),(2); +insert `a1\``b1` values (4),(5); +show create table `a1\``b1`; +Table Create Table +a1\`b1 CREATE TABLE `a1\``b1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from `a1\``b1`; +a +1 +2 +drop table `a1\``b1`; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index d59083d66b0..20205924e15 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -618,3 +618,18 @@ EOF --echo --echo End of tests + +# +# MDEV-13187 incorrect backslash parsing in clients +# +create table `a1\``b1` (a int); +show tables; +insert `a1\``b1` values (1),(2); +show create table `a1\``b1`; +--exec $MYSQL_DUMP --compact test +--exec $MYSQL_DUMP test > $MYSQLTEST_VARDIR/tmp/bug.sql +insert `a1\``b1` values (4),(5); +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/bug.sql +show create table `a1\``b1`; +select * from `a1\``b1`; +drop table `a1\``b1`; From d5cd33450413816f8696125cd66c8393921e6267 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Jun 2017 14:00:10 +0200 Subject: [PATCH 2/2] MDEV-13187 incorrect backslash parsing in clients cover ANSI_QUOTES and NO_BACKSLASH_ESCAPES in mysqltest --- client/mysql.cc | 2 ++ client/mysqltest.cc | 14 ++++++++++++-- include/mysql_com.h | 2 ++ mysql-test/r/mysql.result | 30 ++++++++++++++++++++++++++++++ mysql-test/r/mysqltest.result | 5 +++++ mysql-test/t/mysql.test | 15 +++++++++++++++ mysql-test/t/mysqltest.test | 8 +++++++- sql/sql_class.cc | 2 ++ sql/sys_vars.cc | 4 ++++ 9 files changed, 79 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 6a800e407a3..a965ced89c6 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2288,6 +2288,8 @@ static bool add_line(String &buffer, char *line, ulong line_length, } #endif if (!*ml_comment && inchar == '\\' && *in_string != '`' && + !(*in_string == '"' && + (mysql.server_status & SERVER_STATUS_ANSI_QUOTES)) && !(*in_string && (mysql.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES))) { diff --git a/client/mysqltest.cc b/client/mysqltest.cc index ee636c9401d..f5ee94f1839 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -6486,6 +6486,16 @@ my_bool end_of_query(int c) } +static inline bool is_escape_char(char c, char in_string) +{ + if (c != '\\' || in_string == '`') return false; + if (!cur_con) return true; + uint server_status= cur_con->mysql->server_status; + if (server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) return false; + return !(server_status & SERVER_STATUS_ANSI_QUOTES && in_string == '"'); +} + + /* Read one "line" from the file @@ -6594,7 +6604,7 @@ int read_line(char *buf, int size) state= R_Q; } } - have_slash= (c == '\\' && last_quote != '`'); + have_slash= is_escape_char(c, last_quote); break; case R_COMMENT: @@ -6664,7 +6674,7 @@ int read_line(char *buf, int size) case R_Q: if (c == last_quote) state= R_NORMAL; - else if (c == '\\' && last_quote != '`') + else if (is_escape_char(c, last_quote)) state= R_SLASH_IN_Q; break; diff --git a/include/mysql_com.h b/include/mysql_com.h index 0d57b178937..df9681e02a4 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -296,6 +296,8 @@ enum enum_server_command */ #define SERVER_PS_OUT_PARAMS 4096 +#define SERVER_STATUS_ANSI_QUOTES 32768 + /** Server status flags that must be cleared when starting execution of a new SQL statement. diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index dad8b3a701c..8a24128daa2 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -557,3 +557,33 @@ a 1 2 drop table `a1\``b1`; +set sql_mode=ansi_quotes; +create table "a1\""b1" (a int); +show tables; +Tables_in_test +a1\"b1 +insert "a1\""b1" values (1),(2); +show create table "a1\""b1"; +Table Create Table +a1\"b1 CREATE TABLE "a1\""b1" ( + "a" int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE "a1\""b1" ( + "a" int(11) DEFAULT NULL +); +/*!40101 SET character_set_client = @saved_cs_client */; +INSERT INTO "a1\""b1" VALUES (1),(2); +insert "a1\""b1" values (4),(5); +show create table "a1\""b1"; +Table Create Table +a1\"b1 CREATE TABLE "a1\""b1" ( + "a" int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from "a1\""b1"; +a +1 +2 +drop table "a1\""b1"; +set sql_mode=default; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 0ebef585974..9800aed6368 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -957,4 +957,9 @@ con1 con2 con2 -closed_connection- +set sql_mode=no_backslash_escapes; +select "foo\""bar"; +foo\"bar +foo\"bar +set sql_mode=default; End of tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 20205924e15..dd964c46420 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -633,3 +633,18 @@ insert `a1\``b1` values (4),(5); show create table `a1\``b1`; select * from `a1\``b1`; drop table `a1\``b1`; + +# same with ansi_quotes +set sql_mode=ansi_quotes; +create table "a1\""b1" (a int); +show tables; +insert "a1\""b1" values (1),(2); +show create table "a1\""b1"; +--exec $MYSQL_DUMP --compact --compatible=postgres test +--exec $MYSQL_DUMP --compatible=postgres test > $MYSQLTEST_VARDIR/tmp/bug.sql +insert "a1\""b1" values (4),(5); +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/bug.sql +show create table "a1\""b1"; +select * from "a1\""b1"; +drop table "a1\""b1"; +set sql_mode=default; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 6470ede4f14..afe37926591 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -2942,11 +2942,17 @@ disconnect $x; # Disconnect the selected connection disconnect $y; --echo $CURRENT_CONNECTION +connection default; +# +# MDEV-13187 incorrect backslash parsing in clients +# +set sql_mode=no_backslash_escapes; +select "foo\""bar"; +set sql_mode=default; --echo End of tests -connection default; # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 46eabb41a74..3c07c1606a2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1250,6 +1250,8 @@ void THD::init(void) server_status= SERVER_STATUS_AUTOCOMMIT; if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; + if (variables.sql_mode & MODE_ANSI_QUOTES) + server_status|= SERVER_STATUS_ANSI_QUOTES; transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 35997525456..ffe861ddfbc 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2173,6 +2173,10 @@ static bool fix_sql_mode(sys_var *self, THD *thd, enum_var_type type) thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; else thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES; + if (thd->variables.sql_mode & MODE_ANSI_QUOTES) + thd->server_status|= SERVER_STATUS_ANSI_QUOTES; + else + thd->server_status&= ~SERVER_STATUS_ANSI_QUOTES; } return false; }