From febda72f628cbd3c9ca638f0022ef1c765d41c2c Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 21 Nov 2004 11:51:19 +0300 Subject: [PATCH 01/11] Fix for BUG#4177: * Make index merge quick selects code allow perform several scans. * Delay additional handler objects creation till row retrieval is started. include/queues.h: Added trivial queue_remove_all macro mysql-test/r/index_merge.result: Testcase for BUG#4177 mysql-test/t/index_merge.test: Testcase for BUG#4177 sql/opt_range.cc: Fix for BUG#4177: * For any quick select, row retrieval can be performed several times. Now all index_merge quick selects code handles such cases properly. * In QUICK_INDEX_MERGE_SELECT we use one handler object for all merged scans, and it was possible that in destructor several cleanup functions were called * Additionally - Removed redundant QUICK_INDEX_MERGE_SELECT members. - Now QUICK_ROR_*_SELECTs create additional handler objects only when row retrieval is started So if join optimizer chooses other access method, we don't create/delete handlers. --- include/queues.h | 1 + mysql-test/r/index_merge.result | 53 ++++++++++++++- mysql-test/t/index_merge.test | 49 +++++++++++++- sql/opt_range.cc | 114 ++++++++++++++++++++++---------- sql/opt_range.h | 18 ++--- 5 files changed, 188 insertions(+), 47 deletions(-) diff --git a/include/queues.h b/include/queues.h index ac15b09719b..02ab768198e 100644 --- a/include/queues.h +++ b/include/queues.h @@ -53,6 +53,7 @@ int resize_queue(QUEUE *queue, uint max_elements); void delete_queue(QUEUE *queue); void queue_insert(QUEUE *queue,byte *element); byte *queue_remove(QUEUE *queue,uint idx); +#define queue_remove_all(queue) { (queue)->elements= 0; } void _downheap(QUEUE *queue,uint idx); void queue_fix(QUEUE *queue); #define is_queue_inited(queue) ((queue)->root != 0) diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index 6b41992a733..4ccec5ef0d8 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -1,4 +1,4 @@ -drop table if exists t0, t1, t2, t3,t4; +drop table if exists t0, t1, t2, t3, t4; create table t0 ( key1 int not null, @@ -335,4 +335,55 @@ key1 key2 key3 key4 key5 key6 key7 key8 select count(*) from t0; count(*) 1021 +drop table t4; +create table t4 (a int); +insert into t4 values (1),(4),(3); +set @save_join_buffer_size=@@join_buffer_size; +set join_buffer_size= 4000; +show variables like 'join_buffer_size'; +Variable_name Value +join_buffer_size 8228 +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 < 500000 or A.key2 < 3) +and (B.key1 < 500000 or B.key2 < 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where +1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 < 500000 or A.key2 < 3) +and (B.key1 < 500000 or B.key2 < 3); +max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +10240 +update t0 set key1=1; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 = 1 or A.key2 = 1) +and (B.key1 = 1 or B.key2 = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1020 Using union(i1,i2); Using where +1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1020 Using union(i1,i2); Using where +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A force index(i1,i2), t0 as B force index (i1,i2) +where (A.key1 = 1 or A.key2 = 1) +and (B.key1 = 1 or B.key2 = 1); +max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +8194 +alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200); +update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A, t0 as B +where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) +and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where +1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +from t0 as A, t0 as B +where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) +and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); +max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) +8186 +set join_buffer_size= @save_join_buffer_size; drop table t0, t1, t2, t3, t4; diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test index a4f7b71e5a3..3ab68d85125 100644 --- a/mysql-test/t/index_merge.test +++ b/mysql-test/t/index_merge.test @@ -1,9 +1,8 @@ # # Index merge tests # - --disable_warnings -drop table if exists t0, t1, t2, t3,t4; +drop table if exists t0, t1, t2, t3, t4; --enable_warnings # Create and fill a table with simple keys @@ -278,4 +277,48 @@ delete from t0 where key1 < 3 or key2 < 4; select * from t0 where key1 < 3 or key2 < 4; select count(*) from t0; -drop table t0, t1, t2, t3, t4; +# Test for BUG#4177 +drop table t4; +create table t4 (a int); +insert into t4 values (1),(4),(3); +set @save_join_buffer_size=@@join_buffer_size; +set join_buffer_size= 4000; +show variables like 'join_buffer_size'; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) + from t0 as A force index(i1,i2), t0 as B force index (i1,i2) + where (A.key1 < 500000 or A.key2 < 3) + and (B.key1 < 500000 or B.key2 < 3); + +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) + from t0 as A force index(i1,i2), t0 as B force index (i1,i2) + where (A.key1 < 500000 or A.key2 < 3) + and (B.key1 < 500000 or B.key2 < 3); + +update t0 set key1=1; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) + from t0 as A force index(i1,i2), t0 as B force index (i1,i2) + where (A.key1 = 1 or A.key2 = 1) + and (B.key1 = 1 or B.key2 = 1); + +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) + from t0 as A force index(i1,i2), t0 as B force index (i1,i2) + where (A.key1 = 1 or A.key2 = 1) + and (B.key1 = 1 or B.key2 = 1); + +alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200); +update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; +explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) + from t0 as A, t0 as B + where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) + and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); + +select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) + from t0 as A, t0 as B + where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) + and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); + +set join_buffer_size= @save_join_buffer_size; +# Test for BUG#4177 ends + +drop table t0, t1, t2, t3, t4; + diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f036cbc799b..ec7434d215b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -777,8 +777,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param, TABLE *table) - :cur_quick_it(quick_selects),pk_quick_select(NULL),unique(NULL), - thd(thd_param) + :pk_quick_select(NULL), thd(thd_param) { DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT"); index= MAX_KEY; @@ -790,17 +789,14 @@ QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param, int QUICK_INDEX_MERGE_SELECT::init() { - cur_quick_it.rewind(); - cur_quick_select= cur_quick_it++; - return 0; + DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::init"); + DBUG_RETURN(0); } int QUICK_INDEX_MERGE_SELECT::reset() { - int result; DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset"); - result= cur_quick_select->reset() || prepare_unique(); - DBUG_RETURN(result); + DBUG_RETURN(read_keys_and_merge()); } bool @@ -820,8 +816,12 @@ QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range) QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT() { + List_iterator_fast quick_it(quick_selects); + QUICK_RANGE_SELECT* quick; DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT"); - delete unique; + quick_it.rewind(); + while ((quick= quick_it++)) + quick->file= NULL; quick_selects.delete_elements(); delete pk_quick_select; free_root(&alloc,MYF(0)); @@ -833,7 +833,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param, TABLE *table, bool retrieve_full_rows, MEM_ROOT *parent_alloc) - : cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows) + : cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows), + scans_inited(false) { index= MAX_KEY; head= table; @@ -859,8 +860,9 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param, int QUICK_ROR_INTERSECT_SELECT::init() { - /* Check if last_rowid was successfully allocated in ctor */ - return !last_rowid; + DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init"); + /* Check if last_rowid was successfully allocated in ctor */ + DBUG_RETURN(!last_rowid); } @@ -953,7 +955,7 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan"); /* Initialize all merged "children" quick selects */ - DBUG_ASSERT(!(need_to_fetch_row && !reuse_handler)); + DBUG_ASSERT(!need_to_fetch_row || reuse_handler); if (!need_to_fetch_row && reuse_handler) { quick= quick_it++; @@ -995,7 +997,14 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) int QUICK_ROR_INTERSECT_SELECT::reset() { DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::reset"); - DBUG_RETURN(init_ror_merged_scan(TRUE)); + if (!scans_inited && init_ror_merged_scan(TRUE)) + DBUG_RETURN(1); + scans_inited= true; + List_iterator_fast it(quick_selects); + QUICK_RANGE_SELECT *quick; + while ((quick= it++)) + quick->reset(); + DBUG_RETURN(0); } @@ -1034,7 +1043,7 @@ QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT() QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param, TABLE *table) - :thd(thd_param) + : thd(thd_param), scans_inited(false) { index= MAX_KEY; head= table; @@ -1057,18 +1066,19 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param, int QUICK_ROR_UNION_SELECT::init() { + DBUG_ENTER("QUICK_ROR_UNION_SELECT::init"); if (init_queue(&queue, quick_selects.elements, 0, FALSE , QUICK_ROR_UNION_SELECT::queue_cmp, (void*) this)) { bzero(&queue, sizeof(QUEUE)); - return 1; + DBUG_RETURN(1); } if (!(cur_rowid= (byte*)alloc_root(&alloc, 2*head->file->ref_length))) - return 1; + DBUG_RETURN(1); prev_rowid= cur_rowid + head->file->ref_length; - return 0; + DBUG_RETURN(0); } @@ -1106,6 +1116,18 @@ int QUICK_ROR_UNION_SELECT::reset() int error; DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset"); have_prev_rowid= FALSE; + if (!scans_inited) + { + QUICK_SELECT_I *quick; + List_iterator_fast it(quick_selects); + while ((quick= it++)) + { + if (quick->init_ror_merged_scan(FALSE)) + DBUG_RETURN(1); + } + scans_inited= true; + } + queue_remove_all(&queue); /* Initialize scans for merged quick selects and put all merged quick selects into the queue. @@ -1113,7 +1135,7 @@ int QUICK_ROR_UNION_SELECT::reset() List_iterator_fast it(quick_selects); while ((quick= it++)) { - if (quick->init_ror_merged_scan(FALSE)) + if (quick->reset()) DBUG_RETURN(1); if ((error= quick->get_next())) { @@ -1591,7 +1613,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu", keys_to_use.to_ulonglong(), (ulong) prev_tables, (ulong) const_tables)); - delete quick; quick=0; needed_reg.clear_all(); @@ -5545,22 +5566,29 @@ err: /* - Fetch all row ids into unique. - + Perform key scans for all used indexes (except CPK), get rowids and merge + them into an ordered non-recurrent sequence of rowids. + + The merge/duplicate removal is performed using Unique class. We put all + rowids into Unique, get the sorted sequence and destroy the Unique. + If table has a clustered primary key that covers all rows (TRUE for bdb and innodb currently) and one of the index_merge scans is a scan on PK, then - primary key scan rowids are not put into Unique and also - rows that will be retrieved by PK scan are not put into Unique + rows that will be retrieved by PK scan are not put into Unique and + primary key scan is not performed here, it is performed later separately. RETURN 0 OK other error */ -int QUICK_INDEX_MERGE_SELECT::prepare_unique() +int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() { + List_iterator_fast cur_quick_it(quick_selects); + QUICK_RANGE_SELECT* cur_quick; int result; + Unique *unique; DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique"); /* We're going to just read rowids. */ @@ -5575,7 +5603,17 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique() */ head->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); - cur_quick_select->init(); + cur_quick_it.rewind(); + cur_quick= cur_quick_it++; + DBUG_ASSERT(cur_quick); + + /* + We reuse the same instance of handler so we need to call both init and + reset here. + */ + if (cur_quick->init()) + DBUG_RETURN(1); + cur_quick->reset(); unique= new Unique(refpos_order_cmp, (void *)head->file, head->file->ref_length, @@ -5584,24 +5622,28 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique() DBUG_RETURN(1); for (;;) { - while ((result= cur_quick_select->get_next()) == HA_ERR_END_OF_FILE) + while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE) { - cur_quick_select->range_end(); - cur_quick_select= cur_quick_it++; - if (!cur_quick_select) + cur_quick->range_end(); + cur_quick= cur_quick_it++; + if (!cur_quick) break; - if (cur_quick_select->init()) + if (cur_quick->file->inited != handler::NONE) + cur_quick->file->ha_index_end(); + if (cur_quick->init()) DBUG_RETURN(1); - /* QUICK_RANGE_SELECT::reset never fails */ - cur_quick_select->reset(); + cur_quick->reset(); } if (result) { if (result != HA_ERR_END_OF_FILE) + { + cur_quick->range_end(); DBUG_RETURN(result); + } break; } @@ -5612,8 +5654,8 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique() if (pk_quick_select && pk_quick_select->row_in_ranges()) continue; - cur_quick_select->file->position(cur_quick_select->record); - result= unique->unique_add((char*)cur_quick_select->file->ref); + cur_quick->file->position(cur_quick->record); + result= unique->unique_add((char*)cur_quick->file->ref); if (result) DBUG_RETURN(1); @@ -5621,6 +5663,7 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique() /* ok, all row ids are in Unique */ result= unique->get(head); + delete unique; doing_pk_scan= FALSE; /* start table scan */ init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1); @@ -5660,6 +5703,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next() doing_pk_scan= TRUE; if ((result= pk_quick_select->init())) DBUG_RETURN(result); + pk_quick_select->reset(); DBUG_RETURN(pk_quick_select->get_next()); } } diff --git a/sql/opt_range.h b/sql/opt_range.h index 19234f61ea2..74d388128c8 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -127,7 +127,8 @@ public: reset() should be called when it is certain that row retrieval will be necessary. This call may do heavyweight initialization like buffering first N records etc. If reset() call fails get_next() must not be called. - + Note that reset() may be called several times if this quick select + executes in a subselect. RETURN 0 OK other Error code @@ -274,6 +275,10 @@ public: next=0; range= NULL; cur_range= NULL; + /* + Note: in opt_range.cc there are places where it is assumed that this + function always succeeds + */ return 0; } int init(); @@ -388,21 +393,15 @@ public: /* range quick selects this index_merge read consists of */ List quick_selects; - /* quick select which is currently used for rows retrieval */ - List_iterator_fast cur_quick_it; - QUICK_RANGE_SELECT* cur_quick_select; - /* quick select that uses clustered primary key (NULL if none) */ QUICK_RANGE_SELECT* pk_quick_select; /* true if this select is currently doing a clustered PK scan */ bool doing_pk_scan; - Unique *unique; MEM_ROOT alloc; - THD *thd; - int prepare_unique(); + int read_keys_and_merge(); /* used to get rows collected in Unique */ READ_RECORD read_record; @@ -465,6 +464,8 @@ public: MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */ THD *thd; /* current thread */ bool need_to_fetch_row; /* if true, do retrieve full table records. */ + /* in top-level quick select, true if merged scans where initialized */ + bool scans_inited; }; @@ -514,6 +515,7 @@ public: uint rowid_length; /* table rowid length */ private: static int queue_cmp(void *arg, byte *val1, byte *val2); + bool scans_inited; }; From 0f99fe728e9d32d8b6bf098775d1ef86235f8a47 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Dec 2004 11:10:45 +0200 Subject: [PATCH 02/11] Added support for a LOCK TABLES...WHERE ENGINE = InnoDB query which sets transactional table locks to tables mentioned in the query. These locks are released at the end of the transaction automatically. This is fix for bugs #5655, #5998 and issue #3762. innobase/include/lock0lock.h: Added a new lock type LOCK_TABLE_TRANSACTIONAL. innobase/include/trx0trx.h: Added a varible to store the number of transactional table locks reserved by the transaction and stored in the trx_locks list. innobase/lock/lock0lock.c: Added a lock type LOCK_TABLE_TRANSACTIONAL. innobase/row/row0mysql.c: Added support for a transactional table lock. innobase/trx/trx0roll.c: Make compiler happy and format function. innobase/trx/trx0trx.c: Added information about number of explicit and transactional table locks in the innodb monitor. sql/ha_innodb.cc: Added support for a LOCK_TABLE_TRANSACTIONAL table lock (SQLCOM_LOCK_TABLES_TRANSACTIONAL). Transactional table locks are taken in the function ::transactional_table_lock(). sql/ha_innodb.h: Added prototype for a function trandactional_table_lock(). sql/handler.h: Added prototype for a virtual function transactional_table_lock(). Handler does not need to implement this function. sql/lock.cc: Added a function transactional_lock_tables() to lock all tables in the list with transactional table lock. These locks can cause a deadlock and this error should be reported back to user. sql/mysql_priv.h: Added prototype for a function transactional_lock_tables(). sql/sql_lex.h: Added SQLCOM_LOCK_TABLES_TRANSACTIONAL command. sql/sql_parse.cc: Added SQLCOM_LOCK_TABLES_TRANSACTIONAL command. sql/sql_yacc.yy: Added parsing rules for a LOCK TABLES...WHERE ENGINE = x; --- innobase/include/lock0lock.h | 2 + innobase/include/trx0trx.h | 4 ++ innobase/lock/lock0lock.c | 34 ++++++++++--- innobase/row/row0mysql.c | 12 +++-- innobase/trx/trx0roll.c | 7 ++- innobase/trx/trx0trx.c | 13 +++-- sql/ha_innodb.cc | 96 ++++++++++++++++++++++++++++++++++-- sql/ha_innodb.h | 1 + sql/handler.h | 1 + sql/lock.cc | 62 +++++++++++++++++++++++ sql/mysql_priv.h | 1 + sql/sql_lex.h | 1 + sql/sql_parse.cc | 21 ++++++++ sql/sql_yacc.yy | 13 ++++- 14 files changed, 248 insertions(+), 20 deletions(-) diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h index d642fe46fef..2199ba36881 100644 --- a/innobase/include/lock0lock.h +++ b/innobase/include/lock0lock.h @@ -585,6 +585,8 @@ extern lock_sys_t* lock_sys; #define LOCK_TABLE 16 /* these type values should be so high that */ #define LOCK_REC 32 /* they can be ORed to the lock mode */ #define LOCK_TABLE_EXP 80 /* explicit table lock (80 = 16 + 64) */ +#define LOCK_TABLE_TRANSACTIONAL 144 + /* transactional table lock (144 = 16 + 128)*/ #define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the type_mode field in a lock */ /* Waiting lock flag */ diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 8eb71dac763..e305226f9e3 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -464,6 +464,10 @@ struct trx_struct{ ulint n_lock_table_exp;/* number of explicit table locks (LOCK TABLES) reserved by the transaction, stored in trx_locks */ + ulint n_lock_table_transactional; + /* number of transactional table locks + (LOCK TABLES..WHERE ENGINE) reserved by + the transaction, stored in trx_locks */ UT_LIST_NODE_T(trx_t) trx_list; /* list of transactions */ UT_LIST_NODE_T(trx_t) diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index d2d16a1ae4e..1ff16bce45a 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -2207,7 +2207,8 @@ lock_grant( release it at the end of the SQL statement */ lock->trx->auto_inc_lock = lock; - } else if (lock_get_type(lock) == LOCK_TABLE_EXP) { + } else if (lock_get_type(lock) == LOCK_TABLE_EXP || + lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { ut_a(lock_get_mode(lock) == LOCK_S || lock_get_mode(lock) == LOCK_X); } @@ -3421,6 +3422,10 @@ lock_table_create( lock->trx->n_lock_table_exp++; } + if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { + lock->trx->n_lock_table_transactional++; + } + lock->un_member.tab_lock.table = table; UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); @@ -3458,7 +3463,11 @@ lock_table_remove_low( } if (lock_get_type(lock) == LOCK_TABLE_EXP) { - lock->trx->n_lock_table_exp--; + trx->n_lock_table_exp--; + } + + if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { + trx->n_lock_table_transactional--; } UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock); @@ -3592,7 +3601,8 @@ lock_table( DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set, does nothing; - if LOCK_TABLE_EXP bits are set, + if LOCK_TABLE_EXP|LOCK_TABLE_TRANSACTIONAL + bits are set, creates an explicit table lock */ dict_table_t* table, /* in: database table in dictionary cache */ ulint mode, /* in: lock mode */ @@ -3608,7 +3618,8 @@ lock_table( return(DB_SUCCESS); } - ut_a(flags == 0 || flags == LOCK_TABLE_EXP); + ut_a(flags == 0 || flags == LOCK_TABLE_EXP || + flags == LOCK_TABLE_TRANSACTIONAL); trx = thr_get_trx(thr); @@ -3722,7 +3733,8 @@ lock_table_dequeue( ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_a(lock_get_type(in_lock) == LOCK_TABLE || - lock_get_type(in_lock) == LOCK_TABLE_EXP); + lock_get_type(in_lock) == LOCK_TABLE_EXP || + lock_get_type(in_lock) == LOCK_TABLE_TRANSACTIONAL); lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock); @@ -3826,7 +3838,9 @@ lock_release_off_kernel( } lock_table_dequeue(lock); - if (lock_get_type(lock) == LOCK_TABLE_EXP) { + + if (lock_get_type(lock) == LOCK_TABLE_EXP || + lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { ut_a(lock_get_mode(lock) == LOCK_S || lock_get_mode(lock) == LOCK_X); } @@ -3850,6 +3864,7 @@ lock_release_off_kernel( ut_a(trx->auto_inc_lock == NULL); ut_a(trx->n_lock_table_exp == 0); + ut_a(trx->n_lock_table_transactional == 0); } /************************************************************************* @@ -3915,6 +3930,7 @@ lock_release_tables_off_kernel( } ut_a(trx->n_lock_table_exp == 0); + ut_a(trx->n_lock_table_transactional == 0); } /************************************************************************* @@ -4028,11 +4044,15 @@ lock_table_print( ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_a(lock_get_type(lock) == LOCK_TABLE || - lock_get_type(lock) == LOCK_TABLE_EXP); + lock_get_type(lock) == LOCK_TABLE_EXP || + lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL); if (lock_get_type(lock) == LOCK_TABLE_EXP) { fputs("EXPLICIT ", file); + } else if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) { + fputs("TRANSACTIONAL ", file); } + fputs("TABLE LOCK table ", file); ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name); fprintf(file, " trx id %lu %lu", diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index be243b44488..79a4ffb36ae 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -784,7 +784,7 @@ row_lock_table_for_mysql( table handle */ dict_table_t* table, /* in: table to lock, or NULL if prebuilt->table should be - locked as LOCK_TABLE_EXP | + locked or a prebuilt->select_lock_type */ ulint mode) /* in: lock mode of table */ { @@ -822,8 +822,14 @@ run_again: if (table) { err = lock_table(0, table, mode, thr); } else { - err = lock_table(LOCK_TABLE_EXP, prebuilt->table, - prebuilt->select_lock_type, thr); + if (mode == LOCK_TABLE_TRANSACTIONAL) { + err = lock_table(LOCK_TABLE_TRANSACTIONAL, + prebuilt->table, + prebuilt->select_lock_type, thr); + } else { + err = lock_table(LOCK_TABLE_EXP, prebuilt->table, + prebuilt->select_lock_type, thr); + } } trx->error_state = err; diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index db5e16c7778..105fa97080f 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -335,8 +335,10 @@ undo log. If the transaction was not yet committed, then we roll it back. Note: this is done in a background thread */ void * -trx_rollback_or_clean_all_without_sess(void *i) -/*========================================*/ +trx_rollback_or_clean_all_without_sess( +/*===================================*/ + /* out: arguments */ + void *i) /* in: arguments (unused) */ { mem_heap_t* heap; que_fork_t* fork; @@ -496,6 +498,7 @@ loop: goto loop; os_thread_exit(i); /* not reached */ + return(i); } /*********************************************************************** diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index ab8bd898dd6..f676c21934b 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -153,6 +153,7 @@ trx_create( trx->auto_inc_lock = NULL; trx->n_lock_table_exp = 0; + trx->n_lock_table_transactional = 0; trx->read_view_heap = mem_heap_create(256); trx->read_view = NULL; @@ -285,6 +286,7 @@ trx_free( ut_a(!trx->has_search_latch); ut_a(!trx->auto_inc_lock); ut_a(!trx->n_lock_table_exp); + ut_a(!trx->n_lock_table_transactional); ut_a(trx->dict_operation_lock_mode == 0); @@ -1645,10 +1647,15 @@ trx_print( putc('\n', f); if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) { + fprintf(f, "mysql tables in use %lu, locked %lu\n", + (ulong) trx->n_mysql_tables_in_use, + (ulong) trx->mysql_n_tables_locked); + } - fprintf(f, "mysql tables in use %lu, locked %lu\n", - (ulong) trx->n_mysql_tables_in_use, - (ulong) trx->mysql_n_tables_locked); + if (trx->n_lock_table_transactional > 0 || trx->n_lock_table_exp > 0) { +fprintf(f, "mysql explicit table locks %lu, transactional table locks %lu\n", + (ulong) trx->n_lock_table_exp, + (ulong) trx->n_lock_table_transactional); } newline = TRUE; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 8713d145f2f..3b1af3c58e4 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1327,7 +1327,8 @@ innobase_commit( 3. innobase_query_caching_of_table_permitted(), 4. innobase_savepoint(), 5. ::init_table_handle_for_HANDLER(), - 6. innobase_start_trx_and_assign_read_view() + 6. innobase_start_trx_and_assign_read_view(), + 7. ::transactional_table_lock() and it is only set to 0 in a commit or a rollback. If it is 0 we know there cannot be resources to be freed and we could return immediately. @@ -5095,8 +5096,9 @@ ha_innobase::start_stmt( select_lock_type value. The value of stored_select_lock_type was decided in: 1) ::store_lock(), - 2) ::external_lock(), and - 3) ::init_table_handle_for_HANDLER(). */ + 2) ::external_lock(), + 3) ::init_table_handle_for_HANDLER(), and + 4) :.transactional_table_lock(). */ prebuilt->select_lock_type = prebuilt->stored_select_lock_type; @@ -5287,6 +5289,94 @@ ha_innobase::external_lock( DBUG_RETURN(0); } +/********************************************************************** +With this function MySQL request a transactional lock to a table when +user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */ + +int +ha_innobase::transactional_table_lock( +/*==================================*/ + /* out: 0 */ + THD* thd, /* in: handle to the user thread */ + int lock_type) /* in: lock type */ +{ + row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + trx_t* trx; + + DBUG_ENTER("ha_innobase::transactional_table_lock"); + DBUG_PRINT("enter",("lock_type: %d", lock_type)); + + /* We do not know if MySQL can call this function before calling + external_lock(). To be safe, update the thd of the current table + handle. */ + + update_thd(thd); + + if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB error:\n" +"MySQL is trying to use a table handle but the .ibd file for\n" +"table %s does not exist.\n" +"Have you deleted the .ibd file from the database directory under\n" +"the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"Look from section 15.1 of http://www.innodb.com/ibman.html\n" +"how you can resolve the problem.\n", + prebuilt->table->name); + DBUG_RETURN(HA_ERR_CRASHED); + } + + trx = prebuilt->trx; + + prebuilt->sql_stat_start = TRUE; + prebuilt->hint_need_to_fetch_extra_cols = 0; + + prebuilt->read_just_key = 0; + prebuilt->keep_other_fields_on_keyread = FALSE; + + if (lock_type == F_WRLCK) { + prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; + } else if (lock_type == F_RDLCK) { + prebuilt->select_lock_type = LOCK_X; + prebuilt->stored_select_lock_type = LOCK_X; + } else { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB error:\n" +"MySQL is trying to set transactional table lock with corrupted lock type\n" +"to table %s, lock type %d does not exist.\n", + prebuilt->table->name, lock_type); + DBUG_RETURN(HA_ERR_CRASHED); + } + + /* MySQL is setting a new transactional table lock */ + + /* Set the MySQL flag to mark that there is an active transaction */ + thd->transaction.all.innodb_active_trans = 1; + + if (thd->in_lock_tables && thd->variables.innodb_table_locks) { + ulint error = DB_SUCCESS; + + error = row_lock_table_for_mysql(prebuilt,NULL, + LOCK_TABLE_TRANSACTIONAL); + + if (error != DB_SUCCESS) { + error = convert_error_code_to_mysql(error, user_thd); + DBUG_RETURN(error); + } + + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + + /* Store the current undo_no of the transaction + so that we know where to roll back if we have + to roll back the next SQL statement */ + + trx_mark_sql_stat_end(trx); + } + } + + DBUG_RETURN(0); +} + /**************************************************************************** Here we export InnoDB status variables to MySQL. */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index a64bbc665c1..eb906a744da 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -149,6 +149,7 @@ class ha_innobase: public handler int discard_or_import_tablespace(my_bool discard); int extra(enum ha_extra_function operation); int external_lock(THD *thd, int lock_type); + int transactional_table_lock(THD *thd, int lock_type); int start_stmt(THD *thd); void position(byte *record); diff --git a/sql/handler.h b/sql/handler.h index c70ea266734..c7131d75156 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -450,6 +450,7 @@ public: { return extra(operation); } virtual int reset() { return extra(HA_EXTRA_RESET); } virtual int external_lock(THD *thd, int lock_type)=0; + virtual int transactional_table_lock(THD *thd, int lock_type) {return 0;} virtual void unlock_row() {} virtual int start_stmt(THD *thd) {return 0;} /* diff --git a/sql/lock.cc b/sql/lock.cc index 3367c6a2900..0db23f54c50 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -695,6 +695,9 @@ static void print_lock_error(int error) case HA_ERR_READ_ONLY_TRANSACTION: textno=ER_READ_ONLY_TRANSACTION; break; + case HA_ERR_LOCK_DEADLOCK: + textno=ER_LOCK_DEADLOCK; + break; default: textno=ER_CANT_LOCK; break; @@ -870,3 +873,62 @@ bool make_global_read_lock_block_commit(THD *thd) thd->exit_cond(old_message); DBUG_RETURN(error); } + +/* + Take transactional table lock for all tables in the list + + SYNOPSIS + transactional_lock_tables + thd Thread THD + tables list of tables + counter number of tables in the list + + NOTES + + RETURN + 0 - OK + -1 - error + +*/ +int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter) +{ + uint i; + int lock_type,error=0; + TABLE_LIST *table; + TABLE **start,**ptr; + + DBUG_ENTER("transactional_lock_tables"); + + if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*) * counter))) + return -1; + + for (table= tables; table; table= table->next_global) + { + if (!table->placeholder() && !table->schema_table) + *(ptr++)= table->table; + } + + for (i=1 ; i <= counter ; i++, start++) + { + DBUG_ASSERT((*start)->reginfo.lock_type >= TL_READ); + lock_type=F_WRLCK; /* Lock exclusive */ + + if ((*start)->db_stat & HA_READ_ONLY || + ((*start)->reginfo.lock_type >= TL_READ && + (*start)->reginfo.lock_type <= TL_READ_NO_INSERT)) + lock_type=F_RDLCK; + + if ((error=(*start)->file->transactional_table_lock(thd, lock_type))) + { + print_lock_error(error); + DBUG_RETURN(-1); + } + else + { + (*start)->db_stat &= ~ HA_BLOCK_LOCK; + (*start)->current_lock= lock_type; + } + } + + DBUG_RETURN(0); +} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 09bec0a9323..f632dd8760f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -827,6 +827,7 @@ int open_tables(THD *thd, TABLE_LIST *tables, uint *counter); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter); +int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); bool rm_temporary_table(enum db_type base, char *path); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e99e6138b6d..fb1c6ee376b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -87,6 +87,7 @@ enum enum_sql_command { SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW, SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, + SQLCOM_LOCK_TABLES_TRANSACTIONAL, /* This should be the last !!! */ SQLCOM_END }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e27cd20e15e..f682b38641b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3252,6 +3252,27 @@ create_error: thd->options&= ~(ulong) (OPTION_TABLE_LOCK); thd->in_lock_tables=0; break; + case SQLCOM_LOCK_TABLES_TRANSACTIONAL: + { + uint counter = 0; + + if (check_db_used(thd, all_tables)) + goto error; + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0)) + goto error; + + thd->in_lock_tables=1; + thd->options|= OPTION_TABLE_LOCK; + + if (open_tables(thd, all_tables, &counter) == 0 && + transactional_lock_tables(thd, all_tables, counter) == 0) + send_ok(thd); + else + thd->options&= ~(ulong) (OPTION_TABLE_LOCK); + + thd->in_lock_tables=0; + break; + } case SQLCOM_CREATE_DB: { char *alias; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 74a96701bdc..1f467702056 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7395,8 +7395,8 @@ lock: { Lex->sql_command=SQLCOM_LOCK_TABLES; } - table_lock_list - {} + table_lock_list lock_engine_opt + {} ; table_or_tables: @@ -7422,6 +7422,15 @@ lock_option: | READ_SYM LOCAL_SYM { $$= TL_READ; } ; +lock_engine_opt: + /* empty */ + | WHERE + { + Lex->sql_command=SQLCOM_LOCK_TABLES_TRANSACTIONAL; + } + ENGINE_SYM opt_equal storage_engines + ; + unlock: UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; } ; From 795a8c829bac0c28e1fa4ceea3cc9c44e312b021 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 13 Dec 2004 14:22:18 +0200 Subject: [PATCH 03/11] Fixed problems with deadlocks on LOCK TABLES...WHERE ENGINE = InnoDB. innobase/lock/lock0lock.c: Fixed problem with deadlocks on LOCK TABLES...WHERE ENGINE = InnoDB. Added TRX_PREPARED to transaction concurrency states in validate. --- innobase/lock/lock0lock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index ee171de114c..05466764063 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -3642,7 +3642,7 @@ lock_table( /* Another trx has a request on the table in an incompatible mode: this trx may have to wait */ - err = lock_table_enqueue_waiting(mode, table, thr); + err = lock_table_enqueue_waiting(mode | flags, table, thr); lock_mutex_exit_kernel(); @@ -4438,6 +4438,7 @@ lock_table_queue_validate( while (lock) { ut_a(((lock->trx)->conc_state == TRX_ACTIVE) + || ((lock->trx)->conc_state == TRX_PREPARED) || ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY)); if (!lock_get_wait(lock)) { @@ -4485,6 +4486,7 @@ lock_rec_queue_validate( while (lock) { ut_a(lock->trx->conc_state == TRX_ACTIVE + || lock->trx->conc_state == TRX_PREPARED || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY); @@ -4539,6 +4541,7 @@ lock_rec_queue_validate( while (lock) { ut_a(lock->trx->conc_state == TRX_ACTIVE + || lock->trx->conc_state == TRX_PREPARED || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY); ut_a(trx_in_trx_list(lock->trx)); @@ -4621,6 +4624,7 @@ loop: ut_a(trx_in_trx_list(lock->trx)); ut_a(lock->trx->conc_state == TRX_ACTIVE + || lock->trx->conc_state == TRX_PREPARED || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY); for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) { From 868266f1b1ec0adde75db2887bbc73306441caeb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Dec 2004 09:52:19 +0200 Subject: [PATCH 04/11] Print a error message if the handler don't support transactional table locks (LOCK TABLES ... WHERE ENGINE = ). sql/handler.h: Return a error if the handler don't support transactional table locks. sql/lock.cc: Print a error message if the handler don't support transactional table locks. --- sql/handler.h | 8 +++++++- sql/lock.cc | 20 ++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/sql/handler.h b/sql/handler.h index 4c6bd1c986b..bd2d5e42b65 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -452,7 +452,13 @@ public: { return extra(operation); } virtual int reset() { return extra(HA_EXTRA_RESET); } virtual int external_lock(THD *thd, int lock_type) { return 0; } - virtual int transactional_table_lock(THD *thd, int lock_type) {return 0;} + /* + This is called to set transactional table lock to a table. + If the handler don't support this, then this function will + return HA_ERR_WRONG_COMMAND and MySQL will give + ER_ILLEGAL_HA error message. + */ + virtual int transactional_table_lock(THD *thd, int lock_type) {return HA_ERR_WRONG_COMMAND;} virtual void unlock_row() {} virtual int start_stmt(THD *thd) {return 0;} /* diff --git a/sql/lock.cc b/sql/lock.cc index 1d511fec415..393cf4cf142 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -79,7 +79,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count, bool unlock, TABLE **write_locked); static int lock_external(THD *thd, TABLE **table,uint count); static int unlock_external(THD *thd, TABLE **table,uint count); -static void print_lock_error(int error); +static void print_lock_error(int error, const char *); MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) @@ -187,7 +187,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count) (*tables)->file->external_lock(thd, F_UNLCK); (*tables)->current_lock=F_UNLCK; } - print_lock_error(error); + print_lock_error(error, (*tables)->file->table_type()); DBUG_RETURN(error); } else @@ -380,7 +380,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count) table++; } while (--count); if (error_code) - print_lock_error(error_code); + print_lock_error(error_code, (*table)->file->table_type()); DBUG_RETURN(error_code); } @@ -683,7 +683,7 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list, } -static void print_lock_error(int error) +static void print_lock_error(int error, const char *table) { int textno; DBUG_ENTER("print_lock_error"); @@ -698,11 +698,19 @@ static void print_lock_error(int error) case HA_ERR_LOCK_DEADLOCK: textno=ER_LOCK_DEADLOCK; break; + case HA_ERR_WRONG_COMMAND: + textno=ER_ILLEGAL_HA; + break; default: textno=ER_CANT_LOCK; break; } - my_error(textno,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error); + + if ( textno == ER_ILLEGAL_HA ) + my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table); + else + my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error); + DBUG_VOID_RETURN; } @@ -977,7 +985,7 @@ int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter) if ((error=(*start)->file->transactional_table_lock(thd, lock_type))) { - print_lock_error(error); + print_lock_error(error, (*start)->file->table_type()); DBUG_RETURN(-1); } else From bc152db57932ffec118a11ad9607fb99d9d2bdd4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Dec 2004 15:34:48 +0300 Subject: [PATCH 05/11] Fix for bug #6849 "Crash while preparing query containing const expr with IN and CONVERT_TZ()" (with after review changes). Now we add implicitly used time zone tables to global table list right at the parsing stage instead of doing it later in mysql_execute_command() or in check_prepared_statement(). No special test-case needed since this bug also manifests itself as timezone2.test failure if one runs it with --ps-protocol option. sql/sql_base.cc: relink_tables_for_multidelete(): presence of implicitly used time zone tables is no longer condition for propagation of TABLE pointers from global table list to local table lists (since now global list is always created...) sql/sql_lex.cc: - Added LEX::add_time_zone_tables_to_query_tables() function which adds implicitly used time zone tables to global table list. - Definition of fake_time_zone_tables_list moved to tztime.cc, since it is no longer used in parser. sql/sql_lex.h: - Since now we add implicitly used time zone tables right at parsing stage, LEX::time_zone_tables_used is either zero or points to valid time zone tables list. Updated its description to reflect that. - Added LEX::add_time_zone_tables_to_query_tables() function which adds implicitly used time zone tables to global table list. - Declaration of fake_time_zone_tables_list moved to tztime.h, since it is no longer used in parser. sql/sql_parse.cc: mysql_execute_command(): Removed adding list of implicitly used time zone tables to global table list, since now we do this right at the parsing stage. sql/sql_yacc.yy: Let us add implicitly used time zone tables to global table list right at the parsing stage instead of doing it later in mysql_execute_command() or in check_prepared_statement(). sql/tztime.cc: Moved fake_time_zone_tables_list definition from sql_lex.cc to tztime.cc since now it is used only for error reporting from my_tz_get_table_list() function. sql/tztime.h: Moved fake_time_zone_tables_list declaration from sql_lex.h to tztime.h since now it is used only for error reporting from my_tz_get_table_list() function. --- sql/sql_base.cc | 3 +-- sql/sql_lex.cc | 34 +++++++++++++++++++++++++--------- sql/sql_lex.h | 7 +++---- sql/sql_parse.cc | 13 ------------- sql/sql_yacc.yy | 8 +++++--- sql/tztime.cc | 6 ++++++ sql/tztime.h | 1 + 7 files changed, 41 insertions(+), 31 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b4a2f368bc2..6d2aa3a6fba 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1864,8 +1864,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) static void relink_tables_for_multidelete(THD *thd) { - if (thd->lex->all_selects_list->next_select_in_list() || - thd->lex->time_zone_tables_used) + if (thd->lex->all_selects_list->next_select_in_list()) { for (SELECT_LEX *sl= thd->lex->all_selects_list; sl; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 12e4d912f15..8f5114b290a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -30,15 +30,6 @@ */ sys_var_long_ptr trg_new_row_fake_var(0, 0); -/* - Fake table list object, pointer to which is used as special value for - st_lex::time_zone_tables_used indicating that we implicitly use time - zone tables in this statement but real table list was not yet created. - Pointer to it is also returned by my_tz_get_tables_list() as indication - of transient error; -*/ -TABLE_LIST fake_time_zone_tables_list; - /* Macros to look like lex */ #define yyGet() *(lex->ptr++) @@ -1880,6 +1871,31 @@ void st_lex::first_lists_tables_same() } +/* + Add implicitly used time zone description tables to global table list + (if needed). + + SYNOPSYS + st_lex::add_time_zone_tables_to_query_tables() + thd - pointer to current thread context + + RETURN VALUE + TRUE - error + FALSE - success +*/ + +bool st_lex::add_time_zone_tables_to_query_tables(THD *thd) +{ + /* We should not add these tables twice */ + if (!time_zone_tables_used) + { + time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last); + if (time_zone_tables_used == &fake_time_zone_tables_list) + return TRUE; + } + return FALSE; +} + /* Link table back that was unlinked with unlink_first_table() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 1c0e3e2e02e..e0e9d2503fe 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -735,9 +735,8 @@ typedef struct st_lex /* Names of user variables holding parameters (in EXECUTE) */ List prepared_stmt_params; /* - If points to fake_time_zone_tables_list indicates that time zone - tables are implicitly used by statement, also is used for holding - list of those tables after they are opened. + Points to part of global table list which contains time zone tables + implicitly used by the statement. */ TABLE_LIST *time_zone_tables_used; sp_head *sphead; @@ -802,6 +801,7 @@ typedef struct st_lex *(table->prev_global= query_tables_last)= table; query_tables_last= &table->next_global; } + bool add_time_zone_tables_to_query_tables(THD *thd); bool can_be_merged(); bool can_use_merged(); @@ -810,7 +810,6 @@ typedef struct st_lex bool need_correct_ident(); } LEX; -extern TABLE_LIST fake_time_zone_tables_list; struct st_lex_local: public st_lex { static void *operator new(size_t size) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3d4252a2b17..3094bd76b4e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2114,19 +2114,6 @@ mysql_execute_command(THD *thd) } #endif /* !HAVE_REPLICATION */ - if (lex->time_zone_tables_used) - { - TABLE_LIST *tmp; - if ((tmp= my_tz_get_table_list(thd, &lex->query_tables_last)) == - &fake_time_zone_tables_list) - { - DBUG_RETURN(-1); - } - lex->time_zone_tables_used= tmp; - if (!all_tables) - all_tables= tmp; - } - /* When option readonly is set deny operations which change tables. Except for the replication thread and the 'super' users. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3511777dd27..673f340722b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4266,7 +4266,8 @@ simple_expr: { $$= create_func_contains($3, $5); } | CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')' { - Lex->time_zone_tables_used= &fake_time_zone_tables_list; + if (Lex->add_time_zone_tables_to_query_tables(YYTHD)) + YYABORT; $$= new Item_func_convert_tz($3, $5, $7); } | CURDATE optional_braces @@ -7276,8 +7277,9 @@ internal_variable_name: If this is time_zone variable we should open time zone describing tables */ - if (tmp == &sys_time_zone) - Lex->time_zone_tables_used= &fake_time_zone_tables_list; + if (tmp == &sys_time_zone && + lex->add_time_zone_tables_to_query_tables(YYTHD)) + YYABORT; } else { diff --git a/sql/tztime.cc b/sql/tztime.cc index 50c496577e0..2c25c647a19 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1439,6 +1439,12 @@ tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr) } +/* + Fake table list object, pointer to which is returned by + my_tz_get_tables_list() as indication of error. +*/ +TABLE_LIST fake_time_zone_tables_list; + /* Create table list with time zone related tables and add it to the end of global table list. diff --git a/sql/tztime.h b/sql/tztime.h index 6d2388bb160..07e9146c6e9 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -64,6 +64,7 @@ extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables); extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap); extern void my_tz_free(); +extern TABLE_LIST fake_time_zone_tables_list; /* Check if we have pointer to the beggining of list of implictly used From 5db116af7a818141a475a8b8cf8a4ea5caf53cc0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Dec 2004 09:55:06 +0300 Subject: [PATCH 06/11] Added test which covers nicely recent cleanup in derived tables processing. --- mysql-test/r/derived.result | 5 +++++ mysql-test/t/derived.test | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index ddd8f82de2c..da2bb9081de 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -330,3 +330,8 @@ SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MA min max avg 10.00 10.00 10 DROP TABLE t1; +CREATE TABLE t1 (a char(10), b char(10)); +INSERT INTO t1 VALUES ('root','localhost'), ('root','%'); +SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c; +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 64e3fe8929b..d204947b1fa 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -214,3 +214,16 @@ CREATE TABLE `t1` ( `itemid` int(11) NOT NULL default '0', `grpid` varchar(15) N insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10); SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MAX(concat(date_,";",price)), 12) price FROM t1 WHERE itemid=128 AND grpid='rozn' GROUP BY itemid, grpid, vendor) lastprices; DROP TABLE t1; + +# +# Test for bug #7413 "Subquery with non-scalar results participating in +# select list of derived table crashes server" aka "VIEW with sub query can +# cause the MySQL server to crash". If we have encountered problem during +# filling of derived table we should report error and perform cleanup +# properly. +# +CREATE TABLE t1 (a char(10), b char(10)); +INSERT INTO t1 VALUES ('root','localhost'), ('root','%'); +--error 1242 +SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c; +DROP TABLE t1; From 060baf18217ca5823ae747d72d676e7e46c425ce Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Dec 2004 20:18:17 +0400 Subject: [PATCH 07/11] A fix (bug #7283: Test failure: 'update' (using '--ps-protocol': server crash)). client/mysqltest.c: A fix (bug #7283: Test failure: 'update' (using '--ps-protocol': server crash)). Unused bind slots should be zeroed. --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index bd4de026acb..8ddcfb90cad 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2896,7 +2896,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) /* Allocate array with bind structs, lengths and NULL flags */ bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), - MYF(MY_WME | MY_FAE)); + MYF(MY_WME | MY_FAE | MY_ZEROFILL)); length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long), MYF(MY_WME | MY_FAE)); is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), From 1fc04e0b1202857c2b5e245f2f1654d3f49a11e3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Dec 2004 01:59:58 +0300 Subject: [PATCH 08/11] Fix for BUG#4480: In joins with SELECT_STRAIGHT_JOIN re-order tables by outer join dependency, so we read dependent tables after tables they depend on (this is needed for outer joins) mysql-test/r/join_outer.result: Test for BUG#4480 mysql-test/t/join_outer.test: Test for BUG#4480 --- mysql-test/r/join_outer.result | 15 ++++++++++++ mysql-test/t/join_outer.test | 10 ++++++++ sql/sql_select.cc | 42 ++++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 2f420905195..b7343065c73 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -853,4 +853,19 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index 1 SIMPLE t2 ALL NULL NULL NULL NULL 2 1 SIMPLE t3 ALL NULL NULL NULL NULL 2 +drop table t1,t2; +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2),(3,3); +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2); +select * from t2 right join t1 on t2.a=t1.a; +a b a b +1 1 1 1 +2 2 2 2 +NULL NULL 3 3 +select straight_join * from t2 right join t1 on t2.a=t1.a; +a b a b +1 1 1 1 +2 2 2 2 +NULL NULL 3 3 DROP TABLE t0,t1,t2,t3; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 665b4fafbca..ce2ce577b46 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -606,4 +606,14 @@ INSERT INTO t1 VALUES (0); SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1; EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1; +# Test for BUG#4480 +drop table t1,t2; +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2),(3,3); +create table t2 (a int, b int); +insert into t2 values (1,1), (2,2); + +select * from t2 right join t1 on t2.a=t1.a; +select straight_join * from t2 right join t1 on t2.a=t1.a; + DROP TABLE t0,t1,t2,t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 44412cdc43a..570774c8054 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -64,6 +64,7 @@ static void best_extension_by_limited_search(JOIN *join, uint prune_level); static uint determine_search_depth(JOIN* join); static int join_tab_cmp(const void* ptr1, const void* ptr2); +static int join_tab_cmp_straight(const void* ptr1, const void* ptr2); /* TODO: 'find_best' is here only temporarily until 'greedy_search' is tested and approved. @@ -3678,22 +3679,26 @@ choose_plan(JOIN *join, table_map join_tables) { uint search_depth= join->thd->variables.optimizer_search_depth; uint prune_level= join->thd->variables.optimizer_prune_level; - + bool straight_join= join->select_options & SELECT_STRAIGHT_JOIN; DBUG_ENTER("choose_plan"); - if (join->select_options & SELECT_STRAIGHT_JOIN) + /* + if (SELECT_STRAIGHT_JOIN option is set) + reorder tables so dependent tables come after tables they depend + on, otherwise keep tables in the order they were specified in the query + else + Apply heuristic: pre-sort all access plans with respect to the number of + records accessed. + */ + qsort(join->best_ref + join->const_tables, join->tables - join->const_tables, + sizeof(JOIN_TAB*), straight_join?join_tab_cmp_straight:join_tab_cmp); + + if (straight_join) { optimize_straight_join(join, join_tables); } else { - /* - Heuristic: pre-sort all access plans with respect to the number of - records accessed. - */ - qsort(join->best_ref + join->const_tables, join->tables - join->const_tables, - sizeof(JOIN_TAB*), join_tab_cmp); - if (search_depth == MAX_TABLES+2) { /* TODO: 'MAX_TABLES+2' denotes the old implementation of find_best before @@ -3750,6 +3755,23 @@ join_tab_cmp(const void* ptr1, const void* ptr2) } +/* + Same as join_tab_cmp, but for use with SELECT_STRAIGHT_JOIN. +*/ + +static int +join_tab_cmp_straight(const void* ptr1, const void* ptr2) +{ + JOIN_TAB *jt1= *(JOIN_TAB**) ptr1; + JOIN_TAB *jt2= *(JOIN_TAB**) ptr2; + + if (jt1->dependent & jt2->table->map) + return 1; + if (jt2->dependent & jt1->table->map) + return -1; + return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0); +} + /* Heuristic procedure to automatically guess a reasonable degree of exhaustiveness for the greedy search procedure. @@ -3832,7 +3854,7 @@ optimize_straight_join(JOIN *join, table_map join_tables) uint idx= join->const_tables; double record_count= 1.0; double read_time= 0.0; - + for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++) { /* Find the best access method from 's' to the current partial plan */ From 920ed11aef4fbf43e114965fa294d81c4ffe5bbe Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Dec 2004 15:53:01 +0200 Subject: [PATCH 09/11] Review fixes. --- sql/ha_innodb.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 61481de6e10..cb23e31225b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -5357,7 +5357,7 @@ ha_innobase::transactional_table_lock( "MySQL is trying to use a table handle but the .ibd file for\n" "table %s does not exist.\n" "Have you deleted the .ibd file from the database directory under\n" -"the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"the MySQL datadir?" "Look from section 15.1 of http://www.innodb.com/ibman.html\n" "how you can resolve the problem.\n", prebuilt->table->name); @@ -5376,8 +5376,8 @@ ha_innobase::transactional_table_lock( prebuilt->select_lock_type = LOCK_X; prebuilt->stored_select_lock_type = LOCK_X; } else if (lock_type == F_RDLCK) { - prebuilt->select_lock_type = LOCK_X; - prebuilt->stored_select_lock_type = LOCK_X; + prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; } else { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB error:\n" From 5676cbc12b3e9aec9875566585cdde75921f6534 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Dec 2004 17:16:39 +0100 Subject: [PATCH 10/11] small fixes in documentation --- ndb/include/ndbapi/NdbEventOperation.hpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ndb/include/ndbapi/NdbEventOperation.hpp b/ndb/include/ndbapi/NdbEventOperation.hpp index 056e9a58c74..6a2e7d56ca8 100644 --- a/ndb/include/ndbapi/NdbEventOperation.hpp +++ b/ndb/include/ndbapi/NdbEventOperation.hpp @@ -64,7 +64,7 @@ class NdbEventOperationImpl; * * Known issues: * - * When several NdbEventOperation s are tied to the same event in the same + * When several NdbEventOperation's are tied to the same event in the same * process they will share the circular buffer. The BufferLength will then * be the same for all and decided by the first NdbEventOperation * instantiation. Just make sure to instantiate the "largest" one first. @@ -84,7 +84,7 @@ class NdbEventOperationImpl; * replica. If a node fails events will not be received twice anymore * for data in corresponding fragment. Will be optimized in later versions. * - * If a nodefailiure has occured not all events will be recieved + * If a node failure has occured not all events will be recieved * anymore. Drop NdbEventOperation and Create again after nodes are up * again. Will be fixed in later versions. * @@ -97,7 +97,7 @@ class NdbEventOperationImpl; * * Useful API programs: * - * select_all -d sys 'NDB$EVENTS_0' + * ndb_select_all -d sys 'NDB$EVENTS_0' * Will show contents in the system table containing created events. * */ @@ -187,8 +187,19 @@ public: */ NdbDictionary::Event::TableEvent getEventType(); + /** + * + */ Uint32 getGCI(); + + /** + * + */ Uint32 getLatestGCI(); + + /* + * + */ void print(); private: From 8b80b584885ba68e8884704d608a05dfb3611062 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Dec 2004 01:00:29 +0300 Subject: [PATCH 11/11] Bug #7468 Instance Manager fails to compile: thread_registry.cc This fix icludes workaround for Irix compiler bug & removs some unused variables (resulted in warnings) server-tools/instance-manager/mysql_connection.cc: removed unused variable server-tools/instance-manager/parse.cc: removed unused variable server-tools/instance-manager/thread_registry.cc: Workaround for the Irix compiler bug server-tools/instance-manager/user_map.cc: removed unused variable --- server-tools/instance-manager/mysql_connection.cc | 1 - server-tools/instance-manager/parse.cc | 1 - server-tools/instance-manager/thread_registry.cc | 5 +++-- server-tools/instance-manager/user_map.cc | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc index 83b046c1e5b..d3f58bf3771 100644 --- a/server-tools/instance-manager/mysql_connection.cc +++ b/server-tools/instance-manager/mysql_connection.cc @@ -296,7 +296,6 @@ int Mysql_connection_thread::check_user(const char *user, const char *password) int Mysql_connection_thread::do_command() { char *packet; - uint old_timeout; ulong packet_length; /* We start to count packets from 0 for each new command */ diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc index 38e10c7f2f5..d029267f9b8 100644 --- a/server-tools/instance-manager/parse.cc +++ b/server-tools/instance-manager/parse.cc @@ -131,7 +131,6 @@ Command *parse_command(Command_factory *factory, const char *text) const char *instance_name; uint instance_name_len; Command *command; - const char *saved_text= text; Token tok1= shift_token(&text, &word_len); diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc index 4037da71880..d0bf51f3d61 100644 --- a/server-tools/instance-manager/thread_registry.cc +++ b/server-tools/instance-manager/thread_registry.cc @@ -148,6 +148,7 @@ int Thread_registry::cond_wait(Thread_info *info, pthread_cond_t *cond, void Thread_registry::deliver_shutdown() { + Thread_info *info; struct timespec shutdown_time; set_timespec(shutdown_time, 1); @@ -161,7 +162,7 @@ void Thread_registry::deliver_shutdown() stopped alarm processing. */ process_alarm(THR_SERVER_ALARM); - for (Thread_info *info= head.next; info != &head; info= info->next) + for (info= head.next; info != &head; info= info->next) { pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL); /* @@ -190,7 +191,7 @@ void Thread_registry::deliver_shutdown() so this time everybody should be informed (presumably each worker can get CPU during shutdown_time.) */ - for (Thread_info *info= head.next; info != &head; info= info->next) + for (info= head.next; info != &head; info= info->next) { pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL); if (info->current_cond) diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc index b921152d858..8cbceceac7c 100644 --- a/server-tools/instance-manager/user_map.cc +++ b/server-tools/instance-manager/user_map.cc @@ -123,7 +123,6 @@ int User_map::load(const char *password_file_name) 1 + /* for ':' */ 1 + /* for newline */ 1]; /* for trailing zero */ - uint line_length; User *user; int rc= 1;