summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-03-18 08:44:24 +0100
committerSergei Golubchik <sergii@pisem.net>2013-03-18 08:44:24 +0100
commit8f607aae127439e132dae00b2750727162f4d564 (patch)
tree2a470ac1ca3ad8c0f9e782d9ed0edcaadf112538
parent3827d70a0edb9b88f30dd64a2d7ee2853524dd4e (diff)
downloadmariadb-git-8f607aae127439e132dae00b2750727162f4d564.tar.gz
MDEV-4283 Assertion `scale <= precision' fails in strings/decimal.c
with decimals=NOT_FIXED_DEC it is possible to have 'decimals' larger than 'max_length', it's not an error for temporal functions. But when Item_func_numhybrid converts the value to DECIMAL_RESULT, it must limit 'decimals' to be a valid scale of a decimal number.
-rw-r--r--mysql-test/r/temporal_scale_4283.result12
-rw-r--r--mysql-test/t/temporal_scale_4283.test13
-rw-r--r--sql/item_func.cc4
-rw-r--r--sql/item_func.h7
4 files changed, 35 insertions, 1 deletions
diff --git a/mysql-test/r/temporal_scale_4283.result b/mysql-test/r/temporal_scale_4283.result
new file mode 100644
index 00000000000..685a6192a97
--- /dev/null
+++ b/mysql-test/r/temporal_scale_4283.result
@@ -0,0 +1,12 @@
+create table t1 (a int);
+insert into t1 values (4),(8);
+select distinct 100 mod timestampadd( week, a, '2002-05-20' ) from t1;
+100 mod timestampadd( week, a, '2002-05-20' )
+100
+drop table t1;
+create table t1 (i int);
+insert into t1 values (2),(4);
+select distinct convert_tz( '2001-03-21', 'utc', 'met' ) mod i from t1;
+convert_tz( '2001-03-21', 'utc', 'met' ) mod i
+0
+drop table t1;
diff --git a/mysql-test/t/temporal_scale_4283.test b/mysql-test/t/temporal_scale_4283.test
new file mode 100644
index 00000000000..d79ca7caa54
--- /dev/null
+++ b/mysql-test/t/temporal_scale_4283.test
@@ -0,0 +1,13 @@
+#
+# MDEV-4283 Assertion `scale <= precision' fails in strings/decimal.c
+#
+create table t1 (a int);
+insert into t1 values (4),(8);
+select distinct 100 mod timestampadd( week, a, '2002-05-20' ) from t1;
+drop table t1;
+
+create table t1 (i int);
+insert into t1 values (2),(4);
+select distinct convert_tz( '2001-03-21', 'utc', 'met' ) mod i from t1;
+drop table t1;
+
diff --git a/sql/item_func.cc b/sql/item_func.cc
index f3a5c08d621..120e3d73a34 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -742,13 +742,14 @@ void Item_num_op::find_num_type(void)
{
hybrid_type= DECIMAL_RESULT;
result_precision();
+ fix_decimals();
}
else
{
DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
- decimals= 0;
hybrid_type=INT_RESULT;
result_precision();
+ decimals= 0;
}
DBUG_PRINT("info", ("Type: %s",
(hybrid_type == REAL_RESULT ? "REAL_RESULT" :
@@ -1492,6 +1493,7 @@ void Item_func_div::fix_length_and_dec()
break;
case DECIMAL_RESULT:
result_precision();
+ fix_decimals();
break;
case STRING_RESULT:
case ROW_RESULT:
diff --git a/sql/item_func.h b/sql/item_func.h
index 2db8ab76ffe..6cd036920f8 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -348,6 +348,13 @@ public:
void fix_num_length_and_dec();
virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */
+ inline void fix_decimals()
+ {
+ DBUG_ASSERT(result_type() == DECIMAL_RESULT);
+ if (decimals == NOT_FIXED_DEC)
+ set_if_smaller(decimals, max_length - 1);
+ }
+
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);