Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mishka.local:/home/my/mysql-5.0 BitKeeper/etc/logging_ok: auto-union sql/mysql_priv.h: Auto merged sql/sp.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_lex.cc: Auto merged
This commit is contained in:
commit
ac473c3813
@ -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
|
||||
|
@ -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 <my_alloc.h>
|
||||
|
||||
/* 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 *);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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` (
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 <union1,3> 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<t2.a*4 order by 1 desc limit 1), a from t2;
|
||||
(select a from t3 where a<t2.a*4 order by 1 desc limit 1) a
|
||||
3 1
|
||||
@ -202,7 +202,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using where
|
||||
2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where; Using filesort
|
||||
Warnings:
|
||||
Note 1003 select (select `test`.`t3`.`a` AS `a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by `test`.`t3`.`a` 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`
|
||||
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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
316
mysys/default.c
316
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));
|
||||
|
78
sql/item.cc
78
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
|
||||
|
10
sql/item.h
10
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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -3270,9 +3270,25 @@ Item_func_sp::Item_func_sp(sp_name *name, List<Item> &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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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(')');
|
||||
}
|
||||
|
10
sql/log.cc
10
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;
|
||||
}
|
||||
|
@ -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<Item> &fields,List<Item> &values, bool ignore_errors);
|
||||
int fill_record(Field **field,List<Item> &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);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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 имеют разное количество столбцов"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -357,7 +357,7 @@ character-set=koi8u
|
||||
"'%-.64s.%-.64s' ΞΕ € %s"
|
||||
"σΤΟΧΒΕΓΨ '%-.64s' ΞΕ ΝΟΦΕ ΒΥΤΙ ΪΝΙΞΕΞΙΚ"
|
||||
"View SELECT ΝΑ€ Π¦ΔΪΑΠΙΤ Υ ΛΟΞΣΤ<CEA3>ΥΛΓ¦§ FROM"
|
||||
"View SELECT ÍÁ¤ ËÏÎÓÔÒÕËæÀ PROCEDURE"
|
||||
"View SELECT ÍÁ¤ ËÏÎÓÔÒÕËæÀ '%s'"
|
||||
"View SELECT ΝΑ€ ΪΝΙΞΞΥ ΑΒΟ ΠΑ<CEA0>ΑΝΕΤΕ<CEA4>"
|
||||
"View SELECT ΧΙΛΟ<CE9B>ΙΣΤΟΧΥ€ ΤΙΝήΑΣΟΧΥ ΤΑΒΜΙΓΐ '%-.64s'"
|
||||
"View SELECT ¦ ΠΕ<CEA0>ΕΜ¦Λ ΣΤΟΧΒΓ¦Χ view ΝΑΐΤΨ <20>¦ΪΞΥ Λ¦ΜΨΛ¦ΣΤΨ ΣΛΟΧΒΓ¦Χ"
|
||||
|
14
sql/sp.cc
14
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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
217
sql/sql_base.cc
217
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<Item> *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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -51,6 +51,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
List<Item> &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<Item> &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<Item> &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<Item> &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<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields, List<Item> &update_values,
|
||||
enum_duplicates duplic)
|
||||
|
||||
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> &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<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields, List<Item> &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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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<key_part_spec> col_list;
|
||||
List<key_part_spec> ref_list;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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<String> *) 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);
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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) &&
|
||||
|
@ -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);
|
||||
|
@ -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<Item> ¬_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
|
||||
}
|
||||
|
333
sql/sql_view.cc
333
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<Item> it(select_lex->item_list);
|
||||
List_iterator_fast<LEX_STRING> 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<Item> it(select_lex->item_list);
|
||||
List_iterator_fast<LEX_STRING> 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<Item> it(select_lex->item_list);
|
||||
it++;
|
||||
while((item= it++))
|
||||
while ((item= it++))
|
||||
{
|
||||
Item *check;
|
||||
List_iterator_fast<Item> 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<Item> *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;
|
||||
}
|
||||
|
@ -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 */ {}
|
||||
|
36
sql/table.cc
36
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)
|
||||
*/
|
||||
|
13
sql/table.h
13
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; }
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user