diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 2074abd0f85..f622b2d2fb2 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1869,6 +1869,16 @@ static void net_clear_error(NET *net) } } +static void stmt_clear_error(MYSQL_STMT *stmt) +{ + if (stmt->last_errno) + { + stmt->last_errno= 0; + stmt->last_error[0]= '\0'; + strmov(stmt->sqlstate, not_error_sqlstate); + } +} + /* Set statement error code, sqlstate, and error message from given errcode and sqlstate. @@ -4907,13 +4917,12 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) { MYSQL *mysql= stmt->mysql; MYSQL_DATA *result= &stmt->result; - my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor; /* Reset stored result set if so was requested or it's a part of cursor fetch. */ - if (result->data && (has_cursor || (flags & RESET_STORE_RESULT))) + if (result->data && (flags & RESET_STORE_RESULT)) { /* Result buffered */ free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); @@ -4944,7 +4953,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) mysql->status= MYSQL_STATUS_READY; } } - if (has_cursor || (flags & RESET_SERVER_SIDE)) + if (flags & RESET_SERVER_SIDE) { /* Reset the server side statement and close the server side @@ -4960,6 +4969,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) stmt->state= MYSQL_STMT_INIT_DONE; return 1; } + stmt_clear_error(stmt); } } stmt->state= MYSQL_STMT_PREPARE_DONE; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index de2e96acd2e..66db34bdf83 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -905,6 +905,10 @@ select * from t1 where city = 'Durban '; id city 2 Durban drop table t1; +create table t1 (x set('A', 'B') default 0) character set utf8; +ERROR 42000: Invalid default value for 'x' +create table t1 (x enum('A', 'B') default 0) character set utf8; +ERROR 42000: Invalid default value for 'x' SET NAMES UTF8; CREATE TABLE t1 ( `id` int(20) NOT NULL auto_increment, diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result index dc51454f1d5..3b52be4b1f2 100644 --- a/mysql-test/r/fulltext_order_by.result +++ b/mysql-test/r/fulltext_order_by.result @@ -86,3 +86,77 @@ a rel 1 1 2 2 drop table t1; +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +thread int(11) NOT NULL default '0', +beitrag longtext NOT NULL, +PRIMARY KEY (id), +KEY thread (thread), +FULLTEXT KEY beitrag (beitrag) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7923 ; +CREATE TABLE t2 ( +id int(11) NOT NULL auto_increment, +text varchar(100) NOT NULL default '', +PRIMARY KEY (id), +KEY text (text) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=63 ; +CREATE TABLE t3 ( +id int(11) NOT NULL auto_increment, +forum int(11) NOT NULL default '0', +betreff varchar(70) NOT NULL default '', +PRIMARY KEY (id), +KEY forum (forum), +FULLTEXT KEY betreff (betreff) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ; +select a.text, b.id, b.betreff +from +t2 a inner join t3 b on a.id = b.forum inner join +t1 c on b.id = c.thread +where +match(b.betreff) against ('+abc' in boolean mode) +group by a.text, b.id, b.betreff +union +select a.text, b.id, b.betreff +from +t2 a inner join t3 b on a.id = b.forum inner join +t1 c on b.id = c.thread +where +match(c.beitrag) against ('+abc' in boolean mode) +group by +a.text, b.id, b.betreff +order by +match(b.betreff) against ('+abc' in boolean mode) desc; +ERROR 42S02: Unknown table 'b' in order clause +select a.text, b.id, b.betreff +from +t2 a inner join t3 b on a.id = b.forum inner join +t1 c on b.id = c.thread +where +match(b.betreff) against ('+abc' in boolean mode) +union +select a.text, b.id, b.betreff +from +t2 a inner join t3 b on a.id = b.forum inner join +t1 c on b.id = c.thread +where +match(c.beitrag) against ('+abc' in boolean mode) +order by +match(b.betreff) against ('+abc' in boolean mode) desc; +ERROR 42S02: Unknown table 'b' in order clause +select a.text, b.id, b.betreff +from +t2 a inner join t3 b on a.id = b.forum inner join +t1 c on b.id = c.thread +where +match(b.betreff) against ('+abc' in boolean mode) +union +select a.text, b.id, b.betreff +from +t2 a inner join t3 b on a.id = b.forum inner join +t1 c on b.id = c.thread +where +match(c.beitrag) against ('+abc' in boolean mode) +order by +match(betreff) against ('+abc' in boolean mode) desc; +ERROR HY000: The used table type doesn't support FULLTEXT indexes +drop table t1,t2,t3; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index aab4eb696d2..2c73cbeeea4 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -2466,3 +2466,12 @@ select * from t1; a val 2 1 drop table t1; +CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; +INSERT INTO t1 (GRADE) VALUES (151),(252),(343); +SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; +GRADE +252 +SELECT GRADE FROM t1 WHERE GRADE= 151; +GRADE +151 +DROP TABLE t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index bd06be07a8e..1896db84de0 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -681,3 +681,116 @@ execute stmt; execute stmt; deallocate prepare stmt; drop table t1; +create table t1 ( +id int(11) unsigned not null primary key auto_increment, +partner_id varchar(35) not null, +t1_status_id int(10) unsigned +); +insert into t1 values ("1", "partner1", "10"), ("2", "partner2", "10"), +("3", "partner3", "10"), ("4", "partner4", "10"); +create table t2 ( +id int(11) unsigned not null default '0', +t1_line_id int(11) unsigned not null default '0', +article_id varchar(20), +sequence int(11) not null default '0', +primary key (id,t1_line_id) +); +insert into t2 values ("1", "1", "sup", "0"), ("2", "1", "sup", "1"), +("2", "2", "sup", "2"), ("2", "3", "sup", "3"), +("2", "4", "imp", "4"), ("3", "1", "sup", "0"), +("4", "1", "sup", "0"); +create table t3 ( +id int(11) not null default '0', +preceeding_id int(11) not null default '0', +primary key (id,preceeding_id) +); +create table t4 ( +user_id varchar(50) not null, +article_id varchar(20) not null, +primary key (user_id,article_id) +); +insert into t4 values("nicke", "imp"); +prepare stmt from +'select distinct t1.partner_id +from t1 left join t3 on t1.id = t3.id + left join t1 pp on pp.id = t3.preceeding_id +where + exists ( + select * + from t2 as pl_inner + where pl_inner.id = t1.id + and pl_inner.sequence <= ( + select min(sequence) from t2 pl_seqnr + where pl_seqnr.id = t1.id + ) + and exists ( + select * from t4 + where t4.article_id = pl_inner.article_id + and t4.user_id = ? + ) + ) + and t1.id = ? +group by t1.id +having count(pp.id) = 0'; +set @user_id = 'nicke'; +set @id = '2'; +execute stmt using @user_id, @id; +partner_id +execute stmt using @user_id, @id; +partner_id +deallocate prepare stmt; +drop table t1, t2, t3, t4; +prepare stmt from 'select ?=?'; +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +?=? +1 +execute stmt using @a, @b; +?=? +1 +set @a=1, @b=2; +execute stmt using @a, @b; +?=? +0 +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +?=? +1 +deallocate prepare stmt; +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +utext +lily +river +execute stmt using @param1; +utext +lily +river +select utext from t1 where utext like '%%'; +utext +lily +river +drop table t1; +deallocate prepare stmt; +create table t1 (a int); +prepare stmt from "select ??"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1 +prepare stmt from "select ?FROM t1"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?FROM t1' at line 1 +prepare stmt from "select FROM t1 WHERE?=1"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FROM t1 WHERE?=1' at line 1 +prepare stmt from "update t1 set a=a+?WHERE 1"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?WHERE 1' at line 1 +select ?; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1 +select ??; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '??' at line 1 +select ? from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1 +drop table t1; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index a9342636349..64dc09f864c 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 -def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 -def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 +def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63 +def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -1810,17 +1810,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -1828,8 +1828,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 3a470d218d1..792d74231f2 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 -def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 -def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 +def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63 +def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -1793,17 +1793,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -1811,8 +1811,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index beeaff05ece..7dcb8546a83 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1794,17 +1794,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -1812,8 +1812,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index fada983a561..77b1a242452 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -120,8 +120,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 -def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 -def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 +def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63 +def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -1730,17 +1730,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -1748,8 +1748,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 @@ -3132,8 +3132,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 -def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 -def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 +def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63 +def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -4742,17 +4742,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -4760,8 +4760,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index 404c25c2c37..0489c7ef078 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 -def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 -def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 +def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63 +def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -1793,17 +1793,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -1811,8 +1811,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index ffddec6d5c2..b0049b3e943 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -77,8 +77,8 @@ def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 -def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 -def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 +def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63 +def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -1793,17 +1793,17 @@ def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 -def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 +def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8 def test t5 t5 const05 const05 253 3 3 N 129 0 63 -def test t5 t5 param05 param05 252 16777215 3 Y 144 0 63 +def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63 def test t5 t5 const06 const06 253 10 10 N 1 0 8 -def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8 +def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8 def test t5 t5 const07 const07 10 10 10 Y 128 0 63 -def test t5 t5 param07 param07 252 16777215 10 Y 144 0 63 +def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63 def test t5 t5 const08 const08 253 19 19 N 1 0 8 -def test t5 t5 param08 param08 252 16777215 19 Y 16 0 8 +def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8 def test t5 t5 const09 const09 12 19 19 Y 128 0 63 -def test t5 t5 param09 param09 252 16777215 19 Y 144 0 63 +def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63 def test t5 t5 const10 const10 3 10 9 N 32769 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 @@ -1811,8 +1811,8 @@ def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param13 param13 246 67 0 Y 0 30 63 -def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 -def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 +def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8 +def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63 const01 8 param01 8 const02 8.0 diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d02c28a0a97..d0503d1b83b 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2711,3 +2711,38 @@ DROP TABLE t1,t2; select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0 16 16 2 2 +CREATE TABLE t1 ( +acct_id int(11) NOT NULL default '0', +profile_id smallint(6) default NULL, +UNIQUE KEY t1$acct_id (acct_id), +KEY t1$profile_id (profile_id) +); +INSERT INTO t1 VALUES (132,17),(133,18); +CREATE TABLE t2 ( +profile_id smallint(6) default NULL, +queue_id int(11) default NULL, +seq int(11) default NULL, +KEY t2$queue_id (queue_id) +); +INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); +CREATE TABLE t3 ( +id int(11) NOT NULL default '0', +qtype int(11) default NULL, +seq int(11) default NULL, +warn_lvl int(11) default NULL, +crit_lvl int(11) default NULL, +rr1 tinyint(4) NOT NULL default '0', +rr2 int(11) default NULL, +default_queue tinyint(4) NOT NULL default '0', +KEY t3$qtype (qtype), +KEY t3$id (id) +); +INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), +(36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); +SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q +WHERE +(pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND +(pq.queue_id = q.id) AND (q.rr1 <> 1); +COUNT(*) +4 +drop table t1,t2,t3; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 18acd2e4c03..13f46e507ba 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -286,6 +286,19 @@ ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable call p(42, @tmp_y, 43)| ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable drop procedure p| +create procedure p() begin end| +lock table t1 read| +call p()| +unlock tables| +drop procedure p| +lock tables t1 read, mysql.proc write| +ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables +lock tables mysql.proc write, mysql.user write| +ERROR HY000: You can't combine write-locking of system 'mysql.proc' table with other tables +lock tables t1 read, mysql.proc read| +unlock tables| +lock tables mysql.proc write| +unlock tables| create procedure bug1965() begin declare c cursor for select val from t1 order by valname; @@ -477,7 +490,7 @@ begin select * from t1; end| lock table t1 read| -call bug9566()| +alter procedure bug9566 comment 'Some comment'| ERROR HY000: Table 'proc' was not locked with LOCK TABLES unlock tables| drop procedure bug9566| diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result index a9d50e6e697..e6b8128c336 100644 --- a/mysql-test/r/sp-threads.result +++ b/mysql-test/r/sp-threads.result @@ -55,3 +55,12 @@ call bug11158(); unlock tables; drop procedure bug11158; drop table t1, t2; +drop function if exists bug11554; +drop view if exists v1; +create table t1 (i int); +create function bug11554 () returns int return 1; +create view v1 as select bug11554() as f; +insert into t1 (select f from v1); +drop function bug11554; +drop table t1; +drop view v1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 746c900d743..efd09ba08fc 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -232,9 +232,6 @@ if new.id > f1() then set new.id:= f1(); end if; end| -select f1(); -f1() -10 insert into t1 values (1, "first"); insert into t1 values (f1(), "max"); select * from t1; @@ -300,7 +297,7 @@ drop trigger t1.trg; ERROR HY000: Trigger does not exist create view v1 as select * from t1; create trigger trg before insert on v1 for each row set @a:=1; -ERROR HY000: Trigger's 'v1' is view or temporary table +ERROR HY000: 'test.v1' is not BASE TABLE drop view v1; drop table t1; create temporary table t1 (i int); @@ -573,3 +570,13 @@ i k ts 1 1 0000-00-00 00:00:00 2 2 0000-00-00 00:00:00 drop table t1, t2; +drop function if exists bug5893; +create table t1 (col1 int, col2 int); +insert into t1 values (1, 2); +create function bug5893 () returns int return 5; +create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); +drop function bug5893; +update t1 set col2 = 4; +ERROR 42000: FUNCTION test.bug5893 does not exist +drop trigger t1.t1_bu; +drop table t1; diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index aed2a478c0e..c1039189a43 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -876,15 +876,6 @@ SELECT * FROM t1; f1 f2 9999999999999999999999999999999999.00000000000000000000 0.00 DROP TABLE t1; -CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; -INSERT INTO t1 (GRADE) VALUES (151),(252),(343); -SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; -GRADE -252 -SELECT GRADE FROM t1 WHERE GRADE= 151; -GRADE -151 -DROP TABLE t1; select abs(10/0); abs(10/0) NULL diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 6bfc8513e23..bcb8ec2ba76 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -747,6 +747,15 @@ select * from t1 where city = 'Durban'; select * from t1 where city = 'Durban '; drop table t1; +# +# Bug #11819 CREATE TABLE with a SET DEFAULT 0 and UTF8 crashes server. +# +--error 1067 +create table t1 (x set('A', 'B') default 0) character set utf8; +--error 1067 +create table t1 (x enum('A', 'B') default 0) character set utf8; + + # # Test for bug #11167: join for utf8 varchar value longer than 255 bytes # @@ -776,12 +785,14 @@ INSERT INTO t1 VALUES (1,'blah','464','aaa','fkc1c9ilc20x0hgae7lx6j09','ERR','ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми','ИМРИ.АФИМИМ.АЕИМИМРИМДМРИМРМРИРОР',3,'2005-06-01 17:30:43','1234567890'), (2,'blah','464','aaa','haxpl2ilc20x00bj4tt2m5ti','11','11 g','G',3,'2005-06-02 22:43:10','1234567890'); +--disable_warnings CREATE TABLE t2 ( `msisdn` varchar(15) NOT NULL default '', `operator_id` int(11) NOT NULL default '0', `created` datetime NOT NULL default '0000-00-00 00:00:00', UNIQUE KEY `PK_user` (`msisdn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +--enable_warnings INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25'); diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 5c1b4127d8c..3101242613a 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -54,3 +54,86 @@ SELECT a, MATCH (message) AGAINST ('t* f*' IN BOOLEAN MODE) as rel FROM t1; SELECT a, MATCH (message) AGAINST ('t* f*' IN BOOLEAN MODE) as rel FROM t1 ORDER BY rel,a; drop table t1; +# BUG#11869 +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + thread int(11) NOT NULL default '0', + beitrag longtext NOT NULL, + PRIMARY KEY (id), + KEY thread (thread), + FULLTEXT KEY beitrag (beitrag) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7923 ; + +CREATE TABLE t2 ( + id int(11) NOT NULL auto_increment, + text varchar(100) NOT NULL default '', + PRIMARY KEY (id), + KEY text (text) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=63 ; + +CREATE TABLE t3 ( + id int(11) NOT NULL auto_increment, + forum int(11) NOT NULL default '0', + betreff varchar(70) NOT NULL default '', + PRIMARY KEY (id), + KEY forum (forum), + FULLTEXT KEY betreff (betreff) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=996 ; + +--error 1109 +select a.text, b.id, b.betreff +from + t2 a inner join t3 b on a.id = b.forum inner join + t1 c on b.id = c.thread +where + match(b.betreff) against ('+abc' in boolean mode) +group by a.text, b.id, b.betreff +union +select a.text, b.id, b.betreff +from + t2 a inner join t3 b on a.id = b.forum inner join + t1 c on b.id = c.thread +where + match(c.beitrag) against ('+abc' in boolean mode) +group by + a.text, b.id, b.betreff +order by + match(b.betreff) against ('+abc' in boolean mode) desc; + +--error 1109 +select a.text, b.id, b.betreff +from + t2 a inner join t3 b on a.id = b.forum inner join + t1 c on b.id = c.thread +where + match(b.betreff) against ('+abc' in boolean mode) +union +select a.text, b.id, b.betreff +from + t2 a inner join t3 b on a.id = b.forum inner join + t1 c on b.id = c.thread +where + match(c.beitrag) against ('+abc' in boolean mode) +order by + match(b.betreff) against ('+abc' in boolean mode) desc; + +-- todo psergey: fix +--error 1214 +select a.text, b.id, b.betreff +from + t2 a inner join t3 b on a.id = b.forum inner join + t1 c on b.id = c.thread +where + match(b.betreff) against ('+abc' in boolean mode) +union +select a.text, b.id, b.betreff +from + t2 a inner join t3 b on a.id = b.forum inner join + t1 c on b.id = c.thread +where + match(c.beitrag) against ('+abc' in boolean mode) +order by + match(betreff) against ('+abc' in boolean mode) desc; + +drop table t1,t2,t3; + diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 485eeec05d9..2d0e2a4dd65 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1381,3 +1381,15 @@ update t1 set a=2 where a=1; insert into t1 (val) values (1); select * from t1; drop table t1; +# +# Bug #10465 +# + +--disable_warnings +CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; +--enable_warnings +INSERT INTO t1 (GRADE) VALUES (151),(252),(343); +SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; +SELECT GRADE FROM t1 WHERE GRADE= 151; +DROP TABLE t1; + diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 913b6c645af..fa5dd0680b5 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -705,3 +705,122 @@ execute stmt; execute stmt; deallocate prepare stmt; drop table t1; +# +# Bug#11458 "Prepared statement with subselects return random data": +# drop PARAM_TABLE_BIT from the list of tables used by a subquery +# +create table t1 ( + id int(11) unsigned not null primary key auto_increment, + partner_id varchar(35) not null, + t1_status_id int(10) unsigned +); + +insert into t1 values ("1", "partner1", "10"), ("2", "partner2", "10"), + ("3", "partner3", "10"), ("4", "partner4", "10"); + +create table t2 ( + id int(11) unsigned not null default '0', + t1_line_id int(11) unsigned not null default '0', + article_id varchar(20), + sequence int(11) not null default '0', + primary key (id,t1_line_id) +); + +insert into t2 values ("1", "1", "sup", "0"), ("2", "1", "sup", "1"), + ("2", "2", "sup", "2"), ("2", "3", "sup", "3"), + ("2", "4", "imp", "4"), ("3", "1", "sup", "0"), + ("4", "1", "sup", "0"); + +create table t3 ( + id int(11) not null default '0', + preceeding_id int(11) not null default '0', + primary key (id,preceeding_id) +); + +create table t4 ( + user_id varchar(50) not null, + article_id varchar(20) not null, + primary key (user_id,article_id) +); + +insert into t4 values("nicke", "imp"); + +prepare stmt from +'select distinct t1.partner_id +from t1 left join t3 on t1.id = t3.id + left join t1 pp on pp.id = t3.preceeding_id +where + exists ( + select * + from t2 as pl_inner + where pl_inner.id = t1.id + and pl_inner.sequence <= ( + select min(sequence) from t2 pl_seqnr + where pl_seqnr.id = t1.id + ) + and exists ( + select * from t4 + where t4.article_id = pl_inner.article_id + and t4.user_id = ? + ) + ) + and t1.id = ? +group by t1.id +having count(pp.id) = 0'; +set @user_id = 'nicke'; +set @id = '2'; +execute stmt using @user_id, @id; +execute stmt using @user_id, @id; +deallocate prepare stmt; +drop table t1, t2, t3, t4; +# +# Bug#9379: make sure that Item::collation is reset when one sets +# a parameter marker from a string variable. +# +prepare stmt from 'select ?=?'; +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +execute stmt using @a, @b; +set @a=1, @b=2; +execute stmt using @a, @b; +set @a='CHRISTINE '; +set @b='CHRISTINE'; +execute stmt using @a, @b; +deallocate prepare stmt; +# +# Bug#9442 Set parameter make query fail if column character set is UCS2 +# +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +execute stmt using @param1; +select utext from t1 where utext like '%%'; +drop table t1; +deallocate prepare stmt; +# +# Bug#11299 "prepared statement makes wrong SQL syntax in binlog which stops +# replication": check that errouneous queries with placeholders are not +# allowed +# +create table t1 (a int); +--error 1064 +prepare stmt from "select ??"; +--error 1064 +prepare stmt from "select ?FROM t1"; +--error 1064 +prepare stmt from "select FROM t1 WHERE?=1"; +--error 1064 +prepare stmt from "update t1 set a=a+?WHERE 1"; +--disable_ps_protocol +--error 1064 +select ?; +--error 1064 +select ??; +--error 1064 +select ? from t1; +--enable_ps_protocol +drop table t1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 2e4bb3e13ad..712658a19a6 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2290,3 +2290,43 @@ DROP TABLE t1,t2; # select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; +# Test for BUG#11700 +CREATE TABLE t1 ( + acct_id int(11) NOT NULL default '0', + profile_id smallint(6) default NULL, + UNIQUE KEY t1$acct_id (acct_id), + KEY t1$profile_id (profile_id) +); +INSERT INTO t1 VALUES (132,17),(133,18); + +CREATE TABLE t2 ( + profile_id smallint(6) default NULL, + queue_id int(11) default NULL, + seq int(11) default NULL, + KEY t2$queue_id (queue_id) +); +INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); + +CREATE TABLE t3 ( + id int(11) NOT NULL default '0', + qtype int(11) default NULL, + seq int(11) default NULL, + warn_lvl int(11) default NULL, + crit_lvl int(11) default NULL, + rr1 tinyint(4) NOT NULL default '0', + rr2 int(11) default NULL, + default_queue tinyint(4) NOT NULL default '0', + KEY t3$qtype (qtype), + KEY t3$id (id) +); + +INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), + (36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); + +SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q +WHERE + (pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND + (pq.queue_id = q.id) AND (q.rr1 <> 1); + +drop table t1,t2,t3; + diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 7750071c715..7f567449311 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -386,6 +386,29 @@ call p(42, @tmp_y, 43)| drop procedure p| +# +# Let us test that we can access mysql.proc table for routines +# definitions lookup without locking it explicitly. +# +create procedure p() begin end| +lock table t1 read| +# This should succeed +call p()| +unlock tables| +drop procedure p| +# Let us check restrictions which this ability puts on mysql.proc locking. +--error ER_WRONG_LOCK_OF_SYSTEM_TABLE +lock tables t1 read, mysql.proc write| +--error ER_WRONG_LOCK_OF_SYSTEM_TABLE +lock tables mysql.proc write, mysql.user write| +# Locking for read should be OK +lock tables t1 read, mysql.proc read| +unlock tables| +# You also should be able lock only mysql.proc for write +lock tables mysql.proc write| +unlock tables| + + # # BUG#1965 # @@ -676,9 +699,7 @@ create procedure bug6600() # BUG#9566: explicit LOCK TABLE and store procedures result in illegal state # # We should not think that mysql.proc table does not exist if we are unable -# to open it under LOCK TABLE or in prelocked mode. Probably this test -# should be removed when Monty will allow access to mysql.proc without -# locking it. +# to open it under LOCK TABLE or in prelocked mode. # --disable_warnings drop procedure if exists bug9566| @@ -688,9 +709,11 @@ begin select * from t1; end| lock table t1 read| -# This should fail because we forgot to lock mysql.proc table explicitly +# This should fail since we forgot to lock mysql.proc for writing +# explicitly, and we can't open mysql.proc for _writing_ if there +# are locked tables. --error 1100 -call bug9566()| +alter procedure bug9566 comment 'Some comment'| unlock tables| # This should succeed drop procedure bug9566| diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test index 8fec5d14bc1..4c192f3e96f 100644 --- a/mysql-test/t/sp-threads.test +++ b/mysql-test/t/sp-threads.test @@ -111,6 +111,25 @@ connection con1root; drop procedure bug11158; drop table t1, t2; +# +# BUG#11554: Server crashes on statement indirectly using non-cached function +# +--disable_warnings +drop function if exists bug11554; +drop view if exists v1; +--enable_warnings +create table t1 (i int); +create function bug11554 () returns int return 1; +create view v1 as select bug11554() as f; +connection con2root; +# This should not crash server +insert into t1 (select f from v1); +# Clean-up +connection con1root; +drop function bug11554; +drop table t1; +drop view v1; + # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 229cbd3c79c..8a27636ed84 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -244,8 +244,6 @@ begin end if; end| delimiter ;| -# Remove this once bug #11554 will be fixed. -select f1(); insert into t1 values (1, "first"); insert into t1 values (f1(), "max"); select * from t1; @@ -319,7 +317,7 @@ drop trigger t1.trg; drop trigger t1.trg; create view v1 as select * from t1; ---error 1361 +--error 1347 create trigger trg before insert on v1 for each row set @a:=1; drop view v1; @@ -578,15 +576,18 @@ drop table t1, t2; # Test for bug #5893 "Triggers with dropped functions cause crashes" # Appropriate error should be reported instead of crash. -# Had to disable this test until bug #11554 will be fixed. -#--disable_warnings -#drop function if exists bug5893; -#--enable_warnings -#create table t1 (col1 int, col2 int); -#insert into t1 values (1, 2); -#create function bug5893 () returns int return 5; -#create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); -#drop function bug5893; -#--error 1305 -#update t1 set col2 = 4; -#drop table t1; +# Also test for bug #11889 "Server crashes when dropping trigger +# using stored routine". +--disable_warnings +drop function if exists bug5893; +--enable_warnings +create table t1 (col1 int, col2 int); +insert into t1 values (1, 2); +create function bug5893 () returns int return 5; +create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); +drop function bug5893; +--error 1305 +update t1 set col2 = 4; +# This should not crash server too. +drop trigger t1.t1_bu; +drop table t1; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index f54c8d80f09..f295311fe4e 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -907,18 +907,6 @@ INSERT INTO t1 VALUES (9999999999999999999999999999999999, 0); SELECT * FROM t1; DROP TABLE t1; -# -# Bug #10465 -# - ---disable_warnings -CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; ---enable_warnings -INSERT INTO t1 (GRADE) VALUES (151),(252),(343); -SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; -SELECT GRADE FROM t1 WHERE GRADE= 151; -DROP TABLE t1; - # # Bug #10599: problem with NULL # diff --git a/mysys/my_os2cond.c b/mysys/my_os2cond.c index e23afb89e66..83a03d62046 100644 --- a/mysys/my_os2cond.c +++ b/mysys/my_os2cond.c @@ -100,7 +100,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, rc = DosWaitEventSem(cond->semaphore, timeout); if (rc != 0) - rval = ETIME; + rval= ETIMEDOUT; if (mutex) pthread_mutex_lock(mutex); diff --git a/sql/field.cc b/sql/field.cc index fef4195c46d..58844db2f38 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -47,6 +47,8 @@ uchar Field_null::null[1]={1}; const char field_separator=','; #define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320 +#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \ +((ulong) ((LL(1) << min(arg, 4) * 8) - LL(1))) /* Rules for merging different types of fields in UNION @@ -6697,7 +6699,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg,uint blob_pack_length, CHARSET_INFO *cs) - :Field_longstr(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L, + :Field_longstr(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length), null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, cs), packlength(blob_pack_length) diff --git a/sql/item.cc b/sql/item.cc index ff9d0496779..c04d7c346d1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -601,15 +601,43 @@ bool Item::eq(const Item *item, bool binary_cmp) const Item *Item::safe_charset_converter(CHARSET_INFO *tocs) { /* + Allow conversion from and to "binary". Don't allow automatic conversion to non-Unicode charsets, as it potentially loses data. */ - if (!(tocs->state & MY_CS_UNICODE)) + if (collation.collation != &my_charset_bin && + tocs != &my_charset_bin && + !(tocs->state & MY_CS_UNICODE)) return NULL; // safe conversion is not possible return new Item_func_conv_charset(this, tocs); } +/* + Created mostly for mysql_prepare_table(). Important + when a string ENUM/SET column is described with a numeric default value: + + CREATE TABLE t1(a SET('a') DEFAULT 1); + + We cannot use generic Item::safe_charset_converter(), because + the latter returns a non-fixed Item, so val_str() crashes afterwards. + Override Item_num method, to return a fixed item. +*/ +Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs) +{ + Item_string *conv; + char buf[64]; + String *s, tmp(buf, sizeof(buf), &my_charset_bin); + s= val_str(&tmp); + if ((conv= new Item_string(s->ptr(), s->length(), s->charset()))) + { + conv->str_value.copy(); + conv->str_value.mark_as_const(); + } + return conv; +} + + Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) { Item_string *conv; @@ -1701,6 +1729,7 @@ void Item_param::set_null() max_length= 0; decimals= 0; state= NULL_VALUE; + item_type= Item::NULL_ITEM; DBUG_VOID_RETURN; } @@ -1941,6 +1970,7 @@ void Item_param::reset() to the binary log. */ str_value.set_charset(&my_charset_bin); + collation.set(&my_charset_bin, DERIVATION_COERCIBLE); state= NO_VALUE; maybe_null= 1; null_value= 0; @@ -2242,37 +2272,12 @@ bool Item_param::convert_str_value(THD *thd) */ str_value_ptr.set(str_value.ptr(), str_value.length(), str_value.charset()); + /* Synchronize item charset with value charset */ + collation.set(str_value.charset(), DERIVATION_COERCIBLE); } return rc; } -bool Item_param::fix_fields(THD *thd, Item **ref) -{ - DBUG_ASSERT(fixed == 0); - SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select; - - /* - Parameters in a subselect should mark the subselect as not constant - during prepare - */ - if (state == NO_VALUE) - { - /* - SELECT_LEX_UNIT::item set only for subqueries, so test of it presence - can be barrier to stop before derived table SELECT or very outer SELECT - */ - for (; cursel->master_unit()->item; - cursel= cursel->outer_select()) - { - Item_subselect *subselect_item= cursel->master_unit()->item; - subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; - subselect_item->const_item_cache= 0; - } - } - fixed= 1; - return 0; -} - bool Item_param::basic_const_item() const { @@ -3782,6 +3787,20 @@ bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const return FALSE; } + +Item *Item_hex_string::safe_charset_converter(CHARSET_INFO *tocs) +{ + Item_string *conv; + String tmp, *str= val_str(&tmp); + + if (!(conv= new Item_string(str->ptr(), str->length(), tocs))) + return NULL; + conv->str_value.copy(); + conv->str_value.mark_as_const(); + return conv; +} + + /* bin item. In string context this is a binary string. diff --git a/sql/item.h b/sql/item.h index 8a694a467ae..a10934e40fb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -771,6 +771,7 @@ class Item_num: public Item { public: virtual Item_num *neg()= 0; + Item *safe_charset_converter(CHARSET_INFO *tocs); }; #define NO_CACHED_FIELD_INDEX ((uint)(-1)) @@ -1039,7 +1040,6 @@ public: bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); int save_in_field(Field *field, bool no_conversions); - bool fix_fields(THD *, Item **); void set_null(); void set_int(longlong i, uint32 max_length_arg); @@ -1370,6 +1370,7 @@ public: // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} bool eq(const Item *item, bool binary_cmp) const; + virtual Item *safe_charset_converter(CHARSET_INFO *tocs); }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 7576bca6701..0817282b673 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -192,11 +192,24 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, } if ((*arg)->type() == FIELD_ITEM) ((Item_field *)(*arg))->no_const_subst= 1; + /* + If in statement prepare, then we create a converter for two + constant items, do it once and then reuse it. + If we're in execution of a prepared statement, arena is NULL, + and the conv was created in runtime memory. This can be + the case only if the argument is a parameter marker ('?'), + because for all true constants the charset converter has already + been created in prepare. In this case register the change for + rollback. + */ + if (arena) + *arg= conv; + else + thd->change_item_tree(arg, conv); /* We do not check conv->fixed, because Item_func_conv_charset which can be return by safe_charset_converter can't be fixed at creation */ - *arg= conv; conv->fix_fields(thd, arg); } if (arena) @@ -3144,7 +3157,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) THD* thd=current_thd; User_level_lock* ull; struct timespec abstime; - int lock_name_len,error=0; + int lock_name_len; lock_name_len=strlen(lock_name); pthread_mutex_lock(&LOCK_user_locks); @@ -3178,8 +3191,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout) set_timespec(abstime,lock_timeout); while (!thd->killed && - (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime)) - != ETIME && error != ETIMEDOUT && ull->locked) ; + pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, + &abstime) != ETIMEDOUT && ull->locked) ; if (ull->locked) { if (!--ull->count) @@ -3281,14 +3294,14 @@ longlong Item_func_get_lock::val_int() set_timespec(abstime,timeout); while (!thd->killed && (error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime)) - != ETIME && error != ETIMEDOUT && error != EINVAL && ull->locked) ; + != ETIMEDOUT && error != EINVAL && ull->locked) ; if (thd->killed) error=EINTR; // Return NULL if (ull->locked) { if (!--ull->count) delete ull; // Should never happen - if (error != ETIME && error != ETIMEDOUT) + if (error != ETIMEDOUT) { error=1; null_value=1; // Return NULL @@ -4382,6 +4395,9 @@ bool Item_func_match::fix_index() if (key == NO_SUCH_KEY) return 0; + + if (!table) + goto err; for (keynr=0 ; keynr < table->s->keys ; keynr++) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index e05db4a00cc..0b5736169fa 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -121,7 +121,6 @@ public: friend class Item_in_optimizer; friend bool Item_field::fix_fields(THD *, Item **); friend bool Item_ref::fix_fields(THD *, Item **); - friend bool Item_param::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, Field*, Item*, Item_ident*); diff --git a/sql/lock.cc b/sql/lock.cc index 01bc2fc303f..a666c6da17a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -424,6 +424,19 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, tables+=table_ptr[i]->file->lock_count(); lock_count++; } + /* + To be able to open and lock for reading system tables like 'mysql.proc', + when we already have some tables opened and locked, and avoid deadlocks + we have to disallow write-locking of these tables with any other tables. + */ + if (table_ptr[i]->s->system_table && + table_ptr[i]->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE && + count != 1) + { + my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table_ptr[i]->s->db, + table_ptr[i]->s->table_name); + return 0; + } } if (!(sql_lock= (MYSQL_LOCK*) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9e4f9b5aef1..83f2903c8fc 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -735,7 +735,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem, - bool *refresh); + bool *refresh, uint flags); TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table); TABLE *find_locked_table(THD *thd, const char *db,const char *table_name); bool reopen_table(TABLE *table,bool locked); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 622c570fa9a..f999f17aedf 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5368,3 +5368,5 @@ ER_TOO_BIG_PRECISION 42000 S1009 eng "Too big precision %d specified for column '%-.64s'. Maximum is %d." ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009 eng "Scale may not be larger than the precision (column '%-.64s')." +ER_WRONG_LOCK_OF_SYSTEM_TABLE + eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables" diff --git a/sql/slave.cc b/sql/slave.cc index a0779543148..445e2120475 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2370,7 +2370,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, else pthread_cond_wait(&data_cond, &data_lock); DBUG_PRINT("info",("Got signal of master update or timed out")); - if (error == ETIMEDOUT || error == ETIME) + if (error == ETIMEDOUT) { error= -1; break; diff --git a/sql/sp.cc b/sql/sp.cc index cf842803c01..55087f47f5e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -62,57 +62,152 @@ bool mysql_proc_table_exists= 1; /* Tells what SP_DEFAULT_ACCESS should be mapped to */ #define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL -/* *opened=true means we opened ourselves */ -static int -db_find_routine_aux(THD *thd, int type, sp_name *name, - enum thr_lock_type ltype, TABLE **tablep, bool *opened) -{ - TABLE *table; - byte key[MAX_KEY_LENGTH]; // db, name, optional key length type - DBUG_ENTER("db_find_routine_aux"); - DBUG_PRINT("enter", ("type: %d name: %*s", - type, name->m_name.length, name->m_name.str)); - *opened= FALSE; - *tablep= 0; +/* + Close mysql.proc, opened with open_proc_table_for_read(). + + SYNOPSIS + close_proc_table() + thd Thread context +*/ + +static void close_proc_table(THD *thd) +{ + close_thread_tables(thd); + thd->pop_open_tables_state(); +} + + +/* + Open the mysql.proc table for read. + + SYNOPSIS + open_proc_table_for_read() + thd Thread context + + NOTES + Thanks to restrictions which we put on opening and locking of + this table for writing, we can open and lock it for reading + even when we already have some other tables open and locked. + One must call close_proc_table() to close table opened with + this call. + + RETURN + 0 Error + # Pointer to TABLE object of mysql.proc +*/ + +static TABLE *open_proc_table_for_read(THD *thd) +{ + TABLE_LIST tables; + TABLE *table; + bool old_open_tables= thd->open_tables != 0; + bool refresh; + DBUG_ENTER("open_proc_table"); /* Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists is set when we create or read stored procedure or on flush privileges. */ - if (!mysql_proc_table_exists && ltype == TL_READ) - DBUG_RETURN(SP_OPEN_TABLE_FAILED); + if (!mysql_proc_table_exists) + DBUG_RETURN(0); - if (thd->lex->proc_table) - table= thd->lex->proc_table->table; - else - { - for (table= thd->open_tables ; table ; table= table->next) - if (strcmp(table->s->db, "mysql") == 0 && - strcmp(table->s->table_name, "proc") == 0) - break; - } - if (!table) - { - TABLE_LIST tables; + if (thd->push_open_tables_state()) + DBUG_RETURN(0); - memset(&tables, 0, sizeof(tables)); - tables.db= (char*)"mysql"; - tables.table_name= tables.alias= (char*)"proc"; - if (! (table= open_ltable(thd, &tables, ltype))) - { - /* - Under explicit LOCK TABLES or in prelocked mode we should not - say that mysql.proc table does not exist if we are unable to - open it since this condition may be transient. - */ - if (!(thd->locked_tables || thd->prelocked_mode)) - mysql_proc_table_exists= 0; - DBUG_RETURN(SP_OPEN_TABLE_FAILED); - } - *opened= TRUE; + bzero((char*) &tables, sizeof(tables)); + tables.db= (char*) "mysql"; + tables.table_name= tables.alias= (char*)"proc"; + if (!(table= open_table(thd, &tables, thd->mem_root, &refresh, + MYSQL_LOCK_IGNORE_FLUSH))) + { + thd->pop_open_tables_state(); + mysql_proc_table_exists= 0; + DBUG_RETURN(0); } - mysql_proc_table_exists= 1; + + DBUG_ASSERT(table->s->system_table); + + table->reginfo.lock_type= TL_READ; + /* + If we have other tables opened, we have to ensure we are not blocked + by a flush tables or global read lock, as this could lead to a deadlock + */ + if (!(thd->lock= mysql_lock_tables(thd, &table, 1, + old_open_tables ? + (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | + MYSQL_LOCK_IGNORE_FLUSH) : 0))) + { + close_proc_table(thd); + DBUG_RETURN(0); + } + DBUG_RETURN(table); +} + + +/* + Open the mysql.proc table for update. + + SYNOPSIS + open_proc_table_for_update() + thd Thread context + + NOTES + Table opened with this call should closed using close_thread_tables(). + + RETURN + 0 Error + # Pointer to TABLE object of mysql.proc +*/ + +static TABLE *open_proc_table_for_update(THD *thd) +{ + TABLE_LIST tables; + TABLE *table; + DBUG_ENTER("open_proc_table"); + + bzero((char*) &tables, sizeof(tables)); + tables.db= (char*) "mysql"; + tables.table_name= tables.alias= (char*)"proc"; + tables.lock_type= TL_WRITE; + + table= open_ltable(thd, &tables, TL_WRITE); + + /* + Under explicit LOCK TABLES or in prelocked mode we should not + say that mysql.proc table does not exist if we are unable to + open and lock it for writing since this condition may be + transient. + */ + if (!(thd->locked_tables || thd->prelocked_mode) || table) + mysql_proc_table_exists= test(table); + + DBUG_RETURN(table); +} + + +/* + Find row in open mysql.proc table representing stored routine. + + SYNOPSIS + db_find_routine_aux() + thd Thread context + type Type of routine to find (function or procedure) + name Name of routine + table TABLE object for open mysql.proc table. + + RETURN VALUE + SP_OK - Routine found + SP_KEY_NOT_FOUND- No routine with given name +*/ + +static int +db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) +{ + byte key[MAX_KEY_LENGTH]; // db, name, optional key length type + DBUG_ENTER("db_find_routine_aux"); + DBUG_PRINT("enter", ("type: %d name: %*s", + type, name->m_name.length, name->m_name.str)); /* Create key to find row. We have to use field->store() to be able to @@ -122,9 +217,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, same fields. */ if (name->m_name.length > table->field[1]->field_length) - { DBUG_RETURN(SP_KEY_NOT_FOUND); - } table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin); table->field[1]->store(name->m_name.str, name->m_name.length, &my_charset_bin); @@ -135,15 +228,33 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, if (table->file->index_read_idx(table->record[0], 0, key, table->key_info->key_length, HA_READ_KEY_EXACT)) - { DBUG_RETURN(SP_KEY_NOT_FOUND); - } - *tablep= table; DBUG_RETURN(SP_OK); } +/* + Find routine definition in mysql.proc table and create corresponding + sp_head object for it. + + SYNOPSIS + db_find_routine() + thd Thread context + type Type of routine (TYPE_ENUM_PROCEDURE/...) + name Name of routine + sphp Out parameter in which pointer to created sp_head + object is returned (0 in case of error). + + NOTE + This function may damage current LEX during execution, so it is good + idea to create temporary LEX and make it active before calling it. + + RETURN VALUE + 0 - Success + non-0 - Error (may be one of special codes like SP_KEY_NOT_FOUND) +*/ + static int db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) { @@ -151,7 +262,6 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) TABLE *table; const char *params, *returns, *body; int ret; - bool opened; const char *definer; longlong created; longlong modified; @@ -165,8 +275,11 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) DBUG_PRINT("enter", ("type: %d name: %*s", type, name->m_name.length, name->m_name.str)); - ret= db_find_routine_aux(thd, type, name, TL_READ, &table, &opened); - if (ret != SP_OK) + *sphp= 0; // In case of errors + if (!(table= open_proc_table_for_read(thd))) + DBUG_RETURN(SP_OPEN_TABLE_FAILED); + + if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) goto done; if (table->s->fields != MYSQL_PROC_FIELD_COUNT) @@ -258,11 +371,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) chistics.comment.str= ptr; chistics.comment.length= length; - if (opened) - { - opened= FALSE; - close_thread_tables(thd, 0, 1); - } + close_proc_table(thd); + table= 0; { String defstr; @@ -338,9 +448,8 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) } done: - - if (opened) - close_thread_tables(thd); + if (table) + close_proc_table(thd); DBUG_RETURN(ret); } @@ -363,7 +472,6 @@ db_create_routine(THD *thd, int type, sp_head *sp) { int ret; TABLE *table; - TABLE_LIST tables; char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; char olddb[128]; bool dbchanged; @@ -378,11 +486,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) goto done; } - memset(&tables, 0, sizeof(tables)); - tables.db= (char*)"mysql"; - tables.table_name= tables.alias= (char*)"proc"; - - if (! (table= open_ltable(thd, &tables, TL_WRITE))) + if (!(table= open_proc_table_for_update(thd))) ret= SP_OPEN_TABLE_FAILED; else { @@ -492,20 +596,18 @@ db_drop_routine(THD *thd, int type, sp_name *name) { TABLE *table; int ret; - bool opened; DBUG_ENTER("db_drop_routine"); DBUG_PRINT("enter", ("type: %d name: %*s", type, name->m_name.length, name->m_name.str)); - ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened); - if (ret == SP_OK) + if (!(table= open_proc_table_for_update(thd))) + DBUG_RETURN(SP_OPEN_TABLE_FAILED); + if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK) { if (table->file->delete_row(table->record[0])) ret= SP_DELETE_ROW_FAILED; } - - if (opened) - close_thread_tables(thd); + close_thread_tables(thd); DBUG_RETURN(ret); } @@ -520,8 +622,9 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) DBUG_PRINT("enter", ("type: %d name: %*s", type, name->m_name.length, name->m_name.str)); - ret= db_find_routine_aux(thd, type, name, TL_WRITE, &table, &opened); - if (ret == SP_OK) + if (!(table= open_proc_table_for_update(thd))) + DBUG_RETURN(SP_OPEN_TABLE_FAILED); + if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK) { store_record(table,record[1]); table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; @@ -539,8 +642,7 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if ((table->file->update_row(table->record[1],table->record[0]))) ret= SP_WRITE_ROW_FAILED; } - if (opened) - close_thread_tables(thd); + close_thread_tables(thd); DBUG_RETURN(ret); } @@ -742,20 +844,9 @@ sp_drop_db_routines(THD *thd, char *db) memset(key+keylen, (int)' ', 64-keylen); // Pad with space keylen= sizeof(key); - for (table= thd->open_tables ; table ; table= table->next) - if (strcmp(table->s->db, "mysql") == 0 && - strcmp(table->s->table_name, "proc") == 0) - break; - if (! table) - { - TABLE_LIST tables; - - memset(&tables, 0, sizeof(tables)); - tables.db= (char*)"mysql"; - tables.table_name= tables.alias= (char*)"proc"; - if (! (table= open_ltable(thd, &tables, TL_WRITE))) - DBUG_RETURN(SP_OPEN_TABLE_FAILED); - } + ret= SP_OPEN_TABLE_FAILED; + if (!(table= open_proc_table_for_update(thd))) + goto err; ret= SP_OK; table->file->ha_index_init(0); @@ -765,7 +856,8 @@ sp_drop_db_routines(THD *thd, char *db) int nxtres; bool deleted= FALSE; - do { + do + { if (! table->file->delete_row(table->record[0])) deleted= TRUE; /* We deleted something */ else @@ -785,6 +877,7 @@ sp_drop_db_routines(THD *thd, char *db) close_thread_tables(thd); +err: DBUG_RETURN(ret); } @@ -978,9 +1071,7 @@ sp_find_function(THD *thd, sp_name *name, bool cache_only) if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) && !cache_only) { - if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK) - sp= NULL; - else + if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) == SP_OK) sp_cache_insert(&thd->sp_func_cache, sp); } DBUG_RETURN(sp); @@ -1058,26 +1149,6 @@ sp_show_status_function(THD *thd, const char *wild) } -bool -sp_function_exists(THD *thd, sp_name *name) -{ - TABLE *table; - bool ret= FALSE; - bool opened= FALSE; - DBUG_ENTER("sp_function_exists"); - - if (sp_cache_lookup(&thd->sp_func_cache, name) || - db_find_routine_aux(thd, TYPE_ENUM_FUNCTION, - name, TL_READ, - &table, &opened) == SP_OK) - ret= TRUE; - if (opened) - close_thread_tables(thd, 0, 1); - thd->clear_error(); - DBUG_RETURN(ret); -} - - /* Structure that represents element in the set of stored routines used by statement or routine. @@ -1276,8 +1347,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, LEX *oldlex= thd->lex; LEX *newlex= new st_lex; thd->lex= newlex; - /* Pass hint pointer to mysql.proc table */ - newlex->proc_table= oldlex->proc_table; newlex->current_select= NULL; name.m_name.str= strchr(name.m_qname.str, '.'); name.m_db.length= name.m_name.str - name.m_qname.str; diff --git a/sql/sp.h b/sql/sp.h index 172559a706f..b8af8d3a321 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -74,9 +74,6 @@ sp_show_create_function(THD *thd, sp_name *name); int sp_show_status_function(THD *thd, const char *wild); -bool -sp_function_exists(THD *thd, sp_name *name); - /* Procedures for pre-caching of stored routines and building table list diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5f1031bcf83..367dc3bb0f6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -542,10 +542,9 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived, bool close_thread_table(THD *thd, TABLE **table_ptr) { - DBUG_ENTER("close_thread_table"); - bool found_old_table= 0; TABLE *table= *table_ptr; + DBUG_ENTER("close_thread_table"); DBUG_ASSERT(table->key_read == 0); DBUG_ASSERT(table->file->inited == handler::NONE); @@ -972,18 +971,34 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) } -/****************************************************************************** -** open a table -** Uses a cache of open tables to find a table not in use. -** If refresh is a NULL pointer, then the is no version number checking and -** the table is not put in the thread-open-list -** If the return value is NULL and refresh is set then one must close -** all tables and retry the open -******************************************************************************/ +/* + Open a table. + + SYNOPSIS + open_table() + thd Thread context + table_list Open first table in list + refresh Pointer to memory that will be set to 1 if + we need to close all tables and reopen them + If this is a NULL pointer, then the is no version + number checking and the table is not put in the + thread-open-list + flags Bitmap of flags to modify how open works: + MYSQL_LOCK_IGNORE_FLUSH - Open table even if someone + has done a flush or namelock on it. + + IMPLEMENTATION + Uses a cache of open tables to find a table not in use. + + RETURN + NULL Open failed. If refresh is set then one should close + all other tables and retry the open + # Success. Pointer to TABLE object for open table. +*/ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, - bool *refresh) + bool *refresh, uint flags) { reg1 TABLE *table; char key[MAX_DBKEY_LENGTH]; @@ -1096,9 +1111,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { if (table->s->version != refresh_version) { + if (flags & MYSQL_LOCK_IGNORE_FLUSH) + { + /* Force close at once after usage */ + thd->version= table->s->version; + continue; + } + /* - ** There is a refresh in progress for this table - ** Wait until the table is freed or the thread is killed. + There is a refresh in progress for this table + Wait until the table is freed or the thread is killed. */ close_old_data_files(thd,thd->open_tables,0,0); if (table->in_use != thd) @@ -1681,6 +1703,15 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, if (error == 5) DBUG_RETURN(0); // we have just opened VIEW + /* + We can't mark all tables in 'mysql' database as system since we don't + allow to lock such tables for writing with any other tables (even with + other system tables) and some privilege tables need this. + */ + if (!my_strcasecmp(system_charset_info, db, "mysql") && + !my_strcasecmp(system_charset_info, name, "proc")) + entry->s->system_table= 1; + if (Table_triggers_list::check_n_load(thd, db, name, entry)) goto err; @@ -1832,7 +1863,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) } (*counter)++; if (!tables->table && - !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh))) + !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, 0))) { free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC)); if (tables->view) @@ -2003,7 +2034,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) thd->current_tablenr= 0; /* open_ltable can be used only for BASIC TABLEs */ table_list->required_type= FRMTYPE_TABLE; - while (!(table= open_table(thd, table_list, thd->mem_root, &refresh)) && + while (!(table= open_table(thd, table_list, thd->mem_root, &refresh, 0)) && refresh) ; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index bf6f41d00ed..d0ac1a16f6b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -156,6 +156,14 @@ bool foreign_key_prefix(Key *a, Key *b) /**************************************************************************** ** Thread specific functions ****************************************************************************/ + +Open_tables_state::Open_tables_state() + :version(refresh_version) +{ + reset_open_tables_state(); +} + + /* Pass nominal parameters to Statement constructor only to ensure that the destructor works OK in case of error. The main_mem_root will be @@ -164,6 +172,7 @@ bool foreign_key_prefix(Key *a, Key *b) THD::THD() :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), + Open_tables_state(), user_time(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), @@ -181,10 +190,8 @@ THD::THD() db_length= col_access=0; query_error= tmp_table_used= 0; next_insert_id=last_insert_id=0; - open_tables= temporary_tables= handler_tables= derived_tables= 0; hash_clear(&handler_tables_hash); tmp_table=0; - lock=locked_tables=0; used_tables=0; cuted_fields= sent_row_count= 0L; limit_found_rows= 0; @@ -230,7 +237,6 @@ THD::THD() #ifndef NO_EMBEDDED_ACCESS_CHECKS db_access=NO_ACCESS; #endif - version=refresh_version; // For boot *scramble= '\0'; init(); @@ -259,7 +265,6 @@ THD::THD() tablespace_op=FALSE; ulong tmp=sql_rnd_with_mutex(); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); - prelocked_mode= NON_PRELOCKED; } @@ -1775,3 +1780,40 @@ void THD::set_status_var_init() { bzero((char*) &status_var, sizeof(status_var)); } + +/**************************************************************************** + Handling of open and locked tables states. + + This is used when we want to open/lock (and then close) some tables when + we already have a set of tables open and locked. We use these methods for + access to mysql.proc table to find definitions of stored routines. +****************************************************************************/ + +bool THD::push_open_tables_state() +{ + Open_tables_state *state; + DBUG_ENTER("push_open_table_state"); + /* Currently we only push things one level */ + DBUG_ASSERT(open_state_list.elements == 0); + + if (!(state= (Open_tables_state*) alloc(sizeof(*state)))) + DBUG_RETURN(1); // Fatal error is set + /* Store state for currently open tables */ + state->set_open_tables_state(this); + if (open_state_list.push_back(state, mem_root)) + DBUG_RETURN(1); // Fatal error is set + reset_open_tables_state(); + DBUG_RETURN(0); +} + +void THD::pop_open_tables_state() +{ + Open_tables_state *state; + DBUG_ENTER("pop_open_table_state"); + /* Currently we only push things one level */ + DBUG_ASSERT(open_state_list.elements == 1); + + state= open_state_list.pop(); + set_open_tables_state(state); + DBUG_VOID_RETURN; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 66f91545f97..44f126d96ec 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -940,13 +940,94 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1, PRELOCKED_UNDER_LOCK_TABLES= 2}; +/* + Class that holds information about tables which were open and locked + by the thread. It is also used to save/restore this information in + push_open_tables_state()/pop_open_tables_state(). +*/ + +class Open_tables_state +{ +public: + /* + open_tables - list of regular tables in use by this thread + temporary_tables - list of temp tables in use by this thread + handler_tables - list of tables that were opened with HANDLER OPEN + and are still in use by this thread + */ + TABLE *open_tables, *temporary_tables, *handler_tables, *derived_tables; + /* + During a MySQL session, one can lock tables in two modes: automatic + or manual. In automatic mode all necessary tables are locked just before + statement execution, and all acquired locks are stored in 'lock' + member. Unlocking takes place automatically as well, when the + statement ends. + Manual mode comes into play when a user issues a 'LOCK TABLES' + statement. In this mode the user can only use the locked tables. + Trying to use any other tables will give an error. The locked tables are + stored in 'locked_tables' member. Manual locking is described in + the 'LOCK_TABLES' chapter of the MySQL manual. + See also lock_tables() for details. + */ + MYSQL_LOCK *lock; + /* + Tables that were locked with explicit or implicit LOCK TABLES. + (Implicit LOCK TABLES happens when we are prelocking tables for + execution of statement which uses stored routines. See description + THD::prelocked_mode for more info.) + */ + MYSQL_LOCK *locked_tables; + /* + prelocked_mode_type enum and prelocked_mode member are used for + indicating whenever "prelocked mode" is on, and what type of + "prelocked mode" is it. + + Prelocked mode is used for execution of queries which explicitly + or implicitly (via views or triggers) use functions, thus may need + some additional tables (mentioned in query table list) for their + execution. + + First open_tables() call for such query will analyse all functions + used by it and add all additional tables to table its list. It will + also mark this query as requiring prelocking. After that lock_tables() + will issue implicit LOCK TABLES for the whole table list and change + thd::prelocked_mode to non-0. All queries called in functions invoked + by the main query will use prelocked tables. Non-0 prelocked_mode + will also surpress mentioned analysys in those queries thus saving + cycles. Prelocked mode will be turned off once close_thread_tables() + for the main query will be called. + + Note: Since not all "tables" present in table list are really locked + thd::prelocked_mode does not imply thd::locked_tables. + */ + prelocked_mode_type prelocked_mode; + ulong version; + uint current_tablenr; + + Open_tables_state(); + + void set_open_tables_state(Open_tables_state *state) + { + *this= *state; + } + + void reset_open_tables_state() + { + open_tables= temporary_tables= handler_tables= derived_tables= 0; + lock= locked_tables= 0; + prelocked_mode= NON_PRELOCKED; + } +}; + + /* For each client connection we create a separate thread with THD serving as a thread/connection descriptor */ class THD :public ilink, - public Statement + public Statement, + public Open_tables_state { public: #ifdef EMBEDDED_LIBRARY @@ -1014,34 +1095,6 @@ public: ulong master_access; /* Global privileges from mysql.user */ ulong db_access; /* Privileges for current db */ - /* - open_tables - list of regular tables in use by this thread - temporary_tables - list of temp tables in use by this thread - handler_tables - list of tables that were opened with HANDLER OPEN - and are still in use by this thread - */ - TABLE *open_tables,*temporary_tables, *handler_tables, *derived_tables; - /* - During a MySQL session, one can lock tables in two modes: automatic - or manual. In automatic mode all necessary tables are locked just before - statement execution, and all acquired locks are stored in 'lock' - member. Unlocking takes place automatically as well, when the - statement ends. - Manual mode comes into play when a user issues a 'LOCK TABLES' - statement. In this mode the user can only use the locked tables. - Trying to use any other tables will give an error. The locked tables are - stored in 'locked_tables' member. Manual locking is described in - the 'LOCK_TABLES' chapter of the MySQL manual. - See also lock_tables() for details. - */ - MYSQL_LOCK *lock; /* Current locks */ - /* - Tables that were locked with explicit or implicit LOCK TABLES. - (Implicit LOCK TABLES happens when we are prelocking tables for - execution of statement which uses stored routines. See description - THD::prelocked_mode for more info.) - */ - MYSQL_LOCK *locked_tables; HASH handler_tables_hash; /* One thread can hold up to one named user-level lock. This variable @@ -1158,6 +1211,7 @@ public: List warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; + List open_state_list; /* Id of current query. Statement can be reused to execute several queries query_id is global in context of the whole MySQL server. @@ -1167,7 +1221,7 @@ public: update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id, warn_id; - ulong version, options, thread_id, col_access; + ulong options, thread_id, col_access; /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; @@ -1175,7 +1229,7 @@ public: ulong row_count; // Row counter, mainly for errors and warnings long dbug_thread_id; pthread_t real_id; - uint current_tablenr,tmp_table,global_read_lock; + uint tmp_table, global_read_lock; uint server_status,open_options,system_thread; uint32 db_length; uint select_number; //number of select (used for EXPLAIN) @@ -1226,31 +1280,6 @@ public: long long_value; } sys_var_tmp; - /* - prelocked_mode_type enum and prelocked_mode member are used for - indicating whenever "prelocked mode" is on, and what type of - "prelocked mode" is it. - - Prelocked mode is used for execution of queries which explicitly - or implicitly (via views or triggers) use functions, thus may need - some additional tables (mentioned in query table list) for their - execution. - - First open_tables() call for such query will analyse all functions - used by it and add all additional tables to table its list. It will - also mark this query as requiring prelocking. After that lock_tables() - will issue implicit LOCK TABLES for the whole table list and change - thd::prelocked_mode to non-0. All queries called in functions invoked - by the main query will use prelocked tables. Non-0 prelocked_mode - will also surpress mentioned analysys in those queries thus saving - cycles. Prelocked mode will be turned off once close_thread_tables() - for the main query will be called. - - Note: Since not all "tables" present in table list are really locked - thd::relocked_mode does not imply thd::locked_tables. - */ - prelocked_mode_type prelocked_mode; - THD(); ~THD(); @@ -1436,8 +1465,11 @@ public: (variables.sql_mode & MODE_STRICT_ALL_TABLES))); } void set_status_var_init(); + bool push_open_tables_state(); + void pop_open_tables_state(); }; + #define tmp_disable_binlog(A) \ {ulong tmp_disable_binlog__save_options= (A)->options; \ (A)->options&= ~OPTION_BIN_LOG diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bfd4bd83a81..fa5930e5205 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1743,7 +1743,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) #endif if (thd->killed || di->status) break; - if (error == ETIME || error == ETIMEDOUT) + if (error == ETIMEDOUT) { thd->killed= THD::KILL_CONNECTION; break; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4d3de481c8b..630a7e950f7 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -145,7 +145,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->found_semicolon= 0; lex->safe_to_cache_query= 1; lex->time_zone_tables_used= 0; - lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0; + lex->leaf_tables_insert= lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; lex->variables_used= 0; lex->select_lex.parent_lex= lex; @@ -164,7 +164,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->current_select= &lex->select_lex; lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); - lex->sql_command=SQLCOM_END; + lex->sql_command= lex->orig_sql_command= SQLCOM_END; lex->duplicates= DUP_ERROR; lex->ignore= 0; lex->sphead= NULL; @@ -556,6 +556,15 @@ int yylex(void *arg, void *yythd) lex->next_state= MY_LEX_START; // Allow signed numbers if (c == ',') lex->tok_start=lex->ptr; // Let tok_start point at next item + /* + Check for a placeholder: it should not precede a possible identifier + because of binlogging: when a placeholder is replaced with + its value in a query for the binlog, the query must stay + grammatically correct. + */ + else if (c == '?' && ((THD*) yythd)->command == COM_STMT_PREPARE && + !ident_map[cs, yyPeek()]) + return(PARAM_MARKER); return((int) c); case MY_LEX_IDENT_OR_NCHAR: diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d0dc98206b7..45c8182a29c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -719,7 +719,6 @@ typedef struct st_lex function) */ TABLE_LIST **query_tables_last; - TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */ /* store original leaf_tables for INSERT SELECT and PS/SP */ TABLE_LIST *leaf_tables_insert; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6993f2e11fe..e0c5338a952 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5193,7 +5193,6 @@ mysql_init_select(LEX *lex) { SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); - lex->orig_sql_command= SQLCOM_END; lex->wild= 0; if (select_lex == &lex->select_lex) { @@ -5216,6 +5215,11 @@ mysql_new_select(LEX *lex, bool move_down) select_lex->init_query(); select_lex->init_select(); select_lex->parent_lex= lex; + /* + Don't evaluate this subquery during statement prepare even if + it's a constant one. The flag is switched off in the end of + mysql_stmt_prepare. + */ if (thd->current_arena->is_stmt_prepare()) select_lex->uncacheable|= UNCACHEABLE_PREPARE; if (move_down) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 53f706bd0f6..3e291243e1e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -106,6 +106,7 @@ public: virtual ~Prepared_statement(); void setup_set_params(); virtual Query_arena::Type type() const; + virtual void close_cursor(); }; static void execute_stmt(THD *thd, Prepared_statement *stmt, @@ -312,24 +313,28 @@ static void set_param_int64(Item_param *param, uchar **pos, ulong len) static void set_param_float(Item_param *param, uchar **pos, ulong len) { + float data; #ifndef EMBEDDED_LIBRARY if (len < 4) return; -#endif - float data; float4get(data,*pos); +#else + data= *(float*) *pos; +#endif param->set_double((double) data); *pos+= 4; } static void set_param_double(Item_param *param, uchar **pos, ulong len) { + double data; #ifndef EMBEDDED_LIBRARY if (len < 8) return; -#endif - double data; float8get(data,*pos); +#else + data= *(double*) *pos; +#endif param->set_double((double) data); *pos+= 8; } @@ -1825,7 +1830,10 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, void init_stmt_after_parse(THD *thd, LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; - + /* + Switch off a temporary flag that prevents evaluation of + subqueries in statement prepare. + */ for (; sl; sl= sl->next_select_in_list()) sl->uncacheable&= ~UNCACHEABLE_PREPARE; } @@ -1983,10 +1991,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) cursor= stmt->cursor; if (cursor && cursor->is_open()) - { - my_error(ER_EXEC_STMT_WITH_OPEN_CURSOR, MYF(0)); - DBUG_VOID_RETURN; - } + stmt->close_cursor(); DBUG_ASSERT(thd->free_list == NULL); mysql_reset_thd_for_next_command(thd); @@ -2281,6 +2286,7 @@ void mysql_stmt_reset(THD *thd, char *packet) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; + stmt->close_cursor(); /* will reset statement params */ cursor= stmt->cursor; if (cursor && cursor->is_open()) { @@ -2292,12 +2298,6 @@ void mysql_stmt_reset(THD *thd, char *packet) stmt->state= Query_arena::PREPARED; - /* - Clear parameters from data which could be set by - mysql_stmt_send_long_data() call. - */ - reset_stmt_params(stmt); - mysql_reset_thd_for_next_command(thd); send_ok(thd); @@ -2445,10 +2445,17 @@ void Prepared_statement::setup_set_params() Prepared_statement::~Prepared_statement() { if (cursor) + { + if (cursor->is_open()) + { + cursor->close(FALSE); + free_items(); + free_root(cursor->mem_root, MYF(0)); + } cursor->Cursor::~Cursor(); - free_items(); - if (cursor) - free_root(cursor->mem_root, MYF(0)); + } + else + free_items(); delete lex->result; } @@ -2457,3 +2464,20 @@ Query_arena::Type Prepared_statement::type() const { return PREPARED_STATEMENT; } + + +void Prepared_statement::close_cursor() +{ + if (cursor && cursor->is_open()) + { + thd->change_list= cursor->change_list; + cursor->close(FALSE); + cleanup_stmt_and_thd_after_use(this, thd); + free_root(cursor->mem_root, MYF(0)); + } + /* + Clear parameters from data which could be set by + mysql_stmt_send_long_data() call. + */ + reset_stmt_params(this); +} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b4afab24d4c..bc45c5fa3be 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1911,12 +1911,6 @@ Cursor::close(bool is_active) } -Cursor::~Cursor() -{ - if (is_open()) - close(FALSE); -} - /*********************************************************************/ /* @@ -5171,11 +5165,17 @@ static void add_not_null_conds(JOIN *join) DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *not_null_item= (Item_field*)item; JOIN_TAB *referred_tab= not_null_item->field->table->reginfo.join_tab; - Item_func_isnotnull *notnull; + Item *notnull; if (!(notnull= new Item_func_isnotnull(not_null_item))) DBUG_VOID_RETURN; - - notnull->quick_fix_field(); + /* + We need to do full fix_fields() call here in order to have correct + notnull->const_item(). This is needed e.g. by test_quick_select + when it is called from make_join_select after this function is + called. + */ + if (notnull->fix_fields(join->thd, ¬null)) + DBUG_VOID_RETURN; DBUG_EXECUTE("where",print_where(notnull, referred_tab->table->alias);); add_cond_and_fix(&referred_tab->select_cond, notnull); diff --git a/sql/sql_select.h b/sql/sql_select.h index ac3e8898cc6..9285e33be33 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -408,7 +408,7 @@ public: void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } Cursor(THD *thd); - ~Cursor(); + ~Cursor() {} }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 22eb2489451..1d7f3ca87be 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -752,10 +752,15 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, Convert the default value from client character set into the column character set if necessary. */ - if (sql_field->def) + if (sql_field->def && cs != sql_field->def->collation.collation) { - sql_field->def= - sql_field->def->safe_charset_converter(cs); + if (!(sql_field->def= + sql_field->def->safe_charset_converter(cs))) + { + /* Could not convert */ + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(-1); + } } if (sql_field->sql_type == FIELD_TYPE_SET) @@ -1761,7 +1766,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, create_info, *extra_fields, *keys, 0, select_field_count)) { - if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0))) + if (!(table= open_table(thd, create_table, thd->mem_root, (bool*)0, 0))) quick_rm_table(create_info->db_type, create_table->db, table_case_name(create_info, create_table->table_name)); } @@ -3572,7 +3577,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, bzero((void*) &tbl, sizeof(tbl)); tbl.db= new_db; tbl.table_name= tbl.alias= tmp_name; - new_table= open_table(thd, &tbl, thd->mem_root, 0); + new_table= open_table(thd, &tbl, thd->mem_root, 0, 0); } else { diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index f058c306d42..fd79fc8b878 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -69,7 +69,10 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) But do we want this ? */ - if (open_and_lock_tables(thd, tables)) + /* We should have only one table in table list. */ + DBUG_ASSERT(tables->next_global == 0); + + if (!(table= open_ltable(thd, tables, tables->lock_type))) DBUG_RETURN(TRUE); /* @@ -80,8 +83,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) if (check_global_access(thd, SUPER_ACL)) DBUG_RETURN(TRUE); - table= tables->table; - /* We do not allow creation of triggers on views or temporary tables. We have to do this check here and not in diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c5d8e0d98e2..5c6324e15fd 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -344,6 +344,8 @@ int mysql_update(THD *thd, break; } } + else + table->file->unlock_row(); } if (thd->killed && !error) error= 1; // Aborted diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 46e267fe165..92680e48945 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -465,6 +465,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PACK_KEYS_SYM %token PARTIAL %token PASSWORD +%token PARAM_MARKER %token PHASE_SYM %token POINTFROMTEXT %token POINT_SYM @@ -6933,23 +6934,15 @@ text_string: ; param_marker: - '?' + PARAM_MARKER { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_STMT_PREPARE) + Item_param *item= new Item_param((uint) (lex->tok_start - + (uchar *) thd->query)); + if (!($$= item) || lex->param_list.push_back(item)) { - Item_param *item= new Item_param((uint) (lex->tok_start - - (uchar *) thd->query)); - if (!($$= item) || lex->param_list.push_back(item)) - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - YYABORT; - } - } - else - { - yyerror(ER(ER_SYNTAX_ERROR)); + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); YYABORT; } } diff --git a/sql/table.h b/sql/table.h index d0c998c4c10..e5653a1f213 100644 --- a/sql/table.h +++ b/sql/table.h @@ -163,6 +163,13 @@ typedef struct st_table_share my_bool crashed; my_bool is_view; my_bool name_lock, replace_with_name_lock; + /* + TRUE if this is a system table like 'mysql.proc', which we want to be + able to open and lock even when we already have some tables open and + locked. To avoid deadlocks we have to put certain restrictions on + locking of this table for writing. FALSE - otherwise. + */ + my_bool system_table; } TABLE_SHARE; diff --git a/storage/ndb/include/ndb_version.h.in b/storage/ndb/include/ndb_version.h.in index d7f43eae40a..826f5124407 100644 --- a/storage/ndb/include/ndb_version.h.in +++ b/storage/ndb/include/ndb_version.h.in @@ -36,8 +36,16 @@ #define MAKE_VERSION(A,B,C) (((A) << 16) | ((B) << 8) | ((C) << 0)) #define NDB_VERSION_D MAKE_VERSION(NDB_VERSION_MAJOR, NDB_VERSION_MINOR, NDB_VERSION_BUILD) - -#define NDB_VERSION_STRING (getVersionString(NDB_VERSION, NDB_VERSION_STATUS)) +#define NDB_VERSION_STRING_BUF_SZ 100 +#ifdef __cplusplus +extern "C" +#else +extern +#endif +char ndb_version_string_buf[NDB_VERSION_STRING_BUF_SZ]; +#define NDB_VERSION_STRING (getVersionString(NDB_VERSION, NDB_VERSION_STATUS, \ + ndb_version_string_buf, \ + sizeof(ndb_version_string_buf))) #define NDB_VERSION ndbGetOwnVersion() diff --git a/storage/ndb/include/portlib/NdbTCP.h b/storage/ndb/include/portlib/NdbTCP.h index 8138a2ef354..308a3833ffd 100644 --- a/storage/ndb/include/portlib/NdbTCP.h +++ b/storage/ndb/include/portlib/NdbTCP.h @@ -31,7 +31,7 @@ #define NDB_NONBLOCK FNDELAY #define NDB_SOCKET_TYPE int #define NDB_INVALID_SOCKET -1 -#define NDB_CLOSE_SOCKET(x) close(x) +#define _NDB_CLOSE_SOCKET(x) close(x) /** * socklen_t not defined in the header files of OSE @@ -52,7 +52,7 @@ typedef int socklen_t; #define EWOULDBLOCK WSAEWOULDBLOCK #define NDB_SOCKET_TYPE SOCKET #define NDB_INVALID_SOCKET INVALID_SOCKET -#define NDB_CLOSE_SOCKET(x) closesocket(x) +#define _NDB_CLOSE_SOCKET(x) closesocket(x) #else @@ -64,7 +64,7 @@ typedef int socklen_t; #define NDB_NONBLOCK O_NONBLOCK #define NDB_SOCKET_TYPE int #define NDB_INVALID_SOCKET -1 -#define NDB_CLOSE_SOCKET(x) ::close(x) +#define _NDB_CLOSE_SOCKET(x) ::close(x) #define InetErrno errno @@ -89,6 +89,12 @@ extern "C" { */ int Ndb_getInAddr(struct in_addr * dst, const char *address); +#ifdef DBUG_OFF +#define NDB_CLOSE_SOCKET(fd) _NDB_CLOSE_SOCKET(fd) +#else +int NDB_CLOSE_SOCKET(int fd); +#endif + #ifdef __cplusplus } #endif diff --git a/storage/ndb/include/transporter/TransporterRegistry.hpp b/storage/ndb/include/transporter/TransporterRegistry.hpp index 1ae8a4068c4..0bb9733e8c4 100644 --- a/storage/ndb/include/transporter/TransporterRegistry.hpp +++ b/storage/ndb/include/transporter/TransporterRegistry.hpp @@ -268,6 +268,8 @@ public: Transporter* get_transporter(NodeId nodeId); NodeId get_localNodeId() { return localNodeId; }; + + struct in_addr get_connect_address(NodeId node_id) const; protected: private: diff --git a/storage/ndb/include/util/SocketServer.hpp b/storage/ndb/include/util/SocketServer.hpp index 2e1afb74945..4c37e63adf0 100644 --- a/storage/ndb/include/util/SocketServer.hpp +++ b/storage/ndb/include/util/SocketServer.hpp @@ -41,7 +41,13 @@ public: protected: friend class SocketServer; friend void* sessionThread_C(void*); - Session(NDB_SOCKET_TYPE sock): m_socket(sock){ m_stop = m_stopped = false;} + Session(NDB_SOCKET_TYPE sock): m_socket(sock) + { + DBUG_ENTER("SocketServer::Session"); + DBUG_PRINT("enter",("NDB_SOCKET: %d", m_socket)); + m_stop = m_stopped = false; + DBUG_VOID_RETURN; + } bool m_stop; // Has the session been ordered to stop? bool m_stopped; // Has the session stopped? diff --git a/storage/ndb/include/util/ndb_opts.h b/storage/ndb/include/util/ndb_opts.h index 72abd6d5d7a..f60ac4e6a63 100644 --- a/storage/ndb/include/util/ndb_opts.h +++ b/storage/ndb/include/util/ndb_opts.h @@ -28,6 +28,7 @@ my_bool opt_ndb_optimized_node_selection int opt_ndb_nodeid; +bool opt_endinfo= 0; my_bool opt_ndb_shm; const char *opt_ndb_connectstring= 0; const char *opt_connect_str= 0; @@ -119,6 +120,7 @@ ndb_std_get_one_option(int optid, { DBUG_PUSH("d:t"); } + opt_endinfo= 1; break; #endif case 'V': diff --git a/storage/ndb/include/util/version.h b/storage/ndb/include/util/version.h index 5459e44b818..62dc07d905a 100644 --- a/storage/ndb/include/util/version.h +++ b/storage/ndb/include/util/version.h @@ -30,7 +30,8 @@ extern "C" { Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build); - const char* getVersionString(Uint32 version, const char * status); + const char* getVersionString(Uint32 version, const char * status, + char *buf, unsigned sz); void ndbPrintVersion(); Uint32 ndbGetOwnVersion(); diff --git a/storage/ndb/src/common/logger/LogHandler.cpp b/storage/ndb/src/common/logger/LogHandler.cpp index ec4137297f1..a9d4512112f 100644 --- a/storage/ndb/src/common/logger/LogHandler.cpp +++ b/storage/ndb/src/common/logger/LogHandler.cpp @@ -31,6 +31,7 @@ LogHandler::LogHandler() : m_last_message[0]= 0; m_last_log_time= 0; m_now= 0; + m_last_level= (Logger::LoggerLevel)-1; } LogHandler::~LogHandler() diff --git a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp index 0e9b2a83e2f..b3d0221fedb 100644 --- a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -47,6 +47,8 @@ ConfigRetriever::ConfigRetriever(const char * _connect_string, Uint32 version, Uint32 node_type) { + DBUG_ENTER("ConfigRetriever::ConfigRetriever"); + m_version = version; m_node_type = node_type; _ownNodeId= 0; @@ -55,23 +57,26 @@ ConfigRetriever::ConfigRetriever(const char * _connect_string, if (m_handle == 0) { setError(CR_ERROR, "Unable to allocate mgm handle"); - return; + DBUG_VOID_RETURN; } if (ndb_mgm_set_connectstring(m_handle, _connect_string)) { setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); - return; + DBUG_VOID_RETURN; } resetError(); + DBUG_VOID_RETURN; } ConfigRetriever::~ConfigRetriever() { + DBUG_ENTER("ConfigRetriever::~ConfigRetriever"); if (m_handle) { ndb_mgm_disconnect(m_handle); ndb_mgm_destroy_handle(&m_handle); } + DBUG_VOID_RETURN; } Uint32 @@ -137,14 +142,14 @@ ConfigRetriever::getConfig() { } ndb_mgm_configuration * -ConfigRetriever::getConfig(NdbMgmHandle m_handle){ - +ConfigRetriever::getConfig(NdbMgmHandle m_handle) +{ ndb_mgm_configuration * conf = ndb_mgm_get_configuration(m_handle,m_version); - if(conf == 0){ + if(conf == 0) + { setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); return 0; } - return conf; } diff --git a/storage/ndb/src/common/portlib/NdbMutex.c b/storage/ndb/src/common/portlib/NdbMutex.c index d3d39ea8cf7..18f8548e4e6 100644 --- a/storage/ndb/src/common/portlib/NdbMutex.c +++ b/storage/ndb/src/common/portlib/NdbMutex.c @@ -23,33 +23,37 @@ NdbMutex* NdbMutex_Create(void) { + DBUG_ENTER("NdbMutex_Create"); NdbMutex* pNdbMutex; int result; pNdbMutex = (NdbMutex*)NdbMem_Allocate(sizeof(NdbMutex)); + DBUG_PRINT("info",("NdbMem_Allocate 0x%lx",pNdbMutex)); if (pNdbMutex == NULL) - return NULL; + DBUG_RETURN(NULL); result = pthread_mutex_init(pNdbMutex, NULL); assert(result == 0); - return pNdbMutex; - + DBUG_RETURN(pNdbMutex); } int NdbMutex_Destroy(NdbMutex* p_mutex) { + DBUG_ENTER("NdbMutex_Destroy"); int result; if (p_mutex == NULL) - return -1; + DBUG_RETURN(-1); result = pthread_mutex_destroy(p_mutex); - free(p_mutex); + + DBUG_PRINT("info",("NdbMem_Free 0x%lx",p_mutex)); + NdbMem_Free(p_mutex); - return result; + DBUG_RETURN(result); } diff --git a/storage/ndb/src/common/portlib/NdbTCP.cpp b/storage/ndb/src/common/portlib/NdbTCP.cpp index a63f5a7ba27..c7b9d33c5f6 100644 --- a/storage/ndb/src/common/portlib/NdbTCP.cpp +++ b/storage/ndb/src/common/portlib/NdbTCP.cpp @@ -54,6 +54,15 @@ Ndb_getInAddr(struct in_addr * dst, const char *address) { return -1; //DBUG_RETURN(-1); } +#ifndef DBUG_OFF +extern "C" +int NDB_CLOSE_SOCKET(int fd) +{ + DBUG_PRINT("info", ("NDB_CLOSE_SOCKET(%d)", fd)); + return _NDB_CLOSE_SOCKET(fd); +} +#endif + #if 0 int Ndb_getInAddr(struct in_addr * dst, const char *address) { diff --git a/storage/ndb/src/common/portlib/NdbThread.c b/storage/ndb/src/common/portlib/NdbThread.c index aaee9b45069..cee4ec018a0 100644 --- a/storage/ndb/src/common/portlib/NdbThread.c +++ b/storage/ndb/src/common/portlib/NdbThread.c @@ -56,6 +56,7 @@ ndb_thread_wrapper(void* _ss){ void *ret; struct NdbThread * ss = (struct NdbThread *)_ss; ret= (* ss->func)(ss->object); + DBUG_POP(); NdbThread_Exit(ret); } /* will never be reached */ @@ -70,6 +71,7 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, const char* p_thread_name, NDB_THREAD_PRIO thread_prio) { + DBUG_ENTER("NdbThread_Create"); struct NdbThread* tmpThread; int result; pthread_attr_t thread_attr; @@ -77,11 +79,13 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, (void)thread_prio; /* remove warning for unused parameter */ if (p_thread_func == NULL) - return 0; + DBUG_RETURN(NULL); tmpThread = (struct NdbThread*)NdbMem_Allocate(sizeof(struct NdbThread)); if (tmpThread == NULL) - return NULL; + DBUG_RETURN(NULL); + + DBUG_PRINT("info",("thread_name: %s", p_thread_name)); strnmov(tmpThread->thread_name,p_thread_name,sizeof(tmpThread->thread_name)); @@ -108,16 +112,20 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, assert(result==0); pthread_attr_destroy(&thread_attr); - return tmpThread; + DBUG_PRINT("exit",("ret: %lx", tmpThread)); + DBUG_RETURN(tmpThread); } void NdbThread_Destroy(struct NdbThread** p_thread) { - if (*p_thread != NULL){ + DBUG_ENTER("NdbThread_Destroy"); + if (*p_thread != NULL){ + DBUG_PRINT("enter",("*p_thread: %lx", * p_thread)); free(* p_thread); * p_thread = 0; } + DBUG_VOID_RETURN; } diff --git a/storage/ndb/src/common/transporter/Transporter.cpp b/storage/ndb/src/common/transporter/Transporter.cpp index 124ed5f7241..377fabe27ab 100644 --- a/storage/ndb/src/common/transporter/Transporter.cpp +++ b/storage/ndb/src/common/transporter/Transporter.cpp @@ -76,6 +76,7 @@ Transporter::Transporter(TransporterRegistry &t_reg, m_connected = false; m_timeOutMillis = 1000; + m_connect_address.s_addr= 0; if(s_port<0) s_port= -s_port; // was dynamic @@ -103,6 +104,13 @@ Transporter::connect_server(NDB_SOCKET_TYPE sockfd) { DBUG_RETURN(true); // TODO assert(0); } + { + struct sockaddr addr; + SOCKET_SIZE_TYPE addrlen= sizeof(addr); + int r= getpeername(sockfd, &addr, &addrlen); + m_connect_address= ((struct sockaddr_in *)&addr)->sin_addr; + } + bool res = connect_server_impl(sockfd); if(res){ m_connected = true; @@ -189,6 +197,13 @@ Transporter::connect_client(NDB_SOCKET_TYPE sockfd) { g_eventLogger.warning("Unable to verify transporter compatability with node %d", nodeId); } + { + struct sockaddr addr; + SOCKET_SIZE_TYPE addrlen= sizeof(addr); + int r= getpeername(sockfd, &addr, &addrlen); + m_connect_address= ((struct sockaddr_in *)&addr)->sin_addr; + } + bool res = connect_client_impl(sockfd); if(res){ m_connected = true; diff --git a/storage/ndb/src/common/transporter/Transporter.hpp b/storage/ndb/src/common/transporter/Transporter.hpp index 8c5e96226a3..c9f4e9bda42 100644 --- a/storage/ndb/src/common/transporter/Transporter.hpp +++ b/storage/ndb/src/common/transporter/Transporter.hpp @@ -147,6 +147,7 @@ private: bool isMgmConnection; SocketClient *m_socket_client; + struct in_addr m_connect_address; protected: Uint32 getErrorCount(); diff --git a/storage/ndb/src/common/transporter/TransporterRegistry.cpp b/storage/ndb/src/common/transporter/TransporterRegistry.cpp index 3776bce7452..60649665d4a 100644 --- a/storage/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/storage/ndb/src/common/transporter/TransporterRegistry.cpp @@ -55,6 +55,12 @@ extern int g_ndb_shm_signum; #include extern EventLogger g_eventLogger; +struct in_addr +TransporterRegistry::get_connect_address(NodeId node_id) const +{ + return theTransporters[node_id]->m_connect_address; +} + SocketServer::Session * TransporterService::newSession(NDB_SOCKET_TYPE sockfd) { DBUG_ENTER("SocketServer::Session * TransporterService::newSession"); @@ -74,7 +80,9 @@ SocketServer::Session * TransporterService::newSession(NDB_SOCKET_TYPE sockfd) TransporterRegistry::TransporterRegistry(void * callback, unsigned _maxTransporters, - unsigned sizeOfLongSignalMemory) { + unsigned sizeOfLongSignalMemory) +{ + DBUG_ENTER("TransporterRegistry::TransporterRegistry"); nodeIdSpecified = false; maxTransporters = _maxTransporters; @@ -112,6 +120,8 @@ TransporterRegistry::TransporterRegistry(void * callback, theOSEReceiver = 0; theOSEJunkSocketSend = 0; theOSEJunkSocketRecv = 0; + + DBUG_VOID_RETURN; } void TransporterRegistry::set_mgm_handle(NdbMgmHandle h) @@ -135,7 +145,9 @@ void TransporterRegistry::set_mgm_handle(NdbMgmHandle h) DBUG_VOID_RETURN; } -TransporterRegistry::~TransporterRegistry() { +TransporterRegistry::~TransporterRegistry() +{ + DBUG_ENTER("TransporterRegistry::~TransporterRegistry"); removeAll(); @@ -157,6 +169,8 @@ TransporterRegistry::~TransporterRegistry() { #endif if (m_mgm_handle) ndb_mgm_destroy_handle(&m_mgm_handle); + + DBUG_VOID_RETURN; } void diff --git a/storage/ndb/src/common/util/Parser.cpp b/storage/ndb/src/common/util/Parser.cpp index dea128ccf66..d692aa18392 100644 --- a/storage/ndb/src/common/util/Parser.cpp +++ b/storage/ndb/src/common/util/Parser.cpp @@ -141,7 +141,10 @@ split(char * buf, char ** name, char ** value){ bool ParserImpl::run(Context * ctx, const class Properties ** pDst, - volatile bool * stop) const { + volatile bool * stop) const +{ + DBUG_ENTER("ParserImpl::run"); + * pDst = 0; bool ownStop = false; if(stop == 0) @@ -153,24 +156,24 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz); if(Eof(ctx->m_currentToken)){ ctx->m_status = Parser::Eof; - return false; + DBUG_RETURN(false); } if(ctx->m_currentToken[0] == 0){ ctx->m_status = Parser::NoLine; - return false; + DBUG_RETURN(false); } if(Empty(ctx->m_currentToken)){ ctx->m_status = Parser::EmptyLine; - return false; + DBUG_RETURN(false); } trim(ctx->m_currentToken); ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows); if(ctx->m_currentCmd == 0){ ctx->m_status = Parser::UnknownCommand; - return false; + DBUG_RETURN(false); } Properties * p = new Properties(); @@ -200,19 +203,19 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, tmp = input.gets(buf, sz); } while((! * stop) && !Eof(tmp) && !Empty(tmp)); } - return false; + DBUG_RETURN(false); } if(* stop){ delete p; ctx->m_status = Parser::ExternalStop; - return false; + DBUG_RETURN(false); } if(!checkMandatory(ctx, p)){ ctx->m_status = Parser::MissingMandatoryArgument; delete p; - return false; + DBUG_RETURN(false); } /** @@ -229,7 +232,7 @@ ParserImpl::run(Context * ctx, const class Properties ** pDst, ctx->m_status = Parser::Ok; * pDst = p; - return true; + DBUG_RETURN(true); } const ParserImpl::DummyRow* diff --git a/storage/ndb/src/common/util/SocketClient.cpp b/storage/ndb/src/common/util/SocketClient.cpp index 38df1417eb8..821624eb5c4 100644 --- a/storage/ndb/src/common/util/SocketClient.cpp +++ b/storage/ndb/src/common/util/SocketClient.cpp @@ -57,6 +57,8 @@ SocketClient::init() return false; } + DBUG_PRINT("info",("NDB_SOCKET: %d", m_sockfd)); + return true; } diff --git a/storage/ndb/src/common/util/SocketServer.cpp b/storage/ndb/src/common/util/SocketServer.cpp index 6019d24d736..15dca2d96b1 100644 --- a/storage/ndb/src/common/util/SocketServer.cpp +++ b/storage/ndb/src/common/util/SocketServer.cpp @@ -64,6 +64,8 @@ SocketServer::tryBind(unsigned short port, const char * intface) { return false; } + DBUG_PRINT("info",("NDB_SOCKET: %d", sock)); + const int on = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { @@ -104,6 +106,8 @@ SocketServer::setup(SocketServer::Service * service, DBUG_RETURN(false); } + DBUG_PRINT("info",("NDB_SOCKET: %d", sock)); + const int on = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { diff --git a/storage/ndb/src/common/util/version.c b/storage/ndb/src/common/util/version.c index 4eff039e1b5..e87a342d7b1 100644 --- a/storage/ndb/src/common/util/version.c +++ b/storage/ndb/src/common/util/version.c @@ -38,22 +38,24 @@ Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build) { } -const char * getVersionString(Uint32 version, const char * status) { - char buff[100]; +char ndb_version_string_buf[NDB_VERSION_STRING_BUF_SZ]; +const char * getVersionString(Uint32 version, const char * status, + char *buf, unsigned sz) +{ if (status && status[0] != 0) - basestring_snprintf(buff, sizeof(buff), + basestring_snprintf(buf, sz, "Version %d.%d.%d (%s)", getMajor(version), getMinor(version), getBuild(version), status); else - basestring_snprintf(buff, sizeof(buff), + basestring_snprintf(buf, sz, "Version %d.%d.%d", getMajor(version), getMinor(version), getBuild(version)); - return strdup(buff); + return buf; } typedef enum { diff --git a/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp index bff79215264..e134609df0a 100644 --- a/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp +++ b/storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp @@ -257,8 +257,8 @@ private: void hbReceivedLab(Signal* signal); void sendCmRegrefLab(Signal* signal, BlockReference ref, CmRegRef::ErrorCode); - void systemErrorBecauseOtherNodeFailed(Signal* signal, NodeId); - void systemErrorLab(Signal* signal, + void systemErrorBecauseOtherNodeFailed(Signal* signal, Uint32 line, NodeId); + void systemErrorLab(Signal* signal, Uint32 line, const char* message = NULL); void prepFailReqLab(Signal* signal); void prepFailConfLab(Signal* signal); diff --git a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp index 04373dae93c..621ec70fbe1 100644 --- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp +++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp @@ -76,7 +76,7 @@ void Qmgr::execCM_HEARTBEAT(Signal* signal) void Qmgr::execCM_NODEINFOREF(Signal* signal) { jamEntry(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//Qmgr::execCM_NODEINFOREF() @@ -121,7 +121,7 @@ void Qmgr::execCONTINUEB(Signal* signal) default: jam(); // ZCOULD_NOT_OCCUR_ERROR; - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; break; }//switch @@ -593,7 +593,7 @@ void Qmgr::execCM_REGCONF(Signal* signal) jam(); char buf[128]; BaseString::snprintf(buf,sizeof(buf),"incompatible version own=0x%x other=0x%x, shutting down", NDB_VERSION, cmRegConf->presidentVersion); - systemErrorLab(signal, buf); + systemErrorLab(signal, __LINE__, buf); return; } @@ -688,7 +688,7 @@ void Qmgr::execCM_REGREF(Signal* signal) switch (TrefuseReason) { case CmRegRef::ZINCOMPATIBLE_VERSION: jam(); - systemErrorLab(signal, "incompatible version, connection refused by running ndb node"); + systemErrorLab(signal, __LINE__, "incompatible version, connection refused by running ndb node"); break; case CmRegRef::ZBUSY: case CmRegRef::ZBUSY_TO_PRES: @@ -1751,7 +1751,7 @@ void Qmgr::execAPI_FAILCONF(Signal* signal) if (failedNodePtr.p->rcv[0] == failedNodePtr.p->rcv[1]) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); } else { jam(); failedNodePtr.p->rcv[0] = 0; @@ -1763,7 +1763,7 @@ void Qmgr::execAPI_FAILCONF(Signal* signal) ndbout << "failedNodePtr.p->failState = " << (Uint32)(failedNodePtr.p->failState) << endl; #endif - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if return; }//Qmgr::execAPI_FAILCONF() @@ -1780,7 +1780,7 @@ void Qmgr::execNDB_FAILCONF(Signal* signal) failedNodePtr.p->failState = NORMAL; } else { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if if (cpresident == getOwnNodeId()) { jam(); @@ -1931,20 +1931,13 @@ void Qmgr::execAPI_REGREQ(Signal* signal) #endif bool compatability_check; - switch(getNodeInfo(apiNodePtr.i).getType()){ + NodeInfo::NodeType type= getNodeInfo(apiNodePtr.i).getType(); + switch(type){ case NodeInfo::API: compatability_check = ndbCompatible_ndb_api(NDB_VERSION, version); - if (!compatability_check) - infoEvent("Connection attempt from api or mysqld id=%d with %s " - "incompatible with %s", apiNodePtr.i, - getVersionString(version,""), NDB_VERSION_STRING); break; case NodeInfo::MGM: compatability_check = ndbCompatible_ndb_mgmt(NDB_VERSION, version); - if (!compatability_check) - infoEvent("Connection attempt from management server id=%d with %s " - "incompatible with %s", apiNodePtr.i, - getVersionString(version,""), NDB_VERSION_STRING); break; case NodeInfo::REP: // compatability_check = ndbCompatible_ndb_api(NDB_VERSION, version); @@ -1953,13 +1946,19 @@ void Qmgr::execAPI_REGREQ(Signal* signal) case NodeInfo::INVALID: default: sendApiRegRef(signal, ref, ApiRegRef::WrongType); - infoEvent("Invalid connection attempt with type %d", - getNodeInfo(apiNodePtr.i).getType()); + infoEvent("Invalid connection attempt with type %d", type); return; } if (!compatability_check) { jam(); + char buf[NDB_VERSION_STRING_BUF_SZ]; + infoEvent("Connection attempt from %s id=%d with %s " + "incompatible with %s", + type == NodeInfo::API ? "api or mysqld" : "management server", + apiNodePtr.i, + getVersionString(version,"",buf,sizeof(buf)), + NDB_VERSION_STRING); apiNodePtr.p->phase = ZAPI_INACTIVE; sendApiRegRef(signal, ref, ApiRegRef::UnsupportedVersion); return; @@ -2085,7 +2084,7 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode, ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec); if (failedNodePtr.i == getOwnNodeId()) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if @@ -2093,7 +2092,7 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode, ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec); if (myNodePtr.p->phase != ZRUNNING) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if TnoFailedNodes = cnoFailedNodes; @@ -2172,7 +2171,7 @@ void Qmgr::execPREP_FAILREQ(Signal* signal) ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec); if (myNodePtr.p->phase != ZRUNNING) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); return; }//if @@ -2675,7 +2674,7 @@ void Qmgr::execREAD_NODESREQ(Signal* signal) ReadNodesConf::SignalLength, JBB); }//Qmgr::execREAD_NODESREQ() -void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal, +void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal, Uint32 line, NodeId failedNodeId) { jam(); @@ -2687,11 +2686,11 @@ void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal, "Node was shutdown during startup because node %d failed", failedNodeId); - progError(__LINE__, ERR_SR_OTHERNODEFAILED, buf); + progError(line, ERR_SR_OTHERNODEFAILED, buf); } -void Qmgr::systemErrorLab(Signal* signal, const char * message) +void Qmgr::systemErrorLab(Signal* signal, Uint32 line, const char * message) { jam(); // Broadcast that this node is failing to other nodes @@ -2699,7 +2698,7 @@ void Qmgr::systemErrorLab(Signal* signal, const char * message) // If it's known why shutdown occured // an error message has been passed to this function - progError(__LINE__, 0, message); + progError(line, 0, message); return; }//Qmgr::systemErrorLab() @@ -2867,7 +2866,7 @@ Uint16 Qmgr::translateDynamicIdToNodeId(Signal* signal, UintR TdynamicId) }//for if (TtdiNodeId == ZNIL) { jam(); - systemErrorLab(signal); + systemErrorLab(signal, __LINE__); }//if return TtdiNodeId; }//Qmgr::translateDynamicIdToNodeId() diff --git a/storage/ndb/src/mgmapi/mgmapi.cpp b/storage/ndb/src/mgmapi/mgmapi.cpp index e5e00b78bfa..5808e2ed534 100644 --- a/storage/ndb/src/mgmapi/mgmapi.cpp +++ b/storage/ndb/src/mgmapi/mgmapi.cpp @@ -265,6 +265,9 @@ static const Properties * ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, const char *cmd, const Properties *cmd_args) { + DBUG_ENTER("ndb_mgm_call"); + DBUG_PRINT("enter",("handle->socket: %d, cmd: %s", + handle->socket, cmd)); SocketOutputStream out(handle->socket); SocketInputStream in(handle->socket, handle->read_timeout); @@ -331,7 +334,8 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, << "' status=" << (Uint32)ctx.m_status << ", curr=" << ctx.m_currentToken << endl; - DBUG_PRINT("info",("parser.parse returned NULL")); + DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s", + ctx.m_status, ctx.m_currentToken)); } #ifdef MGMAPI_LOG else { @@ -341,7 +345,7 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, p->print(handle->logfile, "IN: "); } #endif - return p; + DBUG_RETURN(p); } /** diff --git a/storage/ndb/src/mgmapi/ndb_logevent.cpp b/storage/ndb/src/mgmapi/ndb_logevent.cpp index 2817abcfdbb..27e7c1f36f5 100644 --- a/storage/ndb/src/mgmapi/ndb_logevent.cpp +++ b/storage/ndb/src/mgmapi/ndb_logevent.cpp @@ -369,6 +369,9 @@ int ndb_logevent_get_next(const NdbLogEventHandle h, Properties p; char buf[256]; + struct timeval start_time; + gettimeofday(&start_time, 0); + /* header */ while (1) { if (in.gets(buf,sizeof(buf)) == 0) @@ -383,7 +386,22 @@ int ndb_logevent_get_next(const NdbLogEventHandle h, } if ( strcmp("log event reply\n", buf) == 0 ) break; - ndbout_c("skipped: %s", buf); + + if ( strcmp("\n", buf) ) + ndbout_c("skipped: %s", buf); + + struct timeval now; + gettimeofday(&now, 0); + unsigned elapsed_ms= (now.tv_sec-start_time.tv_sec)*1000 + + ((signed int)now.tv_usec-(signed int)start_time.tv_usec)/1000; + + if (elapsed_ms >= timeout_in_milliseconds) + { + // timed out + return 0; + } + + new (&in) SocketInputStream(h->socket, timeout_in_milliseconds-elapsed_ms); } /* read name-value pairs into properties object */ diff --git a/storage/ndb/src/mgmclient/CommandInterpreter.cpp b/storage/ndb/src/mgmclient/CommandInterpreter.cpp index 3b57e6d4860..72f6e7869b2 100644 --- a/storage/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/storage/ndb/src/mgmclient/CommandInterpreter.cpp @@ -455,11 +455,13 @@ static int do_event_thread; static void* event_thread_run(void* m) { + DBUG_ENTER("event_thread_run"); + NdbMgmHandle handle= *(NdbMgmHandle*)m; int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 }; int fd = ndb_mgm_listen_event(handle, filter); - if (fd > 0) + if (fd != NDB_INVALID_SOCKET) { do_event_thread= 1; char *tmp= 0; @@ -468,15 +470,20 @@ event_thread_run(void* m) do { if (tmp == 0) NdbSleep_MilliSleep(10); if((tmp = in.gets(buf, 1024))) - ndbout << tmp; + { + const char ping_token[]= ""; + if (memcmp(ping_token,tmp,sizeof(ping_token)-1)) + ndbout << tmp; + } } while(do_event_thread); + NDB_CLOSE_SOCKET(fd); } else { do_event_thread= -1; } - return NULL; + DBUG_RETURN(NULL); } bool @@ -516,9 +523,19 @@ CommandInterpreter::connect() do_event_thread == 0 || do_event_thread == -1) { - DBUG_PRINT("warning",("thread not started")); - printf("Warning, event thread startup failed, degraded printouts as result\n"); + DBUG_PRINT("info",("Warning, event thread startup failed, " + "degraded printouts as result, errno=%d", + errno)); + printf("Warning, event thread startup failed, " + "degraded printouts as result, errno=%d\n", errno); do_event_thread= 0; + if (m_event_thread) + { + void *res; + NdbThread_WaitFor(m_event_thread, &res); + NdbThread_Destroy(&m_event_thread); + } + ndb_mgm_disconnect(m_mgmsrv2); } } else @@ -548,6 +565,7 @@ CommandInterpreter::connect() bool CommandInterpreter::disconnect() { + DBUG_ENTER("CommandInterpreter::disconnect"); if (m_event_thread) { void *res; do_event_thread= 0; @@ -564,7 +582,7 @@ CommandInterpreter::disconnect() } m_connected= false; } - return true; + DBUG_RETURN(true); } //***************************************************************************** diff --git a/storage/ndb/src/mgmclient/main.cpp b/storage/ndb/src/mgmclient/main.cpp index 19c84f6ec8d..ba5d0308f1f 100644 --- a/storage/ndb/src/mgmclient/main.cpp +++ b/storage/ndb/src/mgmclient/main.cpp @@ -44,7 +44,9 @@ static Ndb_mgmclient* com; extern "C" void -handler(int sig){ +handler(int sig) +{ + DBUG_ENTER("handler"); switch(sig){ case SIGPIPE: /** @@ -54,6 +56,7 @@ handler(int sig){ com->disconnect(); break; } + DBUG_VOID_RETURN; } NDB_STD_OPTS_VARS; @@ -163,7 +166,8 @@ int main(int argc, char** argv){ com->execute(opt_execute_str,_try_reconnect, &ret); } delete com; - + + ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); return ret; } diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp index 6b9bf7a0978..51356cb75b1 100644 --- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -569,10 +569,11 @@ MgmtSrvr::check_start() bool MgmtSrvr::start(BaseString &error_string) { + DBUG_ENTER("MgmtSrvr::start"); if (_props == NULL) { if (!check_start()) { error_string.append("MgmtSrvr.cpp: check_start() failed."); - return false; + DBUG_RETURN(false); } } theFacade= TransporterFacade::theFacadeInstance @@ -581,12 +582,12 @@ MgmtSrvr::start(BaseString &error_string) if(theFacade == 0) { DEBUG("MgmtSrvr.cpp: theFacade is NULL."); error_string.append("MgmtSrvr.cpp: theFacade is NULL."); - return false; + DBUG_RETURN(false); } if ( theFacade->start_instance (_ownNodeId, (ndb_mgm_configuration*)_config->m_configValues) < 0) { DEBUG("MgmtSrvr.cpp: TransporterFacade::start_instance < 0."); - return false; + DBUG_RETURN(false); } MGM_REQUIRE(_blockNumber == 1); @@ -602,7 +603,7 @@ MgmtSrvr::start(BaseString &error_string) error_string.append("MgmtSrvr.cpp: _blockNumber is -1."); theFacade->stop_instance(); theFacade = 0; - return false; + DBUG_RETURN(false); } TransporterRegistry *reg = theFacade->get_registry(); @@ -624,7 +625,6 @@ MgmtSrvr::start(BaseString &error_string) DBUG_PRINT("info",("Set result: %d: %s",res,msg.c_str())); } - _ownReference = numberToRef(_blockNumber, _ownNodeId); startEventLog(); @@ -644,7 +644,7 @@ MgmtSrvr::start(BaseString &error_string) "MgmtSrvr_Service", NDB_THREAD_PRIO_LOW); - return true; + DBUG_RETURN(true); } @@ -658,6 +658,7 @@ MgmtSrvr::~MgmtSrvr() if(theFacade != 0){ theFacade->stop_instance(); + delete theFacade; theFacade = 0; } @@ -2141,6 +2142,24 @@ MgmtSrvr::getNodeType(NodeId nodeId) const return nodeTypes[nodeId]; } +const char *MgmtSrvr::get_connect_address(Uint32 node_id) +{ + if (m_connect_address[node_id].s_addr == 0 && + theFacade && theFacade->theTransporterRegistry && + theFacade->theClusterMgr && + getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB) + { + const ClusterMgr::Node &node= + theFacade->theClusterMgr->getNodeInfo(node_id); + if (node.connected) + { + m_connect_address[node_id]= + theFacade->theTransporterRegistry->get_connect_address(node_id); + } + } + return inet_ntoa(m_connect_address[node_id]); +} + void MgmtSrvr::get_connected_nodes(NodeBitmask &connected_nodes) const { @@ -2604,19 +2623,6 @@ MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted) } -/***************************************************************************** - * Area 51 ??? - *****************************************************************************/ - -MgmtSrvr::Area51 -MgmtSrvr::getStuff() -{ - Area51 ret; - ret.theFacade = theFacade; - ret.theRegistry = theFacade->theTransporterRegistry; - return ret; -} - NodeId MgmtSrvr::getPrimaryNode() const { #if 0 diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp index 7e13b41438f..b7983e6b441 100644 --- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -61,6 +61,7 @@ public: } void add_listener(const Event_listener&); + void check_listeners(); void update_max_log_level(const LogLevel&); void update_log_level(const LogLevel&); @@ -519,7 +520,7 @@ public: ConfigRetriever *get_config_retriever() { return m_config_retriever; }; - const char *get_connect_address(Uint32 node_id) { return inet_ntoa(m_connect_address[node_id]); } + const char *get_connect_address(Uint32 node_id); void get_connected_nodes(NodeBitmask &connected_nodes) const; SocketServer *get_socket_server() { return m_socket_server; } @@ -775,16 +776,6 @@ private: int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type); ConfigRetriever *m_config_retriever; - -public: - /** - * This method does not exist - */ - struct Area51 { - class TransporterFacade * theFacade; - class TransporterRegistry * theRegistry; - }; - Area51 getStuff(); }; inline diff --git a/storage/ndb/src/mgmsrv/Services.cpp b/storage/ndb/src/mgmsrv/Services.cpp index 1a5101702a0..270d7f716dd 100644 --- a/storage/ndb/src/mgmsrv/Services.cpp +++ b/storage/ndb/src/mgmsrv/Services.cpp @@ -272,15 +272,19 @@ ParserRow commands[] = { }; MgmApiSession::MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock) - : SocketServer::Session(sock), m_mgmsrv(mgm) { + : SocketServer::Session(sock), m_mgmsrv(mgm) +{ + DBUG_ENTER("MgmApiSession::MgmApiSession"); m_input = new SocketInputStream(sock); m_output = new SocketOutputStream(sock); m_parser = new Parser_t(commands, *m_input, true, true, true); m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv); + DBUG_VOID_RETURN; } MgmApiSession::~MgmApiSession() { + DBUG_ENTER("MgmApiSession::~MgmApiSession"); if (m_input) delete m_input; if (m_output) @@ -289,10 +293,19 @@ MgmApiSession::~MgmApiSession() delete m_parser; if (m_allocated_resources) delete m_allocated_resources; + if(m_socket != NDB_INVALID_SOCKET) + { + NDB_CLOSE_SOCKET(m_socket); + m_socket= NDB_INVALID_SOCKET; + } + DBUG_VOID_RETURN; } void -MgmApiSession::runSession() { +MgmApiSession::runSession() +{ + DBUG_ENTER("MgmApiSession::runSession"); + Parser_t::Context ctx; while(!m_stop) { m_parser->run(ctx, *this); @@ -321,7 +334,12 @@ MgmApiSession::runSession() { } } if(m_socket != NDB_INVALID_SOCKET) + { NDB_CLOSE_SOCKET(m_socket); + m_socket= NDB_INVALID_SOCKET; + } + + DBUG_VOID_RETURN; } #ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT @@ -1259,7 +1277,7 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId) LogLevel::EventCategory cat; Logger::LoggerLevel severity; EventLoggerBase::EventTextFunction textF; - int i; + int i, n; DBUG_ENTER("Ndb_mgmd_event_service::log"); DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId)); @@ -1286,19 +1304,22 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId) Vector copy; m_clients.lock(); - for(i = m_clients.size() - 1; i >= 0; i--){ - if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat)){ - if(m_clients[i].m_socket != NDB_INVALID_SOCKET) + for(i = m_clients.size() - 1; i >= 0; i--) + { + if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat)) + { + NDB_SOCKET_TYPE fd= m_clients[i].m_socket; + if(fd != NDB_INVALID_SOCKET) { int r; if (m_clients[i].m_parsable) - r= println_socket(m_clients[i].m_socket, + r= println_socket(fd, MAX_WRITE_TIMEOUT, str.c_str()); else - r= println_socket(m_clients[i].m_socket, + r= println_socket(fd, MAX_WRITE_TIMEOUT, m_text); if (r == -1) { - copy.push_back(m_clients[i].m_socket); + copy.push_back(fd); m_clients.erase(i, false); } } @@ -1306,16 +1327,15 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId) } m_clients.unlock(); - for(i = 0; (unsigned)i < copy.size(); i++){ - NDB_CLOSE_SOCKET(copy[i]); - } + if ((n= (int)copy.size())) + { + for(i= 0; i < n; i++) + NDB_CLOSE_SOCKET(copy[i]); - if(copy.size()){ LogLevel tmp; tmp.clear(); m_clients.lock(); - for(i = 0; (unsigned)i < m_clients.size(); i++){ + for(i= m_clients.size() - 1; i >= 0; i--) tmp.set_max(m_clients[i].m_logLevel); - } m_clients.unlock(); update_log_level(tmp); } @@ -1343,9 +1363,48 @@ Ndb_mgmd_event_service::update_log_level(const LogLevel &tmp) } void -Ndb_mgmd_event_service::add_listener(const Event_listener& client){ +Ndb_mgmd_event_service::check_listeners() +{ + int i, n= 0; + DBUG_ENTER("Ndb_mgmd_event_service::check_listeners"); + m_clients.lock(); + for(i= m_clients.size() - 1; i >= 0; i--) + { + int fd= m_clients[i].m_socket; + DBUG_PRINT("info",("%d %d",i,fd)); + char buf[1]; + buf[0]=0; + if (fd != NDB_INVALID_SOCKET && + println_socket(fd,MAX_WRITE_TIMEOUT,"") == -1) + { + NDB_CLOSE_SOCKET(fd); + m_clients.erase(i, false); + n=1; + } + } + if (n) + { + LogLevel tmp; tmp.clear(); + for(i= m_clients.size() - 1; i >= 0; i--) + tmp.set_max(m_clients[i].m_logLevel); + update_log_level(tmp); + } + m_clients.unlock(); + DBUG_VOID_RETURN; +} + +void +Ndb_mgmd_event_service::add_listener(const Event_listener& client) +{ + DBUG_ENTER("Ndb_mgmd_event_service::add_listener"); + DBUG_PRINT("enter",("client.m_socket: %d", client.m_socket)); + + check_listeners(); + m_clients.push_back(client); update_max_log_level(client.m_logLevel); + + DBUG_VOID_RETURN; } void diff --git a/storage/ndb/src/mgmsrv/main.cpp b/storage/ndb/src/mgmsrv/main.cpp index c7315c61ba1..07b369d4ebc 100644 --- a/storage/ndb/src/mgmsrv/main.cpp +++ b/storage/ndb/src/mgmsrv/main.cpp @@ -96,16 +96,17 @@ read_and_execute(Ndb_mgmclient* com, const char * prompt, int _try_reconnect) * @struct MgmGlobals * @brief Global Variables used in the management server *****************************************************************************/ + +/** Command line arguments */ +static int opt_daemon; // NOT bool, bool need not be int +static int opt_non_interactive; +static int opt_interactive; +static const char * opt_config_filename= 0; + struct MgmGlobals { MgmGlobals(); ~MgmGlobals(); - /** Command line arguments */ - int daemon; // NOT bool, bool need not be int - int non_interactive; - int interactive; - const char * config_filename; - /** Stuff found in environment or in local config */ NodeId localNodeId; bool use_specific_ip; @@ -120,7 +121,7 @@ struct MgmGlobals { }; int g_no_nodeid_checks= 0; -static MgmGlobals glob; +static MgmGlobals *glob= 0; /****************************************************************************** * Function prototypes @@ -144,14 +145,14 @@ static struct my_option my_long_options[] = { NDB_STD_OPTS("ndb_mgmd"), { "config-file", 'f', "Specify cluster configuration file", - (gptr*) &glob.config_filename, (gptr*) &glob.config_filename, 0, + (gptr*) &opt_config_filename, (gptr*) &opt_config_filename, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "daemon", 'd', "Run ndb_mgmd in daemon mode (default)", - (gptr*) &glob.daemon, (gptr*) &glob.daemon, 0, + (gptr*) &opt_daemon, (gptr*) &opt_daemon, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, { "interactive", OPT_INTERACTIVE, "Run interactive. Not supported but provided for testing purposes", - (gptr*) &glob.interactive, (gptr*) &glob.interactive, 0, + (gptr*) &opt_interactive, (gptr*) &opt_interactive, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "no-nodeid-checks", OPT_NO_NODEID_CHECKS, "Do not provide any node id checks", @@ -159,7 +160,7 @@ static struct my_option my_long_options[] = GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "nodaemon", OPT_NO_DAEMON, "Don't run as daemon, but don't read from stdin", - (gptr*) &glob.non_interactive, (gptr*) &glob.non_interactive, 0, + (gptr*) &opt_non_interactive, (gptr*) &opt_non_interactive, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -182,6 +183,7 @@ static void usage() int main(int argc, char** argv) { NDB_INIT(argv[0]); + glob= new MgmGlobals; /** * OSE specific. Enable shared ownership of file system resources. @@ -205,40 +207,40 @@ int main(int argc, char** argv) ndb_std_get_one_option))) exit(ho_error); - if (glob.interactive || - glob.non_interactive) { - glob.daemon= 0; + if (opt_interactive || + opt_non_interactive) { + opt_daemon= 0; } - glob.socketServer = new SocketServer(); + glob->socketServer = new SocketServer(); MgmApiService * mapi = new MgmApiService(); - glob.mgmObject = new MgmtSrvr(glob.socketServer, - glob.config_filename, + glob->mgmObject = new MgmtSrvr(glob->socketServer, + opt_config_filename, opt_connect_str); - if (glob.mgmObject->init()) + if (glob->mgmObject->init()) goto error_end; my_setwd(NdbConfig_get_path(0), MYF(0)); - glob.localNodeId= glob.mgmObject->getOwnNodeId(); - if (glob.localNodeId == 0) { + glob->localNodeId= glob->mgmObject->getOwnNodeId(); + if (glob->localNodeId == 0) { goto error_end; } - glob.port= glob.mgmObject->getPort(); + glob->port= glob->mgmObject->getPort(); - if (glob.port == 0) + if (glob->port == 0) goto error_end; - glob.interface_name = 0; - glob.use_specific_ip = false; + glob->interface_name = 0; + glob->use_specific_ip = false; - if(!glob.use_specific_ip){ + if(!glob->use_specific_ip){ int count= 5; // no of retries for tryBind - while(!glob.socketServer->tryBind(glob.port, glob.interface_name)){ + while(!glob->socketServer->tryBind(glob->port, glob->interface_name)){ if (--count > 0) { NdbSleep_MilliSleep(1000); continue; @@ -247,19 +249,20 @@ int main(int argc, char** argv) "Please check if the port is already used,\n" "(perhaps a ndb_mgmd is already running),\n" "and if you are executing on the correct computer", - (glob.interface_name ? glob.interface_name : "*"), glob.port); + (glob->interface_name ? glob->interface_name : "*"), glob->port); goto error_end; } - free(glob.interface_name); - glob.interface_name = 0; + free(glob->interface_name); + glob->interface_name = 0; } - if(!glob.socketServer->setup(mapi, &glob.port, glob.interface_name)){ + if(!glob->socketServer->setup(mapi, &glob->port, glob->interface_name)) + { ndbout_c("Unable to setup management port: %d!\n" "Please check if the port is already used,\n" "(perhaps a ndb_mgmd is already running),\n" "and if you are executing on the correct computer", - glob.port); + glob->port); delete mapi; goto error_end; } @@ -267,12 +270,12 @@ int main(int argc, char** argv) /* Construct a fake connectstring to connect back to ourselves */ char connect_str[20]; if(!opt_connect_str) { - snprintf(connect_str,20,"localhost:%u",glob.mgmObject->getPort()); + snprintf(connect_str,20,"localhost:%u",glob->mgmObject->getPort()); opt_connect_str= connect_str; } - glob.mgmObject->set_connect_string(opt_connect_str); + glob->mgmObject->set_connect_string(opt_connect_str); - if(!glob.mgmObject->check_start()){ + if(!glob->mgmObject->check_start()){ ndbout_c("Unable to check start management server."); ndbout_c("Probably caused by illegal initial configuration file."); goto error_end; @@ -283,7 +286,7 @@ int main(int argc, char** argv) * config info */ int mgm_connect_result; - mgm_connect_result = glob.mgmObject->get_config_retriever()-> + mgm_connect_result = glob->mgmObject->get_config_retriever()-> do_connect(0,0,0); if(mgm_connect_result<0) { @@ -292,11 +295,10 @@ int main(int argc, char** argv) ndbout_c("This is probably a bug."); } - - if (glob.daemon) { + if (opt_daemon) { // Become a daemon - char *lockfile= NdbConfig_PidFileName(glob.localNodeId); - char *logfile= NdbConfig_StdoutFileName(glob.localNodeId); + char *lockfile= NdbConfig_PidFileName(glob->localNodeId); + char *logfile= NdbConfig_StdoutFileName(glob->localNodeId); NdbAutoPtr tmp_aptr1(lockfile), tmp_aptr2(logfile); if (NdbDaemon_Make(lockfile, logfile, 0) == -1) { @@ -310,7 +312,7 @@ int main(int argc, char** argv) #endif { BaseString error_string; - if(!glob.mgmObject->start(error_string)){ + if(!glob->mgmObject->start(error_string)){ ndbout_c("Unable to start management server."); ndbout_c("Probably caused by illegal initial configuration file."); ndbout_c(error_string.c_str()); @@ -318,8 +320,8 @@ int main(int argc, char** argv) } } - //glob.mgmObject->saveConfig(); - mapi->setMgm(glob.mgmObject); + //glob->mgmObject->saveConfig(); + mapi->setMgm(glob->mgmObject); char msg[256]; BaseString::snprintf(msg, sizeof(msg), @@ -328,20 +330,20 @@ int main(int argc, char** argv) g_eventLogger.info(msg); BaseString::snprintf(msg, 256, "Id: %d, Command port: %d", - glob.localNodeId, glob.port); + glob->localNodeId, glob->port); ndbout_c(msg); g_eventLogger.info(msg); g_StopServer = false; - glob.socketServer->startServer(); + glob->socketServer->startServer(); #if ! defined NDB_OSE && ! defined NDB_SOFTOSE - if(glob.interactive) { + if(opt_interactive) { BaseString con_str; - if(glob.interface_name) - con_str.appfmt("host=%s:%d", glob.interface_name, glob.port); + if(glob->interface_name) + con_str.appfmt("host=%s:%d", glob->interface_name, glob->port); else - con_str.appfmt("localhost:%d", glob.port); + con_str.appfmt("localhost:%d", glob->port); Ndb_mgmclient com(con_str.c_str(), 1); while(g_StopServer != true && read_and_execute(&com, "ndb_mgm> ", 1)); } else @@ -352,23 +354,23 @@ int main(int argc, char** argv) } g_eventLogger.info("Shutting down server..."); - glob.socketServer->stopServer(); - glob.mgmObject->get_config_retriever()->disconnect(); - glob.socketServer->stopSessions(true); + glob->socketServer->stopServer(); + glob->mgmObject->get_config_retriever()->disconnect(); + glob->socketServer->stopSessions(true); g_eventLogger.info("Shutdown complete"); + delete glob; + ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); return 0; error_end: + delete glob; + ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); return 1; } MgmGlobals::MgmGlobals(){ // Default values port = 0; - config_filename = NULL; interface_name = 0; - daemon = 1; - non_interactive = 0; - interactive = 0; socketServer = 0; mgmObject = 0; } diff --git a/storage/ndb/src/ndbapi/ClusterMgr.cpp b/storage/ndb/src/ndbapi/ClusterMgr.cpp index 42b3b01bca1..ef9367ef10e 100644 --- a/storage/ndb/src/ndbapi/ClusterMgr.cpp +++ b/storage/ndb/src/ndbapi/ClusterMgr.cpp @@ -64,16 +64,21 @@ ClusterMgr::ClusterMgr(TransporterFacade & _facade): theStop(0), theFacade(_facade) { + DBUG_ENTER("ClusterMgr::ClusterMgr"); ndbSetOwnVersion(); clusterMgrThreadMutex = NdbMutex_Create(); noOfAliveNodes= 0; noOfConnectedNodes= 0; theClusterMgrThread= 0; + DBUG_VOID_RETURN; } -ClusterMgr::~ClusterMgr(){ +ClusterMgr::~ClusterMgr() +{ + DBUG_ENTER("ClusterMgr::~ClusterMgr"); doStop(); NdbMutex_Destroy(clusterMgrThreadMutex); + DBUG_VOID_RETURN; } void @@ -152,7 +157,6 @@ ClusterMgr::doStop( ){ if (theClusterMgrThread) { NdbThread_WaitFor(theClusterMgrThread, &status); NdbThread_Destroy(&theClusterMgrThread); - theClusterMgrThread= 0; } NdbMutex_Unlock(clusterMgrThreadMutex); DBUG_VOID_RETURN; @@ -481,6 +485,8 @@ ClusterMgr::reportNodeFailed(NodeId nodeId){ ArbitMgr::ArbitMgr(TransporterFacade & _fac) : theFacade(_fac) { + DBUG_ENTER("ArbitMgr::ArbitMgr"); + theThreadMutex = NdbMutex_Create(); theInputCond = NdbCondition_Create(); theInputMutex = NdbMutex_Create(); @@ -498,13 +504,17 @@ ArbitMgr::ArbitMgr(TransporterFacade & _fac) memset(&theChooseReq1, 0, sizeof(theChooseReq1)); memset(&theChooseReq2, 0, sizeof(theChooseReq2)); memset(&theStopOrd, 0, sizeof(theStopOrd)); + + DBUG_VOID_RETURN; } ArbitMgr::~ArbitMgr() { + DBUG_ENTER("ArbitMgr::~ArbitMgr"); NdbMutex_Destroy(theThreadMutex); NdbCondition_Destroy(theInputCond); NdbMutex_Destroy(theInputMutex); + DBUG_VOID_RETURN; } // Start arbitrator thread. This is kernel request. @@ -521,7 +531,7 @@ ArbitMgr::doStart(const Uint32* theData) sendSignalToThread(aSignal); void* value; NdbThread_WaitFor(theThread, &value); - theThread = NULL; + NdbThread_Destroy(&theThread); theState = StateInit; theInputFull = false; } @@ -560,7 +570,7 @@ ArbitMgr::doStop(const Uint32* theData) sendSignalToThread(aSignal); void* value; NdbThread_WaitFor(theThread, &value); - theThread = NULL; + NdbThread_Destroy(&theThread); theState = StateInit; } NdbMutex_Unlock(theThreadMutex); diff --git a/storage/ndb/src/ndbapi/TransporterFacade.cpp b/storage/ndb/src/ndbapi/TransporterFacade.cpp index e2aa6631841..96f376db5a5 100644 --- a/storage/ndb/src/ndbapi/TransporterFacade.cpp +++ b/storage/ndb/src/ndbapi/TransporterFacade.cpp @@ -395,12 +395,10 @@ TransporterFacade::doStop(){ if (theReceiveThread) { NdbThread_WaitFor(theReceiveThread, &status); NdbThread_Destroy(&theReceiveThread); - theReceiveThread= 0; } if (theSendThread) { NdbThread_WaitFor(theSendThread, &status); NdbThread_Destroy(&theSendThread); - theSendThread= 0; } DBUG_VOID_RETURN; } @@ -435,7 +433,7 @@ void TransporterFacade::threadMainSend(void) theTransporterRegistry->stopSending(); m_socket_server.stopServer(); - m_socket_server.stopSessions(); + m_socket_server.stopSessions(true); theTransporterRegistry->stop_clients(); } @@ -477,6 +475,8 @@ TransporterFacade::TransporterFacade() : theReceiveThread(NULL), m_fragmented_signal_id(0) { + DBUG_ENTER("TransporterFacade::TransporterFacade"); + theOwnId = 0; theMutexPtr = NdbMutex_Create(); @@ -493,11 +493,15 @@ TransporterFacade::TransporterFacade() : m_max_trans_id = 0; theClusterMgr = new ClusterMgr(* this); + + DBUG_VOID_RETURN; } bool TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props) { + DBUG_ENTER("TransporterFacade::init"); + theOwnId = nodeId; theTransporterRegistry = new TransporterRegistry(this); @@ -506,7 +510,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props) * theTransporterRegistry); if(res <= 0){ TRP_DEBUG( "configureTransporters returned 0 or less" ); - return false; + DBUG_RETURN(false); } ndb_mgm_configuration_iterator iter(* props, CFG_SECTION_NODE); @@ -516,7 +520,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props) iter.first(); if(iter.find(CFG_NODE_ID, nodeId)){ TRP_DEBUG( "Node info missing from config." ); - return false; + DBUG_RETURN(false); } Uint32 rank = 0; @@ -542,7 +546,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props) if (!theTransporterRegistry->start_service(m_socket_server)){ ndbout_c("Unable to start theTransporterRegistry->start_service"); - return false; + DBUG_RETURN(false); } theReceiveThread = NdbThread_Create(runReceiveResponse_C, @@ -562,7 +566,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props) signalLogger.logOn(true, 0, SignalLoggerManager::LogInOut); #endif - return true; + DBUG_RETURN(true); } @@ -683,8 +687,10 @@ TransporterFacade::open(void* objRef, DBUG_RETURN(r); } -TransporterFacade::~TransporterFacade(){ - +TransporterFacade::~TransporterFacade() +{ + DBUG_ENTER("TransporterFacade::~TransporterFacade"); + NdbMutex_Lock(theMutexPtr); delete theClusterMgr; delete theArbitMgr; @@ -694,6 +700,7 @@ TransporterFacade::~TransporterFacade(){ #ifdef API_TRACE signalLogger.setOutputStream(0); #endif + DBUG_VOID_RETURN; } void diff --git a/storage/ndb/tools/restore/restore_main.cpp b/storage/ndb/tools/restore/restore_main.cpp index 93c40d31adb..d980f29057b 100644 --- a/storage/ndb/tools/restore/restore_main.cpp +++ b/storage/ndb/tools/restore/restore_main.cpp @@ -255,8 +255,9 @@ main(int argc, char** argv) const BackupFormat::FileHeader & tmp = metaData.getFileHeader(); const Uint32 version = tmp.NdbVersion; + char buf[NDB_VERSION_STRING_BUF_SZ]; ndbout << "Ndb version in backup files: " - << getVersionString(version, 0) << endl; + << getVersionString(version, 0, buf, sizeof(buf)) << endl; /** * check wheater we can restore the backup (right version). diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 0fa668b29ac..3e8e4e5abd1 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -440,19 +440,20 @@ then /sbin/chkconfig --add mysql fi -# Create a MySQL user. Do not report any problems if it already -# exists. This is redhat specific and should be handled more portable -useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" %{mysqld_user} 2> /dev/null || true +# Create a MySQL user and group. Do not report any problems if it already +# exists. +groupadd -r -c "MySQL server" %{mysqld_user} 2> /dev/null || true +useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" -g %{mysqld_user} %{mysqld_user} 2> /dev/null || true # Change permissions so that the user that will run the MySQL daemon # owns all database files. -chown -R %{mysqld_user} $mysql_datadir +chown -R %{mysqld_user}:%{mysqld_user} $mysql_datadir # Initiate databases %{_bindir}/mysql_install_db --rpm --user=%{mysqld_user} # Change permissions again to fix any new files. -chown -R %{mysqld_user} $mysql_datadir +chown -R %{mysqld_user}:%{mysqld_user} $mysql_datadir # Fix permissions for the permission database so that only the user # can read them. @@ -666,6 +667,11 @@ fi # itself - note that they must be ordered by date (important when # merging BK trees) %changelog +* Fri Jul 15 2005 Lenz Grimmer + +- create a "mysql" user group and assign the mysql user account to that group + in the server postinstall section. (BUG 10984) + * Tue Jun 14 2005 Lenz Grimmer - Do not build statically on i386 by default, only when adding either "--with diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index ffb848a6ef2..a056814a153 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -698,7 +698,7 @@ static void verify_prepare_field(MYSQL_RES *result, fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", field->org_table, org_table); fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); - fprintf(stdout, "\n length :`%ld`\t(expected: `%ld`)", + fprintf(stdout, "\n length :`%lu`\t(expected: `%lu`)", field->length, length * cs->mbmaxlen); fprintf(stdout, "\n maxlength:`%ld`", field->max_length); fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); @@ -13050,27 +13050,6 @@ static void test_bug9478() check_execute(stmt, rc); if (!opt_silent && i == 0) printf("Fetched row: %s\n", a); - /* - Although protocol-wise an attempt to execute a statement which - already has an open cursor associated with it will yield an error, - the client library behavior tested here is consistent with - the non-cursor execution scenario: mysql_stmt_execute will - silently close the cursor if necessary. - */ - { - char buff[9]; - /* Fill in the execute packet */ - int4store(buff, stmt->stmt_id); - buff[4]= 0; /* Flag */ - int4store(buff+5, 1); /* Reserved for array bind */ - rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_EXECUTE, buff, - sizeof(buff), 0,0,1) || - (*mysql->methods->read_query_result)(mysql)); - DIE_UNLESS(rc); - if (!opt_silent && i == 0) - printf("Got error (as expected): %s\n", mysql_error(mysql)); - } - rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -13429,7 +13408,7 @@ static void test_bug10794() bind[1].length= &a_len; rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - for (i= 0; i < 34; i++) + for (i= 0; i < 42; i++) { id_val= (i+1)*10; sprintf(a, "a%d", i); @@ -13616,7 +13595,6 @@ static void test_bug11656() static void test_bug10214() { - MYSQL_RES* res ; int len; char out[8]; @@ -13639,20 +13617,93 @@ static void test_bug10214() static void test_client_character_set() { MY_CHARSET_INFO cs; - const char *csname; + char *csname; int rc; myheader("test_client_character_set"); - csname = "utf8"; - rc = mysql_set_character_set(mysql, csname); + csname= (char*) "utf8"; + rc= mysql_set_character_set(mysql, csname); DIE_UNLESS(rc == 0); mysql_get_character_set_info(mysql, &cs); DIE_UNLESS(!strcmp(cs.csname, "utf8")); DIE_UNLESS(!strcmp(cs.name, "utf8_general_ci")); + /* Restore the default character set */ + rc= mysql_query(mysql, "set names default"); + myquery(rc); } +/* Test correct max length for MEDIUMTEXT and LONGTEXT columns */ + +static void test_bug9735() +{ + MYSQL_RES *res; + int rc; + + myheader("test_bug9735"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (a mediumtext, b longtext) " + "character set latin1"); + myquery(rc); + rc= mysql_query(mysql, "select * from t1"); + myquery(rc); + res= mysql_store_result(mysql); + verify_prepare_field(res, 0, "a", "a", MYSQL_TYPE_BLOB, + "t1", "t1", current_db, (1U << 24)-1, 0); + verify_prepare_field(res, 1, "b", "b", MYSQL_TYPE_BLOB, + "t1", "t1", current_db, ~0U, 0); + mysql_free_result(res); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11183 "mysql_stmt_reset() doesn't reset information about error" */ + +static void test_bug11183() +{ + int rc; + MYSQL_STMT *stmt; + char bug_statement[]= "insert into t1 values (1)"; + + myheader("test_bug11183"); + + mysql_query(mysql, "drop table t1 if exists"); + mysql_query(mysql, "create table t1 (a int)"); + + stmt= mysql_stmt_init(mysql); + DIE_UNLESS(stmt != 0); + + rc= mysql_stmt_prepare(stmt, bug_statement, strlen(bug_statement)); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + + /* Trying to execute statement that should fail on execute stage */ + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc); + + mysql_stmt_reset(stmt); + DIE_UNLESS(mysql_stmt_errno(stmt) == 0); + + mysql_query(mysql, "create table t1 (a int)"); + + /* Trying to execute statement that should pass ok */ + if (mysql_stmt_execute(stmt)) + { + mysql_stmt_reset(stmt); + DIE_UNLESS(mysql_stmt_errno(stmt) == 0); + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} /* Read and parse arguments and MySQL options from my.cnf @@ -13895,6 +13946,8 @@ static struct my_tests_st my_tests[]= { { "test_bug11172", test_bug11172 }, { "test_bug11656", test_bug11656 }, { "test_bug10214", test_bug10214 }, + { "test_bug9735", test_bug9735 }, + { "test_bug11183", test_bug11183 }, { 0, 0 } };