summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/partition.result22
-rw-r--r--mysql-test/r/sp-code.result4
-rw-r--r--mysql-test/t/disabled.def1
-rw-r--r--mysql-test/t/partition.test27
-rw-r--r--sql/ha_ndbcluster.cc45
-rw-r--r--sql/handler.h1
-rw-r--r--sql/sql_partition.cc67
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;
}