[Commits] Rev 3504: MDEV-382: SQL injections in server code. in http://bazaar.launchpad.net/~maria-captains/maria/5.5

knielsen at knielsen-hq.org knielsen at knielsen-hq.org
Wed Aug 22 15:48:45 EEST 2012


At http://bazaar.launchpad.net/~maria-captains/maria/5.5

------------------------------------------------------------
revno: 3504
revision-id: knielsen at knielsen-hq.org-20120810142232-iqq5z1r6ce1u8h0u
parent: knielsen at knielsen-hq.org-20120706091916-92lztvewh8gij2b9
committer: knielsen at knielsen-hq.org
branch nick: work-5.5-todo220
timestamp: Fri 2012-08-10 16:22:32 +0200
message:
  MDEV-382: SQL injections in server code.
  
  After-review fixes + fix some more injection issues found.
=== modified file 'client/mysqlbinlog.cc'
--- a/client/mysqlbinlog.cc	2012-07-06 09:19:16 +0000
+++ b/client/mysqlbinlog.cc	2012-08-10 14:22:32 +0000
@@ -743,9 +743,7 @@ print_use_stmt(PRINT_EVENT_INFO* pinfo,
     return;
 
   // In case of rewrite rule print USE statement for db_to
-  char buf[FN_REFLEN*2+3];  /* Room for expand ` to `` + initial/final ` + \0 */
-  my_snprintf(buf, sizeof(buf), "%`s", db_to);
-  fprintf(result_file, "use %s%s\n", buf, pinfo->delimiter);
+  my_fprintf(result_file, "use %`s%s\n", db_to, pinfo->delimiter);
 
   // Copy the *original* db to pinfo to suppress emiting
   // of USE stmts by log_event print-functions.

=== modified file 'include/my_sys.h'
--- a/include/my_sys.h	2012-07-06 09:19:16 +0000
+++ b/include/my_sys.h	2012-08-10 14:22:32 +0000
@@ -627,6 +627,7 @@ extern FILE *my_fdopen(File Filedes,cons
 extern FILE *my_freopen(const char *path, const char *mode, FILE *stream);
 extern int my_fclose(FILE *fd,myf MyFlags);
 extern int my_vfprintf(FILE *stream, const char* format, va_list args);
+extern int my_fprintf(FILE *stream, const char* format, ...);
 extern File my_fileno(FILE *fd);
 extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
 extern int my_chmod(const char *name, mode_t mode, myf my_flags);

=== modified file 'mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result	2011-05-12 04:56:41 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result	2012-08-10 14:22:32 +0000
@@ -698,7 +698,7 @@ master-bin.000001	#	Query	#	#	BEGIN
 master-bin.000001       #       Intvar  #       #       INSERT_ID=10
 master-bin.000001       #       Begin_load_query        #       #       ;file_id=#;block_len=#
 master-bin.000001       #       Intvar  #       #       INSERT_ID=10
-master-bin.000001       #       Execute_load_query      #       #       use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @b) SET `b`= @b + bug27417(2) ;file_id=#
+master-bin.000001       #       Execute_load_query      #       #       use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @`b`) SET `b`= @b + bug27417(2) ;file_id=#
 master-bin.000001       #       Query   #       #       ROLLBACK
 /* the output must denote there is the query */;
 drop trigger trg_del_t2;
@@ -950,7 +950,7 @@ master-bin.000001	#	User var	#	#	@`b`=_l
 master-bin.000001       #       Begin_load_query        #       #       ;file_id=#;block_len=#
 master-bin.000001       #       Intvar  #       #       INSERT_ID=10
 master-bin.000001       #       User var        #       #       @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
-master-bin.000001       #       Execute_load_query      #       #       use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @b) SET `b`= @b + bug27417(2) ;file_id=#
+master-bin.000001       #       Execute_load_query      #       #       use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @`b`) SET `b`= @b + bug27417(2) ;file_id=#
 master-bin.000001       #       Query   #       #       ROLLBACK
 drop trigger trg_del_t2;
 drop table t1,t2,t3,t4,t5;

=== modified file 'mysql-test/suite/rpl/r/rpl_mdev382.result'
--- a/mysql-test/suite/rpl/r/rpl_mdev382.result	2012-07-06 09:19:16 +0000
+++ b/mysql-test/suite/rpl/r/rpl_mdev382.result	2012-08-10 14:22:32 +0000
@@ -127,7 +127,7 @@ CREATE TABLE `t``1` (`a``1` VARCHAR(4) P
 LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f''le.txt' INTO TABLE `t``1`
   FIELDS TERMINATED BY ',' ESCAPED BY '\\' ENCLOSED BY ''''
   LINES TERMINATED BY '\n'
-  (`a``1`, `b``2`) SET `c``3` = concat('|', "b""a'z", "!");
+  (`a``1`, @`b```) SET `b``2` = @`b```, `c``3` = concat('|', "b""a'z", "!");
 SELECT * FROM `t``1`;
 a`1     b`2     c`3
 fo\o    bar     |b"a'z!
@@ -147,7 +147,7 @@ master-bin.000001	#	Query	#	#	use `db1``
 `c``3` VARCHAR(7))
 master-bin.000001       #       Query   #       #       BEGIN
 master-bin.000001       #       Begin_load_query        #       #       ;file_id=#;block_len=#
-master-bin.000001       #       Execute_load_query      #       #       use `db1``; SELECT 'oops!'`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f\'le.txt' INTO TABLE `t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3`= concat('|', "b""a'z", "!") ;file_id=#
+master-bin.000001       #       Execute_load_query      #       #       use `db1``; SELECT 'oops!'`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/f\'le.txt' INTO TABLE `t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, @`b```) SET `b``2`= @`b```, `c``3`= concat('|', "b""a'z", "!") ;file_id=#
 master-bin.000001       #       Query   #       #       COMMIT
 master-bin.000001       #       Query   #       #       use `db1``; SELECT 'oops!'`; truncate `t``1`
 master-bin.000001       #       Query   #       #       BEGIN
@@ -175,7 +175,7 @@ SET TIMESTAMP=1000000000/*!*/;
 BEGIN
 /*!*/;
 SET TIMESTAMP=1000000000/*!*/;
-LOAD DATA LOCAL INFILE '<name>' INTO TABLE `t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, `b``2`) SET `c``3`= concat('|', "b""a'z", "!")
+LOAD DATA LOCAL INFILE '<name>' INTO TABLE `t``1` FIELDS TERMINATED BY ',' ENCLOSED BY '\'' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a``1`, @`b```) SET `b``2`= @`b```, `c``3`= concat('|', "b""a'z", "!")
 /*!*/;
 SET TIMESTAMP=1000000000/*!*/;
 COMMIT
@@ -202,6 +202,26 @@ a`1	b`2	c`3
 fo\o    bar     |b"a'z!
 DROP TABLE `db1``; SELECT 'oops!'`.`t``1`;
 drop table t1,t2;
+*** Test truncation of long SET expression in LOAD DATA ***
+CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(1000));
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/file.txt' INTO TABLE t1
+FIELDS TERMINATED BY ','
+  (a, @b) SET b = CONCAT(@b, '| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|', @b);
+SELECT * FROM t1 ORDER BY a;
+a       b
+1       X| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|X
+2       A| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|A
+show binlog events from <binlog_start>;
+Log_name        Pos     Event_type      Server_id       End_log_pos     Info
+master-bin.000001       #       Query   #       #       BEGIN
+master-bin.000001       #       Begin_load_query        #       #       ;file_id=#;block_len=#
+master-bin.000001       #       Execute_load_query      #       #       use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/file.txt' INTO TABLE `t1` FIELDS TERMINATED BY ',' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`a`, @`b`) SET `b`= CONCAT(@b, '| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|', @b) ;file_id=#
+master-bin.000001       #       Query   #       #       COMMIT
+SELECT * FROM t1 ORDER BY a;
+a       b
+1       X| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|X
+2       A| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|A
+DROP TABLE t1;
 *** Test user variables whose names require correct quoting ***
 use `db1``; SELECT 'oops!'`;
 CREATE TABLE t1 (a1 BIGINT PRIMARY KEY, a2 BIGINT, a3 BIGINT, a4 BIGINT UNSIGNED, b DOUBLE, c DECIMAL(65,10), d VARCHAR(100));
@@ -285,16 +305,40 @@ TRUNCATE `t``1`;
 ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`db1``; SELECT 'oops!'`.`t``2`, CONSTRAINT `INNODB_FOREIGN_KEY_NAME` FOREIGN KEY (`c```) REFERENCES `db1``; SELECT 'oops!'`.`t``1` (`a```))
 DROP TABLE `t``2`;
 DROP TABLE `t``1`;
+*** Test correct quoting of DELETE FROM statement binlogged for HEAP table that is emptied due to server restart
+include/stop_slave.inc
+CREATE TABLE `db1``; SELECT 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap;
+INSERT INTO `db1``; SELECT 'oops!'`.`t``1` VALUES (1), (2), (5);
+SELECT * FROM `db1``; SELECT 'oops!'`.`t``1` ORDER BY 1;
+a`
+1
+2
+5
+set timestamp=1000000000;
+# The table should be empty on the master.
+SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`;
+a`
+# The DELETE statement should be correctly quoted
+show binlog events in 'master-bin.000002' from <binlog_start>;
+Log_name        Pos     Event_type      Server_id       End_log_pos     Info
+master-bin.000002       #       Query   #       #       BEGIN
+master-bin.000002       #       Query   #       #       use `test`; DELETE FROM `db1``; SELECT 'oops!'`.`t``1`
+master-bin.000002       #       Query   #       #       COMMIT
+include/start_slave.inc
+# The table should be empty on the slave also.
+SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`;
+a`
+DROP TABLE `db1``; SELECT 'oops!'`.`t``1`;
 use test;
 DROP DATABASE `db1``; SELECT 'oops!'`;
 *** Test correct quoting of mysqlbinlog --rewrite-db option ***
 CREATE TABLE t1 (a INT PRIMARY KEY);
 INSERT INTO t1 VALUES(1);
-show binlog events from <binlog_start>;
+show binlog events in 'master-bin.000002' from <binlog_start>;
 Log_name        Pos     Event_type      Server_id       End_log_pos     Info
-master-bin.000001       #       Query   #       #       BEGIN
-master-bin.000001       #       Query   #       #       use `test`; INSERT INTO t1 VALUES(1)
-master-bin.000001       #       Query   #       #       COMMIT
+master-bin.000002       #       Query   #       #       BEGIN
+master-bin.000002       #       Query   #       #       use `test`; INSERT INTO t1 VALUES(1)
+master-bin.000002       #       Query   #       #       COMMIT
 /*!40019 SET @@session.max_insert_delayed_threads=0*/;
 /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
 DELIMITER /*!*/;

=== modified file 'mysql-test/suite/rpl/t/rpl_mdev382.test'
--- a/mysql-test/suite/rpl/t/rpl_mdev382.test	2012-07-06 09:19:16 +0000
+++ b/mysql-test/suite/rpl/t/rpl_mdev382.test	2012-08-10 14:22:32 +0000
@@ -84,7 +84,7 @@ use test;
 --echo ***Test LOAD DATA INFILE with various identifiers that need correct quoting ***
 
 --let $load_file= $MYSQLTEST_VARDIR/tmp/f'le.txt
---write_file $MYSQLTEST_VARDIR/tmp/f'le.txt
+--write_file $load_file
 'fo\\o','bar'
 EOF
 
@@ -97,8 +97,8 @@ CREATE TABLE `t``1` (`a``1` VARCHAR(4) P
 eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/f''le.txt' INTO TABLE `t``1`
   FIELDS TERMINATED BY ',' ESCAPED BY '\\\\' ENCLOSED BY ''''
   LINES TERMINATED BY '\\n'
-  (`a``1`, `b``2`) SET `c``3` = concat('|', "b""a'z", "!");
-#  FIELDS TERMINATED BY ',' ESCAPED BY '\\' LINES TERMINATED BY '\n'
+  (`a``1`, @`b```) SET `b``2` = @`b```, `c``3` = concat('|', "b""a'z", "!");
+
 SELECT * FROM `t``1`;
 # Also test when code prefixes table name with database.
 truncate `t``1`;
@@ -123,11 +123,40 @@ SELECT * FROM `db1``; SELECT 'oops!'`.`t
 connection master;
 
 DROP TABLE `db1``; SELECT 'oops!'`.`t``1`;
---remove_file $MYSQLTEST_VARDIR/tmp/f'le.txt
+--remove_file $load_file
 
 connection master;
 drop table t1,t2;
 
+
+--echo *** Test truncation of long SET expression in LOAD DATA ***
+CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(1000));
+--let $load_file= $MYSQLTEST_VARDIR/tmp/file.txt
+--write_file $load_file
+1,X
+2,A
+EOF
+
+let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+# The bug was that the SET expression was truncated to 256 bytes, so test with
+# an expression longer than that.
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval LOAD DATA INFILE '$load_file' INTO TABLE t1
+  FIELDS TERMINATED BY ','
+  (a, @b) SET b = CONCAT(@b, '| 123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R123456789123456789T123456789U123456789V123456789W123456789X123456789Y123456789Z123456789|', @b);
+
+SELECT * FROM t1 ORDER BY a;
+--source include/show_binlog_events.inc
+
+sync_slave_with_master;
+connection slave;
+SELECT * FROM t1 ORDER BY a;
+
+connection master;
+--remove_file $load_file
+DROP TABLE t1;
+
+
 --echo *** Test user variables whose names require correct quoting ***
 use `db1``; SELECT 'oops!'`;
 let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
@@ -159,6 +188,67 @@ TRUNCATE `t``1`;
 DROP TABLE `t``2`;
 DROP TABLE `t``1`;
 
+
+--echo *** Test correct quoting of DELETE FROM statement binlogged for HEAP table that is emptied due to server restart
+
+# Let's keep the slave stopped during master restart, to avoid any potential
+# races between slave reconnect and master restart.
+connection slave;
+--source include/stop_slave.inc
+
+connection master;
+CREATE TABLE `db1``; SELECT 'oops!'`.`t``1` (`a``` INT PRIMARY KEY) ENGINE=heap;
+INSERT INTO `db1``; SELECT 'oops!'`.`t``1` VALUES (1), (2), (5);
+SELECT * FROM `db1``; SELECT 'oops!'`.`t``1` ORDER BY 1;
+
+# Restart the master mysqld.
+# This will cause an implicit truncation of the memory-based table, which will
+# cause logging of an explicit DELETE FROM to binlog.
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait-rpl_mdev382.test
+EOF
+
+--shutdown_server 30
+
+--remove_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart-rpl_mdev382.test
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+connection master;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+set timestamp=1000000000;
+
+--echo # The table should be empty on the master.
+let $binlog_file= master-bin.000002;
+let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
+SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`;
+
+--echo # The DELETE statement should be correctly quoted
+--source include/show_binlog_events.inc
+
+connection slave;
+--source include/start_slave.inc
+
+connection master;
+sync_slave_with_master;
+connection slave;
+--echo # The table should be empty on the slave also.
+SELECT * FROM `db1``; SELECT 'oops!'`.`t``1`;
+
+connection master;
+DROP TABLE `db1``; SELECT 'oops!'`.`t``1`;
+sync_slave_with_master;
+
+
 connection master;
 use test;
 DROP DATABASE `db1``; SELECT 'oops!'`;
@@ -169,7 +259,7 @@ let $binlog_start= query_get_value(SHOW
 INSERT INTO t1 VALUES(1);
 --source include/show_binlog_events.inc
 let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1);
---exec $MYSQL_BINLOG --short-form --start-position=$binlog_start --stop-position=$pos2 --rewrite-db='test->ts`et' $MYSQLD_DATADIR/master-bin.000001
+--exec $MYSQL_BINLOG --short-form --start-position=$binlog_start --stop-position=$pos2 --rewrite-db='test->ts`et' $MYSQLD_DATADIR/master-bin.000002
 DROP TABLE t1;
 
 --source include/rpl_end.inc

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2012-08-09 15:22:00 +0000
+++ b/sql/item.cc	2012-08-10 14:22:32 +0000
@@ -992,15 +992,31 @@ void Item::set_name(const char *str, uin
   if (!my_charset_same(cs, system_charset_info))
   {
     size_t res_length;
-    name= sql_strmake_with_convert(str, name_length= length, cs,
+    name= sql_strmake_with_convert(str, length, cs,
                                    MAX_ALIAS_NAME, system_charset_info,
                                    &res_length);
+    name_length= res_length;
   }
   else
     name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME)));
 }
 
 
+void Item::set_name_no_truncate(const char *str, uint length, CHARSET_INFO *cs)
+{
+  if (!my_charset_same(cs, system_charset_info))
+  {
+    size_t res_length;
+    name= sql_strmake_with_convert(str, length, cs,
+                                   UINT_MAX, system_charset_info,
+                                   &res_length);
+    name_length= res_length;
+  }
+  else
+    name= sql_strmake(str, (name_length= length));
+}
+
+
 void Item::set_name_for_rollback(THD *thd, const char *str, uint length,
                                  CHARSET_INFO *cs)
 {

=== modified file 'sql/item.h'
--- a/sql/item.h	2012-06-06 19:26:40 +0000
+++ b/sql/item.h	2012-08-10 14:22:32 +0000
@@ -656,6 +656,7 @@ class Item {
 #endif
   }             /*lint -e1509 */
   void set_name(const char *str, uint length, CHARSET_INFO *cs);
+  void set_name_no_truncate(const char *str, uint length, CHARSET_INFO *cs);
   void set_name_for_rollback(THD *thd, const char *str, uint length,
                              CHARSET_INFO *cs);
   void rename(char *new_name);

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2012-06-20 11:01:28 +0000
+++ b/sql/item_func.cc	2012-08-10 14:22:32 +0000
@@ -5443,10 +5443,10 @@ my_decimal* Item_user_var_as_out_param::
 }
 
 
-void Item_user_var_as_out_param::print(String *str, enum_query_type query_type)
+void Item_user_var_as_out_param::print_for_load(THD *thd, String *str)
 {
   str->append('@');
-  str->append(name.str,name.length);
+  append_identifier(thd, str, name.str, name.length);
 }
 
 

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2012-06-15 07:01:20 +0000
+++ b/sql/item_func.h	2012-08-10 14:22:32 +0000
@@ -1670,7 +1670,7 @@ class Item_user_var_as_out_param :public
   my_decimal *val_decimal(my_decimal *decimal_buffer);
   /* fix_fields() binds variable name with its entry structure */
   bool fix_fields(THD *thd, Item **ref);
-  virtual void print(String *str, enum_query_type query_type);
+  void print_for_load(THD *thd, String *str);
   void set_null_value(CHARSET_INFO* cs);
   void set_value(const char *str, uint length, CHARSET_INFO* cs);
 };

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2012-07-06 09:19:16 +0000
+++ b/sql/log.cc	2012-08-10 14:22:32 +0000
@@ -2073,11 +2073,10 @@ static int binlog_savepoint_set(handlert
   /* Write it to the binary log */
 
   String log_query;
-  if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")))
+  if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) ||
+      append_identifier(thd, &log_query,
+                        thd->lex->ident.str, thd->lex->ident.length))
     DBUG_RETURN(1);
-  /* ToDo: need return value here to check ?!? */
-  append_identifier(thd, &log_query,
-                    thd->lex->ident.str, thd->lex->ident.length);
   int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
   Query_log_event qinfo(thd, log_query.ptr(), log_query.length(),
                         TRUE, FALSE, TRUE, errcode);
@@ -2097,10 +2096,10 @@ static int binlog_savepoint_rollback(han
                (thd->variables.option_bits & OPTION_KEEP_LOG)))
   {
     String log_query;
-    if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")))
+    if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) ||
+        append_identifier(thd, &log_query,
+                          thd->lex->ident.str, thd->lex->ident.length))
       DBUG_RETURN(1);
-    append_identifier(thd, &log_query,
-                      thd->lex->ident.str, thd->lex->ident.length);
     int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
     Query_log_event qinfo(thd, log_query.ptr(), log_query.length(),
                           TRUE, FALSE, TRUE, errcode);

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2012-07-06 09:19:16 +0000
+++ b/sql/log_event.cc	2012-08-10 14:22:32 +0000
@@ -6132,13 +6132,13 @@ Xid_log_event::do_shall_skip(Relay_log_i
 **************************************************************************/
 
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-static void
+static bool
 user_var_append_name_part(THD *thd, String *buf,
                           const char *name, size_t name_len)
 {
-  buf->append("@");
-  append_identifier(thd, buf, name, name_len);
-  buf->append("=");
+  return buf->append("@") ||
+    append_identifier(thd, buf, name, name_len) ||
+    buf->append("=");
 }
 
 void User_var_log_event::pack_info(THD *thd, Protocol* protocol)
@@ -6148,8 +6148,9 @@ void User_var_log_event::pack_info(THD *
   if (is_null)
   {
     String buf(val_offset + 5);
-    user_var_append_name_part(thd, &buf, name, name_len);
-    buf.append("NULL");
+    if (user_var_append_name_part(thd, &buf, name, name_len) ||
+        buf.append("NULL"))
+      return;
     protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
   }
   else
@@ -6160,10 +6161,11 @@ void User_var_log_event::pack_info(THD *
       double real_val;
       char buf2[MY_GCVT_MAX_FIELD_WIDTH+1];
       String buf(val_offset + MY_GCVT_MAX_FIELD_WIDTH + 1);
-      user_var_append_name_part(thd, &buf, name, name_len);
       float8get(real_val, val);
-      buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
-                               MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL));
+      if (user_var_append_name_part(thd, &buf, name, name_len) ||
+          buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
+                                   MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL)))
+        return;
       protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
       break;
     }
@@ -6171,10 +6173,11 @@ void User_var_log_event::pack_info(THD *
     {
       char buf2[22];
       String buf(val_offset + 22);
-      user_var_append_name_part(thd, &buf, name, name_len);
-      buf.append(buf2,
+      if (user_var_append_name_part(thd, &buf, name, name_len) ||
+          buf.append(buf2,
                  longlong10_to_str(uint8korr(val), buf2,
-                   ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2);
+                   ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2))
+        return;
       protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
       break;
     }
@@ -6184,11 +6187,12 @@ void User_var_log_event::pack_info(THD *
       char buf2[DECIMAL_MAX_STR_LENGTH+1];
       String str(buf2, sizeof(buf2), &my_charset_bin);
       my_decimal dec;
-      user_var_append_name_part(thd, &buf, name, name_len);
       binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) (val+2), &dec, val[0],
                         val[1]);
       my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str);
-      buf.append(buf2);
+      if (user_var_append_name_part(thd, &buf, name, name_len) ||
+          buf.append(buf2))
+        return;
       protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
       break;
     }
@@ -6198,23 +6202,29 @@ void User_var_log_event::pack_info(THD *
       String buf(val_offset+val_len*2+1+2*MY_CS_NAME_SIZE+15);
       CHARSET_INFO *cs;
       if (!(cs= get_charset(charset_number, MYF(0))))
-        buf.append("???");
+      {
+        if (buf.append("???"))
+          return;
+      }
       else
       {
         size_t old_len;
         char *beg, *end;
-        user_var_append_name_part(thd, &buf, name, name_len);
-        buf.append("_");
-        buf.append(cs->csname);
-        buf.append(" ");
+        if (user_var_append_name_part(thd, &buf, name, name_len) ||
+            buf.append("_") ||
+            buf.append(cs->csname) ||
+            buf.append(" "))
+          return;
         old_len= buf.length();
-        buf.reserve(old_len + val_len*2 + 2 + sizeof(" COLLATE ") +
-                    MY_CS_NAME_SIZE);
+        if (buf.reserve(old_len + val_len*2 + 2 + sizeof(" COLLATE ") +
+                        MY_CS_NAME_SIZE))
+          return;
         beg= const_cast<char *>(buf.ptr()) + old_len;
         end= str_to_hex(beg, val, val_len);
         buf.length(old_len + (end - beg));
-        buf.append(" COLLATE ");
-        buf.append(cs->name);
+        if (buf.append(" COLLATE ") ||
+            buf.append(cs->name))
+          return;
       }
       protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
       break;
@@ -7696,14 +7706,16 @@ void Execute_load_query_log_event::pack_
   String buf(9 + db_len + q_len + 10 + 21);
   if (db && db_len)
   {
-    buf.append("use ");
-    append_identifier(thd, &buf, db, db_len);
-    buf.append("; ");
-  }
-  if (query && q_len)
-    buf.append(query, q_len);
-  buf.append(" ;file_id=");
-  buf.append_ulonglong(file_id);
+    if (buf.append("use ") ||
+        append_identifier(thd, &buf, db, db_len) ||
+        buf.append("; "))
+      return;
+  }
+  if (query && q_len && buf.append(query, q_len))
+    return;
+  if (buf.append(" ;file_id=") ||
+      buf.append_ulonglong(file_id))
+    return;
   protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
 }
 

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2012-07-06 09:19:16 +0000
+++ b/sql/sql_load.cc	2012-08-10 14:22:32 +0000
@@ -730,7 +730,11 @@ static bool write_execute_load_query_log
       if (item->type() == Item::FIELD_ITEM)
         append_identifier(thd, &query_str, item->name, strlen(item->name));
       else
-        item->print(&query_str, QT_ORDINARY);
+      {
+        /* Actually Item_user_var_as_out_param despite claiming STRING_ITEM. */
+        DBUG_ASSERT(item->type() == Item::STRING_ITEM);
+        ((Item_user_var_as_out_param *)item)->print_for_load(thd, &query_str);
+      }
     }
     query_str.append(")");
   }

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2012-08-09 15:22:00 +0000
+++ b/sql/sql_show.cc	2012-08-10 14:22:32 +0000
@@ -992,9 +992,13 @@ static const char *require_quotes(const
   packet                target string
   name                  the identifier to be appended
   name_length           length of the appending identifier
+
+  RETURN VALUES
+    true                Error
+    false               Ok
 */
 
-void
+bool
 append_identifier(THD *thd, String *packet, const char *name, uint length)
 {
   const char *name_end;
@@ -1002,10 +1006,7 @@ append_identifier(THD *thd, String *pack
   int q= get_quote_char_for_identifier(thd, name, length);
 
   if (q == EOF)
-  {
-    packet->append(name, length, packet->charset());
-    return;
-  }
+    return packet->append(name, length, packet->charset());
 
   /*
     The identifier must be quoted as it includes a quote character or
@@ -1014,7 +1015,8 @@ append_identifier(THD *thd, String *pack
 
   (void) packet->reserve(length*2 + 2);
   quote_char= (char) q;
-  packet->append(&quote_char, 1, system_charset_info);
+  if (packet->append(&quote_char, 1, system_charset_info))
+    return true;
 
   for (name_end= name+length ; name < name_end ; name+= length)
   {
@@ -1029,11 +1031,13 @@ append_identifier(THD *thd, String *pack
     */
     if (!length)
       length= 1;
-    if (length == 1 && chr == (uchar) quote_char)
-      packet->append(&quote_char, 1, system_charset_info);
-    packet->append(name, length, system_charset_info);
+    if (length == 1 && chr == (uchar) quote_char &&
+        packet->append(&quote_char, 1, system_charset_info))
+      return true;
+    if (packet->append(name, length, system_charset_info))
+      return true;
   }
-  packet->append(&quote_char, 1, system_charset_info);
+  return packet->append(&quote_char, 1, system_charset_info);
 }
 
 

=== modified file 'sql/sql_show.h'
--- a/sql/sql_show.h	2011-06-30 15:46:53 +0000
+++ b/sql/sql_show.h	2012-08-10 14:22:32 +0000
@@ -90,7 +90,7 @@ int view_store_create_info(THD *thd, TAB
 
 int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
 
-void append_identifier(THD *thd, String *packet, const char *name,
+bool append_identifier(THD *thd, String *packet, const char *name,
                        uint length);
 void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
 int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);

=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc	2012-07-06 09:19:16 +0000
+++ b/sql/sql_truncate.cc	2012-08-10 14:22:32 +0000
@@ -45,7 +45,7 @@ static bool fk_info_append_fields(THD *t
 
   while ((field= it++))
   {
-    append_identifier(thd, str, field->str, field->length);
+    res|= append_identifier(thd, str, field->str, field->length);
     res|= str->append(", ");
   }
 
@@ -77,22 +77,22 @@ static const char *fk_info_str(THD *thd,
     `db`.`tbl`, CONSTRAINT `id` FOREIGN KEY (`fk`) REFERENCES `db`.`tbl` (`fk`)
   */
 
-  append_identifier(thd, &str, fk_info->foreign_db->str,
-                    fk_info->foreign_db->length);
+  res|= append_identifier(thd, &str, fk_info->foreign_db->str,
+                          fk_info->foreign_db->length);
   res|= str.append(".");
-  append_identifier(thd, &str, fk_info->foreign_table->str,
-                    fk_info->foreign_table->length);
+  res|= append_identifier(thd, &str, fk_info->foreign_table->str,
+                          fk_info->foreign_table->length);
   res|= str.append(", CONSTRAINT ");
-  append_identifier(thd, &str, fk_info->foreign_id->str,
-                    fk_info->foreign_id->length);
+  res|= append_identifier(thd, &str, fk_info->foreign_id->str,
+                          fk_info->foreign_id->length);
   res|= str.append(" FOREIGN KEY (");
   res|= fk_info_append_fields(thd, &str, &fk_info->foreign_fields);
   res|= str.append(") REFERENCES ");
-  append_identifier(thd, &str, fk_info->referenced_db->str,
-                    fk_info->referenced_db->length);
+  res|= append_identifier(thd, &str, fk_info->referenced_db->str,
+                          fk_info->referenced_db->length);
   res|= str.append(".");
-  append_identifier(thd, &str, fk_info->referenced_table->str,
-                    fk_info->referenced_table->length);
+  res|= append_identifier(thd, &str, fk_info->referenced_table->str,
+                          fk_info->referenced_table->length);
   res|= str.append(" (");
   res|= fk_info_append_fields(thd, &str, &fk_info->referenced_fields);
   res|= str.append(')');

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2012-08-09 15:22:00 +0000
+++ b/sql/sql_yacc.yy	2012-08-10 14:22:32 +0000
@@ -12144,7 +12144,7 @@ select_var_ident:
             if (lex->update_list.push_back($1) || 
                 lex->value_list.push_back($4))
                 MYSQL_YYABORT;
-            $4->set_name($3, (uint) ($5 - $3), YYTHD->charset());
+            $4->set_name_no_truncate($3, (uint) ($5 - $3), YYTHD->charset());
           }
         ;
 

=== modified file 'strings/my_vsnprintf.c'
--- a/strings/my_vsnprintf.c	2012-03-13 20:55:56 +0000
+++ b/strings/my_vsnprintf.c	2012-08-10 14:22:32 +0000
@@ -694,6 +694,51 @@ size_t my_snprintf(char* to, size_t n, c
 int my_vfprintf(FILE *stream, const char* format, va_list args)
 {
   char cvtbuf[1024];
-  (void) my_vsnprintf(cvtbuf, sizeof(cvtbuf), format, args);
-  return fprintf(stream, "%s\n", cvtbuf);
+  int alloc= 0;
+  char *p= cvtbuf;
+  size_t cur_len= sizeof(cvtbuf);
+  int ret;
+
+  /*
+    We do not know how much buffer we need.
+    So start with a reasonably-sized stack-allocated buffer, and increase
+    it exponentially until it is big enough.
+  */
+  for (;;)
+  {
+    size_t new_len;
+    size_t actual= my_vsnprintf(p, cur_len, format, args);
+    if (actual < cur_len - 1)
+      break;
+    /*
+      Not enough space (or just enough with nothing to spare - but we cannot
+      distinguish this case from the return value). Allocate a bigger buffer
+      and try again.
+    */
+    if (alloc)
+      (*my_str_free)(p);
+    else
+      alloc= 1;
+    new_len= cur_len*2;
+    if (new_len < cur_len)
+      return 0;                                 /* Overflow */
+    cur_len= new_len;
+    p= (*my_str_malloc)(cur_len);
+    if (!p)
+      return 0;
+  }
+  ret= fprintf(stream, "%s", p);
+  if (alloc)
+    (*my_str_free)(p);
+  return ret;
+}
+
+int my_fprintf(FILE *stream, const char* format, ...)
+{
+  int result;
+  va_list args;
+  va_start(args, format);
+  result= my_vfprintf(stream, format, args);
+  va_end(args);
+  return result;
 }



More information about the commits mailing list