From e334f82ccd4aa3071a804e498c6eeca437f24f63 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Apr 2006 14:27:59 +0400 Subject: [PATCH 01/41] Bug#6951: Triggers/Traditional: SET @ result wrong While executing a trigger, we have to set thd->abort_on_warning to the value it had at trigger creation time. mysql-test/r/trigger.result: Add result for bug#6951. mysql-test/t/trigger.test: Add test case for bug#6951. sql/sp_head.cc: While executing a trigger, set thd->abort_on_warning to the value it had at trigger creation time. --- mysql-test/r/trigger.result | 36 ++++++++++++++++++++++++++++ mysql-test/t/trigger.test | 48 +++++++++++++++++++++++++++++++++++++ sql/sp_head.cc | 6 +++++ 3 files changed, 90 insertions(+) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 681b805f547..b8983df1bc5 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -965,3 +965,39 @@ SELECT * FROM t1 WHERE conn_id != trigger_conn_id; conn_id trigger_conn_id DROP TRIGGER t1_bi; DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i1 INT); +SET @save_sql_mode=@@sql_mode; +SET SQL_MODE=''; +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW +SET @x = 5/0; +SET SQL_MODE='traditional'; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW +SET @x = 5/0; +SET @x=1; +INSERT INTO t1 VALUES (@x); +SELECT @x; +@x +NULL +SET @x=2; +UPDATE t1 SET i1 = @x; +ERROR 22012: Division by 0 +SELECT @x; +@x +2 +SET SQL_MODE=''; +SET @x=3; +INSERT INTO t1 VALUES (@x); +SELECT @x; +@x +NULL +SET @x=4; +UPDATE t1 SET i1 = @x; +ERROR 22012: Division by 0 +SELECT @x; +@x +4 +SET @@sql_mode=@save_sql_mode; +DROP TRIGGER t1_ai; +DROP TRIGGER t1_au; +DROP TABLE t1; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index a0b67b2204d..e9624ee49b0 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1141,4 +1141,52 @@ SELECT * FROM t1 WHERE conn_id != trigger_conn_id; DROP TRIGGER t1_bi; DROP TABLE t1; + +# +# Bug#6951: Triggers/Traditional: SET @ result wrong +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (i1 INT); + +SET @save_sql_mode=@@sql_mode; + +SET SQL_MODE=''; + +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW + SET @x = 5/0; + +SET SQL_MODE='traditional'; + +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW + SET @x = 5/0; + +SET @x=1; +INSERT INTO t1 VALUES (@x); +SELECT @x; + +SET @x=2; +--error 1365 +UPDATE t1 SET i1 = @x; +SELECT @x; + +SET SQL_MODE=''; + +SET @x=3; +INSERT INTO t1 VALUES (@x); +SELECT @x; + +SET @x=4; +--error 1365 +UPDATE t1 SET i1 = @x; +SELECT @x; + +SET @@sql_mode=@save_sql_mode; + +DROP TRIGGER t1_ai; +DROP TRIGGER t1_au; +DROP TABLE t1; + # End of 5.0 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 15d621b1d6d..c5f5d8a787e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -935,6 +935,7 @@ sp_head::execute(THD *thd) bool err_status= FALSE; uint ip= 0; ulong save_sql_mode; + bool save_abort_on_warning; Query_arena *old_arena; /* per-instruction arena */ MEM_ROOT execute_mem_root; @@ -995,6 +996,10 @@ sp_head::execute(THD *thd) thd->derived_tables= 0; save_sql_mode= thd->variables.sql_mode; thd->variables.sql_mode= m_sql_mode; + save_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= + (m_sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); + /* It is also more efficient to save/restore current thd->lex once when do it in each instruction @@ -1127,6 +1132,7 @@ sp_head::execute(THD *thd) DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; + thd->abort_on_warning= save_abort_on_warning; thd->stmt_arena= old_arena; state= EXECUTED; From f4cab9f5e5e2a0b8086e757fd954fa1cf0bbc72a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Apr 2006 21:59:04 +0930 Subject: [PATCH 02/41] sql_mode.test: BUG#14765: Modified test file. sql_mode.result: BUG#14765: Modified result file. mysql-test/r/sql_mode.result: BUG#14765: Modified result file. mysql-test/t/sql_mode.test: BUG#14765: Modified test file. --- mysql-test/r/sql_mode.result | 4 ++++ mysql-test/t/sql_mode.test | 3 +++ 2 files changed, 7 insertions(+) diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index b05680f9c54..474659f7dfc 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -485,6 +485,10 @@ set sql_mode=2097152; select @@sql_mode; @@sql_mode STRICT_TRANS_TABLES +set sql_mode=4194304; +select @@sql_mode; +@@sql_mode +STRICT_ALL_TABLES set sql_mode=16384+(65536*4); select @@sql_mode; @@sql_mode diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index b67f1a73db6..2699cb66471 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -258,6 +258,9 @@ drop table t1, t2; select @@sql_mode; set sql_mode=2097152; select @@sql_mode; +# BUG#14675 +set sql_mode=4194304; +select @@sql_mode; set sql_mode=16384+(65536*4); select @@sql_mode; --error 1231 From 39f93cd92efa82907510db6987b5d9599246b16e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 May 2006 16:28:11 +0930 Subject: [PATCH 03/41] rpl_auto_increment_11932.result, rpl_auto_increment_11932.test: Test case for BUG#11932 --- mysql-test/r/rpl_auto_increment_11932.result | 46 +++++++++++++++ mysql-test/t/rpl_auto_increment_11932.test | 59 ++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 mysql-test/r/rpl_auto_increment_11932.result create mode 100644 mysql-test/t/rpl_auto_increment_11932.test diff --git a/mysql-test/r/rpl_auto_increment_11932.result b/mysql-test/r/rpl_auto_increment_11932.result new file mode 100644 index 00000000000..753e9e9f223 --- /dev/null +++ b/mysql-test/r/rpl_auto_increment_11932.result @@ -0,0 +1,46 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop database if exists t1; +create database t1; +use t1; +CREATE TABLE `t` ( +`id` int(10) unsigned NOT NULL auto_increment, +`fname` varchar(100) default NULL, +PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; +INSERT INTO `t` VALUES (1, 'blablabla'); +CREATE TABLE `test3` ( +`id` int(10) NOT NULL auto_increment, +`comment` varchar(255) NOT NULL default '', +PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO `test3` VALUES (1, 'testtest 1'); +INSERT INTO `test3` VALUES (2, 'test 2'); +CREATE PROCEDURE simpleproc3 () +NOT DETERMINISTIC +BEGIN +INSERT INTO t (fname) (SELECT test3.comment FROM test3 WHERE test3.id = '1'); +INSERT INTO t (fname) VALUES('test'); +END +$ +CALL simpleproc3(); +select * from test3; +id comment +1 testtest 1 +2 test 2 +TRUNCATE TABLE `t`; +CALL simpleproc3(); +select * from t; +id fname +1 testtest 1 +2 test +use t1; +select * from t; +id fname +1 testtest 1 +2 test +drop database t1; diff --git a/mysql-test/t/rpl_auto_increment_11932.test b/mysql-test/t/rpl_auto_increment_11932.test new file mode 100644 index 00000000000..db9a11277ac --- /dev/null +++ b/mysql-test/t/rpl_auto_increment_11932.test @@ -0,0 +1,59 @@ +# +# Test of auto_increment +# BUG#11932 +# +# Test supplied by Are Casilla +# + +source include/master-slave.inc; +--disable_warnings +connection master; +drop database if exists t1; +--enable_warnings +create database t1; +use t1; + +CREATE TABLE `t` ( + `id` int(10) unsigned NOT NULL auto_increment, + `fname` varchar(100) default NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; + +INSERT INTO `t` VALUES (1, 'blablabla'); + +CREATE TABLE `test3` ( + `id` int(10) NOT NULL auto_increment, + `comment` varchar(255) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 ; + +INSERT INTO `test3` VALUES (1, 'testtest 1'); +INSERT INTO `test3` VALUES (2, 'test 2'); + +DELIMITER $; +CREATE PROCEDURE simpleproc3 () + NOT DETERMINISTIC + BEGIN + INSERT INTO t (fname) (SELECT test3.comment FROM test3 WHERE test3.id = '1'); + INSERT INTO t (fname) VALUES('test'); + END + $ +DELIMITER ;$ + +CALL simpleproc3(); + +select * from test3; + +TRUNCATE TABLE `t`; +CALL simpleproc3(); + +select * from t; + +save_master_pos; +connection slave; +sync_with_master; + +use t1; +select * from t; + +drop database t1; From bf8dac3b1949b16b4a91f0f09ec81806e73a46d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 May 2006 18:02:43 +0400 Subject: [PATCH 04/41] Bug#15463: EXPLAIN SELECT..INTO hangs the client (QB, command line) There were two distict bugs: parse error was returned for valid statement and that error wasn't reported to the client. The fix ensures that EXPLAIN SELECT..INTO is accepted by parser and any other parse error will be reported to the client. mysql-test/r/explain.result: Add result for bug#15463. mysql-test/t/explain.test: Add test case for bug#15463. sql/sql_parse.cc: Assert that if parsing error has occured then apropriate error message has been pushed into error stack. sql/sql_yacc.yy: If there is no lex->result in select_var_ident rule, then we have to be in DESCRIBE mode. --- mysql-test/r/explain.result | 4 ++++ mysql-test/t/explain.test | 9 +++++++++ sql/sql_parse.cc | 1 + sql/sql_yacc.yy | 20 +++++++++++++++----- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index d66dec741bd..75e1548cdee 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -53,3 +53,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE таб ref инд0,инд01 инд0 5 const 1 Using where; Using index drop table таб; set names latin1; +select 3 into @v1; +explain select 3 into @v1; +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 diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 2a3a23c5f96..a38771db233 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -43,3 +43,12 @@ drop table set names latin1; # End of 4.1 tests + + +# +# Bug#15463: EXPLAIN SELECT..INTO hangs the client (QB, command line) +# +select 3 into @v1; +explain select 3 into @v1; + +# End of 5.0 tests. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 196e723299a..649714315a6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5709,6 +5709,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) } else { + DBUG_ASSERT(thd->net.report_error); DBUG_PRINT("info",("Command aborted. Fatal_error: %d", thd->is_fatal_error)); query_cache_abort(&thd->net); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6473163a6ec..261d10f3e79 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5795,7 +5795,11 @@ select_var_ident: if (lex->result) ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0,(enum_field_types)0)); else - YYABORT; + /* + The parser won't create select_result instance only + if it's an EXPLAIN. + */ + DBUG_ASSERT(lex->describe); } | ident_or_text { @@ -5807,10 +5811,8 @@ select_var_ident: my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); YYABORT; } - if (! lex->result) - YYABORT; - else - { + if (lex->result) + { my_var *var; ((select_dumpvar *)lex->result)-> var_list.push_back(var= new my_var($1,1,t->offset,t->type)); @@ -5818,6 +5820,14 @@ select_var_ident: if (var) var->sp= lex->sphead; #endif + } + else + { + /* + The parser won't create select_result instance only + if it's an EXPLAIN. + */ + DBUG_ASSERT(lex->describe); } } ; From 9f606932f72ba80e03fd828f25f6e22c908a77b6 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 6 May 2006 09:41:24 +0400 Subject: [PATCH 05/41] Fix race condition of concurrent RENAME and SHOW TABLES which caused random test failures. mysql-test/t/rename.test: Fix race condition and add cleanup code. --- mysql-test/t/rename.test | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test index 5caecef176e..86e4b6eed0a 100644 --- a/mysql-test/t/rename.test +++ b/mysql-test/t/rename.test @@ -61,9 +61,15 @@ connection con2; sleep 1; show tables; UNLOCK TABLES; -sleep 1; +connection con1; +reap; +connection con2; show tables; drop table t2, t4; +disconnect con2; +disconnect con1; +connection default; + # End of 4.1 tests From 59ff52747d4f8c2146f8ff8b79655746e6a2cc5d Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 6 May 2006 13:51:35 +0400 Subject: [PATCH 06/41] Fix for bug #17260 "Multiple invocations of triggers or stored functions hog memory". During each invocation of stored function or trigger some objects which lifetime is one function call (e.g. sp_rcontext) were allocated on arena/memroot of calling statement. This led to consumption of fixed amount of memory for each function/trigger invocation and so statements which involve lot of them were hogging memory. This in its return led to OOM crashes or freezes. This fix introduces new memroot and arena for objects which lifetime is whole duration of function call. So all memory consumed by such objects is freed at the end of function call. sql/sp_head.cc: sp_head::execute_function(): Introduced new memroot and arena for objects which lifetime is whole duration of function call (e.g. sp_rcontext, sp_cursor). We can't use caller's arena/memroot for those objects because in this case some fixed amount of memory will be consumed for each function/trigger invocation and so statements which involve lot of them will hog memory. Got rid of param_values array to avoid excessive juggling with arenas. --- sql/sp_head.cc | 153 +++++++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 67 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index eea3054ab26..e78bd3c59c0 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1209,130 +1209,144 @@ bool sp_head::execute_function(THD *thd, Item **argp, uint argcount, Field *return_value_fld) { - Item_cache **param_values; ulonglong binlog_save_options; bool need_binlog_call; - uint params; + uint arg_no; sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; + char buf[STRING_BUFFER_USUAL_SIZE]; + String binlog_buf(buf, sizeof(buf), &my_charset_bin); bool err_status= FALSE; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); + Query_arena backup_arena; DBUG_ENTER("sp_head::execute_function"); DBUG_PRINT("info", ("function %s", m_name.str)); - params = m_pcont->context_var_count(); - /* Check that the function is called with all specified arguments. If it is not, use my_error() to report an error, or it will not terminate the invoking query properly. */ - - if (argcount != params) + if (argcount != m_pcont->context_var_count()) { /* Need to use my_error here, or it will not terminate the invoking query properly. */ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), - "FUNCTION", m_qname.str, params, argcount); + "FUNCTION", m_qname.str, m_pcont->context_var_count(), argcount); DBUG_RETURN(TRUE); } - - /* Allocate param_values to be used for dumping the call into binlog. */ - - if (!(param_values= (Item_cache**)thd->alloc(sizeof(Item_cache*)*argcount))) - DBUG_RETURN(TRUE); - - // QQ Should have some error checking here? (types, etc...) + /* + Prepare arena and memroot for objects which lifetime is whole + duration of function call (sp_rcontext, it's tables and items, + sp_cursor and Item_cache holders for case expressions). + We can't use caller's arena/memroot for those objects because + in this case some fixed amount of memory will be consumed for + each function/trigger invocation and so statements which involve + lot of them will hog memory. + TODO: we should create sp_rcontext once per command and reuse + it on subsequent executions of a function/trigger. + */ + init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + thd->set_n_backup_active_arena(&call_arena, &backup_arena); if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) || nctx->init(thd)) { - delete nctx; /* Delete nctx if it was init() that failed. */ - DBUG_RETURN(TRUE); + thd->restore_active_arena(&call_arena, &backup_arena); + err_status= TRUE; + goto err_with_cleanup; } + /* + We have to switch temporarily back to callers arena/memroot. + Function arguments belong to the caller and so the may reference + memory which they will allocate during calculation long after + this function call will be finished (e.g. in Item::cleanup()). + */ + thd->restore_active_arena(&call_arena, &backup_arena); + #ifndef DBUG_OFF nctx->sp= this; #endif /* Pass arguments. */ - + for (arg_no= 0; arg_no < argcount; arg_no++) { - uint i; - - for (i= 0 ; i < argcount ; i++) + /* Arguments must be fixed in Item_func_sp::fix_fields */ + DBUG_ASSERT(argp[arg_no]->fixed); + + if ((err_status= nctx->set_variable(thd, arg_no, argp[arg_no]))) + goto err_with_cleanup; + } + + need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); + + /* + Remember the original arguments for unrolled replication of functions + before they are changed by execution. + */ + if (need_binlog_call) + { + binlog_buf.length(0); + binlog_buf.append(STRING_WITH_LEN("SELECT ")); + append_identifier(thd, &binlog_buf, m_name.str, m_name.length); + binlog_buf.append('('); + for (arg_no= 0; arg_no < argcount; arg_no++) { - if (!argp[i]->fixed && argp[i]->fix_fields(thd, &argp[i])) - { - err_status= TRUE; - break; - } + String str_value_holder; + String *str_value; - param_values[i]= Item_cache::get_cache(argp[i]->result_type()); - param_values[i]->store(argp[i]); + if (arg_no) + binlog_buf.append(','); - if (nctx->set_variable(thd, i, param_values[i])) - { - err_status= TRUE; - break; - } + str_value= sp_get_item_value(nctx->get_item(arg_no), + &str_value_holder); + + if (str_value) + binlog_buf.append(*str_value); + else + binlog_buf.append(STRING_WITH_LEN("NULL")); } + binlog_buf.append(')'); } - - if (err_status) - { - delete nctx; - DBUG_RETURN(TRUE); - } - thd->spcont= nctx; binlog_save_options= thd->options; - need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); if (need_binlog_call) { reset_dynamic(&thd->user_var_events); mysql_bin_log.start_union_events(thd); } - + + /* + Switch to call arena/mem_root so objects like sp_cursor or + Item_cache holders for case expressions can be allocated on it. + + TODO: In future we should associate call arena/mem_root with + sp_rcontext and allocate all these objects (and sp_rcontext + itself) on it directly rather than juggle with arenas. + */ + thd->set_n_backup_active_arena(&call_arena, &backup_arena); + thd->options&= ~OPTION_BIN_LOG; err_status= execute(thd); thd->options= binlog_save_options; - + + thd->restore_active_arena(&call_arena, &backup_arena); + if (need_binlog_call) mysql_bin_log.stop_union_events(thd); if (need_binlog_call && thd->binlog_evt_union.unioned_events) { - char buf[256]; - String bufstr(buf, sizeof(buf), &my_charset_bin); - bufstr.length(0); - bufstr.append(STRING_WITH_LEN("SELECT ")); - append_identifier(thd, &bufstr, m_name.str, m_name.length); - bufstr.append('('); - for (uint i=0; i < argcount; i++) - { - String str_value_holder; - String *str_value; - - if (i) - bufstr.append(','); - - str_value= sp_get_item_value(param_values[i], &str_value_holder); - - if (str_value) - bufstr.append(*str_value); - else - bufstr.append(STRING_WITH_LEN("NULL")); - } - bufstr.append(')'); - - Query_log_event qinfo(thd, bufstr.ptr(), bufstr.length(), + Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(), thd->binlog_evt_union.unioned_events_trans, FALSE); - if (mysql_bin_log.write(&qinfo) && + if (mysql_bin_log.write(&qinfo) && thd->binlog_evt_union.unioned_events_trans) { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, @@ -1353,8 +1367,13 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, } } + nctx->pop_all_cursors(); // To avoid memory leaks after an error + +err_with_cleanup: delete nctx; + call_arena.free_items(); + free_root(&call_mem_root, MYF(0)); thd->spcont= octx; DBUG_RETURN(err_status); From f4d209b015e2ac2143f73bef39c73732b38a4f1a Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 6 May 2006 13:57:56 +0400 Subject: [PATCH 07/41] Partial fix for BUG#14106: IM: im_life_cycle and im_utils tests fail on FreeBSD. The patch contains of the following: - make Instance Manager, running in the daemon mode, dump the pid of angel-process in the special file; - default value of angel-pid-file-name is 'mysqlmanager.angel.pid'; - if ordinary (IM) pid-file-name is specified in the configuration, angel-pid-file-name is updated according to the following rule: extension of the basename of pid-file-name is replaced by '.angel.pid. For example: - pid-file-name: /tmp/im.pid => angel-pid-file-name: /tmp/im.angel.pid - pid-file-name: /tmp/im.txt => angel-pid-file-name: /tmp/im.angel.pid - pid-file-name: /tmp/5.0/im => angel-pid-file-name: /tmp/5.0/im.angel.pid - add support for configuration option to customize angel pid file name; - fix test suite to use angel pid to kill Instance Manager by all means if something went wrong. Background ---------- The problem is that on some OSes (FreeBSD for one) Instance Manager does not get SIGTERM, so can not shutdown gracefully. Test suite wasn't able to cope with it, so this leads to the mess in test results. The problem should be split into two: - fix signal handling; - fix test suite. This patch fixes test suite so that it will be able to kill uncooperative Instance Manager. In order to achieve this, test suite needs to know PID of IM Angel process. mysql-test/lib/mtr_process.pl: Added a function to send a signal to a process. mysql-test/mysql-test-run.pl: Changed procedure of stopping Instance Manager. 1. Try to stop IM normally (by sending SIGTERM); 2. If one of IM-related processes is still alive, kill them all by SIGKILL and complain in the log. server-tools/instance-manager/manager.cc: Made create_pid_file() available for the whole project. server-tools/instance-manager/manager.h: Made create_pid_file() available for the whole project. server-tools/instance-manager/mysqlmanager.cc: Dump PID of angel process into file. server-tools/instance-manager/options.cc: Added an option to allow to customize angel pid file name. server-tools/instance-manager/options.h: Added an option to allow to customize angel pid file name. --- mysql-test/lib/mtr_process.pl | 20 +++++ mysql-test/mysql-test-run.pl | 86 ++++++++++++++++--- server-tools/instance-manager/manager.cc | 13 ++- server-tools/instance-manager/manager.h | 2 + server-tools/instance-manager/mysqlmanager.cc | 8 ++ server-tools/instance-manager/options.cc | 57 +++++++++++- server-tools/instance-manager/options.h | 1 + 7 files changed, 169 insertions(+), 18 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 973655a3eb6..6fa6bc73bdb 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -20,6 +20,7 @@ sub mtr_record_dead_children (); sub mtr_exit ($); sub sleep_until_file_created ($$$); sub mtr_kill_processes ($); +sub mtr_kill_process ($$$$); # static in C sub spawn_impl ($$$$$$$$); @@ -885,6 +886,25 @@ sub mtr_kill_processes ($) { } } + +sub mtr_kill_process ($$$$) { + my $pid= shift; + my $signal= shift; + my $retries= shift; + my $timeout= shift; + + while (1) + { + kill($signal, $pid); + + last unless kill (0, $pid) and $retries--; + + mtr_debug("Sleep $timeout second waiting for processes to die"); + + sleep($timeout); + } +} + ############################################################################## # # When we exit, we kill off all children diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3a5fa2e7287..7613e7f087c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -924,6 +924,7 @@ sub command_line_setup () { path_err => "$opt_vardir/log/im.err", path_log => "$opt_vardir/log/im.log", path_pid => "$opt_vardir/run/im.pid", + path_angel_pid => "$opt_vardir/run/im.angel.pid", path_sock => "$sockdir/im.sock", port => $im_port, start_timeout => $master->[0]->{'start_timeout'}, @@ -1179,6 +1180,7 @@ sub environment_setup () { $ENV{'NDB_STATUS_OK'}= "YES"; $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; + $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; $ENV{'IM_PORT'}= $instance_manager->{port}; $ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock}; @@ -1803,6 +1805,7 @@ sub im_create_defaults_file($) { [manager] pid-file = $instance_manager->{path_pid} +angel-pid-file = $instance_manager->{path_angel_pid} socket = $instance_manager->{path_sock} port = $instance_manager->{port} password-file = $instance_manager->{password_file} @@ -1827,7 +1830,7 @@ log-slow-queries = $instance->{path_datadir}/mysqld$server_id.slow.log language = $path_language character-sets-dir = $path_charsetsdir basedir = $path_my_basedir -server_id =$server_id +server_id = $server_id skip-stack-trace skip-innodb skip-bdb @@ -2786,6 +2789,18 @@ sub im_start($$) { sub im_stop($) { my $instance_manager = shift; + # Obtain mysqld-process pids before we start stopping IM (it can delete pid + # files). + + my @mysqld_pids = (); + my $instances = $instance_manager->{'instances'}; + + push(@mysqld_pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'})) + if -r $instances->[0]->{'path_pid'}; + + push(@mysqld_pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'})) + if -r $instances->[1]->{'path_pid'}; + # Re-read pid from the file, since during tests Instance Manager could have # been restarted, so its pid could have been changed. @@ -2793,34 +2808,79 @@ sub im_stop($) { mtr_get_pid_from_file($instance_manager->{'path_pid'}) if -f $instance_manager->{'path_pid'}; + if (-f $instance_manager->{'path_angel_pid'}) + { + $instance_manager->{'angel_pid'} = + mtr_get_pid_from_file($instance_manager->{'path_angel_pid'}) + } + else + { + $instance_manager->{'angel_pid'} = undef; + } + # Inspired from mtr_stop_mysqld_servers(). start_reap_all(); - # Create list of pids. We should stop Instance Manager and all started - # mysqld-instances. Some of them may be nonguarded, so IM will not stop them - # on shutdown. + # Try graceful shutdown. - my @pids = ( $instance_manager->{'pid'} ); - my $instances = $instance_manager->{'instances'}; + mtr_kill_process($instance_manager->{'pid'}, 'TERM', 10, 1); - if ( -r $instances->[0]->{'path_pid'} ) + # Check that all processes died. + + my $clean_shutdown= 0; + + while (1) { - push(@pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'})); + last if kill (0, $instance_manager->{'pid'}); + + last if (defined $instance_manager->{'angel_pid'}) && + kill (0, $instance_manager->{'angel_pid'}); + + foreach my $pid (@mysqld_pids) + { + last if kill (0, $pid); + } + + $clean_shutdown= 1; + last; } - if ( -r $instances->[1]->{'path_pid'} ) + # Kill leftovers (the order is important). + + unless ($clean_shutdown) { - push(@pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'})); + mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1) + if defined $instance_manager->{'angel_pid'}; + + mtr_kill_process($instance_manager->{'pid'}, 'KILL', 10, 1); + + # Shutdown managed mysqld-processes. Some of them may be nonguarded, so IM + # will not stop them on shutdown. So, we should firstly try to end them + # legally. + + mtr_kill_processes(\@mysqld_pids); + + # Complain in error log so that a warning will be shown. + + my $errlog= "$opt_vardir/log/mysql-test-run.pl.err"; + + open (ERRLOG, ">>$errlog") || + mtr_error("Can not open error log ($errlog)"); + + my $ts= localtime(); + print ERRLOG + "Warning: [$ts] Instance Manager did not shutdown gracefully.\n"; + + close ERRLOG; } - # Kill processes. - - mtr_kill_processes(\@pids); + # That's all. stop_reap_all(); $instance_manager->{'pid'} = undef; + $instance_manager->{'angel_pid'} = undef; } diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index 95f9029f648..90d9d04cd36 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -35,12 +35,12 @@ #endif -static int create_pid_file(const char *pid_file_name) +int create_pid_file(const char *pid_file_name, int pid) { if (FILE *pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY, MYF(0))) { - fprintf(pid_file, "%d\n", (int) getpid()); + fprintf(pid_file, "%d\n", (int) pid); my_fclose(pid_file, MYF(0)); return 0; } @@ -138,8 +138,13 @@ void manager(const Options &options) if (user_map.load(options.password_file_name)) return; - /* write pid file */ - if (create_pid_file(options.pid_file_name)) + /* write Instance Manager pid file */ + + log_info("IM pid file: '%s'; PID: %d.", + (const char *) options.pid_file_name, + (int) manager_pid); + + if (create_pid_file(options.pid_file_name, manager_pid)) return; sigset_t mask; diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h index 12ed6b3b1ff..3ddf292132e 100644 --- a/server-tools/instance-manager/manager.h +++ b/server-tools/instance-manager/manager.h @@ -20,4 +20,6 @@ struct Options; void manager(const Options &options); +int create_pid_file(const char *pid_file_name, int pid); + #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index d0b2cf2666c..ef714099de7 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -338,6 +338,14 @@ spawn: /* Here we return to main, and fall into manager */ break; default: // parent, success + pid= getpid(); /* Get our pid. */ + + log_info("Angel pid file: '%s'; PID: %d.", + (const char *) options.angel_pid_file_name, + (int) pid); + + create_pid_file(Options::angel_pid_file_name, pid); + while (child_status == CHILD_OK && is_terminated == 0) sigsuspend(&zeromask); diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index e7d366e7457..4d71680e061 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -44,6 +44,7 @@ const char *Options::user= 0; /* No default value */ const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE); +const char *Options::angel_pid_file_name= NULL; #endif const char *Options::log_file_name= default_log_file_name; const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); @@ -58,6 +59,9 @@ char **Options::saved_argv= NULL; /* Remember if the config file was forced */ bool Options::is_forced_default_file= 0; +static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid"; +static const int ANGEL_PID_FILE_SUFFIX_LEN= strlen(ANGEL_PID_FILE_SUFFIX); + /* List of options, accepted by the instance manager. List must be closed with empty option. @@ -72,6 +76,7 @@ enum options { #ifndef __WIN__ OPT_RUN_AS_SERVICE, OPT_USER, + OPT_ANGEL_PID_FILE, #else OPT_INSTALL_SERVICE, OPT_REMOVE_SERVICE, @@ -94,7 +99,14 @@ static struct my_option my_long_options[] = { "pid-file", OPT_PID_FILE, "Pid file to use.", (gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + +#ifndef __WIN__ + { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.", + (gptr *) &Options::angel_pid_file_name, + (gptr *) &Options::angel_pid_file_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, +#endif { "socket", OPT_SOCKET, "Socket file to use for connection.", (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name, @@ -290,6 +302,46 @@ int Options::load(int argc, char **argv) get_one_option)) != 0) goto err; +#ifndef __WIN__ + if (Options::run_as_service) + { + if (Options::angel_pid_file_name == NULL) + { + /* + Calculate angel pid file on the IM pid file basis: replace the + extension (everything after the last dot) of the pid file basename to + '.angel.pid'. + */ + + char *angel_pid_file_name; + char *base_name_ptr; + char *ext_ptr; + + angel_pid_file_name= (char *) malloc(strlen(Options::pid_file_name) + + ANGEL_PID_FILE_SUFFIX_LEN); + + strcpy(angel_pid_file_name, Options::pid_file_name); + + base_name_ptr= strrchr(angel_pid_file_name, '/'); + + if (!base_name_ptr) + base_name_ptr= angel_pid_file_name + 1; + + ext_ptr= strrchr(base_name_ptr, '.'); + if (ext_ptr) + *ext_ptr= 0; + + strcat(angel_pid_file_name, ANGEL_PID_FILE_SUFFIX); + + Options::angel_pid_file_name= angel_pid_file_name; + } + else + { + Options::angel_pid_file_name= strdup(Options::angel_pid_file_name); + } + } +#endif + return 0; err: @@ -301,6 +353,9 @@ void Options::cleanup() /* free_defaults returns nothing */ if (Options::saved_argv != NULL) free_defaults(Options::saved_argv); + + if (Options::run_as_service) + free((void *) Options::angel_pid_file_name); } #ifdef __WIN__ diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h index abb094eac93..ad3458869b6 100644 --- a/server-tools/instance-manager/options.h +++ b/server-tools/instance-manager/options.h @@ -35,6 +35,7 @@ struct Options #else static char run_as_service; /* handle_options doesn't support bool */ static const char *user; + static const char *angel_pid_file_name; #endif static bool is_forced_default_file; static const char *log_file_name; From 4f15a043e2637d67e2c882a7fd8514ef1c4c0eb7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 May 2006 16:39:11 +0400 Subject: [PATCH 08/41] Fix for bugs#12472/#15137 'CREATE TABLE ... SELECT ... which explicitly or implicitly uses stored function gives "Table not locked" error' CREATE TABLE ... SELECT ... statement which was explicitly or implicitly (through view) using stored function gave "Table not locked" error. The actual bug resides in the current locking scheme of CREATE TABLE SELECT code, which first opens and locks tables of the SELECT statement itself, and then, having SELECT tables locked, creates the .FRM, opens the .FRM and acquires lock on it. This scheme opens a possibility for a deadlock, which was present and ignored since version 3.23 or earlier. This scheme also conflicts with the invariant of the prelocking algorithm -- no table can be open and locked while there are tables locked in prelocked mode. The patch makes an exception for this invariant when doing CREATE TABLE ... SELECT, thus extending the possibility of a deadlock to the prelocked mode. We can't supply a better fix in 5.0. mysql-test/r/sp.result: Added tests for bugs#12472/#15137 'CREATE TABLE ... SELECT ... which explicitly or implicitly uses stored function gives "Table not locked" error' mysql-test/t/sp.test: Added tests for bugs#12472/#15137 'CREATE TABLE ... SELECT ... which explicitly or implicitly uses stored function gives "Table not locked" error' sql/mysql_priv.h: Added flag which can be passed to open_table() routine in order to ignore set of locked tables and prelocked mode. We don't need declaration of create_table_from_items() any longer as it was moved into sql_insert.cc and made static. sql/sql_base.cc: open_table(): Added flag which allows open table ignoring set of locked tables and prelocked mode. sql/sql_insert.cc: Moved create_table_from_items() from sql_table.cc to sql_insert.cc as it was not used outside of sql_insert.cc and contains code which is specific for CREATE TABLE ... SELECT. Also now when we are executing CREATE TABLE ... SELECT ... statement which SELECT part requires execution in prelocked mode we ignore set of locked tables in order to get access to the table we just have created. We probably don't want to do this if we are under real LOCK TABLES since it will widen window for deadlock too much. sql/sql_table.cc: Moved create_table_from_items() routine into sql_insert.cc, since it was not used anywhere outside of this file and contains logic which is specific for CREATE TABLE ... SELECT statement. --- mysql-test/r/sp.result | 25 +++++++ mysql-test/t/sp.test | 23 +++++++ sql/mysql_priv.h | 9 +-- sql/sql_base.cc | 5 +- sql/sql_insert.cc | 147 +++++++++++++++++++++++++++++++++++++++++ sql/sql_table.cc | 99 --------------------------- 6 files changed, 201 insertions(+), 107 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 3e139f8cce5..9dbaf228c95 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4837,4 +4837,29 @@ c 2 b 3 a 1 delete from t1| +drop function if exists bug12472| +create function bug12472() returns int return (select count(*) from t1)| +create table t3 as select bug12472() as i| +show create table t3| +Table Create Table +t3 CREATE TABLE `t3` ( + `i` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t3| +i +0 +drop table t3| +create view v1 as select bug12472() as j| +create table t3 as select * from v1| +show create table t3| +Table Create Table +t3 CREATE TABLE `t3` ( + `j` bigint(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t3| +j +0 +drop table t3| +drop view v1| +drop function bug12472| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 9e1afa53149..515893ed982 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5683,6 +5683,29 @@ select * from t1 order by @x| delete from t1| +# +# BUG#12472/BUG#15137 'CREATE TABLE ... SELECT ... which explicitly or +# implicitly uses stored function gives "Table not locked" error'. +# +--disable_warnings +drop function if exists bug12472| +--enable_warnings +create function bug12472() returns int return (select count(*) from t1)| +# Check case when function is used directly +create table t3 as select bug12472() as i| +show create table t3| +select * from t3| +drop table t3| +# Check case when function is used indirectly through view +create view v1 as select bug12472() as j| +create table t3 as select * from v1| +show create table t3| +select * from t3| +drop table t3| +drop view v1| +drop function bug12472| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ca7801039c5..3f71ee97242 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -718,12 +718,6 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, List &fields, List &keys, bool tmp_table, uint select_field_count); -TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, - TABLE_LIST *create_table, - List *extra_fields, - List *keys, - List *items, - MYSQL_LOCK **lock); bool mysql_alter_table(THD *thd, char *new_db, char *new_name, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, @@ -1312,10 +1306,11 @@ extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags, bool *need_reopen); -/* mysql_lock_tables() flags bits */ +/* mysql_lock_tables() and open_table() flags bits */ #define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001 #define MYSQL_LOCK_IGNORE_FLUSH 0x0002 #define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004 +#define MYSQL_OPEN_IGNORE_LOCKED_TABLES 0x0008 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2b5a3d1f38d..5c8be2b2537 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1076,6 +1076,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) MYSQL_LOCK_IGNORE_FLUSH - Open table even if someone has done a flush or namelock on it. No version number checking is done. + MYSQL_OPEN_IGNORE_LOCKED_TABLES - Open table + ignoring set of locked tables and prelocked mode. IMPLEMENTATION Uses a cache of open tables to find a table not in use. @@ -1135,7 +1137,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, } } - if (thd->locked_tables || thd->prelocked_mode) + if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) && + (thd->locked_tables || thd->prelocked_mode)) { // Using table locks TABLE *best_table= 0; int best_distance= INT_MIN; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ad9606acb83..c157025fbdc 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2434,6 +2434,153 @@ bool select_insert::send_eof() CREATE TABLE (SELECT) ... ***************************************************************************/ +/* + Create table from lists of fields and items (or open existing table + with same name). + + SYNOPSIS + create_table_from_items() + thd in Thread object + create_info in Create information (like MAX_ROWS, ENGINE or + temporary table flag) + create_table in Pointer to TABLE_LIST object providing database + and name for table to be created or to be open + extra_fields in/out Initial list of fields for table to be created + keys in List of keys for table to be created + items in List of items which should be used to produce rest + of fields for the table (corresponding fields will + be added to the end of 'extra_fields' list) + lock out Pointer to the MYSQL_LOCK object for table created + (open) will be returned in this parameter. Since + this table is not included in THD::lock caller is + responsible for explicitly unlocking this table. + + NOTES + If 'create_info->options' bitmask has HA_LEX_CREATE_IF_NOT_EXISTS + flag and table with name provided already exists then this function will + simply open existing table. + Also note that create, open and lock sequence in this function is not + atomic and thus contains gap for deadlock and can cause other troubles. + Since this function contains some logic specific to CREATE TABLE ... SELECT + it should be changed before it can be used in other contexts. + + RETURN VALUES + non-zero Pointer to TABLE object for table created or opened + 0 Error +*/ + +static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, + TABLE_LIST *create_table, + List *extra_fields, + List *keys, List *items, + MYSQL_LOCK **lock) +{ + TABLE tmp_table; // Used during 'create_field()' + TABLE *table= 0; + uint select_field_count= items->elements; + /* Add selected items to field list */ + List_iterator_fast it(*items); + Item *item; + Field *tmp_field; + bool not_used; + DBUG_ENTER("create_table_from_items"); + + tmp_table.alias= 0; + tmp_table.timestamp_field= 0; + tmp_table.s= &tmp_table.share_not_to_be_used; + tmp_table.s->db_create_options=0; + tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; + tmp_table.s->db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM || + create_info->db_type == DB_TYPE_HEAP); + tmp_table.null_row=tmp_table.maybe_null=0; + + while ((item=it++)) + { + create_field *cr_field; + Field *field; + if (item->type() == Item::FUNC_ITEM) + field=item->tmp_table_field(&tmp_table); + else + field=create_tmp_field(thd, &tmp_table, item, item->type(), + (Item ***) 0, &tmp_field, 0, 0, 0, 0, 0); + if (!field || + !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? + ((Item_field *)item)->field : + (Field*) 0)))) + DBUG_RETURN(0); + if (item->maybe_null) + cr_field->flags &= ~NOT_NULL_FLAG; + extra_fields->push_back(cr_field); + } + /* + create and lock table + + We don't log the statement, it will be logged later. + + If this is a HEAP table, the automatic DELETE FROM which is written to the + binlog when a HEAP table is opened for the first time since startup, must + not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we + don't want to delete from it) 2) it would be written before the CREATE + TABLE, which is a wrong order. So we keep binary logging disabled when we + open_table(). + NOTE: By locking table which we just have created (or for which we just have + have found that it already exists) separately from other tables used by the + statement we create potential window for deadlock. + TODO: create and open should be done atomic ! + */ + { + tmp_disable_binlog(thd); + if (!mysql_create_table(thd, create_table->db, create_table->table_name, + create_info, *extra_fields, *keys, 0, + select_field_count)) + { + /* + If we are here in prelocked mode we either create temporary table + or prelocked mode is caused by the SELECT part of this statement. + */ + DBUG_ASSERT(!thd->prelocked_mode || + create_info->options & HA_LEX_CREATE_TMP_TABLE || + thd->lex->requires_prelocking()); + + /* + NOTE: We don't want to ignore set of locked tables here if we are + under explicit LOCK TABLES since it will open gap for deadlock + too wide (and also is not backward compatible). + */ + if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0, + (MYSQL_LOCK_IGNORE_FLUSH | + ((thd->prelocked_mode == PRELOCKED) ? + MYSQL_OPEN_IGNORE_LOCKED_TABLES:0))))) + quick_rm_table(create_info->db_type, create_table->db, + table_case_name(create_info, create_table->table_name)); + } + reenable_binlog(thd); + if (!table) // open failed + DBUG_RETURN(0); + } + + /* + FIXME: What happens if trigger manages to be created while we are + obtaining this lock ? May be it is sensible just to disable + trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH + save us from that ? + */ + table->reginfo.lock_type=TL_WRITE; + if (! ((*lock)= mysql_lock_tables(thd, &table, 1, + MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) + { + VOID(pthread_mutex_lock(&LOCK_open)); + hash_delete(&open_cache,(byte*) table); + VOID(pthread_mutex_unlock(&LOCK_open)); + quick_rm_table(create_info->db_type, create_table->db, + table_case_name(create_info, create_table->table_name)); + DBUG_RETURN(0); + } + table->file->extra(HA_EXTRA_WRITE_CACHE); + DBUG_RETURN(table); +} + + int select_create::prepare(List &values, SELECT_LEX_UNIT *u) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cb556acd5c7..d5bcc131a70 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1760,105 +1760,6 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end) } -/**************************************************************************** -** Create table from a list of fields and items -****************************************************************************/ - -TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, - TABLE_LIST *create_table, - List *extra_fields, - List *keys, - List *items, - MYSQL_LOCK **lock) -{ - TABLE tmp_table; // Used during 'create_field()' - TABLE *table= 0; - uint select_field_count= items->elements; - /* Add selected items to field list */ - List_iterator_fast it(*items); - Item *item; - Field *tmp_field; - bool not_used; - DBUG_ENTER("create_table_from_items"); - - tmp_table.alias= 0; - tmp_table.timestamp_field= 0; - tmp_table.s= &tmp_table.share_not_to_be_used; - tmp_table.s->db_create_options=0; - tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; - tmp_table.s->db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM || - create_info->db_type == DB_TYPE_HEAP); - tmp_table.null_row=tmp_table.maybe_null=0; - - while ((item=it++)) - { - create_field *cr_field; - Field *field; - if (item->type() == Item::FUNC_ITEM) - field=item->tmp_table_field(&tmp_table); - else - field=create_tmp_field(thd, &tmp_table, item, item->type(), - (Item ***) 0, &tmp_field, 0, 0, 0, 0, 0); - if (!field || - !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? - ((Item_field *)item)->field : - (Field*) 0)))) - DBUG_RETURN(0); - if (item->maybe_null) - cr_field->flags &= ~NOT_NULL_FLAG; - extra_fields->push_back(cr_field); - } - /* - create and lock table - - We don't log the statement, it will be logged later. - - If this is a HEAP table, the automatic DELETE FROM which is written to the - binlog when a HEAP table is opened for the first time since startup, must - not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we - don't want to delete from it) 2) it would be written before the CREATE - TABLE, which is a wrong order. So we keep binary logging disabled when we - open_table(). - TODO: create and open should be done atomic ! - */ - { - tmp_disable_binlog(thd); - if (!mysql_create_table(thd, create_table->db, create_table->table_name, - create_info, *extra_fields, *keys, 0, - select_field_count)) - { - if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0, - MYSQL_LOCK_IGNORE_FLUSH))) - quick_rm_table(create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name)); - } - reenable_binlog(thd); - if (!table) // open failed - DBUG_RETURN(0); - } - - /* - FIXME: What happens if trigger manages to be created while we are - obtaining this lock ? May be it is sensible just to disable - trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH - save us from that ? - */ - table->reginfo.lock_type=TL_WRITE; - if (! ((*lock)= mysql_lock_tables(thd, &table, 1, - MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) - { - VOID(pthread_mutex_lock(&LOCK_open)); - hash_delete(&open_cache,(byte*) table); - VOID(pthread_mutex_unlock(&LOCK_open)); - quick_rm_table(create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name)); - DBUG_RETURN(0); - } - table->file->extra(HA_EXTRA_WRITE_CACHE); - DBUG_RETURN(table); -} - - /**************************************************************************** ** Alter a table definition ****************************************************************************/ From c23c38fa31ff9f7350c342a3fb8142e04b10e121 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 May 2006 23:01:31 +0300 Subject: [PATCH 09/41] BUG#14157: utf8 encoding in binlog without set character_set_client e.g DROP temporary Binlog lacks encoding info about DROPped temporary table. Idea of the fix is to switch temporary to system_charset_info when a temporary table is DROPped for binlog. Since that is the server, that automatically, but not the client, who generates the query the binlog should be updated on the server's encoding for the coming DROP. The `write_binlog_with_system_charset()' is introduced to replace similar problematic places in the code. mysql-test/r/drop_temp_table.result: results changed mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/mysqlbinlog.result: results changed mysql-test/r/rpl_temporary.result: results changed mysql-test/t/mysqlbinlog.test: Check roll-forward recovery from binlog where there are DROP temporary tables created in koi8r. mysql-test/t/rpl_temporary.test: Check slave digests binlog with DROP temporary tables created in koi8r. sql/mysql_priv.h: `write_binlog_with_system_charset()' is added to be called when a binlog event is created "implicitly" like DROP temporary table is case of closing connection. sql/sql_base.cc: Idea of the fix is to switch temporary to system_charset_info when a temporary table is DROPped for binlog. Since that is the server, not the client, who generates the query the binlog should be updated on server's encoding for the coming DROP. --- mysql-test/r/drop_temp_table.result | 1 + mysql-test/r/mix_innodb_myisam_binlog.result | 5 +++-- mysql-test/r/mysqlbinlog.result | 7 ++++++- mysql-test/r/rpl_temporary.result | 4 ++++ mysql-test/t/mysqlbinlog.test | 11 ++++++++++- mysql-test/t/rpl_temporary.test | 12 ++++++++++++ sql/mysql_priv.h | 7 +++++++ sql/sql_base.cc | 2 +- 8 files changed, 44 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result index 5f1f142cde5..40afd621676 100644 --- a/mysql-test/r/drop_temp_table.result +++ b/mysql-test/r/drop_temp_table.result @@ -17,6 +17,7 @@ master-bin.000001 # Query 1 # create database `drop-temp+table-test` master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn1 (a int) master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int) master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int) +master-bin.000001 # Query 1 # use `drop-temp+table-test`; SET ONE_SHOT CHARACTER_SET_CLIENT=33,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=8 master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`,`drop-temp+table-test`.`table:name`,`drop-temp+table-test`.`shortn1` master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a") drop database `drop-temp+table-test`; diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index e9613bac833..8cf99e8d623 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -249,7 +249,8 @@ master-bin.000001 1056 Query 1 1056 use `test`; insert t0 select * from t1 master-bin.000001 1117 Query 1 1117 use `test`; DO RELEASE_LOCK("a") master-bin.000001 1172 Query 1 1172 use `test`; insert into t0 select GET_LOCK("lock1",null) master-bin.000001 1251 Query 1 1251 use `test`; create table t2 (n int) engine=innodb -master-bin.000001 1323 Query 1 1323 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` -master-bin.000001 1424 Query 1 1424 use `test`; DO RELEASE_LOCK("lock1") +master-bin.000001 1323 Query 1 1323 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=33,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=8 +master-bin.000001 1457 Query 1 1457 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` +master-bin.000001 1558 Query 1 1558 use `test`; DO RELEASE_LOCK("lock1") do release_lock("lock1"); drop table t0,t2; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index adaf0dad56b..bade0ca9b46 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -101,4 +101,9 @@ HEX(f) select HEX(f) from t4; HEX(f) 835C -drop table t1, t2, t03, t04, t3, t4; +flush logs; +select * from t5 /* must be (1),(1) */; +a +1 +1 +drop table t1, t2, t03, t04, t3, t4, t5; diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index cd67d2592a8..8c6d3f232b1 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -103,3 +103,7 @@ select * from t1 /* must be 1 */; f 1 drop table t1; +select * from t1; +a +1 +drop table t1; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 871886331f6..11aa5814bda 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -114,8 +114,17 @@ select HEX(f) from t3; select HEX(f) from t04; select HEX(f) from t4; +# +#14157: utf8 encoding in binlog without set character_set_client +# +flush logs; +--exec $MYSQL --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' + +# resulted log is client charset insensitive (latin1 not koi8r) as it must be +--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 +select * from t5 /* must be (1),(1) */; # clean up -drop table t1, t2, t03, t04, t3, t4; +drop table t1, t2, t03, t04, t3, t4, t5; # End of 4.1 tests diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 71d7b32b7c9..af952760d6b 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -156,4 +156,16 @@ select * from t1 /* must be 1 */; connection master; drop table t1; +# +#14157: utf8 encoding in binlog without set character_set_client +# +--exec $MYSQL --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' + +sync_slave_with_master; +#connection slave; +select * from t1; + +connection master; +drop table t1; + # End of 4.1 tests diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6676d994cfa..aab65bca82f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1275,6 +1275,13 @@ inline int hexchar_to_int(char c) return -1; } +inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo) +{ + CHARSET_INFO * cs_save= thd->variables.character_set_client; + thd->variables.character_set_client= system_charset_info; + mysql_bin_log.write(qinfo); + thd->variables.character_set_client= cs_save; +} /* Some functions that are different in the embedded library and the normal diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 60e91aff3f9..6365b8c8e40 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -615,7 +615,7 @@ void close_temporary_tables(THD *thd) rightfully causing the slave to stop. */ qinfo.error_code= 0; - mysql_bin_log.write(&qinfo); + write_binlog_with_system_charset(thd, &qinfo); } else { From 82727c62cf11b2a49c512f2612043f899514eaff Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 May 2006 14:12:32 +0400 Subject: [PATCH 10/41] Follow-up for the patch for bugs #12472/#15137 "CREATE TABLE ... SELECT ... which explicitly or implicitly uses stored function gives 'Table not locked' error" Test case for these bugs crashed in --ps-protocol mode. The crash was caused by incorrect usage of check_grant() routine from create_table_precheck() routine. The former assumes that either number of tables to be inspected by it is limited explicitly (i.e. is is not UINT_MAX) or table list used and thd->lex->query_tables_own_last value correspond to each other. create_table_precheck() was not fulfilling this condition and crash happened. The fix simply sets number of tables to be inspected by check_grant() to 1. sql/sql_parse.cc: create_table_precheck(): At the moment when create_table_precheck() is called TABLE_LIST element representing table to be created does not belong to global table list therefore we should limit number of tables to be inspected by check_grant() explicitly (as in this case table list passed to this function does not correspond to thd->lex->query_tables_own_last value). --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 649714315a6..abc945647bd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7227,7 +7227,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, lex->create_info.merge_list.first)) goto err; if (grant_option && want_priv != CREATE_TMP_ACL && - check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) + check_grant(thd, want_priv, create_table, 0, 1, 0)) goto err; if (select_lex->item_list.elements) From f76e0def2d843c0826e6e25fdf0d35311631b64a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 May 2006 14:34:03 +0400 Subject: [PATCH 11/41] Commit forgotten changes for BUG#14106. mysql-test/r/im_options_set.result: Fixed result file. mysql-test/r/im_options_unset.result: Fixed result file. --- mysql-test/r/im_options_set.result | 6 +++--- mysql-test/r/im_options_unset.result | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/im_options_set.result b/mysql-test/r/im_options_set.result index 0d2fa699fc7..5e6c740624e 100644 --- a/mysql-test/r/im_options_set.result +++ b/mysql-test/r/im_options_set.result @@ -1,11 +1,11 @@ -server_id =1 -server_id =2 +server_id = 1 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 SET mysqld1.server_id = 11; server_id =11 -server_id =2 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 diff --git a/mysql-test/r/im_options_unset.result b/mysql-test/r/im_options_unset.result index 834152c35d2..bf54025edb7 100644 --- a/mysql-test/r/im_options_unset.result +++ b/mysql-test/r/im_options_unset.result @@ -1,10 +1,10 @@ -server_id =1 -server_id =2 +server_id = 1 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 UNSET mysqld1.server_id; -server_id =2 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 From 38447ae81ad2fc08f654fd4a759c6446f31f2026 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 May 2006 18:53:28 +0400 Subject: [PATCH 12/41] Make it compilable on Windows. --- server-tools/instance-manager/options.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index 4d71680e061..a98c0e291be 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -354,8 +354,10 @@ void Options::cleanup() if (Options::saved_argv != NULL) free_defaults(Options::saved_argv); +#ifndef __WIN__ if (Options::run_as_service) free((void *) Options::angel_pid_file_name); +#endif } #ifdef __WIN__ From 24a0b385fb48f3d4ace7df12d7115c80d3f4b0be Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 May 2006 23:16:30 +0400 Subject: [PATCH 13/41] Fix for BUG#18587: Function that accepts and returns TEXT garbles data if longer than 766 chars. The problem is that a stored routine returns BLOBs to the previous caller, BLOBs are shallow-copied (i.e. only pointers to the data are copied). The fix is to also copy data of BLOBs. mysql-test/r/sp.result: Updated result file. mysql-test/t/sp.test: Added a test case for BUG#18587. sql/field_conv.cc: Do not jump to optimization if the field type is BLOB and the destination table requires copying of BLOBs. sql/item_func.cc: Request copying BLOBs for the result table. --- mysql-test/r/sp.result | 31 ++++++++++++++++++++++++++++ mysql-test/t/sp.test | 47 ++++++++++++++++++++++++++++++++++++++++++ sql/field_conv.cc | 3 ++- sql/item_func.cc | 1 + 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 0751363a6ea..746cd8f00d4 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4929,4 +4929,35 @@ j drop table t3| drop view v1| drop function bug12472| +DROP FUNCTION IF EXISTS bug18589_f1| +DROP PROCEDURE IF EXISTS bug18589_p1| +DROP PROCEDURE IF EXISTS bug18589_p2| +CREATE FUNCTION bug18589_f1(arg TEXT) RETURNS TEXT +BEGIN +RETURN CONCAT(arg, ""); +END| +CREATE PROCEDURE bug18589_p1(arg TEXT, OUT ret TEXT) +BEGIN +SET ret = CONCAT(arg, ""); +END| +CREATE PROCEDURE bug18589_p2(arg TEXT) +BEGIN +DECLARE v TEXT; +CALL bug18589_p1(arg, v); +SELECT v; +END| +SELECT bug18589_f1(REPEAT("a", 767))| +bug18589_f1(REPEAT("a", 767)) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +SET @bug18589_v1 = ""| +CALL bug18589_p1(REPEAT("a", 767), @bug18589_v1)| +SELECT @bug18589_v1| +@bug18589_v1 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +CALL bug18589_p2(REPEAT("a", 767))| +v +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +DROP FUNCTION bug18589_f1| +DROP PROCEDURE bug18589_p1| +DROP PROCEDURE bug18589_p2| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index a5c3e60b9ca..9995ff5a9ad 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5796,6 +5796,53 @@ drop view v1| drop function bug12472| +# +# BUG#18587: Function that accepts and returns TEXT garbles data if longer than +# 766 chars +# + +# Prepare. + +--disable_warnings +DROP FUNCTION IF EXISTS bug18589_f1| +DROP PROCEDURE IF EXISTS bug18589_p1| +DROP PROCEDURE IF EXISTS bug18589_p2| +--enable_warnings + +CREATE FUNCTION bug18589_f1(arg TEXT) RETURNS TEXT +BEGIN + RETURN CONCAT(arg, ""); +END| + +CREATE PROCEDURE bug18589_p1(arg TEXT, OUT ret TEXT) +BEGIN + SET ret = CONCAT(arg, ""); +END| + +CREATE PROCEDURE bug18589_p2(arg TEXT) +BEGIN + DECLARE v TEXT; + CALL bug18589_p1(arg, v); + SELECT v; +END| + +# Test case. + +SELECT bug18589_f1(REPEAT("a", 767))| + +SET @bug18589_v1 = ""| +CALL bug18589_p1(REPEAT("a", 767), @bug18589_v1)| +SELECT @bug18589_v1| + +CALL bug18589_p2(REPEAT("a", 767))| + +# Cleanup. + +DROP FUNCTION bug18589_f1| +DROP PROCEDURE bug18589_p1| +DROP PROCEDURE bug18589_p2| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 895f022624c..4e977c06180 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -642,7 +642,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) void field_conv(Field *to,Field *from) { - if (to->real_type() == from->real_type()) + if (to->real_type() == from->real_type() && + !(to->type() == FIELD_TYPE_BLOB && to->table->copy_blobs)) { if (to->pack_length() == from->pack_length() && !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && diff --git a/sql/item_func.cc b/sql/item_func.cc index 0447ab115ec..603a00947dd 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4735,6 +4735,7 @@ Item_func_sp::sp_result_field(void) const dummy_table->alias = empty_name; dummy_table->maybe_null = maybe_null; dummy_table->in_use= current_thd; + dummy_table->copy_blobs= TRUE; share->table_cache_key = empty_name; share->table_name = empty_name; } From aeaaa45626fe0d0605f78660e2ae47cb91e26c14 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 May 2006 15:30:54 +0300 Subject: [PATCH 14/41] BUG#7549: Missing error message for invalid view selection with subquery. When a view statement is compiled on CREATE VIEW time, most of the optimizations should not be done. Finding the right optimization for a subquery is one of them. Unfortunately the optimizer is resolving the column references of the left expression of IN subqueries in the process of deciding witch optimization to use (if needed). So there should be a special case in Item_in_subselect::fix_fields() : check the validity of the left expression of IN subqueries in CREATE VIEW mode and then proceed as normal. mysql-test/r/subselect.result: test case mysql-test/r/view.result: chnaged explain due to column being resolved mysql-test/t/subselect.test: test case sql/item_subselect.cc: overloaded fix_fields to fix the left_expr in prepare_view_mode sql/item_subselect.h: fix_fields overloaded so it can prepare left_expr --- mysql-test/r/subselect.result | 8 ++++++++ mysql-test/r/view.result | 2 +- mysql-test/t/subselect.test | 15 +++++++++++++++ sql/item_subselect.cc | 11 +++++++++++ sql/item_subselect.h | 1 + 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 14b05238e14..09ddb4937b0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3169,3 +3169,11 @@ create table t2 (a int, b int); insert into t2 values (2, 1), (1, 0); delete from t1 where c <= 1140006215 and (select b from t2 where a = 2) = 1; drop table t1, t2; +CREATE TABLE t1 (a INT); +CREATE VIEW v1 AS SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'where clause' +CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'where clause' +SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'IN/ALL/ANY subquery' +DROP TABLE t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 667d10cd145..a89b6e9b3b1 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -706,7 +706,7 @@ create view v1 as select a from t1; create view v2 as select a from t2 where a in (select a from v1); show create view v2; View Create View -v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where `a` in (select `v1`.`a` AS `a` from `v1`) +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where `t2`.`a` in (select `v1`.`a` AS `a` from `v1`) drop view v2, v1; drop table t1, t2; CREATE VIEW `v 1` AS select 5 AS `5`; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1ef80bdd7ac..9f4d89a7e50 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2085,3 +2085,18 @@ create table t2 (a int, b int); insert into t2 values (2, 1), (1, 0); delete from t1 where c <= 1140006215 and (select b from t2 where a = 2) = 1; drop table t1, t2; + +# +# Bug #7549: Missing error message for invalid view selection with subquery +# + +CREATE TABLE t1 (a INT); + +--error 1054 +CREATE VIEW v1 AS SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +--error 1054 +CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1); +--error 1054 +SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); + +DROP TABLE t1; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d93f6501ebb..4b304725927 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1351,6 +1351,17 @@ void Item_in_subselect::print(String *str) } +bool Item_in_subselect::fix_fields(THD *thd, Item **ref) +{ + bool result = 0; + + if(thd->lex->view_prepare_mode && left_expr && !left_expr->fixed) + result = left_expr->fix_fields(thd, &left_expr); + + return result || Item_subselect::fix_fields(thd, ref); +} + + Item_subselect::trans_res Item_allany_subselect::select_transformer(JOIN *join) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index a4dac5bda87..293408dc09e 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -258,6 +258,7 @@ public: void top_level_item() { abort_on_null=1; } bool test_limit(st_select_lex_unit *unit); void print(String *str); + bool fix_fields(THD *thd, Item **ref); friend class Item_ref_null_helper; friend class Item_is_not_null_test; From 113b3f959e28a3156c987c3c049eafc751309519 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 May 2006 16:29:02 +0200 Subject: [PATCH 15/41] Bug#15886 (Test: Timing issue in test "rpl_until"): Changed format for SHOW SLAVE STATUS to vertical output. mysql-test/r/rpl_until.result: Result change mysql-test/t/rpl_until.test: Changed format for SHOW SLAVE STATUS to vertical output --- mysql-test/r/rpl_until.result | 148 +++++++++++++++++++++++++++++++--- mysql-test/t/rpl_until.test | 8 +- 2 files changed, 140 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/rpl_until.result b/mysql-test/r/rpl_until.result index b584e04ed57..60b956785ba 100644 --- a/mysql-test/r/rpl_until.result +++ b/mysql-test/r/rpl_until.result @@ -29,9 +29,40 @@ n 2 3 4 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-bin.000001 319 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 319 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-bin.000001 +Until_Log_Pos 319 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; select * from t1; n @@ -39,23 +70,116 @@ n 2 3 4 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-no-such-bin.000001 291 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 319 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-no-such-bin.000001 +Until_Log_Pos 291 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; select * from t2; n 1 2 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 608 # Relay slave-relay-bin.000004 746 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 608 +Relay_Log_Space # +Until_Condition Relay +Until_Log_File slave-relay-bin.000004 +Until_Log_Pos 746 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave; stop slave; start slave until master_log_file='master-bin.000001', master_log_pos=776; -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 776 # Master master-bin.000001 776 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 776 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-bin.000001 +Until_Log_Pos 776 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until master_log_file='master-bin', master_log_pos=561; ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12; diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test index e0ecf981fea..c404ea7e58b 100644 --- a/mysql-test/t/rpl_until.test +++ b/mysql-test/t/rpl_until.test @@ -31,7 +31,7 @@ wait_for_slave_to_stop; select * from t1; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # this should fail right after start start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; @@ -41,7 +41,7 @@ sleep 2; wait_for_slave_to_stop; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # try replicate all until second insert to t2; start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; @@ -50,7 +50,7 @@ wait_for_slave_to_stop; select * from t2; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # clean up start slave; @@ -67,7 +67,7 @@ wait_for_slave_to_stop; # here the sql slave thread should be stopped --replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004 --replace_column 1 # 9 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS #testing various error conditions --error 1277 From c982af51dafecdef7238b5c9f2d02e74fc31f790 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 May 2006 19:48:57 +0200 Subject: [PATCH 16/41] configure.in: Stepped up to 4.0.28 configure.in: Stepped up to 4.0.28 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 0445f7a05e9..8dd224d0a87 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.27) +AM_INIT_AUTOMAKE(mysql, 4.0.28) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From afe2520ecfca0f3dac5280cb7b978af28dbc1097 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 13:55:21 +0400 Subject: [PATCH 17/41] Bug#14635: Accept NEW.x as INOUT parameters to stored procedures from within triggers Add support for passing NEW.x as INOUT and OUT parameters to stored procedures. Passing NEW.x as INOUT parameter requires SELECT and UPDATE privileges on that column, and passing it as OUT parameter requires only UPDATE privilege. mysql-test/r/sp-error.result: Update the result for new message. mysql-test/r/trigger-grant.result: Add result for bug#14635. mysql-test/r/trigger.result: Add result for bug#14635. mysql-test/t/trigger-grant.test: Add test case for bug#14635. mysql-test/t/trigger.test: Add test case for bug#14635. sql/item.cc: Add implementations of set_value() and set_required_privilege() methods of Settable_routine_parameter interface. Use Item_trigger_field::want_privilege instead of Item_trigger_field::access_type. Reset privileges on Item_trigger_field::cleanup(). sql/item.h: Add interface class Settable_routine_parameter and interface query method to Item class. Item_splocal and Item_trigger_field implement this interface. For Item_trigger_field: - add read_only attribute and is_read_only() method. - remove access_type and add original_privilege and want_privilege instead. - add set_value() method. - add reset_privilege() method. sql/item_func.cc: Add implementations of set_value() method of Settable_routine_parameter interface. sql/item_func.h: Item_func_get_user_var implements Settable_routine_parameter interface. sql/share/errmsg.txt: Update english ER_SP_NOT_VAR_ARG message. sql/sp_head.cc: Use Settable_routine_parameter interface for parameter update. sql/sql_yacc.yy: Set read_only and want_privilege members in Item_trigger_field appropriately. For NEW.x trigger variable used in left-hand-side of SET statement the latter is set to UPDATE_ACL, otherwise it is set to SELECT_ACL (but see Item_trigger_field::set_required_privilege(), where it may be updated to different value). --- mysql-test/r/sp-error.result | 4 +- mysql-test/r/trigger-grant.result | 84 +++++++++++++++ mysql-test/r/trigger.result | 56 ++++++++++ mysql-test/t/trigger-grant.test | 173 ++++++++++++++++++++++++++++++ mysql-test/t/trigger.test | 74 +++++++++++++ sql/item.cc | 29 ++++- sql/item.h | 101 +++++++++++++++-- sql/item_func.cc | 12 +++ sql/item_func.h | 12 ++- sql/share/errmsg.txt | 2 +- sql/sp_head.cc | 66 +++--------- sql/sql_yacc.yy | 14 ++- 12 files changed, 561 insertions(+), 66 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index a49b282ddb7..924963017eb 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -282,9 +282,9 @@ select @tmp_x, @tmp_y, @tmp_z| @tmp_x @tmp_y @tmp_z 42 45 87 call p(42, 43, @tmp_z)| -ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable +ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable or NEW pseudo-variable in BEFORE trigger call p(42, @tmp_y, 43)| -ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable +ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable or NEW pseudo-variable in BEFORE trigger drop procedure p| create procedure p() begin end| lock table t1 read| diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result index 87e5e11d779..f6384d479b7 100644 --- a/mysql-test/r/trigger-grant.result +++ b/mysql-test/r/trigger-grant.result @@ -310,3 +310,87 @@ SELECT @mysqltest_var; Hello, world! DROP USER mysqltest_u1@localhost; DROP DATABASE mysqltest_db1; +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +USE mysqltest_db1; +CREATE TABLE t1 (i1 INT); +CREATE TABLE t2 (i1 INT); +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; +GRANT EXECUTE, CREATE ROUTINE, SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT INSERT ON mysqltest_db1.* TO mysqltest_inv@localhost; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 3; +CREATE PROCEDURE p2(INOUT i INT) DETERMINISTIC NO SQL SET i = i * 5; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (7); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +INSERT INTO t2 VALUES (11); +ERROR 42000: SELECT,UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't2' +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +GRANT SELECT ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (13); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +INSERT INTO t2 VALUES (17); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't2' +REVOKE SELECT ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (19); +INSERT INTO t2 VALUES (23); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't2' +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +GRANT SELECT, UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (29); +INSERT INTO t2 VALUES (31); +REVOKE SELECT, UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +DROP PROCEDURE p2; +DROP PROCEDURE p1; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 37; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +INSERT INTO t1 VALUES (41); +DROP PROCEDURE p1; +CREATE PROCEDURE p1(IN i INT) DETERMINISTIC NO SQL SET @v1 = i + 43; +INSERT INTO t1 VALUES (47); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +DROP PROCEDURE p1; +CREATE PROCEDURE p1(INOUT i INT) DETERMINISTIC NO SQL SET i = i + 51; +INSERT INTO t1 VALUES (53); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +DROP PROCEDURE p1; +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t1_bi; +DROP USER mysqltest_inv@localhost; +DROP USER mysqltest_dfn@localhost; +DROP TABLE t2; +DROP TABLE t1; +DROP DATABASE mysqltest_db1; +USE test; +End of 5.0 tests. diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 881933929fe..8b4aba367fb 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1034,3 +1034,59 @@ SET @@sql_mode=@save_sql_mode; DROP TRIGGER t1_ai; DROP TRIGGER t1_au; DROP TABLE t1; +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +CREATE TABLE t1 (i1 INT); +INSERT INTO t1 VALUES (3); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET i1 = 5; +CREATE PROCEDURE p2(INOUT i1 INT) DETERMINISTIC NO SQL SET i1 = i1 * 7; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +BEGIN +CALL p1(NEW.i1); +CALL p2(NEW.i1); +END// +UPDATE t1 SET i1 = 11 WHERE i1 = 3; +DROP TRIGGER t1_bu; +DROP PROCEDURE p2; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (13); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 17; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +CALL p1(OLD.i1); +UPDATE t1 SET i1 = 19 WHERE i1 = 13; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (23); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 29; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +CALL p1(OLD.i1); +UPDATE t1 SET i1 = 31 WHERE i1 = 23; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (37); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 41; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW +CALL p1(NEW.i1); +UPDATE t1 SET i1 = 43 WHERE i1 = 37; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_au; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (47); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 49; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW +CALL p1(NEW.i1); +UPDATE t1 SET i1 = 51 WHERE i1 = 47; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_au; +DROP PROCEDURE p1; +SELECT * FROM t1; +i1 +35 +13 +23 +43 +51 +DROP TABLE t1; diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test index 7a3f7a9fa94..12b929898a8 100644 --- a/mysql-test/t/trigger-grant.test +++ b/mysql-test/t/trigger-grant.test @@ -564,3 +564,176 @@ SELECT @mysqltest_var; DROP USER mysqltest_u1@localhost; DROP DATABASE mysqltest_db1; + + +# +# Test for bug #14635 Accept NEW.x as INOUT parameters to stored +# procedures from within triggers +# +# We require UPDATE privilege when NEW.x passed as OUT parameter, and +# SELECT and UPDATE when NEW.x passed as INOUT parameter. +# +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; +USE mysqltest_db1; + +CREATE TABLE t1 (i1 INT); +CREATE TABLE t2 (i1 INT); + +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; + +GRANT EXECUTE, CREATE ROUTINE, SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT INSERT ON mysqltest_db1.* TO mysqltest_inv@localhost; + +connect (definer,localhost,mysqltest_dfn,,mysqltest_db1); +connect (invoker,localhost,mysqltest_inv,,mysqltest_db1); + +connection definer; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 3; +CREATE PROCEDURE p2(INOUT i INT) DETERMINISTIC NO SQL SET i = i * 5; + +# Check that having no privilege won't work. +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (7); +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES (11); + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +# Check that having only SELECT privilege is not enough. +connection default; +GRANT SELECT ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (13); +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES (17); + +connection default; +REVOKE SELECT ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +# Check that having only UPDATE privilege is enough for OUT parameter, +# but not for INOUT parameter. +connection default; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +INSERT INTO t1 VALUES (19); +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES (23); + +connection default; +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +# Check that having SELECT and UPDATE privileges is enough. +connection default; +GRANT SELECT, UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +INSERT INTO t1 VALUES (29); +INSERT INTO t2 VALUES (31); + +connection default; +REVOKE SELECT, UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +connection default; +DROP PROCEDURE p2; +DROP PROCEDURE p1; + +# Check that late procedure redefining won't open a security hole. +connection default; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 37; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); + +connection invoker; +INSERT INTO t1 VALUES (41); + +connection definer; +DROP PROCEDURE p1; +CREATE PROCEDURE p1(IN i INT) DETERMINISTIC NO SQL SET @v1 = i + 43; + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (47); + +connection definer; +DROP PROCEDURE p1; +CREATE PROCEDURE p1(INOUT i INT) DETERMINISTIC NO SQL SET i = i + 51; + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (53); + +connection default; +DROP PROCEDURE p1; +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t1_bi; + +# Cleanup. +disconnect definer; +disconnect invoker; +connection default; +DROP USER mysqltest_inv@localhost; +DROP USER mysqltest_dfn@localhost; +DROP TABLE t2; +DROP TABLE t1; +DROP DATABASE mysqltest_db1; +USE test; + +--echo End of 5.0 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 02e4ca5f900..a5bd2ba0b38 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1213,4 +1213,78 @@ DROP TRIGGER t1_ai; DROP TRIGGER t1_au; DROP TABLE t1; + +# +# Test for bug #14635 Accept NEW.x as INOUT parameters to stored +# procedures from within triggers +# +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +--enable_warnings + +CREATE TABLE t1 (i1 INT); + +# Check that NEW.x pseudo variable is accepted as INOUT and OUT +# parameter to stored routine. +INSERT INTO t1 VALUES (3); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET i1 = 5; +CREATE PROCEDURE p2(INOUT i1 INT) DETERMINISTIC NO SQL SET i1 = i1 * 7; +delimiter //; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +BEGIN + CALL p1(NEW.i1); + CALL p2(NEW.i1); +END// +delimiter ;// +UPDATE t1 SET i1 = 11 WHERE i1 = 3; +DROP TRIGGER t1_bu; +DROP PROCEDURE p2; +DROP PROCEDURE p1; + +# Check that OLD.x pseudo variable is not accepted as INOUT and OUT +# parameter to stored routine. +INSERT INTO t1 VALUES (13); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 17; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW + CALL p1(OLD.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 19 WHERE i1 = 13; +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; + +INSERT INTO t1 VALUES (23); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 29; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW + CALL p1(OLD.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 31 WHERE i1 = 23; +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; + +# Check that NEW.x pseudo variable is read-only in the AFTER TRIGGER. +INSERT INTO t1 VALUES (37); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 41; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW + CALL p1(NEW.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 43 WHERE i1 = 37; +DROP TRIGGER t1_au; +DROP PROCEDURE p1; + +INSERT INTO t1 VALUES (47); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 49; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW + CALL p1(NEW.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 51 WHERE i1 = 47; +DROP TRIGGER t1_au; +DROP PROCEDURE p1; + +# Post requisite. +SELECT * FROM t1; + +DROP TABLE t1; + # End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index 31fbef0f053..80bef06833f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -958,6 +958,12 @@ void Item_splocal::print(String *str) } +bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item *it) +{ + return ctx->set_variable(thd, get_var_idx(), it); +} + + /***************************************************************************** Item_case_expr methods *****************************************************************************/ @@ -5365,6 +5371,25 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const } +void Item_trigger_field::set_required_privilege(const bool rw) +{ + /* + Require SELECT and UPDATE privilege if this field will be read and + set, and only UPDATE privilege for setting the field. + */ + want_privilege= (rw ? SELECT_ACL | UPDATE_ACL : UPDATE_ACL); +} + + +bool Item_trigger_field::set_value(THD *thd, sp_rcontext */*ctx*/, Item *it) +{ + Item *item= sp_prepare_func_item(thd, &it); + + return (!item || (!fixed && fix_fields(thd, 0)) || + (item->save_in_field(field, 0) < 0)); +} + + bool Item_trigger_field::fix_fields(THD *thd, Item **items) { /* @@ -5387,8 +5412,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) if (table_grants) { - table_grants->want_privilege= - access_type == AT_READ ? SELECT_ACL : UPDATE_ACL; + table_grants->want_privilege= want_privilege; if (check_grant_column(thd, table_grants, triggers->table->s->db, triggers->table->s->table_name, field_name, @@ -5420,6 +5444,7 @@ void Item_trigger_field::print(String *str) void Item_trigger_field::cleanup() { + want_privilege= original_privilege; /* Since special nature of Item_trigger_field we should not do most of things from Item_field::cleanup() or Item_ident::cleanup() here. diff --git a/sql/item.h b/sql/item.h index 24aca4a86d1..617690e1fd9 100644 --- a/sql/item.h +++ b/sql/item.h @@ -372,6 +372,42 @@ public: /*************************************************************************/ +class sp_rcontext; + + +class Settable_routine_parameter +{ +public: + /* + Set required privileges for accessing the parameter. + + SYNOPSIS + set_required_privilege() + rw if 'rw' is true then we are going to read and set the + parameter, so SELECT and UPDATE privileges might be + required, otherwise we only reading it and SELECT + privilege might be required. + */ + virtual void set_required_privilege(bool rw) {}; + + /* + Set parameter value. + + SYNOPSIS + set_value() + thd thread handle + ctx context to which parameter belongs (if it is local + variable). + it item which represents new value + + RETURN + FALSE if parameter value has been set, + TRUE if error has occured. + */ + virtual bool set_value(THD *thd, sp_rcontext *ctx, Item *it)= 0; +}; + + typedef bool (Item::*Item_processor)(byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); @@ -744,6 +780,15 @@ public: } virtual bool is_splocal() { return 0; } /* Needed for error checking */ + + /* + Return Settable_routine_parameter interface of the Item. Return 0 + if this Item is not Settable_routine_parameter. + */ + virtual Settable_routine_parameter *get_settable_routine_parameter() + { + return 0; + } }; @@ -842,7 +887,8 @@ inline bool Item_sp_variable::send(Protocol *protocol, String *str) runtime. *****************************************************************************/ -class Item_splocal :public Item_sp_variable +class Item_splocal :public Item_sp_variable, + private Settable_routine_parameter { uint m_var_idx; @@ -880,6 +926,15 @@ public: inline enum Type type() const; inline Item_result result_type() const; + +private: + bool set_value(THD *thd, sp_rcontext *ctx, Item *it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return this; + } }; /***************************************************************************** @@ -2100,14 +2155,13 @@ class Table_triggers_list; two Field instances representing either OLD or NEW version of this field. */ -class Item_trigger_field : public Item_field +class Item_trigger_field : public Item_field, + private Settable_routine_parameter { public: /* Is this item represents row from NEW or OLD row ? */ enum row_version_type {OLD_ROW, NEW_ROW}; row_version_type row_version; - /* Is this item used for reading or updating the value? */ - enum access_types { AT_READ = 0x1, AT_UPDATE = 0x2 }; /* Next in list of all Item_trigger_field's in trigger */ Item_trigger_field *next_trg_field; /* Index of the field in the TABLE::field array */ @@ -2118,11 +2172,11 @@ public: Item_trigger_field(Name_resolution_context *context_arg, row_version_type row_ver_arg, const char *field_name_arg, - access_types access_type_arg) + ulong priv, const bool ro) :Item_field(context_arg, (const char *)NULL, (const char *)NULL, field_name_arg), - row_version(row_ver_arg), field_idx((uint)-1), - access_type(access_type_arg), table_grants(NULL) + row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv), + want_privilege(priv), table_grants(NULL), read_only (ro) {} void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); enum Type type() const { return TRIGGER_FIELD_ITEM; } @@ -2133,8 +2187,39 @@ public: void cleanup(); private: - access_types access_type; + void set_required_privilege(const bool rw); + bool set_value(THD *thd, sp_rcontext *ctx, Item *it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return (read_only ? 0 : this); + } + + bool set_value(THD *thd, Item *it) + { + return set_value(thd, NULL, it); + } + +private: + /* + 'want_privilege' holds privileges required to perform operation on + this trigger field (SELECT_ACL if we are going to read it and + UPDATE_ACL if we are going to update it). It is initialized at + parse time but can be updated later if this trigger field is used + as OUT or INOUT parameter of stored routine (in this case + set_required_privilege() is called to appropriately update + want_privilege and cleanup() is responsible for restoring of + original want_privilege once parameter's value is updated). + */ + ulong original_privilege; + ulong want_privilege; GRANT_INFO *table_grants; + /* + Trigger field is read-only unless it belongs to the NEW row in a + BEFORE INSERT of BEFORE UPDATE trigger. + */ + bool read_only; }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 603a00947dd..f9ef56af19e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4103,6 +4103,18 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const } +bool Item_func_get_user_var::set_value(THD *thd, + sp_rcontext */*ctx*/, Item *it) +{ + Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), it); + /* + Item_func_set_user_var is not fixed after construction, call + fix_fields(). + */ + return (!suv || suv->fix_fields(thd, &it) || suv->check() || suv->update()); +} + + bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); diff --git a/sql/item_func.h b/sql/item_func.h index ed5924e8fe1..494add0c321 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1178,7 +1178,8 @@ public: }; -class Item_func_get_user_var :public Item_func +class Item_func_get_user_var :public Item_func, + private Settable_routine_parameter { user_var_entry *var_entry; @@ -1205,6 +1206,15 @@ public: table_map used_tables() const { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; + +private: + bool set_value(THD *thd, sp_rcontext *ctx, Item *it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return this; + } }; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7665a7425cd..7e1ded8adf2 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5475,7 +5475,7 @@ ER_SP_DUP_HANDLER 42000 eng "Duplicate handler declared in the same block" ger "Doppelter Handler im selben Block deklariert" ER_SP_NOT_VAR_ARG 42000 - eng "OUT or INOUT argument %d for routine %s is not a variable" + eng "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger" ger "OUT- oder INOUT-Argument %d fЭr Routine %s ist keine Variable" ER_SP_NO_RETSET 0A000 eng "Not allowed to return a result set from a %s" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e78bd3c59c0..0aee7cdb5b9 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1380,19 +1380,6 @@ err_with_cleanup: } -static Item_func_get_user_var *item_is_user_var(Item *it) -{ - if (it->type() == Item::FUNC_ITEM) - { - Item_func *fi= static_cast(it); - - if (fi->functype() == Item_func::GUSERVAR_FUNC) - return static_cast(fi); - } - return NULL; -} - - /* Execute a procedure. SYNOPSIS @@ -1468,22 +1455,28 @@ sp_head::execute_procedure(THD *thd, List *args) for (uint i= 0 ; i < params ; i++) { Item *arg_item= it_args++; - sp_variable_t *spvar= m_pcont->find_variable(i); if (!arg_item) break; + sp_variable_t *spvar= m_pcont->find_variable(i); + if (!spvar) continue; if (spvar->mode != sp_param_in) { - if (!arg_item->is_splocal() && !item_is_user_var(arg_item)) + Settable_routine_parameter *srp= + arg_item->get_settable_routine_parameter(); + + if (!srp) { my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str); err_status= TRUE; break; } + + srp->set_required_privilege(spvar->mode == sp_param_inout); } if (spvar->mode == sp_param_out) @@ -1551,36 +1544,16 @@ sp_head::execute_procedure(THD *thd, List *args) if (spvar->mode == sp_param_in) continue; - if (arg_item->is_splocal()) + Settable_routine_parameter *srp= + arg_item->get_settable_routine_parameter(); + + DBUG_ASSERT(srp); + + if (srp->set_value(thd, octx, nctx->get_item(i))) { - if (octx->set_variable(thd, - ((Item_splocal*) arg_item)->get_var_idx(), - nctx->get_item(i))) - { - err_status= TRUE; - break; - } + err_status= TRUE; + break; } - else - { - Item_func_get_user_var *guv= item_is_user_var(arg_item); - - if (guv) - { - Item *item= nctx->get_item(i); - Item_func_set_user_var *suv; - - suv= new Item_func_set_user_var(guv->get_name(), item); - /* - Item_func_set_user_var is not fixed after construction, - call fix_fields(). - */ - if ((err_status= test(!suv || suv->fix_fields(thd, &item) || - suv->check() || suv->update()))) - break; - } - } - } } @@ -2414,12 +2387,7 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) int sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) { - int res= 0; - Item *it= sp_prepare_func_item(thd, &value); - if (!it || - !trigger_field->fixed && trigger_field->fix_fields(thd, 0) || - (it->save_in_field(trigger_field->field, 0) < 0)) - res= -1; + const int res= (trigger_field->set_value(thd, value) ? -1 : 0); *nextp = m_ip+1; return res; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 261d10f3e79..bfafba53419 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7216,12 +7216,18 @@ simple_ident_q: YYABORT; } + DBUG_ASSERT(!new_row || + (lex->trg_chistics.event == TRG_EVENT_INSERT || + lex->trg_chistics.event == TRG_EVENT_UPDATE)); + const bool read_only= + !(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE); if (!(trg_fld= new Item_trigger_field(Lex->current_context(), new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, $3.str, - Item_trigger_field::AT_READ))) + SELECT_ACL, + read_only))) YYABORT; /* @@ -7857,11 +7863,13 @@ sys_option_value: it= new Item_null(); } + DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && + (lex->trg_chistics.event == TRG_EVENT_INSERT || + lex->trg_chistics.event == TRG_EVENT_UPDATE)); if (!(trg_fld= new Item_trigger_field(Lex->current_context(), Item_trigger_field::NEW_ROW, $2.base_name.str, - Item_trigger_field::AT_UPDATE) - ) || + UPDATE_ACL, FALSE)) || !(sp_fld= new sp_instr_set_trigger_field(lex->sphead-> instructions(), lex->spcont, From fa9b0268ab9bb649707f86946e5d19693481af61 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 17:51:37 +0200 Subject: [PATCH 18/41] Many files: Change mode to -rw-rw-r-- dbug_add_tags.pl: Change mode to -rwxrwxr-- dbug/dbug_add_tags.pl: Change mode to -rwxrwxr-- myisammrg/myrg_range.c: Change mode to -rw-rw-r-- mysql-test/r/innodb_handler.result: Change mode to -rw-rw-r-- mysql-test/r/repair.result: Change mode to -rw-rw-r-- mysql-test/std_data/master-bin.001: Change mode to -rw-rw-r-- mysql-test/std_data/trunc_binlog.001: Change mode to -rw-rw-r-- mysql-test/t/bulk_replace.test: Change mode to -rw-rw-r-- mysql-test/t/create_select_tmp.test: Change mode to -rw-rw-r-- mysql-test/t/ctype_tis620.test: Change mode to -rw-rw-r-- mysql-test/t/handler.test: Change mode to -rw-rw-r-- mysql-test/t/innodb_handler.test: Change mode to -rw-rw-r-- mysql-test/t/mix_innodb_myisam_binlog-master.opt: Change mode to -rw-rw-r-- mysql-test/t/repair.test: Change mode to -rw-rw-r-- mysql-test/t/rpl_commit_after_flush.test: Change mode to -rw-rw-r-- mysql-test/t/rpl_free_items-slave.opt: Change mode to -rw-rw-r-- mysql-test/t/rpl_free_items.test: Change mode to -rw-rw-r-- scripts/mysql_secure_installation.sh: Change mode to -rw-rw-r-- sql/sql_handler.cc: Change mode to -rw-rw-r-- support-files/mysql-multi.server.sh: Change mode to -rw-rw-r-- From db2556fdbed22c163b41a114782fc50c56ca8482 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 18:28:48 +0200 Subject: [PATCH 19/41] Many files: Change mode to -rw-rw-r-- Ereport.pl, Ecreate.pl, Ecompare.pl: Change mode to -rwxrwxr-- bdb/dist/s_dir: Change mode to -rw-rw-r-- myisam/ftbench/Ecompare.pl: Change mode to -rwxrwxr-- myisam/ftbench/Ecreate.pl: Change mode to -rwxrwxr-- myisam/ftbench/Ereport.pl: Change mode to -rwxrwxr-- myisam/ftbench/README: Change mode to -rw-rw-r-- myisammrg/myrg_rnext_same.c: Change mode to -rw-rw-r-- mysql-test/include/rpl_stmt_seq.inc: Change mode to -rw-rw-r-- mysql-test/misc/kill_master.sh: Change mode to -rw-rw-r-- mysql-test/r/blackhole.result: Change mode to -rw-rw-r-- mysql-test/r/ctype_cp1250_ch.result: Change mode to -rw-rw-r-- mysql-test/r/ctype_cp932_binlog.result: Change mode to -rw-rw-r-- mysql-test/r/ctype_euckr.result: Change mode to -rw-rw-r-- mysql-test/r/ctype_gb2312.result: Change mode to -rw-rw-r-- mysql-test/r/ctype_ucs_binlog.result: Change mode to -rw-rw-r-- mysql-test/r/fulltext2.result: Change mode to -rw-rw-r-- mysql-test/r/func_des_encrypt.result: Change mode to -rw-rw-r-- mysql-test/r/grant2.result: Change mode to -rw-rw-r-- mysql-test/r/insert_update.result: Change mode to -rw-rw-r-- mysql-test/r/ndb_database.result: Change mode to -rw-rw-r-- mysql-test/r/ndb_update.result: Change mode to -rw-rw-r-- mysql-test/r/not_embedded_server.result: Change mode to -rw-rw-r-- mysql-test/r/query_cache_notembedded.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_create_database.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_drop_db.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_dual_pos_advance.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_insert_select.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_multi_update3.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_multi_update4.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_slave_status.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_trunc_temp.result: Change mode to -rw-rw-r-- mysql-test/r/timezone_grant.result: Change mode to -rw-rw-r-- mysql-test/std_data/master-bin.000001: Change mode to -rw-rw-r-- mysql-test/t/ctype_latin1.test: Change mode to -rw-rw-r-- mysql-test/t/fulltext2.test: Change mode to -rw-rw-r-- mysql-test/t/gis-rtree.test: Change mode to -rw-rw-r-- mysql-test/t/grant2.test: Change mode to -rw-rw-r-- mysql-test/t/insert_update.test: Change mode to -rw-rw-r-- mysql-test/t/mysqltest.test: Change mode to -rw-rw-r-- mysql-test/t/rpl_ddl.test: Change mode to -rw-rw-r-- mysql-test/t/rpl_insert_ignore.test: Change mode to -rw-rw-r-- mysql-test/t/rpl_multi_query.test: Change mode to -rw-rw-r-- mysql-test/t/rpl_rewrite_db-slave.opt: Change mode to -rw-rw-r-- mysql-test/t/rpl_rewrite_db.test: Change mode to -rw-rw-r-- mysql-test/t/subselect2.test: Change mode to -rw-rw-r-- mysql-test/t/union-master.opt: Change mode to -rw-rw-r-- mysys/mf_tempdir.c: Change mode to -rw-rw-r-- mysys/my_crc32.c: Change mode to -rw-rw-r-- mysys/my_gethwaddr.c: Change mode to -rw-rw-r-- mysys/my_getsystime.c: Change mode to -rw-rw-r-- scripts/mysql_prepare_privilege_tables_for_5.sql: Change mode to -rw-rw-r-- sql/sql_bitmap.h: Change mode to -rw-rw-r-- zlib/Makefile.am: Change mode to -rw-rw-r-- From b572680177cc527fb6ad53832f655c4054bf3da7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 19:00:11 +0200 Subject: [PATCH 20/41] Many files: Change mode to -rw-rw-r-- include/decimal.h: Change mode to -rw-rw-r-- mysql-test/r/archive_gis.result: Change mode to -rw-rw-r-- mysql-test/r/bdb_gis.result: Change mode to -rw-rw-r-- mysql-test/r/binlog.result: Change mode to -rw-rw-r-- mysql-test/r/compress.result: Change mode to -rw-rw-r-- mysql-test/r/federated_archive.result: Change mode to -rw-rw-r-- mysql-test/r/federated_bug_13118.result: Change mode to -rw-rw-r-- mysql-test/r/im_daemon_life_cycle.result: Change mode to -rw-rw-r-- mysql-test/r/im_life_cycle.result: Change mode to -rw-rw-r-- mysql-test/r/im_options_set.result: Change mode to -rw-rw-r-- mysql-test/r/im_options_unset.result: Change mode to -rw-rw-r-- mysql-test/r/im_utils.result: Change mode to -rw-rw-r-- mysql-test/r/innodb-big.result: Change mode to -rw-rw-r-- mysql-test/r/innodb_gis.result: Change mode to -rw-rw-r-- mysql-test/r/innodb_notembedded.result: Change mode to -rw-rw-r-- mysql-test/r/mysql.result: Change mode to -rw-rw-r-- mysql-test/r/mysqldump-max.result: Change mode to -rw-rw-r-- mysql-test/r/ndb_bitfield.result: Change mode to -rw-rw-r-- mysql-test/r/ndb_condition_pushdown.result: Change mode to -rw-rw-r-- mysql-test/r/ndb_gis.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_ignore_revoke.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_trigger.result: Change mode to -rw-rw-r-- mysql-test/r/rpl_view.result: Change mode to -rw-rw-r-- mysql-test/r/sp-code.result: Change mode to -rw-rw-r-- mysql-test/r/sp-destruct.result: Change mode to -rw-rw-r-- mysql-test/r/sp-dynamic.result: Change mode to -rw-rw-r-- mysql-test/r/sp-vars.result: Change mode to -rw-rw-r-- mysql-test/r/sp_trans.result: Change mode to -rw-rw-r-- mysql-test/r/sum_distinct-big.result: Change mode to -rw-rw-r-- mysql-test/r/trigger-compat.result: Change mode to -rw-rw-r-- mysql-test/r/trigger-grant.result: Change mode to -rw-rw-r-- mysql-test/r/trigger-trans.result: Change mode to -rw-rw-r-- mysql-test/r/type_bit_innodb.result: Change mode to -rw-rw-r-- mysql-test/r/type_newdecimal.result: Change mode to -rw-rw-r-- mysql-test/r/user_limits.result: Change mode to -rw-rw-r-- mysql-test/r/view_grant.result: Change mode to -rw-rw-r-- mysql-test/r/view_query_cache.result: Change mode to -rw-rw-r-- mysql-test/r/xa.result: Change mode to -rw-rw-r-- mysql-test/std_data/bug16266.000001: Change mode to -rw-rw-r-- mysql-test/std_data/vchar.frm: Change mode to -rw-rw-r-- mysql-test/t/binlog-master.opt: Change mode to -rw-rw-r-- mysql-test/t/binlog.test: Change mode to -rw-rw-r-- mysql-test/t/flush_read_lock_kill-master.opt: Change mode to -rw-rw-r-- mysql-test/t/flush_read_lock_kill.test: Change mode to -rw-rw-r-- mysql-test/t/sp_trans.test: Change mode to -rw-rw-r-- mysql-test/t/xa.test: Change mode to -rw-rw-r-- mysys/my_mmap.c: Change mode to -rw-rw-r-- sql/sql_array.h: Change mode to -rw-rw-r-- strings/decimal.c: Change mode to -rw-rw-r-- From c212cb25ede28515c588d52061e67286bd3bb7d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 21:29:06 +0300 Subject: [PATCH 21/41] BUG#19188: incorrect temporary table name of DROP query in replication A pattern to generate binlog for DROPped temp table in close_temporary_tables was buggy: could not deal with a grave-accent-in-name table. The fix exploits `append_identifier()' for quoting and duplicating accents. mysql-test/r/rpl_temporary.result: results changed mysql-test/t/rpl_temporary.test: more correct internal table emulation; typo of @@session in bug#17263. sql/mysql_priv.h: bool is_user_table(TABLE * table) is added to answer wheather temporary table was created explicitly. sql/sql_base.cc: Utilizing `append_identifier' to quote. `close_temporary_tables' once again recoded I hope to become much simplier than previously. No-binlog branch is separated completely the rest that adopts String's methods. --- mysql-test/r/rpl_temporary.result | 13 ++- mysql-test/t/rpl_temporary.test | 15 ++- sql/mysql_priv.h | 12 +++ sql/sql_base.cc | 147 ++++++++++++++---------------- 4 files changed, 99 insertions(+), 88 deletions(-) diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index cd67d2592a8..0442109c016 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -89,14 +89,17 @@ f 7 drop table t1,t2; create temporary table t3 (f int); -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); -set @con1_id=connection_id(); -kill @con1_id; +create temporary table `t``201` (id int); +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 71d7b32b7c9..e1dd1f32546 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -135,14 +135,19 @@ sync_with_master; # value was set up at the moment of temp table creation # connection con1; -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); -set @con1_id=connection_id(); -kill @con1_id; +create temporary table `t``201` (id int); +# emulate internal temp table not to come to binlog +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); +disconnect con1; #now do something to show that slave is ok after DROP temp tables connection master; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6676d994cfa..634e7bad738 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1275,6 +1275,18 @@ inline int hexchar_to_int(char c) return -1; } +/* + is_user_table() + return true if the table was created explicitly +*/ + +inline bool is_user_table(TABLE * table) +{ + const char *name= table->real_name; + return strncmp(name, tmp_file_prefix, tmp_file_prefix_length); +} + + /* Some functions that are different in the embedded library and the normal diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 60e91aff3f9..3df9cbace78 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -493,118 +493,107 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) void close_temporary_tables(THD *thd) { - TABLE *next, - *prev_table /* prev link is not maintained in TABLE's double-linked list */, - *table; - char *query= (gptr) 0, *end; - uint query_buf_size, max_names_len; - bool found_user_tables; - + TABLE *table; if (!thd->temporary_tables) return; - LINT_INIT(end); - query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS + if (!mysql_bin_log.is_open()) + { + for (table= thd->temporary_tables; table; table= table->next) + { + close_temporary(table, 1); + } + thd->temporary_tables= 0; + return; + } + TABLE *next, + *prev_table /* prev link is not maintained in TABLE's double-linked list */; + bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */ + // Better add "if exists", in case a RESET MASTER has been done + const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "; + uint stub_len= sizeof(stub) - 1; + char buf[256]; + memcpy(buf, stub, stub_len); + String s_query= String(buf, sizeof(buf), system_charset_info); + bool found_user_tables= false; + LINT_INIT(next); + /* insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id */ - for (prev_table= thd->temporary_tables, - table= prev_table->next, - found_user_tables= (prev_table->real_name[0] != '#'); + + for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) { - TABLE *prev_sorted /* same as for prev_table */, - *sorted; - /* - table not created directly by the user is moved to the tail. - Fixme/todo: nothing (I checked the manual) prevents user to create temp - with `#' - */ - if (table->real_name[0] == '#') - continue; - else + TABLE *prev_sorted /* same as for prev_table */, *sorted; + if (is_user_table(table)) { - found_user_tables = 1; - } - for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; - prev_sorted= sorted, sorted= sorted->next) - { - if (sorted->real_name[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) + if (!found_user_tables) + found_user_tables= true; + for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; + prev_sorted= sorted, sorted= sorted->next) { - /* move into the sorted part of the list from the unsorted */ - prev_table->next= table->next; - table->next= sorted; - if (prev_sorted) + if (!is_user_table(sorted) || + tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) { - prev_sorted->next= table; + /* move into the sorted part of the list from the unsorted */ + prev_table->next= table->next; + table->next= sorted; + if (prev_sorted) + { + prev_sorted->next= table; + } + else + { + thd->temporary_tables= table; + } + table= prev_table; + break; } - else - { - thd->temporary_tables= table; - } - table= prev_table; - break; } } - } - /* - calc query_buf_size as max per sublists, one sublist per pseudo thread id. - Also stop at first occurence of `#'-named table that starts - all implicitly created temp tables - */ - for (max_names_len= 0, table=thd->temporary_tables; - table && table->real_name[0] != '#'; - table=table->next) + } + + /* We always quote db,table names though it is slight overkill */ + if (found_user_tables && + !(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE))) { - uint tmp_names_len; - for (tmp_names_len= table->key_length + 1; - table->next && table->real_name[0] != '#' && - tmpkeyval(thd, table) == tmpkeyval(thd, table->next); - table=table->next) - { - /* - We are going to add 4 ` around the db/table names, so 1 might not look - enough; indeed it is enough, because table->key_length is greater (by 8, - because of server_id and thread_id) than db||table. - */ - tmp_names_len += table->next->key_length + 1; - } - if (tmp_names_len > max_names_len) max_names_len= tmp_names_len; + thd->options |= OPTION_QUOTE_SHOW_CREATE; } - /* allocate */ - if (found_user_tables && mysql_bin_log.is_open() && - (query = alloc_root(thd->mem_root, query_buf_size+= max_names_len))) - // Better add "if exists", in case a RESET MASTER has been done - end= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "); - /* scan sorted tmps to generate sequence of DROP */ - for (table=thd->temporary_tables; table; table= next) + for (table= thd->temporary_tables; table; table= next) { - if (query // we might be out of memory, but this is not fatal - && table->real_name[0] != '#') + if (is_user_table(table)) { - char *end_cur; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); /* Loop forward through all tables within the sublist of common pseudo_thread_id to create single DROP query */ - for (end_cur= end; - table && table->real_name[0] != '#' && + for (s_query.length(stub_len); + table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; table= next) { - end_cur= strxmov(end_cur, "`", table->table_cache_key, "`.`", - table->real_name, "`,", NullS); + /* + We are going to add 4 ` around the db/table names and possible more + due to special characters in the names + */ + append_identifier(thd, &s_query, table->table_cache_key, strlen(table->table_cache_key)); + s_query.q_append('.'); + append_identifier(thd, &s_query, table->real_name, + strlen(table->real_name)); + s_query.q_append(','); next= table->next; close_temporary(table, 1); } thd->clear_error(); - /* The -1 is to remove last ',' */ - Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE); + Query_log_event qinfo(thd, s_query.ptr(), + s_query.length() - 1 /* to remove trailing ',' */, + 0, FALSE); /* Imagine the thread had created a temp table, then was doing a SELECT, and the SELECT was killed. Then it's not clever to mark the statement above as @@ -623,6 +612,8 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1); } } + if (!was_quote_show) + thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; } From 7bb4f77828191917e72c6fb5273149e0f9cb21bb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 May 2006 18:24:38 -0700 Subject: [PATCH 22/41] Fixed bug #19490. The bug that caused server crash manifested itself when executing queries referring to a view with GROUP BY an expression containing non-constant interval. It happened because Item_date_add_interval::eq neglected the fact that the method can be applied to an expression of the form date(col) + interval time_to_sec(col) second at the time when col could not be evaluated yet. An attempt to evaluate time_to_sec(col) in this method resulted in a crash. mysql-test/r/view.result: Added a test case for bug #19490. mysql-test/t/view.test: Added a test case for bug #19490. sql/item_timefunc.cc: Fixed bug #19490. The bug that caused server crash manifested itself when executing queries referring to a view with GROUP BY an expression containing non-constant interval. It happened because Item_date_add_interval::eq neglected the fact that the method can be applied to an expression of the form date(col) + interval time_to_sec(col) second at the time when col could not be evaluated yet. An attempt to evaluate time_to_sec(col) in this method resulted in a crash. The code of Item_date_add_interval::eq was corrected. --- mysql-test/r/view.result | 11 +++++++++++ mysql-test/t/view.test | 16 ++++++++++++++++ sql/item_timefunc.cc | 9 +++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a89b6e9b3b1..4baa56070b7 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2649,3 +2649,14 @@ ldt 2006-01-01 03:00:00 drop view v1, v2; drop table t1; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, d datetime); +CREATE VIEW v1 AS +SELECT id, date(d) + INTERVAL TIME_TO_SEC(d) SECOND AS t, COUNT(*) +FROM t1 GROUP BY id, t; +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`id` AS `id`,(cast(`t1`.`d` as date) + interval time_to_sec(`t1`.`d`) second) AS `t`,count(0) AS `COUNT(*)` from `t1` group by `t1`.`id`,(cast(`t1`.`d` as date) + interval time_to_sec(`t1`.`d`) second) +SELECT * FROM v1; +id t COUNT(*) +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 8f759c2d43e..ea22ada900a 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2512,3 +2512,19 @@ create view v2 as select convert_tz(dt, 'UTC', 'Europe/Moscow') as ldt from v1; select * from v2; drop view v1, v2; drop table t1; + +# +# Bug #19490: usage of view specified by a query with GROUP BY +# an expression containing non-constant interval + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, d datetime); + +CREATE VIEW v1 AS +SELECT id, date(d) + INTERVAL TIME_TO_SEC(d) SECOND AS t, COUNT(*) + FROM t1 GROUP BY id, t; + +SHOW CREATE VIEW v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index e997d4ae70c..72c53272e0c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2144,8 +2144,13 @@ bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const Item_date_add_interval *other= (Item_date_add_interval*) item; if ((int_type != other->int_type) || - (!args[0]->eq(other->args[0], binary_cmp)) || - (get_interval_value(args[1], int_type, &val, &interval))) + (!args[0]->eq(other->args[0], binary_cmp))) + return FALSE; + + if (!args[1]->const_item() || !other->args[1]->const_item()) + return (args[1]->eq(other->args[1], binary_cmp)); + + if (get_interval_value(args[1], int_type, &val, &interval)) return FALSE; val= other->value; From fe3ac3007a3766be7e826724b6bc3cf59b9930d0 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 May 2006 13:13:05 +0500 Subject: [PATCH 23/41] Bug#17048 CREATE TABLE ... SELECT truncate values remove initialization of unsigned_flag for Item_decimal mysql-test/r/case.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/metadata.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/ps_2myisam.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/ps_3innodb.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/ps_4heap.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/ps_5merge.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/ps_6bdb.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/ps_7ndb.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/type_float.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix mysql-test/r/type_newdecimal.result: Bug#17048 CREATE TABLE ... SELECT truncate values result fix --- mysql-test/r/case.result | 8 ++++---- mysql-test/r/metadata.result | 2 +- mysql-test/r/ps_2myisam.result | 4 ++-- mysql-test/r/ps_3innodb.result | 4 ++-- mysql-test/r/ps_4heap.result | 4 ++-- mysql-test/r/ps_5merge.result | 8 ++++---- mysql-test/r/ps_6bdb.result | 4 ++-- mysql-test/r/ps_7ndb.result | 4 ++-- mysql-test/r/type_float.result | 8 ++++---- mysql-test/r/type_newdecimal.result | 14 +++++++------- sql/item.cc | 6 ------ 11 files changed, 30 insertions(+), 36 deletions(-) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 8349d6e9338..cf358e6a404 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -103,8 +103,8 @@ t1 CREATE TABLE `t1` ( `c2` varchar(1) character set latin1 collate latin1_danish_ci NOT NULL default '', `c3` varbinary(1) NOT NULL default '', `c4` varbinary(1) NOT NULL default '', - `c5` varbinary(3) NOT NULL default '', - `c6` varbinary(3) NOT NULL default '', + `c5` varbinary(4) NOT NULL default '', + `c6` varbinary(4) NOT NULL default '', `c7` decimal(2,1) NOT NULL default '0.0', `c8` decimal(2,1) NOT NULL default '0.0', `c9` decimal(2,1) default NULL, @@ -152,11 +152,11 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `COALESCE(1)` int(1) NOT NULL default '0', - `COALESCE(1.0)` decimal(2,1) unsigned NOT NULL default '0.0', + `COALESCE(1.0)` decimal(2,1) NOT NULL default '0.0', `COALESCE('a')` varchar(1) NOT NULL default '', `COALESCE(1,1.0)` decimal(2,1) NOT NULL default '0.0', `COALESCE(1,'1')` varbinary(1) NOT NULL default '', - `COALESCE(1.1,'1')` varbinary(3) NOT NULL default '', + `COALESCE(1.1,'1')` varbinary(4) NOT NULL default '', `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 0a170e16188..50b0b6ae294 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -2,7 +2,7 @@ drop table if exists t1,t2; select 1, 1.0, -1, "hello", NULL; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def 1 8 1 1 N 32897 0 63 -def 1.0 246 3 3 N 161 1 63 +def 1.0 246 4 3 N 129 1 63 def -1 8 2 2 N 32897 0 63 def hello 253 5 5 N 1 31 8 def NULL 6 0 0 Y 32896 0 63 diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 603de2afe4e..207d9ea7475 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1777,7 +1777,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1807,7 +1807,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 9e635f60f14..13aa549949c 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1760,7 +1760,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1790,7 +1790,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index fd51c71cad6..a08dae945bd 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1761,7 +1761,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1791,7 +1791,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 876f7615672..6682b085097 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1697,7 +1697,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1727,7 +1727,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 @@ -4711,7 +4711,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -4741,7 +4741,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index c39621d184f..dc3b984949d 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1760,7 +1760,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1790,7 +1790,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 7c83099311e..000a20da655 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1760,7 +1760,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1790,7 +1790,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index e941e740fcb..61482ab282c 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -245,22 +245,22 @@ show warnings; Level Code Message desc t1; Field Type Null Key Default Extra -x decimal(21,2) unsigned NO 0.00 +x decimal(21,2) NO 0.00 drop table t1; create table t1 select 0.0 x; desc t1; Field Type Null Key Default Extra -x decimal(2,1) unsigned NO 0.0 +x decimal(2,1) NO 0.0 create table t2 select 105213674794682365.00 y; desc t2; Field Type Null Key Default Extra -y decimal(20,2) unsigned NO 0.00 +y decimal(20,2) NO 0.00 create table t3 select x+y a from t1,t2; show warnings; Level Code Message desc t3; Field Type Null Key Default Extra -a decimal(21,2) unsigned NO 0.00 +a decimal(21,2) NO 0.00 drop table t1,t2,t3; create table t1 (s1 float(0,2)); ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 938dccc864c..968c6d3ec6f 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -68,10 +68,10 @@ NULL 1.1 NULL NULL NULL 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `nullif(1.1, 1.1)` decimal(2,1) unsigned default NULL, - `nullif(1.1, 1.2)` decimal(2,1) unsigned default NULL, - `nullif(1.1, 0.11e1)` decimal(2,1) unsigned default NULL, - `nullif(1.0, 1)` decimal(2,1) unsigned default NULL, + `nullif(1.1, 1.1)` decimal(2,1) default NULL, + `nullif(1.1, 1.2)` decimal(2,1) default NULL, + `nullif(1.1, 0.11e1)` decimal(2,1) default NULL, + `nullif(1.0, 1)` decimal(2,1) default NULL, `nullif(1, 1.0)` int(1) default NULL, `nullif(1, 1.1)` int(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -174,9 +174,9 @@ create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(- show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `round(15.4,-1)` decimal(3,0) unsigned NOT NULL default '0', + `round(15.4,-1)` decimal(3,0) NOT NULL default '0', `truncate(-5678.123451,-3)` decimal(4,0) NOT NULL default '0', - `abs(-1.1)` decimal(2,1) NOT NULL default '0.0', + `abs(-1.1)` decimal(3,1) NOT NULL default '0.0', `-(-1.1)` decimal(2,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; @@ -771,7 +771,7 @@ create table t1 as select 0.5; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `0.5` decimal(2,1) unsigned NOT NULL default '0.0' + `0.5` decimal(2,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; select round(1.5),round(2.5); diff --git a/sql/item.cc b/sql/item.cc index 31fbef0f053..8e922c46b8e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1883,7 +1883,6 @@ Item_decimal::Item_decimal(const char *str_arg, uint length, name= (char*) str_arg; decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1893,7 +1892,6 @@ Item_decimal::Item_decimal(longlong val, bool unsig) int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1904,7 +1902,6 @@ Item_decimal::Item_decimal(double val, int precision, int scale) double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1917,7 +1914,6 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg, name= (char*) str; decimals= (uint8) decimal_par; max_length= length; - unsigned_flag= !decimal_value.sign(); fixed= 1; } @@ -1927,7 +1923,6 @@ Item_decimal::Item_decimal(my_decimal *value_par) my_decimal2decimal(value_par, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1939,7 +1934,6 @@ Item_decimal::Item_decimal(const char *bin, int precision, int scale) &decimal_value, precision, scale); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(precision, decimals, unsigned_flag); } From 62be79a2e6208873240fb0a3dafbb99f24c9e577 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 May 2006 12:14:20 +0300 Subject: [PATCH 24/41] BUG#14157: utf8 encoding in binlog without set character_set_client fixing a path to find charset by $MYSQL client. I believe the fix is done what should be by default. mysql-test/t/mysqlbinlog.test: --character-sets-dir=../sql/share/charsets is added otherwise client/.libs/lt-mysql searches in /usr/local/mysql ... A bug? mysql-test/t/rpl_temporary.test: --character-sets-dir=../sql/share/charsets/ --- mysql-test/t/mysqlbinlog.test | 2 +- mysql-test/t/rpl_temporary.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 11aa5814bda..7b6c36bb8c9 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -118,7 +118,7 @@ select HEX(f) from t4; #14157: utf8 encoding in binlog without set character_set_client # flush logs; ---exec $MYSQL --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' # resulted log is client charset insensitive (latin1 not koi8r) as it must be --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 1276b635b74..609e8533849 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -164,7 +164,7 @@ drop table t1; # #14157: utf8 encoding in binlog without set character_set_client # ---exec $MYSQL --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' sync_slave_with_master; #connection slave; From fbafa42bf3c7070627875045a01507a62c688c7a Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 May 2006 11:56:05 -0700 Subject: [PATCH 25/41] Fixed bug #19396: a crash for a an outer join operation over two views when using syntax with curly braces. Each outer join operation must be placed in a separate nest. This was not done when the syntax with curly braces was used. In some cases, in particular, for queries with outer join operation over views it could cause a crash. mysql-test/r/join_outer.result: Added a test case for bug #19396. mysql-test/t/join_outer.test: Added a test case for bug #19396. --- mysql-test/r/join_outer.result | 22 ++++++++++++++++++++++ mysql-test/t/join_outer.test | 26 ++++++++++++++++++++++++++ sql/sql_yacc.yy | 4 ++++ 3 files changed, 52 insertions(+) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 694bab2597c..712a60828f7 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1154,3 +1154,25 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index 1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index DROP TABLE t1,t2; +DROP VIEW IF EXISTS v1,v2; +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a int); +CREATE table t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (1), (1), (3); +INSERT INTO t2 VALUES (2), (3); +CREATE VIEW v1 AS SELECT a FROM t1 JOIN t2 ON t1.a=t2.b; +CREATE VIEW v2 AS SELECT b FROM t2 JOIN t1 ON t2.b=t1.a; +SELECT v1.a, v2. b +FROM v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) +GROUP BY v1.a; +a b +2 NULL +3 3 +SELECT v1.a, v2. b +FROM { OJ v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) } +GROUP BY v1.a; +a b +2 NULL +3 3 +DROP VIEW v1,v2; +DROP TABLE t1,t2; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index c194213e0c9..7134137a430 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -779,3 +779,29 @@ SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; DROP TABLE t1,t2; + +# +# Bug 19396: LEFT OUTER JOIN over views in curly braces +# +--disable_warnings +DROP VIEW IF EXISTS v1,v2; +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +CREATE TABLE t1 (a int); +CREATE table t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (1), (1), (3); +INSERT INTO t2 VALUES (2), (3); + +CREATE VIEW v1 AS SELECT a FROM t1 JOIN t2 ON t1.a=t2.b; +CREATE VIEW v2 AS SELECT b FROM t2 JOIN t1 ON t2.b=t1.a; + +SELECT v1.a, v2. b + FROM v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) + GROUP BY v1.a; +SELECT v1.a, v2. b + FROM { OJ v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) } + GROUP BY v1.a; + +DROP VIEW v1,v2; +DROP TABLE t1,t2; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6473163a6ec..3f1790df63e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -448,6 +448,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token NUMERIC_SYM %token NVARCHAR_SYM %token OFFSET_SYM +%token OJ_SYM %token OLD_PASSWORD %token ON %token ONE_SHOT_SYM @@ -5246,11 +5247,14 @@ table_factor: } expr '}' { + LEX *lex= Lex; YYERROR_UNLESS($3 && $7); add_join_on($7,$10); Lex->pop_context(); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; + if (!($$= lex->current_select->nest_last_join(lex->thd))) + YYABORT; } | select_derived_init get_select_lex select_derived2 { From d388da989e538cfd68a1d606f7e4d109a0263906 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 14 May 2006 20:09:09 +0300 Subject: [PATCH 26/41] BUG#14157: utf8 encoding in binlog without set character_set_client fixing names length. Got an issue when merged to 5.0, decided to fix starting from 4.1 mysql-test/t/mysqlbinlog.test: fixing temp table name to fit to 64 bytes for 5.0 mysql-test/t/rpl_temporary.test: fixing temp table name to fit to 64 bytes for 5.0 --- mysql-test/t/mysqlbinlog.test | 2 +- mysql-test/t/rpl_temporary.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 7b6c36bb8c9..6e3daaef0c3 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -118,7 +118,7 @@ select HEX(f) from t4; #14157: utf8 encoding in binlog without set character_set_client # flush logs; ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t5 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t5 select * from `ящик`' # resulted log is client charset insensitive (latin1 not koi8r) as it must be --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 609e8533849..871ff096476 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -164,7 +164,7 @@ drop table t1; # #14157: utf8 encoding in binlog without set character_set_client # ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `только герои срезают рашпилем грим` (a int); insert into `только герои срезают рашпилем грим` values (1); insert into t1 select * from `только герои срезают рашпилем грим`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t1 select * from `ящик`' sync_slave_with_master; #connection slave; From b9558d8bdaf68c923d2f9940b37eb161fd116e73 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 14 May 2006 20:31:42 +0300 Subject: [PATCH 27/41] BUG#19188: incorrect temporary table name of DROP query in replication manual merge to account 5.0 specific names of TABLE class sql/mysql_priv.h: manual merge: changing to 5.0's TABLE class names sql/sql_base.cc: manual merge: whitespaces and 5.0 TABLE's names --- sql/mysql_priv.h | 2 +- sql/sql_base.cc | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9aa5c3e41d5..776c23a21a6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1602,7 +1602,7 @@ inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo) inline bool is_user_table(TABLE * table) { - const char *name= table->real_name; + const char *name= table->s->table_name; return strncmp(name, tmp_file_prefix, tmp_file_prefix_length); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f0480a1c616..b6694edea78 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -620,7 +620,7 @@ void close_temporary_tables(THD *thd) TABLE *table; if (!thd->temporary_tables) return; - + if (!mysql_bin_log.is_open()) { for (table= thd->temporary_tables; table; table= table->next) @@ -642,12 +642,12 @@ void close_temporary_tables(THD *thd) String s_query= String(buf, sizeof(buf), system_charset_info); bool found_user_tables= false; LINT_INIT(next); - - /* - insertion sort of temp tables by pseudo_thread_id to build ordered list + + /* + insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id */ - + for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) @@ -657,7 +657,7 @@ void close_temporary_tables(THD *thd) { if (!found_user_tables) found_user_tables= true; - for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; + for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; prev_sorted= sorted, sorted= sorted->next) { if (!is_user_table(sorted) || @@ -666,7 +666,7 @@ void close_temporary_tables(THD *thd) /* move into the sorted part of the list from the unsorted */ prev_table->next= table->next; table->next= sorted; - if (prev_sorted) + if (prev_sorted) { prev_sorted->next= table; } @@ -687,11 +687,11 @@ void close_temporary_tables(THD *thd) { thd->options |= OPTION_QUOTE_SHOW_CREATE; } - + /* scan sorted tmps to generate sequence of DROP */ for (table= thd->temporary_tables; table; table= next) { - if (is_user_table(table)) + if (is_user_table(table)) { /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); @@ -706,10 +706,10 @@ void close_temporary_tables(THD *thd) We are going to add 4 ` around the db/table names and possible more due to special characters in the names */ - append_identifier(thd, &s_query, table->table_cache_key, strlen(table->table_cache_key)); + append_identifier(thd, &s_query, table->s->db, strlen(table->s->db)); s_query.q_append('.'); - append_identifier(thd, &s_query, table->real_name, - strlen(table->real_name)); + append_identifier(thd, &s_query, table->s->table_name, + strlen(table->s->table_name)); s_query.q_append(','); next= table->next; close_temporary(table, 1); @@ -730,7 +730,7 @@ void close_temporary_tables(THD *thd) qinfo.error_code= 0; write_binlog_with_system_charset(thd, &qinfo); } - else + else { next= table->next; close_temporary(table, 1); From dccd333ecf4d566029c40e18bee33f6019bc2420 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 15 May 2006 12:01:55 +0200 Subject: [PATCH 28/41] BUG#18037: Fix stack corruption in THD::rollback_item_tree_changes(). Stored procedure execution sometimes placed the address of auto variables in the list of Item changes to undo in THD::rollback_item_tree_changes(). This could cause stack corruption. sql/sp_head.cc: Avoid storing address of auto variables in global rollback list, to prevent stack memory corruption. sql/sp_head.h: Avoid storing address of auto variables in global rollback list, to prevent stack memory corruption. sql/sp_rcontext.cc: Avoid storing address of auto variables in global rollback list, to prevent stack memory corruption. sql/sp_rcontext.h: Avoid storing address of auto variables in global rollback list, to prevent stack memory corruption. sql/sql_class.cc: Avoid storing address of auto variables in global rollback list, to prevent stack memory corruption. --- sql/sp_head.cc | 28 +++++++++++++++------------- sql/sp_head.h | 2 +- sql/sp_rcontext.cc | 13 +++++++------ sql/sp_rcontext.h | 8 ++++---- sql/sql_class.cc | 2 +- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6a7676c7bf2..d1da6f7d3b3 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -310,11 +310,13 @@ sp_prepare_func_item(THD* thd, Item **it_addr) */ bool -sp_eval_expr(THD *thd, Field *result_field, Item *expr_item) +sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) { + Item *expr_item; + DBUG_ENTER("sp_eval_expr"); - if (!(expr_item= sp_prepare_func_item(thd, &expr_item))) + if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr))) DBUG_RETURN(TRUE); bool err_status= FALSE; @@ -1269,7 +1271,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, param_values[i]= Item_cache::get_cache(argp[i]->result_type()); param_values[i]->store(argp[i]); - if (nctx->set_variable(thd, i, param_values[i])) + if (nctx->set_variable(thd, i, (struct Item **)&(param_values[i]))) { err_status= TRUE; break; @@ -1467,7 +1469,7 @@ sp_head::execute_procedure(THD *thd, List *args) Item_null *null_item= new Item_null(); if (!null_item || - nctx->set_variable(thd, i, null_item)) + nctx->set_variable(thd, i, (struct Item **)&null_item)) { err_status= TRUE; break; @@ -1475,7 +1477,7 @@ sp_head::execute_procedure(THD *thd, List *args) } else { - if (nctx->set_variable(thd, i, *it_args.ref())) + if (nctx->set_variable(thd, i, it_args.ref())) { err_status= TRUE; break; @@ -1531,7 +1533,7 @@ sp_head::execute_procedure(THD *thd, List *args) { if (octx->set_variable(thd, ((Item_splocal*) arg_item)->get_var_idx(), - nctx->get_item(i))) + nctx->get_item_addr(i))) { err_status= TRUE; break; @@ -1543,15 +1545,15 @@ sp_head::execute_procedure(THD *thd, List *args) if (guv) { - Item *item= nctx->get_item(i); + Item **item= nctx->get_item_addr(i); Item_func_set_user_var *suv; - suv= new Item_func_set_user_var(guv->get_name(), item); + suv= new Item_func_set_user_var(guv->get_name(), *item); /* Item_func_set_user_var is not fixed after construction, call fix_fields(). */ - if ((err_status= test(!suv || suv->fix_fields(thd, &item) || + if ((err_status= test(!suv || suv->fix_fields(thd, item) || suv->check() || suv->update()))) break; } @@ -2328,7 +2330,7 @@ sp_instr_set::execute(THD *thd, uint *nextp) int sp_instr_set::exec_core(THD *thd, uint *nextp) { - int res= thd->spcont->set_variable(thd, m_offset, m_value); + int res= thd->spcont->set_variable(thd, m_offset, &m_value); if (res && thd->spcont->found_handler_here()) { @@ -2603,7 +2605,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) do it in scope of execution the current context/block. */ - return thd->spcont->set_return_value(thd, m_value); + return thd->spcont->set_return_value(thd, &m_value); } void @@ -3047,7 +3049,7 @@ sp_instr_set_case_expr::execute(THD *thd, uint *nextp) int sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) { - int res= thd->spcont->set_case_expr(thd, m_case_expr_id, m_case_expr); + int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr); if (res && !thd->spcont->get_case_expr(m_case_expr_id) && @@ -3061,7 +3063,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) Item *null_item= new Item_null(); if (!null_item || - thd->spcont->set_case_expr(thd, m_case_expr_id, null_item)) + thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) { /* If this also failed, we have to abort. */ diff --git a/sql/sp_head.h b/sql/sp_head.h index 6a9cf97d739..d5f49d8a964 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1169,6 +1169,6 @@ Item * sp_prepare_func_item(THD* thd, Item **it_addr); bool -sp_eval_expr(THD *thd, Field *result_field, Item *expr_item); +sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr); #endif /* _SP_HEAD_H_ */ diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 38b6de0e75a..3bc27a029d0 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -150,7 +150,7 @@ sp_rcontext::init_var_items() bool -sp_rcontext::set_return_value(THD *thd, Item *return_value_item) +sp_rcontext::set_return_value(THD *thd, Item **return_value_item) { DBUG_ASSERT(m_return_value_fld); @@ -279,14 +279,14 @@ sp_rcontext::pop_cursors(uint count) int -sp_rcontext::set_variable(THD *thd, uint var_idx, Item *value) +sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value) { return set_variable(thd, m_var_table->field[var_idx], value); } int -sp_rcontext::set_variable(THD *thd, Field *field, Item *value) +sp_rcontext::set_variable(THD *thd, Field *field, Item **value) { if (!value) { @@ -478,9 +478,10 @@ sp_rcontext::create_case_expr_holder(THD *thd, Item_result result_type) */ int -sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item) +sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr) { - if (!(case_expr_item= sp_prepare_func_item(thd, &case_expr_item))) + Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr); + if (!case_expr_item) return TRUE; if (!m_case_expr_holders[case_expr_id] || @@ -542,7 +543,7 @@ bool Select_fetch_into_spvars::send_data(List &items) */ for (; spvar= spvar_iter++, item= item_iter++; ) { - if (thd->spcont->set_variable(thd, spvar->offset, item)) + if (thd->spcont->set_variable(thd, spvar->offset, &item)) return TRUE; } return FALSE; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 20aaea3b7c1..30521f6da84 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -91,7 +91,7 @@ class sp_rcontext : public Sql_alloc ~sp_rcontext(); int - set_variable(THD *thd, uint var_idx, Item *value); + set_variable(THD *thd, uint var_idx, Item **value); Item * get_item(uint var_idx); @@ -100,7 +100,7 @@ class sp_rcontext : public Sql_alloc get_item_addr(uint var_idx); bool - set_return_value(THD *thd, Item *return_value_item); + set_return_value(THD *thd, Item **return_value_item); inline bool is_return_value_set() const @@ -200,7 +200,7 @@ class sp_rcontext : public Sql_alloc */ int - set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item); + set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr); Item * get_case_expr(int case_expr_id); @@ -254,7 +254,7 @@ private: Item_cache *create_case_expr_holder(THD *thd, Item_result result_type); - int set_variable(THD *thd, Field *field, Item *value); + int set_variable(THD *thd, Field *field, Item **value); }; // class sp_rcontext : public Sql_alloc diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 026c3e0d515..65fd4d3ac19 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1877,7 +1877,7 @@ bool select_dumpvar::send_data(List &items) if ((yy=var_li++)) { if (thd->spcont->set_variable(current_thd, yy->get_var_idx(), - *it.ref())) + it.ref())) DBUG_RETURN(1); } } From 8069b05da0b23e5bcc3c410f7ee4669afea41714 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 15 May 2006 17:25:37 +0400 Subject: [PATCH 29/41] Applied innodb-4.1-ss29 snapshot. Fix BUG#19542 "InnoDB doesn't increase the Handler_read_prev counter. innobase/os/os0file.c: Applied innodb-4.1-ss29 snapshot. Check the page trailers also after writing to disk. This improves the chances of diagnosing Bug 18886. os_file_check_page_trailers(): New function for checking that two copies of the LSN stamped on the pages match. os_aio_simulated_handle(): Call os_file_check_page_trailers() before and after os_file_write(). sql/ha_innodb.cc: Applied innodb-4.1-ss29 snapshot. Increment statistic counter in ha_innobase::index_prev(). --- innobase/os/os0file.c | 61 ++++++++++++++++++++++++++----------------- sql/ha_innodb.cc | 2 ++ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 6ef6f7cd545..4c90c95c0bd 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -3613,6 +3613,37 @@ os_aio_posix_handle( } #endif +/************************************************************************** +Do a 'last millisecond' check that the page end is sensible; +reported page checksum errors from Linux seem to wipe over the page end. */ +static +void +os_file_check_page_trailers( +/*========================*/ + byte* combined_buf, /* in: combined write buffer */ + ulint total_len) /* in: size of combined_buf, in bytes + (a multiple of UNIV_PAGE_SIZE) */ +{ + ulint len; + + for (len = 0; len + UNIV_PAGE_SIZE <= total_len; + len += UNIV_PAGE_SIZE) { + byte* buf = combined_buf + len; + + if (memcmp(buf + (FIL_PAGE_LSN + 4), buf + (UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4), 4)) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: ERROR: The page to be written seems corrupt!\n" +"InnoDB: Writing a block of %lu bytes, currently at offset %lu\n", + (ulong)total_len, (ulong)len); + buf_page_print(buf); + fprintf(stderr, +"InnoDB: ERROR: The page to be written seems corrupt!\n"); + } + } +} + /************************************************************************** Does simulated aio. This function should be called by an i/o-handler thread. */ @@ -3650,7 +3681,6 @@ os_aio_simulated_handle( ibool ret; ulint n; ulint i; - ulint len2; segment = os_aio_get_array_and_local_segment(&array, global_segment); @@ -3857,33 +3887,16 @@ consecutive_loop: (ulong) total_len); ut_error; } - - /* Do a 'last millisecond' check that the page end - is sensible; reported page checksum errors from - Linux seem to wipe over the page end */ - for (len2 = 0; len2 + UNIV_PAGE_SIZE <= total_len; - len2 += UNIV_PAGE_SIZE) { - if (mach_read_from_4(combined_buf + len2 - + FIL_PAGE_LSN + 4) - != mach_read_from_4(combined_buf + len2 - + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) { - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: ERROR: The page to be written seems corrupt!\n"); - fprintf(stderr, -"InnoDB: Writing a block of %lu bytes, currently writing at offset %lu\n", - (ulong)total_len, (ulong)len2); - buf_page_print(combined_buf + len2); - fprintf(stderr, -"InnoDB: ERROR: The page to be written seems corrupt!\n"); - } - } + os_file_check_page_trailers(combined_buf, total_len); } - + ret = os_file_write(slot->name, slot->file, combined_buf, slot->offset, slot->offset_high, total_len); + + if (array == os_aio_write_array) { + os_file_check_page_trailers(combined_buf, total_len); + } } else { ret = os_file_read(slot->file, combined_buf, slot->offset, slot->offset_high, total_len); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 8455bbaf4d0..6c93ac293d0 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3431,6 +3431,8 @@ ha_innobase::index_prev( mysql_byte* buf) /* in/out: buffer for previous row in MySQL format */ { + statistic_increment(ha_read_prev_count, &LOCK_status); + return(general_fetch(buf, ROW_SEL_PREV, 0)); } From c55912b09ed31596502b693d1939b94aeb193279 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 15 May 2006 18:02:21 +0400 Subject: [PATCH 30/41] Applied innodb-5.0-ss547 snapshot. Fix BUG#19542 "InnoDB doesn't increase the Handler_read_prev counter". innobase/os/os0file.c: Applied innodb-5.0-ss547 snapshot. Check the page trailers also after writing to disk. This improves the chances of diagnosing Bug 18886. os_file_check_page_trailers(): New function for checking that two copies of the LSN stamped on the pages match. os_aio_simulated_handle(): Call os_file_check_page_trailers() before and after os_file_write(). sql/ha_innodb.cc: Applied innodb-5.0-ss547 snapshot. Increment statistic counter in ha_innobase::index_prev(). --- innobase/os/os0file.c | 61 ++++++++++++++++++++++++++----------------- sql/ha_innodb.cc | 3 +++ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 3b8f7576049..df819b73ea6 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -3699,6 +3699,37 @@ os_aio_posix_handle( } #endif +/************************************************************************** +Do a 'last millisecond' check that the page end is sensible; +reported page checksum errors from Linux seem to wipe over the page end. */ +static +void +os_file_check_page_trailers( +/*========================*/ + byte* combined_buf, /* in: combined write buffer */ + ulint total_len) /* in: size of combined_buf, in bytes + (a multiple of UNIV_PAGE_SIZE) */ +{ + ulint len; + + for (len = 0; len + UNIV_PAGE_SIZE <= total_len; + len += UNIV_PAGE_SIZE) { + byte* buf = combined_buf + len; + + if (memcmp(buf + (FIL_PAGE_LSN + 4), buf + (UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4), 4)) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: ERROR: The page to be written seems corrupt!\n" +"InnoDB: Writing a block of %lu bytes, currently at offset %lu\n", + (ulong)total_len, (ulong)len); + buf_page_print(buf); + fprintf(stderr, +"InnoDB: ERROR: The page to be written seems corrupt!\n"); + } + } +} + /************************************************************************** Does simulated aio. This function should be called by an i/o-handler thread. */ @@ -3736,7 +3767,6 @@ os_aio_simulated_handle( ibool ret; ulint n; ulint i; - ulint len2; segment = os_aio_get_array_and_local_segment(&array, global_segment); @@ -3943,33 +3973,16 @@ consecutive_loop: (ulong) total_len); ut_error; } - - /* Do a 'last millisecond' check that the page end - is sensible; reported page checksum errors from - Linux seem to wipe over the page end */ - for (len2 = 0; len2 + UNIV_PAGE_SIZE <= total_len; - len2 += UNIV_PAGE_SIZE) { - if (mach_read_from_4(combined_buf + len2 - + FIL_PAGE_LSN + 4) - != mach_read_from_4(combined_buf + len2 - + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) { - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: ERROR: The page to be written seems corrupt!\n"); - fprintf(stderr, -"InnoDB: Writing a block of %lu bytes, currently writing at offset %lu\n", - (ulong)total_len, (ulong)len2); - buf_page_print(combined_buf + len2); - fprintf(stderr, -"InnoDB: ERROR: The page to be written seems corrupt!\n"); - } - } + os_file_check_page_trailers(combined_buf, total_len); } - + ret = os_file_write(slot->name, slot->file, combined_buf, slot->offset, slot->offset_high, total_len); + + if (array == os_aio_write_array) { + os_file_check_page_trailers(combined_buf, total_len); + } } else { ret = os_file_read(slot->file, combined_buf, slot->offset, slot->offset_high, total_len); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 934437e0c91..28cdfd23b6a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4048,6 +4048,9 @@ ha_innobase::index_prev( mysql_byte* buf) /* in/out: buffer for previous row in MySQL format */ { + statistic_increment(current_thd->status_var.ha_read_prev_count, + &LOCK_status); + return(general_fetch(buf, ROW_SEL_PREV, 0)); } From b6c7f5f2a80e6123f0106254c6c56af8f33f12d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 15 May 2006 18:05:23 +0300 Subject: [PATCH 31/41] BUG#14157: utf8 encoding in binlog without set character_set_client: e.g DROP temporary specific to 5.0 version of the patch is motivated by the fact that a wrapper over MYSQLLOG::write can not help in 5.0 where query's charset is embedded into event instance in the constructor. sql/mysql_priv.h: this 4.1 specific code does not help in 5.0 sql/sql_base.cc: No wrapper similar to 4.1's version is done since Query_log_event constructor takes care of encodings in 5.0 whereas log::write method does it in 4.1. We can introduce an additional constuctor for Query_log_event to pass desired (i.e system_character_info) charset different from THD's version. But I am delaying this while there are not more bugs similar to this one reported. --- sql/mysql_priv.h | 13 ------------- sql/sql_base.cc | 5 ++++- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 776c23a21a6..0290c0178e0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1582,19 +1582,6 @@ inline int hexchar_to_int(char c) return -1; } -/* - wrapper to use instead of mysql_bin_log.write when - query is generated by the server using system_charset encoding -*/ - -inline void write_binlog_with_system_charset(THD * thd, Query_log_event * qinfo) -{ - CHARSET_INFO * cs_save= thd->variables.character_set_client; - thd->variables.character_set_client= system_charset_info; - mysql_bin_log.write(qinfo); - thd->variables.character_set_client= cs_save; -} - /* is_user_table() return true if the table was created explicitly diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b6694edea78..c83e847bc8a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -715,9 +715,12 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1); } thd->clear_error(); + CHARSET_INFO *cs_save= thd->variables.character_set_client; + thd->variables.character_set_client= system_charset_info; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE); + thd->variables.character_set_client= cs_save; /* Imagine the thread had created a temp table, then was doing a SELECT, and the SELECT was killed. Then it's not clever to mark the statement above as @@ -728,7 +731,7 @@ void close_temporary_tables(THD *thd) rightfully causing the slave to stop. */ qinfo.error_code= 0; - write_binlog_with_system_charset(thd, &qinfo); + mysql_bin_log.write(&qinfo); } else { From 798e910bad712f24144a04403bcc46de04ead643 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 15 May 2006 19:57:10 +0200 Subject: [PATCH 32/41] After-merge fixes; some function signatures changed from Item * to Item **. sql/item.cc: After-merge fixes. sql/item.h: After-merge fixes. sql/item_func.cc: After-merge fixes. sql/item_func.h: After-merge fixes. sql/sp_head.cc: After-merge fixes. --- sql/item.cc | 6 +++--- sql/item.h | 8 ++++---- sql/item_func.cc | 6 +++--- sql/item_func.h | 2 +- sql/sp_head.cc | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index fbdb0aa687b..ba378e56cb0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -958,7 +958,7 @@ void Item_splocal::print(String *str) } -bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item *it) +bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it) { return ctx->set_variable(thd, get_var_idx(), it); } @@ -5375,9 +5375,9 @@ void Item_trigger_field::set_required_privilege(const bool rw) } -bool Item_trigger_field::set_value(THD *thd, sp_rcontext */*ctx*/, Item *it) +bool Item_trigger_field::set_value(THD *thd, sp_rcontext */*ctx*/, Item **it) { - Item *item= sp_prepare_func_item(thd, &it); + Item *item= sp_prepare_func_item(thd, it); return (!item || (!fixed && fix_fields(thd, 0)) || (item->save_in_field(field, 0) < 0)); diff --git a/sql/item.h b/sql/item.h index 617690e1fd9..cfc2306f15d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -404,7 +404,7 @@ public: FALSE if parameter value has been set, TRUE if error has occured. */ - virtual bool set_value(THD *thd, sp_rcontext *ctx, Item *it)= 0; + virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0; }; @@ -928,7 +928,7 @@ public: inline Item_result result_type() const; private: - bool set_value(THD *thd, sp_rcontext *ctx, Item *it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); public: Settable_routine_parameter *get_settable_routine_parameter() @@ -2188,7 +2188,7 @@ public: private: void set_required_privilege(const bool rw); - bool set_value(THD *thd, sp_rcontext *ctx, Item *it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); public: Settable_routine_parameter *get_settable_routine_parameter() @@ -2196,7 +2196,7 @@ public: return (read_only ? 0 : this); } - bool set_value(THD *thd, Item *it) + bool set_value(THD *thd, Item **it) { return set_value(thd, NULL, it); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 058650fb17f..5ef9db6f52b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4121,14 +4121,14 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const bool Item_func_get_user_var::set_value(THD *thd, - sp_rcontext */*ctx*/, Item *it) + sp_rcontext */*ctx*/, Item **it) { - Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), it); + Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), *it); /* Item_func_set_user_var is not fixed after construction, call fix_fields(). */ - return (!suv || suv->fix_fields(thd, &it) || suv->check() || suv->update()); + return (!suv || suv->fix_fields(thd, it) || suv->check() || suv->update()); } diff --git a/sql/item_func.h b/sql/item_func.h index 890927aaccd..1d8a1bd5e22 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1209,7 +1209,7 @@ public: bool eq(const Item *item, bool binary_cmp) const; private: - bool set_value(THD *thd, sp_rcontext *ctx, Item *it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); public: Settable_routine_parameter *get_settable_routine_parameter() diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d5c57eca76e..174f62c9497 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1552,7 +1552,7 @@ sp_head::execute_procedure(THD *thd, List *args) DBUG_ASSERT(srp); - if (srp->set_value(thd, octx, nctx->get_item(i))) + if (srp->set_value(thd, octx, nctx->get_item_addr(i))) { err_status= TRUE; break; @@ -2393,7 +2393,7 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) int sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) { - const int res= (trigger_field->set_value(thd, value) ? -1 : 0); + const int res= (trigger_field->set_value(thd, &value) ? -1 : 0); *nextp = m_ip+1; return res; } From bccff08cba9994f12acf52e6aa960c32e949dd9d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 May 2006 09:26:57 +0200 Subject: [PATCH 33/41] Fixed result file (rpl_temporary) mysql-test/r/rpl_temporary.result: Fixed result file --- mysql-test/r/rpl_temporary.result | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index da85ef5104d..751dc7754f7 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -103,15 +103,24 @@ f 1 drop temporary table t4; drop table t5; -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); +create temporary table `t``201` (id int); +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; f 1 drop table t1; +select * from t1; +a +1 +drop table t1; From 808f77f6b003bbd225c21905b0f204bbcb61d457 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 May 2006 10:01:07 +0200 Subject: [PATCH 34/41] Test used a charset not available on many platforms --- mysql-test/r/mysqlbinlog.result | 6 +----- mysql-test/t/mysqlbinlog.test | 15 ++++++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index c3be791b523..664833fab2a 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -190,8 +190,4 @@ select HEX(f) from t4; HEX(f) 835C flush logs; -select * from t5 /* must be (1),(1) */; -a -1 -1 -drop table t1, t2, t03, t04, t3, t4, t5; +drop table t1, t2, t03, t04, t3, t4; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 843536e956d..d74bb1c3a80 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -123,16 +123,21 @@ select HEX(f) from t04; select HEX(f) from t4; # -#14157: utf8 encoding in binlog without set character_set_client +# BUG#14157: utf8 encoding in binlog without set character_set_client +# +# BUG: +# This test only works on the MySQL-internal rpl machines. +# Needs to be fixed. Problem is that koi8r is not installed +# on many machines. # flush logs; ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t5 select * from `ящик`' +# --exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ящик` (a int); insert into `ящик` values (1); insert into t5 select * from `ящик`' # resulted log is client charset insensitive (latin1 not koi8r) as it must be ---exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 -select * from t5 /* must be (1),(1) */; +# --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 +#select * from t5 /* must be (1),(1) */; # clean up -drop table t1, t2, t03, t04, t3, t4, t5; +drop table t1, t2, t03, t04, t3, t4; # End of 5.0 tests From 345cd57a34886518530749262bc0e3c529253148 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 May 2006 10:08:13 +0930 Subject: [PATCH 35/41] rpl_auto_increment_11932.result, rpl_auto_increment_11932.test: Update with correct table and database names. mysql-test/t/rpl_auto_increment_11932.test: Update with correct table and database names. mysql-test/r/rpl_auto_increment_11932.result: Update with correct table and database names. --- mysql-test/r/rpl_auto_increment_11932.result | 32 ++++++++--------- mysql-test/t/rpl_auto_increment_11932.test | 36 +++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/mysql-test/r/rpl_auto_increment_11932.result b/mysql-test/r/rpl_auto_increment_11932.result index 753e9e9f223..d3bf052f0c9 100644 --- a/mysql-test/r/rpl_auto_increment_11932.result +++ b/mysql-test/r/rpl_auto_increment_11932.result @@ -4,43 +4,43 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -drop database if exists t1; -create database t1; -use t1; -CREATE TABLE `t` ( +drop database if exists test1; +create database test1; +use test1; +CREATE TABLE `t1` ( `id` int(10) unsigned NOT NULL auto_increment, `fname` varchar(100) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; -INSERT INTO `t` VALUES (1, 'blablabla'); -CREATE TABLE `test3` ( +INSERT INTO `t1` VALUES (1, 'blablabla'); +CREATE TABLE `t2` ( `id` int(10) NOT NULL auto_increment, `comment` varchar(255) NOT NULL default '', PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=3 ; -INSERT INTO `test3` VALUES (1, 'testtest 1'); -INSERT INTO `test3` VALUES (2, 'test 2'); +INSERT INTO `t2` VALUES (1, 'testtest 1'); +INSERT INTO `t2` VALUES (2, 'test 2'); CREATE PROCEDURE simpleproc3 () NOT DETERMINISTIC BEGIN -INSERT INTO t (fname) (SELECT test3.comment FROM test3 WHERE test3.id = '1'); -INSERT INTO t (fname) VALUES('test'); +INSERT INTO t1 (fname) (SELECT t2.comment FROM t2 WHERE t2.id = '1'); +INSERT INTO t1 (fname) VALUES('test'); END $ CALL simpleproc3(); -select * from test3; +select * from t2; id comment 1 testtest 1 2 test 2 -TRUNCATE TABLE `t`; +TRUNCATE TABLE `t1`; CALL simpleproc3(); -select * from t; +select * from t1; id fname 1 testtest 1 2 test -use t1; -select * from t; +use test1; +select * from t1; id fname 1 testtest 1 2 test -drop database t1; +drop database test1; diff --git a/mysql-test/t/rpl_auto_increment_11932.test b/mysql-test/t/rpl_auto_increment_11932.test index db9a11277ac..057b0c0911b 100644 --- a/mysql-test/t/rpl_auto_increment_11932.test +++ b/mysql-test/t/rpl_auto_increment_11932.test @@ -2,58 +2,60 @@ # Test of auto_increment # BUG#11932 # -# Test supplied by Are Casilla +# Bug reported that master and slave get out of sync after TRUNCATE +# TABLE. # +# Test supplied by Are Casilla source include/master-slave.inc; --disable_warnings connection master; -drop database if exists t1; +drop database if exists test1; --enable_warnings -create database t1; -use t1; +create database test1; +use test1; -CREATE TABLE `t` ( +CREATE TABLE `t1` ( `id` int(10) unsigned NOT NULL auto_increment, `fname` varchar(100) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; -INSERT INTO `t` VALUES (1, 'blablabla'); +INSERT INTO `t1` VALUES (1, 'blablabla'); -CREATE TABLE `test3` ( +CREATE TABLE `t2` ( `id` int(10) NOT NULL auto_increment, `comment` varchar(255) NOT NULL default '', PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=3 ; -INSERT INTO `test3` VALUES (1, 'testtest 1'); -INSERT INTO `test3` VALUES (2, 'test 2'); +INSERT INTO `t2` VALUES (1, 'testtest 1'); +INSERT INTO `t2` VALUES (2, 'test 2'); DELIMITER $; CREATE PROCEDURE simpleproc3 () NOT DETERMINISTIC BEGIN - INSERT INTO t (fname) (SELECT test3.comment FROM test3 WHERE test3.id = '1'); - INSERT INTO t (fname) VALUES('test'); + INSERT INTO t1 (fname) (SELECT t2.comment FROM t2 WHERE t2.id = '1'); + INSERT INTO t1 (fname) VALUES('test'); END $ DELIMITER ;$ CALL simpleproc3(); -select * from test3; +select * from t2; -TRUNCATE TABLE `t`; +TRUNCATE TABLE `t1`; CALL simpleproc3(); -select * from t; +select * from t1; save_master_pos; connection slave; sync_with_master; -use t1; -select * from t; +use test1; +select * from t1; -drop database t1; +drop database test1; From 6d3f0f8c2f11db22fe65d1c9599a3f6ee1166e65 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 May 2006 12:18:18 +0930 Subject: [PATCH 36/41] rpl_auto_increment_11932.test, rpl_auto_increment_11932.result: Drop test1 table in master as well. mysql-test/r/rpl_auto_increment_11932.result: Drop test1 table in master as well. mysql-test/t/rpl_auto_increment_11932.test: Drop test1 table in master as well. --- mysql-test/r/rpl_auto_increment_11932.result | 1 + mysql-test/t/rpl_auto_increment_11932.test | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mysql-test/r/rpl_auto_increment_11932.result b/mysql-test/r/rpl_auto_increment_11932.result index d3bf052f0c9..25eda6ee454 100644 --- a/mysql-test/r/rpl_auto_increment_11932.result +++ b/mysql-test/r/rpl_auto_increment_11932.result @@ -44,3 +44,4 @@ id fname 1 testtest 1 2 test drop database test1; +drop database test1; diff --git a/mysql-test/t/rpl_auto_increment_11932.test b/mysql-test/t/rpl_auto_increment_11932.test index 057b0c0911b..d4b7872fb2b 100644 --- a/mysql-test/t/rpl_auto_increment_11932.test +++ b/mysql-test/t/rpl_auto_increment_11932.test @@ -59,3 +59,5 @@ use test1; select * from t1; drop database test1; +connection master; +drop database test1; From 45710b7f477ba344aae5ddd2f9749707a8a2451b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 May 2006 17:30:28 +0930 Subject: [PATCH 37/41] BUG#17201: Improve handling of views. client/mysqldump.c: Better view handling: Distinguish better between tables and views in the output. Add many comments about the distinctions between tables and views, and the tradeoffs that we make, notably that, since we don't maintain dependencies. get_table_structure: Clarify in the output that a view is first created as a workaround for the lack of dependencies. dump_table: Return if we're trying to dump a view. dump_all_views_in_db: Don't call init_dumping. It's already been done in dump_all_tables_in_db. This is the problem reported in BUG#17201. Change the variable was_views to seen_views, and clarify the comment. The previous name was not overly "intuitive". mysql-test/r/mysqldump.result: We no longer have spurious text in the results. Add results for the final test (BUG#17201) mysql-test/t/mysqldump.test: Add a new test (BUG#17201) --- client/mysqldump.c | 892 +++++++++++++++++----------------- mysql-test/r/mysqldump.result | 98 +++- mysql-test/t/mysqldump.test | 15 + 3 files changed, 554 insertions(+), 451 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index ee6d7b9d12b..49d2b9ae78c 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -21,7 +21,7 @@ ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua) ** DATE: December 3, 1994 ** WARRANTY: None, expressed, impressed, implied -** or other +** or other ** STATUS: Public domain ** Adapted and optimized for MySQL by ** Michael Widenius, Sinisa Milivojevic, Jani Tolonen @@ -77,22 +77,22 @@ #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ static char *add_load_option(char *ptr, const char *object, - const char *statement); + const char *statement); static ulong find_set(TYPELIB *lib, const char *x, uint length, - char **err_pos, uint *err_len); + char **err_pos, uint *err_len); static char *alloc_query_str(ulong size); static char *field_escape(char *to,const char *from,uint length); static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1, - lock_tables=1,ignore_errors=0,flush_logs=0, - opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, + lock_tables=1,ignore_errors=0,flush_logs=0, + opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0, opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0, opt_set_charset=0, - opt_autocommit=0,opt_disable_keys=1,opt_xml=0, - opt_delete_master_logs=0, tty_password=0, - opt_single_transaction=0, opt_comments= 0, opt_compact= 0, - opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, + opt_autocommit=0,opt_disable_keys=1,opt_xml=0, + opt_delete_master_logs=0, tty_password=0, + opt_single_transaction=0, opt_comments= 0, opt_compact= 0, + opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, opt_complete_insert= 0, opt_drop_database= 0, opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1; static ulong opt_max_allowed_packet, opt_net_buffer_length; @@ -129,8 +129,8 @@ static const char *mysql_universal_client_charset= static char *default_charset; static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; -/* do we met VIEWs during tables scaning */ -my_bool was_views= 0; +/* have we seen any VIEWs during table scanning? */ +my_bool seen_views= 0; const char *compatible_mode_names[]= { @@ -149,7 +149,7 @@ const char *compatible_mode_names[]= (1<<10) /* ANSI */\ ) TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, - "", compatible_mode_names, NULL}; + "", compatible_mode_names, NULL}; HASH ignore_table; @@ -276,7 +276,7 @@ static struct my_option my_long_options[] = {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"lock-all-tables", 'x', "Locks all tables across all databases. This " + {"lock-all-tables", 'x', "Locks all tables across all databases. This " "is achieved by taking a global read lock for the duration of the whole " "dump. Automatically turns --single-transaction and --lock-tables off.", (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, @@ -297,7 +297,7 @@ static struct my_option my_long_options[] = GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "", (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0, - GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, + GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "", (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, @@ -411,8 +411,8 @@ static const char *load_default_groups[]= { "mysqldump","client",0 }; static void safe_exit(int error); static void write_header(FILE *sql_file, char *db_name); static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, - const char *prefix,const char *name, - int string_value); + const char *prefix,const char *name, + int string_value); static int dump_selected_tables(char *db, char **table_names, int tables); static int dump_all_tables_in_db(char *db); static int init_dumping(char *); @@ -428,10 +428,10 @@ static my_bool dump_all_views_in_db(char *database); /* exit with message if ferror(file) - + SYNOPSIS check_io() - file - checked file + file - checked file */ void check_io(FILE *file) @@ -456,7 +456,7 @@ static void short_usage_sub(void) { printf("Usage: %s [OPTIONS] database [tables]\n", my_progname); printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n", - my_progname); + my_progname); printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname); NETWARE_SET_SCREEN_MODE(1); } @@ -501,12 +501,12 @@ static void write_header(FILE *sql_file, char *db_name) { fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION); fprintf(sql_file, "-- Host: %s Database: %s\n", - current_host ? current_host : "localhost", db_name ? db_name : - ""); + current_host ? current_host : "localhost", db_name ? db_name : + ""); fputs("-- ------------------------------------------------------\n", - sql_file); + sql_file); fprintf(sql_file, "-- Server version\t%s\n", - mysql_get_server_info(&mysql_connection)); + mysql_get_server_info(&mysql_connection)); } if (opt_set_charset) fprintf(sql_file, @@ -529,10 +529,10 @@ static void write_header(FILE *sql_file, char *db_name) "); } fprintf(sql_file, - "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n" - "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n", - path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",", - compatible_mode_normal_str); + "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n" + "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n", + path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",", + compatible_mode_normal_str); check_io(sql_file); } } /* write_header */ @@ -563,7 +563,7 @@ static void write_footer(FILE *sql_file) "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n" "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"); fprintf(sql_file, - "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"); + "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"); fputs("\n", sql_file); check_io(sql_file); } @@ -577,7 +577,7 @@ static void free_table_ent(char *key) byte* get_table_key(const char *entry, uint *length, - my_bool not_used __attribute__((unused))) + my_bool not_used __attribute__((unused))) { *length= strlen(entry); return (byte*) entry; @@ -594,7 +594,7 @@ void init_table_rule_hash(HASH* h) static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) + char *argument) { switch (optid) { #ifdef __NETWARE__ @@ -608,9 +608,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *start=argument; my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); opt_password=my_strdup(argument,MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ + while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) - start[1]=0; /* Cut length of argument */ + start[1]=0; /* Cut length of argument */ tty_password= 0; } else @@ -618,7 +618,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'r': if (!(md_result_file = my_fopen(argument, O_WRONLY | FILE_BINARY, - MYF(MY_WME)))) + MYF(MY_WME)))) exit(1); break; case 'W': @@ -639,7 +639,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); case 'X': opt_xml = 1; - extended_insert= opt_drop= opt_lock= + extended_insert= opt_drop= opt_lock= opt_disable_keys= opt_autocommit= opt_create_db= 0; break; case 'I': @@ -692,36 +692,36 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_set_charset= 0; opt_compatible_mode_str= argument; opt_compatible_mode= find_set(&compatible_mode_typelib, - argument, strlen(argument), - &err_ptr, &err_len); + argument, strlen(argument), + &err_ptr, &err_len); if (err_len) { - strmake(buff, err_ptr, min(sizeof(buff), err_len)); - fprintf(stderr, "Invalid mode to --compatible: %s\n", buff); - exit(1); + strmake(buff, err_ptr, min(sizeof(buff), err_len)); + fprintf(stderr, "Invalid mode to --compatible: %s\n", buff); + exit(1); } #if !defined(DBUG_OFF) { - uint size_for_sql_mode= 0; - const char **ptr; - for (ptr= compatible_mode_names; *ptr; ptr++) - size_for_sql_mode+= strlen(*ptr); - size_for_sql_mode+= sizeof(compatible_mode_names)-1; - DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode); + uint size_for_sql_mode= 0; + const char **ptr; + for (ptr= compatible_mode_names; *ptr; ptr++) + size_for_sql_mode+= strlen(*ptr); + size_for_sql_mode+= sizeof(compatible_mode_names)-1; + DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode); } #endif mode= opt_compatible_mode; for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++) { - if (mode & 1) - { - end= strmov(end, compatible_mode_names[i]); - end= strmov(end, ","); - } + if (mode & 1) + { + end= strmov(end, compatible_mode_names[i]); + end= strmov(end, ","); + } } if (end!=compatible_mode_normal_str) - end[-1]= 0; - /* + end[-1]= 0; + /* Set charset to the default compiled value if it hasn't been reset yet by --default-character-set=xxx. */ @@ -733,8 +733,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); } break; } @@ -760,12 +760,12 @@ static int get_options(int *argc, char ***argv) *mysql_params->p_net_buffer_length= opt_net_buffer_length; if (opt_delayed) - opt_lock=0; /* Can't have lock with delayed */ + opt_lock=0; /* Can't have lock with delayed */ if (!path && (enclosed || opt_enclosed || escaped || lines_terminated || - fields_terminated)) + fields_terminated)) { fprintf(stderr, - "%s: You must use option --tab with --fields-...\n", my_progname); + "%s: You must use option --tab with --fields-...\n", my_progname); return(1); } @@ -777,7 +777,7 @@ static int get_options(int *argc, char ***argv) fprintf(stderr, "%s: You can't use --single-transaction and " "--lock-all-tables at the same time.\n", my_progname); return(1); - } + } if (opt_master_data) opt_lock_all_tables= !opt_single_transaction; if (opt_single_transaction || opt_lock_all_tables) @@ -790,13 +790,13 @@ static int get_options(int *argc, char ***argv) if ((opt_databases || opt_alldbs) && path) { fprintf(stderr, - "%s: --databases or --all-databases can't be used with --tab.\n", - my_progname); + "%s: --databases or --all-databases can't be used with --tab.\n", + my_progname); return(1); } if (strcmp(default_charset, charset_info->csname) && - !(charset_info= get_charset_by_csname(default_charset, - MY_CS_PRIMARY, MYF(MY_WME)))) + !(charset_info= get_charset_by_csname(default_charset, + MY_CS_PRIMARY, MYF(MY_WME)))) exit(1); if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs)) { @@ -816,7 +816,7 @@ static void DB_error(MYSQL *mysql, const char *when) { DBUG_ENTER("DB_error"); my_printf_error(0,"Got error: %d: %s %s", MYF(0), - mysql_errno(mysql), mysql_error(mysql), when); + mysql_errno(mysql), mysql_error(mysql), when); safe_exit(EX_MYSQLERR); DBUG_VOID_RETURN; } /* DB_error */ @@ -830,14 +830,14 @@ static void DB_error(MYSQL *mysql, const char *when) mysql_query_with_error_report() mysql_con connection to use res if non zero, result will be put there with - mysql_store_result() + mysql_store_result() query query to send to server RETURN VALUES 0 query sending and (if res!=0) result reading went ok 1 error */ - + static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res, const char *query) { @@ -869,7 +869,7 @@ static FILE* open_sql_file_for_table(const char* table) char filename[FN_REFLEN], tmp_path[FN_REFLEN]; convert_dirname(tmp_path,path,NullS); res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4), - O_WRONLY, MYF(MY_WME)); + O_WRONLY, MYF(MY_WME)); return res; } @@ -904,7 +904,7 @@ static int dbConnect(char *host, char *user,char *passwd) #ifdef HAVE_OPENSSL if (opt_use_ssl) mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); + opt_ssl_capath, opt_ssl_cipher); mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (char*)&opt_ssl_verify_server_cert); #endif @@ -933,7 +933,7 @@ static int dbConnect(char *host, char *user,char *passwd) */ sock->reconnect= 0; my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */", - compatible_mode_normal_str); + compatible_mode_normal_str); if (mysql_query_with_error_report(sock, 0, buff)) { mysql_close(sock); @@ -941,7 +941,7 @@ static int dbConnect(char *host, char *user,char *passwd) return 1; } /* - set time_zone to UTC to allow dumping date types between servers with + set time_zone to UTC to allow dumping date types between servers with different time zone settings */ if (opt_tz_utc) @@ -975,8 +975,8 @@ static void unescape(FILE *file,char *pos,uint length) DBUG_ENTER("unescape"); if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME)))) { - ignore_errors=0; /* Fatal error */ - safe_exit(EX_MYSQLERR); /* Force exit */ + ignore_errors=0; /* Fatal error */ + safe_exit(EX_MYSQLERR); /* Force exit */ } mysql_real_escape_string(&mysql_connection, tmp, pos, length); fputc('\'', file); @@ -1003,13 +1003,13 @@ static my_bool test_if_special_chars(const char *str) /* quote_name(name, buff, force) - Quotes char string, taking into account compatible mode + Quotes char string, taking into account compatible mode Args name Unquoted string containing that which will be quoted buff The buffer that contains the quoted value, also returned - force Flag to make it ignore 'test_if_special_chars' + force Flag to make it ignore 'test_if_special_chars' Returns @@ -1082,13 +1082,13 @@ static char *quote_for_like(const char *name, char *buff) /* Quote and print a string. - + SYNOPSIS print_quoted_xml() - output - output file - str - string to print - len - its length - + output - output file + str - string to print + len - its length + DESCRIPTION Quote '<' '>' '&' '\"' chars and print a string to the xml_file. */ @@ -1096,7 +1096,7 @@ static char *quote_for_like(const char *name, char *buff) static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) { const char *end; - + for (end= str + len; str != end; str++) { switch (*str) { @@ -1123,15 +1123,15 @@ static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) /* Print xml tag with one attribute. - + SYNOPSIS print_xml_tag1() - xml_file - output file - sbeg - line beginning - stag_atr - tag and attribute - sval - value of attribute - send - line ending - + xml_file - output file + sbeg - line beginning + stag_atr - tag and attribute + sval - value of attribute + send - line ending + DESCRIPTION Print tag with one attribute to the xml_file. Format is: sbegsend @@ -1141,8 +1141,8 @@ static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) */ static void print_xml_tag1(FILE * xml_file, const char* sbeg, - const char* stag_atr, const char* sval, - const char* send) + const char* stag_atr, const char* sval, + const char* send) { fputs(sbeg, xml_file); fputs("<", xml_file); @@ -1160,11 +1160,11 @@ static void print_xml_tag1(FILE * xml_file, const char* sbeg, SYNOPSIS print_xml_null_tag() - xml_file - output file - sbeg - line beginning - stag_atr - tag and attribute - sval - value of attribute - send - line ending + xml_file - output file + sbeg - line beginning + stag_atr - tag and attribute + sval - value of attribute + send - line ending DESCRIPTION Print tag with one attribute to the xml_file. Format is: @@ -1194,11 +1194,11 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg, SYNOPSIS print_xml_row() - xml_file - output file - row_name - xml tag name - tableRes - query result - row - result row - + xml_file - output file + row_name - xml tag name + tableRes - query result + row - result row + DESCRIPTION Print tag with many attribute to the xml_file. Format is: \t\t @@ -1207,7 +1207,7 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg, */ static void print_xml_row(FILE *xml_file, const char *row_name, - MYSQL_RES *tableRes, MYSQL_ROW *row) + MYSQL_RES *tableRes, MYSQL_ROW *row) { uint i; MYSQL_FIELD *field; @@ -1324,7 +1324,7 @@ static uint dump_routines_for_db(char *db) */ definer_begin= strstr(row[2], " DEFINER"); - + if (definer_begin) { char *definer_end= strstr(definer_begin, " PROCEDURE"); @@ -1388,7 +1388,7 @@ static uint dump_routines_for_db(char *db) ARGS table - table name db - db name - table_type - table type ie "InnoDB" + table_type - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW" ignore_flag - what we must particularly ignore - see IGNORE_ defines above RETURN @@ -1400,10 +1400,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, { my_bool init=0, delayed, write_data, complete_insert; my_ulonglong num_fields; - char *result_table, *opt_quoted_table; + char *result_table, *opt_quoted_table; const char *insert_option; - char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; - char table_buff2[NAME_LEN*2+3], query_buff[512]; + char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; + char table_buff2[NAME_LEN*2+3], query_buff[512]; FILE *sql_file = md_result_file; int len; MYSQL_RES *result; @@ -1473,21 +1473,30 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (!(sql_file= open_sql_file_for_table(table))) { - safe_exit(EX_MYSQLERR); - DBUG_RETURN(0); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); } write_header(sql_file, db); } if (!opt_xml && opt_comments) { + if (strcmp (table_type, "VIEW") == 0) /* view */ + fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n", + result_table); + else fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", - result_table); - check_io(sql_file); + result_table); + check_io(sql_file); } if (opt_drop) { - fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); - check_io(sql_file); + /* + Even if the "table" is a view, we do a DROP TABLE here. The + view-specific code below fills in the DROP VIEW. + */ + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", + opt_quoted_table); + check_io(sql_file); } result= mysql_store_result(sock); @@ -1500,7 +1509,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, mysql_free_result(result); /* - Create a table with the same name as the view and with columns of + Create a table with the same name as the view and with columns of the same name in order to satisfy views that depend on this view. The table will be removed when the actual view is created. @@ -1524,10 +1533,13 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (opt_drop) { + /* + We have already dropped any table of the same name + above, so here we just drop the view. + */ + fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", opt_quoted_table); - fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n", - opt_quoted_table); check_io(sql_file); } @@ -1554,7 +1566,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, } mysql_free_result(result); - was_views= 1; + seen_views= 1; DBUG_RETURN(0); } @@ -1564,11 +1576,11 @@ static uint get_table_structure(char *table, char *db, char *table_type, mysql_free_result(result); } my_snprintf(query_buff, sizeof(query_buff), "show fields from %s", - result_table); + result_table); if (mysql_query_with_error_report(sock, &result, query_buff)) { if (path) - my_fclose(sql_file, MYF(MY_WME)); + my_fclose(sql_file, MYF(MY_WME)); safe_exit(EX_MYSQLERR); DBUG_RETURN(0); } @@ -1621,7 +1633,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, my_progname, mysql_error(sock)); my_snprintf(query_buff, sizeof(query_buff), "show fields from %s", - result_table); + result_table); if (mysql_query_with_error_report(sock, &result, query_buff)) { safe_exit(EX_MYSQLERR); @@ -1635,18 +1647,18 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (!(sql_file= open_sql_file_for_table(table))) { - safe_exit(EX_MYSQLERR); - DBUG_RETURN(0); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); } write_header(sql_file, db); } if (!opt_xml && opt_comments) - fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", - result_table); + fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", + result_table); if (opt_drop) fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table); if (!opt_xml) - fprintf(sql_file, "CREATE TABLE %s (\n", result_table); + fprintf(sql_file, "CREATE TABLE %s (\n", result_table); else print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n"); check_io(sql_file); @@ -1674,10 +1686,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (init) { if (!opt_xml && !tFlag) - { - fputs(",\n",sql_file); - check_io(sql_file); - } + { + fputs(",\n",sql_file); + check_io(sql_file); + } if (complete_insert) dynstr_append_mem(&insert_pat, ", ", 2); } @@ -1687,30 +1699,30 @@ static uint get_table_structure(char *table, char *db, char *table_type, quote_name(row[SHOW_FIELDNAME], name_buff, 0)); if (!tFlag) { - if (opt_xml) - { - print_xml_row(sql_file, "field", result, &row); - continue; - } + if (opt_xml) + { + print_xml_row(sql_file, "field", result, &row); + continue; + } if (opt_keywords) - fprintf(sql_file, " %s.%s %s", result_table, - quote_name(row[SHOW_FIELDNAME],name_buff, 0), - row[SHOW_TYPE]); + fprintf(sql_file, " %s.%s %s", result_table, + quote_name(row[SHOW_FIELDNAME],name_buff, 0), + row[SHOW_TYPE]); else - fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME], - name_buff, 0), - row[SHOW_TYPE]); + fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME], + name_buff, 0), + row[SHOW_TYPE]); if (row[SHOW_DEFAULT]) { - fputs(" DEFAULT ", sql_file); - unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]); + fputs(" DEFAULT ", sql_file); + unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]); } if (!row[SHOW_NULL][0]) - fputs(" NOT NULL", sql_file); + fputs(" NOT NULL", sql_file); if (row[SHOW_EXTRA][0]) - fprintf(sql_file, " %s",row[SHOW_EXTRA]); - check_io(sql_file); + fprintf(sql_file, " %s",row[SHOW_EXTRA]); + check_io(sql_file); } } num_fields= mysql_num_rows(result); @@ -1730,9 +1742,9 @@ static uint get_table_structure(char *table, char *db, char *table_type, goto continue_xml; } fprintf(stderr, "%s: Can't get keys for table %s (%s)\n", - my_progname, result_table, mysql_error(sock)); + my_progname, result_table, mysql_error(sock)); if (path) - my_fclose(sql_file, MYF(MY_WME)); + my_fclose(sql_file, MYF(MY_WME)); safe_exit(EX_MYSQLERR); DBUG_RETURN(0); } @@ -1744,102 +1756,102 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (atoi(row[3]) == 1) { - keynr++; + keynr++; #ifdef FORCE_PRIMARY_KEY - if (atoi(row[1]) == 0 && primary_key == INT_MAX) - primary_key=keynr; + if (atoi(row[1]) == 0 && primary_key == INT_MAX) + primary_key=keynr; #endif - if (!strcmp(row[2],"PRIMARY")) - { - primary_key=keynr; - break; - } + if (!strcmp(row[2],"PRIMARY")) + { + primary_key=keynr; + break; + } } } mysql_data_seek(result,0); keynr=0; while ((row= mysql_fetch_row(result))) { - if (opt_xml) - { - print_xml_row(sql_file, "key", result, &row); - continue; - } + if (opt_xml) + { + print_xml_row(sql_file, "key", result, &row); + continue; + } if (atoi(row[3]) == 1) { - if (keynr++) - putc(')', sql_file); - if (atoi(row[1])) /* Test if duplicate key */ - /* Duplicate allowed */ - fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0)); - else if (keynr == primary_key) - fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */ - else - fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, - 0)); + if (keynr++) + putc(')', sql_file); + if (atoi(row[1])) /* Test if duplicate key */ + /* Duplicate allowed */ + fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0)); + else if (keynr == primary_key) + fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */ + else + fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, + 0)); } else - putc(',', sql_file); + putc(',', sql_file); fputs(quote_name(row[4], name_buff, 0), sql_file); if (row[7]) - fprintf(sql_file, " (%s)",row[7]); /* Sub key */ - check_io(sql_file); + fprintf(sql_file, " (%s)",row[7]); /* Sub key */ + check_io(sql_file); } if (!opt_xml) { - if (keynr) - putc(')', sql_file); - fputs("\n)",sql_file); - check_io(sql_file); + if (keynr) + putc(')', sql_file); + fputs("\n)",sql_file); + check_io(sql_file); } /* Get MySQL specific create options */ if (create_options) { - char show_name_buff[NAME_LEN*2+2+24]; + char show_name_buff[NAME_LEN*2+2+24]; - /* Check memory for quote_for_like() */ + /* Check memory for quote_for_like() */ my_snprintf(buff, sizeof(buff), "show table status like %s", - quote_for_like(table, show_name_buff)); + quote_for_like(table, show_name_buff)); if (mysql_query_with_error_report(sock, &result, buff)) { - if (mysql_errno(sock) != ER_PARSE_ERROR) - { /* If old MySQL version */ - if (verbose) - fprintf(stderr, - "-- Warning: Couldn't get status information for table %s (%s)\n", - result_table,mysql_error(sock)); - } + if (mysql_errno(sock) != ER_PARSE_ERROR) + { /* If old MySQL version */ + if (verbose) + fprintf(stderr, + "-- Warning: Couldn't get status information for table %s (%s)\n", + result_table,mysql_error(sock)); + } } else if (!(row= mysql_fetch_row(result))) { - fprintf(stderr, - "Error: Couldn't read status information for table %s (%s)\n", - result_table,mysql_error(sock)); + fprintf(stderr, + "Error: Couldn't read status information for table %s (%s)\n", + result_table,mysql_error(sock)); } else { - if (opt_xml) - print_xml_row(sql_file, "options", result, &row); - else - { - fputs("/*!",sql_file); - print_value(sql_file,result,row,"engine=","Engine",0); - print_value(sql_file,result,row,"","Create_options",0); - print_value(sql_file,result,row,"comment=","Comment",1); - fputs(" */",sql_file); - check_io(sql_file); - } + if (opt_xml) + print_xml_row(sql_file, "options", result, &row); + else + { + fputs("/*!",sql_file); + print_value(sql_file,result,row,"engine=","Engine",0); + print_value(sql_file,result,row,"","Create_options",0); + print_value(sql_file,result,row,"comment=","Comment",1); + fputs(" */",sql_file); + check_io(sql_file); + } } - mysql_free_result(result); /* Is always safe to free */ + mysql_free_result(result); /* Is always safe to free */ } continue_xml: if (!opt_xml) - fputs(";\n", sql_file); + fputs(";\n", sql_file); else - fputs("\t\n", sql_file); + fputs("\t\n", sql_file); check_io(sql_file); } } @@ -1871,8 +1883,8 @@ continue_xml: static void dump_triggers_for_table (char *table, char *db) { - char *result_table; - char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; + char *result_table; + char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; char query_buff[512]; uint old_opt_compatible_mode=opt_compatible_mode; FILE *sql_file = md_result_file; @@ -1921,7 +1933,7 @@ DELIMITER ;;\n"); uint host_name_len; char host_name_str[HOSTNAME_LENGTH + 1]; char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; - + parse_user(row[7], strlen(row[7]), user_name_str, &user_name_len, host_name_str, &host_name_len); @@ -1937,7 +1949,7 @@ DELIMITER ;;\n"); row[4], /* Timing */ row[1], /* Event */ result_table, - (strchr(" \t\n\r", *(row[3]))) ? "" : " ", + (strchr(" \t\n\r", *(row[3]))) ? "" : " ", row[3] /* Statement */); } if (mysql_num_rows(result)) @@ -1946,7 +1958,7 @@ DELIMITER ;;\n"); "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"); mysql_free_result(result); /* - make sure to set back opt_compatible mode to + make sure to set back opt_compatible mode to original value */ opt_compatible_mode=old_opt_compatible_mode; @@ -1954,7 +1966,7 @@ DELIMITER ;;\n"); } static char *add_load_option(char *ptr,const char *object, - const char *statement) + const char *statement) { if (object) { @@ -1993,7 +2005,7 @@ static char *field_escape(char *to,const char *from,uint length) else { if (*from == '\'' && !end_backslashes) - *to++= *from; /* We want a duplicate of "'" for MySQL */ + *to++= *from; /* We want a duplicate of "'" for MySQL */ end_backslashes=0; } } @@ -2010,8 +2022,8 @@ static char *alloc_query_str(ulong size) if (!(query= (char*) my_malloc(size, MYF(MY_WME)))) { - ignore_errors= 0; /* Fatal error */ - safe_exit(EX_MYSQLERR); /* Force exit */ + ignore_errors= 0; /* Fatal error */ + safe_exit(EX_MYSQLERR); /* Force exit */ } return query; } @@ -2040,11 +2052,11 @@ static void dump_table(char *table, char *db) char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table; char *query= query_buf; int error= 0; - ulong rownr, row_break, total_length, init_length; + ulong rownr, row_break, total_length, init_length; uint num_fields; - MYSQL_RES *res; - MYSQL_FIELD *field; - MYSQL_ROW row; + MYSQL_RES *res; + MYSQL_FIELD *field; + MYSQL_ROW row; DBUG_ENTER("dump_table"); /* @@ -2053,13 +2065,19 @@ static void dump_table(char *table, char *db) */ num_fields= get_table_structure(table, db, table_type, &ignore_flag); + /* + The "table" could be a view. If so, we don't do anything here. + */ + if (strcmp (table_type, "VIEW") == 0) + return; + /* Check --no-data flag */ if (dFlag) { if (verbose) fprintf(stderr, "-- Skipping dump data for table '%s', --no-data was used\n", - table); + table); DBUG_VOID_RETURN; } @@ -2074,8 +2092,8 @@ static void dump_table(char *table, char *db) { if (verbose) fprintf(stderr, - "-- Warning: Skipping data for table '%s' because it's of type %s\n", - table, table_type); + "-- Warning: Skipping data for table '%s' because it's of type %s\n", + table, table_type); DBUG_VOID_RETURN; } /* Check that there are any fields in the table */ @@ -2083,8 +2101,8 @@ static void dump_table(char *table, char *db) { if (verbose) fprintf(stderr, - "-- Skipping dump data for table '%s', it has no fields\n", - table); + "-- Skipping dump data for table '%s', it has no fields\n", + table); DBUG_VOID_RETURN; } @@ -2100,11 +2118,11 @@ static void dump_table(char *table, char *db) my_load_path(tmp_path, tmp_path, NULL); fn_format(filename, table, tmp_path, ".txt", 4); my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if - filename wasn't deleted */ + filename wasn't deleted */ to_unix_path(filename); - my_snprintf(query, QUERY_LENGTH, - "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", - filename); + my_snprintf(query, QUERY_LENGTH, + "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", + filename); end= strend(query); if (fields_terminated || enclosed || opt_enclosed || escaped) @@ -2141,12 +2159,12 @@ static void dump_table(char *table, char *db) if (!opt_xml && opt_comments) { fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n", - result_table); + result_table); check_io(md_result_file); } my_snprintf(query, QUERY_LENGTH, - "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", - result_table); + "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", + result_table); if (where || order_by) { query = alloc_query_str((ulong) (strlen(query) + 1 + @@ -2194,7 +2212,7 @@ static void dump_table(char *table, char *db) if (mysql_num_fields(res) != num_fields) { fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n", - my_progname, result_table); + my_progname, result_table); error= EX_CONSCHECK; goto err; } @@ -2202,7 +2220,7 @@ static void dump_table(char *table, char *db) if (opt_disable_keys) { fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n", - opt_quoted_table); + opt_quoted_table); check_io(md_result_file); } if (opt_lock) @@ -2211,7 +2229,7 @@ static void dump_table(char *table, char *db) check_io(md_result_file); } - total_length= opt_net_buffer_length; /* Force row break */ + total_length= opt_net_buffer_length; /* Force row break */ row_break=0; rownr=0; init_length=(uint) insert_pat.length+4; @@ -2231,15 +2249,15 @@ static void dump_table(char *table, char *db) rownr++; if (!extended_insert && !opt_xml) { - fputs(insert_pat.str,md_result_file); - check_io(md_result_file); + fputs(insert_pat.str,md_result_file); + check_io(md_result_file); } mysql_field_seek(res,0); if (opt_xml) { fputs("\t\n", md_result_file); - check_io(md_result_file); + check_io(md_result_file); } for (i = 0; i < mysql_num_fields(res); i++) @@ -2247,21 +2265,21 @@ static void dump_table(char *table, char *db) int is_blob; ulong length= lengths[i]; - if (!(field = mysql_fetch_field(res))) - { - my_snprintf(query, QUERY_LENGTH, - "%s: Not enough fields from table %s! Aborting.\n", - my_progname, result_table); - fputs(query,stderr); - error= EX_CONSCHECK; - goto err; - } + if (!(field = mysql_fetch_field(res))) + { + my_snprintf(query, QUERY_LENGTH, + "%s: Not enough fields from table %s! Aborting.\n", + my_progname, result_table); + fputs(query,stderr); + error= EX_CONSCHECK; + goto err; + } - /* - 63 is my_charset_bin. If charsetnr is not 63, - we have not a BLOB but a TEXT column. - we'll dump in hex only BLOB columns. - */ + /* + 63 is my_charset_bin. If charsetnr is not 63, + we have not a BLOB but a TEXT column. + we'll dump in hex only BLOB columns. + */ is_blob= (opt_hex_blob && field->charsetnr == 63 && (field->type == MYSQL_TYPE_BIT || field->type == MYSQL_TYPE_STRING || @@ -2271,36 +2289,36 @@ static void dump_table(char *table, char *db) field->type == MYSQL_TYPE_LONG_BLOB || field->type == MYSQL_TYPE_MEDIUM_BLOB || field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0; - if (extended_insert) - { - if (i == 0) - dynstr_set(&extended_row,"("); - else - dynstr_append(&extended_row,","); + if (extended_insert) + { + if (i == 0) + dynstr_set(&extended_row,"("); + else + dynstr_append(&extended_row,","); - if (row[i]) - { - if (length) - { - if (!IS_NUM_FIELD(field)) - { - /* - "length * 2 + 2" is OK for both HEX and non-HEX modes: - - In HEX mode we need exactly 2 bytes per character - plus 2 bytes for '0x' prefix. - - In non-HEX mode we need up to 2 bytes per character, - plus 2 bytes for leading and trailing '\'' characters. - */ - if (dynstr_realloc(&extended_row,length * 2+2)) - { - fputs("Aborting dump (out of memory)",stderr); - error= EX_EOM; - goto err; - } + if (row[i]) + { + if (length) + { + if (!IS_NUM_FIELD(field)) + { + /* + "length * 2 + 2" is OK for both HEX and non-HEX modes: + - In HEX mode we need exactly 2 bytes per character + plus 2 bytes for '0x' prefix. + - In non-HEX mode we need up to 2 bytes per character, + plus 2 bytes for leading and trailing '\'' characters. + */ + if (dynstr_realloc(&extended_row,length * 2+2)) + { + fputs("Aborting dump (out of memory)",stderr); + error= EX_EOM; + goto err; + } if (opt_hex_blob && is_blob) { dynstr_append(&extended_row, "0x"); - extended_row.length+= mysql_hex_string(extended_row.str + + extended_row.length+= mysql_hex_string(extended_row.str + extended_row.length, row[i], length); extended_row.str[extended_row.length]= '\0'; @@ -2315,94 +2333,94 @@ static void dump_table(char *table, char *db) extended_row.str[extended_row.length]='\0'; dynstr_append(&extended_row,"'"); } - } - else - { - /* change any strings ("inf", "-inf", "nan") into NULL */ - char *ptr = row[i]; - if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && - my_isalpha(charset_info, ptr[1]))) - dynstr_append(&extended_row, "NULL"); - else - { - if (field->type == FIELD_TYPE_DECIMAL) - { - /* add " signs around */ - dynstr_append(&extended_row, "'"); - dynstr_append(&extended_row, ptr); - dynstr_append(&extended_row, "'"); - } - else - dynstr_append(&extended_row, ptr); - } - } - } - else - dynstr_append(&extended_row,"''"); - } - else if (dynstr_append(&extended_row,"NULL")) - { - fputs("Aborting dump (out of memory)",stderr); - error= EX_EOM; - goto err; - } - } - else - { - if (i && !opt_xml) - { - fputc(',', md_result_file); - check_io(md_result_file); - } - if (row[i]) - { - if (!IS_NUM_FIELD(field)) - { - if (opt_xml) - { - print_xml_tag1(md_result_file, "\t\t", "field name=", - field->name, ""); - print_quoted_xml(md_result_file, row[i], length); - fputs("\n", md_result_file); - } - else if (opt_hex_blob && is_blob && length) + } + else + { + /* change any strings ("inf", "-inf", "nan") into NULL */ + char *ptr = row[i]; + if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && + my_isalpha(charset_info, ptr[1]))) + dynstr_append(&extended_row, "NULL"); + else + { + if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + dynstr_append(&extended_row, "'"); + dynstr_append(&extended_row, ptr); + dynstr_append(&extended_row, "'"); + } + else + dynstr_append(&extended_row, ptr); + } + } + } + else + dynstr_append(&extended_row,"''"); + } + else if (dynstr_append(&extended_row,"NULL")) + { + fputs("Aborting dump (out of memory)",stderr); + error= EX_EOM; + goto err; + } + } + else + { + if (i && !opt_xml) + { + fputc(',', md_result_file); + check_io(md_result_file); + } + if (row[i]) + { + if (!IS_NUM_FIELD(field)) + { + if (opt_xml) + { + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); + print_quoted_xml(md_result_file, row[i], length); + fputs("\n", md_result_file); + } + else if (opt_hex_blob && is_blob && length) { /* sakaik got the idea to to provide blob's in hex notation. */ char *ptr= row[i], *end= ptr + length; fputs("0x", md_result_file); for (; ptr < end ; ptr++) - fprintf(md_result_file, "%02X", *((uchar *)ptr)); + fprintf(md_result_file, "%02X", *((uchar *)ptr)); } else unescape(md_result_file, row[i], length); - } - else - { - /* change any strings ("inf", "-inf", "nan") into NULL */ - char *ptr = row[i]; - if (opt_xml) - { - print_xml_tag1(md_result_file, "\t\t", "field name=", - field->name, ""); - fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL", - md_result_file); - fputs("\n", md_result_file); - } - else if (my_isalpha(charset_info, *ptr) || - (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) - fputs("NULL", md_result_file); - else if (field->type == FIELD_TYPE_DECIMAL) - { - /* add " signs around */ - fputc('\'', md_result_file); - fputs(ptr, md_result_file); - fputc('\'', md_result_file); - } - else - fputs(ptr, md_result_file); - } - } - else + } + else + { + /* change any strings ("inf", "-inf", "nan") into NULL */ + char *ptr = row[i]; + if (opt_xml) + { + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); + fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL", + md_result_file); + fputs("\n", md_result_file); + } + else if (my_isalpha(charset_info, *ptr) || + (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) + fputs("NULL", md_result_file); + else if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + fputc('\'', md_result_file); + fputs(ptr, md_result_file); + fputc('\'', md_result_file); + } + else + fputs(ptr, md_result_file); + } + } + else { /* The field value is NULL */ if (!opt_xml) @@ -2412,61 +2430,61 @@ static void dump_table(char *table, char *db) field->name, "\n"); } check_io(md_result_file); - } + } } if (opt_xml) { fputs("\t\n", md_result_file); - check_io(md_result_file); + check_io(md_result_file); } if (extended_insert) { - ulong row_length; - dynstr_append(&extended_row,")"); + ulong row_length; + dynstr_append(&extended_row,")"); row_length = 2 + extended_row.length; if (total_length + row_length < opt_net_buffer_length) { - total_length += row_length; - fputc(',',md_result_file); /* Always row break */ - fputs(extended_row.str,md_result_file); - } + total_length += row_length; + fputc(',',md_result_file); /* Always row break */ + fputs(extended_row.str,md_result_file); + } else { - if (row_break) - fputs(";\n", md_result_file); - row_break=1; /* This is first row */ + if (row_break) + fputs(";\n", md_result_file); + row_break=1; /* This is first row */ fputs(insert_pat.str,md_result_file); fputs(extended_row.str,md_result_file); - total_length = row_length+init_length; + total_length = row_length+init_length; } - check_io(md_result_file); + check_io(md_result_file); } else if (!opt_xml) { - fputs(");\n", md_result_file); - check_io(md_result_file); + fputs(");\n", md_result_file); + check_io(md_result_file); } } /* XML - close table tag and supress regular output */ if (opt_xml) - fputs("\t\n", md_result_file); + fputs("\t\n", md_result_file); else if (extended_insert && row_break) - fputs(";\n", md_result_file); /* If not empty table */ + fputs(";\n", md_result_file); /* If not empty table */ fflush(md_result_file); check_io(md_result_file); if (mysql_errno(sock)) { my_snprintf(query, QUERY_LENGTH, - "%s: Error %d: %s when dumping table %s at row: %ld\n", - my_progname, - mysql_errno(sock), - mysql_error(sock), - result_table, - rownr); + "%s: Error %d: %s when dumping table %s at row: %ld\n", + my_progname, + mysql_errno(sock), + mysql_error(sock), + result_table, + rownr); fputs(query,stderr); error= EX_CONSCHECK; goto err; @@ -2479,7 +2497,7 @@ static void dump_table(char *table, char *db) if (opt_disable_keys) { fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n", - opt_quoted_table); + opt_quoted_table); check_io(md_result_file); } if (opt_autocommit) @@ -2538,7 +2556,7 @@ static int dump_all_databases() if (dump_all_tables_in_db(row[0])) result=1; } - if (was_views) + if (seen_views) { if (mysql_query(sock, "SHOW DATABASES") || !(tableres = mysql_store_result(sock))) @@ -2567,7 +2585,7 @@ static int dump_databases(char **db_names) if (dump_all_tables_in_db(*db)) result=1; } - if (!result && was_views) + if (!result && seen_views) { for (db= db_names ; *db ; db++) { @@ -2583,26 +2601,26 @@ static int init_dumping(char *database) { if (mysql_get_server_version(sock) >= 50003 && !my_strcasecmp(&my_charset_latin1, database, "information_schema")) - return 1; + return 1; if (mysql_select_db(sock, database)) { DB_error(sock, "when selecting the database"); - return 1; /* If --force */ + return 1; /* If --force */ } if (!path && !opt_xml) { if (opt_databases || opt_alldbs) { /* - length of table name * 2 (if name contains quotes), 2 quotes and 0 + length of table name * 2 (if name contains quotes), 2 quotes and 0 */ char quoted_database_buf[64*2+3]; char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); if (opt_comments) { - fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); - check_io(md_result_file); + fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); + check_io(md_result_file); } if (!opt_create_db) { @@ -2610,9 +2628,9 @@ static int init_dumping(char *database) MYSQL_ROW row; MYSQL_RES *dbinfo; - my_snprintf(qbuf, sizeof(qbuf), - "SHOW CREATE DATABASE IF NOT EXISTS %s", - qdatabase); + my_snprintf(qbuf, sizeof(qbuf), + "SHOW CREATE DATABASE IF NOT EXISTS %s", + qdatabase); if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) { @@ -2621,22 +2639,22 @@ static int init_dumping(char *database) fprintf(md_result_file, "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n", qdatabase); - fprintf(md_result_file, - "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", - qdatabase); - } - else + fprintf(md_result_file, + "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + qdatabase); + } + else { if (opt_drop_database) fprintf(md_result_file, "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n", qdatabase); - row = mysql_fetch_row(dbinfo); - if (row[1]) - { - fprintf(md_result_file,"\n%s;\n",row[1]); + row = mysql_fetch_row(dbinfo); + if (row[1]) + { + fprintf(md_result_file,"\n%s;\n",row[1]); } - } + } } fprintf(md_result_file,"\nUSE %s;\n", qdatabase); check_io(md_result_file); @@ -2741,8 +2759,6 @@ static my_bool dump_all_views_in_db(char *database) uint numrows; char table_buff[NAME_LEN*2+3]; - if (init_dumping(database)) - return 1; if (opt_xml) print_xml_tag1(md_result_file, "", "database name=", database, "\n"); if (lock_tables) @@ -2802,7 +2818,7 @@ static int get_actual_table_name(const char *old_table_name, /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", - quote_for_like(old_table_name, show_name_buff)); + quote_for_like(old_table_name, show_name_buff)); if (mysql_query_with_error_report(sock, 0, query)) { @@ -2908,7 +2924,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* Dump each selected view */ - if (was_views) + if (seen_views) { for(i=0; i < dump_tables.records; i++) { @@ -2961,14 +2977,14 @@ static int do_show_master_status(MYSQL *mysql_con) "recovery from\n--\n\n"); fprintf(md_result_file, "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", - comment_prefix, row[0], row[1]); + comment_prefix, row[0], row[1]); check_io(md_result_file); } else if (!ignore_errors) { /* SHOW MASTER STATUS reports nothing and --force is not enabled */ - my_printf_error(0, "Error: Binlogging on server not active", - MYF(0)); + my_printf_error(0, "Error: Binlogging on server not active", + MYF(0)); mysql_free_result(master); return 1; } @@ -2988,7 +3004,7 @@ static int do_flush_tables_read_lock(MYSQL *mysql_con) and most client connections are stalled. Of course, if a second long update starts between the two FLUSHes, we have that bad stall. */ - return + return ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") || mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES WITH READ LOCK") ); @@ -3030,7 +3046,7 @@ static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now) static ulong find_set(TYPELIB *lib, const char *x, uint length, - char **err_pos, uint *err_len) + char **err_pos, uint *err_len) { const char *end= x + length; ulong found= 0; @@ -3072,10 +3088,10 @@ static ulong find_set(TYPELIB *lib, const char *x, uint length, /* Print a value with a prefix on file */ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, - const char *prefix, const char *name, - int string_value) + const char *prefix, const char *name, + int string_value) { - MYSQL_FIELD *field; + MYSQL_FIELD *field; mysql_field_seek(result, 0); for ( ; (field = mysql_fetch_field(result)) ; row++) @@ -3084,18 +3100,18 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, { if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */ { - fputc(' ',file); - fputs(prefix, file); - if (string_value) - unescape(file,row[0],(uint) strlen(row[0])); - else - fputs(row[0], file); - check_io(file); - return; + fputc(' ',file); + fputs(prefix, file); + if (string_value) + unescape(file,row[0],(uint) strlen(row[0])); + else + fputs(row[0], file); + check_io(file); + return; } } } - return; /* This shouldn't happen */ + return; /* This shouldn't happen */ } /* print_value */ @@ -3106,19 +3122,19 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, Check if we the table is one of the table types that should be ignored: MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts. If the table should be altogether ignored, it returns a TRUE, FALSE if it - should not be ignored. If the user has selected to use INSERT DELAYED, it - sets the value of the bool pointer supports_delayed_inserts to 0 if not + should not be ignored. If the user has selected to use INSERT DELAYED, it + sets the value of the bool pointer supports_delayed_inserts to 0 if not supported, 1 if it is supported. ARGS check_if_ignore_table() - table_name Table name to check + table_name Table name to check table_type Type of table GLOBAL VARIABLES - sock MySQL socket - verbose Write warning messages + sock MySQL socket + verbose Write warning messages RETURN char (bit value) See IGNORE_ values at top @@ -3135,23 +3151,23 @@ char check_if_ignore_table(const char *table_name, char *table_type) /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); my_snprintf(buff, sizeof(buff), "show table status like %s", - quote_for_like(table_name, show_name_buff)); + quote_for_like(table_name, show_name_buff)); if (mysql_query_with_error_report(sock, &res, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) - { /* If old MySQL version */ + { /* If old MySQL version */ if (verbose) - fprintf(stderr, - "-- Warning: Couldn't get status information for table %s (%s)\n", - table_name,mysql_error(sock)); + fprintf(stderr, + "-- Warning: Couldn't get status information for table %s (%s)\n", + table_name,mysql_error(sock)); DBUG_RETURN(result); /* assume table is ok */ } } if (!(row= mysql_fetch_row(res))) { fprintf(stderr, - "Error: Couldn't read status information for table %s (%s)\n", - table_name, mysql_error(sock)); + "Error: Couldn't read status information for table %s (%s)\n", + table_name, mysql_error(sock)); mysql_free_result(res); DBUG_RETURN(result); /* assume table is ok */ } @@ -3214,8 +3230,8 @@ static char *primary_key_fields(const char *table_name) uint result_length = 0; char *result = 0; - my_snprintf(show_keys_buff, sizeof(show_keys_buff), - "SHOW KEYS FROM %s", table_name); + my_snprintf(show_keys_buff, sizeof(show_keys_buff), + "SHOW KEYS FROM %s", table_name); if (mysql_query(sock, show_keys_buff) || !(res = mysql_store_result(sock))) { @@ -3291,7 +3307,7 @@ static int replace(DYNAMIC_STRING *ds_str, if (!start) return 1; init_dynamic_string(&ds_tmp, "", - ds_str->length + replace_len, 256); + ds_str->length + replace_len, 256); dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str); dynstr_append_mem(&ds_tmp, replace_str, replace_len); dynstr_append(&ds_tmp, start + search_len); @@ -3319,9 +3335,9 @@ static my_bool get_view_structure(char *table, char* db) MYSQL_RES *table_res; MYSQL_ROW row; MYSQL_FIELD *field; - char *result_table, *opt_quoted_table; - char table_buff[NAME_LEN*2+3]; - char table_buff2[NAME_LEN*2+3]; + char *result_table, *opt_quoted_table; + char table_buff[NAME_LEN*2+3]; + char table_buff2[NAME_LEN*2+3]; char query[QUERY_LENGTH]; FILE *sql_file = md_result_file; DBUG_ENTER("get_view_structure"); @@ -3334,7 +3350,7 @@ static my_bool get_view_structure(char *table, char* db) #ifdef NOT_REALLY_USED_YET sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", - (opt_quoted || opt_keywords)); + (opt_quoted || opt_keywords)); #endif result_table= quote_name(table, table_buff, 1); @@ -3369,7 +3385,7 @@ static my_bool get_view_structure(char *table, char* db) if (!opt_xml && opt_comments) { - fprintf(sql_file, "\n--\n-- View structure for view %s\n--\n\n", + fprintf(sql_file, "\n--\n-- Final view structure for view %s\n--\n\n", result_table); check_io(sql_file); } @@ -3450,7 +3466,7 @@ static my_bool get_view_structure(char *table, char* db) char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; parse_user(row[1], lengths[1], user_name_str, &user_name_len, - host_name_str, &host_name_len); + host_name_str, &host_name_len); ptr= search_buf; search_len= diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 467e0818646..135c2f7abd4 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1458,7 +1458,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` varchar(30) ) */; @@ -1763,7 +1762,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `a` int(11) ) */; @@ -1821,7 +1819,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` varchar(30) ) */; @@ -1914,7 +1911,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `a` int(11), `b` int(11), @@ -1922,13 +1918,11 @@ DROP TABLE IF EXISTS `v1`; ) */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` int(11) ) */; DROP TABLE IF EXISTS `v3`; /*!50001 DROP VIEW IF EXISTS `v3`*/; -/*!50001 DROP TABLE IF EXISTS `v3`*/; /*!50001 CREATE TABLE `v3` ( `a` int(11), `b` int(11), @@ -2489,7 +2483,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v0`; /*!50001 DROP VIEW IF EXISTS `v0`*/; -/*!50001 DROP TABLE IF EXISTS `v0`*/; /*!50001 CREATE TABLE `v0` ( `a` int(11), `b` varchar(32), @@ -2497,7 +2490,6 @@ DROP TABLE IF EXISTS `v0`; ) */; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `a` int(11), `b` varchar(32), @@ -2505,16 +2497,11 @@ DROP TABLE IF EXISTS `v1`; ) */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` int(11), `b` varchar(32), `c` varchar(32) ) */; - -CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; - -USE `test`; /*!50001 DROP TABLE IF EXISTS `v0`*/; /*!50001 DROP VIEW IF EXISTS `v0`*/; /*!50001 CREATE ALGORITHM=UNDEFINED */ @@ -2731,3 +2718,88 @@ p CREATE DEFINER=`root`@`localhost` PROCEDURE `p`() select 42 drop function f; drop procedure p; +drop database if exists test; +create database test; +use test; +create table t1 (id int); +create view v1 as select * from t1; +insert into t1 values (1232131); +insert into t1 values (4711); +insert into t1 values (3231); +insert into t1 values (0815); +-- MySQL dump 10.10 +-- +-- Host: localhost Database: test +-- ------------------------------------------------------ +-- Server version 5.0.22-debug-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Current Database: `test` +-- + +/*!40000 DROP DATABASE IF EXISTS `test`*/; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; + +-- +-- Table structure for table `t1` +-- + +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `id` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `t1` +-- + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1232131),(4711),(3231),(815); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +-- +-- Temporary table structure for view `v1` +-- + +DROP TABLE IF EXISTS `v1`; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE TABLE `v1` ( + `id` int(11) +) */; + +-- +-- Final view structure for view `v1` +-- + +/*!50001 DROP TABLE IF EXISTS `v1`*/; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v1` AS select `t1`.`id` AS `id` from `t1` */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4076fd258e9..01eb826881e 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1143,3 +1143,18 @@ show create procedure p; drop function f; drop procedure p; +# +# BUG#17201 Spurious 'DROP DATABASE' in output, +# also confusion between tables and views. +# Example code from Markus Popp + +drop database if exists test; +create database test; +use test; +create table t1 (id int); +create view v1 as select * from t1; +insert into t1 values (1232131); +insert into t1 values (4711); +insert into t1 values (3231); +insert into t1 values (0815); +--exec $MYSQL_DUMP --add-drop-database --databases test From 45972e0e83efa046360b3d3cdae0de51c7977e92 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 May 2006 11:00:35 +0930 Subject: [PATCH 38/41] mysqldump.result: Get output from modified test (dropping t1). mysqldump.test: Drop t1 at end so that the next test doesn't trip over it. mysql-test/t/mysqldump.test: Drop t1 at end so that the next test doesn't trip over it. mysql-test/r/mysqldump.result: Get output from modified test (dropping t1). --- mysql-test/r/mysqldump.result | 1 + mysql-test/t/mysqldump.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 135c2f7abd4..099304fe6e7 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2803,3 +2803,4 @@ DROP TABLE IF EXISTS `v1`; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +drop view v1; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 01eb826881e..b7a714815b7 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1158,3 +1158,4 @@ insert into t1 values (4711); insert into t1 values (3231); insert into t1 values (0815); --exec $MYSQL_DUMP --add-drop-database --databases test +drop view v1; From 3eb8a12c08dd18cf24e652f5e886574f77845434 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Jun 2006 23:05:10 +0400 Subject: [PATCH 39/41] Applied innodb-4.1-ss31 snapshot. Fixed BUG#19727 "InnoDB crashed server and crashed tables are not recoverable". innobase/row/row0mysql.c: Applied innodb-4.1-ss31 snapshot. Move trx_commit_for_mysql(trx) calls before calls to row_mysql_unlock_data_dictionary(trx). --- innobase/row/row0mysql.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 23d019b6f78..1ee920ffb14 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2237,14 +2237,14 @@ do not allow the discard. We also reserve the data dictionary latch. */ } } funct_exit: + trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); if (graph) { que_graph_free(graph); } - trx_commit_for_mysql(trx); - trx->op_info = ""; return((int) err); @@ -2374,10 +2374,10 @@ row_import_tablespace_for_mysql( } funct_exit: - row_mysql_unlock_data_dictionary(trx); - trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->op_info = ""; return((int) err); @@ -2769,6 +2769,8 @@ fputs(" InnoDB: You are trying to drop table ", stderr); } funct_exit: + trx_commit_for_mysql(trx); + if (locked_dictionary) { row_mysql_unlock_data_dictionary(trx); } @@ -2779,8 +2781,6 @@ funct_exit: que_graph_free(graph); - trx_commit_for_mysql(trx); - trx->op_info = ""; srv_wake_master_thread(); @@ -2857,10 +2857,10 @@ loop: } } - row_mysql_unlock_data_dictionary(trx); - trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->op_info = ""; return(err); @@ -3272,6 +3272,8 @@ row_rename_table_for_mysql( } } funct_exit: + trx_commit_for_mysql(trx); + if (!recovering_temp_table) { row_mysql_unlock_data_dictionary(trx); } @@ -3284,8 +3286,6 @@ funct_exit: mem_heap_free(heap); } - trx_commit_for_mysql(trx); - trx->op_info = ""; return((int) err); From 9e3f90e54156b10deac06cbb8880fb00749fa8ba Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Jun 2006 23:37:42 +0400 Subject: [PATCH 40/41] Applied innodb-5.0-ss609 snapshot. Fixed BUG#19727 "InnoDB crashed server and crashed tables are not recoverable". innobase/row/row0mysql.c: Applied innodb-5.0-ss609 snapshot. Move trx_commit_for_mysql(trx) calls before calls to row_mysql_unlock_data_dictionary(trx). innobase/row/row0sel.c: Applied innodb-5.0-ss609 snapshot. row_sel_try_search_shortcut(): Do not return SEL_FOUND when the record was not found. This bug was introduced in InnoDB 5.0.3, but luckily it should nerver manifest itself, given that existing InnoDB SQL code never makes use of consistent reads. mysql-test/t/innodb.test: Applied innodb-5.0-ss609 snapshot. Add the big fat warning notice also to the bottom of innodb.test so that it will require more talent to ignore the change of policy. --- innobase/row/row0mysql.c | 20 ++++++++++---------- innobase/row/row0sel.c | 3 ++- mysql-test/t/innodb.test | 13 +++++++++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 89b82882d93..9e922a3e04a 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2570,14 +2570,14 @@ do not allow the discard. We also reserve the data dictionary latch. */ } } funct_exit: + trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); if (graph) { que_graph_free(graph); } - trx_commit_for_mysql(trx); - trx->op_info = ""; return((int) err); @@ -2707,10 +2707,10 @@ row_import_tablespace_for_mysql( } funct_exit: - row_mysql_unlock_data_dictionary(trx); - trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->op_info = ""; return((int) err); @@ -3398,6 +3398,8 @@ fputs(" InnoDB: You are trying to drop table ", stderr); } funct_exit: + trx_commit_for_mysql(trx); + if (locked_dictionary) { row_mysql_unlock_data_dictionary(trx); } @@ -3408,8 +3410,6 @@ funct_exit: que_graph_free(graph); - trx_commit_for_mysql(trx); - trx->op_info = ""; #ifndef UNIV_HOTBACKUP @@ -3488,10 +3488,10 @@ loop: } } - row_mysql_unlock_data_dictionary(trx); - trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->op_info = ""; return(err); @@ -3905,6 +3905,8 @@ row_rename_table_for_mysql( } } funct_exit: + trx_commit_for_mysql(trx); + if (!recovering_temp_table) { row_mysql_unlock_data_dictionary(trx); } @@ -3917,8 +3919,6 @@ funct_exit: mem_heap_free(heap); } - trx_commit_for_mysql(trx); - trx->op_info = ""; return((int) err); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 1402d3aaba6..23971767e7e 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -1064,11 +1064,12 @@ row_sel_try_search_shortcut( ut_ad(plan->pcur.latch_mode == node->latch_mode); plan->n_rows_fetched++; + ret = SEL_FOUND; func_exit: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - return(SEL_FOUND); + return(ret); } /************************************************************************* diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index e4c8bf89cca..71b178d0e57 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2196,3 +2196,16 @@ drop table t2, t1; # --error ER_TABLE_CANT_HANDLE_SPKEYS create table t1 (g geometry not null, spatial gk(g)) engine=innodb; + +####################################################################### +# # +# Please, DO NOT TOUCH this file as well as the innodb.result file. # +# These files are to be modified ONLY BY INNOBASE guys. # +# # +# Use innodb_mysql.[test|result] files instead. # +# # +# If nevertheless you need to make some changes here, please, forward # +# your commit message To: dev@innodb.com Cc: dev-innodb@mysql.com # +# (otherwise your changes may be erased). # +# # +####################################################################### From 7eec6c3f0402401caad46740bd90f04190f2df18 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Jun 2006 11:55:53 +0200 Subject: [PATCH 41/41] BUG#17201: Removed version number from test case output mysql-test/r/mysqldump.result: Remove comments in mysqldump output mysql-test/t/mysqldump.test: Remove comments in mysqldump output --- mysql-test/r/mysqldump.result | 28 ---------------------------- mysql-test/t/mysqldump.test | 2 +- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 099304fe6e7..ad31b8e2a65 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2727,11 +2727,6 @@ insert into t1 values (1232131); insert into t1 values (4711); insert into t1 values (3231); insert into t1 values (0815); --- MySQL dump 10.10 --- --- Host: localhost Database: test --- ------------------------------------------------------ --- Server version 5.0.22-debug-log /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -2744,50 +2739,27 @@ insert into t1 values (0815); /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --- --- Current Database: `test` --- - /*!40000 DROP DATABASE IF EXISTS `test`*/; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; USE `test`; - --- --- Table structure for table `t1` --- - DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( `id` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; --- --- Dumping data for table `t1` --- - /*!40000 ALTER TABLE `t1` DISABLE KEYS */; LOCK TABLES `t1` WRITE; INSERT INTO `t1` VALUES (1232131),(4711),(3231),(815); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; - --- --- Temporary table structure for view `v1` --- - DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `id` int(11) ) */; - --- --- Final view structure for view `v1` --- - /*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 DROP VIEW IF EXISTS `v1`*/; /*!50001 CREATE ALGORITHM=UNDEFINED */ diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index b7a714815b7..4113c136e17 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1157,5 +1157,5 @@ insert into t1 values (1232131); insert into t1 values (4711); insert into t1 values (3231); insert into t1 values (0815); ---exec $MYSQL_DUMP --add-drop-database --databases test +--exec $MYSQL_DUMP --skip-comments --add-drop-database --databases test drop view v1;