From f257aac8148626c81fb3447eeb2bb85d9756735e Mon Sep 17 00:00:00 2001
From: Mattias Jonsson <mattias.jonsson@sun.com>
Date: Sun, 28 Dec 2008 12:33:49 +0100
Subject: [PATCH] Bug#40972: some sql execution lead the whole databse crashing

Problem was an errornous date that lead to end partition
was before the start, leading to a crash.

Solution was to check greater or equal instead of only
equal between start and end partition.

NOTE: partitioning pruning handles incorrect dates
differently than index lookup, which can give different
results in a partitioned table versus a non partitioned
table for queries having 'bad' dates in the where clause.

mysql-test/r/partition_pruning.result:
  Bug#40972: some sql execution lead the whole databse crashing

  Updated result file
mysql-test/t/partition_pruning.test:
  Bug#40972: some sql execution lead the whole databse crashing

  Added test.
sql/sql_partition.cc:
  Bug#40972: some sql execution lead the whole databse crashing

  There can be cases where the start/cur partition is greater
  than the end partition, so it must not continue, since that
  can lead to a crash.
---
 mysql-test/r/partition_pruning.result | 12 ++++++++++++
 mysql-test/t/partition_pruning.test   | 16 ++++++++++++++++
 sql/sql_partition.cc                  |  4 ++--
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result
index b153ad9ad4..26ddc92e97 100644
--- a/mysql-test/r/partition_pruning.result
+++ b/mysql-test/r/partition_pruning.result
@@ -1,4 +1,16 @@
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+CREATE TABLE t1
+(a INT NOT NULL AUTO_INCREMENT,
+b DATETIME,
+PRIMARY KEY (a,b),
+KEY (b))
+PARTITION BY RANGE (to_days(b))
+(PARTITION p0 VALUES LESS THAN (733681) COMMENT = 'LESS THAN 2008-10-01',
+PARTITION p1 VALUES LESS THAN (733712) COMMENT = 'LESS THAN 2008-11-01',
+PARTITION pX VALUES LESS THAN MAXVALUE);
+SELECT a,b FROM t1 WHERE b >= '2008-12-01' AND b < '2009-12-00';
+a	b
+DROP TABLE t1;
 create table t1 ( a int not null) partition by hash(a) partitions 2;
 insert into t1 values (1),(2),(3);
 explain select * from t1 where a=5 and a=6;
diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test
index 31008d2b01..ad102062ef 100644
--- a/mysql-test/t/partition_pruning.test
+++ b/mysql-test/t/partition_pruning.test
@@ -8,6 +8,22 @@
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
 --enable_warnings
 
+#
+# Bug#40972: some sql execution lead the whole database crashing
+#
+# Setup so the start is at partition pX and end is at p1
+# Pruning does handle 'bad' dates differently.
+CREATE TABLE t1
+(a INT NOT NULL AUTO_INCREMENT,
+ b DATETIME,
+ PRIMARY KEY (a,b),
+ KEY (b))
+PARTITION BY RANGE (to_days(b))
+(PARTITION p0 VALUES LESS THAN (733681) COMMENT = 'LESS THAN 2008-10-01',
+ PARTITION p1 VALUES LESS THAN (733712) COMMENT = 'LESS THAN 2008-11-01',
+ PARTITION pX VALUES LESS THAN MAXVALUE);
+SELECT a,b FROM t1 WHERE b >= '2008-12-01' AND b < '2009-12-00';
+DROP TABLE t1;
 
 # Check if we can infer from condition on partition fields that 
 # no records will match.
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index c1df5552eb..9096a2b91e 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -6760,7 +6760,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
     store_key_image_to_rec(field, max_value, field_len);
     bool include_endp= !test(flags & NEAR_MAX);
     part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
-    if (part_iter->part_nums.start == part_iter->part_nums.end &&
+    if (part_iter->part_nums.start >= part_iter->part_nums.end &&
         !part_iter->ret_null_part)
       return 0; /* No partitions */
   }
@@ -6938,7 +6938,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
 
 uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
 {
-  if (part_iter->part_nums.cur == part_iter->part_nums.end)
+  if (part_iter->part_nums.cur >= part_iter->part_nums.end)
   {
     part_iter->part_nums.cur= part_iter->part_nums.start;
     return NOT_A_PARTITION_ID;
-- 
2.30.9