diff --git a/client/mysql.cc b/client/mysql.cc index b8655d7c5f5..bee5376e036 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1598,11 +1598,8 @@ You can turn off this feature to get a quicker startup with -A\n\n"); mysql_free_result(fields); } else - { - tee_fprintf(stdout, - "Didn't find any fields in table '%s'\n",table_row[0]); field_names[i]= 0; - } + i++; } mysql_free_result(tables); diff --git a/client/mysqltest.c b/client/mysqltest.c index ca4d9319707..57b81e46b66 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2781,6 +2781,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (!disable_result_log) { ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ + LINT_INIT(affected_rows); if (res) { diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am index 4ebb9a2d862..83397e24168 100644 --- a/extra/yassl/src/Makefile.am +++ b/extra/yassl/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I../include -I../taocrypt/include -I../mySTL -noinst_LIBRARIES = libyassl.a -libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ +noinst_LTLIBRARIES = libyassl.la +libyassl_la_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \ template_instnt.cpp timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp EXTRA_DIST = ../include/*.hpp ../include/openssl/*.h diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am index 5bf45074a98..4549c218d87 100644 --- a/extra/yassl/taocrypt/src/Makefile.am +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I../include -I../../mySTL -noinst_LIBRARIES = libtaocrypt.a -libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ +noinst_LTLIBRARIES = libtaocrypt.la +libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp integer.cpp \ md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \ template_instnt.cpp diff --git a/include/my_sys.h b/include/my_sys.h index d5488ce12fa..11e8a36f5fa 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -866,6 +866,11 @@ extern void add_compiled_collation(CHARSET_INFO *cs); extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, ulong to_length, const char *from, ulong length); +#ifdef __WIN__ +#define BACKSLASH_MBTAIL +/* File system character set */ +extern CHARSET_INFO *fs_character_set(void); +#endif extern ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info, char *to, ulong to_length, const char *from, ulong length); diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 116ae7b6438..11347f430d4 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -94,6 +94,7 @@ extern ulint srv_max_dirty_pages_pct; extern ulint srv_force_recovery; extern ulong srv_thread_concurrency; +extern ulong srv_commit_concurrency; extern ulint srv_max_n_threads; diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index dc85750f0be..64cbae3644a 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -261,6 +261,7 @@ Value 10 should be good if there are less than 4 processors + 4 disks in the computer. Bigger computers need bigger values. */ ulong srv_thread_concurrency = SRV_CONCURRENCY_THRESHOLD; +ulong srv_commit_concurrency = 0; os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data structures */ diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 35c41b7d2d6..c18984c7584 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -221,6 +221,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) MI_INFO *info=ftb->info; uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength; byte *lastkey_buf=ftbw->word+ftbw->off; + LINT_INIT(off); LINT_INIT(off); if (ftbw->flags & FTB_FLAG_TRUNC) diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index a0c8f317db2..1b5619eb18d 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -17,6 +17,15 @@ select 9223372036854775808+1; select -(0-3),round(-(0-3)), round(9999999999999999999); -(0-3) round(-(0-3)) round(9999999999999999999) 3 3 9999999999999999999 +select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001; +1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 +1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001 +select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 +-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001 +select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); +conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16) +1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5 create table t1 (a bigint unsigned not null, primary key(a)); insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612); select * from t1; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 57942d1fcdf..c7e69ae1d31 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -45,6 +45,123 @@ www. .se select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); substring_index('.tcx.se','.',-2) substring_index('.tcx.se','.tcx',-1) tcx.se .se +select substring_index('aaaaaaaaa1','a',1); +substring_index('aaaaaaaaa1','a',1) + +select substring_index('aaaaaaaaa1','aa',1); +substring_index('aaaaaaaaa1','aa',1) + +select substring_index('aaaaaaaaa1','aa',2); +substring_index('aaaaaaaaa1','aa',2) +aa +select substring_index('aaaaaaaaa1','aa',3); +substring_index('aaaaaaaaa1','aa',3) +aaaa +select substring_index('aaaaaaaaa1','aa',4); +substring_index('aaaaaaaaa1','aa',4) +aaaaaa +select substring_index('aaaaaaaaa1','aa',5); +substring_index('aaaaaaaaa1','aa',5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',1); +substring_index('aaaaaaaaa1','aaa',1) + +select substring_index('aaaaaaaaa1','aaa',2); +substring_index('aaaaaaaaa1','aaa',2) +aaa +select substring_index('aaaaaaaaa1','aaa',3); +substring_index('aaaaaaaaa1','aaa',3) +aaaaaa +select substring_index('aaaaaaaaa1','aaa',4); +substring_index('aaaaaaaaa1','aaa',4) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaaa',1); +substring_index('aaaaaaaaa1','aaaa',1) + +select substring_index('aaaaaaaaa1','aaaa',2); +substring_index('aaaaaaaaa1','aaaa',2) +aaaa +select substring_index('aaaaaaaaa1','1',1); +substring_index('aaaaaaaaa1','1',1) +aaaaaaaaa +select substring_index('aaaaaaaaa1','a',-1); +substring_index('aaaaaaaaa1','a',-1) +1 +select substring_index('aaaaaaaaa1','aa',-1); +substring_index('aaaaaaaaa1','aa',-1) +1 +select substring_index('aaaaaaaaa1','aa',-2); +substring_index('aaaaaaaaa1','aa',-2) +aa1 +select substring_index('aaaaaaaaa1','aa',-3); +substring_index('aaaaaaaaa1','aa',-3) +aaaa1 +select substring_index('aaaaaaaaa1','aa',-4); +substring_index('aaaaaaaaa1','aa',-4) +aaaaaa1 +select substring_index('aaaaaaaaa1','aa',-5); +substring_index('aaaaaaaaa1','aa',-5) +aaaaaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-1); +substring_index('aaaaaaaaa1','aaa',-1) +1 +select substring_index('aaaaaaaaa1','aaa',-2); +substring_index('aaaaaaaaa1','aaa',-2) +aaa1 +select substring_index('aaaaaaaaa1','aaa',-3); +substring_index('aaaaaaaaa1','aaa',-3) +aaaaaa1 +select substring_index('aaaaaaaaa1','aaa',-4); +substring_index('aaaaaaaaa1','aaa',-4) + +select substring_index('the king of thethe hill','the',-2); +substring_index('the king of thethe hill','the',-2) +the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill','the',-2); +substring_index('the king of the the hill','the',-2) + the hill +select substring_index('the king of the the hill',' the ',-1); +substring_index('the king of the the hill',' the ',-1) +hill +select substring_index('the king of the the hill',' the ',-2); +substring_index('the king of the the hill',' the ',-2) + the hill +select substring_index('the king of the the hill',' ',-1); +substring_index('the king of the the hill',' ',-1) +hill +select substring_index('the king of the the hill',' ',-2); +substring_index('the king of the the hill',' ',-2) +the hill +select substring_index('the king of the the hill',' ',-3); +substring_index('the king of the the hill',' ',-3) + the hill +select substring_index('the king of the the hill',' ',-4); +substring_index('the king of the the hill',' ',-4) +the the hill +select substring_index('the king of the the hill',' ',-5); +substring_index('the king of the the hill',' ',-5) +of the the hill +select substring_index('the king of the.the hill','the',-2); +substring_index('the king of the.the hill','the',-2) +.the hill +select substring_index('the king of thethethe.the hill','the',-3); +substring_index('the king of thethethe.the hill','the',-3) +the.the hill +select substring_index('the king of thethethe.the hill','the',-1); +substring_index('the king of thethethe.the hill','the',-1) + hill +select substring_index('the king of the the hill','the',1); +substring_index('the king of the the hill','the',1) + +select substring_index('the king of the the hill','the',2); +substring_index('the king of the the hill','the',2) +the king of +select substring_index('the king of the the hill','the',3); +substring_index('the king of the the hill','the',3) +the king of the select concat(':',ltrim(' left '),':',rtrim(' right '),':'); concat(':',ltrim(' left '),':',rtrim(' right '),':') :left : right: diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index fc157093a7f..dbe5d600a95 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -191,3 +191,9 @@ ERROR 23000: Column 'a' in field list is ambiguous insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; ERROR 23000: Column 't1.a' in field list is ambiguous drop table t1; +CREATE TABLE t1 ( +a BIGINT(20) NOT NULL DEFAULT 0, +PRIMARY KEY (a) +) ENGINE=MyISAM; +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ; +DROP TABLE t1; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 6ff49951d27..0efd5ac1566 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -947,24 +947,18 @@ COUNT(*) Warnings: Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 invalid'; COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1 Warning 1292 Incorrect datetime value: '20050328 invalid' for column 'date' at row 1 -Warning 1292 Truncated incorrect INTEGER value: '20050328 invalid' -Warning 1292 Truncated incorrect INTEGER value: '20050328 invalid' SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 invalid'; COUNT(*) 0 Warnings: Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 Warning 1292 Incorrect datetime value: '20050327 invalid' for column 'date' at row 1 -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' -Warning 1292 Truncated incorrect INTEGER value: '20050327 invalid' show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 diff --git a/mysql-test/r/query_cache_notembedded.result b/mysql-test/r/query_cache_notembedded.result index 16a397f78b6..e773a63525b 100644 --- a/mysql-test/r/query_cache_notembedded.result +++ b/mysql-test/r/query_cache_notembedded.result @@ -80,4 +80,18 @@ show status like "Qcache_free_blocks"; Variable_name Value Qcache_free_blocks 1 drop table t1, t2, t3, t11, t21; +CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE = +MyISAM; +LOCK TABLE t1 READ LOCAL; +INSERT INTO t1 VALUES (), (), (); +SELECT * FROM t1; +a +SELECT * FROM t1; +a +1 +2 +3 +SELECT * FROM t1; +a +drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result index 2f7e8021aa7..c516d7a643f 100644 --- a/mysql-test/r/sp-threads.result +++ b/mysql-test/r/sp-threads.result @@ -37,6 +37,7 @@ Id User Host db Command Time State Info # root localhost test Sleep # NULL # root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2 # root localhost test Query # NULL show processlist +# root localhost test Sleep # NULL unlock tables; drop procedure bug9486; drop table t1, t2; @@ -64,3 +65,27 @@ insert into t1 (select f from v1); drop function bug11554; drop table t1; drop view v1; +drop procedure if exists p1; +drop procedure if exists p2; +create table t1 (s1 int)| +create procedure p1() select * from t1| +create procedure p2() +begin +insert into t1 values (1); +call p1(); +select * from t1; +end| +use test; +lock table t1 write; + call p2(); +use test; +drop procedure p1; +create procedure p1() select * from t1; +unlock tables; +s1 +1 +s1 +1 +drop procedure p1; +drop procedure p2; +drop table t1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 9606ed97ee7..5927419579d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2753,7 +2753,28 @@ WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); one two flag 5 6 N 7 8 N +insert into t2 values (null,null,'N'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +one two test +1 2 0 +2 3 0 +3 4 0 +5 6 1 +7 8 1 +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; +one two test +1 2 NULL +2 3 NULL +3 4 NULL +5 6 1 +7 8 1 DROP TABLE t1,t2; +CREATE TABLE t1 (a char(5), b char(5)); +INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); +SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); +a b +aaa aaa +DROP TABLE t1; create table t1 (df decimal(5,1)); insert into t1 values(1.1); insert into t1 values(2.2); diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 284e4c1556b..ee0a6f6b744 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -651,3 +651,16 @@ insert into t1 values (0); ERROR 0A000: FLUSH is not allowed in stored function or trigger drop procedure p1; drop table t1; +create table t1 (id int, data int, username varchar(16)); +insert into t1 (id, data) values (1, 0); +create trigger t1_whoupdated before update on t1 for each row +begin +declare user varchar(32); +declare i int; +select user() into user; +set NEW.username = user; +select count(*) from ((select 1) union (select 2)) as d1 into i; +end| +update t1 set data = 1; +update t1 set data = 2; +drop table t1; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 035af0d82ac..5988b4f745e 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -34,7 +34,7 @@ select 0 + b'1111111111111111'; select 0 + b'1000000000000001'; 0 + b'1000000000000001' 32769 -drop table if exists t1; +drop table if exists t1,t2; create table t1 (a bit(65)); ERROR 42000: Display width out of range for column 'a' (max = 64) create table t1 (a bit(0)); diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 788478de77e..85f899be5d8 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -26,6 +26,8 @@ Table Op Msg_type Msg_text test.t1 check status OK delete from t1; insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000"); +insert into t1 values ("2003-003-03"); +insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01"); select * from t1; t 2000-01-01 00:00:00 @@ -43,6 +45,17 @@ t 9999-12-31 23:59:59 2003-01-00 00:00:00 2003-00-00 00:00:00 +2003-03-03 00:00:00 +2003-01-02 13:14:15 +2001-01-01 01:01:01 +2001-01-01 01:01:01 +truncate table t1; +insert into t1 values("2003-0303 12:13:14"); +Warnings: +Warning 1264 Out of range value adjusted for column 't' at row 1 +select * from t1; +t +0000-00-00 00:00:00 drop table t1; CREATE TABLE t1 (a timestamp, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); @@ -153,13 +166,3 @@ dt 0000-00-00 00:00:00 0000-00-00 00:00:00 drop table t1; -create table t1 (dt datetime); -insert into t1 values ("20010101T010101"); -insert into t1 values ("2001-01-01T01:01:01"); -insert into t1 values ("2001-1-1T1:01:01"); -select * from t1; -dt -2001-01-01 01:01:01 -2001-01-01 01:01:01 -2001-01-01 01:01:01 -drop table t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index f6b5018cf3a..98020c7ec33 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1880,6 +1880,8 @@ test.v5 check error View 'test.v5' references invalid table(s) or column(s) or f test.v6 check status OK drop view v1, v2, v3, v4, v5, v6; drop table t2; +drop function if exists f1; +drop function if exists f2; CREATE TABLE t1 (col1 time); CREATE TABLE t2 (col1 time); CREATE TABLE t3 (col1 time); diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index 5c06ef89676..5f21d2b5813 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -14,6 +14,9 @@ select +9999999999999999999,-9999999999999999999; select cast(9223372036854775808 as unsigned)+1; select 9223372036854775808+1; select -(0-3),round(-(0-3)), round(9999999999999999999); +select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001; +select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001; +select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16); # # In 3.23 we have to disable the test of column to bigint as diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index c66f3eaa294..4a6c98c8d7f 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -23,6 +23,45 @@ select concat('',left(right(concat('what ',concat('is ','happening')),9),4),'',s select substring_index('www.tcx.se','.',-2),substring_index('www.tcx.se','.',1); select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',-1); select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1); +select substring_index('aaaaaaaaa1','a',1); +select substring_index('aaaaaaaaa1','aa',1); +select substring_index('aaaaaaaaa1','aa',2); +select substring_index('aaaaaaaaa1','aa',3); +select substring_index('aaaaaaaaa1','aa',4); +select substring_index('aaaaaaaaa1','aa',5); +select substring_index('aaaaaaaaa1','aaa',1); +select substring_index('aaaaaaaaa1','aaa',2); +select substring_index('aaaaaaaaa1','aaa',3); +select substring_index('aaaaaaaaa1','aaa',4); +select substring_index('aaaaaaaaa1','aaaa',1); +select substring_index('aaaaaaaaa1','aaaa',2); +select substring_index('aaaaaaaaa1','1',1); +select substring_index('aaaaaaaaa1','a',-1); +select substring_index('aaaaaaaaa1','aa',-1); +select substring_index('aaaaaaaaa1','aa',-2); +select substring_index('aaaaaaaaa1','aa',-3); +select substring_index('aaaaaaaaa1','aa',-4); +select substring_index('aaaaaaaaa1','aa',-5); +select substring_index('aaaaaaaaa1','aaa',-1); +select substring_index('aaaaaaaaa1','aaa',-2); +select substring_index('aaaaaaaaa1','aaa',-3); +select substring_index('aaaaaaaaa1','aaa',-4); +select substring_index('the king of thethe hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill','the',-2); +select substring_index('the king of the the hill',' the ',-1); +select substring_index('the king of the the hill',' the ',-2); +select substring_index('the king of the the hill',' ',-1); +select substring_index('the king of the the hill',' ',-2); +select substring_index('the king of the the hill',' ',-3); +select substring_index('the king of the the hill',' ',-4); +select substring_index('the king of the the hill',' ',-5); +select substring_index('the king of the.the hill','the',-2); +select substring_index('the king of thethethe.the hill','the',-3); +select substring_index('the king of thethethe.the hill','the',-1); +select substring_index('the king of the the hill','the',1); +select substring_index('the king of the the hill','the',2); +select substring_index('the king of the the hill','the',3); select concat(':',ltrim(' left '),':',rtrim(' right '),':'); select concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':'); diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 5948f92d4e0..eda768be1bc 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -101,4 +101,18 @@ insert into t1 select a from t1 on duplicate key update a=a+1 ; insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; drop table t1; +# +# Bug#10109 - INSERT .. SELECT ... ON DUPLICATE KEY UPDATE fails +# Bogus "Duplicate columns" error message +# + +CREATE TABLE t1 ( + a BIGINT(20) NOT NULL DEFAULT 0, + PRIMARY KEY (a) +) ENGINE=MyISAM; + +INSERT INTO t1 ( a ) SELECT 0 ON DUPLICATE KEY UPDATE a = a + VALUES (a) ; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/mysql-test/t/query_cache_notembedded.test b/mysql-test/t/query_cache_notembedded.test index d29dc10ccae..fd4785ffe95 100644 --- a/mysql-test/t/query_cache_notembedded.test +++ b/mysql-test/t/query_cache_notembedded.test @@ -78,4 +78,23 @@ show status like "Qcache_total_blocks"; show status like "Qcache_free_blocks"; drop table t1, t2, t3, t11, t21; +# +# do not use QC if tables locked (BUG#12385) +# +connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root; +CREATE TABLE t1 ( a INT NOT NULL PRIMARY KEY AUTO_INCREMENT ) ENGINE = +MyISAM; +LOCK TABLE t1 READ LOCAL; +connect (root2,localhost,root,,test,$MASTER_MYPORT,master.sock); +connection root2; +INSERT INTO t1 VALUES (), (), (); +connection root; +SELECT * FROM t1; +connection root2; +SELECT * FROM t1; +connection root; +SELECT * FROM t1; +drop table t1; + set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test index 4733201cde2..70c1efb1f0b 100644 --- a/mysql-test/t/sp-threads.test +++ b/mysql-test/t/sp-threads.test @@ -5,6 +5,7 @@ connect (con1root,localhost,root,,); connect (con2root,localhost,root,,); +connect (con3root,localhost,root,,); connection con1root; use test; @@ -130,6 +131,48 @@ drop function bug11554; drop table t1; drop view v1; + +# BUG#12228 +--disable_warnings +drop procedure if exists p1; +drop procedure if exists p2; +--enable_warnings + +connection con1root; +delimiter |; +create table t1 (s1 int)| +create procedure p1() select * from t1| +create procedure p2() +begin + insert into t1 values (1); + call p1(); + select * from t1; +end| +delimiter ;| + +connection con2root; +use test; +lock table t1 write; + +connection con1root; +send call p2(); + +connection con3root; +use test; +drop procedure p1; +create procedure p1() select * from t1; + +connection con2root; +unlock tables; + +connection con1root; +# Crash will be here if we hit BUG#12228 +reap; + +drop procedure p1; +drop procedure p2; +drop table t1; + # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8bc47190dca..995c3528ae6 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1773,8 +1773,23 @@ SELECT * FROM t1 SELECT * FROM t1 WHERE ROW(one,two) IN (SELECT DISTINCT one,two FROM t1 WHERE flag = 'N'); +insert into t2 values (null,null,'N'); +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N') as 'test' from t1; +SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N' group by one,two) as 'test' from t1; + DROP TABLE t1,t2; +# +# Bug #12392: where cond with IN predicate for rows and NULL values in table +# + +CREATE TABLE t1 (a char(5), b char(5)); +INSERT INTO t1 VALUES (NULL,'aaa'), ('aaa','aaa'); + +SELECT * FROM t1 WHERE (a,b) IN (('aaa','aaa'), ('aaa','bbb')); + +DROP TABLE t1; + # End of 4.1 tests # diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 789405696c2..49ec42568ad 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -662,3 +662,26 @@ create procedure p1() flush privileges; insert into t1 values (0); drop procedure p1; drop table t1; + +# Test for bug #11973 "SELECT .. INTO var_name; in trigger cause +# crash on update" +create table t1 (id int, data int, username varchar(16)); +insert into t1 (id, data) values (1, 0); +delimiter |; +create trigger t1_whoupdated before update on t1 for each row +begin + declare user varchar(32); + declare i int; + select user() into user; + set NEW.username = user; + select count(*) from ((select 1) union (select 2)) as d1 into i; +end| +delimiter ;| +update t1 set data = 1; + +connect (addconroot, localhost, root,,); +connection addconroot; +update t1 set data = 2; + +connection default; +drop table t1; diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 005a2c78a14..6906cfc2808 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -16,7 +16,7 @@ select 0 + b'1111111111111111'; select 0 + b'1000000000000001'; --disable_warnings -drop table if exists t1; +drop table if exists t1,t2; --enable_warnings --error 1439 diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index ca70e35d3cd..4b6741b4242 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -14,6 +14,17 @@ optimize table t1; check table t1; delete from t1; insert into t1 values("000101"),("691231"),("700101"),("991231"),("00000101"),("00010101"),("99991231"),("00101000000"),("691231000000"),("700101000000"),("991231235959"),("10000101000000"),("99991231235959"),("20030100000000"),("20030000000000"); + +# Strange dates +insert into t1 values ("2003-003-03"); + +# Bug #7308: ISO-8601 date format not handled correctly +insert into t1 values ("20030102T131415"),("2001-01-01T01:01:01"), ("2001-1-1T1:01:01"); +select * from t1; + +# Test some wrong dates +truncate table t1; +insert into t1 values("2003-0303 12:13:14"); select * from t1; drop table t1; @@ -102,14 +113,4 @@ insert into t1 values ("00-00-00"), ("00-00-00 00:00:00"); select * from t1; drop table t1; -# -# Bug #7308: ISO-8601 date format not handled correctly -# -create table t1 (dt datetime); -insert into t1 values ("20010101T010101"); -insert into t1 values ("2001-01-01T01:01:01"); -insert into t1 values ("2001-1-1T1:01:01"); -select * from t1; -drop table t1; - # End of 4.1 tests diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 9885566442f..cba2d75fb7c 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1711,6 +1711,10 @@ CHECK TABLE v1, v2, v3, v4, v5, v6; drop view v1, v2, v3, v4, v5, v6; drop table t2; +--disable_warnings +drop function if exists f1; +drop function if exists f2; +--enable_warnings CREATE TABLE t1 (col1 time); CREATE TABLE t2 (col1 time); CREATE TABLE t3 (col1 time); diff --git a/mysys/charset.c b/mysys/charset.c index 701170b747b..c02144fafc0 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -679,6 +679,32 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, } +#ifdef BACKSLASH_MBTAIL +static CHARSET_INFO *fs_cset_cache= NULL; + +CHARSET_INFO *fs_character_set() +{ + if (!fs_cset_cache) + { + char buf[10]= "cp"; + GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, + buf+2, sizeof(buf)-3); + /* + We cannot call get_charset_by_name here + because fs_character_set() is executed before + LOCK_THD_charset mutex initialization, which + is used inside get_charset_by_name. + As we're now interested in cp932 only, + let's just detect it using strcmp(). + */ + fs_cset_cache= !strcmp(buf, "cp932") ? + &my_charset_cp932_japanese_ci : &my_charset_bin; + } + return fs_cset_cache; +} +#endif + + /* Escape apostrophes by doubling them up diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c index 3de82c05b87..45bf4d56c31 100644 --- a/mysys/mf_dirname.c +++ b/mysys/mf_dirname.c @@ -22,6 +22,9 @@ uint dirname_length(const char *name) { register my_string pos,gpos; +#ifdef BASKSLASH_MBTAIL + CHARSET_INFO *fs= fs_character_set(); +#endif #ifdef FN_DEVCHAR if ((pos=(char*)strrchr(name,FN_DEVCHAR)) == 0) #endif @@ -29,12 +32,22 @@ uint dirname_length(const char *name) gpos= pos++; for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */ + { +#ifdef BASKSLASH_MBTAIL + uint l; + if (use_mb(fs) && (l= my_ismbchar(fs, pos, pos + 3))) + { + pos+= l - 1; + continue; + } +#endif if (*pos == FN_LIBCHAR || *pos == '/' #ifdef FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2 #endif ) gpos=pos; + } return ((uint) (uint) (gpos+1-(char*) name)); } @@ -85,6 +98,9 @@ uint dirname_part(my_string to, const char *name) char *convert_dirname(char *to, const char *from, const char *from_end) { char *to_org=to; +#ifdef BACKSLASH_MBTAIL + CHARSET_INFO *fs= fs_character_set(); +#endif /* We use -2 here, becasue we need place for the last FN_LIBCHAR */ if (!from_end || (from_end - from) > FN_REFLEN-2) @@ -103,7 +119,22 @@ char *convert_dirname(char *to, const char *from, const char *from_end) *to++= FN_C_AFTER_DIR; #endif else - *to++= *from; + { +#ifdef BACKSLASH_MBTAIL + uint l; + if (use_mb(fs) && (l= my_ismbchar(fs, from, from + 3))) + { + memmove(to, from, l); + to+= l; + from+= l - 1; + to_org= to; /* Don't look inside mbchar */ + } + else +#endif + { + *to++= *from; + } + } } *to=0; } diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c index 86172f648f4..049aa59a578 100644 --- a/mysys/mf_pack.c +++ b/mysys/mf_pack.c @@ -124,6 +124,9 @@ uint cleanup_dirname(register my_string to, const char *from) reg4 my_string start; char parent[5], /* for "FN_PARENTDIR" */ buff[FN_REFLEN+1],*end_parentdir; +#ifdef BACKSLASH_MBTAIL + CHARSET_INFO *fs= fs_character_set(); +#endif DBUG_ENTER("cleanup_dirname"); DBUG_PRINT("enter",("from: '%s'",from)); @@ -141,6 +144,15 @@ uint cleanup_dirname(register my_string to, const char *from) length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent); for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++) { +#ifdef BACKSLASH_MBTAIL + uint l; + if (use_mb(fs) && (l= my_ismbchar(fs, from_ptr - 1, from_ptr + 2))) + { + for (l-- ; l ; *++pos= *from_ptr++, l--); + start= pos + 1; /* Don't look inside multi-byte char */ + continue; + } +#endif if (*pos == '/') *pos = FN_LIBCHAR; if (*pos == FN_LIBCHAR) diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index a9d4512112f..521bd346fd3 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -58,7 +58,7 @@ LogHandler::append(const char* pCategory, Logger::LoggerLevel level, } else // repeated message { - if (now < m_last_log_time+m_max_repeat_frequency) + if (now < (time_t) (m_last_log_time+m_max_repeat_frequency)) { m_count_repeated_messages++; m_now= now; diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 95ac779e0cd..72809ee9b4b 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -197,7 +197,9 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ - for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) + for (pos=str; + pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T'); + pos++) ; digits= (uint) (pos-str); @@ -263,7 +265,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, const char *start= str; ulong tmp_value= (uint) (uchar) (*str++ - '0'); while (str != end && my_isdigit(&my_charset_latin1,str[0]) && - --field_length) + (!is_internal_format || --field_length)) { tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0'); str++; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0a01c08c916..02a1ac8e6f6 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -48,6 +48,10 @@ have disables the InnoDB inlining in this file. */ pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */ prepare_commit_mutex; /* to force correct commit order in binlog */ +ulong commit_threads= 0; +pthread_mutex_t commit_threads_m; +pthread_cond_t commit_cond; +pthread_mutex_t commit_cond_m; bool innodb_inited= 0; /*-----------------------------------------------------------------*/ @@ -948,9 +952,7 @@ innobase_query_caching_of_table_permitted( trx = check_trx_exists(thd); if (trx->has_search_latch) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: the calling thread is holding the adaptive search\n" -"InnoDB: latch though calling innobase_query_caching_of_table_permitted\n"); + sql_print_error("The calling thread is holding the adaptive search, latch though calling innobase_query_caching_of_table_permitted."); } innobase_release_stat_resources(trx); @@ -1266,9 +1268,7 @@ innobase_init(void) &srv_log_group_home_dirs); if (ret == FALSE || innobase_mirrored_log_groups != 1) { - fprintf(stderr, - "InnoDB: syntax error in innodb_log_group_home_dir\n" - "InnoDB: or a wrong number of mirrored log groups\n"); + sql_print_error("syntax error in innodb_log_group_home_dir, or a wrong number of mirrored log groups"); my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); @@ -1367,6 +1367,9 @@ innobase_init(void) (hash_get_key) innobase_get_key, 0, 0); pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST); pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); + pthread_cond_init(&commit_cond, NULL); innodb_inited= 1; /* If this is a replication slave and we needed to do a crash recovery, @@ -1416,6 +1419,9 @@ innobase_end(void) MYF(MY_ALLOW_ZERO_PTR)); pthread_mutex_destroy(&innobase_share_mutex); pthread_mutex_destroy(&prepare_commit_mutex); + pthread_mutex_destroy(&commit_threads_m); + pthread_mutex_destroy(&commit_cond_m); + pthread_cond_destroy(&commit_cond); } DBUG_RETURN(err); @@ -1542,8 +1548,10 @@ innobase_commit( reserve the kernel mutex, we have to release the search system latch first to obey the latching order. */ - innobase_release_stat_resources(trx); - + if (trx->has_search_latch) { + trx_search_latch_release_if_reserved(trx); + } + /* The flag trx->active_trans is set to 1 in 1. ::external_lock(), @@ -1562,11 +1570,8 @@ innobase_commit( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - fprintf(stderr, -"InnoDB: Error: trx->active_trans == 0\n" -"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); } - if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { @@ -1575,18 +1580,43 @@ innobase_commit( /* We need current binlog position for ibbackup to work. Note, the position is current because of prepare_commit_mutex */ +retry: + if (srv_commit_concurrency > 0) + { + pthread_mutex_lock(&commit_cond_m); + commit_threads++; + if (commit_threads > srv_commit_concurrency) + { + commit_threads--; + pthread_cond_wait(&commit_cond, &commit_cond_m); + pthread_mutex_unlock(&commit_cond_m); + goto retry; + } + else + pthread_mutex_unlock(&commit_cond_m); + } + trx->mysql_log_file_name = mysql_bin_log.get_log_fname(); trx->mysql_log_offset = (ib_longlong)mysql_bin_log.get_log_file()->pos_in_file; innobase_commit_low(trx); + if (srv_commit_concurrency > 0) + { + pthread_mutex_lock(&commit_cond_m); + commit_threads--; + pthread_cond_signal(&commit_cond); + pthread_mutex_unlock(&commit_cond_m); + } + if (trx->active_trans == 2) { pthread_mutex_unlock(&prepare_commit_mutex); } + trx->active_trans = 0; - + } else { /* We just mark the SQL statement ended and do not do a transaction commit */ @@ -1606,7 +1636,11 @@ innobase_commit( /* Tell the InnoDB server that there might be work for utility threads: */ + if (trx->declared_to_be_inside_innodb) { + /* Release our possible ticket in the FIFO */ + srv_conc_force_exit_innodb(trx); + } srv_active_wake_master_thread(); DBUG_RETURN(0); @@ -1813,21 +1847,7 @@ try_again: if (ret != 0) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: MySQL synchronous replication\n" -"InnoDB: was not able to send the binlog to the slave within the\n" -"InnoDB: timeout %lu. We assume that the slave has become inaccessible,\n" -"InnoDB: and switch off synchronous replication until the communication.\n" -"InnoDB: to the slave works again.\n", - thd->variables.sync_replication_timeout); - fprintf(stderr, -"InnoDB: MySQL synchronous replication has sent binlog\n" -"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name, - (ulong)innobase_repl_pos); - fprintf(stderr, -"InnoDB: This transaction needs it to be sent up to\n" -"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name, - (ulong)trx->repl_wait_binlog_pos); + sql_print_error("MySQL synchronous replication was not able to send the binlog to the slave within the timeout %lu. We assume that the slave has become inaccessible, and switch off synchronous replication until the communication to the slave works again. MySQL synchronous replication has sent binlog to the slave up to file %s, position %lu. This transaction needs it to be sent up to file %s, position %lu.", thd->variables.sync_replication_timeout, innobase_repl_file_name, (ulong)innobase_repl_pos, trx->repl_wait_binlog_name, (ulong)trx->repl_wait_binlog_pos); innobase_repl_state = 0; @@ -1878,9 +1898,7 @@ innobase_repl_report_sent_binlog( if (innobase_repl_state == 0) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Switching MySQL synchronous replication on again at\n" -"InnoDB: binlog file %s, position %lu\n", log_file_name, (ulong)end_offset); + sql_print_warning("Switching MySQL synchronous replication on again at binlog file %s, position %lu", log_file_name, (ulong) end_offset); innobase_repl_state = 1; } @@ -1897,14 +1915,7 @@ innobase_repl_report_sent_binlog( || (cmp == 0 && end_offset < innobase_repl_pos)) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: MySQL synchronous replication has sent binlog\n" -"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name, - (ulong)innobase_repl_pos); - fprintf(stderr, -"InnoDB: but now MySQL reports that it sent the binlog only up to\n" -"InnoDB: file %s, position %lu\n", log_file_name, (ulong)end_offset); - + sql_print_error("MySQL synchronous replication has sent binlog to the slave up to file %s, position %lu, but now MySQL reports that it sent the binlog only up to file %s, position %lu", innobase_repl_file_name, (ulong)innobase_repl_pos, log_file_name, (ulong) end_offset); } } @@ -2149,9 +2160,7 @@ innobase_close_connection( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - fprintf(stderr, -"InnoDB: Error: trx->active_trans == 0\n" -"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); } @@ -2363,9 +2372,7 @@ ha_innobase::open( if (!row_table_got_default_clust_index(ib_table)) { if (primary_key >= MAX_KEY) { - fprintf(stderr, - "InnoDB: Error: table %s has a primary key in InnoDB\n" - "InnoDB: data dictionary, but not in MySQL!\n", name); + sql_print_error("Table %s has a primary key in InnoDB data dictionary, but not in MySQL!", name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -2379,16 +2386,7 @@ ha_innobase::open( ref_length = table->key_info[primary_key].key_length; } else { if (primary_key != MAX_KEY) { - fprintf(stderr, - "InnoDB: Error: table %s has no primary key in InnoDB\n" - "InnoDB: data dictionary, but has one in MySQL!\n" - "InnoDB: If you created the table with a MySQL\n" - "InnoDB: version < 3.23.54 and did not define a primary\n" - "InnoDB: key, but defined a unique key with all non-NULL\n" - "InnoDB: columns, then MySQL internally treats that key\n" - "InnoDB: as the primary key. You can fix this error by\n" - "InnoDB: dump + DROP + CREATE + reimport of the table.\n", - name); + sql_print_error("Table %s has no primary key in InnoDB data dictionary, but has one in MySQL! If you created the table with a MySQL version < 3.23.54 and did not define a primary key, but defined a unique key with all non-NULL columns, then MySQL internally treats that key as the primary key. You can fix this error by dump + DROP + CREATE + reimport of the table.", name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -2405,10 +2403,7 @@ ha_innobase::open( and it will never be updated anyway. */ if (key_used_on_scan != MAX_KEY) { - fprintf(stderr, -"InnoDB: Warning: table %s key_used_on_scan is %lu even though there is no\n" -"InnoDB: primary key inside InnoDB.\n", - name, (ulong)key_used_on_scan); + sql_print_warning("Table %s key_used_on_scan is %lu even though there is no primary key inside InnoDB.", name, (ulong) key_used_on_scan); } } @@ -2563,9 +2558,7 @@ innobase_mysql_cmp( charset = get_charset(charset_number, MYF(MY_WME)); if (charset == NULL) { - fprintf(stderr, -"InnoDB: fatal error: InnoDB needs charset %lu for doing a comparison,\n" -"InnoDB: but MySQL cannot find that charset.\n", (ulong)charset_number); + sql_print_error("InnoDB needs charset %lu for doing a comparison, but MySQL cannot find that charset.", (ulong) charset_number); ut_a(0); } } @@ -3131,11 +3124,8 @@ ha_innobase::write_row( if (prebuilt->trx != (trx_t*) current_thd->ha_data[innobase_hton.slot]) { - fprintf(stderr, -"InnoDB: Error: the transaction object for the table handle is at\n" -"InnoDB: %p, but for the current thread it is at %p\n", - prebuilt->trx, - (trx_t*) current_thd->ha_data[innobase_hton.slot]); + sql_print_error("The transaction object for the table handle is at %p, but for the current thread it is at %p", prebuilt->trx, (trx_t*) current_thd->ha_data[innobase_hton.slot]); + fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr); ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200); fputs("\n" @@ -3622,9 +3612,7 @@ ha_innobase::unlock_row(void) if (last_query_id != user_thd->query_id) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: last_query_id is %lu != user_thd_query_id is %lu\n", - (ulong)last_query_id, (ulong)user_thd->query_id); + sql_print_error("last_query_id is %lu != user_thd_query_id is %lu", (ulong) last_query_id, (ulong) user_thd->query_id); mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } @@ -4284,9 +4272,8 @@ ha_innobase::position( table. */ if (len != ref_length) { - fprintf(stderr, - "InnoDB: Error: stored ref len is %lu, but table ref len is %lu\n", - (ulong)len, (ulong)ref_length); + sql_print_error("Stored ref len is %lu, but table ref len is %lu", + (ulong) len, (ulong) ref_length); } } @@ -4491,11 +4478,8 @@ create_index( || col_type == DATA_FLOAT || col_type == DATA_DOUBLE || col_type == DATA_DECIMAL) { - fprintf(stderr, -"InnoDB: error: MySQL is trying to create a column prefix index field\n" -"InnoDB: on an inappropriate data type. Table name %s, column name %s.\n", - table_name, key_part->field->field_name); - + sql_print_error("MySQL is trying to create a column prefix index field, on an inappropriate data type. Table name %s, column name %s.", table_name, key_part->field->field_name); + prefix_len = 0; } } else { @@ -5378,12 +5362,7 @@ ha_innobase::info( for (i = 0; i < table->s->keys; i++) { if (index == NULL) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: table %s contains less indexes inside InnoDB\n" -"InnoDB: than are defined in the MySQL .frm file. Have you mixed up\n" -"InnoDB: .frm files from different installations? See section\n" -"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n", - ib_table->name); + sql_print_error("Table %s contains less indexes inside InnoDB than are defined in the MySQL .frm file. Have you mixed up .frm files from different installations? See section 15.1 at http://www.innodb.com/ibman.html", ib_table->name); break; } @@ -5391,15 +5370,7 @@ ha_innobase::info( if (j + 1 > index->n_uniq) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: index %s of %s has %lu columns unique inside InnoDB\n" -"InnoDB: but MySQL is asking statistics for %lu columns. Have you mixed up\n" -"InnoDB: .frm files from different installations? See section\n" -"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n", - index->name, - ib_table->name, - (unsigned long) index->n_uniq, - j + 1); + sql_print_error("Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking statistics for %lu columns. Have you mixed up .frm files from different installations? See section 15.1 at http://www.innodb.com/ibman.html", index->name, ib_table->name, (unsigned long) index->n_uniq, j + 1); break; } @@ -5947,9 +5918,7 @@ ha_innobase::start_stmt( if (prebuilt->stored_select_lock_type != LOCK_S && prebuilt->stored_select_lock_type != LOCK_X) { - fprintf(stderr, -"InnoDB: Error: stored_select_lock_type is %lu inside ::start_stmt()!\n", - prebuilt->stored_select_lock_type); + sql_print_error("stored_select_lock_type is %lu inside ::start_stmt()!", prebuilt->stored_select_lock_type); /* Set the value to LOCK_X: this is just fault tolerance, we do not know what the correct value @@ -6725,9 +6694,7 @@ ha_innobase::innobase_read_and_init_auto_inc( error = 0; } else { /* This should not happen in a consistent read */ - fprintf(stderr, -"InnoDB: Error: consistent read of auto-inc column returned %lu\n", - (ulong)error); + sql_print_error("Consistent read of auto-inc column returned %lu", (ulong) error); auto_inc = -1; goto func_exit; @@ -6784,9 +6751,8 @@ ha_innobase::get_auto_increment() initialized. */ ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: error %lu in ::get_auto_increment()\n", - (ulong)error); + sql_print_error("Error %lu in ::get_auto_increment()", + (ulong) error); return(~(ulonglong) 0); } @@ -7053,9 +7019,7 @@ innobase_xa_prepare( if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) { - fprintf(stderr, -"InnoDB: Error: trx->active_trans == 0\n" -"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + sql_print_error("trx->active_trans == 0, but trx->conc_state != TRX_NOT_STARTED"); } if (all diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 3bc1fc5b2c8..4817ab9b682 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -232,6 +232,7 @@ extern ulong srv_n_spin_wait_rounds; extern ulong srv_n_free_tickets_to_enter; extern ulong srv_thread_sleep_delay; extern ulong srv_thread_concurrency; +extern ulong srv_commit_concurrency; } extern TYPELIB innobase_lock_typelib; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d430d0d3c23..261f719e502 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1903,6 +1903,8 @@ in_row::~in_row() byte *in_row::get_value(Item *item) { tmp.store_value(item); + if (item->is_null()) + return 0; return (byte *)&tmp; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 256090d3e61..39e74acb2e9 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1177,11 +1177,23 @@ String *Item_func_substr_index::val_str(String *str) } } else - { // Start counting at end - for (offset=res->length() ; ; offset-=delimeter_length-1) + { + /* + Negative index, start counting at the end + */ + for (offset=res->length(); offset ;) { + /* + this call will result in finding the position pointing to one + address space less than where the found substring is located + in res + */ if ((int) (offset=res->strrstr(*delimeter,offset)) < 0) return res; // Didn't find, return org string + /* + At this point, we've searched for the substring + the number of times as supplied by the index value + */ if (!++count) { offset+=delimeter_length; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 53e377339b3..accc6d420be 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1276,6 +1276,14 @@ void Item_allany_subselect::print(String *str) } +void subselect_engine::set_thd(THD *thd_arg) +{ + thd= thd_arg; + if (result) + result->set_thd(thd_arg); +} + + subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, select_subselect *result, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0b5736169fa..46623f76170 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -299,8 +299,11 @@ public: virtual ~subselect_engine() {}; // to satisfy compiler virtual void cleanup()= 0; - // set_thd should be called before prepare() - void set_thd(THD *thd_arg) { thd= thd_arg; } + /* + Also sets "thd" for subselect_engine::result. + Should be called before prepare(). + */ + void set_thd(THD *thd_arg); THD * get_thd() { return thd; } virtual int prepare()= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f8bfcb75be2..4dddac6b2d1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5314,6 +5314,10 @@ log and this option does nothing anymore.", "Helps in performance tuning in heavily concurrent environments.", (gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency, 0, GET_LONG, REQUIRED_ARG, 20, 1, 1000, 0, 1, 0}, + {"innodb_commit_concurrency", OPT_INNODB_THREAD_CONCURRENCY, + "Helps in performance tuning in heavily concurrent environments.", + (gptr*) &srv_commit_concurrency, (gptr*) &srv_commit_concurrency, + 0, GET_LONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0}, {"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0" " disable a sleep", diff --git a/sql/set_var.cc b/sql/set_var.cc index 637b33f18d2..53f3d45e522 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -411,6 +411,8 @@ sys_var_long_ptr sys_innodb_thread_sleep_delay("innodb_thread_sleep_delay", &srv_thread_sleep_delay); sys_var_long_ptr sys_innodb_thread_concurrency("innodb_thread_concurrency", &srv_thread_concurrency); +sys_var_long_ptr sys_innodb_commit_concurrency("innodb_commit_concurrency", + &srv_commit_concurrency); #endif /* Condition pushdown to storage engine */ @@ -708,6 +710,7 @@ sys_var *sys_variables[]= &sys_innodb_concurrency_tickets, &sys_innodb_thread_sleep_delay, &sys_innodb_thread_concurrency, + &sys_innodb_commit_concurrency, #endif &sys_trust_routine_creators, &sys_engine_condition_pushdown, @@ -828,6 +831,7 @@ struct show_var_st init_vars[]= { {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS}, {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS}, + {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS}, {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, diff --git a/sql/slave.cc b/sql/slave.cc index c09753d805b..d2a60076cef 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2396,8 +2396,8 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) &my_charset_bin); protocol->store((ulonglong) mi->rli.group_relay_log_pos); protocol->store(mi->rli.group_master_log_name, &my_charset_bin); - protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT - ? "Yes":"No", &my_charset_bin); + protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ? + "Yes" : "No", &my_charset_bin); protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin); protocol->store(&replicate_do_db); protocol->store(&replicate_ignore_db); diff --git a/sql/sp.cc b/sql/sp.cc index 0eee0ac209c..5dd7c613a10 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -989,13 +989,11 @@ int sp_drop_procedure(THD *thd, sp_name *name) { int ret; - bool found; DBUG_ENTER("sp_drop_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_proc_cache, name); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1005,13 +1003,11 @@ int sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; - bool found; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_proc_cache, name); ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1102,13 +1098,11 @@ int sp_drop_function(THD *thd, sp_name *name) { int ret; - bool found; DBUG_ENTER("sp_drop_function"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_func_cache, name); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1118,13 +1112,11 @@ int sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; - bool found; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_func_cache, name); ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index c8f0ed6ba2d..68e8dbb3252 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -24,17 +24,78 @@ static pthread_mutex_t Cversion_lock; static ulong Cversion = 0; -void -sp_cache_init() + +/* + Cache of stored routines. +*/ + +class sp_cache +{ +public: + ulong version; + + sp_cache(); + ~sp_cache(); + + inline void insert(sp_head *sp) + { + /* TODO: why don't we check return value? */ + my_hash_insert(&m_hashtable, (const byte *)sp); + } + + inline sp_head *lookup(char *name, uint namelen) + { + return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen); + } + +#ifdef NOT_USED + inline bool remove(char *name, uint namelen) + { + sp_head *sp= lookup(name, namelen); + if (sp) + { + hash_delete(&m_hashtable, (byte *)sp); + return TRUE; + } + return FALSE; + } +#endif + + inline void remove_all() + { + cleanup(); + init(); + } + +private: + void init(); + void cleanup(); + + /* All routines in this cache */ + HASH m_hashtable; +}; // class sp_cache + + +/* Initialize the SP caching once at startup */ + +void sp_cache_init() { pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST); } -void -sp_cache_clear(sp_cache **cp) + +/* + Clear the cache *cp and set *cp to NULL. + SYNOPSIS + sp_cache_clear() + cp Pointer to cache to clear + NOTE + This function doesn't invalidate other caches. +*/ + +void sp_cache_clear(sp_cache **cp) { sp_cache *c= *cp; - if (c) { delete c; @@ -42,86 +103,122 @@ sp_cache_clear(sp_cache **cp) } } -void -sp_cache_insert(sp_cache **cp, sp_head *sp) + +/* + Insert a routine into the cache. + + SYNOPSIS + sp_cache_insert() + cp The cache to put routine into + sp Routine to insert. + + TODO: Perhaps it will be more straightforward if in case we returned an + error from this function when we couldn't allocate sp_cache. (right + now failure to put routine into cache will cause a 'SP not found' + error to be reported at some later time) +*/ + +void sp_cache_insert(sp_cache **cp, sp_head *sp) { sp_cache *c= *cp; - if (! c) - c= new sp_cache(); + if (!c && (c= new sp_cache())) + { + pthread_mutex_lock(&Cversion_lock); // LOCK + c->version= Cversion; + pthread_mutex_unlock(&Cversion_lock); // UNLOCK + } if (c) { - ulong v; - - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - if (*cp) - c->remove_all(); - c->version= v; - } + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + sp->m_qname.str)); c->insert(sp); if (*cp == NULL) *cp= c; } } -sp_head * -sp_cache_lookup(sp_cache **cp, sp_name *name) + +/* + Look up a routine in the cache. + SYNOPSIS + sp_cache_lookup() + cp Cache to look into + name Name of rutine to find + + NOTE + An obsolete (but not more obsolete then since last + sp_cache_flush_obsolete call) routine may be returned. + + RETURN + The routine or + NULL if the routine not found. +*/ + +sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) { - ulong v; sp_cache *c= *cp; - - if (! c) + if (!c) return NULL; - - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - c->remove_all(); - c->version= v; - return NULL; - } return c->lookup(name->m_qname.str, name->m_qname.length); } -bool -sp_cache_remove(sp_cache **cp, sp_name *name) -{ - sp_cache *c= *cp; - bool found= FALSE; - - if (c) - { - ulong v; - - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion++; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - c->remove_all(); - else - found= c->remove(name->m_qname.str, name->m_qname.length); - c->version= v+1; - } - return found; -} - -void -sp_cache_invalidate() + +/* + Invalidate all routines in all caches. + + SYNOPSIS + sp_cache_invalidate() + + NOTE + This is called when a VIEW definition is modifed. We can't destroy sp_head + objects here as one may modify VIEW definitions from prelocking-free SPs. +*/ + +void sp_cache_invalidate() { + DBUG_PRINT("info",("sp_cache: invalidating")); pthread_mutex_lock(&Cversion_lock); // LOCK Cversion++; pthread_mutex_unlock(&Cversion_lock); // UNLOCK } + +/* + Remove out-of-date SPs from the cache. + + SYNOPSIS + sp_cache_flush_obsolete() + cp Cache to flush + + NOTE + This invalidates pointers to sp_head objects this thread uses. + In practice that means 'dont call this function when inside SP'. +*/ + +void sp_cache_flush_obsolete(sp_cache **cp) +{ + sp_cache *c= *cp; + if (c) + { + ulong v; + pthread_mutex_lock(&Cversion_lock); // LOCK + v= Cversion; + pthread_mutex_unlock(&Cversion_lock); // UNLOCK + if (c->version < v) + { + DBUG_PRINT("info",("sp_cache: deleting all functions")); + /* We need to delete all elements. */ + c->remove_all(); + c->version= v; + } + } +} + +/************************************************************************* + Internal functions + *************************************************************************/ + static byte * hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) @@ -136,7 +233,6 @@ static void hash_free_sp_head(void *p) { sp_head *sp= (sp_head *)p; - delete sp; } diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 14b2db97f5f..1021d17b9e2 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -25,94 +25,39 @@ /* Stored procedures/functions cache. This is used as follows: * Each thread has its own cache. - * Each sp_head object is put into its thread cache before it is used, and + * Each sp_head object is put into its thread cache before it is used, and then remains in the cache until deleted. */ class sp_head; class sp_cache; -/* Initialize the SP caching once at startup */ -void sp_cache_init(); - -/* Clear the cache *cp and set *cp to NULL */ -void sp_cache_clear(sp_cache **cp); - -/* Insert an SP into cache. If 'cp' points to NULL, it's set to a new cache */ -void sp_cache_insert(sp_cache **cp, sp_head *sp); - -/* Lookup an SP in cache */ -sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); - -/* - Remove an SP from cache, and also bump the Cversion number so all other - caches are invalidated. - Returns true if something was removed. -*/ -bool sp_cache_remove(sp_cache **cp, sp_name *name); - -/* Invalidate all existing SP caches by bumping Cversion number. */ -void sp_cache_invalidate(); - - /* - * - * The cache class. Don't use this directly, use the C API above - * - */ + Cache usage scenarios: + 1. Application-wide init: + sp_cache_init(); -class sp_cache -{ -public: + 2. SP execution in thread: + 2.1 While holding sp_head* pointers: + + // look up a routine in the cache (no checks if it is up to date or not) + sp_cache_lookup(); + + sp_cache_insert(); + sp_cache_invalidate(); + + 2.2 When not holding any sp_head* pointers: + sp_cache_flush_obsolete(); + + 3. Before thread exit: + sp_cache_clear(); +*/ - ulong version; - - sp_cache(); - - ~sp_cache(); - - void - init(); - - void - cleanup(); - - inline void - insert(sp_head *sp) - { - my_hash_insert(&m_hashtable, (const byte *)sp); - } - - inline sp_head * - lookup(char *name, uint namelen) - { - return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen); - } - - inline bool - remove(char *name, uint namelen) - { - sp_head *sp= lookup(name, namelen); - - if (sp) - { - hash_delete(&m_hashtable, (byte *)sp); - return TRUE; - } - return FALSE; - } - - inline void - remove_all() - { - cleanup(); - init(); - } - -private: - - HASH m_hashtable; - -}; // class sp_cache +void sp_cache_init(); +void sp_cache_clear(sp_cache **cp); +void sp_cache_insert(sp_cache **cp, sp_head *sp); +sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); +void sp_cache_invalidate(); +void sp_cache_flush_obsolete(sp_cache **cp); #endif /* _SP_CACHE_H_ */ diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 15d4f699bc9..0f4fdd52583 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -762,7 +762,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) TABLE_COUNTER_TYPE local_tables; ulong tot_length; DBUG_ENTER("Query_cache::store_query"); - if (query_cache_size == 0) + if (query_cache_size == 0 || thd->locked_tables) DBUG_VOID_RETURN; uint8 tables_type= 0; @@ -936,8 +936,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Query_cache_query_flags flags; DBUG_ENTER("Query_cache::send_result_to_client"); - if (query_cache_size == 0 || thd->variables.query_cache_type == 0) - + if (query_cache_size == 0 || thd->locked_tables || + thd->variables.query_cache_type == 0) goto err; /* Check that we haven't forgot to reset the query cache variables */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 3900b25626f..5d3361d6c51 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1565,6 +1565,7 @@ public: statement/stored procedure. */ virtual void cleanup(); + void set_thd(THD *thd_arg) { thd= thd_arg; } }; @@ -1920,14 +1921,13 @@ class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; - THD *thd; ha_rows deleted, found; uint num_of_tables; int error; bool do_delete, transactional_tables, normal_tables, delete_while_scanning; public: - multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); + multi_delete(TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &items); @@ -1943,7 +1943,6 @@ class multi_update :public select_result_interceptor TABLE_LIST *all_tables; /* query/update command tables */ TABLE_LIST *leaves; /* list of leves of join table tree */ TABLE_LIST *update_tables, *table_being_updated; - THD *thd; TABLE **tmp_tables, *main_table, *table_to_update; TMP_TABLE_PARAM *tmp_table_param; ha_rows updated, found; @@ -1955,7 +1954,7 @@ class multi_update :public select_result_interceptor bool do_update, trans_safe, transactional_tables, ignore; public: - multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list, + multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list, List *fields, List *values, enum_duplicates handle_duplicates, bool ignore); ~multi_update(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d83937098e2..b6183bf5acb 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -407,9 +407,8 @@ bool mysql_multi_delete_prepare(THD *thd) } -multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, - uint num_of_tables_arg) - : delete_tables(dt), thd(thd_arg), deleted(0), found(0), +multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) + : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), do_delete(0), transactional_tables(0), normal_tables(0) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 27342287fcd..f9923283911 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -808,11 +808,11 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, table_list->next_local= 0; select_lex->context.resolve_in_table_list_only(table_list); - if ((values && check_insert_fields(thd, table_list, fields, *values, - !insert_into_view)) || - (values && setup_fields(thd, 0, *values, 0, 0, 0))) - res= TRUE; - else if (duplic == DUP_UPDATE) + if (values && + !(res= check_insert_fields(thd, table_list, fields, *values, + !insert_into_view) || + setup_fields(thd, 0, *values, 0, 0, 0)) && + duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; res= check_update_fields(thd, table_list, update_fields); @@ -2089,7 +2089,26 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) */ lex->current_select= &lex->select_lex; res= check_insert_fields(thd, table_list, *fields, values, - !insert_into_view); + !insert_into_view) || + setup_fields(thd, 0, values, 0, 0, 0); + if (info.handle_duplicates == DUP_UPDATE) + { + TABLE_LIST *save_next_local= table_list->next_local; + table_list->next_local= 0; + lex->select_lex.context.resolve_in_table_list_only(table_list); + lex->select_lex.no_wrap_view_item= TRUE; + res= res || check_update_fields(thd, table_list, *info.update_fields); + lex->select_lex.no_wrap_view_item= FALSE; + + /* + When we are not using GROUP BY we can refer to other tables in the + ON DUPLICATE KEY part + */ + if (!lex->select_lex.group_list.elements) + table_list->next_local= save_next_local; + res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0); + table_list->next_local= save_next_local; + } lex->current_select= lex_current_select_save; if (res) DBUG_RETURN(1); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4bba0c432c7..e8c65ba5100 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -458,6 +458,7 @@ public: inline bool is_prepared() { return prepared; } bool change_result(select_subselect *result, select_subselect *old_result); void set_limit(st_select_lex *values); + void set_thd(THD *thd_arg) { thd= thd_arg; } friend void lex_start(THD *thd, uchar *buf, uint length); friend int subselect_union_engine::exec(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bc5505bb790..fefe670432c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3318,7 +3318,7 @@ end_with_restore_list: if ((res= mysql_multi_delete_prepare(thd))) goto error; - if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, + if (!thd->is_fatal_error && (result= new multi_delete(aux_tables, lex->table_count))) { res= mysql_select(thd, &select_lex->ref_pointer_array, @@ -5311,10 +5311,12 @@ void create_select_for_variable(const char *var_name) We set the name of Item to @@session.var_name because that then is used as the column name in the output. */ - var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string); - end= strxmov(buff, "@@session.", var_name, NullS); - var->set_name(buff, end-buff, system_charset_info); - add_item_to_list(thd, var); + if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_string))) + { + end= strxmov(buff, "@@session.", var_name, NullS); + var->set_name(buff, end-buff, system_charset_info); + add_item_to_list(thd, var); + } DBUG_VOID_RETURN; } @@ -5340,11 +5342,12 @@ void mysql_init_multi_delete(LEX *lex) void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); - mysql_init_query(thd, (uchar*) inBuf, length); if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex= thd->lex; + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); if (!yyparse((void *)thd) && ! thd->is_fatal_error) { #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -6463,11 +6466,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, THR_LOCK_DATA **end_p= lock_p + thd->locked_tables->lock_count; for (; lock_p < end_p; lock_p++) + { if ((*lock_p)->type == TL_WRITE) { my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); return 1; } + } } /* Writing to the binlog could cause deadlocks, as we don't log diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c196bf76dda..8c3a61d39de 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -73,6 +73,7 @@ Long data handling: #include // for isspace() #include "sp_head.h" #include "sp.h" +#include "sp_cache.h" #ifdef EMBEDDED_LIBRARY /* include MYSQL_BIND headers */ #include @@ -1783,6 +1784,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, lex= thd->lex; lex->safe_to_cache_query= 0; + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); + error= yyparse((void *)thd) || thd->is_fatal_error || thd->net.report_error || init_param_array(stmt); /* @@ -1851,6 +1855,13 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) SELECT_LEX *sl= lex->all_selects_list; DBUG_ENTER("reinit_stmt_before_use"); + /* + We have to update "thd" pointer in LEX, all its units and in LEX::result, + since statements which belong to trigger body are associated with TABLE + object and because of this can be used in different threads. + */ + lex->thd= thd; + if (lex->empty_field_list_on_rset) { lex->empty_field_list_on_rset= 0; @@ -1889,6 +1900,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) unit->types.empty(); /* for derived tables & PS (which can't be reset by Item_subquery) */ unit->reinit_exec_mechanism(); + unit->set_thd(thd); } } @@ -1927,7 +1939,10 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) lex->select_lex.leaf_tables= lex->leaf_tables_insert; if (lex->result) + { lex->result->cleanup(); + lex->result->set_thd(thd); + } DBUG_VOID_RETURN; } @@ -2060,6 +2075,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) thd->protocol= stmt->protocol; // Switch to binary protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); mysql_execute_command(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index cdbe8a986b2..c2888bee4c6 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -289,6 +289,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, List_iterator_fast tp(types); Query_arena *arena= thd->current_arena; Item *type; + ulong create_options; while ((type= tp++)) { @@ -300,8 +301,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - ulong create_options= (first_select_in_union()->options | thd_arg->options | - TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; + create_options= (first_select_in_union()->options | thd_arg->options | + TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6deff6b0040..aa39140f9b1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -821,7 +821,7 @@ bool mysql_multi_update(THD *thd, if (mysql_multi_update_prepare(thd)) DBUG_RETURN(TRUE); - if (!(result= new multi_update(thd, table_list, + if (!(result= new multi_update(table_list, thd->lex->select_lex.leaf_tables, fields, values, handle_duplicates, ignore))) @@ -847,13 +847,13 @@ bool mysql_multi_update(THD *thd, } -multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, +multi_update::multi_update(TABLE_LIST *table_list, TABLE_LIST *leaves_list, List *field_list, List *value_list, enum enum_duplicates handle_duplicates_arg, bool ignore_arg) :all_tables(table_list), leaves(leaves_list), update_tables(0), - thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list), + tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), transactional_tables(1), ignore(ignore_arg) diff --git a/strings/Makefile.am b/strings/Makefile.am index ad652862222..c43cf0f290a 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -22,7 +22,7 @@ pkglib_LIBRARIES = libmystrings.a # Exact one of ASSEMBLER_X if ASSEMBLER_x86 ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s -CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c +CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c longlong2str_asm.c else if ASSEMBLER_sparc32 # These file MUST all be on the same line!! Otherwise automake @@ -45,7 +45,7 @@ EXTRA_DIST = ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \ ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \ xml.c decimal.c strto.c strings-x86.s \ - longlong2str.c longlong2str-x86.s \ + longlong2str.c longlong2str-x86.s longlong2str_asm.c \ my_strtoll10.c my_strtoll10-x86.s \ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \ diff --git a/strings/longlong2str-x86.s b/strings/longlong2str-x86.s index fcc57810224..1840bab3f47 100644 --- a/strings/longlong2str-x86.s +++ b/strings/longlong2str-x86.s @@ -16,26 +16,26 @@ # Optimized longlong2str function for Intel 80x86 (gcc/gas syntax) # Some set sequences are optimized for pentuimpro II - .file "longlong2str.s" - .version "1.01" + .file "longlong2str-x86.s" + .version "1.02" .text .align 4 -.globl longlong2str - .type longlong2str,@function +.globl longlong2str_with_dig_vector + .type longlong2str_with_dig_vector,@function -longlong2str: +longlong2str_with_dig_vector: subl $80,%esp pushl %ebp pushl %esi pushl %edi pushl %ebx movl 100(%esp),%esi # Lower part of val - movl 104(%esp),%ebp # Higher part of val - movl 108(%esp),%edi # get dst movl 112(%esp),%ebx # Radix + movl 104(%esp),%ebp # Higher part of val movl %ebx,%eax + movl 108(%esp),%edi # get dst testl %eax,%eax jge .L144 @@ -69,6 +69,8 @@ longlong2str: .L150: leal 92(%esp),%ecx # End of buffer + movl %edi, 108(%esp) # Store possible modified dest + movl 116(%esp), %edi # dig_vec_upper jmp .L155 .align 4 @@ -83,7 +85,7 @@ longlong2str: divl %ebx decl %ecx movl %eax,%esi # quotent in ebp:esi - movb _dig_vec_upper(%edx),%al # al is faster than dl + movb (%edx,%edi),%al # al is faster than dl movb %al,(%ecx) # store value in buff .align 4 .L155: @@ -91,20 +93,22 @@ longlong2str: ja .L153 testl %esi,%esi # rest value jl .L153 - je .L10_mov # Ready + je .L160 # Ready movl %esi,%eax - movl $_dig_vec_upper,%ebp .align 4 .L154: # Do rest with integer precision cltd divl %ebx decl %ecx - movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36 + movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36 testl %eax,%eax movb %dl,(%ecx) jne .L154 +.L160: + movl 108(%esp),%edi # get dst + .L10_mov: movl %ecx,%esi leal 92(%esp),%ecx # End of buffer @@ -129,7 +133,7 @@ longlong2str: jmp .L165 .Lfe3: - .size longlong2str,.Lfe3-longlong2str + .size longlong2str_with_dig_vector,.Lfe3-longlong2str_with_dig_vector # # This is almost equal to the above, except that we can do the final @@ -137,9 +141,6 @@ longlong2str: # .align 4 -.Ltmp: - .long 0xcccccccd - .align 4 .globl longlong10_to_str .type longlong10_to_str,@function @@ -202,8 +203,8 @@ longlong10_to_str: # The following code uses some tricks to change division by 10 to # multiplication and shifts - movl .Ltmp,%esi # set %esi to 0xcccccccd - + movl $0xcccccccd,%esi + .L10_40: movl %ebx,%eax mull %esi diff --git a/strings/longlong2str_asm.c b/strings/longlong2str_asm.c new file mode 100644 index 00000000000..e38a8328b91 --- /dev/null +++ b/strings/longlong2str_asm.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Wrapper for longlong2str.s + + We need this because the assembler code can't access the local variable + _dig_vector in a portable manner. +*/ + +#include +#include "m_string.h" + +extern char *longlong2str_with_dig_vector(longlong val,char *dst,int radix, + const char *dig_vector); + +char *longlong2str(longlong val,char *dst,int radix) +{ + return longlong2str_with_dig_vector(val, dst, radix, _dig_vec_upper); +} diff --git a/strings/my_strtoll10-x86.s b/strings/my_strtoll10-x86.s index c04384667a7..1d8b8f2bbce 100644 --- a/strings/my_strtoll10-x86.s +++ b/strings/my_strtoll10-x86.s @@ -17,21 +17,8 @@ # For documentation, check my_strtoll.c .file "my_strtoll10-x86.s" - .version "01.01" -.data - .align 32 - .type lfactor,@object - .size lfactor,36 -lfactor: - .long 1 - .long 10 - .long 100 - .long 1000 - .long 10000 - .long 100000 - .long 1000000 - .long 10000000 - .long 100000000 + .version "01.02" + .text .align 4 @@ -209,14 +196,16 @@ my_strtoll10: jne .L500 cmpl -36(%ebp),%esi # Test if string is less than 18 digits jne .Lend_i_and_j - jmp .Lend3 # 18 digit string +.L499: + movl $1000000000,%eax + jmp .Lgot_factor # 18 digit string # Handle the possible next to last digit and store in ecx .L500: movb (%esi),%al addb $-48,%al cmpb $9,%al - ja .Lend3 + ja .L499 # 18 digit string incl %esi movzbl %al,%ecx @@ -315,14 +304,41 @@ my_strtoll10: .Lend_i_and_j: movl %esi,%ecx subl -12(%ebp),%ecx # ecx= number of digits in second part - movl lfactor(,%ecx,4),%eax - jmp .L523 - # Return -8(%ebp) * $1000000000 + edi + # Calculate %eax= 10 ** %cl, where %cl <= 8 + # With an array one could do this with: + # movl 10_factor_table(,%ecx,4),%eax + # We calculate the table here to avoid problems in + # position independent code (gcc -pic) + + cmpb $3,%cl + ja .L4_to_8 + movl $1000, %eax + je .Lgot_factor # %cl=3, eax= 1000 + movl $10, %eax + cmpb $1,%cl # %cl is here 0 - 2 + je .Lgot_factor # %cl=1, eax= 10 + movl $100, %eax + ja .Lgot_factor # %cl=2, eax=100 + movl $1, %eax + jmp .Lgot_factor # %cl=0, eax=1 + +.L4_to_8: # %cl is here 4-8 + cmpb $5,%cl + movl $100000, %eax + je .Lgot_factor # %cl=5, eax=100000 + movl $10000, %eax + jbe .Lgot_factor # %cl=4, eax=10000 + movl $10000000, %eax + cmpb $7,%cl + je .Lgot_factor # %cl=7, eax=10000000 + movl $100000000, %eax + ja .Lgot_factor # %cl=8, eax=100000000 + movl $1000000, %eax # %cl=6, eax=1000000 + + # Return -8(%ebp) * %eax + edi .p2align 4,,7 -.Lend3: - movl $1000000000,%eax -.L523: +.Lgot_factor: mull -8(%ebp) addl %edi,%eax adcl $0,%edx diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 75f57436c38..75b41ebe4d1 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7195,7 +7195,7 @@ static void test_prepare_grant() } } -#endif +#endif /* EMBEDDED_LIBRARY */ /* Test a crash when invalid/corrupted .frm is used in the