From e7db9d454537e9d6fa94b57070995cd9b8022190 Mon Sep 17 00:00:00 2001
From: "sergefp@mysql.com" <>
Date: Mon, 24 Jul 2006 21:58:11 +0400
Subject: [PATCH] BUG#20257: Fix partition pruning for BIGINT UNSIGNED:  - Fix
 problems in the "Interval walking" partition interval analyzer.

---
 mysql-test/r/partition_pruning.result | 79 +++++++++++++++++++++++++++
 mysql-test/t/partition_pruning.test   | 66 ++++++++++++++++++++++
 sql/sql_partition.cc                  | 16 ++++--
 3 files changed, 157 insertions(+), 4 deletions(-)

diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result
index 3b08f522129..5e510f5d737 100644
--- a/mysql-test/r/partition_pruning.result
+++ b/mysql-test/r/partition_pruning.result
@@ -704,3 +704,82 @@ id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
 2	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
 NULL	UNION RESULT	<union1,2>	NULL	ALL	NULL	NULL	NULL	NULL	NULL	
 drop table t1;
+create table t1 (a bigint unsigned not null) partition by range(a) (
+partition p0 values less than (10),
+partition p1 values less than (100),
+partition p2 values less than (1000),
+partition p3 values less than (18446744073709551000),
+partition p4 values less than (18446744073709551614)
+);
+insert into t1 values (5),(15),(105),(1005);
+insert into t1 values (18446744073709551000+1);
+insert into t1 values (18446744073709551614-1);
+explain partitions select * from t1 where a < 10;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	system	NULL	NULL	NULL	NULL	1	
+explain partitions select * from t1 
+where a >= 18446744073709551000-1 and a <= 18446744073709551000+1;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p3,p4	ALL	NULL	NULL	NULL	NULL	3	Using where
+explain partitions select * from t1 
+where a between 18446744073709551001 and 18446744073709551002;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p4	ALL	NULL	NULL	NULL	NULL	2	Using where
+explain partitions select * from t1 where a = 18446744073709551000;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p4	ALL	NULL	NULL	NULL	NULL	2	Using where
+explain partitions select * from t1 where a = 18446744073709551613;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p4	ALL	NULL	NULL	NULL	NULL	2	Using where
+explain partitions select * from t1 where a = 18446744073709551614;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+drop table t1;
+create table t1 (a int) 
+partition by range((a & 0xFF) << 56) (
+partition p0 values less than (0x40 << 56),
+partition p1 values less than (0x80 << 56),
+partition p2 values less than (0xFF << 56)
+);
+insert into t1 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE);
+explain partitions select * from t1 where a=0;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p0	ALL	NULL	NULL	NULL	NULL	2	Using where
+explain partitions select * from t1 where a=0xFE;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p2	ALL	NULL	NULL	NULL	NULL	2	Using where
+explain partitions select * from t1 where a>0xFE and a<= 0xFF;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+drop table t1;
+create table t1(a bigint unsigned not null) partition by range(a+0) (
+partition p1 values less than (10),
+partition p2 values less than (20),
+partition p3 values less than (2305561538531885056),
+partition p4 values less than (2305561538531950591)
+);
+insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1);
+insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1);
+explain partitions select * from t1 where 
+a >= 2305561538531885056-10 and a <= 2305561538531885056-8;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p3	ALL	NULL	NULL	NULL	NULL	4	Using where
+explain partitions select * from t1 where 
+a > 0xFFFFFFFFFFFFFFEC and a < 0xFFFFFFFFFFFFFFEE;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+explain partitions select * from t1 where a>=0 and a <= 0xFFFFFFFFFFFFFFFF;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p1,p2,p3,p4	ALL	NULL	NULL	NULL	NULL	8	Using where
+drop table t1;
+create table t1 (a bigint) partition by range(a+0) (
+partition p1 values less than (-1000),
+partition p2 values less than (-10),
+partition p3 values less than (10),
+partition p4 values less than (1000)
+);
+insert into t1 values (-15),(-5),(5),(15),(-15),(-5),(5),(15);
+explain partitions select * from t1 where a>-2 and a <=0;
+id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	p3	ALL	NULL	NULL	NULL	NULL	4	Using where
+drop table t1;
diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test
index 8fdfca15eef..752ba8875c2 100644
--- a/mysql-test/t/partition_pruning.test
+++ b/mysql-test/t/partition_pruning.test
@@ -597,3 +597,69 @@ explain partitions select 1 from t1 union all select 2;
 drop table t1;
 
 
+# BUG#20257: partition pruning test coverage for BIGINT UNSIGNED
+create table t1 (a bigint unsigned not null) partition by range(a) (
+  partition p0 values less than (10),
+  partition p1 values less than (100),
+  partition p2 values less than (1000),
+  partition p3 values less than (18446744073709551000),
+  partition p4 values less than (18446744073709551614)
+);
+insert into t1 values (5),(15),(105),(1005);
+insert into t1 values (18446744073709551000+1);
+insert into t1 values (18446744073709551614-1);
+
+explain partitions select * from t1 where a < 10;
+explain partitions select * from t1 
+  where a >= 18446744073709551000-1 and a <= 18446744073709551000+1;
+
+explain partitions select * from t1 
+  where a between 18446744073709551001 and 18446744073709551002;
+
+explain partitions select * from t1 where a = 18446744073709551000;
+explain partitions select * from t1 where a = 18446744073709551613;
+explain partitions select * from t1 where a = 18446744073709551614;
+drop table t1;
+
+create table t1 (a int) 
+  partition by range((a & 0xFF) << 56) (
+  partition p0 values less than (0x40 << 56),
+  partition p1 values less than (0x80 << 56),
+  partition p2 values less than (0xFF << 56)
+);
+
+insert into t1 values (0x20), (0x20), (0x41), (0x41), (0xFE), (0xFE); 
+explain partitions select * from t1 where a=0;
+explain partitions select * from t1 where a=0xFE;
+explain partitions select * from t1 where a>0xFE and a<= 0xFF;
+drop table t1;
+
+create table t1(a bigint unsigned not null) partition by range(a+0) (
+  partition p1 values less than (10),
+  partition p2 values less than (20),
+  partition p3 values less than (2305561538531885056),
+  partition p4 values less than (2305561538531950591)
+);
+
+insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1);
+insert into t1 values (9),(19),(0xFFFF0000FFFF000-1), (0xFFFF0000FFFFFFF-1);
+
+explain partitions select * from t1 where 
+  a >= 2305561538531885056-10 and a <= 2305561538531885056-8;
+
+explain partitions select * from t1 where 
+  a > 0xFFFFFFFFFFFFFFEC and a < 0xFFFFFFFFFFFFFFEE;
+
+explain partitions select * from t1 where a>=0 and a <= 0xFFFFFFFFFFFFFFFF;
+drop table t1;
+
+create table t1 (a bigint) partition by range(a+0) (
+  partition p1 values less than (-1000),
+  partition p2 values less than (-10),
+  partition p3 values less than (10),
+  partition p4 values less than (1000)
+);
+insert into t1 values (-15),(-5),(5),(15),(-15),(-5),(5),(15);
+explain partitions select * from t1 where a>-2 and a <=0;
+drop table t1;
+
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 44c0b8ffcd9..8350d0b8ffd 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -6566,10 +6566,19 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
   
   store_key_image_to_rec(field, max_value, len);
   b= field->val_int();
+  
+  /* 
+    Handle a special case where the distance between interval bounds is 
+    exactly 4G-1. This interval is too big for range walking, and if it is an
+    (x,y]-type interval then the following "b +=..." code will convert it to 
+    an empty interval by "wrapping around" a + 4G-1 + 1 = a. 
+  */
+  if ((ulonglong)b - (ulonglong)a == ~0ULL)
+    return -1;
 
   a += test(flags & NEAR_MIN);
   b += test(!(flags & NEAR_MAX));
-  uint n_values= b - a;
+  ulonglong n_values= b - a;
   
   if (n_values > total_parts || n_values > MAX_RANGE_TO_WALK)
     return -1;
@@ -6673,7 +6682,8 @@ static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter)
   while (part_iter->field_vals.cur != part_iter->field_vals.end)
   {
     longlong dummy;
-    field->store(part_iter->field_vals.cur++, FALSE);
+    field->store(part_iter->field_vals.cur++,
+                 ((Field_num*)field)->unsigned_flag);
     if (part_iter->part_info->is_sub_partitioned() &&
         !part_iter->part_info->get_part_partition_id(part_iter->part_info,
                                                      &part_id, &dummy) ||
@@ -6681,8 +6691,6 @@ static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter)
                                                 &part_id, &dummy))
       return part_id;
   }
-  //psergey-todo: return partition(part_func(NULL)) here...
-  
   part_iter->field_vals.cur= part_iter->field_vals.start;
   return NOT_A_PARTITION_ID;
 }
-- 
2.30.9