From a2370730b3ec287807c8920131b2ee1c554fa8f5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Nov 2005 11:48:55 -0800 Subject: [PATCH 01/35] Avoid possible race condition in accessing slave statistics during shutdown. (Bug #11796) sql/sql_show.cc: Check that active_mi is not NULL before accessing its members. --- sql/sql_show.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d6ceca5f23c..268292022e4 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1890,7 +1890,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_SLAVE_RUNNING: { pthread_mutex_lock(&LOCK_active_mi); - end= strmov(buff, (active_mi->slave_running && + end= strmov(buff, (active_mi && active_mi->slave_running && active_mi->rli.slave_running) ? "ON" : "OFF"); pthread_mutex_unlock(&LOCK_active_mi); break; @@ -1902,9 +1902,12 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, SLAVE STATUS, and have the sum over all lines here. */ pthread_mutex_lock(&LOCK_active_mi); - pthread_mutex_lock(&active_mi->rli.data_lock); - end= int10_to_str(active_mi->rli.retried_trans, buff, 10); - pthread_mutex_unlock(&active_mi->rli.data_lock); + if (active_mi) + { + pthread_mutex_lock(&active_mi->rli.data_lock); + end= int10_to_str(active_mi->rli.retried_trans, buff, 10); + pthread_mutex_unlock(&active_mi->rli.data_lock); + } pthread_mutex_unlock(&LOCK_active_mi); break; } From 8355bce65862d3effea30f20f12186c8000b0247 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Nov 2005 18:29:06 -0800 Subject: [PATCH 02/35] Don't add optimization flags to CFLAGS if the user specified their own CFLAGS (ditto for CXXFLAGS). (Bug #12640) configure.in: Only add optimization flags when no CFLAGS (and/or CXXFLAGS) were specified. --- configure.in | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/configure.in b/configure.in index 40a3e8ea5d4..f10c7b7a96e 100644 --- a/configure.in +++ b/configure.in @@ -1672,6 +1672,19 @@ if expr "$SYSTEM_TYPE" : ".*netware.*" > /dev/null; then OPTIMIZE_CXXFLAGS="$OPTIMIZE_CXXFLAGS -DNDEBUG" fi +# If the user specified CFLAGS, we won't add any optimizations +if test -n "$SAVE_CFLAGS" +then + OPTIMIZE_CFLAGS="" + DEBUG_OPTIMIZE_CC="" +fi +# Ditto for CXXFLAGS +if test -n "$SAVE_CXXFLAGS" +then + OPTIMIZE_CXXFLAGS="" + DEBUG_OPTIMIZE_CXX="" +fi + AC_ARG_WITH(debug, [ --without-debug Build a production version without debugging code], [with_debug=$withval], From cd0a53655b0fcd52c615f5c8a8cbb3d76da56558 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Nov 2005 11:42:26 +0100 Subject: [PATCH 03/35] base64.c: Pack ported compatibility changes from 5.1 mysys/base64.c: Pack ported compatibility changes from 5.1 --- mysys/base64.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mysys/base64.c b/mysys/base64.c index 0165982fb67..73cb25017b6 100644 --- a/mysys/base64.c +++ b/mysys/base64.c @@ -15,7 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -#include // strchr() +#include /* strchr() */ #ifndef MAIN @@ -134,7 +134,8 @@ base64_decode(const char *src, size_t size, void *dst) { char b[3]; size_t i= 0; - void *d= dst; + char *dst_base= (char *)dst; + char *d= dst_base; size_t j; while (i < size) @@ -193,7 +194,7 @@ base64_decode(const char *src, size_t size, void *dst) { return -1; } - return d - dst; + return d - dst_base; } From 7d183320b0e9b271efe6017986b904b694d32310 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Nov 2005 18:24:12 +0100 Subject: [PATCH 04/35] Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Version for 4.0. It fixes two problems: 1. The cause of the bug was that we did not check the table version for the HANDLER ... READ commands. We did not notice when a table was replaced by a new one. This can happen during ALTER TABLE, REPAIR TABLE, and OPTIMIZE TABLE (there might be more cases). I call the fix for this problem "the primary bug fix". 2. mysql_ha_flush() was not always called with a locked LOCK_open. Though the function comment clearly said it must. I changed the code so that the locking is done when required. I call the fix for this problem "the secondary fix". mysql-test/r/handler.result: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The test result. mysql-test/t/handler.test: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The test case. sql/mysql_priv.h: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed a definition for the secondary fix. sql/sql_base.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed function calls for the secondary fix. sql/sql_class.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed a function call for the secondary fix. sql/sql_handler.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The first two diffs make the primary bug fix. The rest is for the secondary fix. sql/sql_table.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed function calls for the secondary fix. --- mysql-test/r/handler.result | 18 ++++++++++++++ mysql-test/t/handler.test | 29 ++++++++++++++++++++++ sql/mysql_priv.h | 3 ++- sql/sql_base.cc | 7 +++--- sql/sql_class.cc | 2 +- sql/sql_handler.cc | 49 ++++++++++++++++++++++++++++++++++--- sql/sql_table.cc | 6 ++--- 7 files changed, 102 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 5af153930d5..3a61236ea14 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -447,3 +447,21 @@ drop table t2; drop table t3; drop table t4; drop table t5; +create table t1 (c1 int); +insert into t1 values (1); +handler t1 open; +handler t1 read first; +c1 +1 +send the below to another connection, do not wait for the result + optimize table t1; +proceed with the normal connection +handler t1 read next; +c1 +1 +handler t1 close; +read the result from the other connection +Table Op Msg_type Msg_text +test.t1 optimize status OK +proceed with the normal connection +drop table t1; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 53fe8c0a059..d91587b8070 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -339,3 +339,32 @@ drop table t2; drop table t3; drop table t4; drop table t5; + +# +# Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash +# +create table t1 (c1 int); +insert into t1 values (1); +# client 1 +handler t1 open; +handler t1 read first; +# client 2 +connect (con2,localhost,root,,); +connection con2; +--exec echo send the below to another connection, do not wait for the result +send optimize table t1; +--sleep 1 +# client 1 +--exec echo proceed with the normal connection +connection default; +handler t1 read next; +handler t1 close; +# client 2 +--exec echo read the result from the other connection +connection con2; +reap; +# client 1 +--exec echo proceed with the normal connection +connection default; +drop table t1; + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9b9edd905ad..526b79cd73a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -547,7 +547,8 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen= 0); int mysql_ha_close(THD *thd, TABLE_LIST *tables); int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List *,enum ha_rkey_function,Item *,ha_rows,ha_rows); -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags); +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked); /* mysql_ha_flush mode_flags bits */ #define MYSQL_HA_CLOSE_FINAL 0x00 #define MYSQL_HA_REOPEN_ON_USAGE 0x01 diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bc2ad9fff50..4f52904a61e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -390,7 +390,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, + TRUE); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", ("Waiting for others threads to close their open tables")); @@ -863,7 +864,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, } /* close handler tables which are marked for flush */ - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -1262,7 +1263,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9dd75b32d5d..66d23ada163 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -217,7 +217,7 @@ void THD::cleanup(void) close_thread_tables(this); } mysql_ha_flush(this, (TABLE_LIST*) 0, - MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); + MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE); hash_free(&handler_tables_hash); close_temporary_tables(this); hash_free(&user_vars); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index fcdb2aeb668..28e94d1a477 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -357,6 +357,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit,ha_rows offset_limit) { TABLE_LIST *hash_tables; + TABLE **table_ptr; TABLE *table; int err; int keyno=-1; @@ -379,6 +380,27 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->real_name, hash_tables->alias, table)); + /* Table might have been flushed. */ + if (table && (table->version != refresh_version)) + { + /* + We must follow the thd->handler_tables chain, as we need the + address of the 'next' pointer referencing this table + for close_thread_table(). + */ + for (table_ptr= &(thd->handler_tables); + *table_ptr && (*table_ptr != table); + table_ptr= &(*table_ptr)->next) + {} + VOID(pthread_mutex_lock(&LOCK_open)); + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } + VOID(pthread_mutex_unlock(&LOCK_open)); + table= hash_tables->table= NULL; + } if (!table) { /* @@ -593,6 +615,7 @@ err0: MYSQL_HA_REOPEN_ON_USAGE mark for reopen. MYSQL_HA_FLUSH_ALL flush all tables, not only those marked for flush. + is_locked If LOCK_open is locked. DESCRIPTION The list of HANDLER tables may be NULL, in which case all HANDLER @@ -600,7 +623,6 @@ err0: If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, all HANDLER tables marked for flush are closed. Broadcasts a COND_refresh condition, for every table closed. - The caller must lock LOCK_open. NOTE Since mysql_ha_flush() is called when the base table has to be closed, @@ -610,10 +632,12 @@ err0: 0 ok */ -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked) { TABLE_LIST *tmp_tables; TABLE **table_ptr; + bool did_lock= FALSE; DBUG_ENTER("mysql_ha_flush"); DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); @@ -637,6 +661,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) (*table_ptr)->table_cache_key, (*table_ptr)->real_name, (*table_ptr)->table_name)); + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -655,6 +685,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) if ((mode_flags & MYSQL_HA_FLUSH_ALL) || ((*table_ptr)->version != refresh_version)) { + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -662,6 +698,10 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) } } + /* Release the lock if it was taken by this function. */ + if (did_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(0); } @@ -693,8 +733,8 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) table->table_name, mode_flags)); if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, - (byte*) (*table_ptr)->table_name, - strlen((*table_ptr)->table_name) + 1))) + (byte*) table->table_name, + strlen(table->table_name) + 1))) { if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) { @@ -708,6 +748,7 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) } } + safe_mutex_assert_owner(&LOCK_open); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4c269e6830f..987d12ccb40 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -179,7 +179,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { char *db=table->db; uint flags; - mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, TRUE); if (!close_temporary_table(thd, db, table->real_name)) { tmp_table_deleted=1; @@ -1239,7 +1239,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (send_fields(thd, field_list, 1)) DBUG_RETURN(-1); - mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, FALSE); for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; @@ -1500,7 +1500,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } used_fields=create_info->used_fields; - mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE); if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) DBUG_RETURN(-1); From 5412ee4f299a4a2d71db1b7e5f3e62132032fb00 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Nov 2005 12:16:49 +0100 Subject: [PATCH 05/35] Bug#14616 - Freshly imported table returns error 124 when using LIMIT Initialized usable_keys from table->keys_in_use instead of ~0 in test_if_skip_sort_order(). It was possible that a disabled index was used for sorting. mysql-test/r/myisam.result: Bug#14616 - Freshly imported table returns error 124 when using LIMIT The test result. mysql-test/t/myisam.test: Bug#14616 - Freshly imported table returns error 124 when using LIMIT The test case. --- mysql-test/r/myisam.result | 10 ++++++++++ mysql-test/t/myisam.test | 12 ++++++++++++ sql/sql_select.cc | 8 ++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index c55bacdd371..e6df3499eb5 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -462,3 +462,13 @@ select count(*) from t1 where a is null; count(*) 2 drop table t1; +create table t1 ( +c1 varchar(32), +key (c1) +) engine=myisam; +alter table t1 disable keys; +insert into t1 values ('a'), ('b'); +select c1 from t1 order by c1 limit 1; +c1 +a +drop table t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 57b64e30bac..a502002d30e 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -446,3 +446,15 @@ explain select count(*) from t1 where a is null; select count(*) from t1 where a is null; drop table t1; +# +# Bug#14616 - Freshly imported table returns error 124 when using LIMIT +# +create table t1 ( + c1 varchar(32), + key (c1) +) engine=myisam; +alter table t1 disable keys; +insert into t1 values ('a'), ('b'); +select c1 from t1 order by c1 limit 1; +drop table t1; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 46f0139a608..6dd68a60f88 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6003,8 +6003,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, key_map usable_keys; DBUG_ENTER("test_if_skip_sort_order"); - /* Check which keys can be used to resolve ORDER BY */ - usable_keys= ~(key_map) 0; + /* + Check which keys can be used to resolve ORDER BY. + We must not try to use disabled keys. + */ + usable_keys= table->keys_in_use; + for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { if ((*tmp_order->item)->type() != Item::FIELD_ITEM) From 3004c8de2dfc822375202a16e07c3cad196301d8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Nov 2005 15:09:35 -0700 Subject: [PATCH 06/35] fix for BUG#7947 - failure to log DO RELEASE_LOCK() if we disconnect in the middle of transaction while holding the lock. Also test to make sure other binlogging issues reported in the bug have been addressed. sql/item_func.cc: fix for BUG#7947 mysql-test/r/rpl_bug7947.result: New BitKeeper file ``mysql-test/r/rpl_bug7947.result'' mysql-test/t/rpl_bug7947.test: New BitKeeper file ``mysql-test/t/rpl_bug7947.test'' --- mysql-test/r/rpl_bug7947.result | 48 +++++++++++++++++++++++++++++++++ mysql-test/t/rpl_bug7947.test | 22 +++++++++++++++ sql/item_func.cc | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/rpl_bug7947.result create mode 100644 mysql-test/t/rpl_bug7947.test diff --git a/mysql-test/r/rpl_bug7947.result b/mysql-test/r/rpl_bug7947.result new file mode 100644 index 00000000000..8053f47d7d5 --- /dev/null +++ b/mysql-test/r/rpl_bug7947.result @@ -0,0 +1,48 @@ +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; +begin; +create temporary table ti (a int) engine=innodb; +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +insert into ti values(1); +set autocommit=0; +create temporary table t1 (a int) type=myisam; +Warnings: +Warning 1287 'TYPE=storage_engine' is deprecated; use 'ENGINE=storage_engine' instead +commit; +insert t1 values (1); +rollback; +create table t0 (n int); +insert t0 select * from t1; +set autocommit=1; +insert into t0 select GET_LOCK("lock1",null); +set autocommit=0; +create table t2 (n int) engine=innodb; +insert into t2 values (3); +select get_lock("lock1",null); +get_lock("lock1",null) +1 +show binlog events from 79; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.000001 79 Query 1 79 use `test`; BEGIN +master-bin.000001 119 Query 1 79 use `test`; create temporary table ti (a int) engine=innodb +master-bin.000001 201 Query 1 201 use `test`; ROLLBACK +master-bin.000001 244 Query 1 244 use `test`; insert into ti values(1) +master-bin.000001 303 Query 1 303 use `test`; BEGIN +master-bin.000001 343 Query 1 303 use `test`; create temporary table t1 (a int) type=myisam +master-bin.000001 423 Query 1 423 use `test`; COMMIT +master-bin.000001 464 Query 1 464 use `test`; create table t0 (n int) +master-bin.000001 522 Query 1 522 use `test`; insert t0 select * from t1 +master-bin.000001 583 Query 1 583 use `test`; insert into t0 select GET_LOCK("lock1",null) +master-bin.000001 662 Query 1 662 use `test`; create table t2 (n int) engine=innodb +master-bin.000001 734 Query 1 734 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` +master-bin.000001 835 Query 1 835 use `test`; DO RELEASE_LOCK("lock1") +select release_lock("lock1"); +release_lock("lock1") +1 +drop table t0,t2; diff --git a/mysql-test/t/rpl_bug7947.test b/mysql-test/t/rpl_bug7947.test new file mode 100644 index 00000000000..15630ebea04 --- /dev/null +++ b/mysql-test/t/rpl_bug7947.test @@ -0,0 +1,22 @@ +--source include/master-slave.inc +connection master; +begin; +create temporary table ti (a int) engine=innodb; +rollback; +insert into ti values(1); +set autocommit=0; +create temporary table t1 (a int) type=myisam; commit; +insert t1 values (1); rollback; +create table t0 (n int); +insert t0 select * from t1; +set autocommit=1; +insert into t0 select GET_LOCK("lock1",null); +set autocommit=0; +create table t2 (n int) engine=innodb; +insert into t2 values (3); +disconnect master; +connect (master,localhost,root,,test,$MASTER_MYPORT,master.sock); +select get_lock("lock1",null); +show binlog events from 79; +select release_lock("lock1"); +drop table t0,t2; diff --git a/sql/item_func.cc b/sql/item_func.cc index aff4adb788a..d80eed4754a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1975,7 +1975,7 @@ void item_user_lock_release(User_level_lock *ull) tmp.copy(command, strlen(command), tmp.charset()); tmp.append(ull->key,ull->key_length); tmp.append("\")", 2); - Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1, FALSE); + Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),0, FALSE); qev.error_code=0; // this query is always safe to run on slave mysql_bin_log.write(&qev); } From 232652e9d68d4d8c84d6183a69a0fdd9b6a88c8d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Nov 2005 20:51:30 -0700 Subject: [PATCH 07/35] changed select release_lock() to do release_lock() to avoid having to compare the non-deterministic result in the test case for BUG#7947 the bug fix for BUG#7947 now fixed the result of mix_innodb_myisam_binlog test, which in the past was missing DO RELEASE_LOCK() in the output of SHOW BINLOG EVENTS mysql-test/r/mix_innodb_myisam_binlog.result: DO RELEASE_LOCK() was supposed to be there from the very start mysql-test/r/rpl_bug7947.result: changed select release_lock() to do release_lock() to avoid having to compare the non-deterministic result mysql-test/t/rpl_bug7947.test: changed select release_lock() to do release_lock() to avoid having to compare the non-deterministic result --- mysql-test/r/mix_innodb_myisam_binlog.result | 1 + mysql-test/r/rpl_bug7947.result | 4 +--- mysql-test/t/rpl_bug7947.test | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 72288d1027b..587209a26ae 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -93,6 +93,7 @@ master-bin.000001 79 Query 1 79 use `test`; BEGIN master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(8) master-bin.000001 178 Query 1 79 use `test`; insert into t2 select * from t1 master-bin.000001 244 Query 1 244 use `test`; ROLLBACK +master-bin.000001 287 Query 1 287 use `test`; DO RELEASE_LOCK("a") delete from t1; delete from t2; reset master; diff --git a/mysql-test/r/rpl_bug7947.result b/mysql-test/r/rpl_bug7947.result index 8053f47d7d5..117e71a63d5 100644 --- a/mysql-test/r/rpl_bug7947.result +++ b/mysql-test/r/rpl_bug7947.result @@ -42,7 +42,5 @@ master-bin.000001 583 Query 1 583 use `test`; insert into t0 select GET_LOCK("lo master-bin.000001 662 Query 1 662 use `test`; create table t2 (n int) engine=innodb master-bin.000001 734 Query 1 734 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` master-bin.000001 835 Query 1 835 use `test`; DO RELEASE_LOCK("lock1") -select release_lock("lock1"); -release_lock("lock1") -1 +do release_lock("lock1"); drop table t0,t2; diff --git a/mysql-test/t/rpl_bug7947.test b/mysql-test/t/rpl_bug7947.test index 15630ebea04..e802a311b6c 100644 --- a/mysql-test/t/rpl_bug7947.test +++ b/mysql-test/t/rpl_bug7947.test @@ -18,5 +18,5 @@ disconnect master; connect (master,localhost,root,,test,$MASTER_MYPORT,master.sock); select get_lock("lock1",null); show binlog events from 79; -select release_lock("lock1"); +do release_lock("lock1"); drop table t0,t2; From 425207c938447c209756351a3e4a00d66eb9c3c1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 11:10:52 +0100 Subject: [PATCH 08/35] Fixed BUG#14723: Dumping of stored functions seems to cause corruption in the function body Changed the way the end of query was found from the lex state. The routine body was not extracted correctly when using the /*!version ... */ wrapper (in dump files); for some types of routines (e.g. with a label at the first begin), the trailing "*/" was not skipped. mysql-test/r/sp.result: New test case for BUG#14723. mysql-test/t/sp.test: New test case for BUG#14723. sql/sp_head.cc: Changed the way the end of the definition and body is found from the lex state. In the case of /*!version */ wrappers we must take the trailing " */" into account. --- mysql-test/r/sp.result | 31 +++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 32 ++++++++++++++++++++++++++++++++ sql/sp_head.cc | 25 ++++++++++++++----------- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index d50e6dd3751..1e49f966bc4 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3617,4 +3617,35 @@ count(*) drop table t3, t4| drop procedure bug14210| set @@session.max_heap_table_size=default| +drop function if exists bug14723| +drop procedure if exists bug14723| +/*!50003 create function bug14723() +returns bigint(20) +main_loop: begin +return 42; +end */;; +show create function bug14723;; +Function sql_mode Create Function +bug14723 CREATE FUNCTION `bug14723`() RETURNS bigint(20) +main_loop: begin +return 42; +end +select bug14723();; +bug14723() +42 +/*!50003 create procedure bug14723() +main_loop: begin +select 42; +end */;; +show create procedure bug14723;; +Procedure sql_mode Create Procedure +bug14723 CREATE PROCEDURE `bug14723`() +main_loop: begin +select 42; +end +call bug14723();; +42 +42 +drop function bug14723| +drop procedure bug14723| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index eaf69c0ab03..362faec167c 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4541,6 +4541,38 @@ drop table t3, t4| drop procedure bug14210| set @@session.max_heap_table_size=default| + +# +# BUG#1473: Dumping of stored functions seems to cause corruption in +# the function body +# +--disable_warnings +drop function if exists bug14723| +drop procedure if exists bug14723| +--enable_warnings + +delimiter ;;| +/*!50003 create function bug14723() + returns bigint(20) +main_loop: begin + return 42; +end */;; +show create function bug14723;; +select bug14723();; + +/*!50003 create procedure bug14723() +main_loop: begin + select 42; +end */;; +show create procedure bug14723;; +call bug14723();; + +delimiter |;; + +drop function bug14723| +drop procedure bug14723| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_head.cc b/sql/sp_head.cc index abc66ce0b21..3073372cd00 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -476,7 +476,7 @@ void sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) { DBUG_ENTER("sp_head::init_strings"); - uint n; /* Counter for nul trimming */ + uchar *endp; /* Used to trim the end */ /* During parsing, we must use thd->mem_root */ MEM_ROOT *root= thd->mem_root; @@ -509,17 +509,20 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) (char *)m_param_begin, m_params.length); } - m_body.length= lex->ptr - m_body_begin; - /* Trim nuls at the end */ - n= 0; - while (m_body.length && m_body_begin[m_body.length-1] == '\0') - { - m_body.length-= 1; - n+= 1; - } + /* If ptr has overrun end_of_query then end_of_query is the end */ + endp= (lex->ptr > lex->end_of_query ? lex->end_of_query : lex->ptr); + /* + Trim "garbage" at the end. This is sometimes needed with the + "/ * ! VERSION... * /" wrapper in dump files. + */ + while (m_body_begin < endp && + (endp[-1] <= ' ' || endp[-1] == '*' || + endp[-1] == '/' || endp[-1] == ';')) + endp-= 1; + + m_body.length= endp - m_body_begin; m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length); - m_defstr.length= lex->ptr - lex->buf; - m_defstr.length-= n; + m_defstr.length= endp - lex->buf; m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length); DBUG_VOID_RETURN; } From 56f43d9d021ddad1342d5f9c8b47f56a4adbc04e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 20:03:32 +0300 Subject: [PATCH 09/35] Fix bug #13622 Wrong view .frm created if some field's alias contain \n View .frm parser assumes that query string will take only 1 line, with \n in aliases query stringmay take several lines thus produces bad .frm file. 'query' parameter type changed from 'string' to 'escaped string' sql/sql_view.cc: Fix bug #13622 \n in column alias results in broken .frm 'query' parameter type changed to 'escaped string' mysql-test/r/view.result: Test case for bug #13622 Wrong view .frm created if some field's alias contain \n mysql-test/t/view.test: Test case for bug #13622 Wrong view .frm created if some field's alias contain \n --- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 9 +++++++++ sql/sql_view.cc | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6f15e7af399..45d7ef6882d 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2323,3 +2323,11 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +create table t1 (f1 int); +create view v1 as select t1.f1 as '123 +456' from t1; +select * from v1; +123 +456 +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index aa3189bad69..3bb1e9beb11 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2189,4 +2189,13 @@ EXPLAIN SELECT * FROM v2 WHERE a=1; DROP VIEW v1,v2; DROP TABLE t1,t2,t3; +# +# Bug #13622 Wrong view .frm created if some field's alias contain \n +# +create table t1 (f1 int); +create view v1 as select t1.f1 as '123 +456' from t1; +select * from v1; +drop view v1; +drop table t1; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index b30f8cb156c..4e7074dc0e5 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -496,7 +496,7 @@ static const int num_view_backups= 3; static File_option view_parameters[]= {{{(char*) STRING_WITH_LEN("query")}, offsetof(TABLE_LIST, query), - FILE_OPTIONS_STRING}, + FILE_OPTIONS_ESTRING}, {{(char*) STRING_WITH_LEN("md5")}, offsetof(TABLE_LIST, md5), FILE_OPTIONS_STRING}, From 26eb2ecc1dc076331c118e2ab314ffad1ef9e687 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Nov 2005 15:23:04 -0800 Subject: [PATCH 10/35] Update out-of-date URLs in 'help' text of mysql client. (Bug #14801) client/mysql.cc: Update text, URLs in mysql client 'help' text --- client/mysql.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index d408e8a5423..1c4fbf8f06f 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1813,9 +1813,13 @@ com_help(String *buffer __attribute__((unused)), if (help_arg) return com_server_help(buffer,line,help_arg+1); - put_info("\nFor the complete MySQL Manual online, visit:\n http://www.mysql.com/documentation\n", INFO_INFO); - put_info("For info on technical support from MySQL developers, visit:\n http://www.mysql.com/support\n", INFO_INFO); - put_info("For info on MySQL books, utilities, consultants, etc., visit:\n http://www.mysql.com/portal\n", INFO_INFO); + put_info("\nFor information about MySQL products and services, visit:\n" + " http://www.mysql.com/\n" + "For developer information, including the MySQL Reference Manual, " + "visit:\n" + " http://dev.mysql.com/\n" + "To buy MySQL Network Support, training, or other products, visit:\n" + " https://shop.mysql.com/\n", INFO_INFO); put_info("List of all MySQL commands:", INFO_INFO); if (!named_cmds) put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO); From dc44851352f68e240074ecc571216a8c2503ae0b Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Nov 2005 11:25:14 +0400 Subject: [PATCH 11/35] Fix for BUG#5686 - #1034 - Incorrect key file for table - only utf8 myisam/ft_parser.c: word->len calculation correction. mysql-test/r/fulltext.result: Test case for bug#5686. mysql-test/t/fulltext.test: Test case for bug#5686. --- myisam/ft_parser.c | 4 +++- mysql-test/r/fulltext.result | 4 ++++ mysql-test/t/fulltext.test | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 0b1e68b0d70..8e4769ebc75 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -188,8 +188,10 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end, for (word->pos=doc; doclen= (uint)(doc-word->pos) - mwc; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 8fa2df2e756..87551f96a13 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -428,4 +428,8 @@ REPAIR TABLE t1; Table Op Msg_type Msg_text test.t1 repair status OK SET myisam_repair_threads=@@global.myisam_repair_threads; +INSERT INTO t1 VALUES('testword\'\''); +SELECT a FROM t1 WHERE MATCH a AGAINST('testword' IN BOOLEAN MODE); +a +testword'' DROP TABLE t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index fa63778c4c1..7c7927b638b 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -348,6 +348,12 @@ INSERT INTO t1 VALUES('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); SET myisam_repair_threads=2; REPAIR TABLE t1; SET myisam_repair_threads=@@global.myisam_repair_threads; + +# +# BUG#5686 - #1034 - Incorrect key file for table - only utf8 +# +INSERT INTO t1 VALUES('testword\'\''); +SELECT a FROM t1 WHERE MATCH a AGAINST('testword' IN BOOLEAN MODE); DROP TABLE t1; # End of 4.1 tests From 6c708fadcbdc4449c8307c23cf27b0ec7f70067e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 21:52:39 +0300 Subject: [PATCH 12/35] Fix bug #14850 Item_ref's null_value wasn't updated Item_ref's null_value wasn't updated in save_org_in_field() causing reported error. sql/item.h: Fix bug #14850 Item_ref's null_value wasn't updated Make save_org_in_field() update Item_ref's null_value. mysql-test/r/view.result: Test case for bug #14850 Item_ref's null_value wasn't updated mysql-test/t/view.test: Test case for bug #14850 Item_ref's null_value wasn't updated --- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/item.h | 6 +++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 97df059c86a..ded9eb199f7 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2385,3 +2385,11 @@ show create view v1; View Create View v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` drop view v1; +create table t1(f1 int, f2 int); +insert into t1 values (null, 10), (null,2); +create view v1 as select * from t1; +select f1, sum(f2) from v1 group by f1; +f1 sum(f2) +NULL 12 +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 5addcd2570d..899279dc912 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2253,3 +2253,13 @@ drop view v1; create definer = current_user sql security invoker view v1 as select 1; show create view v1; drop view v1; + +# +# Bug #14850 Item_ref's values wasn't updated +# +create table t1(f1 int, f2 int); +insert into t1 values (null, 10), (null,2); +create view v1 as select * from t1; +select f1, sum(f2) from v1 group by f1; +drop view v1; +drop table t1; diff --git a/sql/item.h b/sql/item.h index 8bc659c3060..332eac70145 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1603,7 +1603,11 @@ public: void make_field(Send_field *field); bool fix_fields(THD *, Item **); int save_in_field(Field *field, bool no_conversions); - void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } + void save_org_in_field(Field *field) + { + (*ref)->save_org_in_field(field); + null_value= (*ref)->null_value; + } enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } Field *get_tmp_table_field() From 0a9badeca4aae7afe7a6f7028c11cf22dbfd6aaa Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Nov 2005 22:10:34 +0300 Subject: [PATCH 13/35] Fix bug #14816 test_if_order_by_key() expected only Item_fields. test_if_order_by_key() expected only Item_fields to be in order->item, thus failing to find available index on view's field, which results in reported error. Now test_if_order_by_key() calls order->item->real_item() to get field for choosing index. sql/sql_select.cc: Fix bug #14816 test_if_order_by_key() expected only Item_fields. Make test_if_order_by_key() use real_item() to get field. mysql-test/r/view.result: Test case for bug#14816 test_if_order_by_key() expected only Item_fields. mysql-test/t/view.test: Test case for bug#14816 test_if_order_by_key() expected only Item_fields. --- mysql-test/r/view.result | 8 ++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 97df059c86a..bc0e00dfffb 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2385,3 +2385,11 @@ show create view v1; View Create View v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select 1 AS `1` drop view v1; +create table t1 (id INT, primary key(id)); +insert into t1 values (1),(2); +create view v1 as select * from t1; +explain select id from v1 order by id; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 5addcd2570d..32c6eefb830 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2253,3 +2253,13 @@ drop view v1; create definer = current_user sql security invoker view v1 as select 1; show create view v1; drop view v1; + +# +# Bug #14816 test_if_order_by_key() expected only Item_fields. +# +create table t1 (id INT, primary key(id)); +insert into t1 values (1),(2); +create view v1 as select * from t1; +explain select id from v1 order by id; +drop view v1; +drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 44c4ec998bb..b65e25335fc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10988,7 +10988,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, for (; order ; order=order->next, const_key_parts>>=1) { - Field *field=((Item_field*) (*order->item))->field; + Field *field=((Item_field*) (*order->item)->real_item())->field; int flag; /* From 69fae29c589e92233cf63ae32bffb9c6023d3780 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Nov 2005 18:14:53 +0200 Subject: [PATCH 14/35] Test suite for BUG#13673 (the bug was fixed in the bugfix for BUG#14138) mysql-test/r/analyze.result: Test suite for BUG#13673 mysql-test/t/analyze.test: Test suite for BUG#13673 --- mysql-test/r/analyze.result | 7 +++++++ mysql-test/t/analyze.test | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/mysql-test/r/analyze.result b/mysql-test/r/analyze.result index 0b44a502b13..796b382f5d6 100644 --- a/mysql-test/r/analyze.result +++ b/mysql-test/r/analyze.result @@ -30,3 +30,10 @@ check table t1; Table Op Msg_type Msg_text test.t1 check status OK drop table t1; +CREATE TABLE t1 (a int); +prepare stmt1 from "SELECT * FROM t1 PROCEDURE ANALYSE()"; +execute stmt1; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +execute stmt1; +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +deallocate prepare stmt1; diff --git a/mysql-test/t/analyze.test b/mysql-test/t/analyze.test index 3c3b3933bc3..5d653b65579 100644 --- a/mysql-test/t/analyze.test +++ b/mysql-test/t/analyze.test @@ -39,4 +39,13 @@ check table t1; drop table t1; +# +# procedure in PS BUG#13673 +# +CREATE TABLE t1 (a int); +prepare stmt1 from "SELECT * FROM t1 PROCEDURE ANALYSE()"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + # End of 4.1 tests From 675226728c40b2b9c477b7628a867292b243351d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Nov 2005 18:01:30 +0100 Subject: [PATCH 15/35] Bug#14616 - Freshly imported table returns error 124 when using LIMIT After merge fix. --- mysql-test/r/myisam.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 352cc2fabb9..d2d0417f6e6 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -498,7 +498,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary 1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct drop table t1,t2; -drop table t1; create table t1 ( c1 varchar(32), key (c1) @@ -508,6 +507,7 @@ insert into t1 values ('a'), ('b'); select c1 from t1 order by c1 limit 1; c1 a +drop table t1; CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) ENGINE=MyISAM; Got one of the listed errors create table t1 (a int, b varchar(200), c text not null) checksum=1; From 4b1cb9888811edc1d307b4926bc786b284c508a0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Nov 2005 13:38:06 -0700 Subject: [PATCH 16/35] merged in the test case for BUG#7947 BitKeeper/deleted/.del-rpl_bug7947.result~1b40af7545a6c692: Delete: mysql-test/r/rpl_bug7947.result BitKeeper/deleted/.del-rpl_bug7947.test~20613cfdc560a16c: Delete: mysql-test/t/rpl_bug7947.test --- mysql-test/r/mix_innodb_myisam_binlog.result | 48 ++++++++++++++++++++ mysql-test/r/rpl_bug7947.result | 46 ------------------- mysql-test/t/mix_innodb_myisam_binlog.test | 28 +++++++++++- mysql-test/t/rpl_bug7947.test | 22 --------- 4 files changed, 75 insertions(+), 69 deletions(-) delete mode 100644 mysql-test/r/rpl_bug7947.result delete mode 100644 mysql-test/t/rpl_bug7947.test diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 587209a26ae..a586ad93ce4 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -203,3 +203,51 @@ select (@after-@before) >= 2; (@after-@before) >= 2 1 drop table t1,t2; +commit; +begin; +create temporary table ti (a int) engine=innodb; +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +insert into ti values(1); +set autocommit=0; +create temporary table t1 (a int) engine=myisam; +commit; +insert t1 values (1); +rollback; +create table t0 (n int); +insert t0 select * from t1; +set autocommit=1; +insert into t0 select GET_LOCK("lock1",null); +set autocommit=0; +create table t2 (n int) engine=innodb; +insert into t2 values (3); +select get_lock("lock1",null); +get_lock("lock1",null) +0 +show binlog events from 79; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.000001 79 Query 1 79 use `test`; BEGIN +master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(16) +master-bin.000001 179 Query 1 79 use `test`; insert into t1 values(18) +master-bin.000001 239 Query 1 239 use `test`; COMMIT +master-bin.000001 280 Query 1 280 use `test`; delete from t1 +master-bin.000001 329 Query 1 329 use `test`; delete from t2 +master-bin.000001 378 Query 1 378 use `test`; alter table t2 type=MyISAM +master-bin.000001 439 Query 1 439 use `test`; insert into t1 values (1) +master-bin.000001 499 Query 1 499 use `test`; insert into t2 values (20) +master-bin.000001 560 Query 1 560 use `test`; drop table t1,t2 +master-bin.000001 611 Query 1 611 use `test`; BEGIN +master-bin.000001 651 Query 1 611 use `test`; create temporary table ti (a int) engine=innodb +master-bin.000001 733 Query 1 733 use `test`; ROLLBACK +master-bin.000001 776 Query 1 776 use `test`; insert into ti values(1) +master-bin.000001 835 Query 1 835 use `test`; BEGIN +master-bin.000001 875 Query 1 835 use `test`; create temporary table t1 (a int) engine=myisam +master-bin.000001 957 Query 1 957 use `test`; COMMIT +master-bin.000001 998 Query 1 998 use `test`; create table t0 (n int) +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 +do release_lock("lock1"); +drop table t0,t2; diff --git a/mysql-test/r/rpl_bug7947.result b/mysql-test/r/rpl_bug7947.result deleted file mode 100644 index 117e71a63d5..00000000000 --- a/mysql-test/r/rpl_bug7947.result +++ /dev/null @@ -1,46 +0,0 @@ -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; -begin; -create temporary table ti (a int) engine=innodb; -rollback; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back -insert into ti values(1); -set autocommit=0; -create temporary table t1 (a int) type=myisam; -Warnings: -Warning 1287 'TYPE=storage_engine' is deprecated; use 'ENGINE=storage_engine' instead -commit; -insert t1 values (1); -rollback; -create table t0 (n int); -insert t0 select * from t1; -set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); -set autocommit=0; -create table t2 (n int) engine=innodb; -insert into t2 values (3); -select get_lock("lock1",null); -get_lock("lock1",null) -1 -show binlog events from 79; -Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 79 Query 1 79 use `test`; BEGIN -master-bin.000001 119 Query 1 79 use `test`; create temporary table ti (a int) engine=innodb -master-bin.000001 201 Query 1 201 use `test`; ROLLBACK -master-bin.000001 244 Query 1 244 use `test`; insert into ti values(1) -master-bin.000001 303 Query 1 303 use `test`; BEGIN -master-bin.000001 343 Query 1 303 use `test`; create temporary table t1 (a int) type=myisam -master-bin.000001 423 Query 1 423 use `test`; COMMIT -master-bin.000001 464 Query 1 464 use `test`; create table t0 (n int) -master-bin.000001 522 Query 1 522 use `test`; insert t0 select * from t1 -master-bin.000001 583 Query 1 583 use `test`; insert into t0 select GET_LOCK("lock1",null) -master-bin.000001 662 Query 1 662 use `test`; create table t2 (n int) engine=innodb -master-bin.000001 734 Query 1 734 use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` -master-bin.000001 835 Query 1 835 use `test`; DO RELEASE_LOCK("lock1") -do release_lock("lock1"); -drop table t0,t2; diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index 6eb9eae2d99..a25ab9c368e 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -206,7 +206,33 @@ select (@after:=unix_timestamp())*0; # always give repeatable output # the bug, the reap would return immediately after the insert into t2. select (@after-@before) >= 2; -# cleanup drop table t1,t2; +commit; + +# test for BUG#7947 - DO RELEASE_LOCK() not written to binlog on rollback in the middle +# of a transaction + +connection con2; +begin; +create temporary table ti (a int) engine=innodb; +rollback; +insert into ti values(1); +set autocommit=0; +create temporary table t1 (a int) engine=myisam; commit; +insert t1 values (1); rollback; +create table t0 (n int); +insert t0 select * from t1; +set autocommit=1; +insert into t0 select GET_LOCK("lock1",null); +set autocommit=0; +create table t2 (n int) engine=innodb; +insert into t2 values (3); +disconnect con2; +connection con3; +select get_lock("lock1",null); +show binlog events from 79; +do release_lock("lock1"); +drop table t0,t2; + # End of 4.1 tests diff --git a/mysql-test/t/rpl_bug7947.test b/mysql-test/t/rpl_bug7947.test deleted file mode 100644 index e802a311b6c..00000000000 --- a/mysql-test/t/rpl_bug7947.test +++ /dev/null @@ -1,22 +0,0 @@ ---source include/master-slave.inc -connection master; -begin; -create temporary table ti (a int) engine=innodb; -rollback; -insert into ti values(1); -set autocommit=0; -create temporary table t1 (a int) type=myisam; commit; -insert t1 values (1); rollback; -create table t0 (n int); -insert t0 select * from t1; -set autocommit=1; -insert into t0 select GET_LOCK("lock1",null); -set autocommit=0; -create table t2 (n int) engine=innodb; -insert into t2 values (3); -disconnect master; -connect (master,localhost,root,,test,$MASTER_MYPORT,master.sock); -select get_lock("lock1",null); -show binlog events from 79; -do release_lock("lock1"); -drop table t0,t2; From 013b3d8ab33b052d504a2e3fa63a85c919c649cc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 Nov 2005 21:57:02 +0100 Subject: [PATCH 17/35] Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Version for 5.0. It fixes three problems: 1. The cause of the bug was that we did not check the table version for the HANDLER ... READ commands. We did not notice when a table was replaced by a new one. This can happen during ALTER TABLE, REPAIR TABLE, and OPTIMIZE TABLE (there might be more cases). I call the fix for this problem "the primary bug fix". 2. mysql_ha_flush() was not always called with a locked LOCK_open. Though the function comment clearly said it must. I changed the code so that the locking is done when required. I call the fix for this problem "the secondary fix". 3. In 5.0 (not in 4.1 or 4.0) DROP TABLE had a possible deadlock flaw in concur with FLUSH TABLES WITH READ LOCK. I call the fix for this problem "the 5.0 addendum fix". include/my_pthread.h: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Added a new macro for the 5.0 addendum fix. mysql-test/r/handler.result: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The test result. mysql-test/t/handler.test: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The test case. sql/lock.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed a comment which did confuse me and which is not fully correct anymore after the 5.0 addendum fix. Added an assertion which would fire without the 5.0 addendum fix. sql/mysql_priv.h: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed a definition for the secondary fix. sql/sql_base.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed function calls for the secondary fix. sql/sql_class.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Changed a function call for the secondary fix. sql/sql_handler.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The first two diffs make the primary bug fix. The rest is for the secondary fix. sql/sql_table.cc: Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash The first diff (four changed places) make the 5.0 addendum fix. The other three are changed function calls for the secondary fix. --- include/my_pthread.h | 8 +++- mysql-test/r/handler.result | 37 ++++++++++++++++++ mysql-test/t/handler.test | 75 +++++++++++++++++++++++++++++++++++++ sql/lock.cc | 18 +++++++-- sql/mysql_priv.h | 3 +- sql/sql_base.cc | 7 ++-- sql/sql_class.cc | 2 +- sql/sql_handler.cc | 50 +++++++++++++++++++++++-- sql/sql_table.cc | 23 +++++++----- 9 files changed, 200 insertions(+), 23 deletions(-) diff --git a/include/my_pthread.h b/include/my_pthread.h index ee2c801ff6e..6f60a6df2c1 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -536,9 +536,15 @@ void safe_mutex_end(FILE *file); #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) #define pthread_mutex_trylock(A) pthread_mutex_lock(A) #define pthread_mutex_t safe_mutex_t -#define safe_mutex_assert_owner(mp) DBUG_ASSERT((mp)->count > 0 && pthread_equal(pthread_self(),(mp)->thread)) +#define safe_mutex_assert_owner(mp) \ + DBUG_ASSERT((mp)->count > 0 && \ + pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_assert_not_owner(mp) \ + DBUG_ASSERT(! (mp)->count || \ + ! pthread_equal(pthread_self(), (mp)->thread)) #else #define safe_mutex_assert_owner(mp) +#define safe_mutex_assert_not_owner(mp) #endif /* SAFE_MUTEX */ /* READ-WRITE thread locking */ diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 072d4582cbc..133683fb273 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -445,3 +445,40 @@ drop table t2; drop table t3; drop table t4; drop table t5; +create table t1 (c1 int); +insert into t1 values (1); +handler t1 open; +handler t1 read first; +c1 +1 +send the below to another connection, do not wait for the result + optimize table t1; +proceed with the normal connection +handler t1 read next; +c1 +1 +handler t1 close; +read the result from the other connection +Table Op Msg_type Msg_text +test.t1 optimize status OK +proceed with the normal connection +drop table t1; +create table t1 (c1 int); +insert into t1 values (14397); +flush tables with read lock; +drop table t1; +ERROR HY000: Can't execute the query because you have a conflicting read lock +send the below to another connection, do not wait for the result + drop table t1; +proceed with the normal connection +select * from t1; +c1 +14397 +unlock tables; +read the result from the other connection +proceed with the normal connection +select * from t1; +ERROR 42S02: Table 'test.t1' doesn't exist +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 1bb9b1d3504..f3e14c3cd2b 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -347,4 +347,79 @@ drop table t3; drop table t4; drop table t5; +# +# Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash +# +create table t1 (c1 int); +insert into t1 values (1); +# client 1 +handler t1 open; +handler t1 read first; +# client 2 +connect (con2,localhost,root,,); +connection con2; +--exec echo send the below to another connection, do not wait for the result +send optimize table t1; +--sleep 1 +# client 1 +--exec echo proceed with the normal connection +connection default; +handler t1 read next; +handler t1 close; +# client 2 +--exec echo read the result from the other connection +connection con2; +reap; +# client 1 +--exec echo proceed with the normal connection +connection default; +drop table t1; + # End of 4.1 tests + +# +# Addendum to Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash +# Show that DROP TABLE can no longer deadlock against +# FLUSH TABLES WITH READ LOCK. This is a 5.0 issue. +# +create table t1 (c1 int); +insert into t1 values (14397); +flush tables with read lock; +# The thread with the global read lock cannot drop the table itself: +--error 1223 +drop table t1; +# +# client 2 +# We need a second connection to try the drop. +# The drop waits for the global read lock to go away. +# Without the addendum fix it locked LOCK_open before entering the wait loop. +connection con2; +--exec echo send the below to another connection, do not wait for the result +send drop table t1; +--sleep 1 +# +# client 1 +# Now we need something that wants LOCK_open. A simple table access which +# opens the table does the trick. +--exec echo proceed with the normal connection +connection default; +# This would hang on LOCK_open without the 5.0 addendum fix. +select * from t1; +# Release the read lock. This should make the DROP go through. +unlock tables; +# +# client 2 +# Read the result of the drop command. +connection con2; +--exec echo read the result from the other connection +reap; +# +# client 1 +# Now back to normal operation. The table should not exist any more. +--exec echo proceed with the normal connection +connection default; +--error 1146 +select * from t1; +# Just to be sure and not confuse the next test case writer. +drop table if exists t1; + diff --git a/sql/lock.cc b/sql/lock.cc index f4c4a781e45..fe8dcb3aa5e 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -815,10 +815,13 @@ static void print_lock_error(int error, const char *table) access to them is protected with a mutex LOCK_global_read_lock - (XXX: one should never take LOCK_open if LOCK_global_read_lock is taken, - otherwise a deadlock may occur - see mysql_rm_table. Other mutexes could - be a problem too - grep the code for global_read_lock if you want to use - any other mutex here) + (XXX: one should never take LOCK_open if LOCK_global_read_lock is + taken, otherwise a deadlock may occur. Other mutexes could be a + problem too - grep the code for global_read_lock if you want to use + any other mutex here) Also one must not hold LOCK_open when calling + wait_if_global_read_lock(). When the thread with the global read lock + tries to close its tables, it needs to take LOCK_open in + close_thread_table(). How blocking of threads by global read lock is achieved: that's advisory. Any piece of code which should be blocked by global read lock must @@ -937,6 +940,13 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, DBUG_ENTER("wait_if_global_read_lock"); LINT_INIT(old_message); + /* + Assert that we do not own LOCK_open. If we would own it, other + threads could not close their tables. This would make a pretty + deadlock. + */ + safe_mutex_assert_not_owner(&LOCK_open); + (void) pthread_mutex_lock(&LOCK_global_read_lock); if ((need_exit_cond= must_wait)) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1719253a458..2a65b99585a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -890,7 +890,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen); bool mysql_ha_close(THD *thd, TABLE_LIST *tables); bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List *,enum ha_rkey_function,Item *,ha_rows,ha_rows); -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags); +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked); /* mysql_ha_flush mode_flags bits */ #define MYSQL_HA_CLOSE_FINAL 0x00 #define MYSQL_HA_REOPEN_ON_USAGE 0x01 diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1e7fce9001f..771a70ffebb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -311,7 +311,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, + TRUE); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", @@ -1238,7 +1239,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, /* close handler tables which are marked for flush */ if (thd->handler_tables) - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -1642,7 +1643,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index fc9df020b6c..7ffe60ec2b2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -376,7 +376,7 @@ void THD::cleanup(void) close_thread_tables(this); } mysql_ha_flush(this, (TABLE_LIST*) 0, - MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); + MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE); hash_free(&handler_tables_hash); delete_dynamic(&user_var_events); hash_free(&user_vars); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index cc45a7001cd..07f4de26707 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -336,6 +336,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit_cnt, ha_rows offset_limit_cnt) { TABLE_LIST *hash_tables; + TABLE **table_ptr; TABLE *table; MYSQL_LOCK *lock; List list; @@ -368,6 +369,28 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->table_name, hash_tables->alias, table)); + /* Table might have been flushed. */ + if (table && (table->s->version != refresh_version)) + { + /* + We must follow the thd->handler_tables chain, as we need the + address of the 'next' pointer referencing this table + for close_thread_table(). + */ + for (table_ptr= &(thd->handler_tables); + *table_ptr && (*table_ptr != table); + table_ptr= &(*table_ptr)->next) + {} + (*table_ptr)->file->ha_index_or_rnd_end(); + VOID(pthread_mutex_lock(&LOCK_open)); + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } + VOID(pthread_mutex_unlock(&LOCK_open)); + table= hash_tables->table= NULL; + } if (!table) { /* @@ -594,6 +617,7 @@ err0: MYSQL_HA_REOPEN_ON_USAGE mark for reopen. MYSQL_HA_FLUSH_ALL flush all tables, not only those marked for flush. + is_locked If LOCK_open is locked. DESCRIPTION The list of HANDLER tables may be NULL, in which case all HANDLER @@ -601,7 +625,6 @@ err0: If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, all HANDLER tables marked for flush are closed. Broadcasts a COND_refresh condition, for every table closed. - The caller must lock LOCK_open. NOTE Since mysql_ha_flush() is called when the base table has to be closed, @@ -611,10 +634,12 @@ err0: 0 ok */ -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked) { TABLE_LIST *tmp_tables; TABLE **table_ptr; + bool did_lock= FALSE; DBUG_ENTER("mysql_ha_flush"); DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); @@ -640,6 +665,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) (*table_ptr)->s->db, (*table_ptr)->s->table_name, (*table_ptr)->alias)); + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -658,6 +689,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) if ((mode_flags & MYSQL_HA_FLUSH_ALL) || ((*table_ptr)->s->version != refresh_version)) { + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -665,6 +702,10 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) } } + /* Release the lock if it was taken by this function. */ + if (did_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(0); } @@ -696,8 +737,8 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) table->alias, mode_flags)); if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, - (byte*) (*table_ptr)->alias, - strlen((*table_ptr)->alias) + 1))) + (byte*) table->alias, + strlen(table->alias) + 1))) { if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) { @@ -712,6 +753,7 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) } (*table_ptr)->file->ha_index_or_rnd_end(); + safe_mutex_assert_owner(&LOCK_open); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c0748abf333..0d6ef9bb767 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -103,23 +103,28 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, /* mark for close and remove all cached entries */ - thd->mysys_var->current_mutex= &LOCK_open; - thd->mysys_var->current_cond= &COND_refresh; - VOID(pthread_mutex_lock(&LOCK_open)); - if (!drop_temporary) { if ((error= wait_if_global_read_lock(thd, 0, 1))) { my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name); - goto err; + DBUG_RETURN(TRUE); } else need_start_waiters= TRUE; } + + /* + Acquire LOCK_open after wait_if_global_read_lock(). If we would hold + LOCK_open during wait_if_global_read_lock(), other threads could not + close their tables. This would make a pretty deadlock. + */ + thd->mysys_var->current_mutex= &LOCK_open; + thd->mysys_var->current_cond= &COND_refresh; + VOID(pthread_mutex_lock(&LOCK_open)); + error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0); -err: pthread_mutex_unlock(&LOCK_open); pthread_mutex_lock(&thd->mysys_var->mutex); @@ -232,7 +237,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, char *db=table->db; db_type table_type= DB_TYPE_UNKNOWN; - mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, TRUE); if (!close_temporary_table(thd, db, table->table_name)) { tmp_table_deleted=1; @@ -2171,7 +2176,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, FALSE); for (table= tables; table; table= table->next_local) { char table_name[NAME_LEN*2+2]; @@ -3128,7 +3133,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, new_db= db; used_fields=create_info->used_fields; - mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE); /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, From 517967de1ab922113a97d0dd19d0c2ea50978c67 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 18:26:30 +1100 Subject: [PATCH 18/35] WL#2779 ndb_size.pl fix some small bugs, slightly improve output, add --help ndb/tools/ndb_size.pl: Provide --help and --usage. Fix some bugs related to quoting table names. ndb/tools/ndb_size.tmpl: A NAME and A HREF to tables from the main list --- ndb/tools/ndb_size.pl | 30 +++++++++++++++++++----------- ndb/tools/ndb_size.tmpl | 6 +++--- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/ndb/tools/ndb_size.pl b/ndb/tools/ndb_size.pl index 64a20423636..0203b0c1112 100644 --- a/ndb/tools/ndb_size.pl +++ b/ndb/tools/ndb_size.pl @@ -26,24 +26,33 @@ use HTML::Template; # BUGS # ---- # - enum/set is 0 byte storage! Woah - efficient! +# - DECIMAL is 0 byte storage. A bit too efficient. # - some float stores come out weird (when there's a comma e.g. 'float(4,1)') # - no disk data values # - computes the storage requirements of views (and probably MERGE) # - ignores character sets. my $template = HTML::Template->new(filename => 'ndb_size.tmpl', - die_on_bad_params => 0); + die_on_bad_params => 0) + or die "Could not open ndb_size.tmpl."; my $dbh; +if(@ARGV < 3 || $ARGV[0] eq '--usage' || $ARGV[0] eq '--help') +{ + print STDERR "Usage:\n"; + print STDERR "\tndb_size.pl database hostname user password\n\n"; + print STDERR "If you need to specify a port number, use host:port\n\n"; + exit(1); +} + { my $database= $ARGV[0]; my $hostname= $ARGV[1]; - my $port= $ARGV[2]; - my $user= $ARGV[3]; - my $password= $ARGV[4]; - my $dsn = "DBI:mysql:database=$database;host=$hostname;port=$port"; - $dbh= DBI->connect($dsn, $user, $password); + my $user= $ARGV[2]; + my $password= $ARGV[3]; + my $dsn = "DBI:mysql:database=$database;host=$hostname"; + $dbh= DBI->connect($dsn, $user, $password) or exit(1); $template->param(db => $database); $template->param(dsn => $dsn); } @@ -68,9 +77,8 @@ foreach(@{$tables}) { my $table= @{$_}[0]; my @columns; - my $info= $dbh->selectall_hashref("describe ".$dbh->quote($table),"Field"); - my @count = $dbh->selectrow_array("select count(*) from " - .$dbh->quote($table)); + my $info= $dbh->selectall_hashref('describe `'.$table.'`',"Field"); + my @count = $dbh->selectrow_array('select count(*) from `'.$table.'`'); my %columnsize; # used for index calculations # We now work out the DataMemory usage @@ -132,7 +140,7 @@ foreach(@{$tables}) my $fixed= 1+$size; my @dynamic=$dbh->selectrow_array("select avg(length(" .$dbh->quote($name) - .")) from ".$dbh->quote($table)); + .")) from `".$table.'`'); $dynamic[0]=0 if !$dynamic[0]; @realsize= ($fixed,$fixed,ceil($dynamic[0])); } @@ -166,7 +174,7 @@ foreach(@{$tables}) # we can still connect to pre-5.0 mysqlds. my %indexes; { - my $sth= $dbh->prepare("show index from "$dbh->quote($table)); + my $sth= $dbh->prepare("show index from `".$table.'`'); $sth->execute; while(my $i = $sth->fetchrow_hashref) { diff --git a/ndb/tools/ndb_size.tmpl b/ndb/tools/ndb_size.tmpl index d83d5d2c6af..5d9fc8bf0c5 100644 --- a/ndb/tools/ndb_size.tmpl +++ b/ndb/tools/ndb_size.tmpl @@ -13,18 +13,18 @@ td,th { border: 1px solid black }

MySQL Cluster analysis for

This is an automated analysis of the database for migration into MySQL Cluster. No warranty is made to the accuracy of the information.

-

This information should be valid for MySQL 4.1

+

This information should be valid for MySQL 4.1 and 5.0. Since 5.1 is not a final release yet, the numbers should be used as a guide only.


-

+

">

From 74ae82f5c4ed135f4edbc0aa223a45fdd507cb3b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 19:47:03 +1100 Subject: [PATCH 19/35] WL#2779 ndb_size.pl Add display of minimum requirements for various cluster parameters e.g. DataMemory, IndexMemory, MaxNoOfTables, MaxNoOfAttributes etc and the memory usage because of them. ndb/tools/ndb_size.pl: Computer minimum parameter settings (MaxNoOfTables, Attributes, Indexes, Triggers) and the memory usage because of these settings. ndb/tools/ndb_size.tmpl: display parameters --- ndb/tools/ndb_size.pl | 57 ++++++++++++++++++++++++++++++++++++++++- ndb/tools/ndb_size.tmpl | 40 +++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/ndb/tools/ndb_size.pl b/ndb/tools/ndb_size.pl index 0203b0c1112..ece0901e0b2 100644 --- a/ndb/tools/ndb_size.pl +++ b/ndb/tools/ndb_size.pl @@ -64,6 +64,14 @@ my $tables = $dbh->selectall_arrayref("show tables"); my @table_size; +my @dbDataMemory; +my @dbIndexMemory; +my @NoOfAttributes; +my @NoOfIndexes; +my @NoOfTables; +$NoOfTables[$_]{val} = @{$tables} foreach 0..$#releases; + + sub align { my($to,@unaligned) = @_; my @aligned; @@ -147,7 +155,10 @@ foreach(@{$tables}) elsif($type =~ /binary/ || $type =~ /char/) {@realsize=($size,$size,$size)} elsif($type =~ /text/ || $type =~ /blob/) - {@realsize=(256,256,1)} # FIXME check if 5.1 is correct + { + @realsize=(256,256,1); + $NoOfTables[$_]{val} += 1 foreach 0..$#releases; # blob uses table + } # FIXME check if 5.1 is correct @realsize= align(4,@realsize); @@ -265,7 +276,51 @@ foreach(@{$tables}) IndexMemory=>\@IndexMemory, }; + + $dbDataMemory[$_]{val} += $DataMemory[$_]{val} foreach 0..$#releases; + $dbIndexMemory[$_]{val} += $IndexMemory[$_]{val} foreach 0..$#releases; + $NoOfAttributes[$_]{val} += @columns foreach 0..$#releases; + $NoOfIndexes[$_]{val} += @indexes foreach 0..$#releases; +} + +my @NoOfTriggers; +# for unique hash indexes +$NoOfTriggers[$_]{val} += $NoOfIndexes[$_]{val}*3 foreach 0..$#releases; +# for ordered index +$NoOfTriggers[$_]{val} += $NoOfIndexes[$_]{val} foreach 0..$#releases; + +my @ParamMemory; +foreach (0..$#releases) { + $ParamMemory[0]{releases}[$_]{val}= POSIX::ceil(200*$NoOfAttributes[$_]{val}/1024); + $ParamMemory[0]{name}= 'Attributes'; + + $ParamMemory[1]{releases}[$_]{val}= 20*$NoOfTables[$_]{val}; + $ParamMemory[1]{name}= 'Tables'; + + $ParamMemory[2]{releases}[$_]{val}= 10*$NoOfIndexes[$_]{val}; + $ParamMemory[2]{name}= 'OrderedIndexes'; + + $ParamMemory[3]{releases}[$_]{val}= 15*$NoOfIndexes[$_]{val}; + $ParamMemory[3]{name}= 'UniqueHashIndexes'; } $template->param(tables => \@table_size); +$template->param(Parameters => [{name=>'DataMemory (kb)', + releases=>\@dbDataMemory}, + {name=>'IndexMemory (kb)', + releases=>\@dbIndexMemory}, + {name=>'MaxNoOfTables', + releases=>\@NoOfTables}, + {name=>'MaxNoOfAttributes', + releases=>\@NoOfAttributes}, + {name=>'MaxNoOfOrderedIndexes', + releases=>\@NoOfIndexes}, + {name=>'MaxNoOfUniqueHashIndexes', + releases=>\@NoOfIndexes}, + {name=>'MaxNoOfTriggers', + releases=>\@NoOfTriggers} + ] + ); +$template->param(ParamMemory => \@ParamMemory); + print $template->output; diff --git a/ndb/tools/ndb_size.tmpl b/ndb/tools/ndb_size.tmpl index 5d9fc8bf0c5..dc02b5a5970 100644 --- a/ndb/tools/ndb_size.tmpl +++ b/ndb/tools/ndb_size.tmpl @@ -15,6 +15,46 @@ td,th { border: 1px solid black }

This information should be valid for MySQL 4.1 and 5.0. Since 5.1 is not a final release yet, the numbers should be used as a guide only.

+

Parameter Settings

+

NOTE the configuration parameters below do not take into account system tables and other requirements.

+
Column
+ + + + + + + + + + + + + + +
Parameter
+ +

Memory usage because of parameters

+ +

Usage is in kilobytes. Actual usage will vary as you should set the parameters larger than those listed in the table above.

+ + + + + + + + + + + + + + + +
Parameter
+ +

Table List

  • ">
  • From 563e5c8d7961c79106fcf3b83656942ece4b4cd4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 11:52:09 +0100 Subject: [PATCH 20/35] ndb - bug#14007 4.1 [re-commit for LenZ merge] mysql-test/r/ndb_charset.result: bug#14007 test [re-commit] mysql-test/t/ndb_charset.test: bug#14007 test [re-commit] ndb/include/kernel/AttributeDescriptor.hpp: bug#14007 4.1 need getSizeInBytes [re-commit] ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp: bug#14007 4.1 *** do not AUTOmerge to 5.0 *** [re-commit] --- mysql-test/r/ndb_charset.result | 22 +++++++++++++----- mysql-test/t/ndb_charset.test | 19 ++++++++------- ndb/include/kernel/AttributeDescriptor.hpp | 9 ++++++++ ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp | 23 ++++++++++++++++++- 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/ndb_charset.result b/mysql-test/r/ndb_charset.result index 00bc36a7c0d..b8d881fca83 100644 --- a/mysql-test/r/ndb_charset.result +++ b/mysql-test/r/ndb_charset.result @@ -190,12 +190,22 @@ p a 6 AAA drop table t1; create table t1 ( -a varchar(10) primary key -) engine=ndb; -insert into t1 values ('jonas % '); -replace into t1 values ('jonas % '); -replace into t1 values ('jonas % '); +a char(10) primary key +) engine=ndbcluster default charset=latin1; +insert into t1 values ('aaabb'); select * from t1; a -jonas % +aaabb +replace into t1 set a = 'AAABB'; +select * from t1; +a +AAABB +replace into t1 set a = 'aAaBb'; +select * from t1; +a +aAaBb +replace into t1 set a = 'aaabb'; +select * from t1; +a +aaabb drop table t1; diff --git a/mysql-test/t/ndb_charset.test b/mysql-test/t/ndb_charset.test index 89f1ed17cfb..a885427f593 100644 --- a/mysql-test/t/ndb_charset.test +++ b/mysql-test/t/ndb_charset.test @@ -159,14 +159,17 @@ select * from t1 where a = 'AaA' order by p; select * from t1 where a = 'AAA' order by p; drop table t1; -# bug +# bug#14007 create table t1 ( - a varchar(10) primary key -) engine=ndb; -insert into t1 values ('jonas % '); -replace into t1 values ('jonas % '); -replace into t1 values ('jonas % '); + a char(10) primary key +) engine=ndbcluster default charset=latin1; + +insert into t1 values ('aaabb'); +select * from t1; +replace into t1 set a = 'AAABB'; +select * from t1; +replace into t1 set a = 'aAaBb'; +select * from t1; +replace into t1 set a = 'aaabb'; select * from t1; drop table t1; - -# End of 4.1 tests diff --git a/ndb/include/kernel/AttributeDescriptor.hpp b/ndb/include/kernel/AttributeDescriptor.hpp index 071d45e2607..9d7de21d904 100644 --- a/ndb/include/kernel/AttributeDescriptor.hpp +++ b/ndb/include/kernel/AttributeDescriptor.hpp @@ -36,6 +36,7 @@ private: static Uint32 getType(const Uint32 &); static Uint32 getSize(const Uint32 &); + static Uint32 getSizeInBytes(const Uint32 &); static Uint32 getSizeInWords(const Uint32 &); static Uint32 getArrayType(const Uint32 &); static Uint32 getArraySize(const Uint32 &); @@ -79,6 +80,7 @@ private: #define AD_SIZE_SHIFT (4) #define AD_SIZE_MASK (7) +#define AD_SIZE_IN_BYTES_SHIFT (3) #define AD_SIZE_IN_WORDS_OFFSET (31) #define AD_SIZE_IN_WORDS_SHIFT (5) @@ -185,6 +187,13 @@ AttributeDescriptor::getSize(const Uint32 & desc){ return (desc >> AD_SIZE_SHIFT) & AD_SIZE_MASK; } +inline +Uint32 +AttributeDescriptor::getSizeInBytes(const Uint32 & desc){ + return (getArraySize(desc) << getSize(desc)) + >> AD_SIZE_IN_BYTES_SHIFT; +} + inline Uint32 AttributeDescriptor::getSizeInWords(const Uint32 & desc){ diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index cbb165c3eb1..7b642f90a17 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -700,6 +700,27 @@ Dbtup::checkUpdateOfPrimaryKey(Uint32* updateBuffer, Tablerec* const regTabPtr) Uint32 attrDescriptorIndex = regTabPtr->tabDescriptor + (attributeId << ZAD_LOG_SIZE); Uint32 attrDescriptor = tableDescriptor[attrDescriptorIndex].tabDescr; Uint32 attributeOffset = tableDescriptor[attrDescriptorIndex + 1].tabDescr; + + Uint32 xfrmBuffer[1 + MAX_KEY_SIZE_IN_WORDS * 1]; // strxfrm_multiply == 1 + Uint32 charsetFlag = AttributeOffset::getCharsetFlag(attributeOffset); + if (charsetFlag) { + Uint32 csPos = AttributeOffset::getCharsetPos(attributeOffset); + CHARSET_INFO* cs = regTabPtr->charsetArray[csPos]; + Uint32 sizeInBytes = AttributeDescriptor::getSizeInBytes(attrDescriptor); + Uint32 sizeInWords = AttributeDescriptor::getSizeInWords(attrDescriptor); + const uchar* srcPtr = (uchar*)&updateBuffer[1]; + uchar* dstPtr = (uchar*)&xfrmBuffer[1]; + Uint32 n = + (*cs->coll->strnxfrm)(cs, dstPtr, sizeInBytes, srcPtr, sizeInBytes); + // pad with blanks (unlikely) and zeroes to match NDB API behaviour + while (n < sizeInBytes) + dstPtr[n++] = 0x20; + while (n < 4 * sizeInWords) + dstPtr[n++] = 0; + xfrmBuffer[0] = ahIn.m_value; + updateBuffer = xfrmBuffer; + } + ReadFunction f = regTabPtr->readFunctionArray[attributeId]; AttributeHeader::init(&attributeHeader, attributeId, 0); @@ -707,7 +728,7 @@ Dbtup::checkUpdateOfPrimaryKey(Uint32* updateBuffer, Tablerec* const regTabPtr) tMaxRead = MAX_KEY_SIZE_IN_WORDS; bool tmp = tXfrmFlag; - tXfrmFlag = false; + tXfrmFlag = true; ndbrequire((this->*f)(&keyReadBuffer[0], ahOut, attrDescriptor, attributeOffset)); tXfrmFlag = tmp; ndbrequire(tOutBufIndex == ahOut->getDataSize()); From 8a661e77ea3759eb0bdc0fd1a0caecc708593732 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 14:09:06 +0200 Subject: [PATCH 21/35] Issuing error about presence of commit/rollback statements in stored functions and triggers added to SP parsing procedure (BUG#13627) The crash mentioned in original bug report is already prevented by one of previous patches (fix for bug #13343 "CREATE|etc TRIGGER|VIEW|USER don't commit the transaction (inconsistency)"), this patch only improve error returning. mysql-test/r/sp-error.result: Test that statements which implicitly commit transaction mysql-test/t/sp-error.test: Test that statements which implicitly commit transaction sql/sp_head.cc: We set the new flag about commit/rollback statements presence sql/sp_head.h: The new flag about commit/rollback presence added A comment fixed sql/sql_yacc.yy: Removed commit/rollback-statement-present errors spread by this file, only one check left which check flags of a SP --- mysql-test/r/sp-error.result | 103 ++++++++++++++++++++++++++ mysql-test/t/sp-error.test | 138 +++++++++++++++++++++++++++++++++++ sql/sp_head.cc | 39 ++++++++++ sql/sp_head.h | 13 +++- sql/sql_yacc.yy | 57 +-------------- 5 files changed, 293 insertions(+), 57 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index fabbf13a96b..2f4b420a2ae 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -872,6 +872,109 @@ names foo4 drop procedure bug13510_3| drop procedure bug13510_4| +drop function if exists bug_13627_f| +CREATE TABLE t1 (a int)| +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DROP TRIGGER test1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN DROP TRIGGER test1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN load table t1 from master; END | +ERROR 0A000: LOAD TABLE is not allowed in stored procedures +CREATE FUNCTION bug_13627_f() returns int BEGIN load table t1 from master; return 1; END | +ERROR 0A000: LOAD TABLE is not allowed in stored procedures +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create table t2 (a int); END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create table t2 (a int); return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create index t1_i on t1 (a); END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create index t1_i on t1 (a); return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter table t1 add column b int; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN alter table t1 add column b int; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename table t1 to t2; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN rename table t1 to t2; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN truncate table t1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN truncate table t1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop table t1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop table t1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop index t1_i on t1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop index t1_i on t1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN unlock tables; END | +ERROR 0A000: UNLOCK is not allowed in stored procedures +CREATE FUNCTION bug_13627_f() returns int BEGIN unlock tables; return 1; END | +ERROR 0A000: UNLOCK is not allowed in stored procedures +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN LOCK TABLE t1 READ; END | +ERROR 0A000: LOCK is not allowed in stored procedures +CREATE FUNCTION bug_13627_f() returns int BEGIN LOCK TABLE t1 READ; return 1; END | +ERROR 0A000: LOCK is not allowed in stored procedures +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create database mysqltest; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create database mysqltest; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop database mysqltest; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop database mysqltest; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create view v1 as select 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create view v1 as select 1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter view v1 as select 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN alter view v1 as select 1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop view v1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop view v1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create trigger tr2 before insert on t1 for each row do select 1; END | +ERROR 2F003: Can't create a TRIGGER from within another stored routine +CREATE FUNCTION bug_13627_f() returns int BEGIN create trigger tr2 before insert on t1 for each row do select 1; return 1; END | +ERROR 2F003: Can't create a TRIGGER from within another stored routine +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop function bug_13627_f; END | +ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine +CREATE FUNCTION bug_13627_f() returns int BEGIN drop function bug_13627_f; return 1; END | +ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create function f2 () returns int return 1; END | +ERROR 2F003: Can't create a FUNCTION from within another stored routine +CREATE FUNCTION bug_13627_f() returns int BEGIN create function f2 () returns int return 1; return 1; END | +ERROR 2F003: Can't create a FUNCTION from within another stored routine +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +CREATE TEMPORARY TABLE t2 (a int); +DROP TEMPORARY TABLE t2; +END | +CREATE FUNCTION bug_13627_f() returns int +BEGIN +CREATE TEMPORARY TABLE t2 (a int); +DROP TEMPORARY TABLE t2; +return 1; +END | +drop table t1| +drop function bug_13627_f| create database mysqltest1; use mysqltest1; drop database mysqltest1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 3c1efe73c18..f16562227f3 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1263,6 +1263,144 @@ call bug13510_4()| drop procedure bug13510_3| drop procedure bug13510_4| + + +# +# Test that statements which implicitly commit transaction are prohibited +# in stored function and triggers. Attempt to create function or trigger +# containing such statement should produce error (includes test for +# bug #13627). +# +--disable_warnings +drop function if exists bug_13627_f| +--enable_warnings + +CREATE TABLE t1 (a int)| +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DROP TRIGGER test1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN DROP TRIGGER test1; return 1; END | + +-- error ER_SP_BADSTATEMENT +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN load table t1 from master; END | +-- error ER_SP_BADSTATEMENT +CREATE FUNCTION bug_13627_f() returns int BEGIN load table t1 from master; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create table t2 (a int); END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create table t2 (a int); return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create index t1_i on t1 (a); END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create index t1_i on t1 (a); return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter table t1 add column b int; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN alter table t1 add column b int; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename table t1 to t2; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN rename table t1 to t2; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN truncate table t1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN truncate table t1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop table t1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop table t1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop index t1_i on t1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop index t1_i on t1; return 1; END | + +-- error ER_SP_BADSTATEMENT +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN unlock tables; END | +-- error ER_SP_BADSTATEMENT +CREATE FUNCTION bug_13627_f() returns int BEGIN unlock tables; return 1; END | + +-- error ER_SP_BADSTATEMENT +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN LOCK TABLE t1 READ; END | +-- error ER_SP_BADSTATEMENT +CREATE FUNCTION bug_13627_f() returns int BEGIN LOCK TABLE t1 READ; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create database mysqltest; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create database mysqltest; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop database mysqltest; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop database mysqltest; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create view v1 as select 1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create view v1 as select 1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter view v1 as select 1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN alter view v1 as select 1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop view v1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop view v1; return 1; END | + +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create trigger tr2 before insert on t1 for each row do select 1; END | +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE FUNCTION bug_13627_f() returns int BEGIN create trigger tr2 before insert on t1 for each row do select 1; return 1; END | + +-- error ER_SP_NO_DROP_SP +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop function bug_13627_f; END | +-- error ER_SP_NO_DROP_SP +CREATE FUNCTION bug_13627_f() returns int BEGIN drop function bug_13627_f; return 1; END | + +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create function f2 () returns int return 1; END | +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE FUNCTION bug_13627_f() returns int BEGIN create function f2 () returns int return 1; return 1; END | + +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW + BEGIN + CREATE TEMPORARY TABLE t2 (a int); + DROP TEMPORARY TABLE t2; + END | +CREATE FUNCTION bug_13627_f() returns int + BEGIN + CREATE TEMPORARY TABLE t2 (a int); + DROP TEMPORARY TABLE t2; + return 1; + END | + +drop table t1| +drop function bug_13627_f| + delimiter ;| # diff --git a/sql/sp_head.cc b/sql/sp_head.cc index facd984cc50..e3cdc909048 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -120,6 +120,45 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_DEALLOCATE_PREPARE: flags= sp_head::CONTAINS_DYNAMIC_SQL; break; + case SQLCOM_CREATE_TABLE: + if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) + flags= 0; + else + flags= sp_head::HAS_COMMIT_OR_ROLLBACK; + break; + case SQLCOM_DROP_TABLE: + if (lex->drop_temporary) + flags= 0; + else + flags= sp_head::HAS_COMMIT_OR_ROLLBACK; + break; + case SQLCOM_CREATE_INDEX: + case SQLCOM_CREATE_DB: + case SQLCOM_CREATE_VIEW: + case SQLCOM_CREATE_TRIGGER: + case SQLCOM_CREATE_USER: + case SQLCOM_ALTER_TABLE: + case SQLCOM_BEGIN: + case SQLCOM_RENAME_TABLE: + case SQLCOM_RENAME_USER: + case SQLCOM_DROP_INDEX: + case SQLCOM_DROP_DB: + case SQLCOM_DROP_USER: + case SQLCOM_DROP_VIEW: + case SQLCOM_DROP_TRIGGER: + case SQLCOM_TRUNCATE: + case SQLCOM_COMMIT: + case SQLCOM_ROLLBACK: + case SQLCOM_LOAD_MASTER_DATA: + case SQLCOM_LOCK_TABLES: + case SQLCOM_CREATE_PROCEDURE: + case SQLCOM_CREATE_SPFUNCTION: + case SQLCOM_ALTER_PROCEDURE: + case SQLCOM_ALTER_FUNCTION: + case SQLCOM_DROP_PROCEDURE: + case SQLCOM_DROP_FUNCTION: + flags= sp_head::HAS_COMMIT_OR_ROLLBACK; + break; default: flags= 0; break; diff --git a/sql/sp_head.h b/sql/sp_head.h index d1a122fd410..8c2d58a696e 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -115,10 +115,13 @@ public: MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s) CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE IS_INVOKED= 32, // Is set if this sp_head is being used - HAS_SET_AUTOCOMMIT_STMT = 64 // Is set if a procedure with 'set autocommit' + HAS_SET_AUTOCOMMIT_STMT= 64,// Is set if a procedure with 'set autocommit' + /* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */ + HAS_COMMIT_OR_ROLLBACK= 128 }; - int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE + /* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */ + int m_type; uint m_flags; // Boolean attributes of a stored routine enum enum_field_types m_returns; // For FUNCTIONs only Field::geometry_type m_geom_returns; @@ -292,6 +295,12 @@ public: my_error(ER_SP_NO_RETSET, MYF(0), where); else if (m_flags & HAS_SET_AUTOCOMMIT_STMT) my_error(ER_SP_CANT_SET_AUTOCOMMIT, MYF(0)); + else if (m_type != TYPE_ENUM_PROCEDURE && + (m_flags & sp_head::HAS_COMMIT_OR_ROLLBACK)) + { + my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); + return TRUE; + } return test(m_flags & (CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT)); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 55002def5e9..339091ed4e8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1159,11 +1159,6 @@ create: | CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON table_ident { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_CREATE_INDEX; if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL, TL_OPTION_UPDATING)) @@ -3299,11 +3294,6 @@ alter: { THD *thd= YYTHD; LEX *lex= thd->lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_ALTER_TABLE; lex->name= 0; lex->duplicates= DUP_ERROR; @@ -3614,11 +3604,6 @@ start: START_SYM TRANSACTION_SYM start_transaction_opts { LEX *lex= Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_BEGIN; lex->start_transaction_opt= $3; } @@ -3803,13 +3788,7 @@ opt_no_write_to_binlog: rename: RENAME table_or_tables { - LEX *lex= Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } - lex->sql_command=SQLCOM_RENAME_TABLE; + Lex->sql_command= SQLCOM_RENAME_TABLE; } table_to_table_list {} @@ -5946,21 +5925,10 @@ drop: lex->sql_command = SQLCOM_DROP_TABLE; lex->drop_temporary= $2; lex->drop_if_exists= $4; - if (!lex->drop_temporary && lex->sphead && - lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } } | DROP INDEX_SYM ident ON table_ident {} { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_DROP_INDEX; lex->alter_info.drop_list.empty(); lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY, @@ -6006,13 +5974,7 @@ drop: } | DROP VIEW_SYM if_exists table_list opt_restrict { - THD *thd= YYTHD; - LEX *lex= thd->lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } + LEX *lex= Lex; lex->sql_command= SQLCOM_DROP_VIEW; lex->drop_if_exists= $3; } @@ -8652,11 +8614,6 @@ begin: BEGIN_SYM { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command = SQLCOM_BEGIN; lex->start_transaction_opt= 0; } @@ -8689,11 +8646,6 @@ commit: COMMIT_SYM opt_work opt_chain opt_release { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_COMMIT; lex->tx_chain= $3; lex->tx_release= $4; @@ -8704,11 +8656,6 @@ rollback: ROLLBACK_SYM opt_work opt_chain opt_release { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_ROLLBACK; lex->tx_chain= $3; lex->tx_release= $4; From 74dcfd251b0508e713e49105c806b0ab5a248fd8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 13:26:26 +0100 Subject: [PATCH 22/35] ndb - bug#14007 5.0 *** does not automerge into 5.1 *** mysql-test/r/ndb_charset.result: bug#14007 5.0 mysql-test/t/ndb_charset.test: bug#14007 5.0 ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp: bug#14007 5.0 ndb/src/kernel/vm/SimulatedBlock.cpp: bug#14007 5.0 ndb/src/kernel/vm/SimulatedBlock.hpp: bug#14007 5.0 --- mysql-test/r/ndb_charset.result | 20 +++- mysql-test/t/ndb_charset.test | 15 ++- ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp | 22 ++--- ndb/src/kernel/vm/SimulatedBlock.cpp | 92 ++++++++++--------- ndb/src/kernel/vm/SimulatedBlock.hpp | 6 +- 5 files changed, 87 insertions(+), 68 deletions(-) diff --git a/mysql-test/r/ndb_charset.result b/mysql-test/r/ndb_charset.result index 500b0497890..3763e20e59a 100644 --- a/mysql-test/r/ndb_charset.result +++ b/mysql-test/r/ndb_charset.result @@ -306,11 +306,21 @@ count(*) drop table t1; create table t1 ( a char(10) primary key -) engine=ndb; -insert into t1 values ('jonas % '); -replace into t1 values ('jonas % '); -replace into t1 values ('jonas % '); +) engine=ndbcluster default charset=latin1; +insert into t1 values ('aaabb'); select * from t1; a -jonas % +aaabb +replace into t1 set a = 'AAABB'; +select * from t1; +a +AAABB +replace into t1 set a = 'aAaBb'; +select * from t1; +a +aAaBb +replace into t1 set a = 'aaabb'; +select * from t1; +a +aaabb drop table t1; diff --git a/mysql-test/t/ndb_charset.test b/mysql-test/t/ndb_charset.test index fb43e1831f3..5941e5750db 100644 --- a/mysql-test/t/ndb_charset.test +++ b/mysql-test/t/ndb_charset.test @@ -237,13 +237,18 @@ drop table t1; #select a,b,length(a),length(b) from t1 where a='c' and b='c'; #drop table t1; -# bug +# bug#14007 create table t1 ( a char(10) primary key -) engine=ndb; -insert into t1 values ('jonas % '); -replace into t1 values ('jonas % '); -replace into t1 values ('jonas % '); +) engine=ndbcluster default charset=latin1; + +insert into t1 values ('aaabb'); +select * from t1; +replace into t1 set a = 'AAABB'; +select * from t1; +replace into t1 set a = 'aAaBb'; +select * from t1; +replace into t1 set a = 'aaabb'; select * from t1; drop table t1; diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index db916b2d4d2..8a55777ac05 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -685,22 +685,16 @@ Dbtup::checkUpdateOfPrimaryKey(Uint32* updateBuffer, Tablerec* const regTabPtr) Uint32 attrDescriptor = tableDescriptor[attrDescriptorIndex].tabDescr; Uint32 attributeOffset = tableDescriptor[attrDescriptorIndex + 1].tabDescr; - Uint32 xfrmBuffer[1 + MAX_KEY_SIZE_IN_WORDS * 1]; // strxfrm_multiply == 1 + Uint32 xfrmBuffer[1 + MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY]; Uint32 charsetFlag = AttributeOffset::getCharsetFlag(attributeOffset); if (charsetFlag) { - Uint32 csPos = AttributeOffset::getCharsetPos(attributeOffset); - CHARSET_INFO* cs = regTabPtr->charsetArray[csPos]; - Uint32 sizeInBytes = AttributeDescriptor::getSizeInBytes(attrDescriptor); - Uint32 sizeInWords = AttributeDescriptor::getSizeInWords(attrDescriptor); - const uchar* srcPtr = (uchar*)&updateBuffer[1]; - uchar* dstPtr = (uchar*)&xfrmBuffer[1]; - Uint32 n = - (*cs->coll->strnxfrm)(cs, dstPtr, sizeInBytes, srcPtr, sizeInBytes); - // pad with blanks (unlikely) and zeroes to match NDB API behaviour - while (n < sizeInBytes) - dstPtr[n++] = 0x20; - while (n < 4 * sizeInWords) - dstPtr[n++] = 0; + Uint32 csIndex = AttributeOffset::getCharsetPos(attributeOffset); + CHARSET_INFO* cs = regTabPtr->charsetArray[csIndex]; + Uint32 srcPos = 0; + Uint32 dstPos = 0; + xfrm_attr(attrDescriptor, cs, &updateBuffer[1], srcPos, + &xfrmBuffer[1], dstPos, MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY); + ahIn.setDataSize(dstPos); xfrmBuffer[0] = ahIn.m_value; updateBuffer = xfrmBuffer; } diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp index d708052ca4e..4625cd43640 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.cpp +++ b/ndb/src/kernel/vm/SimulatedBlock.cpp @@ -1868,55 +1868,61 @@ SimulatedBlock::xfrm_key(Uint32 tab, const Uint32* src, while (i < noOfKeyAttr) { const KeyDescriptor::KeyAttr& keyAttr = desc->keyAttr[i]; - - Uint32 srcBytes = - AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor); - Uint32 srcWords = (srcBytes + 3) / 4; - Uint32 dstWords = ~0; - uchar* dstPtr = (uchar*)&dst[dstPos]; - const uchar* srcPtr = (const uchar*)&src[srcPos]; - CHARSET_INFO* cs = keyAttr.charsetInfo; - - if (cs == NULL) - { - jam(); - memcpy(dstPtr, srcPtr, srcWords << 2); - dstWords = srcWords; - } - else - { - jam(); - Uint32 typeId = - AttributeDescriptor::getType(keyAttr.attributeDescriptor); - Uint32 lb, len; - bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); - ndbrequire(ok); - Uint32 xmul = cs->strxfrm_multiply; - if (xmul == 0) - xmul = 1; - /* - * Varchar is really Char. End spaces do not matter. To get - * same hash we blank-pad to maximum length via strnxfrm. - * TODO use MySQL charset-aware hash function instead - */ - Uint32 dstLen = xmul * (srcBytes - lb); - ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); - int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); - ndbrequire(n != -1); - while ((n & 3) != 0) - { - dstPtr[n++] = 0; - } - dstWords = (n >> 2); - } - dstPos += dstWords; - srcPos += srcWords; + Uint32 dstWords = + xfrm_attr(keyAttr.attributeDescriptor, keyAttr.charsetInfo, + src, srcPos, dst, dstPos, dstSize); keyPartLen[i++] = dstWords; } return dstPos; } +Uint32 +SimulatedBlock::xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs, + const Uint32* src, Uint32 & srcPos, + Uint32* dst, Uint32 & dstPos, Uint32 dstSize) const +{ + Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(attrDesc); + Uint32 srcWords = (srcBytes + 3) / 4; + Uint32 dstWords = ~0; + uchar* dstPtr = (uchar*)&dst[dstPos]; + const uchar* srcPtr = (const uchar*)&src[srcPos]; + + if (cs == NULL) + { + jam(); + memcpy(dstPtr, srcPtr, srcWords << 2); + dstWords = srcWords; + } + else + { + jam(); + Uint32 typeId = AttributeDescriptor::getType(attrDesc); + Uint32 lb, len; + bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); + ndbrequire(ok); + Uint32 xmul = cs->strxfrm_multiply; + if (xmul == 0) + xmul = 1; + /* + * Varchar end-spaces are ignored in comparisons. To get same hash + * we blank-pad to maximum length via strnxfrm. + */ + Uint32 dstLen = xmul * (srcBytes - lb); + ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); + int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); + ndbrequire(n != -1); + while ((n & 3) != 0) + { + dstPtr[n++] = 0; + } + dstWords = (n >> 2); + } + dstPos += dstWords; + srcPos += srcWords; + return dstWords; +} + Uint32 SimulatedBlock::create_distr_key(Uint32 tableId, Uint32 *data, diff --git a/ndb/src/kernel/vm/SimulatedBlock.hpp b/ndb/src/kernel/vm/SimulatedBlock.hpp index ce77fa916d8..b7bd8c57ee8 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -395,8 +395,12 @@ protected: * @return length */ Uint32 xfrm_key(Uint32 tab, const Uint32* src, - Uint32 *dst, Uint32 dstLen, + Uint32 *dst, Uint32 dstSize, Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const; + + Uint32 xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs, + const Uint32* src, Uint32 & srcPos, + Uint32* dst, Uint32 & dstPos, Uint32 dstSize) const; /** * From dcf5d348cc74d9ad8963903e9b614c950a7e109a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 15:17:08 +0100 Subject: [PATCH 23/35] bug#14433 - archive uses wrong ref_length mysql-test/t/func_group.test: re-enable the test --- mysql-test/t/disabled.def | 1 - mysql-test/t/func_group.test | 4 ++-- sql/ha_archive.cc | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index eedf4b30e73..fe95a543fb5 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -15,4 +15,3 @@ rpl_relayrotate : Unstable test case, bug#12429 rpl_until : Unstable test case, bug#12429 rpl_deadlock : Unstable test case, bug#12429 kill : Unstable test case, bug#9712 -archive_gis : The test fails on 32bit Linux diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 9237205eeb5..c667f90940c 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -2,8 +2,6 @@ # simple test of all group functions # ---source include/have_innodb.inc - --disable_warnings drop table if exists t1,t2; --enable_warnings @@ -545,10 +543,12 @@ DROP TABLE t1; # Bug #12882 min/max inconsistent on empty table # +--disable_warnings create table t1m (a int) engine=myisam; create table t1i (a int) engine=innodb; create table t2m (a int) engine=myisam; create table t2i (a int) engine=innodb; +--enable_warnings insert into t2m values (5); insert into t2i values (5); diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index c4801de5fb2..1e8fc582eb8 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -233,7 +233,8 @@ ha_archive::ha_archive(TABLE *table_arg) buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); /* The size of the offset value we will use for position() */ - ref_length = sizeof(z_off_t); + ref_length = 2 << ((zlibCompileFlags() >> 6) & 3); + DBUG_ASSERT(ref_length <= sizeof(z_off_t)); } /* From cd1abd99db00f92311f5b3bba85fe6e997a29f0d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 15:58:17 +0100 Subject: [PATCH 24/35] Bug#14616 - Freshly imported table returns error 124 when using LIMIT After merge fix. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ae40a81643f..9c7df461a3e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11132,7 +11132,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, Check which keys can be used to resolve ORDER BY. We must not try to use disabled keys. */ - usable_keys= table->keys_in_use; + usable_keys= table->s->keys_in_use; for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { From b67076102b62454e5560cd5a7a484366b47eb984 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2005 03:15:10 +0300 Subject: [PATCH 25/35] A fix and a test case for Bug#14077 "Failure to replicate a stored function with a cursor". Enable execution of SELECT queries in SP on slave. mysql-test/r/rpl_sp.result: Test results were fixed (Bug#14077). mysql-test/t/rpl_sp.test: Add a test case for Bug#14077 "Failure to replicate a stored function with a cursor". sql/sql_parse.cc: Do not rewrite SELECTs with DOs on slave: if this SELECT was for a stored routine cursor, slave must be able to execute the SELECT in order to open a cursor. At the moment the bug is present only in stored functions and stored procedures called from stored functions, because, due to stored procedure unfolding for replication, top level stored procedures are never executed on slave. --- mysql-test/r/rpl_sp.result | 25 +++++++++++++++++++++++++ mysql-test/t/rpl_sp.test | 36 ++++++++++++++++++++++++++++++++++++ sql/sql_parse.cc | 12 ------------ 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index ba840caf6c2..41bcfc7d72c 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -375,3 +375,28 @@ drop procedure foo; drop function fn1; drop database mysqltest1; drop user "zedjzlcsjhd"@127.0.0.1; +use test; +use test; +drop function if exists f1; +create function f1() returns int reads sql data +begin +declare var integer; +declare c cursor for select a from v1; +open c; +fetch c into var; +close c; +return var; +end| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +a +1 +drop view v1; +drop function f1; +select * from t1; +a +1 +drop table t1; +reset master; diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index e7a3afca9cb..386582f8f1b 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -360,4 +360,40 @@ connection master; drop function fn1; drop database mysqltest1; drop user "zedjzlcsjhd"@127.0.0.1; +use test; sync_slave_with_master; +use test; + +# +# Bug#14077 "Failure to replicate a stored function with a cursor": +# verify that stored routines with cursors work on slave. +# +connection master; +--disable_warnings +drop function if exists f1; +--enable_warnings +delimiter |; +create function f1() returns int reads sql data +begin + declare var integer; + declare c cursor for select a from v1; + open c; + fetch c into var; + close c; + return var; +end| +delimiter ;| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +drop view v1; +drop function f1; +sync_slave_with_master; +connection slave; +select * from t1; + +# cleanup +connection master; +drop table t1; +reset master; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c19d54feda5..1e6810e0036 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2403,18 +2403,6 @@ mysql_execute_command(THD *thd) reset_one_shot_variables(thd); DBUG_RETURN(0); } -#ifndef TO_BE_DELETED - /* - This is a workaround to deal with the shortcoming in 3.23.44-3.23.46 - masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK() - as DO RELEASE_LOCK() - */ - if (lex->sql_command == SQLCOM_SELECT) - { - lex->sql_command = SQLCOM_DO; - lex->insert_list = &select_lex->item_list; - } -#endif } else #endif /* HAVE_REPLICATION */ From d518f7020011b685f6753b1d86e9dd7a98a9c171 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2005 03:51:14 +0300 Subject: [PATCH 26/35] Fix for bug #13399 Crash when executing PS/SP which should activate trigger which is now dropped" and bug #12329 "Bogus error msg when executing PS with stored procedure after SP was re-created". mysql-test/r/sp-error.result: Added test for bug #12329 "Bogus error msg when executing PS with stored procedure after SP was re-created". mysql-test/r/trigger.result: Added test for bug #13399 Crash when executing PS/SP which should activate trigger which is now dropped". mysql-test/t/sp-error.test: Added test for bug #12329 "Bogus error msg when executing PS with stored procedure after SP was re-created". mysql-test/t/trigger.test: Added test for bug #13399 Crash when executing PS/SP which should activate trigger which is now dropped". sql/sp_head.cc: sp_head::add_used_tables_to_table_list(): We have to copy database/table names and alias to PS/SP memory since current instance of sp_head object can pass away before next execution of PS/SP for which tables are added to prelocking list. This will be fixed by introducing of proper invalidation mechanism once new TDC is ready. --- mysql-test/r/sp-error.result | 18 +++++++++++++++++ mysql-test/r/trigger.result | 25 +++++++++++++++++++++++ mysql-test/t/sp-error.test | 22 ++++++++++++++++++++ mysql-test/t/trigger.test | 39 ++++++++++++++++++++++++++++++++++++ sql/sp_head.cc | 21 ++++++++++--------- 5 files changed, 115 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 2f4b420a2ae..26bb0fa4694 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -975,6 +975,24 @@ return 1; END | drop table t1| drop function bug_13627_f| +drop function if exists bug12329; +create table t1 as select 1 a; +create table t2 as select 1 a; +create function bug12329() returns int return (select a from t1); +prepare stmt1 from 'select bug12329()'; +execute stmt1; +bug12329() +1 +drop function bug12329; +create function bug12329() returns int return (select a+100 from t2); +select bug12329(); +bug12329() +101 +execute stmt1; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +deallocate prepare stmt1; +drop function bug12329; +drop table t1, t2; create database mysqltest1; use mysqltest1; drop database mysqltest1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index d3fbb56e493..af99dea58b9 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -738,3 +738,28 @@ f1 1 drop trigger t1_bi; drop tables t1, t2; +create table t1 (id int); +create table t2 (id int); +create trigger t1_bi before insert on t1 for each row insert into t2 values (new.id); +prepare stmt1 from "insert into t1 values (10)"; +create procedure p1() insert into t1 values (10); +call p1(); +drop trigger t1_bi; +execute stmt1; +call p1(); +deallocate prepare stmt1; +drop procedure p1; +create table t3 (id int); +create trigger t1_bi after insert on t1 for each row insert into t2 values (new.id); +prepare stmt1 from "insert into t1 values (10)"; +create procedure p1() insert into t1 values (10); +call p1(); +drop trigger t1_bi; +create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id); +execute stmt1; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +call p1(); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +deallocate prepare stmt1; +drop procedure p1; +drop table t1, t2, t3; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index f16562227f3..4cc141fea4b 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1403,6 +1403,28 @@ drop function bug_13627_f| delimiter ;| +# BUG#12329: "Bogus error msg when executing PS with stored procedure after +# SP was re-created". See also test for related bug#13399 in trigger.test +--disable_warnings +drop function if exists bug12329; +--enable_warnings +create table t1 as select 1 a; +create table t2 as select 1 a; +create function bug12329() returns int return (select a from t1); +prepare stmt1 from 'select bug12329()'; +execute stmt1; +drop function bug12329; +create function bug12329() returns int return (select a+100 from t2); +select bug12329(); +# Until we implement proper mechanism for invalidation of PS/SP when table +# or SP's are changed the following statement will fail with 'Table ... was +# not locked' error (this mechanism should be based on the new TDC). +--error 1100 +execute stmt1; +deallocate prepare stmt1; +drop function bug12329; +drop table t1, t2; + # # Bug#13514 "server crash when create a stored procedure before choose a # database" and diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index cd79eb82ace..02d994128e2 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -875,3 +875,42 @@ drop function f1; drop view v1; drop table t1, t2, t3; --enable_parsing + +# +# Test for bug #13399 "Crash when executing PS/SP which should activate +# trigger which is now dropped". See also test for similar bug for stored +# routines in sp-error.test (#12329). +create table t1 (id int); +create table t2 (id int); +create trigger t1_bi before insert on t1 for each row insert into t2 values (new.id); +prepare stmt1 from "insert into t1 values (10)"; +create procedure p1() insert into t1 values (10); +call p1(); +# Actually it is enough to do FLUSH TABLES instead of DROP TRIGGER +drop trigger t1_bi; +# Server should not crash on these two statements +execute stmt1; +call p1(); +deallocate prepare stmt1; +drop procedure p1; + +# Let us test more complex situation when we alter trigger in such way that +# it uses different set of tables (or simply add new trigger). +create table t3 (id int); +create trigger t1_bi after insert on t1 for each row insert into t2 values (new.id); +prepare stmt1 from "insert into t1 values (10)"; +create procedure p1() insert into t1 values (10); +call p1(); +# Altering trigger forcing it use different set of tables +drop trigger t1_bi; +create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id); +# Until we implement proper mechanism for invalidation of PS/SP when table +# or SP's are changed these two statements will fail with 'Table ... was +# not locked' error (this mechanism should be based on the new TDC). +--error 1100 +execute stmt1; +--error 1100 +call p1(); +deallocate prepare stmt1; +drop procedure p1; +drop table t1, t2, t3; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e3cdc909048..6248a60521b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2906,33 +2906,34 @@ sp_head::add_used_tables_to_table_list(THD *thd, DBUG_ENTER("sp_head::add_used_tables_to_table_list"); /* - Use persistent arena for table list allocation to be PS friendly. + Use persistent arena for table list allocation to be PS/SP friendly. + Note that we also have to copy database/table names and alias to PS/SP + memory since current instance of sp_head object can pass away before + next execution of PS/SP for which tables are added to prelocking list. + This will be fixed by introducing of proper invalidation mechanism + once new TDC is ready. */ arena= thd->activate_stmt_arena_if_needed(&backup); for (i=0 ; i < m_sptabs.records ; i++) { - char *tab_buff; + char *tab_buff, *key_buff; TABLE_LIST *table; SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i); if (stab->temp) continue; if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) * - stab->lock_count))) + stab->lock_count)) || + !(key_buff= (char*)thd->memdup(stab->qname.str, + stab->qname.length + 1))) DBUG_RETURN(FALSE); for (uint j= 0; j < stab->lock_count; j++) { table= (TABLE_LIST *)tab_buff; - /* - It's enough to just copy the pointers as the data will not change - during the lifetime of the SP. If the SP is used by PS, we assume - that the PS will be invalidated if the functions is deleted or - changed. - */ - table->db= stab->qname.str; + table->db= key_buff; table->db_length= stab->db_length; table->table_name= table->db + table->db_length + 1; table->table_name_length= stab->table_name_length; From 4d93df791452162f4ed54a4eb44178f1892b41ba Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Nov 2005 21:17:38 -0700 Subject: [PATCH 27/35] fixed the race condition in the test case for BUG#7947 --- mysql-test/r/mix_innodb_myisam_binlog.result | 8 +++++--- mysql-test/t/mix_innodb_myisam_binlog.test | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index a586ad93ce4..e9613bac833 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -222,9 +222,9 @@ insert into t0 select GET_LOCK("lock1",null); set autocommit=0; create table t2 (n int) engine=innodb; insert into t2 values (3); -select get_lock("lock1",null); -get_lock("lock1",null) -0 +select get_lock("lock1",60); +get_lock("lock1",60) +1 show binlog events from 79; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.000001 79 Query 1 79 use `test`; BEGIN @@ -249,5 +249,7 @@ 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") do release_lock("lock1"); drop table t0,t2; diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index a25ab9c368e..4581736ac8c 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -218,8 +218,10 @@ create temporary table ti (a int) engine=innodb; rollback; insert into ti values(1); set autocommit=0; -create temporary table t1 (a int) engine=myisam; commit; -insert t1 values (1); rollback; +create temporary table t1 (a int) engine=myisam; +commit; +insert t1 values (1); +rollback; create table t0 (n int); insert t0 select * from t1; set autocommit=1; @@ -229,7 +231,7 @@ create table t2 (n int) engine=innodb; insert into t2 values (3); disconnect con2; connection con3; -select get_lock("lock1",null); +select get_lock("lock1",60); show binlog events from 79; do release_lock("lock1"); drop table t0,t2; From 5b8a965408f172c5b00d5a1351cec32cd9645edf Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2005 16:20:12 +0300 Subject: [PATCH 28/35] A fix and a test case for Bug#13524 "lock timeout gives incorrect warning on open cursor" sql/sql_prepare.cc: A fix for Bug#13524 "lock timeout gives incorrect warning on open cursor": reset the connection for next command before performing a cursor fetch (add an omitted line). tests/mysql_client_test.c: A test case for Bug#13524 "lock timeout gives incorrect warning on open cursor" --- sql/sql_prepare.cc | 1 + tests/mysql_client_test.c | 63 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ced862170ec..c7145e3aabc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2312,6 +2312,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) Server_side_cursor *cursor; DBUG_ENTER("mysql_stmt_fetch"); + mysql_reset_thd_for_next_command(thd); statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) DBUG_VOID_RETURN; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index b065a0dfa03..e0f3fd91e5c 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14419,7 +14419,7 @@ static void test_bug14210() myquery(rc); } -/* Bug#13488 */ +/* Bug#13488: wrong column metadata when fetching from cursor */ static void test_bug13488() { @@ -14487,6 +14487,66 @@ static void test_bug13488() myquery(rc); } +/* + Bug#13524: warnings of a previous command are not reset when fetching + from a cursor. +*/ + +static void test_bug13524() +{ + MYSQL_STMT *stmt; + int rc; + unsigned int warning_count; + const ulong type= CURSOR_TYPE_READ_ONLY; + const char *query= "select * from t1"; + + myheader("test_bug13524"); + + rc= mysql_query(mysql, "drop table if exists t1, t2"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (a int not null primary key)"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + check_execute(stmt, rc); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + warning_count= mysql_warning_count(mysql); + DIE_UNLESS(warning_count == 0); + + /* Check that DROP TABLE produced a warning (no such table) */ + rc= mysql_query(mysql, "drop table if exists t2"); + myquery(rc); + warning_count= mysql_warning_count(mysql); + DIE_UNLESS(warning_count == 1); + + /* + Check that fetch from a cursor cleared the warning from the previous + command. + */ + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + warning_count= mysql_warning_count(mysql); + DIE_UNLESS(warning_count == 0); + + /* Cleanup */ + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14744,6 +14804,7 @@ static struct my_tests_st my_tests[]= { { "test_bug12243", test_bug12243 }, { "test_bug14210", test_bug14210 }, { "test_bug13488", test_bug13488 }, + { "test_bug13524", test_bug13524 }, { 0, 0 } }; From 30df60fa732eada8c7f9958710469c69cf81ab08 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2005 15:08:49 +0100 Subject: [PATCH 29/35] set_var.cc, mysqld.cc, ha_innodb.h: BUG#12701: SHOW VARIABLES does not show correct size of buffer pool. ha_innodb.cc: BUG#12701: SHOW VARIABLES does not show correct size of buffer pool sql/ha_innodb.cc: BUG#12701: SHOW VARIABLES does not show correct size of buffer pool sql/ha_innodb.h: BUG#12701: SHOW VARIABLES does not show correct size of buffer pool. sql/mysqld.cc: BUG#12701: SHOW VARIABLES does not show correct size of buffer pool. sql/set_var.cc: BUG#12701: SHOW VARIABLES does not show correct size of buffer pool. --- sql/ha_innodb.cc | 34 +++++++++++++++++++++++++++------- sql/ha_innodb.h | 5 +++-- sql/mysqld.cc | 8 +++++--- sql/set_var.cc | 4 ++-- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 556186d5584..60ec6f8e2bb 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -142,15 +142,16 @@ uint innobase_init_flags = 0; ulong innobase_cache_size = 0; ulong innobase_large_page_size = 0; -/* The default values for the following, type long, start-up parameters -are declared in mysqld.cc: */ +/* The default values for the following, type long or longlong, start-up +parameters are declared in mysqld.cc: */ long innobase_mirrored_log_groups, innobase_log_files_in_group, - innobase_log_file_size, innobase_log_buffer_size, - innobase_buffer_pool_awe_mem_mb, - innobase_buffer_pool_size, innobase_additional_mem_pool_size, - innobase_file_io_threads, innobase_lock_wait_timeout, - innobase_force_recovery, innobase_open_files; + innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb, + innobase_additional_mem_pool_size, innobase_file_io_threads, + innobase_lock_wait_timeout, innobase_force_recovery, + innobase_open_files; + +longlong innobase_buffer_pool_size, innobase_log_file_size; /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -1210,6 +1211,25 @@ innobase_init(void) ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); + /* Check that values don't overflow on 32-bit systems. */ + if (sizeof(ulint) == 4) { + if (innobase_buffer_pool_size > UINT_MAX32) { + sql_print_error( + "innobase_buffer_pool_size can't be over 4GB" + " on 32-bit systems"); + + DBUG_RETURN(0); + } + + if (innobase_log_file_size > UINT_MAX32) { + sql_print_error( + "innobase_log_file_size can't be over 4GB" + " on 32-bit systems"); + + DBUG_RETURN(0); + } + } + os_innodb_umask = (ulint)my_umask; /* First calculate the default path for innodb_data_home_dir etc., diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 78cd0f927e9..eb4e10e545f 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -206,8 +206,9 @@ extern ulong innobase_large_page_size; extern char *innobase_home, *innobase_tmpdir, *innobase_logdir; extern long innobase_lock_scan_time; extern long innobase_mirrored_log_groups, innobase_log_files_in_group; -extern long innobase_log_file_size, innobase_log_buffer_size; -extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size; +extern longlong innobase_buffer_pool_size, innobase_log_file_size; +extern long innobase_log_buffer_size; +extern long innobase_additional_mem_pool_size; extern long innobase_buffer_pool_awe_mem_mb; extern long innobase_file_io_threads, innobase_lock_wait_timeout; extern long innobase_force_recovery; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 890b1716212..b22330152e8 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5418,7 +5418,8 @@ log and this option does nothing anymore.", {"innodb_buffer_pool_size", OPT_INNODB_BUFFER_POOL_SIZE, "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", (gptr*) &innobase_buffer_pool_size, (gptr*) &innobase_buffer_pool_size, 0, - GET_LONG, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, ~0L, 0, 1024*1024L, 0}, + GET_LL, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, LONGLONG_MAX, 0, + 1024*1024L, 0}, {"innodb_concurrency_tickets", OPT_INNODB_CONCURRENCY_TICKETS, "Number of times a thread is allowed to enter InnoDB within the same \ SQL query after it has once got the ticket", @@ -5442,9 +5443,10 @@ log and this option does nothing anymore.", (gptr*) &innobase_log_buffer_size, (gptr*) &innobase_log_buffer_size, 0, GET_LONG, REQUIRED_ARG, 1024*1024L, 256*1024L, ~0L, 0, 1024, 0}, {"innodb_log_file_size", OPT_INNODB_LOG_FILE_SIZE, - "Size of each log file in a log group in megabytes.", + "Size of each log file in a log group.", (gptr*) &innobase_log_file_size, (gptr*) &innobase_log_file_size, 0, - GET_LONG, REQUIRED_ARG, 5*1024*1024L, 1*1024*1024L, ~0L, 0, 1024*1024L, 0}, + GET_LL, REQUIRED_ARG, 5*1024*1024L, 1*1024*1024L, LONGLONG_MAX, 0, + 1024*1024L, 0}, {"innodb_log_files_in_group", OPT_INNODB_LOG_FILES_IN_GROUP, "Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.", (gptr*) &innobase_log_files_in_group, (gptr*) &innobase_log_files_in_group, diff --git a/sql/set_var.cc b/sql/set_var.cc index 5a6ff7d05ad..89ad00d7839 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -818,7 +818,7 @@ struct show_var_st init_vars[]= { {"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG }, {sys_innodb_autoextend_increment.name, (char*) &sys_innodb_autoextend_increment, SHOW_SYS}, {"innodb_buffer_pool_awe_mem_mb", (char*) &innobase_buffer_pool_awe_mem_mb, SHOW_LONG }, - {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG }, + {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONGLONG }, {"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL}, {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS}, {sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS}, @@ -836,7 +836,7 @@ struct show_var_st init_vars[]= { {"innodb_log_arch_dir", (char*) &innobase_log_arch_dir, SHOW_CHAR_PTR}, {"innodb_log_archive", (char*) &innobase_log_archive, SHOW_MY_BOOL}, {"innodb_log_buffer_size", (char*) &innobase_log_buffer_size, SHOW_LONG }, - {"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONG}, + {"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONGLONG}, {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG}, {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, From 57ad6b20ed8b22b010af1c354b23591570f12b09 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2005 19:40:48 +0300 Subject: [PATCH 30/35] Post-review fixes (Bug#13524). sql/sql_prepare.cc: Post-review fixes (Bug#13524): make sure mysql_reset_thd_for_next_command is called first for all PS commands. --- sql/sql_prepare.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c7145e3aabc..c285b70c7f6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1827,13 +1827,16 @@ static bool init_param_array(Prepared_statement *stmt) void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) { - Prepared_statement *stmt= new Prepared_statement(thd, &thd->protocol_prep); + Prepared_statement *stmt; bool error; DBUG_ENTER("mysql_stmt_prepare"); DBUG_PRINT("prep_query", ("%s", packet)); - if (stmt == 0) + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); + + if (! (stmt= new Prepared_statement(thd, &thd->protocol_prep))) DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */ if (thd->stmt_map.insert(stmt)) @@ -1842,7 +1845,6 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) DBUG_VOID_RETURN; /* out of memory */ } - mysql_reset_thd_for_next_command(thd); /* Reset warnings from previous command */ mysql_reset_errors(thd, 0); sp_cache_flush_obsolete(&thd->sp_proc_cache); @@ -2186,13 +2188,15 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) packet+= 9; /* stmt_id + 5 bytes of flags */ + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); + if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; DBUG_PRINT("exec_query", ("%s", stmt->query)); DBUG_PRINT("info",("stmt: %p", stmt)); - mysql_reset_thd_for_next_command(thd); sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); @@ -2312,6 +2316,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) Server_side_cursor *cursor; DBUG_ENTER("mysql_stmt_fetch"); + /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) @@ -2374,6 +2379,9 @@ void mysql_stmt_reset(THD *thd, char *packet) Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_reset"); + /* First of all clear possible warnings from the previous command */ + mysql_reset_thd_for_next_command(thd); + statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; @@ -2388,7 +2396,6 @@ void mysql_stmt_reset(THD *thd, char *packet) stmt->state= Query_arena::PREPARED; - mysql_reset_thd_for_next_command(thd); send_ok(thd); DBUG_VOID_RETURN; From 39ceae40cc071e50e947f3416e12052389091c80 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Nov 2005 20:17:49 -0800 Subject: [PATCH 31/35] Fix mix_innodb_myisam_binlog test and results after merge mysql-test/r/mix_innodb_myisam_binlog.result: update results mysql-test/t/mix_innodb_myisam_binlog.test: Update binlog test --- mysql-test/r/mix_innodb_myisam_binlog.result | 66 ++++++++++---------- mysql-test/t/mix_innodb_myisam_binlog.test | 4 +- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index ac6e08ef5fe..c84bd65e748 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -87,13 +87,12 @@ insert into t2 select * from t1; select get_lock("a",10); get_lock("a",10) 1 -show binlog events from 79; -Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 79 Query 1 79 use `test`; BEGIN -master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(8) -master-bin.000001 178 Query 1 79 use `test`; insert into t2 select * from t1 -master-bin.000001 244 Query 1 244 use `test`; ROLLBACK -master-bin.000001 287 Query 1 287 use `test`; DO RELEASE_LOCK("a") +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 # use `test`; BEGIN +master-bin.000001 166 Query 1 # use `test`; insert into t1 values(8) +master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 347 Query 1 # use `test`; ROLLBACK delete from t1; delete from t2; reset master; @@ -218,6 +217,8 @@ create temporary table t1 (a int) engine=myisam; commit; insert t1 values (1); rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back create table t0 (n int); insert t0 select * from t1; set autocommit=1; @@ -228,31 +229,30 @@ insert into t2 values (3); select get_lock("lock1",60); get_lock("lock1",60) 1 -show binlog events from 79; -Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 79 Query 1 79 use `test`; BEGIN -master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(16) -master-bin.000001 179 Query 1 79 use `test`; insert into t1 values(18) -master-bin.000001 239 Query 1 239 use `test`; COMMIT -master-bin.000001 280 Query 1 280 use `test`; delete from t1 -master-bin.000001 329 Query 1 329 use `test`; delete from t2 -master-bin.000001 378 Query 1 378 use `test`; alter table t2 type=MyISAM -master-bin.000001 439 Query 1 439 use `test`; insert into t1 values (1) -master-bin.000001 499 Query 1 499 use `test`; insert into t2 values (20) -master-bin.000001 560 Query 1 560 use `test`; drop table t1,t2 -master-bin.000001 611 Query 1 611 use `test`; BEGIN -master-bin.000001 651 Query 1 611 use `test`; create temporary table ti (a int) engine=innodb -master-bin.000001 733 Query 1 733 use `test`; ROLLBACK -master-bin.000001 776 Query 1 776 use `test`; insert into ti values(1) -master-bin.000001 835 Query 1 835 use `test`; BEGIN -master-bin.000001 875 Query 1 835 use `test`; create temporary table t1 (a int) engine=myisam -master-bin.000001 957 Query 1 957 use `test`; COMMIT -master-bin.000001 998 Query 1 998 use `test`; create table t0 (n int) -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") +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 # use `test`; BEGIN +master-bin.000001 166 Query 1 # use `test`; insert into t1 values(16) +master-bin.000001 254 Query 1 # use `test`; insert into t1 values(18) +master-bin.000001 342 Xid 1 # COMMIT /* xid=105 */ +master-bin.000001 369 Query 1 # use `test`; delete from t1 +master-bin.000001 446 Xid 1 # COMMIT /* xid=114 */ +master-bin.000001 473 Query 1 # use `test`; delete from t2 +master-bin.000001 550 Xid 1 # COMMIT /* xid=115 */ +master-bin.000001 577 Query 1 # use `test`; alter table t2 type=MyISAM +master-bin.000001 666 Query 1 # use `test`; insert into t1 values (1) +master-bin.000001 754 Xid 1 # COMMIT /* xid=117 */ +master-bin.000001 781 Query 1 # use `test`; insert into t2 values (20) +master-bin.000001 870 Query 1 # use `test`; drop table t1,t2 +master-bin.000001 949 Query 1 # use `test`; create temporary table ti (a int) engine=innodb +master-bin.000001 1059 Query 1 # use `test`; insert into ti values(1) +master-bin.000001 1146 Xid 1 # COMMIT /* xid=132 */ +master-bin.000001 1173 Query 1 # use `test`; create temporary table t1 (a int) engine=myisam +master-bin.000001 1283 Query 1 # use `test`; insert t1 values (1) +master-bin.000001 1366 Query 1 # use `test`; create table t0 (n int) +master-bin.000001 1452 Query 1 # use `test`; insert t0 select * from t1 +master-bin.000001 1541 Query 1 # use `test`; insert into t0 select GET_LOCK("lock1",null) +master-bin.000001 1648 Query 1 # use `test`; create table t2 (n int) engine=innodb +master-bin.000001 1748 Query 1 # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`.`t1`,`test`.`ti` do release_lock("lock1"); drop table t0,t2; diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index add4bd7b572..658584b625e 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -253,7 +253,9 @@ insert into t2 values (3); disconnect con2; connection con3; select get_lock("lock1",60); -show binlog events from 79; +--replace_column 5 # +--replace_result "xid=208" "xid=105" "xid=227" "xid=114" "xid=230" "xid=115" "xid=234" "xid=117" "xid=261" "xid=132" +show binlog events from 98; do release_lock("lock1"); drop table t0,t2; From 283962473c83d0e62943baef380c1ae2da936226 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Nov 2005 10:51:46 +0200 Subject: [PATCH 32/35] WL#2486 - natural/using joins according to SQL:2003. Enabled view tests that didn't work before. mysql-test/r/view.result: Enabled natural outer join tests with views - now they work after WL#2486 was pushed. mysql-test/t/view.test: Enabled natural outer join tests with views - now they work after WL#2486 was pushed. --- mysql-test/r/view.result | 15 +++++++++++++++ mysql-test/t/view.test | 2 -- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 42708a7c835..9a3dc950c10 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -204,6 +204,21 @@ create table t1 (a int); insert into t1 values (1), (2), (3); create view v1 (a) as select a+1 from t1; create view v2 (a) as select a-1 from t1; +select * from t1 natural left join v1; +a +1 +2 +3 +select * from v2 natural left join t1; +a +0 +1 +2 +select * from v2 natural left join v1; +a +0 +1 +2 drop view v1, v2; drop table t1; create table t1 (a int); diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7608d121c55..ad51597fd6f 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -147,11 +147,9 @@ insert into t1 values (1), (2), (3); create view v1 (a) as select a+1 from t1; create view v2 (a) as select a-1 from t1; ---disable_parsing # WL #2486 should enable these tests select * from t1 natural left join v1; select * from v2 natural left join t1; select * from v2 natural left join v1; ---enable_parsing drop view v1, v2; drop table t1; From fe94b6bfb3f39514d6b7db9333febf34ed8279ab Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Nov 2005 17:55:52 +0300 Subject: [PATCH 33/35] A test case for Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0". The bug itself cannot be repeated. mysql-test/r/sp.result: Test results were fixed (Bug#14845) mysql-test/t/sp.test: An SQL language test case for Bug#14845 tests/mysql_client_test.c: A test case for Bug#14845 --- mysql-test/r/sp.result | 19 +++++++++++++++++ mysql-test/t/sp.test | 21 +++++++++++++++++++ tests/mysql_client_test.c | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1e49f966bc4..93332af21a9 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3648,4 +3648,23 @@ call bug14723();; 42 drop function bug14723| drop procedure bug14723| +create procedure bug14845() +begin +declare a char(255); +declare done int default 0; +declare c cursor for select count(*) from t1 where 1 = 0; +declare continue handler for sqlstate '02000' set done = 1; +open c; +repeat +fetch c into a; +if not done then +select a; +end if; +until done end repeat; +close c; +end| +call bug14845()| +a +0 +drop procedure bug14845| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 362faec167c..5ad2b9287aa 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4572,6 +4572,27 @@ delimiter |;; drop function bug14723| drop procedure bug14723| +# +# Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0" +# Check that when fetching from a cursor, COUNT(*) works properly. +# +create procedure bug14845() +begin + declare a char(255); + declare done int default 0; + declare c cursor for select count(*) from t1 where 1 = 0; + declare continue handler for sqlstate '02000' set done = 1; + open c; + repeat + fetch c into a; + if not done then + select a; + end if; + until done end repeat; + close c; +end| +call bug14845()| +drop procedure bug14845| # # BUG#NNNN: New bug synopsis diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index e0f3fd91e5c..ce732690700 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14546,6 +14546,49 @@ static void test_bug13524() myquery(rc); } +/* + Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0" +*/ + +static void test_bug14845() +{ + MYSQL_STMT *stmt; + int rc; + const ulong type= CURSOR_TYPE_READ_ONLY; + const char *query= "select count(*) from t1 where 1 = 0"; + + myheader("test_bug14845"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + rc= mysql_query(mysql, "create table t1 (id int(11) default null, " + "name varchar(20) default null)" + "engine=MyISAM DEFAULT CHARSET=utf8"); + myquery(rc); + rc= mysql_query(mysql, "insert into t1 values (1,'abc'),(2,'def')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + check_execute(stmt, rc); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + /* Cleanup */ + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} /* Read and parse arguments and MySQL options from my.cnf @@ -14805,6 +14848,7 @@ static struct my_tests_st my_tests[]= { { "test_bug14210", test_bug14210 }, { "test_bug13488", test_bug13488 }, { "test_bug13524", test_bug13524 }, + { "test_bug14845", test_bug14845 }, { 0, 0 } }; From a11caf1e01de600b9212c129903395758dc63378 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Nov 2005 23:46:04 +0300 Subject: [PATCH 34/35] A test case for Bug#8568 "GROUP_CONCAT returns string, unless in a UNION in which case returns BLOB". The bug is not present anymore. mysql-test/r/func_gconcat.result: Bug#8568: test results mysql-test/t/func_gconcat.test: Add a test case for Bug#8568 --- mysql-test/r/func_gconcat.result | 15 +++++++++++++++ mysql-test/t/func_gconcat.test | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 90884dcc596..7987ceca712 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -596,3 +596,18 @@ GROUP_CONCAT(a ORDER BY a) ,x ,z DROP TABLE t1; +set names latin1; +create table t1 (a char, b char); +insert into t1 values ('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b'); +create table t2 select group_concat(b) as a from t1 where a = 'a'; +create table t3 (select group_concat(a) as a from t1 where a = 'a') union +(select group_concat(b) as a from t1 where a = 'b'); +select charset(a) from t2; +charset(a) +latin1 +select charset(a) from t3; +charset(a) +latin1 +latin1 +drop table t1, t2, t3; +set names default; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index a519d51e0b5..cd686585dd8 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -390,3 +390,19 @@ SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; DROP TABLE t1; # End of 4.1 tests + +# +# Bug#8568 "GROUP_CONCAT returns string, unless in a UNION in which case +# returns BLOB": add a test case, the bug can not be repeated any more. +# + +set names latin1; +create table t1 (a char, b char); +insert into t1 values ('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b'); +create table t2 select group_concat(b) as a from t1 where a = 'a'; +create table t3 (select group_concat(a) as a from t1 where a = 'a') union + (select group_concat(b) as a from t1 where a = 'b'); +select charset(a) from t2; +select charset(a) from t3; +drop table t1, t2, t3; +set names default; From 6ba79a251681a765f491db1428a467a0a06a69bd Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 19 Nov 2005 01:22:12 +0300 Subject: [PATCH 35/35] Bug#13510 "Setting password local variable changes current password": additional fix, also make sure that a syntax error is returned for set names="foo" when there is no such variable or no stored procedure. mysql-test/r/sp-error.result: Test results fixed: a new test for Bug#13510 mysql-test/t/sp-error.test: A new test for Bug#13510 (set names out of an SP) sql/sql_yacc.yy: Bug#13510: fix the case when there is no stored procedure or no 'names' variable declared. Return a syntax error in this case. --- mysql-test/r/sp-error.result | 2 ++ mysql-test/t/sp-error.test | 4 ++++ sql/sql_yacc.yy | 3 +++ 3 files changed, 9 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 26bb0fa4694..858f7d0bb16 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -845,6 +845,8 @@ set password = 'foo1'; select password; end| ERROR 42000: Variable 'password' must be quoted with `...`, or renamed +set names='foo2'| +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 create procedure bug13510_2() begin declare names varchar(10); diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 4cc141fea4b..5057dd0d9f8 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1233,6 +1233,10 @@ begin select password; end| +# Check that an error message is sent +--error ER_PARSE_ERROR +set names='foo2'| + --error ER_SP_BAD_VAR_SHADOW create procedure bug13510_2() begin diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 339091ed4e8..2dc06642259 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7925,6 +7925,9 @@ option_value: names.length= 5; if (spc && spc->find_pvar(&names)) my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); + else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; } | NAMES_SYM charset_name_or_default opt_collate