List:Commits« Previous MessageNext Message »
From:Li-Bing.Song Date:December 15 2009 5:14am
Subject:bzr commit into mysql-5.1-bugteam branch (Li-Bing.Song:3271) Bug#34628
View as plain text  
#At file:///home/anders/work/bzrwork/worktree6/mysql-5.1-bugteam/ based on revid:alexey.kopytov@stripped

 3271 Li-Bing.Song@stripped	2009-12-15
      Bug #34628  	LOAD DATA CONCURRENT INFILE drops CONCURRENT in binary log
      
      'LOAD DATA CONCURRENT [LOCAL] INFILE ...' statment only is binlogged as
      'LOAD DATA [LOCAL] INFILE ...' in SBR and MBR.  As a result, if replication is on, 
      queries on slaves will be blocked by the replication SQL thread.
      
      This patch write code to write 'CONCURRENT' into the log event if 'CONCURRENT' option
      is in the original statement in SBR and MBR. 

    added:
      mysql-test/suite/rpl/r/rpl_loaddata_concurrent.result
      mysql-test/suite/rpl/t/rpl_loaddata_concurrent.test
    modified:
      mysql-test/extra/rpl_tests/rpl_loaddata.test
      mysql-test/suite/rpl/r/rpl_loaddata.result
      sql/log_event.cc
      sql/log_event.h
=== modified file 'mysql-test/extra/rpl_tests/rpl_loaddata.test'
--- a/mysql-test/extra/rpl_tests/rpl_loaddata.test	2009-10-27 15:15:53 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test	2009-12-15 05:14:14 +0000
@@ -21,14 +21,26 @@ connection slave;
 reset master;
 connection master;
 
+# MTR is not case-sensitive.
+let $lower_stmt_head= load data;
+let $UPPER_STMT_HEAD= LOAD DATA;
+if (`SELECT '$lock_option' <> ''`)
+{
+  #if $lock_option is null, an extra blank is added into the statement,
+  #this will change the result of rpl_loaddata test case. so $lock_option
+  #is set only when it is not null.
+  let $lower_stmt_head= load data $lock_option;
+  let $UPPER_STMT_HEAD= LOAD DATA $lock_option;
+}
+
 select last_insert_id();
 create table t1(a int not null auto_increment, b int, primary key(a) );
-load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata.dat' into table t1;
 # verify that LAST_INSERT_ID() is set by LOAD DATA INFILE
 select last_insert_id();
 
 create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60));
-load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines;
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines;
 
 create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60));
 insert into t3 select * from t2;
@@ -56,7 +68,7 @@ sync_with_master;
 insert into t1 values(1,10);
 
 connection master;
-load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata.dat' into table t1;
 
 save_master_pos;
 connection slave;
@@ -70,9 +82,11 @@ connection slave;
 set global sql_slave_skip_counter=1;
 start slave;
 sync_with_master;
---replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 16 # 23 # 33 #
-show slave status;
+let $last_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
+echo Last_SQL_Errno=$last_error;
+let $last_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
+echo Last_SQL_Error;
+echo $last_error;
 
 # Trigger error again to test CHANGE MASTER
 
@@ -80,7 +94,7 @@ connection master;
 set sql_log_bin=0;
 delete from t1;
 set sql_log_bin=1;
-load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata.dat' into table t1;
 save_master_pos;
 connection slave;
 # The SQL slave thread should be stopped now. 
@@ -92,9 +106,11 @@ connection slave;
 stop slave;
 change master to master_user='test';
 change master to master_user='root';
---replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 16 # 23 # 33 #
-show slave status;
+let $last_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
+echo Last_SQL_Errno=$last_error;
+let $last_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
+echo Last_SQL_Error;
+echo $last_error;
 
 # Trigger error again to test RESET SLAVE
 
@@ -105,7 +121,7 @@ connection master;
 set sql_log_bin=0;
 delete from t1;
 set sql_log_bin=1;
-load data infile '../../std_data/rpl_loaddata.dat' into table t1;
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata.dat' into table t1;
 save_master_pos;
 connection slave;
 # The SQL slave thread should be stopped now.
@@ -114,9 +130,11 @@ connection slave;
 # RESET SLAVE and see if error is cleared in SHOW SLAVE STATUS.
 stop slave;
 reset slave;
---replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 8 # 9 # 16 # 23 # 33 #
-show slave status;
+let $last_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
+echo Last_SQL_Errno=$last_error;
+let $last_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
+echo Last_SQL_Error;
+echo $last_error;
 
 # Finally, see if logging is done ok on master for a failing LOAD DATA INFILE
 
@@ -125,7 +143,7 @@ reset master;
 eval create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60),
 unique(day)) engine=$engine_type; # no transactions
 --error ER_DUP_ENTRY
-load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
 terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
 '\n##\n' starting by '>' ignore 1 lines;
 select * from t2;
@@ -141,7 +159,7 @@ alter table t2 drop key day;
 connection master;
 delete from t2;
 --error ER_DUP_ENTRY
-load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
+eval $lower_stmt_head infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
 terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
 '\n##\n' starting by '>' ignore 1 lines;
 connection slave;
@@ -154,7 +172,7 @@ drop table t1, t2;
 CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB;
 
 --error ER_DUP_ENTRY
-LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1;
+eval $UPPER_STMT_HEAD INFILE "../../std_data/words.dat" INTO TABLE t1;
 
 DROP TABLE IF EXISTS t1;
 
@@ -182,17 +200,17 @@ DROP TABLE IF EXISTS t1;
 
 -- echo ### assertion: works with cross-referenced database
 -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
+-- eval $UPPER_STMT_HEAD LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
 
 -- eval use $db1
 -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
 -- echo ### assertion: works with fully qualified name on current database
 -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
+-- eval $UPPER_STMT_HEAD LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
 
 -- echo ### assertion: works without fully qualified name on current database
 -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1
+-- eval $UPPER_STMT_HEAD LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1
 
 -- echo ### create connection without default database
 -- echo ### connect (conn2,localhost,root,,*NO-ONE*);
@@ -200,7 +218,7 @@ connect (conn2,localhost,root,,*NO-ONE*)
 -- connection conn2
 -- echo ### assertion: works without stating the default database
 -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
+-- eval $UPPER_STMT_HEAD LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1
 -- echo ### disconnect and switch back to master connection
 -- disconnect conn2
 -- connection master

=== modified file 'mysql-test/suite/rpl/r/rpl_loaddata.result'
--- a/mysql-test/suite/rpl/r/rpl_loaddata.result	2009-10-27 15:15:53 +0000
+++ b/mysql-test/suite/rpl/r/rpl_loaddata.result	2009-12-15 05:14:14 +0000
@@ -34,9 +34,9 @@ insert into t1 values(1,10);
 load data infile '../../std_data/rpl_loaddata.dat' into table t1;
 set global sql_slave_skip_counter=1;
 start slave;
-show slave status;
-Slave_IO_State	Master_Host	Master_User	Master_Port	Connect_Retry	Master_Log_File	Read_Master_Log_Pos	Relay_Log_File	Relay_Log_Pos	Relay_Master_Log_File	Slave_IO_Running	Slave_SQL_Running	Replicate_Do_DB	Replicate_Ignore_DB	Replicate_Do_Table	Replicate_Ignore_Table	Replicate_Wild_Do_Table	Replicate_Wild_Ignore_Table	Last_Errno	Last_Error	Skip_Counter	Exec_Master_Log_Pos	Relay_Log_Space	Until_Condition	Until_Log_File	Until_Log_Pos	Master_SSL_Allowed	Master_SSL_CA_File	Master_SSL_CA_Path	Master_SSL_Cert	Master_SSL_Cipher	Master_SSL_Key	Seconds_Behind_Master	Master_SSL_Verify_Server_Cert	Last_IO_Errno	Last_IO_Error	Last_SQL_Errno	Last_SQL_Error
-#	127.0.0.1	root	MASTER_PORT	1	master-bin.000001	2009	#	#	master-bin.000001	Yes	Yes				#			0		0	2009	#	None		0	No						#	No	0		0	
+Last_SQL_Errno=0
+Last_SQL_Error
+
 set sql_log_bin=0;
 delete from t1;
 set sql_log_bin=1;
@@ -44,9 +44,9 @@ load data infile '../../std_data/rpl_loa
 stop slave;
 change master to master_user='test';
 change master to master_user='root';
-show slave status;
-Slave_IO_State	Master_Host	Master_User	Master_Port	Connect_Retry	Master_Log_File	Read_Master_Log_Pos	Relay_Log_File	Relay_Log_Pos	Relay_Master_Log_File	Slave_IO_Running	Slave_SQL_Running	Replicate_Do_DB	Replicate_Ignore_DB	Replicate_Do_Table	Replicate_Ignore_Table	Replicate_Wild_Do_Table	Replicate_Wild_Ignore_Table	Last_Errno	Last_Error	Skip_Counter	Exec_Master_Log_Pos	Relay_Log_Space	Until_Condition	Until_Log_File	Until_Log_Pos	Master_SSL_Allowed	Master_SSL_CA_File	Master_SSL_CA_Path	Master_SSL_Cert	Master_SSL_Cipher	Master_SSL_Key	Seconds_Behind_Master	Master_SSL_Verify_Server_Cert	Last_IO_Errno	Last_IO_Error	Last_SQL_Errno	Last_SQL_Error
-#	127.0.0.1	root	MASTER_PORT	1	master-bin.000001	2044	#	#	master-bin.000001	No	No				#			0		0	2044	#	None		0	No						#	No	0		0	
+Last_SQL_Errno=0
+Last_SQL_Error
+
 set global sql_slave_skip_counter=1;
 start slave;
 set sql_log_bin=0;
@@ -55,9 +55,9 @@ set sql_log_bin=1;
 load data infile '../../std_data/rpl_loaddata.dat' into table t1;
 stop slave;
 reset slave;
-show slave status;
-Slave_IO_State	Master_Host	Master_User	Master_Port	Connect_Retry	Master_Log_File	Read_Master_Log_Pos	Relay_Log_File	Relay_Log_Pos	Relay_Master_Log_File	Slave_IO_Running	Slave_SQL_Running	Replicate_Do_DB	Replicate_Ignore_DB	Replicate_Do_Table	Replicate_Ignore_Table	Replicate_Wild_Do_Table	Replicate_Wild_Ignore_Table	Last_Errno	Last_Error	Skip_Counter	Exec_Master_Log_Pos	Relay_Log_Space	Until_Condition	Until_Log_File	Until_Log_Pos	Master_SSL_Allowed	Master_SSL_CA_File	Master_SSL_CA_Path	Master_SSL_Cert	Master_SSL_Cipher	Master_SSL_Key	Seconds_Behind_Master	Master_SSL_Verify_Server_Cert	Last_IO_Errno	Last_IO_Error	Last_SQL_Errno	Last_SQL_Error
-#	127.0.0.1	root	MASTER_PORT	1		4	#	#		No	No				#			0		0	0	#	None		0	No						#	No	0		0	
+Last_SQL_Errno=0
+Last_SQL_Error
+
 reset master;
 create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60),
 unique(day)) engine=MyISAM;

=== added file 'mysql-test/suite/rpl/r/rpl_loaddata_concurrent.result'
--- a/mysql-test/suite/rpl/r/rpl_loaddata_concurrent.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_loaddata_concurrent.result	2009-12-15 05:14:14 +0000
@@ -0,0 +1,128 @@
+CREATE TABLE t1 (c1 char(50));
+LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1;
+LOAD DATA CONCURRENT INFILE '../../std_data/words.dat' INTO TABLE t1;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t1 (c1 char(50))
+master-bin.000001	#	Begin_load_query	#	#	;file_id=#;block_len=#
+master-bin.000001	#	Execute_load_query	#	#	use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (c1) ;file_id=#
+master-bin.000001	#	Begin_load_query	#	#	;file_id=#;block_len=#
+master-bin.000001	#	Execute_load_query	#	#	use `test`; LOAD DATA CONCURRENT INFILE '../../std_data/words.dat' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (c1) ;file_id=#
+DROP TABLE t1;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+reset master;
+select last_insert_id();
+last_insert_id()
+0
+create table t1(a int not null auto_increment, b int, primary key(a) );
+load data CONCURRENT infile '../../std_data/rpl_loaddata.dat' into table t1;
+select last_insert_id();
+last_insert_id()
+1
+create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60));
+load data CONCURRENT infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines;
+create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60));
+insert into t3 select * from t2;
+select * from t1;
+a	b
+1	10
+2	15
+select * from t3;
+day	id	category	name
+2003-02-22	2461	b	a a a @ %  ' " a
+2003-03-22	2161	c	asdf
+2003-03-22	2416	a	bbbbb
+drop table t1;
+drop table t2;
+drop table t3;
+create table t1(a int, b int, unique(b));
+insert into t1 values(1,10);
+load data CONCURRENT infile '../../std_data/rpl_loaddata.dat' into table t1;
+set global sql_slave_skip_counter=1;
+start slave;
+Last_SQL_Errno=0
+Last_SQL_Error
+
+set sql_log_bin=0;
+delete from t1;
+set sql_log_bin=1;
+load data CONCURRENT infile '../../std_data/rpl_loaddata.dat' into table t1;
+stop slave;
+change master to master_user='test';
+change master to master_user='root';
+Last_SQL_Errno=0
+Last_SQL_Error
+
+set global sql_slave_skip_counter=1;
+start slave;
+set sql_log_bin=0;
+delete from t1;
+set sql_log_bin=1;
+load data CONCURRENT infile '../../std_data/rpl_loaddata.dat' into table t1;
+stop slave;
+reset slave;
+Last_SQL_Errno=0
+Last_SQL_Error
+
+reset master;
+create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60),
+unique(day)) engine=MyISAM;
+load data CONCURRENT infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
+terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
+'\n##\n' starting by '>' ignore 1 lines;
+ERROR 23000: Duplicate entry '2003-03-22' for key 'day'
+select * from t2;
+day	id	category	name
+2003-02-22	2461	b	a a a @ %  ' " a
+2003-03-22	2161	c	asdf
+start slave;
+select * from t2;
+day	id	category	name
+2003-02-22	2461	b	a a a @ %  ' " a
+2003-03-22	2161	c	asdf
+alter table t2 drop key day;
+delete from t2;
+load data CONCURRENT infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
+terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
+'\n##\n' starting by '>' ignore 1 lines;
+ERROR 23000: Duplicate entry '2003-03-22' for key 'day'
+drop table t1, t2;
+drop table t1, t2;
+CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB;
+LOAD DATA CONCURRENT INFILE "../../std_data/words.dat" INTO TABLE t1;
+ERROR 23000: Duplicate entry 'Aarhus' for key 'PRIMARY'
+DROP TABLE IF EXISTS t1;
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop database if exists b48297_db1;
+drop database if exists b42897_db2;
+create database b48297_db1;
+create database b42897_db2;
+use b48297_db1;
+CREATE TABLE t1 (c1 VARCHAR(256)) engine=MyISAM;;
+use b42897_db2;
+### assertion: works with cross-referenced database
+LOAD DATA CONCURRENT LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1;
+use b48297_db1;
+### assertion: works with fully qualified name on current database
+LOAD DATA CONCURRENT LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1;
+### assertion: works without fully qualified name on current database
+LOAD DATA CONCURRENT LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1;
+### create connection without default database
+### connect (conn2,localhost,root,,*NO-ONE*);
+### assertion: works without stating the default database
+LOAD DATA CONCURRENT LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1;
+### disconnect and switch back to master connection
+use b48297_db1;
+Comparing tables master:b48297_db1.t1 and slave:b48297_db1.t1
+DROP DATABASE b48297_db1;
+DROP DATABASE b42897_db2;

=== added file 'mysql-test/suite/rpl/t/rpl_loaddata_concurrent.test'
--- a/mysql-test/suite/rpl/t/rpl_loaddata_concurrent.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_loaddata_concurrent.test	2009-12-15 05:14:14 +0000
@@ -0,0 +1,12 @@
+-- source include/not_ndb_default.inc
+-- source include/have_log_bin.inc
+
+CREATE TABLE t1 (c1 char(50));
+LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1;
+LOAD DATA CONCURRENT INFILE '../../std_data/words.dat' INTO TABLE t1;
+-- source include/show_binlog_events.inc
+DROP TABLE t1;
+
+let $lock_option= CONCURRENT;
+let $engine_type=MyISAM;
+-- source extra/rpl_tests/rpl_loaddata.test

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-12-07 00:28:14 +0000
+++ b/sql/log_event.cc	2009-12-15 05:14:14 +0000
@@ -4006,6 +4006,7 @@ uint Load_log_event::get_query_buffer_le
   return
     5 + db_len + 3 +                        // "use DB; "
     18 + fname_len + 2 +                    // "LOAD DATA INFILE 'file''"
+    11 +                                    // "CONCURRENT "
     7 +					    // LOCAL
     9 +                                     // " REPLACE or IGNORE "
     13 + table_name_len*2 +                 // "INTO TABLE `table`"
@@ -4033,6 +4034,9 @@ void Load_log_event::print_query(bool ne
 
   pos= strmov(pos, "LOAD DATA ");
 
+  if (thd->lex->lock_option == TL_WRITE_CONCURRENT_INSERT)
+    pos= strmov(pos, "CONCURRENT ");
+
   if (fn_start)
     *fn_start= pos;
 

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2009-10-22 00:15:45 +0000
+++ b/sql/log_event.h	2009-12-15 05:14:14 +0000
@@ -1766,7 +1766,7 @@ private:
 
   @verbatim
    (1)    USE db;
-   (2)    LOAD DATA [LOCAL] INFILE 'file_name'
+   (2)    LOAD DATA [CONCURRENT] [LOCAL] INFILE 'file_name'
    (3)    [REPLACE | IGNORE]
    (4)    INTO TABLE 'table_name'
    (5)    [FIELDS


Attachment: [text/bzr-bundle] bzr/li-bing.song@sun.com-20091215051414-j5lrr1cx7bjjio5t.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Li-Bing.Song:3271) Bug#34628Li-Bing.Song15 Dec