summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/main/partition_range.result44
-rw-r--r--mysql-test/main/partition_range.test46
-rw-r--r--sql/my_decimal.cc4
-rw-r--r--sql/my_decimal.h2
-rw-r--r--sql/sql_partition.cc26
5 files changed, 116 insertions, 6 deletions
diff --git a/mysql-test/main/partition_range.result b/mysql-test/main/partition_range.result
index 00171e3e0bd..2c72d9f1865 100644
--- a/mysql-test/main/partition_range.result
+++ b/mysql-test/main/partition_range.result
@@ -1009,3 +1009,47 @@ select * from t1 partition (p1);
d
2000-01-01 00:00:01.000000
DROP TABLE t1, t2;
+#
+# MDEV-21195 INSERT chooses wrong partition for RANGE partitioning by DECIMAL column
+#
+create or replace table t (
+d decimal(2,1)) partition by range (d)
+(partition p1 values less than (10));
+insert into t values (9.9);
+create or replace table t (
+d decimal(2,1)) partition by range (d)
+(partition p1 values less than (10),
+partition p2 values less than (20));
+insert into t values (9.9);
+select * from t partition (p1);
+d
+9.9
+select * from t partition (p2);
+d
+create or replace table t (
+d decimal(2,1)) partition by range (d)
+(partition p1 values less than (-3));
+insert into t values (-3.3);
+create or replace table t (
+d decimal(2,1)) partition by range (d+1)
+(partition p1 values less than (10),
+partition p2 values less than (20));
+insert into t values (8.9);
+select * from t partition (p1);
+d
+8.9
+select * from t partition (p2);
+d
+set time_zone='+00:00';
+create or replace table t (
+d timestamp(1)) partition by range (unix_timestamp(d))
+(partition p1 values less than (1577836800),
+partition p2 values less than (2000000000));
+insert into t values (from_unixtime(1577836799.9));
+select * from t partition (p1);
+d
+2019-12-31 23:59:59.9
+select * from t partition (p2);
+d
+set time_zone=default;
+drop table t;
diff --git a/mysql-test/main/partition_range.test b/mysql-test/main/partition_range.test
index 628602ffa25..abba4c5f374 100644
--- a/mysql-test/main/partition_range.test
+++ b/mysql-test/main/partition_range.test
@@ -999,3 +999,49 @@ select * from t1 partition (p0);
select * from t1 partition (p1);
DROP TABLE t1, t2;
+
+--echo #
+--echo # MDEV-21195 INSERT chooses wrong partition for RANGE partitioning by DECIMAL column
+--echo #
+create or replace table t (
+ d decimal(2,1)) partition by range (d)
+ (partition p1 values less than (10));
+
+insert into t values (9.9);
+
+create or replace table t (
+ d decimal(2,1)) partition by range (d)
+ (partition p1 values less than (10),
+ partition p2 values less than (20));
+
+insert into t values (9.9);
+select * from t partition (p1);
+select * from t partition (p2);
+
+create or replace table t (
+ d decimal(2,1)) partition by range (d)
+ (partition p1 values less than (-3));
+
+insert into t values (-3.3);
+
+create or replace table t (
+ d decimal(2,1)) partition by range (d+1)
+ (partition p1 values less than (10),
+ partition p2 values less than (20));
+
+insert into t values (8.9);
+select * from t partition (p1);
+select * from t partition (p2);
+
+set time_zone='+00:00';
+create or replace table t (
+ d timestamp(1)) partition by range (unix_timestamp(d))
+ (partition p1 values less than (1577836800),
+ partition p2 values less than (2000000000));
+
+insert into t values (from_unixtime(1577836799.9));
+select * from t partition (p1);
+select * from t partition (p2);
+
+set time_zone=default;
+drop table t;
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 01fad3dde37..8acb46b9ef2 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -345,12 +345,12 @@ void my_decimal_trim(ulonglong *precision, uint *scale)
*/
int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag,
- longlong *l)
+ longlong *l, decimal_round_mode round_type)
{
int res;
my_decimal rounded;
/* decimal_round can return only E_DEC_TRUNCATED */
- decimal_round(d, &rounded, 0, HALF_UP);
+ decimal_round(d, &rounded, 0, round_type);
res= (unsigned_flag ?
decimal2ulonglong(&rounded, (ulonglong *) l) :
decimal2longlong(&rounded, l));
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index 6d6bb258293..b409a87bdd4 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -348,7 +348,7 @@ my_decimal *seconds2my_decimal(bool sign, ulonglong sec, ulong microsec,
(TIME)->second_part, (DECIMAL))
int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag,
- longlong *l);
+ longlong *l, decimal_round_mode round_type= HALF_UP);
inline
int my_decimal2double(uint, const decimal_t *d, double *result)
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 00a78ce3199..febd88c4b9b 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2840,14 +2840,34 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields)
static inline int part_val_int(Item *item_expr, longlong *result)
{
- *result= item_expr->val_int();
+ switch (item_expr->cmp_type())
+ {
+ case DECIMAL_RESULT:
+ {
+ my_decimal buf;
+ my_decimal *val= item_expr->val_decimal(&buf);
+ if (val && my_decimal2int(E_DEC_FATAL_ERROR, val, item_expr->unsigned_flag,
+ result, FLOOR) != E_DEC_OK)
+ return true;
+ break;
+ }
+ case INT_RESULT:
+ *result= item_expr->val_int();
+ break;
+ case STRING_RESULT:
+ case REAL_RESULT:
+ case ROW_RESULT:
+ case TIME_RESULT:
+ DBUG_ASSERT(0);
+ break;
+ }
if (item_expr->null_value)
{
if (unlikely(current_thd->is_error()))
- return TRUE;
+ return true;
*result= LONGLONG_MIN;
}
- return FALSE;
+ return false;
}