diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 033c55707fc..d2357aa10ec 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -682,8 +682,16 @@ Begin_load_query event for file_id: %u\n", exlq->file_id); end: rec_count++; + /* + Destroy the log_event object. If reading from a remote host, + set the temp_buf to NULL so that memory isn't freed twice. + */ if (ev) + { + if (remote_opt) + ev->temp_buf= 0; delete ev; + } DBUG_RETURN(0); } @@ -1172,6 +1180,12 @@ could be out of memory"); error= 1; goto err; } + /* + If reading from a remote host, ensure the temp_buf for the + Log_event class is pointing to the incoming stream. + */ + if (remote_opt) + ev->register_temp_buf((char*) net->read_pos + 1); Log_event_type type= ev->get_type_code(); if (glob_description_event->binlog_version >= 3 || diff --git a/mysql-test/extra/rpl_tests/rpl_loaddata.test b/mysql-test/extra/rpl_tests/rpl_loaddata.test index 111b66ff7fe..dea83f65898 100644 --- a/mysql-test/extra/rpl_tests/rpl_loaddata.test +++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test @@ -15,6 +15,7 @@ # Last_slave_errno in SHOW SLAVE STATUS (1st and 3rd commands did not: bug 986) -- source include/master-slave.inc +source include/have_innodb.inc; connection slave; reset master; @@ -156,4 +157,15 @@ drop table t2; connection master; drop table t2; drop table t1; + +# BUG#17233 LOAD DATA INFILE: failure causes mysqld dbug_assert, binlog not flushed +CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB; + +--error ER_DUP_ENTRY_WITH_KEY_NAME +LOAD DATA INFILE "../std_data_ln/words.dat" INTO TABLE t1; + +--disable warnings +DROP TABLE IF EXISTS t1; +--enable warnings + # End of 4.1 tests diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index df39be15f05..50edcecbfa9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1804,6 +1804,18 @@ sub environment_setup () { $ENV{'CHARSETSDIR'}= $path_charsetsdir; $ENV{'UMASK'}= "0660"; # The octal *string* $ENV{'UMASK_DIR'}= "0770"; # The octal *string* + + # + # MySQL tests can produce output in various character sets + # (especially, ctype_xxx.test). To avoid confusing Perl + # with output which is incompatible with the current locale + # settings, we reset the current values of LC_ALL and LC_CTYPE to "C". + # For details, please see + # Bug#27636 tests fails if LC_* variables set to *_*.UTF-8 + # + $ENV{'LC_ALL'}= "C"; + $ENV{'LC_CTYPE'}= "C"; + $ENV{'LC_COLLATE'}= "C"; $ENV{'USE_RUNNING_SERVER'}= $opt_extern; $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; @@ -3851,13 +3863,15 @@ sub mysqld_arguments ($$$$) { } else { - mtr_add_arg($args, "%s--master-user=root", $prefix); - mtr_add_arg($args, "%s--master-connect-retry=1", $prefix); - mtr_add_arg($args, "%s--master-host=127.0.0.1", $prefix); - mtr_add_arg($args, "%s--master-password=", $prefix); - mtr_add_arg($args, "%s--master-port=%d", $prefix, - $master->[0]->{'port'}); # First master - + if ($mysql_version_id < 50200) + { + mtr_add_arg($args, "%s--master-user=root", $prefix); + mtr_add_arg($args, "%s--master-connect-retry=1", $prefix); + mtr_add_arg($args, "%s--master-host=127.0.0.1", $prefix); + mtr_add_arg($args, "%s--master-password=", $prefix); + mtr_add_arg($args, "%s--master-port=%d", $prefix, + $master->[0]->{'port'}); # First master + } my $slave_server_id= 2 + $idx; my $slave_rpl_rank= $slave_server_id; mtr_add_arg($args, "%s--server-id=%d", $prefix, $slave_server_id); diff --git a/mysql-test/r/rpl_critical_errors.result b/mysql-test/r/rpl_critical_errors.result deleted file mode 100644 index bcc53565084..00000000000 --- a/mysql-test/r/rpl_critical_errors.result +++ /dev/null @@ -1 +0,0 @@ -Turn on parsing to run this test diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index cabc20b7057..680796a4be6 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -86,3 +86,7 @@ ERROR 23000: Duplicate entry '2003-03-22' for key 'day' drop table t2; drop table t2; drop table t1; +CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB; +LOAD DATA INFILE "../std_data_ln/words.dat" INTO TABLE t1; +ERROR 23000: Duplicate entry 'Aarhus' for key 'PRIMARY' +DROP TABLE IF EXISTS t1; diff --git a/mysql-test/r/rpl_row_mysqlbinlog.result b/mysql-test/r/rpl_row_mysqlbinlog.result index c9f46e73cfd..e2df1459ac0 100644 --- a/mysql-test/r/rpl_row_mysqlbinlog.result +++ b/mysql-test/r/rpl_row_mysqlbinlog.result @@ -190,6 +190,75 @@ DELIMITER ; ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; +--- Test 4 Second Remote test -- +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +stop slave; +reset master; +reset slave; +start slave; +SELECT COUNT(*) from t1; +COUNT(*) +352 +SELECT COUNT(*) from t2; +COUNT(*) +500 +SELECT COUNT(*) from t3; +COUNT(*) +500 +SELECT * FROM t1 ORDER BY word LIMIT 5; +word +Aarhus +Aarhus +Aarhus +Aarhus +Aarhus +SELECT * FROM t2 ORDER BY id LIMIT 5; +id +1 +2 +3 +4 +5 +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; +c1 c3 c4 c5 +1 2006-02-22 00:00:00 Tested in Texas 2.2 +2 2006-02-22 00:00:00 Tested in Texas 4.4 +3 2006-02-22 00:00:00 Tested in Texas 6.6 +4 2006-02-22 00:00:00 Tested in Texas 8.8 +5 2006-02-22 00:00:00 Tested in Texas 11 +SELECT COUNT(*) from t1; +COUNT(*) +352 +SELECT COUNT(*) from t2; +COUNT(*) +500 +SELECT COUNT(*) from t3; +COUNT(*) +500 +SELECT * FROM t1 ORDER BY word LIMIT 5; +word +Aarhus +Aarhus +Aarhus +Aarhus +Aarhus +SELECT * FROM t2 ORDER BY id LIMIT 5; +id +1 +2 +3 +4 +5 +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; +c1 c3 c4 c5 +1 2006-02-22 00:00:00 Tested in Texas 2.2 +2 2006-02-22 00:00:00 Tested in Texas 4.4 +3 2006-02-22 00:00:00 Tested in Texas 6.6 +4 2006-02-22 00:00:00 Tested in Texas 8.8 +5 2006-02-22 00:00:00 Tested in Texas 11 + --- Test 5 LOAD DATA -- /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; @@ -273,4 +342,11 @@ HEX(f) 835C --- Test cleanup -- +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT NOT NULL KEY, b INT); +INSERT INTO t1 VALUES(1,1); +SELECT * FROM t1; +a b +1 1 +FLUSH LOGS; DROP TABLE IF EXISTS t1, t2, t3, t04, t05, t4, t5; diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result index 236c50774bd..f71b8cadabb 100644 --- a/mysql-test/r/xml.result +++ b/mysql-test/r/xml.result @@ -547,6 +547,13 @@ UpdateXML(@xml, '/a/b/@bb2', '') select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"'); UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"') bb +select updatexml('
12
', +'/','12') as upd1; +upd1 +12 +select updatexml('', '/', '') as upd2; +upd2 + SET @xml= 'lesser wombat'; select extractvalue(@xml,'order/clerk'); extractvalue(@xml,'order/clerk') @@ -884,3 +891,124 @@ test select ExtractValue('test', '/a/self'); ExtractValue('test', '/a/self') test +set @i=1; +select ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') +b1 +set @i=2; +select ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') +b2 +set @i=NULL; +select ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') + +CREATE PROCEDURE spxml(xml VARCHAR(128)) +BEGIN +DECLARE c INT; +DECLARE i INT DEFAULT 1; +SET c= ExtractValue(xml,'count(/a/b)'); +SET @i= c; +WHILE i <= c DO +BEGIN +SELECT i, @i, ExtractValue(xml,'/a/b[$i]'), ExtractValue(xml,'/a/b[$@i]'); +SET i= i + 1; +SET @i= @i - 1; +END; +END WHILE; +END| +call spxml('b1b2b3'); +i @i ExtractValue(xml,'/a/b[$i]') ExtractValue(xml,'/a/b[$@i]') +1 3 b1 b3 +i @i ExtractValue(xml,'/a/b[$i]') ExtractValue(xml,'/a/b[$@i]') +2 2 b2 b2 +i @i ExtractValue(xml,'/a/b[$i]') ExtractValue(xml,'/a/b[$@i]') +3 1 b3 b1 +drop procedure spxml; +Multiple matches, but no index specification +SELECT ExtractValue('b1b2','/a/b'); +ExtractValue('b1b2','/a/b') +b1 b2 +No matches +SELECT ExtractValue('b1b2','/a/c'); +ExtractValue('b1b2','/a/c') + +Index out of range +SELECT ExtractValue('b1b2','/a/b[-1]'); +ExtractValue('b1b2','/a/b[-1]') + +SELECT ExtractValue('b1b2','/a/b[10]'); +ExtractValue('b1b2','/a/b[10]') + +With string-to-number conversion +SELECT ExtractValue('b1b2','/a/b["1"]'); +ExtractValue('b1b2','/a/b["1"]') +b1 +SELECT ExtractValue('b1b2','/a/b["1 and string"]'); +ExtractValue('b1b2','/a/b["1 and string"]') +b1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '1 and string"]' +Warning 1292 Truncated incorrect INTEGER value: '1 and string"]' +SELECT ExtractValue('b1b2','/a/b["string and 1"]'); +ExtractValue('b1b2','/a/b["string and 1"]') + +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'string and 1"]' +Warning 1292 Truncated incorrect INTEGER value: 'string and 1"]' +SELECT ExtractValue('b1b2','/a/b["string"]'); +ExtractValue('b1b2','/a/b["string"]') + +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'string"]' +Warning 1292 Truncated incorrect INTEGER value: 'string"]' +String-to-number conversion from a user variable +SET @i='1'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') +b1 +SET @i='1 and string'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') +b1 +SET @i='string and 1'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') + +SET @i='string'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +ExtractValue('b1b2','/a/b[$@i]') + +String-to-number conversion with a CHAR SP variable +CREATE PROCEDURE spxml(xml VARCHAR(128), i CHAR(16)) +BEGIN +SELECT ExtractValue(xml,'/a/b[$i]'); +END| +CALL spxml('b1b2', '1'); +ExtractValue(xml,'/a/b[$i]') +b1 +CALL spxml('b1b2', '1 and string'); +ExtractValue(xml,'/a/b[$i]') +b1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '1 and string ' +Warning 1292 Truncated incorrect INTEGER value: '1 and string ' +CALL spxml('b1b2', 'string and 1'); +ExtractValue(xml,'/a/b[$i]') + +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'string and 1 ' +Warning 1292 Truncated incorrect INTEGER value: 'string and 1 ' +CALL spxml('b1b2', 'string'); +ExtractValue(xml,'/a/b[$i]') + +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'string ' +Warning 1292 Truncated incorrect INTEGER value: 'string ' +DROP PROCEDURE spxml; +select UpdateXML('a',repeat('a b ',1000),''); +ERROR HY000: XPATH syntax error: 'b a b a b a b a b a b a b a b a ' +select ExtractValue('a', '/a[@x=@y0123456789_0123456789_0123456789_0123456789]'); +ERROR HY000: XPATH error: comparison of two nodesets is not supported: '=@y0123456789_0123456789_0123456' +select ExtractValue('a', '/a[@x=$y0123456789_0123456789_0123456789_0123456789]'); +ERROR HY000: Unknown XPATH variable at: '$y0123456789_0123456789_01234567' diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index e2a0b30c592..c584f448a34 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -25,11 +25,10 @@ rpl_ndb_circular_simplex : BUG#27972 2007-04-20 mats Slave cannot start where it rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 Seems to pass currently rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD -rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement -rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly +#rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly synchronization : Bug#24529 Test 'synchronization' fails on Mac pushbuild; Also on Linux 64 bit. # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open diff --git a/mysql-test/t/rpl_ndb_ddl.test b/mysql-test/t/rpl_ndb_ddl.test index ca7a4ce4968..66db755de15 100644 --- a/mysql-test/t/rpl_ndb_ddl.test +++ b/mysql-test/t/rpl_ndb_ddl.test @@ -24,6 +24,7 @@ # --source include/master-slave.inc +--source include/have_binlog_format_row.inc --source include/have_ndb.inc let $engine_type= NDB; let $temp_engine_type= MEMORY; diff --git a/mysql-test/t/rpl_row_mysqlbinlog.test b/mysql-test/t/rpl_row_mysqlbinlog.test index 1a5dd281ae1..dd46d64f684 100644 --- a/mysql-test/t/rpl_row_mysqlbinlog.test +++ b/mysql-test/t/rpl_row_mysqlbinlog.test @@ -183,67 +183,67 @@ select "--- Test 3 First Remote test --" as ""; --exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 # This part is disabled due to bug #17654 -################### Start Bug 17654 ###################### -#--disable_query_log -#select "--- Test 4 Second Remote test --" as ""; -#--enable_query_log -#--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql -#--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 >> $MYSQLTEST_VARDIR/tmp/remote.sql +--disable_query_log +select "--- Test 4 Second Remote test --" as ""; +--enable_query_log +--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql + +--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 >> $MYSQLTEST_VARDIR/tmp/remote.sql # Now that we have our file, lets get rid of the current database. # Cleanup the master and the slave and try to recreate. -#DROP TABLE t1; -#DROP TABLE t2; -#DROP TABLE t3; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; -#sync_slave_with_master; +sync_slave_with_master; #we expect STOP SLAVE to produce a warning as the slave is stopped #(the server was started with skip-slave-start) -#--disable_warnings -#stop slave; -#--enable_warnings -#--require r/slave-stopped.result -#show status like 'Slave_running'; -#connection master; -#reset master; -#connection slave; -#reset slave; -#start slave; -#--require r/slave-running.result -#show status like 'Slave_running'; -#connection master; +--disable_warnings +stop slave; +--enable_warnings +--require r/slave-stopped.result +show status like 'Slave_running'; +connection master; +reset master; +connection slave; +reset slave; +start slave; +--require r/slave-running.result +show status like 'Slave_running'; +connection master; # We should be clean at this point, now we will run in the file from above. -#--exec $MYSQL -e "source $MYSQLTEST_VARDIR/tmp/remote.sql" +--exec $MYSQL -e "source $MYSQLTEST_VARDIR/tmp/remote.sql" # Lets Check the tables on the Master -#SELECT COUNT(*) from t1; -#SELECT COUNT(*) from t2; -#SELECT COUNT(*) from t3; -#SELECT * FROM t1 ORDER BY word LIMIT 5; -#SELECT * FROM t2 ORDER BY id LIMIT 5; -#SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; # Should have the same on the slave; -#sync_slave_with_master; -#SELECT COUNT(*) from t1; -#SELECT COUNT(*) from t2; -#SELECT COUNT(*) from t3; -#SELECT * FROM t1 ORDER BY word LIMIT 5; -#SELECT * FROM t2 ORDER BY id LIMIT 5; -#SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; -#connection master; +sync_slave_with_master; +SELECT COUNT(*) from t1; +SELECT COUNT(*) from t2; +SELECT COUNT(*) from t3; +SELECT * FROM t1 ORDER BY word LIMIT 5; +SELECT * FROM t2 ORDER BY id LIMIT 5; +SELECT c1, c3, c4, c5 FROM t3 ORDER BY c1 LIMIT 5; +connection master; # We should be gold by the time, so I will get rid of our file. -#--exec rm $MYSQLTEST_VARDIR/tmp/remote.sql +--exec rm $MYSQLTEST_VARDIR/tmp/remote.sql ################### End Bug 17654 ###################### # LOAD DATA @@ -315,7 +315,34 @@ select "--- Test cleanup --" as ""; --enable_query_log # clean up connection master; -DROP TABLE IF EXISTS t1, t2, t3, t04, t05, t4, t5; sync_slave_with_master; +connection master; + +# BUG#17654 also test mysqlbinlog to ensure it can read the binlog from a remote server +# and ensure that the results are the same as if read from a file (the same file). + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a INT NOT NULL KEY, b INT); + +INSERT INTO t1 VALUES(1,1); + +SELECT * FROM t1; + +FLUSH LOGS; + +--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql +--exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/local.sql + +--diff_files $MYSQLTEST_VARDIR/tmp/local.sql $MYSQLTEST_VARDIR/tmp/remote.sql + +--exec rm $MYSQLTEST_VARDIR/tmp/remote.sql + +--exec rm $MYSQLTEST_VARDIR/tmp/local.sql + +DROP TABLE IF EXISTS t1, t2, t3, t04, t05, t4, t5; + # End of 4.1 tests diff --git a/mysql-test/t/xml.test b/mysql-test/t/xml.test index 8517dce111f..1d16652ab1e 100644 --- a/mysql-test/t/xml.test +++ b/mysql-test/t/xml.test @@ -231,6 +231,13 @@ select UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"'); select UpdateXML(@xml, '/a/b/@bb2', ''); select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"'); +# +# Bug#27898 UPDATEXML Crashes the Server! +# +select updatexml('
12
', + '/','12') as upd1; +select updatexml('', '/', '') as upd2; + # # Bug#16234 XML: Crash if ExtractValue() # @@ -444,3 +451,85 @@ select ExtractValue('test', '/a/parent'); select ExtractValue('test', '/a/preceding'); select ExtractValue('test', '/a/preceding-sibling'); select ExtractValue('test', '/a/self'); + +# +# Bug#26518 XPath and variables problem +# Check with user defined variables +# +set @i=1; +select ExtractValue('b1b2','/a/b[$@i]'); +set @i=2; +select ExtractValue('b1b2','/a/b[$@i]'); +set @i=NULL; +select ExtractValue('b1b2','/a/b[$@i]'); + +# +# Check variables in a stored procedure - both local and user variables +# Make sure that SP and local variables with the same name work together. +# +DELIMITER |; +CREATE PROCEDURE spxml(xml VARCHAR(128)) +BEGIN + DECLARE c INT; + DECLARE i INT DEFAULT 1; + SET c= ExtractValue(xml,'count(/a/b)'); + SET @i= c; + WHILE i <= c DO + BEGIN + SELECT i, @i, ExtractValue(xml,'/a/b[$i]'), ExtractValue(xml,'/a/b[$@i]'); + SET i= i + 1; + SET @i= @i - 1; + END; + END WHILE; +END| +DELIMITER ;| + +call spxml('b1b2b3'); +drop procedure spxml; + +# +# Additional tests for bug#26518 +--echo Multiple matches, but no index specification +SELECT ExtractValue('b1b2','/a/b'); +--echo No matches +SELECT ExtractValue('b1b2','/a/c'); +--echo Index out of range +SELECT ExtractValue('b1b2','/a/b[-1]'); +SELECT ExtractValue('b1b2','/a/b[10]'); +--echo With string-to-number conversion +SELECT ExtractValue('b1b2','/a/b["1"]'); +SELECT ExtractValue('b1b2','/a/b["1 and string"]'); +SELECT ExtractValue('b1b2','/a/b["string and 1"]'); +SELECT ExtractValue('b1b2','/a/b["string"]'); +--echo String-to-number conversion from a user variable +SET @i='1'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +SET @i='1 and string'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +SET @i='string and 1'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); +SET @i='string'; +SELECT ExtractValue('b1b2','/a/b[$@i]'); + +--echo String-to-number conversion with a CHAR SP variable +DELIMITER |; +CREATE PROCEDURE spxml(xml VARCHAR(128), i CHAR(16)) +BEGIN + SELECT ExtractValue(xml,'/a/b[$i]'); +END| +DELIMITER ;| +CALL spxml('b1b2', '1'); +CALL spxml('b1b2', '1 and string'); +CALL spxml('b1b2', 'string and 1'); +CALL spxml('b1b2', 'string'); +DROP PROCEDURE spxml; + +# +# Bug#28558 UpdateXML called with garbage crashes server +# +--error 1105 +select UpdateXML('a',repeat('a b ',1000),''); +--error 1105 +select ExtractValue('a', '/a[@x=@y0123456789_0123456789_0123456789_0123456789]'); +--error 1105 +select ExtractValue('a', '/a[@x=$y0123456789_0123456789_0123456789_0123456789]'); diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 26474990644..428bffa6879 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -19,7 +19,7 @@ #include "mysql_priv.h" #include "my_xml.h" - +#include "sp_pcontext.h" /* TODO: future development directions: @@ -923,8 +923,8 @@ static Item *create_comparator(MY_XPATH *xpath, else if (a->type() == Item::XPATH_NODESET && b->type() == Item::XPATH_NODESET) { - uint len= context->end - context->beg; - set_if_bigger(len, 32); + uint len= xpath->query.end - context->beg; + set_if_smaller(len, 32); my_printf_error(ER_UNKNOWN_ERROR, "XPATH error: " "comparison of two nodesets is not supported: '%.*s'", @@ -2412,21 +2412,78 @@ my_xpath_parse_QName(MY_XPATH *xpath) } -/* +/** Scan Variable reference - SYNOPSYS + @details Implements parsing of two syntax structures: - [36] VariableReference ::= '$' QName - RETURN - 1 - success - 0 - failure + 1. Standard XPath syntax [36], for SP variables: + + VariableReference ::= '$' QName + + Finds a SP variable with the given name. + If outside of a SP context, or variable with + the given name doesn't exists, then error is returned. + + 2. Non-standard syntax - MySQL extension for user variables: + + VariableReference ::= '$' '@' QName + + Item, corresponding to the variable, is returned + in xpath->item in both cases. + + @param xpath pointer to XPath structure + + @return Operation status + @retval 1 Success + @retval 0 Failure */ + static int my_xpath_parse_VariableReference(MY_XPATH *xpath) { - return my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) && - my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT); + LEX_STRING name; + int user_var; + const char *dollar_pos; + if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) || + (!(dollar_pos= xpath->prevtok.beg)) || + (!((user_var= my_xpath_parse_term(xpath, MY_XPATH_LEX_AT) && + my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))) && + !my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))) + return 0; + + name.length= xpath->prevtok.end - xpath->prevtok.beg; + name.str= (char*) xpath->prevtok.beg; + + if (user_var) + xpath->item= new Item_func_get_user_var(name); + else + { + sp_variable_t *spv; + sp_pcontext *spc; + LEX *lex; + if ((lex= current_thd->lex) && + (spc= lex->spcont) && + (spv= spc->find_variable(&name))) + { + Item_splocal *splocal= new Item_splocal(name, spv->offset, spv->type, 0); +#ifndef DBUG_OFF + if (splocal) + splocal->m_sp= lex->sphead; +#endif + xpath->item= (Item*) splocal; + } + else + { + xpath->item= NULL; + DBUG_ASSERT(xpath->query.end > dollar_pos); + uint len= xpath->query.end - dollar_pos; + set_if_smaller(len, 32); + my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'", + MYF(0), len, dollar_pos); + } + } + return xpath->item ? 1 : 0; } @@ -2534,12 +2591,10 @@ void Item_xml_str_func::fix_length_and_dec() if (!rc) { - char context[32]; uint clen= xpath.query.end - xpath.lasttok.beg; - set_if_bigger(clen, sizeof(context) - 1); - strmake(context, xpath.lasttok.beg, clen); - my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%s'", - MYF(0), context); + set_if_smaller(clen, 32); + my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'", + MYF(0), clen, xpath.lasttok.beg); return; } @@ -2768,6 +2823,16 @@ String *Item_func_xml_update::val_str(String *str) nodebeg+= fltbeg->num; + if (!nodebeg->level) + { + /* + Root element, without NameTest: + UpdateXML(xml, '/', 'replacement'); + Just return the replacement string. + */ + return rep; + } + tmp_value.length(0); tmp_value.set_charset(collation.collation); uint offs= nodebeg->type == MY_XML_NODE_TAG ? 1 : 0; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index a98797d7596..5c7a29df33b 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -413,9 +413,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (error) { - if (transactional_table) - ha_autocommit_or_rollback(thd,error); - if (read_file_from_client) while (!read_info.next_line()) ; @@ -463,6 +460,9 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } } #endif /*!EMBEDDED_LIBRARY*/ + if (transactional_table) + ha_autocommit_or_rollback(thd,error); + error= -1; // Error on read goto err; } diff --git a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c index fbf3e541372..5ee0168d4b4 100644 --- a/storage/heap/hp_hash.c +++ b/storage/heap/hp_hash.c @@ -379,7 +379,13 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec) ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key) { - register ulong nr=0; + /* + Note, if a key consists of a combination of numeric and + a text columns, it most likely won't work well. + Making text columns work with NEW_HASH_FUNCTION + needs also changes in strings/ctype-xxx.c. + */ + ulong nr= 1, nr2= 4; HA_KEYSEG *seg,*endseg; for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++) @@ -401,14 +407,15 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key) } if (seg->type == HA_KEYTYPE_TEXT) { - seg->charset->hash_sort(seg->charset,pos,((uchar*)key)-pos,&nr,NULL); + seg->charset->coll->hash_sort(seg->charset, pos, ((uchar*)key)-pos, + &nr, &nr2); } else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */ { uint pack_length= 2; /* Key packing is constant */ uint length= uint2korr(pos); - seg->charset->hash_sort(seg->charset, pos+pack_length, length, &nr, - NULL); + seg->charset->coll->hash_sort(seg->charset, pos+pack_length, length, + &nr, &nr2); key+= pack_length; } else @@ -428,7 +435,7 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key) ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec) { - register ulong nr=0; + ulong nr= 1, nr2= 4; HA_KEYSEG *seg,*endseg; for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++) @@ -444,14 +451,16 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec) } if (seg->type == HA_KEYTYPE_TEXT) { - seg->charset->hash_sort(seg->charset,pos,((uchar*)key)-pos,&nr,NULL); + uint char_length= seg->length; /* TODO: fix to use my_charpos() */ + seg->charset->coll->hash_sort(seg->charset, pos, char_length, + &nr, &nr2); } else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */ { uint pack_length= seg->bit_start; uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos)); - seg->charset->hash_sort(seg->charset, pos+pack_length, - length, &nr, NULL); + seg->charset->coll->hash_sort(seg->charset, pos+pack_length, + length, &nr, &nr2); } else {