From 824acf6ee5f443bfdeb2429d0fd966152137407a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Aug 2004 18:17:50 +0400 Subject: [PATCH 01/22] Please rewiev. Here added a function to process config. files options. A lot of the default.c module code was refactored. The patch is needed for the IM. include/my_sys.h: Definitions added. mysys/default.c: Added new api call: process_default_option_files. Also some coments changed to reflect current state of the code. It takes Basename for config file and the function to process options. The function is called everytime when we find an option. This way it is possible to get and process options from several groups in one file traversal. BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + include/my_sys.h | 7 + mysys/default.c | 310 +++++++++++++++++++++++++++------------ 3 files changed, 228 insertions(+), 90 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index bd45ae65224..b850584df5b 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -31,6 +31,7 @@ bk@mysql.r18.ru brian@avenger.(none) brian@brian-akers-computer.local carsten@tsort.bitbybit.dk +cps@silver_beast.(none) davida@isil.mysql.com dlenev@brandersnatch.localdomain dlenev@build.mysql.com diff --git a/include/my_sys.h b/include/my_sys.h index 0cfad5750c1..2ac86df87e8 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -506,6 +506,10 @@ my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ typedef uint32 ha_checksum; +/* Define the type of function to be passed to process_default_option_files */ +typedef int (*Process_option_func)(void *ctx, const char *group_name, + const char *option); + #include /* Prototypes for mysys and my_func functions */ @@ -740,6 +744,9 @@ extern char *strmake_root(MEM_ROOT *root,const char *str,uint len); extern char *memdup_root(MEM_ROOT *root,const char *str,uint len); extern int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); +extern int process_default_option_files(const char *conf_file, + Process_option_func func, + void *func_ctx); extern void free_defaults(char **argv); extern void print_defaults(const char *conf_file, const char **groups); extern my_bool my_compress(byte *, ulong *, ulong *); diff --git a/mysys/default.c b/mysys/default.c index 792233ed10d..eb5c6446b83 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -66,13 +66,203 @@ 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) + + 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)))) + return 1; + if (insert_dynamic(ctx->args, (gptr) &tmp)) + return 1; + strmov(tmp, option); + } + + return 0; +} + + /* Read options from configurations files @@ -101,7 +291,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 +298,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 +326,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 +406,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 +419,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 +486,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 +497,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 +529,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 +571,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)); From 36b5ed33c88abf9448951843c12c0f32961017e2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Aug 2004 21:47:52 +0300 Subject: [PATCH 02/22] fixed printing of stored procedure functions names (BUG#5149) mysql-test/r/view.result: VIEW based on functions with complex names mysql-test/t/view.test: VIEW based on functions with complex names sql/item_func.cc: fixed printing of stored procedure functions names --- mysql-test/r/view.result | 10 ++++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/item_func.cc | 15 ++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 18da4882894..28162334546 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1166,3 +1166,13 @@ 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`; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index e73133afa67..4f5a6f3ddc4 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1106,3 +1106,13 @@ 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`; diff --git a/sql/item_func.cc b/sql/item_func.cc index c2c93586af8..f5a9d9ef9bc 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3270,9 +3270,22 @@ Item_func_sp::Item_func_sp(sp_name *name, List &list) const char * Item_func_sp::func_name() const { - return m_name->m_name.str; + THD * thd= current_thd; + uint len= ((m_name->m_db.length + + m_name->m_name.length)*2 + //characters*quoting + 2 + // ` and ` + 1 + // . + 1); // end of string + String qname(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) { From fa8a74b3ba0fb8b1fed200fba6bbbd4755e1df13 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Aug 2004 22:52:50 +0300 Subject: [PATCH 03/22] fixed case when real length very close to calculated (BUG#5150) mysql-test/r/view.result: tested problem when function name length close to ALIGN_SIZE mysql-test/t/view.test: tested problem when function name length close to ALIGN_SIZE sql/item_func.cc: fixed case when real length very close to calculated (less then ALIGN) --- mysql-test/r/view.result | 7 +++++++ mysql-test/t/view.test | 9 +++++++++ sql/item_func.cc | 6 ++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 28162334546..193adac7533 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1176,3 +1176,10 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 4f5a6f3ddc4..cc659a59f6d 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1116,3 +1116,12 @@ 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; diff --git a/sql/item_func.cc b/sql/item_func.cc index f5a9d9ef9bc..b5af98b6caf 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3271,12 +3271,14 @@ const char * Item_func_sp::func_name() const { 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 - String qname(alloc_root(&thd->mem_root, len), len, + 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); From 6e314e047d0acd336954df032cb519101889bd0c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 31 Aug 2004 10:06:38 +0300 Subject: [PATCH 04/22] fixed open_and_lock_tables result processing (all open_and_lock_tables revision) fixed printing of COLLATE operation (BUG#5155) mysql-test/r/case.result: fixed printing of COLLATE operation mysql-test/r/func_if.result: fixed printing of COLLATE operation mysql-test/r/func_in.result: fixed printing of COLLATE operation mysql-test/r/func_str.result: fixed printing of COLLATE operation mysql-test/r/func_test.result: fixed printing of COLLATE operation mysql-test/r/view.result: VIEW with collation mysql-test/t/view.test: VIEW with collation sql/item_strfunc.cc: fixed printing of COLLATE operation sql/item_strfunc.h: fixed printing of COLLATE operation sql/sp_head.cc: fixed open_and_lock_tables result processing sql/sql_base.cc: fixed open_and_lock_tables result processing sql/sql_delete.cc: fixed open_and_lock_tables result processing sql/sql_help.cc: fixed open_and_lock_tables result processing sql/sql_load.cc: fixed open_and_lock_tables result processing sql/sql_parse.cc: fixed open_and_lock_tables result processing sql/sql_prepare.cc: fixed open_and_lock_tables result processing sql/sql_show.cc: fixed open_and_lock_tables result processing sql/sql_update.cc: fixed open_and_lock_tables result processing --- mysql-test/r/case.result | 2 +- mysql-test/r/func_if.result | 2 +- mysql-test/r/func_in.result | 2 +- mysql-test/r/func_str.result | 2 +- mysql-test/r/func_test.result | 2 +- mysql-test/r/view.result | 10 ++++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/item_strfunc.cc | 12 ++++++++++++ sql/item_strfunc.h | 2 +- sql/sp_head.cc | 8 ++++---- sql/sql_base.cc | 1 + sql/sql_delete.cc | 4 ++-- sql/sql_help.cc | 5 +---- sql/sql_load.cc | 7 ++++--- sql/sql_parse.cc | 3 +-- sql/sql_prepare.cc | 19 ++++++++----------- sql/sql_show.cc | 26 ++++++++++++++++++-------- sql/sql_update.cc | 4 ++-- 18 files changed, 79 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index dba21877644..75d0c9a7e3b 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -141,7 +141,7 @@ COALESCE('a' COLLATE latin1_bin,'b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate _latin1'latin1_bin'),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')` +Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate latin1_bin),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')` SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index 36bd9a36d1c..f0445199744 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -43,7 +43,7 @@ explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using filesort Warnings: -Note 1003 select if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate _latin1'BINARY')) AS `s` from `test`.`t1` where (`test`.`t1`.`st` like _latin1'%a%') order by if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate _latin1'BINARY')) +Note 1003 select if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate BINARY)) AS `s` from `test`.`t1` where (`test`.`t1`.`st` like _latin1'%a%') order by if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,(`test`.`t1`.`st` collate BINARY)) select nullif(u=0, 'test') from t1; nullif(u=0, 'test') NULL diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 025ea02e454..f264103390d 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -146,7 +146,7 @@ explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (_latin1'a' in (`test`.`t1`.`a`,`test`.`t1`.`b`,(`test`.`t1`.`c` collate _latin1'latin1_bin'))) +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (_latin1'a' in (`test`.`t1`.`a`,`test`.`t1`.`b`,(`test`.`t1`.`c` collate latin1_bin))) drop table t1; select '1.0' in (1,2); '1.0' in (1,2) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index e07ee4f0add..6495b81c195 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -638,7 +638,7 @@ explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'moo id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,(_latin1'HE' collate _latin1'BINARY') AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate _latin1'latin1_bin'),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")` +Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,(_latin1'HE' collate BINARY) AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate latin1_bin),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")` SELECT lpad(12345, 5, "#"); lpad(12345, 5, "#") 12345 diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index a969bf390bc..6f8bc702a80 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -108,7 +108,7 @@ explain extended select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select (_koi8r'a' = (_koi8r'A' collate _latin1'koi8r_general_ci')) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci` +Note 1003 select (_koi8r'a' = (_koi8r'A' collate koi8r_general_ci)) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci` select _koi8r'a' = _koi8r'A' COLLATE koi8r_bin; _koi8r'a' = _koi8r'A' COLLATE koi8r_bin 0 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 193adac7533..14df4f1846d 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1183,3 +1183,13 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index cc659a59f6d..d4209cc3cb8 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1125,3 +1125,13 @@ 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; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d3493e1fad1..5f2c37dd8a7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2274,6 +2274,18 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const return 1; } + +void Item_func_set_collation::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(" collate ", 9); + DBUG_ASSERT(args[1]->basic_const_item() && + args[1]->type() == Item::STRING_ITEM); + args[1]->str_value.print(str); + str->append(')'); +} + String *Item_func_charset::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 08123370bc6..df8861b2ee0 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -635,7 +635,7 @@ public: void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } - void print(String *str) { print_op(str); } + void print(String *str); }; class Item_func_charset :public Item_str_func diff --git a/sql/sp_head.cc b/sql/sp_head.cc index fd95767b7cd..c7cd49d26f5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1192,7 +1192,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) @@ -1293,7 +1293,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) @@ -1350,7 +1350,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) @@ -1406,7 +1406,7 @@ sp_instr_freturn::execute(THD *thd, uint *nextp) if (tables && ((res= check_table_access(thd, SELECT_ACL, tables, 0)) || (res= open_and_lock_tables(thd, tables)))) - DBUG_RETURN(-1); + DBUG_RETURN(res); it= sp_eval_func_item(thd, m_value, m_type); if (! it) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d1fd5fd02cc..5ae385ca313 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1751,6 +1751,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() diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 910b673dc32..00ce016a550 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -39,8 +39,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, ha_rows deleted; DBUG_ENTER("mysql_delete"); - if ((open_and_lock_tables(thd, table_list))) - DBUG_RETURN(-1); + if ((error= open_and_lock_tables(thd, table_list))) + DBUG_RETURN(error); table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 85d5271d4c3..8fc0671c808 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -640,11 +640,8 @@ int mysqld_help(THD *thd, const char *mask) uint mlen= strlen(mask); MEM_ROOT *mem_root= &thd->mem_root; - if (open_and_lock_tables(thd, tables)) - { - res= -1; + if (res= open_and_lock_tables(thd, tables)) goto end; - } /* Init tables and fields to be usable from items diff --git a/sql/sql_load.cc b/sql/sql_load.cc index fa3adf236fe..b629493a692 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -99,8 +99,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, loaded is located */ char *tdb= thd->db ? thd->db : db; // Result is never null - bool transactional_table, log_delayed; ulong skip_lines= ex->skip_lines; + int res; + bool transactional_table, log_delayed; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -114,8 +115,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_RETURN(-1); } table_list->lock_type= lock_type; - if (open_and_lock_tables(thd, table_list)) - DBUG_RETURN(-1); + if ((res= open_and_lock_tables(thd, table_list))) + DBUG_RETURN(res); /* TODO: add key check when we will support VIEWs in LOAD */ if (!table_list->updatable) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58385c67493..3abb2b957bc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2136,7 +2136,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); @@ -2400,7 +2400,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, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 452804240b6..a65a8c79daa 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -897,10 +897,10 @@ static int mysql_test_insert(Prepared_statement *stmt, tables & preparation procedure */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, table_list)) + if ((res= open_and_lock_tables(thd, table_list))) { thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(-1); + DBUG_RETURN(res); } if ((values= its++)) @@ -969,9 +969,7 @@ static int mysql_test_update(Prepared_statement *stmt, */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, table_list)) - res= -1; - else + if (!(res= open_and_lock_tables(thd, table_list))) { if (!(res= mysql_prepare_update(thd, table_list, &select->where, @@ -1030,9 +1028,7 @@ static int mysql_test_delete(Prepared_statement *stmt, */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, table_list)) - res= -1; - else + if (!(res= open_and_lock_tables(thd, table_list))) { res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where); lex->unit.cleanup(); @@ -1065,6 +1061,7 @@ static int mysql_test_select(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX_UNIT *unit= &lex->unit; + int res; DBUG_ENTER("mysql_test_select"); @@ -1084,11 +1081,11 @@ static int mysql_test_select(Prepared_statement *stmt, tables & preparation procedure */ thd->allocate_temporary_memory_pool_for_ps_preparing(); - if (open_and_lock_tables(thd, tables)) + if ((res= open_and_lock_tables(thd, tables))) { - send_error(thd); goto err; } + res= 1; thd->used_tables= 0; // Updated by setup_fields @@ -1126,7 +1123,7 @@ err_prep: unit->cleanup(); err: thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(1); + DBUG_RETURN(res); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fa8b81f8ea2..7298d1d5249 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -497,6 +497,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) TABLE *table; Protocol *protocol= thd->protocol; TIME time; + int res; DBUG_ENTER("mysqld_extend_show_tables"); (void) sprintf(path,"%s/%s",mysql_data_home,db); @@ -554,13 +555,18 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) table_list.select_lex= &thd->lex->select_lex; if (lower_case_table_names) my_casedn_str(files_charset_info, file_name); - if (open_and_lock_tables(thd, &table_list)) + if ((res= open_and_lock_tables(thd, &table_list))) { for (uint i=2 ; i < field_list.elements ; i++) protocol->store_null(); - // Send error to Comment field - protocol->store(thd->net.last_error, system_charset_info); - thd->clear_error(); + // Send error to Comment field if possible + if (res < 0) + { + protocol->store(thd->net.last_error, system_charset_info); + thd->clear_error(); + } + else + DBUG_RETURN(1) } else if (table_list.view) { @@ -695,14 +701,16 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, char tmp[MAX_FIELD_WIDTH]; Item *item; Protocol *protocol= thd->protocol; + int res; DBUG_ENTER("mysqld_show_fields"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); table_list->lock_type= TL_UNLOCK; - if (open_and_lock_tables(thd, table_list)) + if ((res= open_and_lock_tables(thd, table_list))) { - send_error(thd); + if (res < 0) + send_error(thd); DBUG_RETURN(1); } table= table_list->table; @@ -836,14 +844,16 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); + int res; DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); /* Only one table for now, but VIEW can involve several tables */ - if (open_and_lock_tables(thd, table_list)) + if ((res= open_and_lock_tables(thd, table_list))) { - send_error(thd); + if (res < 0) + send_error(thd); DBUG_RETURN(1); } /* TODO: add environment variables show when it become possible */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 61fb4b97200..a27244e1055 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -113,8 +113,8 @@ int mysql_update(THD *thd, LINT_INIT(used_index); LINT_INIT(timestamp_query_id); - if ((open_and_lock_tables(thd, table_list))) - DBUG_RETURN(-1); + if ((error= open_and_lock_tables(thd, table_list))) + DBUG_RETURN(error); thd->proc_info="init"; table= table_list->table; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); From d3423ca699ef20de336cbed8574df63f1970d278 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 31 Aug 2004 11:58:45 +0300 Subject: [PATCH 05/22] ORDER clause printing fixed (BUG#5156) mysql-test/r/subselect.result: ORDER clause printing fixed mysql-test/r/view.result: order by refers on integer field mysql-test/t/view.test: order by refers on integer field sql/sql_lex.cc: ORDER clause printing fixed sql/sql_parse.cc: fields for correct ORDER printing added sql/sql_select.cc: fields for correct ORDER printing added sql/table.h: fields for correct ORDER printing added --- mysql-test/r/subselect.result | 4 ++-- mysql-test/r/view.result | 9 +++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/sql_lex.cc | 9 ++++++++- sql/sql_parse.cc | 1 + sql/sql_select.cc | 4 +++- sql/table.h | 3 +++ 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 80dd5c4077a..cdde932f851 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -186,7 +186,7 @@ id select_type table type possible_keys key key_len ref rows Extra 4 SUBQUERY t2 ALL NULL NULL NULL NULL 2 NULL UNION RESULT ALL NULL NULL NULL NULL NULL Warnings: -Note 1003 (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = (select `test`.`t3`.`a` AS `a` from `test`.`t3` order by `test`.`t3`.`a` desc limit 1))) union (select `test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t4` where (`test`.`t4`.`b` = (select (max(`test`.`t2`.`a`) * 4) AS `max(t2.a)*4` from `test`.`t2`)) order by `test`.`t4`.`a`) +Note 1003 (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = (select `test`.`t3`.`a` AS `a` from `test`.`t3` order by 1 desc limit 1))) union (select `test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t4` where (`test`.`t4`.`b` = (select (max(`test`.`t2`.`a`) * 4) AS `max(t2.a)*4` from `test`.`t2`)) order by `test`.`t4`.`a`) select (select a from t3 where a 1)) `tt` +Note 1003 select (select `test`.`t3`.`a` AS `a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt` select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 14df4f1846d..8ed85e611a6 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1193,3 +1193,12 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index d4209cc3cb8..3bb995f8022 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1135,3 +1135,13 @@ 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; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 31c175fee88..dc69a41b090 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3abb2b957bc..54156459f86 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4935,6 +4935,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); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1768f332fd3..3ecda7284c8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10066,8 +10066,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; diff --git a/sql/table.h b/sql/table.h index dd41ab79b7b..68c7febb5b6 100644 --- a/sql/table.h +++ b/sql/table.h @@ -29,9 +29,12 @@ typedef struct st_order { Item **item; /* Point at item in select fields */ Item *item_ptr; /* Storage for initial item */ Item **item_copy; /* For SPs; the original item ptr */ + int counter; /* position in SELECT list, correct + only if counter_used is true*/ bool asc; /* true if ascending */ bool free_me; /* true if item isn't shared */ bool in_field_list; /* true if in select field list */ + bool counter_used; /* parapeter was counter of columns */ Field *field; /* If tmp-table group */ char *buff; /* If tmp-table group */ table_map used,depend_map; From c33897765f0bd4af57d23afad665788c12b774e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Sep 2004 19:00:41 +0300 Subject: [PATCH 06/22] adding mysql.proc to table list if view contains stored procedures (BUG#5151) mysql-test/r/view.result: fixed test VIEW over droped function mysql-test/t/view.test: VIEW over droped function sql/item_func.cc: after review fix sql/sp.cc: hint to find mysql.proc sql/sql_lex.h: hint to find mysql.proc sql/sql_parse.cc: hint to find mysql.proc sql/sql_view.cc: adding mysql.proc to table list if view contains stored procedures --- mysql-test/r/view.result | 19 +++++++++++++++++-- mysql-test/t/view.test | 18 +++++++++++++++++- sql/item_func.cc | 3 ++- sql/sp.cc | 14 ++++++++++---- sql/sql_lex.h | 1 + sql/sql_parse.cc | 2 +- sql/sql_view.cc | 35 +++++++++++++++++++++++++++++++---- 7 files changed, 79 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 8ed85e611a6..e0124597d36 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -940,7 +940,7 @@ grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost; create view v4 as select b+1 from mysqltest.t2; REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; drop database mysqltest; -drop view v1,v2; +drop view v1,v2,v4; set sql_mode='ansi'; create table t1 ("a*b" int); create view v1 as select "a*b" from t1; @@ -1040,7 +1040,6 @@ CREATE VIEW v02 AS SELECT * FROM DUAL; ERROR HY000: No tables used SHOW TABLES; Tables_in_test table_type -v4 VIEW CREATE VIEW v1 AS SELECT EXISTS (SELECT 1 UNION SELECT 2); select * from v1; EXISTS (SELECT 1 UNION SELECT 2) @@ -1202,3 +1201,19 @@ select * from v1; 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 3bb995f8022..690c4e0d64c 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -849,7 +849,7 @@ create view v4 as select b+1 from mysqltest.t2; connection root; REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost; drop database mysqltest; -drop view v1,v2; +drop view v1,v2,v4; # # VIEW fields quoting @@ -1145,3 +1145,19 @@ 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; diff --git a/sql/item_func.cc b/sql/item_func.cc index b5af98b6caf..f9ab1886a23 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3270,7 +3270,7 @@ Item_func_sp::Item_func_sp(sp_name *name, List &list) const char * Item_func_sp::func_name() const { - THD * thd= current_thd; + 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 @@ -3280,6 +3280,7 @@ Item_func_sp::func_name() const 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('.'); diff --git a/sql/sp.cc b/sql/sp.cc index b881eeb78d9..a69f18e10be 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -93,10 +93,15 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, key[128]= type; keylen= sizeof(key); - for (table= thd->open_tables ; table ; table= table->next) - if (strcmp(table->table_cache_key, "mysql") == 0 && - strcmp(table->real_name, "proc") == 0) - break; + if (thd->lex->proc_table) + table= thd->lex->proc_table->table; + else + { + for (table= thd->open_tables ; table ; table= table->next) + if (strcmp(table->table_cache_key, "mysql") == 0 && + strcmp(table->real_name, "proc") == 0) + break; + } if (table) *opened= FALSE; else @@ -954,6 +959,7 @@ sp_cache_functions(THD *thd, LEX *lex) LEX *newlex= new st_lex; thd->lex= newlex; + newlex->proc_table= oldlex->proc_table; // hint if mysql.oper is opened name.m_name.str= strchr(name.m_qname.str, '.'); name.m_db.length= name.m_name.str - name.m_qname.str; name.m_db.str= strmake_root(&thd->mem_root, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 84b5cf3454b..1c479444485 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -641,6 +641,7 @@ typedef struct st_lex TABLE_LIST *query_tables; /* global list of all tables in this query */ /* last element next_global of previous list */ TABLE_LIST **query_tables_last; + TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */ List col_list; List ref_list; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 54156459f86..d0ac3cfbc6a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4246,7 +4246,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; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 3f0e0db1724..17c5951d5cd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -520,6 +520,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, my_bool mysql_make_view(File_parser *parser, TABLE_LIST *table) { + bool include_proc_table= 0; DBUG_ENTER("mysql_make_view"); if (table->view) @@ -612,10 +613,25 @@ 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.array.buffer) - hash_free(&lex->spfuns); + if (lex->spfuns.records) + { + /* move SP to main LEX */ + sp_merge_funs(old_lex, lex); + if (lex->spfuns.array.buffer) + hash_free(&lex->spfuns); + 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; + } + } old_next= table->next_global; if ((table->next_global= lex->query_tables)) @@ -742,6 +758,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); From 321918b3009c4b0443bc3cf4e5eae8a072037b90 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Sep 2004 20:30:48 +0300 Subject: [PATCH 07/22] fixed printing of real constants (BUG#5160) mysql-test/r/view.result: VIEW with floating point (long bumber) as column mysql-test/t/view.test: VIEW with floating point (long bumber) as column sql/item.cc: fixed printing of real constants sql/item.h: fixed printing of real constants --- mysql-test/r/view.result | 5 +++++ mysql-test/t/view.test | 7 +++++++ sql/item.cc | 15 +++++++++++++++ sql/item.h | 8 +++++--- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index e0124597d36..9164eb1b8c4 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1217,3 +1217,8 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 690c4e0d64c..89841312cd6 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1161,3 +1161,10 @@ show table status; 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; diff --git a/sql/item.cc b/sql/item.cc index 138ab384caf..5b1f0aa39ab 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1756,6 +1756,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 diff --git a/sql/item.h b/sql/item.h index 4030c0fc097..725ac4e733d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -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); }; From a3695785e47f8445813774c591d3568686c0e0fd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Sep 2004 22:48:59 +0300 Subject: [PATCH 08/22] system charset (with wich VIEW printed) saved in .frm and restored before parsing view (BUG#5163) mysql-test/r/view.result: VIEWs with national characters mysql-test/t/view.test: VIEWs with national characters sql/sql_view.cc: system charset (with wich VIEW printed) saved in .frm and restored before parsing view sql/table.h: system charset (with wich VIEW printed) saved in .frm --- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/sql_view.cc | 36 +++++++++++++++++++++++++++++------- sql/table.h | 1 + 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 9164eb1b8c4..305c72cb063 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1222,3 +1222,11 @@ 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ü; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 89841312cd6..28fb40d4045 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1168,3 +1168,13 @@ drop table t1; 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ü; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 17c5951d5cd..c27ca9e1c09 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -318,8 +318,10 @@ 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 last_parameter= 8; static char *view_field_names[]= { @@ -327,6 +329,7 @@ static char *view_field_names[]= (char*)"md5", (char*)"updatable", (char*)"algorithm", + (char*)"syscharset", (char*)"revision", (char*)"timestamp", (char*)"create-version", @@ -343,13 +346,15 @@ static File_option view_parameters[]= FILE_OPTIONS_ULONGLONG}, {{view_field_names[3], 9}, offsetof(TABLE_LIST, algorithm), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[4], 8}, offsetof(TABLE_LIST, revision), + {{view_field_names[4], 10}, offsetof(TABLE_LIST, syscharset), + FILE_OPTIONS_STRING}, + {{view_field_names[5], 8}, offsetof(TABLE_LIST, revision), FILE_OPTIONS_REV}, - {{view_field_names[5], 9}, offsetof(TABLE_LIST, timestamp), + {{view_field_names[6], 9}, offsetof(TABLE_LIST, timestamp), FILE_OPTIONS_TIMESTAMP}, - {{view_field_names[6], 14}, offsetof(TABLE_LIST, file_version), + {{view_field_names[7], 14}, offsetof(TABLE_LIST, file_version), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[7], 6}, offsetof(TABLE_LIST, source), + {{view_field_names[8], 6}, offsetof(TABLE_LIST, source), FILE_OPTIONS_ESTRING}, {{NULL, 0}, 0, FILE_OPTIONS_STRING} @@ -468,6 +473,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, view->query.length= str.length()-1; // we do not need last \0 view->source.str= thd->query; view->source.length= thd->query_length; + view->syscharset.str= (char *)system_charset_info->csname; + view->syscharset.length= strlen(view->syscharset.str); view->file_version= 1; view->calc_md5(md5); view->md5.str= md5; @@ -552,7 +559,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) 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, + last_parameter)) goto err; /* @@ -604,7 +612,21 @@ 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; + if (!table->syscharset.length) + thd->variables.character_set_client= system_charset_info; + else + { + if (!(thd->variables.character_set_client= + get_charset_by_csname(table->syscharset.str, + MY_CS_PRIMARY, MYF(MY_WME)))) + { + thd->variables.character_set_client= save_cs; + goto err; + } + } res= yyparse((void *)thd); + thd->variables.character_set_client= save_cs; thd->options= options; } if (!res && !thd->is_fatal_error) diff --git a/sql/table.h b/sql/table.h index 68c7febb5b6..93a7b8f7cf5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -224,6 +224,7 @@ typedef struct st_table_list LEX_STRING view_db; /* save view database */ LEX_STRING view_name; /* save view name */ LEX_STRING timestamp; /* GMT time stamp of last operation */ + LEX_STRING syscharset; /* charset of VIEW query text*/ ulonglong file_version; /* version of file's field set */ ulonglong updatable_view; /* VIEW can be updated */ ulonglong revision; /* revision control number */ From 292f8adf50d85f5bd3a7a52880e7d5476019a2e5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Sep 2004 23:27:40 +0300 Subject: [PATCH 09/22] fixed staistic of subquery if outer field resolved in merged view (BUG#5247) mysql-test/r/view.result: problem with used_tables() of outer reference resolved in VIEW mysql-test/t/view.test: problem with used_tables() of outer reference resolved in VIEW sql/item.cc: fixed staistic of subquery if outer field resolved in merged view --- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/item.cc | 40 ++++++++++++++++++++++++++++++---------- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 305c72cb063..b6d7b881498 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1230,3 +1230,11 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 28fb40d4045..506fdf8f5d8 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1178,3 +1178,13 @@ insert into v 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; diff --git a/sql/item.cc b/sql/item.cc index 5b1f0aa39ab..e1c57a0540d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1302,11 +1302,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 && @@ -2029,11 +2039,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; } From 5009663b0706284f26debdf85ee0f262773e0853 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Sep 2004 00:11:40 +0300 Subject: [PATCH 10/22] fixed printing of characters casting operartion (BUG#5264) mysql-test/r/view.result: view with cast operation mysql-test/t/view.test: view with cast operation sql/item_timefunc.cc: fixed printing of characters casting operartion --- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 8 ++++++++ sql/item_timefunc.cc | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index b6d7b881498..6129850b9dc 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1238,3 +1238,11 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 506fdf8f5d8..3b1d4a0b362 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1188,3 +1188,11 @@ 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; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 5aa14010058..0e7594a1d98 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2011,7 +2011,7 @@ void Item_char_typecast::print(String *str) if (cast_cs) { str->append(" charset ", 9); - str->append(cast_cs->name); + str->append(cast_cs->csname); } str->append(')'); } From 1bbf71849f8f7fe2c5516c07f44207a1344559d6 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Sep 2004 07:40:48 +0300 Subject: [PATCH 11/22] fixed bug handling in views (BUG#5276) mysql-test/r/view.result: bug handlimg from VIEWs mysql-test/t/view.test: bug handlimg from VIEWs sql/sql_base.cc: fixed bug handling in views --- mysql-test/r/view.result | 7 +++++++ mysql-test/t/view.test | 11 +++++++++++ sql/sql_base.cc | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6129850b9dc..449144e3770 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1246,3 +1246,10 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 3b1d4a0b362..a44624d4df9 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1196,3 +1196,14 @@ 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; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5ae385ca313..c76a4849776 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1761,9 +1761,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)); } From 5feaa7b677a401b5e08c0cc605bcc70b2a1be546 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Sep 2004 12:09:26 +0300 Subject: [PATCH 12/22] checked INTO clause during view creation (BUG#5332) include/mysqld_error.h: bug name and number of bugs fixed mysql-test/r/view.result: VIEW over SELECT with prohibited clauses mysql-test/t/view.test: VIEW over SELECT with prohibited clauses sql/share/czech/errmsg.txt: error message made more general sql/share/danish/errmsg.txt: error message made more general sql/share/dutch/errmsg.txt: error message made more general sql/share/english/errmsg.txt: error message made more general sql/share/estonian/errmsg.txt: error message made more general sql/share/french/errmsg.txt: error message made more general sql/share/german/errmsg.txt: error message made more general sql/share/greek/errmsg.txt: error message made more general sql/share/hungarian/errmsg.txt: error message made more general sql/share/italian/errmsg.txt: error message made more general sql/share/japanese/errmsg.txt: error message made more general sql/share/korean/errmsg.txt: error message made more general sql/share/norwegian-ny/errmsg.txt: error message made more general sql/share/norwegian/errmsg.txt: error message made more general sql/share/polish/errmsg.txt: error message made more general sql/share/portuguese/errmsg.txt: error message made more general sql/share/romanian/errmsg.txt: error message made more general sql/share/russian/errmsg.txt: error message made more general sql/share/serbian/errmsg.txt: error message made more general sql/share/slovak/errmsg.txt: error message made more general sql/share/spanish/errmsg.txt: error message made more general sql/share/swedish/errmsg.txt: error message made more general sql/share/ukrainian/errmsg.txt: error message made more general sql/sql_view.cc: checked INTO clause during view creation --- include/mysqld_error.h | 4 ++-- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 12 ++++++++++++ sql/share/czech/errmsg.txt | 2 +- sql/share/danish/errmsg.txt | 4 ++-- sql/share/dutch/errmsg.txt | 2 +- sql/share/english/errmsg.txt | 2 +- sql/share/estonian/errmsg.txt | 2 +- sql/share/french/errmsg.txt | 2 +- sql/share/german/errmsg.txt | 2 +- sql/share/greek/errmsg.txt | 2 +- sql/share/hungarian/errmsg.txt | 2 +- sql/share/italian/errmsg.txt | 2 +- sql/share/japanese/errmsg.txt | 2 +- sql/share/korean/errmsg.txt | 2 +- sql/share/norwegian-ny/errmsg.txt | 2 +- sql/share/norwegian/errmsg.txt | 2 +- sql/share/polish/errmsg.txt | 2 +- sql/share/portuguese/errmsg.txt | 2 +- sql/share/romanian/errmsg.txt | 2 +- sql/share/russian/errmsg.txt | 2 +- sql/share/serbian/errmsg.txt | 2 +- sql/share/slovak/errmsg.txt | 2 +- sql/share/spanish/errmsg.txt | 2 +- sql/share/swedish/errmsg.txt | 2 +- sql/share/ukrainian/errmsg.txt | 2 +- sql/sql_view.cc | 17 +++++++++++++---- 27 files changed, 59 insertions(+), 30 deletions(-) diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 3ee12fa9580..432919db04b 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -365,7 +365,7 @@ #define ER_WRONG_OBJECT 1346 #define ER_NONUPDATEABLE_COLUMN 1347 #define ER_VIEW_SELECT_DERIVED 1348 -#define ER_VIEW_SELECT_PROCEDURE 1349 +#define ER_VIEW_SELECT_CLAUSE 1349 #define ER_VIEW_SELECT_VARIABLE 1350 #define ER_VIEW_SELECT_TMPTABLE 1351 #define ER_VIEW_WRONG_LIST 1352 @@ -374,4 +374,4 @@ #define ER_VIEW_INVALID 1355 #define ER_SP_NO_DROP_SP 1356 #define ER_SP_GOTO_IN_HNDLR 1357 -#define ER_ERROR_MESSAGES 357 +#define ER_ERROR_MESSAGES 358 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 449144e3770..a00938add07 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1253,3 +1253,11 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index a44624d4df9..f03e48167fd 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1207,3 +1207,15 @@ 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; diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 9d1c429d5b6..35310f5210f 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -361,7 +361,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index b2d2fdf4d77..d6a0a9d81e8 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -1,4 +1,4 @@ -/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB +:/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB This file is public domain and comes with NO WARRANTY of any kind */ /* Knud Riishøjgård knudriis@post.tele.dk 99 && @@ -355,7 +355,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 85c0443869f..8fd5277d4ec 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -363,7 +363,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 641f267d67e..a60881b5df6 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index e64c0c17e74..2e8a9270cd3 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -357,7 +357,7 @@ character-set=latin7 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index f3443457346..b8ec7866a68 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 498a230faed..c28792cc8c6 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -364,7 +364,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 2827517ba9a..8ceb24bd376 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -352,7 +352,7 @@ character-set=greek "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index fab0b156322..f47684f9225 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 24634514a23..eb241ef08a0 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 68f2857aeca..166d6e8e1c1 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -354,7 +354,7 @@ character-set=ujis "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 70267c82364..66486fd8a0f 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -352,7 +352,7 @@ character-set=euckr "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 1d84a3a5e5a..739d40178df 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index be881d54473..227e16e1590 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 8a576b5bf82..62e10e778f2 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -356,7 +356,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 6794db726cc..08c03fcaf2a 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -353,7 +353,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 9eaa4860b64..0f6df4f919b 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -356,7 +356,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index eec85d611fc..71c983ff55e 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -354,7 +354,7 @@ character-set=koi8r "'%-.64s.%-.64s' - ÎÅ %s" "óÔÏÌÂÅà '%-.64s' ÎÅ ÏÂÎÏ×ÌÑÅÍÙÊ" "View SELECT ÓÏÄÅÒÖÉÔ ÐÏÄÚÁÐÒÏÓ × ËÏÎÓÔÒÕËÃÉÉ FROM" -"View SELECT ÓÏÄÅÒÖÉÔ ËÏÎÓÔÒÕËÃÉÀ PROCEDURE" +"View SELECT ÓÏÄÅÒÖÉÔ ËÏÎÓÔÒÕËÃÉÀ '%s'" "View SELECT ÓÏÄÅÒÖÉÔ ÐÅÒÅÍÅÎÎÕÀ ÉÌÉ ÐÁÒÁÍÅÔÒ" "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'" "View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 4039268f446..bff4fad6108 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -358,7 +358,7 @@ character-set=cp1250 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 9be5ce01d6a..363ba86afc7 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -360,7 +360,7 @@ character-set=latin2 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index dc15f8b8d5e..7ab9b416c2e 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -354,7 +354,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index ee5436c3b80..b7add017e44 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -352,7 +352,7 @@ character-set=latin1 "'%-.64s.%-.64s' is not %s" "Column '%-.64s' is not updatable" "View's SELECT contains a subquery in the FROM clause" -"View's SELECT contains a PROCEDURE clause" +"View's SELECT contains a '%s' clause" "View's SELECT contains a variable or parameter" "View's SELECT contains a temporary table '%-.64s'" "View's SELECT and view's field list have different column counts" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index cb1d99e2fec..364a2a03c16 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -357,7 +357,7 @@ character-set=koi8u "'%-.64s.%-.64s' ÎÅ ¤ %s" "óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÚÍÉÎÅÎÉÊ" "View SELECT ÍÁ¤ ЦÄÚÁÐÉÔ Õ ËÏÎÓÔÒÕËæ§ FROM" -"View SELECT ÍÁ¤ ËÏÎÓÔÒÕËæÀ PROCEDURE" +"View SELECT ÍÁ¤ ËÏÎÓÔÒÕËæÀ '%s'" "View SELECT ÍÁ¤ ÚÍÉÎÎÕ ÁÂÏ ÐÁÒÁÍÅÔÅÒ" "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'" "View SELECT ¦ ÐÅÒÅÌ¦Ë ÓÔÏ×ÂÃ¦× view ÍÁÀÔØ Ò¦ÚÎÕ Ë¦ÌØË¦ÓÔØ ÓËÏ×Âæ×" diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c27ca9e1c09..ebddc685594 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -59,12 +59,21 @@ int mysql_create_view(THD *thd, int res= 0; DBUG_ENTER("mysql_create_view"); - if (lex->derived_tables || lex->proc_list.first || + if (lex->proc_list.first || + lex->result) + { + my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), (lex->result ? + "INTO" : + "PROCEDURE")); + res= -1; + goto err; + } + if (lex->derived_tables || lex->variables_used || lex->param_list.elements) { - my_error((lex->derived_tables ? ER_VIEW_SELECT_DERIVED : - (lex->proc_list.first ? ER_VIEW_SELECT_PROCEDURE : - ER_VIEW_SELECT_VARIABLE)), MYF(0)); + my_error((lex->derived_tables ? + ER_VIEW_SELECT_DERIVED : + ER_VIEW_SELECT_VARIABLE), MYF(0)); res= -1; goto err; } From 339859d261ffaf3d588da247284680a3d4ec3104 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Sep 2004 17:24:25 +0200 Subject: [PATCH 13/22] Fixed BUG#5287: Stored procedure crash if leave outside loop. Bug in diff_handlers and diff_cursors made it attempt to pop the wrong number at jumps sometimes. mysql-test/r/sp.result: New testcase for BUG#5287. mysql-test/t/sp.test: New testcase for BUG#5287. sql/sp_pcontext.cc: Fixed diff_handlers and diff_cursors methods, they miscounted. sql/sp_pcontext.h: Made m_handlers available for diff_handlers. --- mysql-test/r/sp.result | 12 ++++++++++++ mysql-test/t/sp.test | 17 +++++++++++++++++ sql/sp_pcontext.cc | 9 +++------ sql/sp_pcontext.h | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 9abb60634d9..8b20ae68dce 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1764,6 +1764,18 @@ 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| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| create procedure ifac(n int unsigned) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 0c3bda1311c..c420865b2b3 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1924,6 +1924,23 @@ 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| + # # Some "real" examples diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index c83259c3926..3b60f0936f9 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -28,7 +28,7 @@ sp_pcontext::sp_pcontext(sp_pcontext *prev) : Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0), - m_parent(prev), m_handlers(0) + m_handlers(0), m_parent(prev) { VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); @@ -94,7 +94,7 @@ sp_pcontext::diff_handlers(sp_pcontext *ctx) while (pctx && pctx != ctx) { - n+= pctx->max_handlers(); + n+= pctx->m_handlers; pctx= pctx->parent_context(); } if (pctx) @@ -109,12 +109,9 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx) sp_pcontext *pctx= this; while (pctx && pctx != ctx) - { - n+= pctx->max_cursors(); pctx= pctx->parent_context(); - } if (pctx) - return n; + return ctx->current_cursors() - pctx->current_cursors(); return 0; // Didn't find ctx } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 6db62614aa5..36e4ed06aa7 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -275,6 +275,7 @@ protected: uint m_psubsize; uint m_csubsize; uint m_hsubsize; + uint m_handlers; // No. of handlers in this context private: @@ -282,7 +283,6 @@ private: uint m_poffset; // Variable offset for this context uint m_coffset; // Cursor offset for this context - uint m_handlers; // No. of handlers in this context DYNAMIC_ARRAY m_pvar; // Parameters/variables DYNAMIC_ARRAY m_cond; // Conditions From 2c3f49a64d773395cc0e41fb35c5b6e3b5a56871 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Sep 2004 19:14:34 +0200 Subject: [PATCH 14/22] Fixed BUG#5307: Stored procedure allows statement after BEGIN ... END. mysql-test/r/sp.result: New test case for BUG#5307 mysql-test/t/sp.test: New test case for BUG#5307 sql/sp_head.cc: Use the correct end-of-query pointer when extracting the body in the case of a create procedure compound with another statement. --- mysql-test/r/sp.result | 8 ++++++++ mysql-test/t/sp.test | 12 ++++++++++++ sql/sp_head.cc | 13 +++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 8b20ae68dce..afd8c3430b3 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1776,6 +1776,14 @@ end loop; end| call bug5287(1)| drop procedure bug5287| +create procedure bug5307() +begin +end; set @x = 3| +call bug5307()| +select @x| +@x +3 +drop procedure bug5307| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| create procedure ifac(n int unsigned) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index c420865b2b3..92d6110cf7a 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1942,6 +1942,18 @@ call bug5287(1)| drop procedure bug5287| +# +# BUG#5307: Stored procedure allows statement after BEGIN ... END +# +create procedure bug5307() +begin +end; set @x = 3| + +call bug5307()| +select @x| +drop procedure bug5307| + + # # Some "real" examples # diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b2d3b8202c8..16d13154263 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -288,6 +288,7 @@ void sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) { DBUG_ENTER("sp_head::init_strings"); + uint n; /* Counter for nul trimming */ /* During parsing, we must use thd->mem_root */ MEM_ROOT *root= &thd->mem_root; @@ -351,9 +352,17 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) (char *)m_returns_begin, m_retstr.length); } } - m_body.length= lex->end_of_query - m_body_begin; + m_body.length= lex->ptr - m_body_begin; + /* Trim nuls at the end */ + n= 0; + while (m_body.length && m_body_begin[m_body.length-1] == '\0') + { + m_body.length-= 1; + n+= 1; + } m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length); - m_defstr.length= lex->end_of_query - lex->buf; + m_defstr.length= lex->ptr - lex->buf; + m_defstr.length-= n; m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length); DBUG_VOID_RETURN; } From 1948909aeeb1e0ecebfc55802756667f2aeb9b81 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Sep 2004 21:38:01 +0300 Subject: [PATCH 15/22] ufter review fix sql/sql_view.cc: name of variable changed to make merge easy removed charset field sql/table.h: removed charset field layout fixed --- sql/sql_view.cc | 30 +++++++----------------------- sql/table.h | 3 +-- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index ebddc685594..0d92e87c299 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -330,7 +330,7 @@ err: /* 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 last_parameter= 8; +static const int required_view_parameters= 7; static char *view_field_names[]= { @@ -338,7 +338,6 @@ static char *view_field_names[]= (char*)"md5", (char*)"updatable", (char*)"algorithm", - (char*)"syscharset", (char*)"revision", (char*)"timestamp", (char*)"create-version", @@ -355,15 +354,13 @@ static File_option view_parameters[]= FILE_OPTIONS_ULONGLONG}, {{view_field_names[3], 9}, offsetof(TABLE_LIST, algorithm), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[4], 10}, offsetof(TABLE_LIST, syscharset), - FILE_OPTIONS_STRING}, - {{view_field_names[5], 8}, offsetof(TABLE_LIST, revision), + {{view_field_names[4], 8}, offsetof(TABLE_LIST, revision), FILE_OPTIONS_REV}, - {{view_field_names[6], 9}, offsetof(TABLE_LIST, timestamp), + {{view_field_names[5], 9}, offsetof(TABLE_LIST, timestamp), FILE_OPTIONS_TIMESTAMP}, - {{view_field_names[7], 14}, offsetof(TABLE_LIST, file_version), + {{view_field_names[6], 14}, offsetof(TABLE_LIST, file_version), FILE_OPTIONS_ULONGLONG}, - {{view_field_names[8], 6}, offsetof(TABLE_LIST, source), + {{view_field_names[7], 6}, offsetof(TABLE_LIST, source), FILE_OPTIONS_ESTRING}, {{NULL, 0}, 0, FILE_OPTIONS_STRING} @@ -482,8 +479,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, view->query.length= str.length()-1; // we do not need last \0 view->source.str= thd->query; view->source.length= thd->query_length; - view->syscharset.str= (char *)system_charset_info->csname; - view->syscharset.length= strlen(view->syscharset.str); view->file_version= 1; view->calc_md5(md5); view->md5.str= md5; @@ -569,7 +564,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) be used here */ if (parser->parse((gptr)table, &thd->mem_root, view_parameters, - last_parameter)) + required_view_parameters)) goto err; /* @@ -622,18 +617,7 @@ 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; - if (!table->syscharset.length) - thd->variables.character_set_client= system_charset_info; - else - { - if (!(thd->variables.character_set_client= - get_charset_by_csname(table->syscharset.str, - MY_CS_PRIMARY, MYF(MY_WME)))) - { - thd->variables.character_set_client= save_cs; - goto err; - } - } + thd->variables.character_set_client= system_charset_info; res= yyparse((void *)thd); thd->variables.character_set_client= save_cs; thd->options= options; diff --git a/sql/table.h b/sql/table.h index 93a7b8f7cf5..e8905ba092f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -224,9 +224,8 @@ typedef struct st_table_list LEX_STRING view_db; /* save view database */ LEX_STRING view_name; /* save view name */ LEX_STRING timestamp; /* GMT time stamp of last operation */ - LEX_STRING syscharset; /* charset of VIEW query text*/ 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 */ From d0211cf5beae33c7f33d7aab6acebe13892af47c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Sep 2004 21:43:04 +0300 Subject: [PATCH 16/22] Cleanup of new code pushed into 5.0 since last pull Merged the different find_xxxx_table_in_list functions to one + some inline functions mysql-test/r/view.result: Fix result (remove not used view from show tables) sql/item_subselect.cc: Remove not used functions sql/item_subselect.h: Remove not used functions sql/mysql_priv.h: Merged the different find_xxxx_table_in_list functions to one + some inline functions sql/sql_acl.cc: More debugging + simple cleanups sql/sql_base.cc: Merged the different find_xxxx_table_in_list functions to one + some inline functions Indentation cleanups & more comments sql/sql_delete.cc: Namechange sql/sql_insert.cc: Simple optimizations & Style cleanups Merged common code (in mysql_prepare_insert_check_table) sql/sql_lex.cc: function name changes More comments sql/sql_parse.cc: Function name changes Made check_one_table_access returning bool More debugging in 'check_access' Added function 'check_some_access', which is used when creating a view sql/sql_prepare.cc: Resetting flag directly after test makes code easier to read sql/sql_select.cc: Code simplifications sql/sql_show.cc: Indentation cleanups. Fixed typo in name sql/sql_update.cc: Function name change sql/sql_view.cc: Simple optimizations. Style fixes. Remove view_field_names[] Simplified 'check_key_in_view()' sql/table.cc: Simplified new code in openfrm() variable name change i -> item Indentation changes sql/table.h: Fixed typo in variable name Method name change in field iterator: end() -> end_of_fields() tests/client_test.c: Changed number to macro --- mysql-test/r/view.result | 2 - sql/item_subselect.cc | 17 --- sql/item_subselect.h | 2 - sql/mysql_priv.h | 30 ++++- sql/sql_acl.cc | 36 +++-- sql/sql_base.cc | 212 +++++++++++++---------------- sql/sql_delete.cc | 2 +- sql/sql_insert.cc | 158 ++++++++++++---------- sql/sql_lex.cc | 12 +- sql/sql_parse.cc | 68 ++++++++-- sql/sql_prepare.cc | 2 +- sql/sql_select.cc | 67 +++++----- sql/sql_show.cc | 6 +- sql/sql_update.cc | 4 +- sql/sql_view.cc | 282 +++++++++++++++++++-------------------- sql/table.cc | 36 +++-- sql/table.h | 8 +- tests/client_test.c | 5 +- 18 files changed, 491 insertions(+), 458 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 98c04b31e96..37e9c8fc2fa 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -138,7 +138,6 @@ v3 VIEW v4 VIEW v5 VIEW v6 VIEW -vt1 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 5 9 45 38654705663 1024 0 NULL # # NULL latin1_swedish_ci NULL @@ -148,7 +147,6 @@ v3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL vie v4 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view v5 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view v6 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view -vt1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view drop view v1,v2,v3,v4,v5,v6; create view v1 (c,d,e,f) as select a,b, a in (select a+2 from t1), a = all (select a from t1) from t1; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 33e661ce46e..b1d6d7bbe35 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -990,23 +990,6 @@ Item_in_subselect::select_transformer(JOIN *join) } -Item_subselect::trans_res -Item_in_subselect::no_select_transform() -{ - DBUG_ENTER("Item_in_subselect::no_select_transform"); - // We have execute fix_fields() for left expression - SELECT_LEX *current= thd->lex->current_select, *up; - thd->lex->current_select= up= current->return_after_parsing(); - if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr)) - { - thd->lex->current_select= current; - DBUG_RETURN(RES_ERROR); - } - thd->lex->current_select= current; - DBUG_RETURN(RES_OK); -} - - void Item_in_subselect::print(String *str) { if (transformed) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index d50688e0b58..1268b435816 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -84,7 +84,6 @@ public: null_value= 1; } virtual trans_res select_transformer(JOIN *join); - virtual trans_res no_select_transform() { return RES_OK; } bool assigned() { return value_assigned; } void assigned(bool a) { value_assigned= a; } enum Type type() const; @@ -220,7 +219,6 @@ public: was_null= 0; } trans_res select_transformer(JOIN *join); - trans_res no_select_transform(); trans_res single_value_transformer(JOIN *join, Comp_creator *func); trans_res row_value_transformer(JOIN * join); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ba19ee15ce6..ac0890c60df 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -398,8 +398,9 @@ void free_items(Item *item); void cleanup_items(Item *item); class THD; void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0); -int check_one_table_access(THD *thd, ulong privilege, +bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables); +bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table); bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); int multi_update_precheck(THD *thd, TABLE_LIST *tables); @@ -764,12 +765,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); @@ -785,6 +784,23 @@ int fill_record(List &fields,List &values, bool ignore_errors); int fill_record(Field **field,List &values, bool ignore_errors); OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); +inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table, + const char *db_name, + const char *table_name) +{ + return find_table_in_list(table, offsetof(TABLE_LIST, next_global), + db_name, table_name); +} + +inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table, + const char *db_name, + const char *table_name) +{ + return find_table_in_list(table, offsetof(TABLE_LIST, next_local), + db_name, table_name); +} + + /* sql_calc.cc */ bool eval_const_cond(COND *cond); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 10a12ef6d04..394d7336c79 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2750,7 +2750,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, @@ -2758,14 +2773,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) { /* @@ -2775,10 +2793,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 @@ -2802,7 +2818,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); @@ -2837,7 +2853,7 @@ err: thd->host_or_ip, table ? table->real_name : "unknown"); } - return 1; + DBUG_RETURN(1); } @@ -2931,7 +2947,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, if (!(grant_table= grant->grant_table)) goto err; /* purecov: inspected */ - for (; fields->end(); fields->next()) + for (; !fields->end_of_fields(); fields->next()) { const char *field_name= fields->name(); grant_column= column_hash_search(grant_table, field_name, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 781e7273e7a..6fdc8014db1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -548,81 +548,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; } @@ -1363,7 +1319,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 @@ -1403,10 +1359,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; @@ -1603,7 +1559,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); } @@ -1671,7 +1627,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) thd->proc_info="Opening table"; thd->current_tablenr= 0; - while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) ; + while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) + ; if (table) { @@ -1900,7 +1857,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; @@ -1979,6 +1936,7 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list, return fld; } + /* Find field in table @@ -2561,23 +2519,47 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, } -/**************************************************************************** - This just drops in all fields instead of current '*' field - Returns pointer to last inserted field if ok -****************************************************************************/ +/* + Drops in all fields instead of current '*' field + + SYNOPSIS + insert_fields() + thd Thread handler + tables List of tables + db_name Database name in case of 'database_name.table_name.*' + table_name Table name in case of 'table_name.*' + it Pointer to '*' + any_privileges 0 If we should ensure that we have SELECT privileges + for all columns + 1 If any privilege is ok + RETURN + 0 ok + 'it' is updated to point at last inserted + 1 error. The error message is sent to client +*/ bool insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it, bool any_privileges) { + /* allocate variables on stack to avoid pool alloaction */ + Field_iterator_table table_iter; + Field_iterator_view view_iter; uint found; DBUG_ENTER("insert_fields"); - found=0; + found= 0; for (; tables; tables= tables->next_local) { - TABLE *table=tables->table; + Field_iterator *iterator; + TABLE_LIST *natural_join_table; + Field *field; + TABLE_LIST *embedded; + TABLE_LIST *last; + TABLE_LIST *embedding; + TABLE *table= tables->table; + if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, tables->alias) && (!db_name || !strcmp(tables->db,db_name)))) @@ -2588,36 +2570,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) @@ -2648,7 +2620,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; @@ -2699,9 +2671,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 @@ -2735,15 +2705,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); } @@ -2832,13 +2804,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(); @@ -2854,9 +2829,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; @@ -3190,17 +3163,19 @@ 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, uint db_stat, uint prgflag, 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); - 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)) { @@ -3217,10 +3192,7 @@ open_new_frm(const char *path, const char *alias, uint db_stat, uint prgflag, bzero(outparam, sizeof(outparam)); // do not run repair DBUG_RETURN(1); } + DBUG_RETURN(0); } - else - { - DBUG_RETURN(1); - } - DBUG_RETURN(0); + DBUG_RETURN(1); } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 910b673dc32..d9d60be162a 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -282,7 +282,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); DBUG_RETURN(-1); } - if (find_real_table_in_list(table_list->next_global, + if (find_table_in_global_list(table_list->next_global, table_list->db, table_list->real_name)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 33b99d4ccf9..7d3479a18bb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -51,6 +51,8 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, List &values, ulong counter, bool check_unique) { TABLE *table= table_list->table; + int error; + if (fields.elements == 0 && values.elements != 0) { if (values.elements != table->fields) @@ -61,11 +63,11 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, return -1; } #ifndef NO_EMBEDDED_ACCESS_CHECKS + if (grant_option) { Field_iterator_table fields; fields.set_table(table); - if (grant_option && - check_grant_all_columns(thd, INSERT_ACL, &table->grant, + if (check_grant_all_columns(thd, INSERT_ACL, &table->grant, table->table_cache_key, table->real_name, &fields)) return -1; @@ -75,7 +77,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, } else { // Part field list - TABLE_LIST *save_next= table_list->next_local; + TABLE_LIST *save_next; if (fields.elements != values.elements) { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, @@ -84,14 +86,13 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, return -1; } - table_list->next_local= 0; thd->dupp_field=0; - if (setup_fields(thd, 0, table_list, fields, 1, 0, 0)) - { - table_list->next_local= save_next; - return -1; - } + save_next= table_list->next_local; // fields only from first table + table_list->next_local= 0; + error= setup_fields(thd, 0, table_list, fields, 1, 0, 0); table_list->next_local= save_next; + if (error) + return -1; // setup_fields failed if (check_unique && thd->dupp_field) { @@ -407,7 +408,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 { @@ -420,7 +421,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; @@ -444,46 +445,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->type() == 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 */ @@ -491,14 +504,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); @@ -506,29 +518,28 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id) /* - Prepare items in INSERT statement + Check if table can be updated SYNOPSIS - mysql_prepare_insert() - thd - thread handler - table_list - global/local table list + mysql_prepare_insert_check_table() + thd Thread handle + table_list Table list (only one table) + fields List of fields to be updated + where Pointer to where clause - RETURN VALUE - 0 - OK - -1 - error (message is not sent to user) + RETURN + 0 ok + 1 ERROR */ -int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, - List &fields, List_item *values, - List &update_fields, List &update_values, - enum_duplicates duplic) + +static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, + List &fields, COND **where) { bool insert_into_view= (table_list->view != 0); - DBUG_ENTER("mysql_prepare_insert"); + DBUG_ENTER("mysql_prepare_insert_check_table"); - /* TODO: use this condition for 'WHITH CHECK OPTION' */ - Item *unused_conds= 0; - if (setup_tables(thd, table_list, &unused_conds)) - DBUG_RETURN(-1); + if (setup_tables(thd, table_list, where)) + DBUG_RETURN(1); if (insert_into_view && !fields.elements) { @@ -542,8 +553,37 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, check_view_insertability(table_list, thd->query_id))) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); - DBUG_RETURN(-1); + DBUG_RETURN(1); } + DBUG_RETURN(0); +} + + +/* + Prepare items in INSERT statement + + SYNOPSIS + mysql_prepare_insert() + thd Thread handler + table_list Global/local table list + + RETURN VALUE + 0 OK + -1 error (message is not sent to user) +*/ + +int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, + List &fields, List_item *values, + List &update_fields, List &update_values, + enum_duplicates duplic) +{ + bool insert_into_view= (table_list->view != 0); + /* TODO: use this condition for 'WITH CHECK OPTION' */ + Item *unused_conds= 0; + 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) || @@ -553,7 +593,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, 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); @@ -1555,27 +1595,11 @@ bool delayed_insert::handle_inserts(void) int mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; - TABLE_LIST *table_list= lex->query_tables; - bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_insert_select_prepare"); - - if (setup_tables(thd, table_list, &lex->select_lex.where)) + if (mysql_prepare_insert_check_table(thd, lex->query_tables, + lex->field_list, + &lex->select_lex.where)) DBUG_RETURN(-1); - - if (insert_into_view && !lex->field_list.elements) - { - lex->empty_field_list_on_rset= 1; - insert_view_fields(&lex->field_list, table_list); - } - - if (!table_list->updatable || - check_key_in_view(thd, table_list) || - (insert_into_view && - check_view_insertability(table_list, thd->query_id))) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); - DBUG_RETURN(-1); - } DBUG_RETURN(0); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d96c6371ff1..aa5cb04f628 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1422,7 +1422,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(); @@ -1631,14 +1631,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) @@ -1692,11 +1694,11 @@ void st_lex::first_lists_tables_same() TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first; if (query_tables != first_table && first_table != 0) { + TABLE_LIST *next; if (query_tables_last == &first_table->next_global) query_tables_last= first_table->prev_global; - TABLE_LIST *next= *first_table->prev_global= first_table->next_global; - first_table->next_global= 0; - if (next) + + if ((next= *first_table->prev_global= first_table->next_global)) next->prev_global= first_table->prev_global; /* include in new place */ first_table->next_global= query_tables; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index be063211a7d..0ba1789cfbf 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1905,7 +1905,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 && @@ -2381,8 +2381,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; @@ -2752,7 +2752,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 */ @@ -3907,7 +3907,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)) @@ -3951,13 +3951,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 @@ -3965,8 +3965,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 */ } @@ -3991,6 +3992,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, @@ -4009,13 +4011,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, @@ -4103,6 +4109,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) { @@ -4960,6 +5002,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) @@ -5011,7 +5054,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; - ptr->select_lex= thd->lex->current_select; + ptr->select_lex= lex->current_select; ptr->cacheable_table= 1; if (use_index_arg) ptr->use_index=(List *) thd->memdup((gptr) use_index_arg, @@ -5035,8 +5078,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } } } + /* Link table in local list (list for current select) */ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local); - LEX *lex= thd->lex; + /* Link table in global list (all used tables) */ *(ptr->prev_global= lex->query_tables_last)= ptr; lex->query_tables_last= &ptr->next_global; DBUG_RETURN(ptr); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5214ae95b86..46d83e61e22 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1665,8 +1665,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) if (lex->empty_field_list_on_rset) { - lex->field_list.empty(); lex->empty_field_list_on_rset= 0; + lex->field_list.empty(); } for (; sl; sl= sl->next_select_in_list()) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 328fd4f9976..10a4d551d32 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -225,25 +225,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result) thd->net.report_error)); if (thd->net.report_error) res= 1; - if (res > 0) + if (unlikely(res)) { if (result) { - result->send_error(0, NullS); + if (res > 0) + result->send_error(0, NullS); result->abort(); } - else + else if (res > 0) send_error(thd, 0, NullS); res= 1; // Error sent to client } - if (res < 0) - { - if (result) - { - result->abort(); - } - res= 1; - } if (result != lex->result) delete result; DBUG_RETURN(res); @@ -348,9 +341,7 @@ JOIN::prepare(Item ***rref_pointer_array, if ((subselect= select_lex->master_unit()->item)) { Item_subselect::trans_res res; - if ((res= ((!thd->lex->view_prepare_mode) ? - subselect->select_transformer(this) : - subselect->no_select_transform())) != + if ((res= subselect->select_transformer(this)) != Item_subselect::RES_OK) { select_lex->fix_prepare_information(thd, &conds); @@ -11192,7 +11183,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 */ @@ -11248,30 +11239,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) - { - str->append(view_db.str, view_db.length); - str->append('.'); - str->append(view_name.str, view_name.length); - if (my_strcasecmp(table_alias_charset, view_name.str, alias)) - { - str->append(' '); - str->append(alias); - } - } - else if (derived) - { - str->append('('); - derived->print(str); - str->append(") ", 2); - str->append(alias); - } else { - str->append(db); - str->append('.'); - str->append(real_name); - if (my_strcasecmp(table_alias_charset, real_name, alias)) + const char *cmp_name; // Name to compare with alias + if (view_name.str) + { + str->append(view_db.str, view_db.length); + str->append('.'); + str->append(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 + { + str->append(db); + str->append('.'); + str->append(real_name); + cmp_name= real_name; + } + if (my_strcasecmp(table_alias_charset, cmp_name, alias)) { str->append(' '); str->append(alias); @@ -11279,6 +11271,7 @@ void st_table_list::print(THD *thd, String *str) } } + void st_select_lex::print(THD *thd, String *str) { if (!thd) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index da0a6ed3d28..d9180df3791 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1551,11 +1551,11 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) MODE_MAXDB | MODE_ANSI)) != 0; buff->append("CREATE ", 7); - if(!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE || - table->algorithm == VIEW_ALGORITHM_TMEPTABLE)) + if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE || + table->algorithm == VIEW_ALGORITHM_TMPTABLE)) { buff->append("ALGORITHM=", 10); - if (table->algorithm == VIEW_ALGORITHM_TMEPTABLE) + if (table->algorithm == VIEW_ALGORITHM_TMPTABLE) buff->append("TMPTABLE ", 9); else buff->append("MERGE ", 6); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7d49c422194..77d48dccb10 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -483,7 +483,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); @@ -760,7 +760,7 @@ int multi_update::prepare(List ¬_used_values, { TABLE *table=table_ref->table; if (!(tables_to_update & table->map) && - find_real_table_in_list(update_tables, table_ref->db, + find_table_in_global_list(update_tables, table_ref->db, table_ref->real_name)) table->no_cache= 1; // Disable row cache } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 5a16f0ff3fc..d8198f98a32 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -79,25 +79,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), @@ -113,7 +96,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; /* @@ -166,7 +149,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; @@ -189,19 +172,18 @@ int mysql_create_view(THD *thd, /* view list (list of view fields names) */ if (lex->view_list.elements) { + List_iterator_fast it(select_lex->item_list); + List_iterator_fast nm(lex->view_list); + Item *item; + LEX_STRING *name; + if (lex->view_list.elements != select_lex->item_list.elements) { my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0)); goto err; } - List_iterator_fast it(select_lex->item_list); - List_iterator_fast nm(lex->view_list); - Item *item; - LEX_STRING *name; - while((item= it++, name= nm++)) - { + while ((item= it++, name= nm++)) item->set_name(name->str, name->length, system_charset_info); - } } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -214,7 +196,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) & @@ -223,10 +205,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, @@ -242,7 +224,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, @@ -266,14 +248,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); @@ -292,40 +271,36 @@ err: // index of revision number in following table static const int revision_number_position= 4; -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), + {{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable), 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} }; +static const uint required_view_parameters= 6; + static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}}; @@ -368,16 +343,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); @@ -390,34 +367,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 @@ -448,14 +418,14 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, } view->algorithm= thd->lex->create_view_algorithm; if ((view->updatable= (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) + if (tbl->view && !tbl->updatable) { view->updatable= 0; break; @@ -478,7 +448,13 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, mysql_make_view() parser - parser object; table - TABLE_LIST structure for filling + + RETURN + 0 ok + 1 error + */ + my_bool mysql_make_view(File_parser *parser, TABLE_LIST *table) { @@ -487,7 +463,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) 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); } @@ -507,13 +483,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; /* @@ -535,7 +512,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) */ table->view= lex= thd->lex= (LEX*) new(&thd->mem_root) st_lex_local; lex_start(thd, (uchar*)table->query.str, table->query.length); - mysql_init_query(thd, true); + mysql_init_query(thd, TRUE); lex->select_lex.select_number= ++thd->select_number; old_lex->derived_tables|= DERIVED_VIEW; { @@ -613,7 +590,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())) @@ -656,11 +633,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) goto ok; } - table->effective_algorithm= VIEW_ALGORITHM_TMEPTABLE; + table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE; if (table->updatable) { - //TOTO: warning: can't be updateable, .frm edited by hand. version - //downgrade? + /* + TODO: warning: can't be updateable, .frm edited by hand. version + downgrade? + */ table->updatable= 0; } @@ -672,7 +651,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; } @@ -720,6 +700,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"); @@ -729,8 +710,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))) @@ -782,21 +763,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, header, 10, MYF(MY_WME)) == MY_FILE_ERROR) - { - my_close(file, MYF(MY_WME)); - DBUG_RETURN(FRMTYPE_ERROR); - } + length= my_read(file, 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 } @@ -815,72 +795,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); } } } @@ -899,18 +888,17 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) void insert_view_fields(List *list, TABLE_LIST *view) { - uint num= view->view->select_lex.item_list.elements; - Item **trans= view->field_translation; + uint elements_in_view= view->view->select_lex.item_list.elements; + Item **trans; DBUG_ENTER("insert_view_fields"); - if (!trans) + + if (!(trans= view->field_translation)) DBUG_VOID_RETURN; - for (uint i= 0; i < num; i++) + for (uint i= 0; i < elements_in_view; i++) { if (trans[i]->type() == Item::FIELD_ITEM) - { list->push_back(trans[i]); - } } DBUG_VOID_RETURN; } diff --git a/sql/table.cc b/sql/table.cc index 43b39ffb37e..8ac0f409e2f 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -88,6 +88,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam)); error=1; + disk_buff=NULL; + old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); if ((file=my_open(fn_format(index_file, name, "", reg_ext, MY_UNPACK_FILENAME), @@ -118,11 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, bzero((char*) outparam,sizeof(*outparam)); outparam->blob_ptr_size=sizeof(char*); - disk_buff=NULL; record= NULL; keynames=NullS; outparam->db_stat = db_stat; - init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); - old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root); outparam->real_name=strdup_root(&outparam->mem_root, @@ -742,11 +741,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, DBUG_RETURN (0); err_w_init: - //awoid problem with uninitialized data + /* Avoid problem with uninitialized data */ bzero((char*) outparam,sizeof(*outparam)); outparam->real_name= (char*)name+dirname_length(name); - old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); - disk_buff= 0; err_not_open: x_free((gptr) disk_buff); @@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name) st_table_list::calc_md5() buffer buffer for md5 writing */ + void st_table_list::calc_md5(char *buffer) { my_MD5_CTX context; - unsigned char digest[16]; - my_MD5Init (&context); - my_MD5Update (&context,(unsigned char *) query.str, query.length); - my_MD5Final (digest, &context); + uchar digest[16]; + my_MD5Init(&context); + my_MD5Update(&context,(uchar *) query.str, query.length); + my_MD5Final(digest, &context); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], @@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer) SYNOPSIS st_table_list::set_ancestor() */ + void st_table_list::set_ancestor() { if (ancestor->ancestor) @@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor() (without fields) for name resolving, but substituted expressions will return correct used tables mask. */ + bool st_table_list::setup_ancestor(THD *thd, Item **conds) { Item **transl; @@ -1515,13 +1515,13 @@ 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; - 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; } @@ -1545,19 +1545,17 @@ 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; 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) { @@ -1566,12 +1564,12 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) goto err; if (arena) - thd->set_n_backup_item_arena(arena, &backup); + thd->set_n_backup_item_arena(arena, &backup); if (outer_join) { /* Store WHERE condition to ON expression for outer join, because we - can't use WHERE to correctly execute jeft joins on VIEWs and this + can't use WHERE to correctly execute jeft joins on VIEWs and this expression will not be moved to WHERE condition (i.e. will be clean correctly for PS/SP) */ diff --git a/sql/table.h b/sql/table.h index 5e00820a6e5..02e470a69e0 100644 --- a/sql/table.h +++ b/sql/table.h @@ -172,7 +172,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; @@ -255,7 +255,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; @@ -270,7 +270,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; } @@ -284,7 +284,7 @@ public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table); void next() { ptr++; } - bool end() { return ptr < array_end; } + bool end_of_fields() { return ptr == array_end; } const char *name(); Item *item(THD *thd) { return *ptr; } Field *field() { return 0; } diff --git a/tests/client_test.c b/tests/client_test.c index 13f5a3ac852..e9adf40d8b6 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -30,6 +30,7 @@ #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ +#define MAX_KEY 64 /* set default options */ static char *opt_db= 0; @@ -6818,13 +6819,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); From fa3bfbe45796edd85cce30e62ff1fcfb81df745c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 4 Sep 2004 15:02:57 +0300 Subject: [PATCH 17/22] Print value of Item_param if it has a value (when debugging) libmysql/libmysql.c: More debug sql/item.h: Print value of param if it has a value (when debugging) sql/log.cc: Better variable name sql/sql_insert.cc: Fix bug casused by merge sql/sql_parse.cc: Added missing command names (caused crash when running with --debug) sql/sql_select.cc: More debugging sql/sql_yacc.yy: Fixed typo tests/client_test.c: More debugging --- libmysql/libmysql.c | 2 +- sql/item.cc | 21 ++++++++++++++++++++- sql/item.h | 2 +- sql/log.cc | 10 +++++----- sql/sql_insert.cc | 7 +++---- sql/sql_parse.cc | 1 + sql/sql_select.cc | 9 ++++++--- sql/sql_yacc.yy | 2 +- tests/client_test.c | 2 ++ 9 files changed, 40 insertions(+), 16 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 2dd35809a7b..a93a89f797f 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2384,7 +2384,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) char buff[4 /* size of stmt id */ + 5 /* execution flags */]; DBUG_ENTER("execute"); - DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); + DBUG_DUMP("packet", packet, length); mysql->last_used_con= mysql; int4store(buff, stmt->stmt_id); /* Send stmt id to server */ diff --git a/sql/item.cc b/sql/item.cc index 517309acd2b..099e6b977d6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1143,8 +1143,27 @@ bool Item_param::convert_str_value(THD *thd) return rc; } -/* End of Item_param related */ +void Item_param::print(String *str) +{ + if (state == NO_VALUE) + { + str->append('?'); + } + else + { + char buffer[80]; + String tmp(buffer, sizeof(buffer), &my_charset_bin); + const String *res; + res= query_val_str(&tmp); + str->append(*res); + } +} + + +/**************************************************************************** + Item_copy_string +****************************************************************************/ void Item_copy_string::copy() { diff --git a/sql/item.h b/sql/item.h index 4030c0fc097..63463c6cc41 100644 --- a/sql/item.h +++ b/sql/item.h @@ -635,7 +635,7 @@ public: */ virtual table_map used_tables() const { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } - void print(String *str) { str->append('?'); } + void print(String *str); /* parameter never equal to other parameter of other item */ bool eq(const Item *item, bool binary_cmp) const { return 0; } }; diff --git a/sql/log.cc b/sql/log.cc index 5e15b2b170c..44c8ce59aaf 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -838,13 +838,13 @@ int MYSQL_LOG::purge_logs(const char *to_log, while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && !log_in_use(log_info.log_file_name)) { - ulong tmp; - LINT_INIT(tmp); + ulong file_size; + LINT_INIT(file_size); if (decrease_log_space) //stat the file we want to delete { MY_STAT s; if (my_stat(log_info.log_file_name,&s,MYF(0))) - tmp= s.st_size; + file_size= s.st_size; else { /* @@ -852,7 +852,7 @@ int MYSQL_LOG::purge_logs(const char *to_log, of space that deletion will free. In most cases, deletion won't work either, so it's not a problem. */ - tmp= 0; + file_size= 0; } } /* @@ -861,7 +861,7 @@ int MYSQL_LOG::purge_logs(const char *to_log, */ DBUG_PRINT("info",("purging %s",log_info.log_file_name)); if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space) - *decrease_log_space-= tmp; + *decrease_log_space-= file_size; if (find_next_log(&log_info, 0) || exit_loop) break; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 754db176faa..b7940e2d9d0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -86,14 +86,13 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List &fields, return -1; } - table_list->next_local= 0; thd->dupp_field=0; - save_next= table_list->next_local; // fields only from first table - 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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 36a240fa74e..98f1810adc3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -78,6 +78,7 @@ const char *command_name[]={ "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", "Binlog Dump","Table Dump", "Connect Out", "Register Slave", "Prepare", "Prepare Execute", "Long Data", "Close stmt", + "Reset stmt", "Set option", "Fetch", "Error" // Last command number }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3e0ed0de96c..5bd7cb62667 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -543,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); @@ -560,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); } @@ -11641,7 +11646,6 @@ void st_table_list::print(THD *thd, String *str) } if (my_strcasecmp(table_alias_charset, cmp_name, alias)) { - { str->append(' '); append_identifier(thd, str, alias, strlen(alias)); } @@ -11649,7 +11653,6 @@ void st_table_list::print(THD *thd, String *str) } - void st_select_lex::print(THD *thd, String *str) { if (!thd) @@ -11657,7 +11660,7 @@ void st_select_lex::print(THD *thd, String *str) str->append("select ", 7); - //options + /* First add options */ if (options & SELECT_STRAIGHT_JOIN) str->append("straight_join ", 14); if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) && diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 172ec48fb18..ba3a36f2c34 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7553,7 +7553,7 @@ algorithm: | ALGORITHM_SYM EQ MERGE_SYM { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; } | ALGORITHM_SYM EQ TEMPTABLE_SYM - { Lex->create_view_algorithm= VIEW_ALGORITHM_TMEPTABLE; } + { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; } ; check_option: /* empty */ {} diff --git a/tests/client_test.c b/tests/client_test.c index 9b6c215b66b..08ea345a355 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -5508,6 +5508,7 @@ static void test_subselect() MYSQL_STMT *stmt; int rc, id; MYSQL_BIND bind[1]; + DBUG_ENTER("test_subselect"); myheader("test_subselect"); @@ -5609,6 +5610,7 @@ static void test_subselect() assert(rc == MYSQL_NO_DATA); mysql_stmt_close(stmt); + DBUG_VOID_RETURN; } From d7d2712f60e8b43cd9424bd56a2ec18171b501d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 4 Sep 2004 23:05:12 +0300 Subject: [PATCH 18/22] memory leaks fixed sql/sql_derived.cc: memory leak fixed sql/sql_view.cc: memory leak fixed --- sql/sql_derived.cc | 8 +++++--- sql/sql_view.cc | 6 ++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 3137890f2ba..5c827741e6d 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -220,10 +220,12 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, table->next= thd->derived_tables; thd->derived_tables= table; } + } + else + free_tmp_table(thd, table); exit: - delete derived_result; - lex->current_select= save_current_select; - } + delete derived_result; + lex->current_select= save_current_select; DBUG_RETURN(res); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 67c7c39e223..2b1971907b3 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -339,8 +339,6 @@ static File_option view_parameters[]= FILE_OPTIONS_STRING} }; -static const uint required_view_parameters= 6; - static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}}; @@ -604,8 +602,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) { /* move SP to main LEX */ sp_merge_funs(old_lex, lex); - if (lex->spfuns.array.buffer) - hash_free(&lex->spfuns); if (old_lex->proc_table == 0 && (old_lex->proc_table= (TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0) @@ -619,6 +615,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) include_proc_table= 1; } } + if (lex->spfuns.array.buffer) + hash_free(&lex->spfuns); old_next= table->next_global; if ((table->next_global= lex->query_tables)) From 810512972b785b63ca7d999c9c944526cad397a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 6 Sep 2004 00:32:21 +0400 Subject: [PATCH 19/22] After review fix: added a comment --- mysys/default.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysys/default.c b/mysys/default.c index eb5c6446b83..70a3c462c3c 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -239,6 +239,12 @@ int process_default_option_files(const char *conf_file, 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 From 0a04f6b165035ec77e602b66482510d54c28e0bd Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 6 Sep 2004 14:37:10 +0300 Subject: [PATCH 20/22] do not use Item_ref for view fields if it is UPDATE of INSERT (BUG#5263) mysql-test/r/view.result: INSERT into VIEW with ON DUPLICATE mysql-test/t/view.test: INSERT into VIEW with ON DUPLICATE sql/sql_insert.cc: do not use Item_ref for view fields if it is UPDATE of INSERT --- mysql-test/r/view.result | 9 +++++++++ mysql-test/t/view.test | 11 +++++++++++ sql/sql_insert.cc | 6 +++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a00938add07..35b76a8ab4b 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1261,3 +1261,12 @@ create table t1 (a int); create view v1 as select a from t1 procedure analyse(); ERROR HY000: View's SELECT contains a 'PROCEDURE' clause drop table t1; +create table t1 (s1 int, primary key (s1)); +create view v1 as select * from t1; +insert into v1 values (1) on duplicate key update s1 = 7; +insert into v1 values (1) on duplicate key update s1 = 7; +select * from t1; +s1 +7 +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index f03e48167fd..9464e291e05 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1219,3 +1219,14 @@ create table t1 (a int); -- error 1349 create view v1 as select a from t1 procedure analyse(); drop table t1; + +# +# INSERT into VIEW with ON DUPLICATE +# +create table t1 (s1 int, primary key (s1)); +create view v1 as select * from t1; +insert into v1 values (1) on duplicate key update s1 = 7; +insert into v1 values (1) on duplicate key update s1 = 7; +select * from t1; +drop view v1; +drop table t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b7940e2d9d0..857c500f200 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -582,6 +582,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, 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)) @@ -591,7 +592,10 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, !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); From 898e363c3ac44a2afe87f71566c2b147ab575748 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 6 Sep 2004 18:19:19 +0400 Subject: [PATCH 21/22] Fixed memory allocation: allocated memory wasn't enough to store the final 0 of the string. mysys/default.c: Wrong memory allocation fixed. --- mysys/default.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/default.c b/mysys/default.c index 70a3c462c3c..a8343c6a21d 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -258,7 +258,7 @@ static int handle_default_option(void *in_ctx, const char *group_name, 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)))) + if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1))) return 1; if (insert_dynamic(ctx->args, (gptr) &tmp)) return 1; From 9c5510807a75cb6999f392741590aa5cafc2cfaf Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 6 Sep 2004 20:11:04 +0300 Subject: [PATCH 22/22] postmerge fix (found by Dmitry) sql/item.cc: postmerge fix --- sql/item.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item.cc b/sql/item.cc index d8f4871486f..efd94716dc7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2117,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