summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <kaa@polly.local>2006-10-11 14:16:30 +0400
committerunknown <kaa@polly.local>2006-10-11 14:16:30 +0400
commit78f47fbf3a600157c63a2dccee865b07d3a94b1c (patch)
treeede2b70c4281feecf1c13c6253569bac4ec72722 /sql
parent17bda20821e3d885456ec2fe80e87a4ca5a5c25e (diff)
parent634d3ff2c658902fa3ed4eb0f988a79564cfe94e (diff)
downloadmariadb-git-78f47fbf3a600157c63a2dccee865b07d3a94b1c.tar.gz
Merge polly.local:/tmp/maint/bug11655/my41-bug11655
into polly.local:/tmp/maint/bug11655/my50-bug11655 sql/time.cc: Auto merged include/my_time.h: Manually merged mysql-test/r/func_sapdb.result: Manually merged mysql-test/r/func_time.result: Manually merged mysql-test/t/func_time.test: Manually merged sql-common/my_time.c: Manually merged sql/field.cc: Manually merged sql/item_timefunc.cc: Manually merged
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc35
-rw-r--r--sql/item_timefunc.cc226
-rw-r--r--sql/time.cc6
3 files changed, 201 insertions, 66 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 98de224f900..1d7b6980cb4 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4759,9 +4759,10 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
{
TIME ltime;
long tmp;
- int error;
+ int error= 0;
+ int warning;
- if (str_to_time(from, len, &ltime, &error))
+ if (str_to_time(from, len, &ltime, &warning))
{
tmp=0L;
error= 2;
@@ -4770,29 +4771,27 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
}
else
{
- if (error)
+ if (warning & MYSQL_TIME_WARN_TRUNCATED)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_TIME, 1);
-
- if (ltime.month)
- ltime.day=0;
- tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
- if (tmp > 8385959)
+ if (warning & MYSQL_TIME_WARN_OUT_OF_RANGE)
{
- tmp=8385959;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
from, len, MYSQL_TIMESTAMP_TIME, !error);
error= 1;
}
+ if (ltime.month)
+ ltime.day=0;
+ tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
if (error > 1)
error= 2;
}
if (ltime.neg)
tmp= -tmp;
- error |= Field_time::store((longlong) tmp, FALSE);
+ int3store(ptr,tmp);
return error;
}
@@ -4811,16 +4810,16 @@ int Field_time::store(double nr)
{
long tmp;
int error= 0;
- if (nr > 8385959.0)
+ if (nr > (double)TIME_MAX_VALUE)
{
- tmp=8385959L;
+ tmp= TIME_MAX_VALUE;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
error= 1;
}
- else if (nr < -8385959.0)
+ else if (nr < (double)-TIME_MAX_VALUE)
{
- tmp= -8385959L;
+ tmp= -TIME_MAX_VALUE;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME);
error= 1;
@@ -4848,17 +4847,17 @@ int Field_time::store(longlong nr, bool unsigned_val)
{
long tmp;
int error= 0;
- if (nr < (longlong) -8385959L && !unsigned_val)
+ if (nr < (longlong) -TIME_MAX_VALUE && !unsigned_val)
{
- tmp= -8385959L;
+ tmp= -TIME_MAX_VALUE;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr,
MYSQL_TIMESTAMP_TIME, 1);
error= 1;
}
- else if (nr > (longlong) 8385959 || nr < 0 && unsigned_val)
+ else if (nr > (longlong) TIME_MAX_VALUE || nr < 0 && unsigned_val)
{
- tmp=8385959L;
+ tmp= TIME_MAX_VALUE;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE, nr,
MYSQL_TIMESTAMP_TIME, 1);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 9e1962835c8..e320275f53d 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -96,6 +96,124 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
/*
+ Wrapper over make_datetime() with validation of the input TIME value
+
+ NOTE
+ see make_datetime() for more information
+
+ RETURN
+ 1 if there was an error during converion
+ 0 otherwise
+*/
+
+static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime,
+ String *str)
+{
+ int warning= 0;
+ bool rc;
+
+ if (make_datetime(format, ltime, str))
+ return 1;
+ if (check_time_range(ltime, &warning))
+ return 1;
+ if (!warning)
+ return 0;
+
+ make_truncated_value_warning(current_thd, str->ptr(), str->length(),
+ MYSQL_TIMESTAMP_TIME);
+ return make_datetime(format, ltime, str);
+}
+
+
+/*
+ Wrapper over make_time() with validation of the input TIME value
+
+ NOTE
+ see make_time() for more info
+
+ RETURN
+ 1 if there was an error during conversion
+ 0 otherwise
+*/
+
+static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
+ TIME *l_time, String *str)
+{
+ int warning= 0;
+ make_time(format, l_time, str);
+ if (check_time_range(l_time, &warning))
+ return 1;
+ if (warning)
+ {
+ make_truncated_value_warning(current_thd, str->ptr(), str->length(),
+ MYSQL_TIMESTAMP_TIME);
+ make_time(format, l_time, str);
+ }
+
+ return 0;
+}
+
+
+/*
+ Convert seconds to TIME value with overflow checking
+
+ SYNOPSIS:
+ sec_to_time()
+ seconds number of seconds
+ unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise
+ ltime output TIME value
+
+ DESCRIPTION
+ If the 'seconds' argument is inside TIME data range, convert it to a
+ corresponding value.
+ Otherwise, truncate the resulting value to the nearest endpoint, and
+ produce a warning message.
+
+ RETURN
+ 1 if the value was truncated during conversion
+ 0 otherwise
+*/
+
+static bool sec_to_time(longlong seconds, bool unsigned_flag, TIME *ltime)
+{
+ uint sec;
+
+ bzero((char *)ltime, sizeof(*ltime));
+
+ if (seconds < 0)
+ {
+ if (unsigned_flag)
+ goto overflow;
+ ltime->neg= 1;
+ if (seconds < -3020399)
+ goto overflow;
+ seconds= -seconds;
+ }
+ else if (seconds > 3020399)
+ goto overflow;
+
+ sec= (uint) ((ulonglong) seconds % 3600);
+ ltime->hour= (uint) (seconds/3600);
+ ltime->minute= sec/60;
+ ltime->second= sec % 60;
+
+ return 0;
+
+overflow:
+ ltime->hour= TIME_MAX_HOUR;
+ ltime->minute= TIME_MAX_MINUTE;
+ ltime->second= TIME_MAX_SECOND;
+
+ char buf[22];
+ int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10)
+ - buf);
+ make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME);
+
+ return 1;
+}
+
+
+/*
Date formats corresponding to compound %r and %T conversion specifiers
Note: We should init at least first element of "positions" array
@@ -1570,8 +1688,6 @@ int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions)
String *Item_func_sec_to_time::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- longlong seconds=(longlong) args[0]->val_int();
- uint sec;
TIME ltime;
if ((null_value=args[0]->null_value) || str->alloc(19))
@@ -1580,19 +1696,8 @@ String *Item_func_sec_to_time::val_str(String *str)
return (String*) 0;
}
- ltime.neg= 0;
- if (seconds < 0)
- {
- seconds= -seconds;
- ltime.neg= 1;
- }
-
- sec= (uint) ((ulonglong) seconds % 3600);
- ltime.day= 0;
- ltime.hour= (uint) (seconds/3600);
- ltime.minute= sec/60;
- ltime.second= sec % 60;
-
+ sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, &ltime);
+
make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
}
@@ -1601,16 +1706,15 @@ String *Item_func_sec_to_time::val_str(String *str)
longlong Item_func_sec_to_time::val_int()
{
DBUG_ASSERT(fixed == 1);
- longlong seconds=args[0]->val_int();
- longlong sign=1;
+ TIME ltime;
+
if ((null_value=args[0]->null_value))
return 0;
- if (seconds < 0)
- {
- seconds= -seconds;
- sign= -1;
- }
- return sign*((seconds / 3600)*10000+((seconds/60) % 60)*100+ (seconds % 60));
+
+ sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, &ltime);
+
+ return (ltime.neg ? -1 : 1) *
+ ((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
}
@@ -2690,7 +2794,9 @@ String *Item_func_add_time::val_str(String *str)
}
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
-
+
+ bzero((char *)&l_time3, sizeof(l_time3));
+
l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
&seconds, &microseconds);
@@ -2719,9 +2825,9 @@ String *Item_func_add_time::val_str(String *str)
}
l_time3.hour+= days*24;
- if (!make_datetime(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
+ if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
+ TIME_MICROSECOND : TIME_ONLY,
+ &l_time3, str))
return str;
null_date:
@@ -2776,6 +2882,8 @@ String *Item_func_timediff::val_str(String *str)
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
+ bzero((char *)&l_time3, sizeof(l_time3));
+
l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign,
&seconds, &microseconds);
@@ -2789,9 +2897,9 @@ String *Item_func_timediff::val_str(String *str)
calc_time_from_sec(&l_time3, (long) seconds, microseconds);
- if (!make_datetime(l_time1.second_part || l_time2.second_part ?
- TIME_MICROSECOND : TIME_ONLY,
- &l_time3, str))
+ if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ?
+ TIME_MICROSECOND : TIME_ONLY,
+ &l_time3, str))
return str;
null_date:
@@ -2809,29 +2917,57 @@ String *Item_func_maketime::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
+ bool overflow= 0;
- long hour= (long) args[0]->val_int();
- long minute= (long) args[1]->val_int();
- long second= (long) args[2]->val_int();
+ longlong hour= args[0]->val_int();
+ longlong minute= args[1]->val_int();
+ longlong second= args[2]->val_int();
if ((null_value=(args[0]->null_value ||
- args[1]->null_value ||
- args[2]->null_value ||
- minute > 59 || minute < 0 ||
- second > 59 || second < 0 ||
- str->alloc(19))))
+ args[1]->null_value ||
+ args[2]->null_value ||
+ minute < 0 || minute > 59 ||
+ second < 0 || second > 59 ||
+ str->alloc(19))))
return 0;
+ bzero((char *)&ltime, sizeof(ltime));
ltime.neg= 0;
+
+ /* Check for integer overflows */
if (hour < 0)
{
- ltime.neg= 1;
- hour= -hour;
+ if (args[0]->unsigned_flag)
+ overflow= 1;
+ else
+ ltime.neg= 1;
+ }
+ if (-hour > UINT_MAX || hour > UINT_MAX)
+ overflow= 1;
+
+ if (!overflow)
+ {
+ ltime.hour= (uint) ((hour < 0 ? -hour : hour));
+ ltime.minute= (uint) minute;
+ ltime.second= (uint) second;
+ }
+ else
+ {
+ ltime.hour= TIME_MAX_HOUR;
+ ltime.minute= TIME_MAX_MINUTE;
+ ltime.second= TIME_MAX_SECOND;
+ char buf[28];
+ char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
+ int len = (int)(ptr - buf) +
+ my_sprintf(ptr, (ptr, ":%02u:%02u", (uint)minute, (uint)second));
+ make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME);
+ }
+
+ if (make_time_with_warn((DATE_TIME_FORMAT *) 0, &ltime, str))
+ {
+ null_value= 1;
+ return 0;
}
- ltime.hour= (ulong) hour;
- ltime.minute= (ulong) minute;
- ltime.second= (ulong) second;
- make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
}
@@ -3172,7 +3308,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
goto null_date;
null_value= 0;
- bzero((char*) ltime, sizeof(ltime));
+ bzero((char*) ltime, sizeof(*ltime));
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
diff --git a/sql/time.cc b/sql/time.cc
index 5069031081d..c71ea08fb77 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -254,9 +254,9 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *in_dst_time_gap)
bool
str_to_time_with_warn(const char *str, uint length, TIME *l_time)
{
- int was_cut;
- bool ret_val= str_to_time(str, length, l_time, &was_cut);
- if (was_cut)
+ int warning;
+ bool ret_val= str_to_time(str, length, l_time, &warning);
+ if (ret_val || warning)
make_truncated_value_warning(current_thd, str, length,
MYSQL_TIMESTAMP_TIME, NullS);
return ret_val;