diff options
-rw-r--r-- | mysql-test/r/partition.result | 22 | ||||
-rw-r--r-- | mysql-test/r/sp-code.result | 4 | ||||
-rw-r--r-- | mysql-test/t/disabled.def | 1 | ||||
-rw-r--r-- | mysql-test/t/partition.test | 27 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 45 | ||||
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/sql_partition.cc | 67 |
7 files changed, 160 insertions, 7 deletions
diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index a638babc365..699f448689b 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -278,3 +278,25 @@ partition p1 values in (14) insert into t1 values (10,1); ERROR HY000: Table has no partition for value 11 drop table t1; +create table t1 (f1 integer,f2 integer, f3 varchar(10), primary key(f1,f2)) +partition by range(f1) subpartition by hash(f2) subpartitions 2 +(partition p1 values less than (0), +partition p2 values less than (2), +partition p3 values less than (2147483647)); +insert into t1 values(10,10,'10'); +insert into t1 values(2,2,'2'); +select * from t1 where f1 = 2; +f1 f2 f3 +2 2 2 +drop table t1; +create table t1 (f1 integer,f2 integer, unique index(f1)) +partition by range(f1 div 2) +subpartition by hash(f1) subpartitions 2 +(partition partb values less than (2), +partition parte values less than (4), +partition partf values less than (10000)); +insert into t1 values(10,1); +select * from t1 where f1 = 10; +f1 f2 +10 1 +drop table t1; diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index 4156b351281..8bdb9a724d7 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -155,11 +155,11 @@ Pos Instruction 0 stmt 9 "drop temporary table if exists sudoku..." 1 stmt 1 "create temporary table sudoku_work ( ..." 2 stmt 1 "create temporary table sudoku_schedul..." -3 stmt 94 "call sudoku_init(" +3 stmt 95 "call sudoku_init(" 4 jump_if_not 7(8) p_naive@0 5 stmt 4 "update sudoku_work set cnt = 0 where ..." 6 jump 8 -7 stmt 94 "call sudoku_count(" +7 stmt 95 "call sudoku_count(" 8 stmt 6 "insert into sudoku_schedule (row,col)..." 9 set v_scounter@2 0 10 set v_i@3 1 diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index c062aec5a4a..916e63bc7cb 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -33,7 +33,6 @@ rpl_until : Unstable test case, bug#15886 sp-goto : GOTO is currently is disabled - will be fixed in the future subselect : Bug#15706 (ps mode) [PATCH PENDING] rpl_ndb_log : result not deterministic -sp-code : Bug #17360 binlog_row_mix_innodb_myisam : Bug #17386 binlog_row_insert_select : Bug #17385 rpl_row_basic_2myisam : Bug #17385 diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 301c1971c91..fd7e3bf7b70 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -353,3 +353,30 @@ insert into t1 values (10,1); drop table t1; +# +# Bug#16901 Partitions: crash, SELECT, column of part. +# function=first column of primary key +# +create table t1 (f1 integer,f2 integer, f3 varchar(10), primary key(f1,f2)) +partition by range(f1) subpartition by hash(f2) subpartitions 2 +(partition p1 values less than (0), + partition p2 values less than (2), + partition p3 values less than (2147483647)); + +insert into t1 values(10,10,'10'); +insert into t1 values(2,2,'2'); +select * from t1 where f1 = 2; +drop table t1; + +# +# Bug #16907 Partitions: crash, SELECT goes into last partition, UNIQUE INDEX +# +create table t1 (f1 integer,f2 integer, unique index(f1)) +partition by range(f1 div 2) +subpartition by hash(f1) subpartitions 2 +(partition partb values less than (2), +partition parte values less than (4), +partition partf values less than (10000)); +insert into t1 values(10,1); +select * from t1 where f1 = 10; +drop table t1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 1b1b16f4ae4..16fa0052214 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2198,6 +2198,7 @@ int ha_ndbcluster::full_table_scan(byte *buf) int res; NdbScanOperation *op; NdbTransaction *trans= m_active_trans; + part_id_range part_spec; DBUG_ENTER("full_table_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); @@ -2209,6 +2210,35 @@ int ha_ndbcluster::full_table_scan(byte *buf) op->readTuples(lm, 0, parallelism)) ERR_RETURN(trans->getNdbError()); m_active_cursor= op; + + if (m_use_partition_function) + { + part_spec.start_part= 0; + part_spec.end_part= get_tot_partitions(m_part_info) - 1; + prune_partition_set(table, &part_spec); + DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u", + part_spec.start_part, part_spec.end_part)); + /* + If partition pruning has found no partition in set + we can return HA_ERR_END_OF_FILE + If partition pruning has found exactly one partition in set + we can optimize scan to run towards that partition only. + */ + if (part_spec.start_part > part_spec.end_part) + { + DBUG_RETURN(HA_ERR_END_OF_FILE); + } + else if (part_spec.start_part == part_spec.end_part) + { + /* + Only one partition is required to scan, if sorted is required we + don't need it any more since output from one ordered partitioned + index is always sorted. + */ + m_active_cursor->setPartitionId(part_spec.start_part); + } + } + if (generate_scan_filter(m_cond_stack, op)) DBUG_RETURN(ndb_err(trans)); if ((res= define_read_attrs(buf, op))) @@ -3012,6 +3042,14 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, if (m_use_partition_function) { get_partition_set(table, buf, active_index, start_key, &part_spec); + DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u", + part_spec.start_part, part_spec.end_part)); + /* + If partition pruning has found no partition in set + we can return HA_ERR_END_OF_FILE + If partition pruning has found exactly one partition in set + we can optimize scan to run towards that partition only. + */ if (part_spec.start_part > part_spec.end_part) { DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -3026,6 +3064,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, sorted= FALSE; } } + m_write_op= FALSE; switch (type){ case PRIMARY_KEY_ORDERED_INDEX: @@ -7003,6 +7042,12 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, get_partition_set(table, curr, active_index, &multi_range_curr->start_key, &part_spec); + DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u", + part_spec.start_part, part_spec.end_part)); + /* + If partition pruning has found no partition in set + we can skip this scan + */ if (part_spec.start_part > part_spec.end_part) { /* diff --git a/sql/handler.h b/sql/handler.h index 55af6cf4da6..b8852d35e66 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1126,6 +1126,7 @@ char *generate_partition_syntax(partition_info *part_info, uint *buf_length, bool use_sql_alloc, bool write_all); bool partition_key_modified(TABLE *table, List<Item> &fields); +void prune_partition_set(const TABLE *table, part_id_range *part_spec); void get_partition_set(const TABLE *table, byte *buf, const uint index, const key_range *key_spec, part_id_range *part_spec); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 290d512198f..71fbbcd2426 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3605,7 +3605,52 @@ void get_full_part_id_from_key(const TABLE *table, byte *buf, part_spec->start_part++; DBUG_VOID_RETURN; } - + +/* + Prune the set of partitions to use in query + + SYNOPSIS + prune_partition_set() + table The table object + out:part_spec Contains start part, end part + + DESCRIPTION + This function is called to prune the range of partitions to scan by + checking the used_partitions bitmap. + If start_part > end_part at return it means no partition needs to be + scanned. If start_part == end_part it always means a single partition + needs to be scanned. + + RETURN VALUE + part_spec +*/ +void prune_partition_set(const TABLE *table, part_id_range *part_spec) +{ + int last_partition= -1; + uint i; + partition_info *part_info= table->part_info; + + DBUG_ENTER("prune_partition_set"); + for (i= part_spec->start_part; i <= part_spec->end_part; i++) + { + if (bitmap_is_set(&(part_info->used_partitions), i)) + { + DBUG_PRINT("info", ("Partition %d is set", i)); + if (last_partition == -1) + /* First partition found in set and pruned bitmap */ + part_spec->start_part= i; + last_partition= i; + } + } + if (last_partition == -1) + /* No partition found in pruned bitmap */ + part_spec->start_part= part_spec->end_part + 1; + else //if (last_partition != -1) + part_spec->end_part= last_partition; + + DBUG_VOID_RETURN; +} + /* Get the set of partitions to use in query. @@ -3669,6 +3714,10 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index, is needed. */ get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec); + /* + Check if range can be adjusted by looking in used_partitions + */ + prune_partition_set(table, part_spec); DBUG_VOID_RETURN; } else if (is_sub_partitioned(part_info)) @@ -3711,6 +3760,10 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index, */ get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec); clear_indicator_in_key_fields(key_info); + /* + Check if range can be adjusted by looking in used_partitions + */ + prune_partition_set(table, part_spec); DBUG_VOID_RETURN; } else if (is_sub_partitioned(part_info)) @@ -3754,7 +3807,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index, subpartitions. This is a range without holes. */ DBUG_ASSERT(sub_part == no_parts); - part_spec->start_part= part_part * part_info->no_parts; + part_spec->start_part= part_part * part_info->no_subparts; part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1; } else @@ -3770,10 +3823,13 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index, } if (found_part_field) clear_indicator_in_key_fields(key_info); + /* + Check if range can be adjusted by looking in used_partitions + */ + prune_partition_set(table, part_spec); DBUG_VOID_RETURN; } - /* If the table is partitioned we will read the partition info into the .frm file here. @@ -6009,7 +6065,10 @@ static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter) field->store(part_iter->field_vals.start, FALSE); part_iter->field_vals.start++; longlong dummy; - if (!part_iter->part_info->get_partition_id(part_iter->part_info, + if (is_sub_partitioned(part_iter->part_info) && + !part_iter->part_info->get_part_partition_id(part_iter->part_info, + &part_id, &dummy) || + !part_iter->part_info->get_partition_id(part_iter->part_info, &part_id, &dummy)) return part_id; } |