diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index bd45ae65224..b850584df5b 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -31,6 +31,7 @@ bk@mysql.r18.ru brian@avenger.(none) brian@brian-akers-computer.local carsten@tsort.bitbybit.dk +cps@silver_beast.(none) davida@isil.mysql.com dlenev@brandersnatch.localdomain dlenev@build.mysql.com diff --git a/include/my_sys.h b/include/my_sys.h index 0cfad5750c1..2ac86df87e8 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -506,6 +506,10 @@ my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ typedef uint32 ha_checksum; +/* Define the type of function to be passed to process_default_option_files */ +typedef int (*Process_option_func)(void *ctx, const char *group_name, + const char *option); + #include /* Prototypes for mysys and my_func functions */ @@ -740,6 +744,9 @@ extern char *strmake_root(MEM_ROOT *root,const char *str,uint len); extern char *memdup_root(MEM_ROOT *root,const char *str,uint len); extern int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); +extern int process_default_option_files(const char *conf_file, + Process_option_func func, + void *func_ctx); extern void free_defaults(char **argv); extern void print_defaults(const char *conf_file, const char **groups); extern my_bool my_compress(byte *, ulong *, ulong *); diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 3ee12fa9580..432919db04b 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -365,7 +365,7 @@ #define ER_WRONG_OBJECT 1346 #define ER_NONUPDATEABLE_COLUMN 1347 #define ER_VIEW_SELECT_DERIVED 1348 -#define ER_VIEW_SELECT_PROCEDURE 1349 +#define ER_VIEW_SELECT_CLAUSE 1349 #define ER_VIEW_SELECT_VARIABLE 1350 #define ER_VIEW_SELECT_TMPTABLE 1351 #define ER_VIEW_WRONG_LIST 1352 @@ -374,4 +374,4 @@ #define ER_VIEW_INVALID 1355 #define ER_SP_NO_DROP_SP 1356 #define ER_SP_GOTO_IN_HNDLR 1357 -#define ER_ERROR_MESSAGES 357 +#define ER_ERROR_MESSAGES 358 diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 2dd35809a7b..a93a89f797f 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2384,7 +2384,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) char buff[4 /* size of stmt id */ + 5 /* execution flags */]; DBUG_ENTER("execute"); - DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); + DBUG_DUMP("packet", packet, length); mysql->last_used_con= mysql; int4store(buff, stmt->stmt_id); /* Send stmt id to server */ diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index dba21877644..75d0c9a7e3b 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -141,7 +141,7 @@ COALESCE('a' COLLATE latin1_bin,'b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate _latin1'latin1_bin'),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')` +Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate latin1_bin),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')` SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index 36bd9a36d1c..f0445199744 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -43,7 +43,7 @@ explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using filesort Warnings: -Note 1003 select if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate _latin1'BINARY')) AS `s` from `test`.`t1` where (`test`.`t1`.`st` like _latin1'%a%') order by if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate _latin1'BINARY')) +Note 1003 select if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate BINARY)) AS `s` from `test`.`t1` where (`test`.`t1`.`st` like _latin1'%a%') order by if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate BINARY)) select nullif(u=0, 'test') from t1; nullif(u=0, 'test') NULL diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 025ea02e454..f264103390d 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -146,7 +146,7 @@ explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (_latin1'a' in (`test`.`t1`.`a`,`test`.`t1`.`b`,(`test`.`t1`.`c` collate _latin1'latin1_bin'))) +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (_latin1'a' in (`test`.`t1`.`a`,`test`.`t1`.`b`,(`test`.`t1`.`c` collate latin1_bin))) drop table t1; select '1.0' in (1,2); '1.0' in (1,2) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index e07ee4f0add..6495b81c195 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -638,7 +638,7 @@ explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'moo id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,(_latin1'HE' collate _latin1'BINARY') AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate _latin1'latin1_bin'),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")` +Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,(_latin1'HE' collate BINARY) AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate latin1_bin),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")` SELECT lpad(12345, 5, "#"); lpad(12345, 5, "#") 12345 diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index a969bf390bc..6f8bc702a80 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -108,7 +108,7 @@ explain extended select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select (_koi8r'a' = (_koi8r'A' collate _latin1'koi8r_general_ci')) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci` +Note 1003 select (_koi8r'a' = (_koi8r'A' collate koi8r_general_ci)) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci` select _koi8r'a' = _koi8r'A' COLLATE koi8r_bin; _koi8r'a' = _koi8r'A' COLLATE koi8r_bin 0 diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 9abb60634d9..afd8c3430b3 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1764,6 +1764,26 @@ call bug5251()| Table Checksum test.t1 0 drop procedure bug5251| +create procedure bug5287(param1 int) +label1: +begin +declare c cursor for select 5; +loop +if param1 >= 0 then +leave label1; +end if; +end loop; +end| +call bug5287(1)| +drop procedure bug5287| +create procedure bug5307() +begin +end; set @x = 3| +call bug5307()| +select @x| +@x +3 +drop procedure bug5307| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| create procedure ifac(n int unsigned) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 80dd5c4077a..cdde932f851 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -186,7 +186,7 @@ id select_type table type possible_keys key key_len ref rows Extra 4 SUBQUERY t2 ALL NULL NULL NULL NULL 2 NULL UNION RESULT ALL NULL NULL NULL NULL NULL Warnings: -Note 1003 (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = (select `test`.`t3`.`a` AS `a` from `test`.`t3` order by `test`.`t3`.`a` desc limit 1))) union (select `test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t4` where (`test`.`t4`.`b` = (select (max(`test`.`t2`.`a`) * 4) AS `max(t2.a)*4` from `test`.`t2`)) order by `test`.`t4`.`a`) +Note 1003 (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = (select `test`.`t3`.`a` AS `a` from `test`.`t3` order by 1 desc limit 1))) union (select `test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t4` where (`test`.`t4`.`b` = (select (max(`test`.`t2`.`a`) * 4) AS `max(t2.a)*4` from `test`.`t2`)) order by `test`.`t4`.`a`) select (select a from t3 where a 1)) `tt` +Note 1003 select (select `test`.`t3`.`a` AS `a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 18da4882894..35b76a8ab4b 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -940,7 +940,7 @@ grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost; create view v4 as select b+1 from mysqltest.t2; REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; drop database mysqltest; -drop view v1,v2; +drop view v1,v2,v4; set sql_mode='ansi'; create table t1 ("a*b" int); create view v1 as select "a*b" from t1; @@ -1040,7 +1040,6 @@ CREATE VIEW v02 AS SELECT * FROM DUAL; ERROR HY000: No tables used SHOW TABLES; Tables_in_test table_type -v4 VIEW CREATE VIEW v1 AS SELECT EXISTS (SELECT 1 UNION SELECT 2); select * from v1; EXISTS (SELECT 1 UNION SELECT 2) @@ -1166,3 +1165,108 @@ Table Create Table v3 CREATE VIEW `test`.`v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from `test`.`v1` join `test`.`v2` where (`v1`.`col1` = `v2`.`col1`) drop view v3, v2, v1; drop table t2, t1; +create function `f``1` () returns int return 5; +create view v1 as select test.`f``1` (); +show create view v1; +Table Create Table +v1 CREATE VIEW `test`.`v1` AS select `test`.`f``1`() AS `test.``f````1`` ()` +select * from v1; +test.`f``1` () +5 +drop view v1; +drop function `f``1`; +create function x () returns int return 5; +create view v1 as select x (); +select * from v1; +x () +5 +drop view v1; +drop function x; +create table t2 (col1 char collate latin1_german2_ci); +create view v2 as select col1 collate latin1_german1_ci from t2; +show create view v2; +Table Create Table +v2 CREATE VIEW `test`.`v2` AS select (`test`.`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `test`.`t2` +show create view v2; +Table Create Table +v2 CREATE VIEW `test`.`v2` AS select (`test`.`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `test`.`t2` +drop view v2; +drop table t2; +create table t1 (a int); +insert into t1 values (1), (2); +create view v1 as select 5 from t1 order by 1; +select * from v1; +5 +5 +5 +drop view v1; +drop table t1; +create function x1 () returns int return 5; +create table t1 (s1 int); +create view v1 as select x1() from t1; +drop function x1; +select * from v1; +ERROR 42000: FUNCTION test.x1 does not exist +show table status; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 9 Fixed 0 0 0 21474836479 1024 0 NULL # # NULL latin1_swedish_ci NULL +v1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view +show table status; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +t1 MyISAM 9 Fixed 0 0 0 21474836479 1024 0 NULL # # NULL latin1_swedish_ci NULL +v1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view +drop view v1; +drop table t1; +create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1; +show create view v1; +Table Create Table +v1 CREATE VIEW `test`.`v1` AS select 99999999999999999999999999999999999999999999999999999 AS `col1` +drop view v1; +create table tЭ (cЭ char); +create view vЭ as select cЭ from tЭ; +insert into vЭ values ('Э'); +select * from vЭ; +cЭ +Э +drop view vЭ; +drop table tЭ; +create table t1 (a int, b int); +insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10); +create view v1(c) as select a+1 from t1 where b >= 4; +select c from v1 where exists (select * from t1 where a=2 and b=c); +c +4 +drop view v1; +drop table t1; +create view v1 as select cast(1 as char(3)); +show create view v1; +Table Create Table +v1 CREATE VIEW `test`.`v1` AS select cast(1 as char(3) charset latin1) AS `cast(1 as char(3))` +select * from v1; +cast(1 as char(3)) +1 +drop view v1; +create view v1 as select 'a',1; +create view v2 as select * from v1 union all select * from v1; +create view v3 as select * from v2 where 1 = (select `1` from v2); +create view v4 as select * from v3; +select * from v4; +ERROR 21000: Subquery returns more than 1 row +drop view v4, v3, v2, v1; +create view v1 as select 5 into @w; +ERROR HY000: View's SELECT contains a 'INTO' clause +create view v1 as select 5 into outfile 'ttt'; +ERROR HY000: View's SELECT contains a 'INTO' clause +create table t1 (a int); +create view v1 as select a from t1 procedure analyse(); +ERROR HY000: View's SELECT contains a 'PROCEDURE' clause +drop table t1; +create table t1 (s1 int, primary key (s1)); +create view v1 as select * from t1; +insert into v1 values (1) on duplicate key update s1 = 7; +insert into v1 values (1) on duplicate key update s1 = 7; +select * from t1; +s1 +7 +drop view v1; +drop table t1; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 0c3bda1311c..92d6110cf7a 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1924,6 +1924,35 @@ call bug5251()| call bug5251()| drop procedure bug5251| +# +# BUG#5287: Stored procedure crash if leave outside loop +# +create procedure bug5287(param1 int) +label1: + begin + declare c cursor for select 5; + + loop + if param1 >= 0 then + leave label1; + end if; + end loop; +end| +call bug5287(1)| +drop procedure bug5287| + + +# +# BUG#5307: Stored procedure allows statement after BEGIN ... END +# +create procedure bug5307() +begin +end; set @x = 3| + +call bug5307()| +select @x| +drop procedure bug5307| + # # Some "real" examples diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index e73133afa67..9464e291e05 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -849,7 +849,7 @@ create view v4 as select b+1 from mysqltest.t2; connection root; REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; drop database mysqltest; -drop view v1,v2; +drop view v1,v2,v4; # # VIEW fields quoting @@ -1106,3 +1106,127 @@ select * from v3; show create view v3; drop view v3, v2, v1; drop table t2, t1; + +# +# VIEW based on functions with complex names +# +create function `f``1` () returns int return 5; +create view v1 as select test.`f``1` (); +show create view v1; +select * from v1; +drop view v1; +drop function `f``1`; + +# +# tested problem when function name length close to ALIGN_SIZE +# +create function x () returns int return 5; +create view v1 as select x (); +select * from v1; +drop view v1; +drop function x; + +# +# VIEW with collation +# +create table t2 (col1 char collate latin1_german2_ci); +create view v2 as select col1 collate latin1_german1_ci from t2; +show create view v2; +show create view v2; +drop view v2; +drop table t2; + +# +# order by refers on integer field +# +create table t1 (a int); +insert into t1 values (1), (2); +create view v1 as select 5 from t1 order by 1; +select * from v1; +drop view v1; +drop table t1; + +# +# VIEW over droped function +# +create function x1 () returns int return 5; +create table t1 (s1 int); +create view v1 as select x1() from t1; +drop function x1; +-- error 1304 +select * from v1; +--replace_column 12 # 13 # +show table status; +--replace_column 12 # 13 # +show table status; +drop view v1; +drop table t1; + +# +# VIEW with floating point (long bumber) as column +# +create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1; +show create view v1; +drop view v1; + +# +# VIEWs with national characters +# +create table tЭ (cЭ char); +create view vЭ as select cЭ from tЭ; +insert into vЭ values ('Э'); +select * from vЭ; +drop view vЭ; +drop table tЭ; + +# +# problem with used_tables() of outer reference resolved in VIEW +# +create table t1 (a int, b int); +insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10); +create view v1(c) as select a+1 from t1 where b >= 4; +select c from v1 where exists (select * from t1 where a=2 and b=c); +drop view v1; +drop table t1; + +# +# view with cast operation +# +create view v1 as select cast(1 as char(3)); +show create view v1; +select * from v1; +drop view v1; + +# +# bug handlimg from VIEWs +# +create view v1 as select 'a',1; +create view v2 as select * from v1 union all select * from v1; +create view v3 as select * from v2 where 1 = (select `1` from v2); +create view v4 as select * from v3; +-- error 1242 +select * from v4; +drop view v4, v3, v2, v1; + +# +# VIEW over SELECT with prohibited clauses +# +-- error 1349 +create view v1 as select 5 into @w; +-- error 1349 +create view v1 as select 5 into outfile 'ttt'; +create table t1 (a int); +-- error 1349 +create view v1 as select a from t1 procedure analyse(); +drop table t1; + +# +# INSERT into VIEW with ON DUPLICATE +# +create table t1 (s1 int, primary key (s1)); +create view v1 as select * from t1; +insert into v1 values (1) on duplicate key update s1 = 7; +insert into v1 values (1) on duplicate key update s1 = 7; +select * from t1; +drop view v1; +drop table t1; diff --git a/mysys/default.c b/mysys/default.c index 792233ed10d..a8343c6a21d 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -66,13 +66,209 @@ NullS, #define windows_ext ".ini" #endif -static int search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc, +/* + This structure defines the context that we pass to callback + function 'handle_default_option' used in search_default_file + to process each option. This context is used if search_default_file + was called from load_defaults. +*/ + +struct handle_option_ctx +{ + MEM_ROOT *alloc; + DYNAMIC_ARRAY *args; + TYPELIB *group; +}; + +static int search_default_file(Process_option_func func, void *func_ctx, const char *dir, const char *config_file, - const char *ext, TYPELIB *group); + const char *ext); static char *remove_end_comment(char *ptr); +/* + Process config files in default directories. + + SYNOPSIS + search_files() + conf_file Basename for configuration file to search for. + If this is a path, then only this file is read. + argc Pointer to argc of original program + argv Pointer to argv of original program + args_used Pointer to variable for storing the number of + arguments used. + func Pointer to the function to process options + func_ctx It's context. Usually it is the structure to + store additional options. + DESCRIPTION + + This function looks for config files in default directories. Then it + travesrses each of the files and calls func to process each option. + + RETURN + 0 ok + 1 given cinf_file doesn't exist +*/ + +static int search_files(const char *conf_file, int *argc, char ***argv, + uint *args_used, Process_option_func func, + void *func_ctx) +{ + const char **dirs, *forced_default_file; + int error= 0; + DBUG_ENTER("search_files"); + + args_used= 0; + + /* Check if we want to force the use a specific default file */ + forced_default_file= 0; + if (*argc >= 2) + { + if (is_prefix(argv[0][1],"--defaults-file=")) + { + forced_default_file= strchr(argv[0][1],'=') + 1; + *args_used++; + } + else if (is_prefix(argv[0][1],"--defaults-extra-file=")) + { + defaults_extra_file= strchr(argv[0][1],'=') + 1; + *args_used++; + } + } + + if (forced_default_file) + { + if ((error= search_default_file(func, func_ctx, "", + forced_default_file, "")) < 0) + goto err; + if (error > 0) + { + fprintf(stderr, "Could not open required defaults file: %s\n", + forced_default_file); + goto err; + } + } + else if (dirname_length(conf_file)) + { + if ((error= search_default_file(func, func_ctx, NullS, conf_file, + default_ext)) < 0) + goto err; + } + else + { +#ifdef __WIN__ + char system_dir[FN_REFLEN]; + GetWindowsDirectory(system_dir,sizeof(system_dir)); + if ((search_default_file(func, func_ctx, system_dir, conf_file, + windows_ext))) + goto err; +#endif +#if defined(__EMX__) || defined(OS2) + if (getenv("ETC") && + (search_default_file(func, func_ctx, getenv("ETC"), conf_file, + default_ext)) < 0) + goto err; +#endif + for (dirs= default_directories ; *dirs; dirs++) + { + if (**dirs) + { + if (search_default_file(func, func_ctx, *dirs, conf_file, default_ext) < 0) + goto err; + } + else if (defaults_extra_file) + { + if (search_default_file(func, func_ctx, NullS, defaults_extra_file, + default_ext) < 0) + goto err; /* Fatal error */ + } + } + } + + DBUG_RETURN(error); + +err: + fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); + exit(1); + return 0; /* Keep compiler happy */ +} + + +/* + Simplified version of search_files (no argv, argc to process). + + SYNOPSIS + process_default_option_files() + conf_file Basename for configuration file to search for. + If this is a path, then only this file is read. + func Pointer to the function to process options + func_ctx It's context. Usually it is the structure to + store additional options. + + DESCRIPTION + + Often we want only to get options from default config files. In this case we + don't want to provide any argc and argv parameters. This function is a + simplified variant of search_files which allows us to forget about + argc, argv. + + RETURN + 0 ok + 1 given cinf_file doesn't exist +*/ + +int process_default_option_files(const char *conf_file, + Process_option_func func, void *func_ctx) +{ + int argc= 1; + /* this is a dummy variable for search_files() */ + uint args_used; + + return search_files(conf_file, &argc, NULL, &args_used, func, func_ctx); +} + +/* + The option handler for load_defaults. + + SYNOPSIS + handle_deault_option() + in_ctx Handler context. In this case it is a + handle_option_ctx structure. + group_name The name of the group the option belongs to. + option The very option to be processed. It is already + prepared to be used in argv (has -- prefix) + + DESCRIPTION + + This handler checks whether a group is one of the listed and adds an option + to the array if yes. Some other handler can record, for instance, all groups + and their options, not knowing in advance the names and amount of groups. + + RETURN + 0 - ok + 1 - error occured +*/ + +static int handle_default_option(void *in_ctx, const char *group_name, + const char *option) +{ + char *tmp; + struct handle_option_ctx *ctx; + ctx= (struct handle_option_ctx *) in_ctx; + if(find_type((char *)group_name, ctx->group, 3)) + { + if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1))) + return 1; + if (insert_dynamic(ctx->args, (gptr) &tmp)) + return 1; + strmov(tmp, option); + } + + return 0; +} + + /* Read options from configurations files @@ -101,7 +297,6 @@ static char *remove_end_comment(char *ptr); RETURN 0 ok 1 The given conf_file didn't exists - 2 The given conf_file was not a normal readable file */ @@ -109,13 +304,13 @@ int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv) { DYNAMIC_ARRAY args; - const char **dirs, *forced_default_file; TYPELIB group; my_bool found_print_defaults=0; uint args_used=0; int error= 0; MEM_ROOT alloc; char *ptr,**res; + struct handle_option_ctx ctx; DBUG_ENTER("load_defaults"); init_alloc_root(&alloc,512,0); @@ -137,79 +332,22 @@ int load_defaults(const char *conf_file, const char **groups, DBUG_RETURN(0); } - /* Check if we want to force the use a specific default file */ - forced_default_file=0; - if (*argc >= 2) - { - if (is_prefix(argv[0][1],"--defaults-file=")) - { - forced_default_file=strchr(argv[0][1],'=')+1; - args_used++; - } - else if (is_prefix(argv[0][1],"--defaults-extra-file=")) - { - defaults_extra_file=strchr(argv[0][1],'=')+1; - args_used++; - } - } - group.count=0; group.name= "defaults"; group.type_names= groups; + for (; *groups ; groups++) group.count++; if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32)) goto err; - if (forced_default_file) - { - if ((error= search_default_file(&args, &alloc, "", - forced_default_file, "", &group)) < 0) - goto err; - if (error > 0) - { - fprintf(stderr, "Could not open required defaults file: %s\n", - forced_default_file); - goto err; - } - } - else if (dirname_length(conf_file)) - { - if ((error= search_default_file(&args, &alloc, NullS, conf_file, - default_ext, &group)) < 0) - goto err; - } - else - { -#ifdef __WIN__ - char system_dir[FN_REFLEN]; - GetWindowsDirectory(system_dir,sizeof(system_dir)); - if ((search_default_file(&args, &alloc, system_dir, conf_file, - windows_ext, &group))) - goto err; -#endif -#if defined(__EMX__) || defined(OS2) - if (getenv("ETC") && - (search_default_file(&args, &alloc, getenv("ETC"), conf_file, - default_ext, &group)) < 0) - goto err; -#endif - for (dirs=default_directories ; *dirs; dirs++) - { - if (**dirs) - { - if (search_default_file(&args, &alloc, *dirs, conf_file, - default_ext, &group) < 0) - goto err; - } - else if (defaults_extra_file) - { - if (search_default_file(&args, &alloc, NullS, defaults_extra_file, - default_ext, &group) < 0) - goto err; /* Fatal error */ - } - } - } + + ctx.alloc= &alloc; + ctx.args= &args; + ctx.group= &group; + + error= search_files(conf_file, argc, argv, &args_used, + handle_default_option, (void *) &ctx); /* Here error contains <> 0 only if we have a fully specified conf_file or a forced default file @@ -274,8 +412,10 @@ void free_defaults(char **argv) SYNOPSIS search_default_file() - args Store pointer to found options here - alloc Allocate strings in this object + opt_handler Option handler function. It is used to process + every separate option. + handler_ctx Pointer to the structure to store actual + parameters of the function. dir directory to read config_file Name of configuration file ext Extension for configuration file @@ -285,17 +425,17 @@ void free_defaults(char **argv) 0 Success -1 Fatal error, abort 1 File not found (Warning) - 2 File is not a regular file (Warning) */ -static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, +static int search_default_file(Process_option_func opt_handler, void *handler_ctx, const char *dir, const char *config_file, - const char *ext, TYPELIB *group) + const char *ext) { - char name[FN_REFLEN+10],buff[4096],*ptr,*end,*value,*tmp; + char name[FN_REFLEN+10], buff[4096], curr_gr[4096], *ptr, *end; + char *value, option[4096]; FILE *fp; uint line=0; - my_bool read_values=0,found_group=0; + my_bool found_group=0; if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3) return 0; /* Ignore wrong paths */ @@ -352,7 +492,8 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, } for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;/* Remove end space */ end[0]=0; - read_values=find_type(ptr,group,3) > 0; + + strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096)); continue; } if (!found_group) @@ -362,19 +503,17 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, name,line); goto err; } - if (!read_values) - continue; + + end= remove_end_comment(ptr); if ((value= strchr(ptr, '='))) end= value; /* Option without argument */ for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ; if (!value) { - if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3))) - goto err; - strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr)); - if (insert_dynamic(args,(gptr) &tmp)) - goto err; + strmake(strmov(option,"--"),ptr,(uint) (end-ptr)); + if (opt_handler(handler_ctx, curr_gr, option)) + goto err; } else { @@ -396,12 +535,7 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, value++; value_end--; } - if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 + - (uint) (value_end-value)+1))) - goto err; - if (insert_dynamic(args,(gptr) &tmp)) - goto err; - ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr)); + ptr=strnmov(strmov(option,"--"),ptr,(uint) (end-ptr)); *ptr++= '='; for ( ; value != value_end; value++) @@ -443,6 +577,8 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, *ptr++= *value; } *ptr=0; + if (opt_handler(handler_ctx, curr_gr, option)) + goto err; } } my_fclose(fp,MYF(0)); diff --git a/sql/item.cc b/sql/item.cc index 517309acd2b..efd94716dc7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1143,8 +1143,27 @@ bool Item_param::convert_str_value(THD *thd) return rc; } -/* End of Item_param related */ +void Item_param::print(String *str) +{ + if (state == NO_VALUE) + { + str->append('?'); + } + else + { + char buffer[80]; + String tmp(buffer, sizeof(buffer), &my_charset_bin); + const String *res; + res= query_val_str(&tmp); + str->append(*res); + } +} + + +/**************************************************************************** + Item_copy_string +****************************************************************************/ void Item_copy_string::copy() { @@ -1302,11 +1321,21 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) table_list, ref, 0, 1)) != not_found_field) { - if (tmp && tmp != view_ref_found) - { - prev_subselect_item->used_tables_cache|= tmp->table->map; - prev_subselect_item->const_item_cache= 0; - } + if (tmp) + { + if (tmp != view_ref_found) + { + prev_subselect_item->used_tables_cache|= tmp->table->map; + prev_subselect_item->const_item_cache= 0; + } + else + { + prev_subselect_item->used_tables_cache|= + (*ref)->used_tables(); + prev_subselect_item->const_item_cache&= + (*ref)->const_item(); + } + } break; } if (sl->resolve_mode == SELECT_LEX::SELECT_MODE && @@ -1756,6 +1785,21 @@ int Item_real::save_in_field(Field *field, bool no_conversions) return field->store(nr); } + +void Item_real::print(String *str) +{ + if (presentation) + { + str->append(presentation); + return; + } + char buffer[20]; + String num(buffer, sizeof(buffer), &my_charset_bin); + num.set(value, decimals, &my_charset_bin); + str->append(num); +} + + /**************************************************************************** ** varbinary item ** In string context this is a binary string @@ -2014,11 +2058,21 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) table_list, reference, 0, 1)) != not_found_field) { - if (tmp && tmp != view_ref_found) - { - prev_subselect_item->used_tables_cache|= tmp->table->map; - prev_subselect_item->const_item_cache= 0; - } + if (tmp) + { + if (tmp != view_ref_found) + { + prev_subselect_item->used_tables_cache|= tmp->table->map; + prev_subselect_item->const_item_cache= 0; + } + else + { + prev_subselect_item->used_tables_cache|= + (*reference)->used_tables(); + prev_subselect_item->const_item_cache&= + (*reference)->const_item(); + } + } break; } @@ -2063,8 +2117,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) if (!((*reference)= fld= new Item_field(tmp))) return 1; mark_as_dependent(thd, last, thd->lex->current_select, fld); - return 0; register_item_tree_changing(reference); + return 0; } /* We can leave expression substituted from view for next PS/SP diff --git a/sql/item.h b/sql/item.h index 4030c0fc097..dd4a402bcb8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -635,7 +635,7 @@ public: */ virtual table_map used_tables() const { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } - void print(String *str) { str->append('?'); } + void print(String *str); /* parameter never equal to other parameter of other item */ bool eq(const Item *item, bool binary_cmp) const { return 0; } }; @@ -698,12 +698,13 @@ public: class Item_real :public Item_num { + char *presentation; public: double value; // Item_real() :value(0) {} Item_real(const char *str_arg, uint length) :value(my_atof(str_arg)) { - name=(char*) str_arg; + presentation= name=(char*) str_arg; decimals=(uint8) nr_of_decimals(str_arg); max_length=length; fixed= 1; @@ -711,12 +712,12 @@ public: Item_real(const char *str,double val_arg,uint decimal_par,uint length) :value(val_arg) { - name=(char*) str; + presentation= name=(char*) str; decimals=(uint8) decimal_par; max_length=length; fixed= 1; } - Item_real(double value_par) :value(value_par) { fixed= 1; } + Item_real(double value_par) :presentation(0), value(value_par) { fixed= 1; } int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } @@ -732,6 +733,7 @@ public: void cleanup() {} Item *new_item() { return new Item_real(name,value,decimals,max_length); } Item_num *neg() { value= -value; return this; } + void print(String *str); }; diff --git a/sql/item_func.cc b/sql/item_func.cc index c2c93586af8..f9ab1886a23 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3270,9 +3270,25 @@ Item_func_sp::Item_func_sp(sp_name *name, List &list) const char * Item_func_sp::func_name() const { - return m_name->m_name.str; + THD *thd= current_thd; + /* Calculate length to avoud reallocation of string for sure */ + uint len= ((m_name->m_db.length + + m_name->m_name.length)*2 + //characters*quoting + 2 + // ` and ` + 1 + // . + 1 + // end of string + ALIGN_SIZE(1)); // to avoid String reallocation + String qname((char *)alloc_root(&thd->mem_root, len), len, + system_charset_info); + + qname.length(0); + append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length); + qname.append('.'); + append_identifier(thd, &qname, m_name->m_name.str, m_name->m_name.length); + return qname.ptr(); } + int Item_func_sp::execute(Item **itp) { diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d3493e1fad1..5f2c37dd8a7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2274,6 +2274,18 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const return 1; } + +void Item_func_set_collation::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(" collate ", 9); + DBUG_ASSERT(args[1]->basic_const_item() && + args[1]->type() == Item::STRING_ITEM); + args[1]->str_value.print(str); + str->append(')'); +} + String *Item_func_charset::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 08123370bc6..df8861b2ee0 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -635,7 +635,7 @@ public: void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } - void print(String *str) { print_op(str); } + void print(String *str); }; class Item_func_charset :public Item_str_func diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 766fa215a8f..c615bcf7e0f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -995,23 +995,6 @@ Item_in_subselect::select_transformer(JOIN *join) } -Item_subselect::trans_res -Item_in_subselect::no_select_transform() -{ - DBUG_ENTER("Item_in_subselect::no_select_transform"); - // We have execute fix_fields() for left expression - SELECT_LEX *current= thd->lex->current_select, *up; - thd->lex->current_select= up= current->return_after_parsing(); - if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr)) - { - thd->lex->current_select= current; - DBUG_RETURN(RES_ERROR); - } - thd->lex->current_select= current; - DBUG_RETURN(RES_OK); -} - - void Item_in_subselect::print(String *str) { if (transformed) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 90c301c6571..e5defe24756 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -84,7 +84,6 @@ public: null_value= 1; } virtual trans_res select_transformer(JOIN *join); - virtual trans_res no_select_transform() { return RES_OK; } bool assigned() { return value_assigned; } void assigned(bool a) { value_assigned= a; } enum Type type() const; @@ -220,7 +219,6 @@ public: was_null= 0; } trans_res select_transformer(JOIN *join); - trans_res no_select_transform(); trans_res single_value_transformer(JOIN *join, Comp_creator *func); trans_res row_value_transformer(JOIN * join); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 5aa14010058..0e7594a1d98 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2011,7 +2011,7 @@ void Item_char_typecast::print(String *str) if (cast_cs) { str->append(" charset ", 9); - str->append(cast_cs->name); + str->append(cast_cs->csname); } str->append(')'); } diff --git a/sql/log.cc b/sql/log.cc index 5e15b2b170c..44c8ce59aaf 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -838,13 +838,13 @@ int MYSQL_LOG::purge_logs(const char *to_log, while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && !log_in_use(log_info.log_file_name)) { - ulong tmp; - LINT_INIT(tmp); + ulong file_size; + LINT_INIT(file_size); if (decrease_log_space) //stat the file we want to delete { MY_STAT s; if (my_stat(log_info.log_file_name,&s,MYF(0))) - tmp= s.st_size; + file_size= s.st_size; else { /* @@ -852,7 +852,7 @@ int MYSQL_LOG::purge_logs(const char *to_log, of space that deletion will free. In most cases, deletion won't work either, so it's not a problem. */ - tmp= 0; + file_size= 0; } } /* @@ -861,7 +861,7 @@ int MYSQL_LOG::purge_logs(const char *to_log, */ DBUG_PRINT("info",("purging %s",log_info.log_file_name)); if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space) - *decrease_log_space-= tmp; + *decrease_log_space-= file_size; if (find_next_log(&log_info, 0) || exit_loop) break; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 52280b28f4f..a100aa0cd3a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -398,8 +398,9 @@ void free_items(Item *item); void cleanup_items(Item *item); class THD; void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0); -int check_one_table_access(THD *thd, ulong privilege, +bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables); +bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table); bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); int multi_update_precheck(THD *thd, TABLE_LIST *tables); @@ -767,12 +768,10 @@ void free_io_cache(TABLE *entry); void intern_close_table(TABLE *entry); bool close_thread_table(THD *thd, TABLE **table_ptr); void close_temporary_tables(THD *thd); -TABLE_LIST * find_real_table_in_list(TABLE_LIST *table, - const char *db_name, - const char *table_name); -TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table, - const char *db_name, - const char *table_name); +TABLE_LIST *find_table_in_list(TABLE_LIST *table, + uint offset_to_list, + const char *db_name, + const char *table_name); TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name); bool close_temporary_table(THD *thd, const char *db, const char *table_name); void close_temporary(TABLE *table, bool delete_table=1); @@ -788,6 +787,23 @@ int fill_record(List &fields,List &values, bool ignore_errors); int fill_record(Field **field,List &values, bool ignore_errors); OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); +inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table, + const char *db_name, + const char *table_name) +{ + return find_table_in_list(table, offsetof(TABLE_LIST, next_global), + db_name, table_name); +} + +inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table, + const char *db_name, + const char *table_name) +{ + return find_table_in_list(table, offsetof(TABLE_LIST, next_local), + db_name, table_name); +} + + /* sql_calc.cc */ bool eval_const_cond(COND *cond); diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 9d1c429d5b6..35310f5210f 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -361,7 +361,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index b2d2fdf4d77..d6a0a9d81e8 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -1,4 +1,4 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB +:/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB This file is public domain and comes with NO WARRANTY of any kind */ /* Knud RiishЬjgЕrd knudriis@post.tele.dk 99 && @@ -355,7 +355,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 85c0443869f..8fd5277d4ec 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -363,7 +363,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 641f267d67e..a60881b5df6 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index e64c0c17e74..2e8a9270cd3 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -357,7 +357,7 @@ character-set=latin7 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index f3443457346..b8ec7866a68 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 498a230faed..c28792cc8c6 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -364,7 +364,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 2827517ba9a..8ceb24bd376 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -352,7 +352,7 @@ character-set=greek "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index fab0b156322..f47684f9225 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 24634514a23..eb241ef08a0 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 68f2857aeca..166d6e8e1c1 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -354,7 +354,7 @@ character-set=ujis "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 70267c82364..66486fd8a0f 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -352,7 +352,7 @@ character-set=euckr "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 1d84a3a5e5a..739d40178df 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index be881d54473..227e16e1590 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 8a576b5bf82..62e10e778f2 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -356,7 +356,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 6794db726cc..08c03fcaf2a 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -353,7 +353,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 9eaa4860b64..0f6df4f919b 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -356,7 +356,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index eec85d611fc..71c983ff55e 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -354,7 +354,7 @@ character-set=koi8r "'%-.64s.%-.64s' - не %s" "Столбец '%-.64s' не обновляемый" "View SELECT содержит подзапрос в конструкции FROM" -"View SELECT содержит конструкцию PROCEDURE" +"View SELECT содержит конструкцию '%s'" "View SELECT содержит переменную или параметр" "View SELECT содержит ссылку на временную таблицу '%-.64s'" "View SELECT и список полей view имеют разное количество столбцов" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 4039268f446..bff4fad6108 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -358,7 +358,7 @@ character-set=cp1250 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 9be5ce01d6a..363ba86afc7 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -360,7 +360,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index dc15f8b8d5e..7ab9b416c2e 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index ee5436c3b80..b7add017e44 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index cb1d99e2fec..364a2a03c16 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -357,7 +357,7 @@ character-set=koi8u "'%-.64s.%-.64s' не ╓ %s" "Стовбець '%-.64s' не може бути зминений" "View SELECT ма╓ п╕дзапит у конструкц╕╖ FROM" -"View SELECT ма╓ конструкц╕ю PROCEDURE" +"View SELECT ма╓ конструкц╕ю '%s'" "View SELECT ма╓ зминну або параметер" "View SELECT використову╓ тимчасову таблицю '%-.64s'" "View SELECT ╕ перел╕к стовбц╕в view мають р╕зну к╕льк╕сть сковбц╕в" diff --git a/sql/sp.cc b/sql/sp.cc index dda6e0fad60..cd52cff90a3 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -93,10 +93,15 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, key[128]= type; keylen= sizeof(key); - for (table= thd->open_tables ; table ; table= table->next) - if (strcmp(table->table_cache_key, "mysql") == 0 && - strcmp(table->real_name, "proc") == 0) - break; + if (thd->lex->proc_table) + table= thd->lex->proc_table->table; + else + { + for (table= thd->open_tables ; table ; table= table->next) + if (strcmp(table->table_cache_key, "mysql") == 0 && + strcmp(table->real_name, "proc") == 0) + break; + } if (table) *opened= FALSE; else @@ -955,6 +960,7 @@ sp_cache_functions(THD *thd, LEX *lex) LEX *newlex= new st_lex; thd->lex= newlex; + newlex->proc_table= oldlex->proc_table; // hint if mysql.oper is opened name.m_name.str= strchr(name.m_qname.str, '.'); name.m_db.length= name.m_name.str - name.m_qname.str; name.m_db.str= strmake_root(&thd->mem_root, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b2d3b8202c8..4bb06fd8172 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -288,6 +288,7 @@ void sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) { DBUG_ENTER("sp_head::init_strings"); + uint n; /* Counter for nul trimming */ /* During parsing, we must use thd->mem_root */ MEM_ROOT *root= &thd->mem_root; @@ -351,9 +352,17 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) (char *)m_returns_begin, m_retstr.length); } } - m_body.length= lex->end_of_query - m_body_begin; + m_body.length= lex->ptr - m_body_begin; + /* Trim nuls at the end */ + n= 0; + while (m_body.length && m_body_begin[m_body.length-1] == '\0') + { + m_body.length-= 1; + n+= 1; + } m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length); - m_defstr.length= lex->end_of_query - lex->buf; + m_defstr.length= lex->ptr - lex->buf; + m_defstr.length-= n; m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length); DBUG_VOID_RETURN; } @@ -1193,7 +1202,7 @@ sp_instr_set::execute(THD *thd, uint *nextp) if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) || (res= open_and_lock_tables(thd, tables)))) - DBUG_RETURN(-1); + DBUG_RETURN(res); it= sp_eval_func_item(thd, m_value, m_type); if (! it) @@ -1294,7 +1303,7 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp) if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) || (res= open_and_lock_tables(thd, tables)))) - DBUG_RETURN(-1); + DBUG_RETURN(res); it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); if (!it) @@ -1351,7 +1360,7 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp) if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) || (res= open_and_lock_tables(thd, tables)))) - DBUG_RETURN(-1); + DBUG_RETURN(res); it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); if (! it) @@ -1407,7 +1416,7 @@ sp_instr_freturn::execute(THD *thd, uint *nextp) if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) || (res= open_and_lock_tables(thd, tables)))) - DBUG_RETURN(-1); + DBUG_RETURN(res); it= sp_eval_func_item(thd, m_value, m_type); if (! it) diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index c83259c3926..3b60f0936f9 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -28,7 +28,7 @@ sp_pcontext::sp_pcontext(sp_pcontext *prev) : Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0), - m_parent(prev), m_handlers(0) + m_handlers(0), m_parent(prev) { VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); @@ -94,7 +94,7 @@ sp_pcontext::diff_handlers(sp_pcontext *ctx) while (pctx && pctx != ctx) { - n+= pctx->max_handlers(); + n+= pctx->m_handlers; pctx= pctx->parent_context(); } if (pctx) @@ -109,12 +109,9 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx) sp_pcontext *pctx= this; while (pctx && pctx != ctx) - { - n+= pctx->max_cursors(); pctx= pctx->parent_context(); - } if (pctx) - return n; + return ctx->current_cursors() - pctx->current_cursors(); return 0; // Didn't find ctx } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 6db62614aa5..36e4ed06aa7 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -275,6 +275,7 @@ protected: uint m_psubsize; uint m_csubsize; uint m_hsubsize; + uint m_handlers; // No. of handlers in this context private: @@ -282,7 +283,6 @@ private: uint m_poffset; // Variable offset for this context uint m_coffset; // Cursor offset for this context - uint m_handlers; // No. of handlers in this context DYNAMIC_ARRAY m_pvar; // Parameters/variables DYNAMIC_ARRAY m_cond; // Conditions diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5ea59b26bd6..0a970640e32 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2761,7 +2761,22 @@ void grant_reload(THD *thd) /**************************************************************************** Check table level grants - All errors are written directly to the client if no_errors is given ! + + SYNPOSIS + bool check_grant() + thd Thread handler + want_access Bits of privileges user needs to have + tables List of tables to check. The user should have 'want_access' + to all tables in list. + show_table <> 0 if we are in show table. In this case it's enough to have + any privilege for the table + number Check at most this number of tables. + no_errors If 0 then we write an error. The error is sent directly to + the client + + RETURN + 0 ok + 1 Error: User did not have the requested privielges ****************************************************************************/ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, @@ -2769,14 +2784,17 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, { TABLE_LIST *table; char *user = thd->priv_user; + DBUG_ENTER("check_grant"); + DBUG_ASSERT(number > 0); - want_access &= ~thd->master_access; + want_access&= ~thd->master_access; if (!want_access) - return 0; // ok + DBUG_RETURN(0); // ok rw_rdlock(&LOCK_grant); for (table= tables; table && number--; table= table->next_global) { + GRANT_TABLE *grant_table; if (!(~table->grant.privilege & want_access) || table->derived) { /* @@ -2786,10 +2804,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, table->grant.want_privilege= 0; continue; // Already checked } - GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip, - table->db,user, - table->real_name,0); - if (!grant_table) + if (!(grant_table= table_hash_search(thd->host,thd->ip, + table->db,user, table->real_name,0))) { want_access &= ~table->grant.privilege; goto err; // No grants @@ -2813,7 +2829,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, } } rw_unlock(&LOCK_grant); - return 0; + DBUG_RETURN(0); err: rw_unlock(&LOCK_grant); @@ -2848,7 +2864,7 @@ err: thd->host_or_ip, table ? table->real_name : "unknown"); } - return 1; + DBUG_RETURN(1); } @@ -2942,7 +2958,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, if (!(grant_table= grant->grant_table)) goto err; /* purecov: inspected */ - for (; fields->end(); fields->next()) + for (; !fields->end_of_fields(); fields->next()) { const char *field_name= fields->name(); grant_column= column_hash_search(grant_table, field_name, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d1fd5fd02cc..5fcfe945f27 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -549,81 +549,37 @@ void close_temporary_tables(THD *thd) thd->temporary_tables=0; } -#ifdef UNUSED + /* - Find first suitable table by alias in given list. + Find table in list. SYNOPSIS find_table_in_list() - table - pointer to table list - db_name - data base name or 0 for any - table_name - table name or 0 for any + table Pointer to table list + offset Offset to which list in table structure to use + db_name Data base name + table_name Table name + + NOTES: + This is called by find_table_in_local_list() and + find_table_in_global_list(). RETURN VALUES NULL Table not found # Pointer to found table. */ -TABLE_LIST * find_table_in_list(TABLE_LIST *table, - const char *db_name, const char *table_name) +TABLE_LIST *find_table_in_list(TABLE_LIST *table, + uint offset, + const char *db_name, + const char *table_name) { - for (; table; table= table->next) - if ((!db_name || !strcmp(table->db, db_name)) && - (!table_name || !my_strcasecmp(table_alias_charset, - table->alias, table_name))) - break; - return table; -} -#endif /*UNUSED*/ - -/* - Find real table in given global list. - - SYNOPSIS - find_real_table_in_list() - table - pointer to table list - db_name - data base name - table_name - table name - - RETURN VALUES - NULL Table not found - # Pointer to found table. -*/ - -TABLE_LIST * find_real_table_in_list(TABLE_LIST *table, - const char *db_name, - const char *table_name) -{ - for (; table; table= table->next_global) - if (!strcmp(table->db, db_name) && - !strcmp(table->real_name, table_name)) - break; - return table; -} - - -/* - Find real table in given local list. - - SYNOPSIS - find_real_table_in_local_list() - table - pointer to table list - db_name - data base name - table_name - table name - - RETURN VALUES - NULL Table not found - # Pointer to found table. -*/ - -TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table, - const char *db_name, - const char *table_name) -{ - for (; table; table= table->next_local) + for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) + { if (!strcmp(table->db, db_name) && !strcmp(table->real_name, table_name)) break; + } return table; } @@ -1364,7 +1320,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name) db Database name name Table name alias Alias name - table_desc TABLE_LIST descriptor + table_desc TABLE_LIST descriptor (used with views) mem_root temporary mem_root for parsing NOTES @@ -1402,10 +1358,10 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, if (!entry->crashed) { /* - Frm file could not be found on disk - Since it does not exist, no one can be using it - LOCK_open has been locked to protect from someone else - trying to discover the table at the same time. + Frm file could not be found on disk + Since it does not exist, no one can be using it + LOCK_open has been locked to protect from someone else + trying to discover the table at the same time. */ if (discover_retry_count++ != 0) goto err; @@ -1610,7 +1566,7 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter) tables->table->grant= tables->grant; } thd->proc_info=0; - free_root(&new_frm_mem, MYF(0)); + free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block DBUG_RETURN(result); } @@ -1680,7 +1636,8 @@ 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, 0, &refresh)) && refresh) ; + while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) + ; if (table) { @@ -1751,6 +1708,7 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) RETURN 0 - ok -1 - error + 1 - error reported to user NOTE The lock will automaticly be freed by close_thread_tables() @@ -1760,9 +1718,9 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("open_and_lock_tables"); uint counter; - if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter)) + if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter) + || mysql_handle_derived(thd->lex)) DBUG_RETURN(thd->net.report_error ? -1 : 1); /* purecov: inspected */ - DBUG_RETURN(mysql_handle_derived(thd->lex)); } @@ -1909,7 +1867,7 @@ bool rm_temporary_table(enum db_type base, char *path) ** return unique field ******************************************************************************/ -// Special Field pointers for find_field_in_tables returning +/* Special Field pointers for find_field_in_tables returning */ const Field *not_found_field= (Field*) 0x1; const Field *view_ref_found= (Field*) 0x2; @@ -2005,6 +1963,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, return fld; } + /* Find field in table @@ -2594,23 +2553,47 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, } -/**************************************************************************** - This just drops in all fields instead of current '*' field - Returns pointer to last inserted field if ok -****************************************************************************/ +/* + Drops in all fields instead of current '*' field + + SYNOPSIS + insert_fields() + thd Thread handler + tables List of tables + db_name Database name in case of 'database_name.table_name.*' + table_name Table name in case of 'table_name.*' + it Pointer to '*' + any_privileges 0 If we should ensure that we have SELECT privileges + for all columns + 1 If any privilege is ok + RETURN + 0 ok + 'it' is updated to point at last inserted + 1 error. The error message is sent to client +*/ bool insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges) { + /* allocate variables on stack to avoid pool alloaction */ + Field_iterator_table table_iter; + Field_iterator_view view_iter; uint found; DBUG_ENTER("insert_fields"); - found=0; + found= 0; for (; tables; tables= tables->next_local) { - TABLE *table=tables->table; + Field_iterator *iterator; + TABLE_LIST *natural_join_table; + Field *field; + TABLE_LIST *embedded; + TABLE_LIST *last; + TABLE_LIST *embedding; + TABLE *table= tables->table; + if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, tables->alias) && (!db_name || !strcmp(tables->db,db_name)))) @@ -2621,36 +2604,26 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, { if (tables->view) { - Field_iterator_view fields; - fields.set(tables); + view_iter.set(tables); if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant, tables->view_db.str, tables->view_name.str, - &fields)) - DBUG_RETURN(1); + &view_iter)) + goto err; } else { - Field_iterator_table fields; - fields.set(tables); + table_iter.set(tables); if (check_grant_all_columns(thd, SELECT_ACL, &table->grant, table->table_cache_key, table->real_name, - &fields)) - DBUG_RETURN(1); + &table_iter)) + goto err; } } #endif - /* allocate 2 variables on stack to avoid pool alloaction */ - Field_iterator_table table_iter; - Field_iterator_view view_iter; - Field_iterator *iterator; - TABLE_LIST *natural_join_table= 0; - Field *field; - - thd->used_tables|=table->map; - TABLE_LIST *embedded= tables; - TABLE_LIST *last= embedded; - TABLE_LIST *embedding; + natural_join_table= 0; + thd->used_tables|= table->map; + last= embedded= tables; while ((embedding= embedded->embedding) && embedding->join_list->elements != 1) @@ -2681,7 +2654,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, iterator= &table_iter; iterator->set(tables); - for (; iterator->end(); iterator->next()) + for (; !iterator->end_of_fields(); iterator->next()) { Item *not_used_item; uint not_used_field_index= NO_CACHED_FIELD_INDEX; @@ -2733,9 +2706,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, thd->host_or_ip, fld->field_name, tab); - /* TODO: should be removed to have only one send_error */ - send_error(thd); - DBUG_RETURN(1); + goto err; } } #endif @@ -2769,15 +2740,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, table->used_fields=table->fields; } } - if (!found) - { - if (!table_name) - my_error(ER_NO_TABLES_USED,MYF(0)); - else - my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name); - send_error(thd); - } - DBUG_RETURN(!found); + if (found) + DBUG_RETURN(0); + + if (!table_name) + my_error(ER_NO_TABLES_USED, MYF(0)); + else + my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name); + +err: + send_error(thd); + DBUG_RETURN(1); } @@ -2866,13 +2839,16 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) if (arena) thd->set_n_backup_item_arena(arena, &backup); + TABLE *t1=tab1->table; TABLE *t2=tab2->table; - /* allocate 2 variables on stack to avoid pool alloaction */ Field_iterator_table table_iter; Field_iterator_view view_iter; Field_iterator *iterator; + Field *t1_field, *t2_field; + Item *item_t2; Item_cond_and *cond_and=new Item_cond_and(); + if (!cond_and) // If not out of memory DBUG_RETURN(1); cond_and->top_level_item(); @@ -2888,9 +2864,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) table_iter.set(tab1); } - Field *t1_field, *t2_field; - Item *item_t2; - for (; iterator->end(); iterator->next()) + for (; !iterator->end_of_fields(); iterator->next()) { const char *t1_field_name= iterator->name(); uint not_used_field_index= NO_CACHED_FIELD_INDEX; @@ -3227,6 +3201,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) table_desc TABLE_LIST descriptor mem_root temporary MEM_ROOT for parsing */ + static my_bool open_new_frm(const char *path, const char *alias, const char *db, const char *table_name, @@ -3234,16 +3209,17 @@ open_new_frm(const char *path, const char *alias, uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc, MEM_ROOT *mem_root) { - DBUG_ENTER("open_new_frm"); LEX_STRING pathstr; - pathstr.str= (char *)path; + File_parser *parser; + DBUG_ENTER("open_new_frm"); + + pathstr.str= (char*) path; pathstr.length= strlen(path); if (!mem_root) mem_root= ¤t_thd->mem_root; - File_parser *parser= sql_parse_prepare(&pathstr, mem_root, 1); - if (parser) + if ((parser= sql_parse_prepare(&pathstr, mem_root, 1))) { if (!strncmp("VIEW", parser->type()->str, parser->type()->length)) { @@ -3261,12 +3237,9 @@ open_new_frm(const char *path, const char *alias, my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str); goto err; } + DBUG_RETURN(0); } - else - goto err; - - DBUG_RETURN(0); - + err: bzero(outparam, sizeof(TABLE)); // do not run repair DBUG_RETURN(1); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 910b673dc32..089c0c00c3b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -39,8 +39,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, ha_rows deleted; DBUG_ENTER("mysql_delete"); - if ((open_and_lock_tables(thd, table_list))) - DBUG_RETURN(-1); + if ((error= open_and_lock_tables(thd, table_list))) + DBUG_RETURN(error); table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; @@ -282,7 +282,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); DBUG_RETURN(-1); } - if (find_real_table_in_list(table_list->next_global, + if (find_table_in_global_list(table_list->next_global, table_list->db, table_list->real_name)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 3137890f2ba..5c827741e6d 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -220,10 +220,12 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, table->next= thd->derived_tables; thd->derived_tables= table; } + } + else + free_tmp_table(thd, table); exit: - delete derived_result; - lex->current_select= save_current_select; - } + delete derived_result; + lex->current_select= save_current_select; DBUG_RETURN(res); } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 85d5271d4c3..8fc0671c808 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -640,11 +640,8 @@ int mysqld_help(THD *thd, const char *mask) uint mlen= strlen(mask); MEM_ROOT *mem_root= &thd->mem_root; - if (open_and_lock_tables(thd, tables)) - { - res= -1; + if (res= open_and_lock_tables(thd, tables)) goto end; - } /* Init tables and fields to be usable from items diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b43c4d31b34..857c500f200 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -51,6 +51,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, List &values, ulong counter, bool check_unique) { TABLE *table= table_list->table; + if (fields.elements == 0 && values.elements != 0) { if (values.elements != table->fields) @@ -61,11 +62,11 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, return -1; } #ifndef NO_EMBEDDED_ACCESS_CHECKS + if (grant_option) { Field_iterator_table fields; fields.set_table(table); - if (grant_option && - check_grant_all_columns(thd, INSERT_ACL, &table->grant, + if (check_grant_all_columns(thd, INSERT_ACL, &table->grant, table->table_cache_key, table->real_name, &fields)) return -1; @@ -75,7 +76,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, } else { // Part field list - TABLE_LIST *save_next= table_list->next_local; + TABLE_LIST *save_next; int res; if (fields.elements != values.elements) { @@ -85,16 +86,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, return -1; } - table_list->next_local= 0; thd->dupp_field=0; thd->lex->select_lex.no_wrap_view_item= 1; + save_next= table_list->next_local; // fields only from first table + table_list->next_local= 0; res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); - thd->lex->select_lex.no_wrap_view_item= 0; table_list->next_local= save_next; + thd->lex->select_lex.no_wrap_view_item= 0; if (res) - { return -1; - } if (check_unique && thd->dupp_field) { @@ -410,7 +410,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, !thd->cuted_fields)) { thd->row_count_func= info.copied+info.deleted+info.updated; - send_ok(thd, (ulong) (ulong) thd->row_count_func, id); + send_ok(thd, (ulong) thd->row_count_func, id); } else { @@ -423,7 +423,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields); thd->row_count_func= info.copied+info.deleted+info.updated; - ::send_ok(thd, (ulong) thd->row_count_func, (ulonglong)id,buff); + ::send_ok(thd, (ulong) thd->row_count_func, id, buff); } free_underlaid_joins(thd, &thd->lex->select_lex); table->insert_values=0; @@ -447,46 +447,58 @@ abort: check_view_insertability() view - reference on VIEW + IMPLEMENTATION + A view is insertable if the folloings are true: + - All columns in the view are columns from a table + - All not used columns in table have a default values + - All field in view are unique (not referring to the same column) + RETURN FALSE - OK + view->contain_auto_increment is 1 if and only if the view contains an + auto_increment field + TRUE - can't be used for insert */ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) { + uint num= view->view->select_lex.item_list.elements; + TABLE *table= view->table; + Item **trans_start= view->field_translation, **trans_end=trans_start+num; + Item **trans; + Field **field_ptr= table->field; + ulong other_query_id= query_id - 1; DBUG_ENTER("check_key_in_view"); - uint i; - TABLE *table= view->table; - Item **trans= view->field_translation; - Field **field_ptr= table->field; - uint num= view->view->select_lex.item_list.elements; - ulong other_query_id= query_id - 1; DBUG_ASSERT(view->table != 0 && view->field_translation != 0); view->contain_auto_increment= 0; /* check simplicity and prepare unique test of view */ - for (i= 0; i < num; i++) + for (trans= trans_start; trans != trans_end; trans++) { + Item_field *field; /* simple SELECT list entry (field without expression) */ - if (trans[i]->type() != Item::FIELD_ITEM) + if ((*trans)->type() != Item::FIELD_ITEM) DBUG_RETURN(TRUE); - if (((Item_field *)trans[i])->field->unireg_check == Field::NEXT_NUMBER) + field= (Item_field *)(*trans); + if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ - ((Item_field *)trans[i])->field->query_id= other_query_id; + field->field->query_id= other_query_id; } /* unique test */ - for (i= 0; i < num; i++) + for (trans= trans_start; trans != trans_end; trans++) { - Item_field *field= (Item_field *)trans[i]; + /* Thanks to test above, we know that all columns are of type Item_field */ + Item_field *field= (Item_field *)(*trans); if (field->field->query_id == query_id) DBUG_RETURN(TRUE); field->field->query_id= query_id; } /* VIEW contain all fields without default value */ - for (; *field_ptr; ++field_ptr) + for (; *field_ptr; field_ptr++) { Field *field= *field_ptr; /* field have not default value */ @@ -494,14 +506,13 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) (table->timestamp_field != field || field->unireg_check == Field::TIMESTAMP_UN_FIELD)) { - uint i= 0; - for (; i < num; i++) + for (trans= trans_start; ; trans++) { - if (((Item_field *)trans[i])->field == *field_ptr) - break; + if (trans == trans_end) + DBUG_RETURN(TRUE); // Field was not part of view + if (((Item_field *)(*trans))->field == *field_ptr) + break; // ok } - if (i >= num) - DBUG_RETURN(TRUE); } } DBUG_RETURN(FALSE); @@ -509,29 +520,28 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) /* - Prepare items in INSERT statement + Check if table can be updated SYNOPSIS - mysql_prepare_insert() - thd - thread handler - table_list - global/local table list + mysql_prepare_insert_check_table() + thd Thread handle + table_list Table list (only one table) + fields List of fields to be updated + where Pointer to where clause - RETURN VALUE - 0 - OK - -1 - error (message is not sent to user) + RETURN + 0 ok + 1 ERROR */ -int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, - List &fields, List_item *values, - List &update_fields, List &update_values, - enum_duplicates duplic) + +static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, + List &fields, COND **where) { bool insert_into_view= (table_list->view != 0); - DBUG_ENTER("mysql_prepare_insert"); + DBUG_ENTER("mysql_prepare_insert_check_table"); - /* TODO: use this condition for 'WHITH CHECK OPTION' */ - Item *unused_conds= 0; - if (setup_tables(thd, table_list, &unused_conds)) - DBUG_RETURN(-1); + if (setup_tables(thd, table_list, where)) + DBUG_RETURN(1); if (insert_into_view && !fields.elements) { @@ -545,18 +555,51 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, check_view_insertability(table_list, thd->query_id))) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); - DBUG_RETURN(-1); + DBUG_RETURN(1); } + DBUG_RETURN(0); +} + + +/* + Prepare items in INSERT statement + + SYNOPSIS + mysql_prepare_insert() + thd Thread handler + table_list Global/local table list + + RETURN VALUE + 0 OK + -1 error (message is not sent to user) +*/ + +int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, + List &fields, List_item *values, + List &update_fields, List &update_values, + enum_duplicates duplic) +{ + bool insert_into_view= (table_list->view != 0); + /* TODO: use this condition for 'WITH CHECK OPTION' */ + Item *unused_conds= 0; + int res; + DBUG_ENTER("mysql_prepare_insert"); + + if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds)) + DBUG_RETURN(-1); if (check_insert_fields(thd, table_list, fields, *values, 1, !insert_into_view) || setup_fields(thd, 0, table_list, *values, 0, 0, 0) || (duplic == DUP_UPDATE && - (setup_fields(thd, 0, table_list, update_fields, 0, 0, 0) || + ((thd->lex->select_lex.no_wrap_view_item= 1, + (res= setup_fields(thd, 0, table_list, update_fields, 0, 0, 0)), + thd->lex->select_lex.no_wrap_view_item= 0, + res) || setup_fields(thd, 0, table_list, update_values, 0, 0, 0)))) DBUG_RETURN(-1); - if (find_real_table_in_list(table_list->next_global, + if (find_table_in_global_list(table_list->next_global, table_list->db, table_list->real_name)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); @@ -1558,27 +1601,11 @@ bool delayed_insert::handle_inserts(void) int mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; - TABLE_LIST *table_list= lex->query_tables; - bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_insert_select_prepare"); - - if (setup_tables(thd, table_list, &lex->select_lex.where)) + if (mysql_prepare_insert_check_table(thd, lex->query_tables, + lex->field_list, + &lex->select_lex.where)) DBUG_RETURN(-1); - - if (insert_into_view && !lex->field_list.elements) - { - lex->empty_field_list_on_rset= 1; - insert_view_fields(&lex->field_list, table_list); - } - - if (!table_list->updatable || - check_key_in_view(thd, table_list) || - (insert_into_view && - check_view_insertability(table_list, thd->query_id))) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); - DBUG_RETURN(-1); - } DBUG_RETURN(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 31c175fee88..07888a8443b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1421,7 +1421,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table) */ bool st_select_lex::check_updateable(char *db, char *table) { - if (find_real_table_in_local_list(get_table_list(), db, table)) + if (find_table_in_local_list(get_table_list(), db, table)) return 1; for (SELECT_LEX_UNIT *un= first_inner_unit(); @@ -1470,7 +1470,14 @@ void st_select_lex::print_order(String *str, ORDER *order) { for (; order; order= order->next) { - (*order->item)->print(str); + if (order->counter_used) + { + char buffer[20]; + my_snprintf(buffer, 20, "%u", order->counter); + str->append(buffer); + } + else + (*order->item)->print(str); if (!order->asc) str->append(" desc", 5); if (order->next) @@ -1655,14 +1662,16 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values, SYNOPSIS unlink_first_table() - link_to_local do we need link this table to local + link_to_local Set to 1 if caller should link this table to local NOTES We rely on fact that first table in both list are same or local list is empty RETURN + 0 If 'query_tables' == 0 unlinked table + In this case link_to_local is set. */ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) @@ -1716,11 +1725,11 @@ void st_lex::first_lists_tables_same() TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first; if (query_tables != first_table && first_table != 0) { + TABLE_LIST *next; if (query_tables_last == &first_table->next_global) query_tables_last= first_table->prev_global; - TABLE_LIST *next= *first_table->prev_global= first_table->next_global; - first_table->next_global= 0; - if (next) + + if ((next= *first_table->prev_global= first_table->next_global)) next->prev_global= first_table->prev_global; /* include in new place */ first_table->next_global= query_tables; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 84b5cf3454b..1c479444485 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -641,6 +641,7 @@ typedef struct st_lex TABLE_LIST *query_tables; /* global list of all tables in this query */ /* last element next_global of previous list */ TABLE_LIST **query_tables_last; + TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */ List col_list; List ref_list; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index fa3adf236fe..b629493a692 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -99,8 +99,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, loaded is located */ char *tdb= thd->db ? thd->db : db; // Result is never null - bool transactional_table, log_delayed; ulong skip_lines= ex->skip_lines; + int res; + bool transactional_table, log_delayed; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -114,8 +115,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_RETURN(-1); } table_list->lock_type= lock_type; - if (open_and_lock_tables(thd, table_list)) - DBUG_RETURN(-1); + if ((res= open_and_lock_tables(thd, table_list))) + DBUG_RETURN(res); /* TODO: add key check when we will support VIEWs in LOAD */ if (!table_list->updatable) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58385c67493..546183563c9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -78,6 +78,7 @@ const char *command_name[]={ "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", "Binlog Dump","Table Dump", "Connect Out", "Register Slave", "Prepare", "Prepare Execute", "Long Data", "Close stmt", + "Reset stmt", "Set option", "Fetch", "Error" // Last command number }; @@ -1910,7 +1911,7 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(first_table == all_tables && first_table != 0); */ lex->first_lists_tables_same(); - /* should be assigned after making firts tables same */ + /* should be assigned after making first tables same */ all_tables= lex->query_tables; if (lex->sql_command != SQLCOM_CREATE_PROCEDURE && @@ -2136,7 +2137,7 @@ mysql_execute_command(THD *thd) case SQLCOM_DO: if (all_tables && ((res= check_table_access(thd, SELECT_ACL, all_tables, 0)) || - (res= open_and_lock_tables(thd, all_tables)))) + (res= open_and_lock_tables(thd, all_tables)))) break; res= mysql_do(thd, *lex->insert_list); @@ -2386,8 +2387,8 @@ mysql_execute_command(THD *thd) of query */ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && - find_real_table_in_list(select_tables, create_table->db, - create_table->real_name)) + find_table_in_global_list(select_tables, create_table->db, + create_table->real_name)) { net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name); goto create_error; @@ -2400,7 +2401,6 @@ mysql_execute_command(THD *thd) if (!(res= open_and_lock_tables(thd, select_tables))) { - res= -1; // If error if ((result= new select_create(create_table, &lex->create_info, lex->create_list, @@ -2757,7 +2757,7 @@ unsent_create_error: unit->set_limit(select_lex, select_lex); // is table which we are changing used somewhere in other parts of query - if (find_real_table_in_list(all_tables->next_global, + if (find_table_in_global_list(all_tables->next_global, first_table->db, first_table->real_name)) { /* Using same table for INSERT and SELECT */ @@ -3916,7 +3916,7 @@ error: 1 - access denied, error is sent to client */ -int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) +bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) { if (check_access(thd, privilege, all_tables->db, &all_tables->grant.privilege, 0, 0)) @@ -3960,13 +3960,13 @@ bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors) { - DBUG_ENTER("check_access"); - DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access, - thd->master_access)); #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; #endif ulong dummy; + DBUG_ENTER("check_access"); + DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu", + db ? db : "", want_access, thd->master_access)); if (save_priv) *save_priv=0; else @@ -3974,8 +3974,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { + DBUG_PRINT("error",("No database")); if (!no_errors) - send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } @@ -4000,6 +4001,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) || ! db && dont_check_global_grants) { // We can never grant this + DBUG_PRINT("error",("No possible access")); if (!no_errors) net_printf(thd,ER_ACCESS_DENIED_ERROR, thd->priv_user, @@ -4018,13 +4020,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, db_access=thd->db_access; /* Remove SHOW attribute and access rights we already have */ want_access &= ~(thd->master_access | EXTRA_ACL); + DBUG_PRINT("info",("db_access: %lu want_access: %lu", + db_access, want_access)); db_access= ((*save_priv=(db_access | thd->master_access)) & want_access); /* grant_option is set if there exists a single table or column grant */ if (db_access == want_access || - ((grant_option && !dont_check_global_grants) && + (grant_option && !dont_check_global_grants && !(want_access & ~(db_access | TABLE_ACLS)))) DBUG_RETURN(FALSE); /* Ok */ + + DBUG_PRINT("error",("Access denied")); if (!no_errors) net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, @@ -4112,6 +4118,42 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, return FALSE; } + +/* + Check if the given table has any of the asked privileges + + SYNOPSIS + check_some_access() + thd Thread handler + want_access Bitmap of possible privileges to check for + + RETURN + 0 ok + 1 error +*/ + + +bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) +{ + ulong access; + DBUG_ENTER("check_some_access"); + + /* This loop will work as long as we have less than 32 privileges */ + for (access= 1; access < want_access ; access<<= 1) + { + if (access & want_access) + { + if (!check_access(thd, access, table->db, + &table->grant.privilege, 0, 1) && + !grant_option || !check_grant(thd, access, table, 0, 1, 1)) + DBUG_RETURN(0); + } + } + DBUG_PRINT("exit",("no matching access rights")); + DBUG_RETURN(1); +} + + bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list) { @@ -4247,7 +4289,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length, bool lexonly) lex->lock_option= TL_READ; lex->found_colon= 0; lex->safe_to_cache_query= 1; - lex->query_tables= 0; + lex->proc_table= lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; lex->variables_used= 0; lex->select_lex.parent_lex= lex; @@ -4936,6 +4978,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) order->asc = asc; order->free_me=0; order->used=0; + order->counter_used= 0; list.link_in_list((byte*) order,(byte**) &order->next); DBUG_RETURN(0); } @@ -4971,6 +5014,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, { register TABLE_LIST *ptr; char *alias_str; + LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); if (!table) @@ -5022,7 +5066,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; - ptr->select_lex= thd->lex->current_select; + ptr->select_lex= lex->current_select; ptr->cacheable_table= 1; if (use_index_arg) ptr->use_index=(List *) thd->memdup((gptr) use_index_arg, @@ -5046,8 +5090,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } } } + /* Link table in local list (list for current select) */ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local); - LEX *lex= thd->lex; + /* Link table in global list (all used tables) */ *(ptr->prev_global= lex->query_tables_last)= ptr; lex->query_tables_last= &ptr->next_global; DBUG_RETURN(ptr); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 452804240b6..92e235399da 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -897,10 +897,10 @@ static int mysql_test_insert(Prepared_statement *stmt, tables & preparation procedure */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, table_list)) + if ((res= open_and_lock_tables(thd, table_list))) { thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(-1); + DBUG_RETURN(res); } if ((values= its++)) @@ -969,9 +969,7 @@ static int mysql_test_update(Prepared_statement *stmt, */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, table_list)) - res= -1; - else + if (!(res= open_and_lock_tables(thd, table_list))) { if (!(res= mysql_prepare_update(thd, table_list, &select->where, @@ -1030,9 +1028,7 @@ static int mysql_test_delete(Prepared_statement *stmt, */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, table_list)) - res= -1; - else + if (!(res= open_and_lock_tables(thd, table_list))) { res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where); lex->unit.cleanup(); @@ -1065,6 +1061,7 @@ static int mysql_test_select(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX_UNIT *unit= &lex->unit; + int res; DBUG_ENTER("mysql_test_select"); @@ -1084,11 +1081,11 @@ static int mysql_test_select(Prepared_statement *stmt, tables & preparation procedure */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, tables)) + if ((res= open_and_lock_tables(thd, tables))) { - send_error(thd); goto err; } + res= 1; thd->used_tables= 0; // Updated by setup_fields @@ -1126,7 +1123,7 @@ err_prep: unit->cleanup(); err: thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(1); + DBUG_RETURN(res); } @@ -1683,8 +1680,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) if (lex->empty_field_list_on_rset) { - lex->field_list.empty(); lex->empty_field_list_on_rset= 0; + lex->field_list.empty(); } for (; sl; sl= sl->next_select_in_list()) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1768f332fd3..a7ce5320ae4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -225,25 +225,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result) thd->net.report_error)); if (thd->net.report_error) res= 1; - if (res > 0) + if (unlikely(res)) { if (result) { - result->send_error(0, NullS); + if (res > 0) + result->send_error(0, NullS); result->abort(); } - else + else if (res > 0) send_error(thd, 0, NullS); res= 1; // Error sent to client } - if (res < 0) - { - if (result) - { - result->abort(); - } - res= 1; - } if (result != lex->result) delete result; DBUG_RETURN(res); @@ -348,9 +341,7 @@ JOIN::prepare(Item ***rref_pointer_array, if ((subselect= select_lex->master_unit()->item)) { Item_subselect::trans_res res; - if ((res= ((!thd->lex->view_prepare_mode) ? - subselect->select_transformer(this) : - subselect->no_select_transform())) != + if ((res= subselect->select_transformer(this)) != Item_subselect::RES_OK) { select_lex->fix_prepare_information(thd, &conds); @@ -552,6 +543,7 @@ JOIN::optimize() if (cond_value == Item::COND_FALSE || (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) { /* Impossible cond */ + DBUG_PRINT("info", ("Impossible WHERE")); zero_result_cause= "Impossible WHERE"; error= 0; DBUG_RETURN(0); @@ -569,20 +561,24 @@ JOIN::optimize() { if (res > 1) { + DBUG_PRINT("error",("Error from opt_sum_query")); DBUG_RETURN(1); } if (res < 0) { + DBUG_PRINT("info",("No matching min/max row")); zero_result_cause= "No matching min/max row"; error=0; DBUG_RETURN(0); } + DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved } } if (!tables_list) { + DBUG_PRINT("info",("No tables")); error= 0; DBUG_RETURN(0); } @@ -10066,8 +10062,10 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, thd->where); return 1; } - order->item= ref_pointer_array + count-1; + order->item= ref_pointer_array + count - 1; order->in_field_list= 1; + order->counter= count; + order->counter_used= 1; return 0; } uint counter; @@ -11568,7 +11566,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) SYNOPSIS print_join() thd thread handler - str string where table should bbe printed + str string where table should be printed tables list of tables in join */ @@ -11624,30 +11622,31 @@ void st_table_list::print(THD *thd, String *str) print_join(thd, str, &nested_join->join_list); str->append(')'); } - else if (view_name.str) - { - append_identifier(thd, str, view_db.str, view_db.length); - str->append('.'); - append_identifier(thd, str, view_name.str, view_name.length); - if (my_strcasecmp(table_alias_charset, view_name.str, alias)) - { - str->append(' '); - append_identifier(thd, str, alias, strlen(alias)); - } - } - else if (derived) - { - str->append('('); - derived->print(str); - str->append(") ", 2); - append_identifier(thd, str, alias, strlen(alias)); - } else { - append_identifier(thd, str, db, db_length); - str->append('.'); - append_identifier(thd, str, real_name, real_name_length); - if (my_strcasecmp(table_alias_charset, real_name, alias)) + const char *cmp_name; // Name to compare with alias + if (view_name.str) + { + append_identifier(thd, str, view_db.str, view_db.length); + str->append('.'); + append_identifier(thd, str, view_name.str, view_name.length); + cmp_name= view_name.str; + } + else if (derived) + { + str->append('('); + derived->print(str); + str->append(')'); + cmp_name= ""; // Force printing of alias + } + else + { + append_identifier(thd, str, db, db_length); + str->append('.'); + append_identifier(thd, str, real_name, real_name_length); + cmp_name= real_name; + } + if (my_strcasecmp(table_alias_charset, cmp_name, alias)) { str->append(' '); append_identifier(thd, str, alias, strlen(alias)); @@ -11663,7 +11662,7 @@ void st_select_lex::print(THD *thd, String *str) str->append("select ", 7); - //options + /* First add options */ if (options & SELECT_STRAIGHT_JOIN) str->append("straight_join ", 14); if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) && diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fa8b81f8ea2..f7b98bb0738 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -497,6 +497,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) TABLE *table; Protocol *protocol= thd->protocol; TIME time; + int res; DBUG_ENTER("mysqld_extend_show_tables"); (void) sprintf(path,"%s/%s",mysql_data_home,db); @@ -554,13 +555,18 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) table_list.select_lex= &thd->lex->select_lex; if (lower_case_table_names) my_casedn_str(files_charset_info, file_name); - if (open_and_lock_tables(thd, &table_list)) + if ((res= open_and_lock_tables(thd, &table_list))) { for (uint i=2 ; i < field_list.elements ; i++) protocol->store_null(); - // Send error to Comment field - protocol->store(thd->net.last_error, system_charset_info); - thd->clear_error(); + // Send error to Comment field if possible + if (res < 0) + { + protocol->store(thd->net.last_error, system_charset_info); + thd->clear_error(); + } + else + DBUG_RETURN(1) } else if (table_list.view) { @@ -695,14 +701,16 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, char tmp[MAX_FIELD_WIDTH]; Item *item; Protocol *protocol= thd->protocol; + int res; DBUG_ENTER("mysqld_show_fields"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); table_list->lock_type= TL_UNLOCK; - if (open_and_lock_tables(thd, table_list)) + if ((res= open_and_lock_tables(thd, table_list))) { - send_error(thd); + if (res < 0) + send_error(thd); DBUG_RETURN(1); } table= table_list->table; @@ -836,14 +844,16 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); + int res; DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); /* Only one table for now, but VIEW can involve several tables */ - if (open_and_lock_tables(thd, table_list)) + if ((res= open_and_lock_tables(thd, table_list))) { - send_error(thd); + if (res < 0) + send_error(thd); DBUG_RETURN(1); } /* TODO: add environment variables show when it become possible */ @@ -1565,11 +1575,11 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) MODE_MAXDB | MODE_ANSI)) != 0; buff->append("CREATE ", 7); - if(!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE || - table->algorithm == VIEW_ALGORITHM_TMEPTABLE)) + if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE || + table->algorithm == VIEW_ALGORITHM_TMPTABLE)) { buff->append("ALGORITHM=", 10); - if (table->algorithm == VIEW_ALGORITHM_TMEPTABLE) + if (table->algorithm == VIEW_ALGORITHM_TMPTABLE) buff->append("TMPTABLE ", 9); else buff->append("MERGE ", 6); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 61fb4b97200..9d7134aee84 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -113,8 +113,8 @@ int mysql_update(THD *thd, LINT_INIT(used_index); LINT_INIT(timestamp_query_id); - if ((open_and_lock_tables(thd, table_list))) - DBUG_RETURN(-1); + if ((error= open_and_lock_tables(thd, table_list))) + DBUG_RETURN(error); thd->proc_info="init"; table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -496,7 +496,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(-1); /* Check that we are not using table that we are updating in a sub select */ - if (find_real_table_in_list(table_list->next_global, + if (find_table_in_global_list(table_list->next_global, table_list->db, table_list->real_name)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); @@ -788,7 +788,7 @@ int multi_update::prepare(List ¬_used_values, { TABLE *table=table_ref->table; if (!(tables_to_update & table->map) && - find_real_table_in_list(update_tables, table_ref->db, + find_table_in_global_list(update_tables, table_ref->db, table_ref->real_name)) table->no_cache= 1; // Disable row cache } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 3f0e0db1724..2b1971907b3 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -59,12 +59,21 @@ int mysql_create_view(THD *thd, int res= 0; DBUG_ENTER("mysql_create_view"); - if (lex->derived_tables || lex->proc_list.first || + if (lex->proc_list.first || + lex->result) + { + my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), (lex->result ? + "INTO" : + "PROCEDURE")); + res= -1; + goto err; + } + if (lex->derived_tables || lex->variables_used || lex->param_list.elements) { - my_error((lex->derived_tables ? ER_VIEW_SELECT_DERIVED : - (lex->proc_list.first ? ER_VIEW_SELECT_PROCEDURE : - ER_VIEW_SELECT_VARIABLE)), MYF(0)); + my_error((lex->derived_tables ? + ER_VIEW_SELECT_DERIVED : + ER_VIEW_SELECT_VARIABLE), MYF(0)); res= -1; goto err; } @@ -81,25 +90,8 @@ int mysql_create_view(THD *thd, /* Ensure that we have some privilage on this table, more strict check will be done on column level after preparation, - - SELECT_ACL will be checked for sure for all fields because it is - listed first (if we have not rights to SELECT from whole table this - right will be written as tbl->grant.want_privilege and will be checked - later (except fields which need any privilege and can be updated). */ - if ((check_access(thd, SELECT_ACL, tbl->db, - &tbl->grant.privilege, 0, 1) || - grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 1)) && - (check_access(thd, INSERT_ACL, tbl->db, - &tbl->grant.privilege, 0, 1) || - grant_option && check_grant(thd, INSERT_ACL, tbl, 0, 1, 1)) && - (check_access(thd, DELETE_ACL, tbl->db, - &tbl->grant.privilege, 0, 1) || - grant_option && check_grant(thd, DELETE_ACL, tbl, 0, 1, 1)) && - (check_access(thd, UPDATE_ACL, tbl->db, - &tbl->grant.privilege, 0, 1) || - grant_option && check_grant(thd, UPDATE_ACL, tbl, 0, 1, 1)) - ) + if (check_some_access(thd, VIEW_ANY_ACL, tbl)) { my_printf_error(ER_TABLEACCESS_DENIED_ERROR, ER(ER_TABLEACCESS_DENIED_ERROR), @@ -115,7 +107,7 @@ int mysql_create_view(THD *thd, /* We need to check only SELECT_ACL for all normal fields, fields - where we need any privilege will be pmarked later + where we need any privilege will be marked later */ tbl->grant.want_privilege= SELECT_ACL; /* @@ -167,7 +159,7 @@ int mysql_create_view(THD *thd, /* check that tables are not temporary */ for (tbl= tables; tbl; tbl= tbl->next_global) { - if (tbl->table->tmp_table != NO_TMP_TABLE && !test(tbl->view)) + if (tbl->table->tmp_table != NO_TMP_TABLE && !tbl->view) { my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias); res= -1; @@ -197,19 +189,18 @@ int mysql_create_view(THD *thd, /* view list (list of view fields names) */ if (lex->view_list.elements) { + List_iterator_fast it(select_lex->item_list); + List_iterator_fast nm(lex->view_list); + Item *item; + LEX_STRING *name; + if (lex->view_list.elements != select_lex->item_list.elements) { my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0)); goto err; } - List_iterator_fast it(select_lex->item_list); - List_iterator_fast nm(lex->view_list); - Item *item; - LEX_STRING *name; - while((item= it++, name= nm++)) - { + while ((item= it++, name= nm++)) item->set_name(name->str, name->length, system_charset_info); - } } /* Test absence of duplicates names */ @@ -217,11 +208,11 @@ int mysql_create_view(THD *thd, Item *item; List_iterator_fast it(select_lex->item_list); it++; - while((item= it++)) + while ((item= it++)) { Item *check; List_iterator_fast itc(select_lex->item_list); - while((check= itc++) && check != item) + while ((check= itc++) && check != item) { if (strcmp(item->name, check->name) == 0) { @@ -243,7 +234,7 @@ int mysql_create_view(THD *thd, Item *item; fill_effective_table_privileges(thd, &view->grant, db, view->real_name); - while((item= it++)) + while ((item= it++)) { uint priv= (get_column_grant(thd, &view->grant, db, view->real_name, item->name) & @@ -252,10 +243,10 @@ int mysql_create_view(THD *thd, { Item_field *fld= (Item_field *)item; /* - There are no any privileges on VIWE column or there are + There are no any privileges on VIEW column or there are some other privileges then we have for underlaying table */ - if (priv == 0 || test(~fld->have_privileges & priv)) + if (priv == 0 || (~fld->have_privileges & priv)) { /* VIEW column has more privileges */ my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, @@ -271,7 +262,7 @@ int mysql_create_view(THD *thd, } else { - if (!test(priv & SELECT_ACL)) + if (!(priv & SELECT_ACL)) { /* user have not privilege to SELECT expression */ my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, @@ -295,14 +286,11 @@ int mysql_create_view(THD *thd, goto err; } VOID(pthread_mutex_lock(&LOCK_open)); - if ((res= mysql_register_view(thd, view, mode))) - { - VOID(pthread_mutex_unlock(&LOCK_open)); - start_waiting_global_read_lock(thd); - goto err; - } + res= mysql_register_view(thd, view, mode); VOID(pthread_mutex_unlock(&LOCK_open)); start_waiting_global_read_lock(thd); + if (res) + goto err; send_ok(thd); lex->link_first_table_back(view, link_to_local); @@ -318,38 +306,34 @@ err: } -// index of revision number in following table -static const int revision_number_position= 4; +/* index of revision number in following table */ +static const int revision_number_position= 5; +/* index of last required parameter for making view */ +static const int required_view_parameters= 7; -static char *view_field_names[]= -{ - (char*)"query", - (char*)"md5", - (char*)"updatable", - (char*)"algorithm", - (char*)"revision", - (char*)"timestamp", - (char*)"create-version", - (char*)"source" -}; +/* + table of VIEW .frm field descriptors + + Note that one should NOT change the order for this, as it's used by + parse() +*/ -// table of VIEW .frm field descriprors static File_option view_parameters[]= -{{{view_field_names[0], 5}, offsetof(TABLE_LIST, query), +{{{(char*) "query", 5}, offsetof(TABLE_LIST, query), FILE_OPTIONS_STRING}, - {{view_field_names[1], 3}, offsetof(TABLE_LIST, md5), + {{(char*) "md5", 3}, offsetof(TABLE_LIST, md5), FILE_OPTIONS_STRING}, - {{view_field_names[2], 9}, offsetof(TABLE_LIST, updatable_view), + {{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable_view), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[3], 9}, offsetof(TABLE_LIST, algorithm), + {{(char*) "algorithm", 9}, offsetof(TABLE_LIST, algorithm), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[4], 8}, offsetof(TABLE_LIST, revision), + {{(char*) "revision", 8}, offsetof(TABLE_LIST, revision), FILE_OPTIONS_REV}, - {{view_field_names[5], 9}, offsetof(TABLE_LIST, timestamp), + {{(char*) "timestamp", 9}, offsetof(TABLE_LIST, timestamp), FILE_OPTIONS_TIMESTAMP}, - {{view_field_names[6], 14}, offsetof(TABLE_LIST, file_version), + {{(char*)"create-version", 14},offsetof(TABLE_LIST, file_version), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[7], 6}, offsetof(TABLE_LIST, source), + {{(char*) "source", 6}, offsetof(TABLE_LIST, source), FILE_OPTIONS_ESTRING}, {{NULL, 0}, 0, FILE_OPTIONS_STRING} @@ -402,16 +386,18 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, dir.length= strlen(dir_buff); file.str= file_buff; - file.length= my_snprintf(file_buff, FN_REFLEN, "%s%s", - view->real_name, reg_ext); + file.length= (strxnmov(file_buff, FN_REFLEN, view->real_name, reg_ext, + NullS) - file_buff); /* init timestamp */ - if (!test(view->timestamp.str)) + if (!view->timestamp.str) view->timestamp.str= view->timestamp_buffer; // check old .frm { char path_buff[FN_REFLEN]; LEX_STRING path; + File_parser *parser; + path.str= path_buff; fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME); path.length= strlen(path_buff); @@ -424,34 +410,27 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, DBUG_RETURN(1); } - File_parser *parser= sql_parse_prepare(&path, &thd->mem_root, 0); - if (parser) - { - if(parser->ok() && - !strncmp("VIEW", parser->type()->str, parser->type()->length)) - { - /* - read revision number - - TODO: read dependense list, too, to process cascade/restrict - TODO: special cascade/restrict procedure for alter? - */ - if (parser->parse((gptr)view, &thd->mem_root, - view_parameters + revision_number_position, 1)) - { - DBUG_RETURN(1); - } - } - else - { - my_error(ER_WRONG_OBJECT, MYF(0), (view->db?view->db:thd->db), - view->real_name, "VIEW"); - DBUG_RETURN(1); - } - } - else - { + if (!(parser= sql_parse_prepare(&path, &thd->mem_root, 0))) DBUG_RETURN(1); + + if (!parser->ok() || + strncmp("VIEW", parser->type()->str, parser->type()->length)) + { + my_error(ER_WRONG_OBJECT, MYF(0), (view->db ? view->db : thd->db), + view->real_name, "VIEW"); + DBUG_RETURN(1); + } + + /* + read revision number + + TODO: read dependense list, too, to process cascade/restrict + TODO: special cascade/restrict procedure for alter? + */ + if (parser->parse((gptr)view, &thd->mem_root, + view_parameters + revision_number_position, 1)) + { + DBUG_RETURN(1); } } else @@ -482,14 +461,14 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, } view->algorithm= thd->lex->create_view_algorithm; if ((view->updatable_view= (can_be_merged && - view->algorithm != VIEW_ALGORITHM_TMEPTABLE))) + view->algorithm != VIEW_ALGORITHM_TMPTABLE))) { // TODO: change here when we will support UNIONs for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first; tbl; tbl= tbl->next_local) { - if (tbl->view != 0 && !tbl->updatable_view) + if (tbl->view && !tbl->updatable_view) { view->updatable_view= 0; break; @@ -514,18 +493,21 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, table - TABLE_LIST structure for filling RETURN - TRUE OK - FALSE error + 0 ok + 1 error + */ + my_bool mysql_make_view(File_parser *parser, TABLE_LIST *table) { + bool include_proc_table= 0; DBUG_ENTER("mysql_make_view"); if (table->view) { DBUG_PRINT("info", - ("VIEW %s.%s is already processed on previos PS/SP execution", + ("VIEW %s.%s is already processed on previous PS/SP execution", table->view_db.str, table->view_name.str)); DBUG_RETURN(0); } @@ -545,13 +527,14 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) thd->set_n_backup_item_arena(arena, &backup); /* init timestamp */ - if (!test(table->timestamp.str)) + if (!table->timestamp.str) table->timestamp.str= table->timestamp_buffer; /* TODO: when VIEWs will be stored in cache, table mem_root should be used here */ - if (parser->parse((gptr)table, &thd->mem_root, view_parameters, 6)) + if (parser->parse((gptr)table, &thd->mem_root, view_parameters, + required_view_parameters)) goto err; /* @@ -603,7 +586,10 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) */ thd->options&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES); + CHARSET_INFO *save_cs= thd->variables.character_set_client; + thd->variables.character_set_client= system_charset_info; res= yyparse((void *)thd); + thd->variables.character_set_client= save_cs; thd->options= options; } if (!res && !thd->is_fatal_error) @@ -612,8 +598,23 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->belong_to_view : table); - /* move SP to main LEX */ - sp_merge_funs(old_lex, lex); + if (lex->spfuns.records) + { + /* move SP to main LEX */ + sp_merge_funs(old_lex, lex); + if (old_lex->proc_table == 0 && + (old_lex->proc_table= + (TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0) + { + TABLE_LIST *table= old_lex->proc_table; + table->db= (char*)"mysql"; + table->db_length= 5; + table->real_name= table->alias= (char*)"proc"; + table->real_name_length= 4; + table->cacheable_table= 1; + include_proc_table= 1; + } + } if (lex->spfuns.array.buffer) hash_free(&lex->spfuns); @@ -656,7 +657,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) - VIEW SELECT allow marging - VIEW used in subquery or command support MERGE algorithm */ - if (table->algorithm != VIEW_ALGORITHM_TMEPTABLE && + if (table->algorithm != VIEW_ALGORITHM_TMPTABLE && lex->can_be_merged() && (table->select_lex->master_unit() != &old_lex->unit || old_lex->can_use_merged()) && @@ -702,7 +703,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) goto ok; } - table->effective_algorithm= VIEW_ALGORITHM_TMEPTABLE; + table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE; DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE")); lex->select_lex.linkage= DERIVED_TABLE_TYPE; table->updatable= 0; @@ -715,7 +716,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) { if ((tbl_end= table->next_global)) { - for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next); + for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next) + ; if ((tbl_end->next_global= old_next)) tbl_end->next_global->prev_global= &tbl_end->next_global; } @@ -742,6 +744,17 @@ ok: lex->all_selects_list->link_prev= (st_select_lex_node**)&old_lex->all_selects_list; + if (include_proc_table) + { + TABLE_LIST *proc= old_lex->proc_table; + if((proc->next_global= table->next_global)) + { + table->next_global->prev_global= &proc->next_global; + } + proc->prev_global= &table->next_global; + table->next_global= proc; + } + thd->lex= old_lex; DBUG_RETURN(0); @@ -768,6 +781,7 @@ err: -1 Error 1 Error and error message given */ + int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) { DBUG_ENTER("mysql_drop_view"); @@ -777,8 +791,8 @@ int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) for (view= views; view; view= view->next_local) { - strxmov(path, mysql_data_home, "/", view->db, "/", view->real_name, - reg_ext, NullS); + strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/", + view->real_name, reg_ext, NullS); (void) unpack_filename(path, path); VOID(pthread_mutex_lock(&LOCK_open)); if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW))) @@ -830,21 +844,20 @@ frm_type_enum mysql_frm_type(char *path) { File file; char header[10]; //"TYPE=VIEW\n" it is 10 characters + int length; DBUG_ENTER("mysql_frm_type"); if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0) { DBUG_RETURN(FRMTYPE_ERROR); } - if (my_read(file, (byte*) header, 10, MYF(MY_WME)) == MY_FILE_ERROR) - { - my_close(file, MYF(MY_WME)); - DBUG_RETURN(FRMTYPE_ERROR); - } + length= my_read(file, (byte*) header, 10, MYF(MY_WME)); my_close(file, MYF(MY_WME)); - if (strncmp(header, "TYPE=VIEW\n", 10) != 0) - DBUG_RETURN(FRMTYPE_TABLE); - DBUG_RETURN(FRMTYPE_VIEW); + if (length == (int) MY_FILE_ERROR) + DBUG_RETURN(FRMTYPE_ERROR); + if (!strncmp(header, "TYPE=VIEW\n", 10)) + DBUG_RETURN(FRMTYPE_VIEW); + DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table } @@ -863,72 +876,81 @@ frm_type_enum mysql_frm_type(char *path) bool check_key_in_view(THD *thd, TABLE_LIST *view) { + TABLE *table; + Item **trans; + KEY *key_info, *key_info_end; + uint i, elements_in_view; DBUG_ENTER("check_key_in_view"); + if (!view->view) DBUG_RETURN(FALSE); /* it is normal table */ + table= view->table; + trans= view->field_translation; + key_info_end= (key_info= table->key_info)+ table->keys; - TABLE *table= view->table; - Item **trans= view->field_translation; - KEY *key_info= table->key_info; - uint primary_key= table->primary_key; - uint num= view->view->select_lex.item_list.elements; + elements_in_view= view->view->select_lex.item_list.elements; DBUG_ASSERT(view->table != 0 && view->field_translation != 0); - /* try to find key */ - for (uint i=0; i < table->keys; i++, key_info++) + /* Loop over all keys to see if a unique-not-null key is used */ + for (;key_info != key_info_end ; key_info++) { - if (i == primary_key && !strcmp(key_info->name, primary_key_name) || - key_info->flags & HA_NOSAME) + if ((key_info->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) { KEY_PART_INFO *key_part= key_info->key_part; - bool found= 1; - for (uint j=0; j < key_info->key_parts && found; j++, key_part++) + KEY_PART_INFO *key_part_end= key_part + key_info->key_parts; + + /* check that all key parts are used */ + for (;;) { - found= 0; - for (uint k= 0; k < num; k++) + uint k; + for (k= 0; k < elements_in_view; k++) { if (trans[k]->type() == Item::FIELD_ITEM && - ((Item_field *)trans[k])->field == key_part->field && - (key_part->field->flags & NOT_NULL_FLAG)) - { - found= 1; + ((Item_field *)trans[k])->field == key_part->field) break; - } } + if (k == elements_in_view) + break; // Key is not possible + if (++key_part == key_part_end) + DBUG_RETURN(FALSE); // Found usable key } - if (found) - DBUG_RETURN(FALSE); } } + DBUG_PRINT("info", ("checking if all fields of table are used")); /* check all fields presence */ { - Field **field_ptr= table->field; - for (; *field_ptr; ++field_ptr) + Field **field_ptr; + for (field_ptr= table->field; *field_ptr; field_ptr++) { - uint i= 0; - for (; i < num; i++) + for (i= 0; i < elements_in_view; i++) { if (trans[i]->type() == Item::FIELD_ITEM && ((Item_field *)trans[i])->field == *field_ptr) break; } - if (i >= num) + if (i == elements_in_view) // If field didn't exists { ulong mode= thd->variables.sql_updatable_view_key; - /* 1 == YES, 2 == LIMIT1 */ + /* + 0 == NO ; Don't give any errors + 1 == YES ; Give always an error + 2 == LIMIT1 ; Give an error if this is used with LIMIT 1 + This is used to protect against gui programs that + uses LIMIT 1 to update just the current row. This + doesn't work reliable if the view doesn't have a + unique key or if the view doesn't use all fields in + table. + */ if (mode == 1 || (mode == 2 && - thd->lex->select_lex.select_limit == 1)) + thd->lex->unit.global_parameters->select_limit == 1)) { DBUG_RETURN(TRUE); } - else - { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY)); - DBUG_RETURN(FALSE); - } + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY)); + DBUG_RETURN(FALSE); } } } @@ -947,18 +969,17 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) void insert_view_fields(List *list, TABLE_LIST *view) { - uint num= view->view->select_lex.item_list.elements; - Item **trans= view->field_translation; + uint elements_in_view= view->view->select_lex.item_list.elements; + Item **trans; DBUG_ENTER("insert_view_fields"); - if (!trans) + + if (!(trans= view->field_translation)) DBUG_VOID_RETURN; - for (uint i= 0; i < num; i++) + for (uint i= 0; i < elements_in_view; i++) { if (trans[i]->type() == Item::FIELD_ITEM) - { list->push_back(trans[i]); - } } DBUG_VOID_RETURN; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 172ec48fb18..ba3a36f2c34 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7553,7 +7553,7 @@ algorithm: | ALGORITHM_SYM EQ MERGE_SYM { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; } | ALGORITHM_SYM EQ TEMPTABLE_SYM - { Lex->create_view_algorithm= VIEW_ALGORITHM_TMEPTABLE; } + { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; } ; check_option: /* empty */ {} diff --git a/sql/table.cc b/sql/table.cc index 3e481443801..1764df75a7e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -88,6 +88,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam)); error=1; + disk_buff=NULL; + old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); if ((file=my_open(fn_format(index_file, name, "", reg_ext, MY_UNPACK_FILENAME), @@ -118,11 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, bzero((char*) outparam,sizeof(*outparam)); outparam->blob_ptr_size=sizeof(char*); - disk_buff=NULL; record= NULL; keynames=NullS; outparam->db_stat = db_stat; - init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root); outparam->real_name=strdup_root(&outparam->mem_root, @@ -742,11 +741,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, DBUG_RETURN (0); err_w_init: - //awoid problem with uninitialized data + /* Avoid problem with uninitialized data */ bzero((char*) outparam,sizeof(*outparam)); outparam->real_name= (char*)name+dirname_length(name); - old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); - disk_buff= 0; err_not_open: x_free((gptr) disk_buff); @@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name) st_table_list::calc_md5() buffer buffer for md5 writing */ + void st_table_list::calc_md5(char *buffer) { my_MD5_CTX context; - unsigned char digest[16]; - my_MD5Init (&context); - my_MD5Update (&context,(unsigned char *) query.str, query.length); - my_MD5Final (digest, &context); + uchar digest[16]; + my_MD5Init(&context); + my_MD5Update(&context,(uchar *) query.str, query.length); + my_MD5Final(digest, &context); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], @@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer) SYNOPSIS st_table_list::set_ancestor() */ + void st_table_list::set_ancestor() { if (ancestor->ancestor) @@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor() (without fields) for name resolving, but substituted expressions will return correct used tables mask. */ + bool st_table_list::setup_ancestor(THD *thd, Item **conds) { Item **transl; @@ -1520,15 +1520,15 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) thd->set_query_id= 1; /* this view was prepared already on previous PS/SP execution */ Item **end= field_translation + select->item_list.elements; - for (Item **i= field_translation; i < end; i++) + for (Item **item= field_translation; item < end; item++) { - //TODO: fix for several tables in VIEW + /* TODO: fix for several tables in VIEW */ uint want_privilege= ancestor->table->grant.want_privilege; /* real rights will be checked in VIEW field */ ancestor->table->grant.want_privilege= 0; /* aggregate function are allowed */ thd->allow_sum_func= 1; - if (!(*i)->fixed && (*i)->fix_fields(thd, ancestor, i)) + if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item)) goto err; ancestor->table->grant.want_privilege= want_privilege; } @@ -1557,21 +1557,19 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) thd->set_query_id= 1; while ((item= it++)) { - //TODO: fix for several tables in VIEW + /* TODO: fix for several tables in VIEW */ uint want_privilege= ancestor->table->grant.want_privilege; /* real rights will be checked in VIEW field */ ancestor->table->grant.want_privilege= 0; /* aggregate function are allowed */ thd->allow_sum_func= 1; if (!item->fixed && item->fix_fields(thd, ancestor, &item)) - { goto err; - } ancestor->table->grant.want_privilege= want_privilege; transl[i++]= item; } field_translation= transl; - //TODO: sort this list? Use hash for big number of fields + /* TODO: sort this list? Use hash for big number of fields */ if (where) { @@ -1580,12 +1578,12 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) goto err; if (arena) - thd->set_n_backup_item_arena(arena, &backup); + thd->set_n_backup_item_arena(arena, &backup); if (outer_join) { /* Store WHERE condition to ON expression for outer join, because we - can't use WHERE to correctly execute jeft joins on VIEWs and this + can't use WHERE to correctly execute jeft joins on VIEWs and this expression will not be moved to WHERE condition (i.e. will be clean correctly for PS/SP) */ diff --git a/sql/table.h b/sql/table.h index dd41ab79b7b..b7cabe21638 100644 --- a/sql/table.h +++ b/sql/table.h @@ -29,9 +29,12 @@ typedef struct st_order { Item **item; /* Point at item in select fields */ Item *item_ptr; /* Storage for initial item */ Item **item_copy; /* For SPs; the original item ptr */ + int counter; /* position in SELECT list, correct + only if counter_used is true*/ bool asc; /* true if ascending */ bool free_me; /* true if item isn't shared */ bool in_field_list; /* true if in select field list */ + bool counter_used; /* parapeter was counter of columns */ Field *field; /* If tmp-table group */ char *buff; /* If tmp-table group */ table_map used,depend_map; @@ -179,7 +182,7 @@ struct st_table { #define JOIN_TYPE_RIGHT 2 #define VIEW_ALGORITHM_UNDEFINED 0 -#define VIEW_ALGORITHM_TMEPTABLE 1 +#define VIEW_ALGORITHM_TMPTABLE 1 #define VIEW_ALGORITHM_MERGE 2 struct st_lex; @@ -222,7 +225,7 @@ typedef struct st_table_list LEX_STRING view_name; /* save view name */ LEX_STRING timestamp; /* GMT time stamp of last operation */ ulonglong file_version; /* version of file's field set */ - ulonglong updatable_view; /* VIEW can be updated */ + ulonglong updatable_view; /* VIEW can be updated */ ulonglong revision; /* revision control number */ ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */ uint effective_algorithm; /* which algorithm was really used */ @@ -267,7 +270,7 @@ public: virtual ~Field_iterator() {} virtual void set(TABLE_LIST *)= 0; virtual void next()= 0; - virtual bool end()= 0; + virtual bool end_of_fields()= 0; /* Return 1 at end of list */ virtual const char *name()= 0; virtual Item *item(THD *)= 0; virtual Field *field()= 0; @@ -282,7 +285,7 @@ public: void set(TABLE_LIST *table) { ptr= table->table->field; } void set_table(TABLE *table) { ptr= table->field; } void next() { ptr++; } - bool end() { return test(*ptr); } + bool end_of_fields() { return *ptr == 0; } const char *name(); Item *item(THD *thd); Field *field() { return *ptr; } @@ -296,7 +299,7 @@ public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table); void next() { ptr++; } - bool end() { return ptr < array_end; } + bool end_of_fields() { return ptr == array_end; } const char *name(); Item *item(THD *thd) { return *ptr; } Field *field() { return 0; } diff --git a/tests/client_test.c b/tests/client_test.c index a47e22fe7d8..08ea345a355 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -30,6 +30,7 @@ #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ +#define MAX_KEY 64 /* set default options */ static char *opt_db= 0; @@ -5507,6 +5508,7 @@ static void test_subselect() MYSQL_STMT *stmt; int rc, id; MYSQL_BIND bind[1]; + DBUG_ENTER("test_subselect"); myheader("test_subselect"); @@ -5608,6 +5610,7 @@ static void test_subselect() assert(rc == MYSQL_NO_DATA); mysql_stmt_close(stmt); + DBUG_VOID_RETURN; } @@ -7018,13 +7021,13 @@ static void test_explain_bug() "", "", "", 10, 0); verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, - "", "", "", NAME_LEN*64, 0); + "", "", "", NAME_LEN*MAX_KEY, 0); verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN, 0); verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, - "", "", "", NAME_LEN*64, 0); + "", "", "", NAME_LEN*MAX_KEY, 0); verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN*16, 0);