diff options
-rw-r--r-- | mysql-test/r/table_elim.result | 31 | ||||
-rw-r--r-- | mysql-test/suite/handler/innodb.result | 10 | ||||
-rw-r--r-- | mysql-test/suite/handler/innodb.test | 11 | ||||
-rw-r--r-- | mysql-test/t/table_elim.test | 32 | ||||
-rw-r--r-- | sql/handler.h | 23 | ||||
-rw-r--r-- | sql/table.h | 2 | ||||
-rw-r--r-- | storage/federated/ha_federated.cc | 2 | ||||
-rw-r--r-- | storage/maria/ha_maria.cc | 2 | ||||
-rw-r--r-- | storage/maria/ma_pagecache.c | 25 | ||||
-rw-r--r-- | storage/maria/maria_read_log.c | 17 |
10 files changed, 126 insertions, 29 deletions
diff --git a/mysql-test/r/table_elim.result b/mysql-test/r/table_elim.result index e635f745ed3..19567770042 100644 --- a/mysql-test/r/table_elim.result +++ b/mysql-test/r/table_elim.result @@ -535,3 +535,34 @@ HAVING field4 != 6; field1 field2 field3 field4 field5 field6 drop table t0,t1,t2,t3,t4,t5,t6; +# +# BUG#675118: Elimination of a table results in an invalid execution plan +# +CREATE TABLE t1 (f1 int(11), PRIMARY KEY (f1)) ; +CREATE TABLE t2 (f4 varchar(1024), KEY (f4)) ; +Warnings: +Warning 1071 Specified key was too long; max key length is 1000 bytes +INSERT IGNORE INTO t2 VALUES ('xcddwntkbxyorzdv'), +('cnxxcddwntkbxyor'),('r'),('r'), ('did'),('I'),('when'), +('hczkfqjeggivdvac'),('e'),('okay'),('up'); +CREATE TABLE t3 (f4 varchar(1024), f1 int(11), f2 int(11)) ; +INSERT IGNORE INTO t3 VALUES ('f','4','0'),('n','5','-996540416'); +CREATE TABLE t4 (f1 int(11), f3 varchar(10)) ; +INSERT IGNORE INTO t4 VALUES ('8','n'),('9','nwzcerzsgx'),('10','c'); +CREATE TABLE t5 (f5 int(11), KEY (f5)) ; +EXPLAIN +SELECT t3.f2 +FROM t2 +LEFT JOIN t3 +LEFT JOIN t4 +LEFT JOIN t1 ON t4.f1 = t1.f1 +JOIN t5 ON t4.f3 ON t3.f1 = t5.f5 ON t2.f4 = t3.f4 +WHERE t3.f2 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where +1 SIMPLE t5 ref f5 f5 5 test.t3.f1 2 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 3 +1 SIMPLE t2 ALL f4 NULL NULL NULL 11 Using where; Using join buffer +# ^^ The above must not produce a QEP of t3,t5,t2,t4 +# as that violates the "no interleaving of outer join nests" rule. +DROP TABLE t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/handler/innodb.result b/mysql-test/suite/handler/innodb.result index 6c3d03e291f..9d3bbb2ddfe 100644 --- a/mysql-test/suite/handler/innodb.result +++ b/mysql-test/suite/handler/innodb.result @@ -688,3 +688,13 @@ HANDLER t1 READ a NEXT; a HANDLER t1 CLOSE; DROP TABLE t1; +CREATE TABLE t1 (f1 integer, f2 integer, primary key (f1), key (f2)) engine=innodb; +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +HANDLER t1 OPEN; +HANDLER t1 READ FIRST WHERE f2 <= 1; +f1 f2 +1 1 +HANDLER t1 READ `PRIMARY` PREV; +f1 f2 +3 3 +DROP TABLE t1; diff --git a/mysql-test/suite/handler/innodb.test b/mysql-test/suite/handler/innodb.test index f4e4bf7cc3f..6527c4bb8bb 100644 --- a/mysql-test/suite/handler/innodb.test +++ b/mysql-test/suite/handler/innodb.test @@ -15,3 +15,14 @@ let $engine_type= InnoDB; --source init.inc --source handler.inc + +# +# LP#697610 ha_index_prev(uchar*): Assertion `inited==INDEX' +# + +CREATE TABLE t1 (f1 integer, f2 integer, primary key (f1), key (f2)) engine=innodb; +INSERT INTO t1 VALUES (1,1),(2,2),(3,3); +HANDLER t1 OPEN; +HANDLER t1 READ FIRST WHERE f2 <= 1; +HANDLER t1 READ `PRIMARY` PREV; +DROP TABLE t1; diff --git a/mysql-test/t/table_elim.test b/mysql-test/t/table_elim.test index 7ad69d5bf37..5576362b396 100644 --- a/mysql-test/t/table_elim.test +++ b/mysql-test/t/table_elim.test @@ -467,3 +467,35 @@ HAVING field4 != 6; drop table t0,t1,t2,t3,t4,t5,t6; + +--echo # +--echo # BUG#675118: Elimination of a table results in an invalid execution plan +--echo # +CREATE TABLE t1 (f1 int(11), PRIMARY KEY (f1)) ; + +CREATE TABLE t2 (f4 varchar(1024), KEY (f4)) ; +INSERT IGNORE INTO t2 VALUES ('xcddwntkbxyorzdv'), + ('cnxxcddwntkbxyor'),('r'),('r'), ('did'),('I'),('when'), + ('hczkfqjeggivdvac'),('e'),('okay'),('up'); + +CREATE TABLE t3 (f4 varchar(1024), f1 int(11), f2 int(11)) ; +INSERT IGNORE INTO t3 VALUES ('f','4','0'),('n','5','-996540416'); + +CREATE TABLE t4 (f1 int(11), f3 varchar(10)) ; +INSERT IGNORE INTO t4 VALUES ('8','n'),('9','nwzcerzsgx'),('10','c'); + +CREATE TABLE t5 (f5 int(11), KEY (f5)) ; + +EXPLAIN +SELECT t3.f2 +FROM t2 +LEFT JOIN t3 +LEFT JOIN t4 +LEFT JOIN t1 ON t4.f1 = t1.f1 +JOIN t5 ON t4.f3 ON t3.f1 = t5.f5 ON t2.f4 = t3.f4 +WHERE t3.f2 ; +--echo # ^^ The above must not produce a QEP of t3,t5,t2,t4 +--echo # as that violates the "no interleaving of outer join nests" rule. + +DROP TABLE t1,t2,t3,t4,t5; + diff --git a/sql/handler.h b/sql/handler.h index 0878206b2ac..02fab02e52e 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1559,16 +1559,20 @@ public: DBUG_ENTER("ha_index_init"); DBUG_ASSERT(inited==NONE); if (!(result= index_init(idx, sorted))) - inited=INDEX; - end_range= NULL; + { + inited= INDEX; + active_index= idx; + end_range= NULL; + } DBUG_RETURN(result); } int ha_index_end() { DBUG_ENTER("ha_index_end"); DBUG_ASSERT(inited==INDEX); - inited=NONE; - end_range= NULL; + inited= NONE; + active_index= MAX_KEY; + end_range= NULL; DBUG_RETURN(index_end()); } /* This is called after index_init() if we need to do a index scan */ @@ -1751,7 +1755,12 @@ public: as there may be several calls to this routine. */ virtual void column_bitmaps_signal(); - uint get_index(void) const { return active_index; } + /* + We have to check for inited as some engines, like innodb, sets + active_index during table scan. + */ + uint get_index(void) const + { return inited == INDEX ? active_index : MAX_KEY; } virtual int close(void)=0; /** @@ -2261,8 +2270,8 @@ private: */ virtual int open(const char *name, int mode, uint test_if_locked)=0; - virtual int index_init(uint idx, bool sorted) { active_index= idx; return 0; } - virtual int index_end() { active_index= MAX_KEY; return 0; } + virtual int index_init(uint idx, bool sorted) { return 0; } + virtual int index_end() { return 0; } /** rnd_init() can be called two times without rnd_end() in between (it only makes sense if scan=1). diff --git a/sql/table.h b/sql/table.h index 7688d289f81..0dccc02d51f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1813,7 +1813,7 @@ typedef struct st_nested_join 2. All child join nest nodes are fully covered. */ - bool is_fully_covered() const { return join_list.elements == counter; } + bool is_fully_covered() const { return n_tables == counter; } } NESTED_JOIN; diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index fcc178b09a6..34509e04799 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -2453,7 +2453,6 @@ int ha_federated::index_init(uint keynr, bool sorted) { DBUG_ENTER("ha_federated::index_init"); DBUG_PRINT("info", ("table: '%s' key: %u", table->s->table_name.str, keynr)); - active_index= keynr; DBUG_RETURN(0); } @@ -2589,7 +2588,6 @@ int ha_federated::index_end(void) { DBUG_ENTER("ha_federated::index_end"); free_result(); - active_index= MAX_KEY; DBUG_RETURN(0); } diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 6f01d1e9b5e..98e4a11053d 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -228,7 +228,7 @@ static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size, "The size of the buffer used for index blocks for Aria tables. " "Increase this to get better index handling (for all reads and " "multiple writes) to as much as you can afford.", 0, 0, - KEY_CACHE_SIZE, 0, ~(ulong) 0, 1); + KEY_CACHE_SIZE, 8192*16L, ~(ulong) 0, 1); static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit, PLUGIN_VAR_RQCMDARG, diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index 9a253fbf90c..4d7eb008d77 100644 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2008 MySQL AB +/* Copyright (C) 2000-2008 MySQL AB, 2008-2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -760,6 +760,8 @@ ulong init_pagecache(PAGECACHE *pagecache, size_t use_mem, { if (blocks < 8) { + my_message(ENOMEM, "Not enough memory to allocate 8 pagecache pages", + MYF(0)); my_errno= ENOMEM; goto err; } @@ -4214,6 +4216,7 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block) DBUG_ASSERT(block->rlocks == 0); DBUG_ASSERT(block->rlocks_queue == 0); DBUG_ASSERT(block->pins == 0); + DBUG_ASSERT((block->status & ~(PCBLOCK_ERROR | PCBLOCK_READ | PCBLOCK_IN_FLUSH | PCBLOCK_CHANGED | PCBLOCK_REASSIGNED)) == 0); block->status= 0; #ifndef DBUG_OFF block->type= PAGECACHE_EMPTY_PAGE; @@ -4542,6 +4545,7 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache, KEYCACHE_DBUG_ASSERT(count<= pagecache->blocks_used); } } + count++; /* Allocate one extra for easy end-of-buffer test */ /* Allocate a new buffer only if its bigger than the one we have */ if (count > FLUSH_CACHE && !(cache= @@ -4579,22 +4583,24 @@ restart: DBUG_ASSERT(filter_res == FLUSH_FILTER_OK); } { + DBUG_ASSERT(!(block->status & PCBLOCK_IN_FLUSH)); /* - Mark the block with BLOCK_IN_FLUSH in order not to let - other threads to use it for new pages and interfere with - our sequence of flushing dirty file pages + We care only for the blocks for which flushing was not + initiated by other threads as a result of page swapping */ - block->status|= PCBLOCK_IN_FLUSH; - if (! (block->status & PCBLOCK_IN_SWITCH)) { - /* - We care only for the blocks for which flushing was not - initiated by other threads as a result of page swapping + /* + Mark the block with BLOCK_IN_FLUSH in order not to let + other threads to use it for new pages and interfere with + our sequence of flushing dirty file pages */ + block->status|= PCBLOCK_IN_FLUSH; + reg_requests(pagecache, block, 1); if (type != FLUSH_IGNORE_CHANGED) { + *pos++= block; /* It's not a temporary file */ if (pos == end) { @@ -4614,7 +4620,6 @@ restart: */ goto restart; } - *pos++= block; } else { diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index 3657e2db332..7a630e274e3 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -192,14 +192,18 @@ static struct my_option my_long_options[] = {"display-only", 'd', "display brief info read from records' header", &opt_display_only, &opt_display_only, 0, GET_BOOL, NO_ARG,0, 0, 0, 0, 0, 0}, + { "end-lsn", 'e', "Stop applying at this lsn. If end-lsn is used, UNDO:s " + "will not be applied", &opt_end_lsn, &opt_end_lsn, + 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 }, {"aria-log-dir-path", 'l', "Path to the directory where to store transactional log", (uchar **) &maria_data_root, (uchar **) &maria_data_root, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - { "page-buffer-size", 'P', "", + { "page-buffer-size", 'P', + "The size of the buffer used for index blocks for Maria tables", &opt_page_buffer_size, &opt_page_buffer_size, 0, GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, - (long) USE_BUFFER_INIT, (long) ~(ulong) 0, (long) MALLOC_OVERHEAD, + 1024L*1024L, (long) ~(ulong) 0, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0}, { "start-from-lsn", 'o', "Start reading log from this lsn", &opt_start_from_lsn, &opt_start_from_lsn, @@ -207,18 +211,12 @@ static struct my_option my_long_options[] = {"start-from-checkpoint", 'C', "Start applying from last checkpoint", &opt_start_from_checkpoint, &opt_start_from_checkpoint, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - { "end-lsn", 'e', "Stop applying at this lsn. If end-lsn is used, UNDO:s " - "will not be applied", &opt_end_lsn, &opt_end_lsn, - 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 }, {"silent", 's', "Print less information during apply/undo phase", &opt_silent, &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tables-to-redo", 'T', "List of tables sepearated with , that we should apply REDO on. Use this if you only want to recover some tables", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Print more information during apply/undo phase", - &maria_recovery_verbose, &maria_recovery_verbose, 0, - GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Path for temporary files. Multiple paths can be specified, " "separated by " #if defined( __WIN__) || defined(__NETWARE__) @@ -230,6 +228,9 @@ static struct my_option my_long_options[] = {"undo", 'u', "Apply UNDO records to tables. (disable with --disable-undo)", (uchar **) &opt_apply_undo, (uchar **) &opt_apply_undo, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"verbose", 'v', "Print more information during apply/undo phase", + &maria_recovery_verbose, &maria_recovery_verbose, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |