diff options
-rw-r--r-- | mysql-test/r/cast.result | 4 | ||||
-rw-r--r-- | mysql-test/r/func_sapdb.result | 12 | ||||
-rw-r--r-- | mysql-test/t/func_sapdb.test | 6 | ||||
-rw-r--r-- | sql/item_create.cc | 4 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 322 | ||||
-rw-r--r-- | sql/item_timefunc.h | 82 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/protocol.cc | 13 | ||||
-rw-r--r-- | sql/sql_string.cc | 17 | ||||
-rw-r--r-- | sql/sql_string.h | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 9 | ||||
-rw-r--r-- | sql/time.cc | 1 |
12 files changed, 238 insertions, 236 deletions
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index a14ea4d61a6..5d185bee005 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -44,10 +44,10 @@ t1 CREATE TABLE `t1` ( drop table t1; select cast("2001-1-1" as date) = "2001-01-01"; cast("2001-1-1" as date) = "2001-01-01" -0 +1 select cast("2001-1-1" as datetime) = "2001-01-01 00:00:00"; cast("2001-1-1" as datetime) = "2001-01-01 00:00:00" -0 +1 select cast("1:2:3" as TIME) = "1:02:03"; cast("1:2:3" as TIME) = "1:02:03" 0 diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index 5c044d00726..e330c73727b 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -101,8 +101,8 @@ timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); timediff("1997-12-31 23:59:59.000001","23:59:59.000001") NULL -select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1"); -timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1") +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); +timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001") -00:00:00.000001 select maketime(10,11,12); maketime(10,11,12) @@ -122,6 +122,12 @@ NULL select timestamp("2001-12-01", "25:01:01"); timestamp("2001-12-01", "25:01:01") 2001-12-02 01:01:01 +select timestamp("2001-12-01 01:01:01.000100"); +timestamp("2001-12-01 01:01:01.000100") +2001-12-01 01:01:01.000100 +select timestamp("2001-12-01"); +timestamp("2001-12-01") +2001-12-01 00:00:00 select day("1997-12-31 23:59:59.000001"); day("1997-12-31 23:59:59.000001") 31 @@ -147,7 +153,7 @@ addtime(cast("23:59:59.999999" as time) , "1 1:1:1.000002") as f3, timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, maketime(10,11,12) as f6, -timestamp("2001-12-01", "01:01:01") as f7, +timestamp(cast("2001-12-01" as date), "01:01:01") as f7, date("1997-12-31 23:59:59.000001") as f8, time("1997-12-31 23:59:59.000001") as f9; describe t1; diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test index 05e1f20fe1e..afd84fe9630 100644 --- a/mysql-test/t/func_sapdb.test +++ b/mysql-test/t/func_sapdb.test @@ -51,7 +51,7 @@ select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); -select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1"); +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); select maketime(10,11,12); select maketime(25,11,12); @@ -61,6 +61,8 @@ select maketime(-25,11,12); select timestamp("2001-12-01", "01:01:01.999999"); select timestamp("2001-13-01", "01:01:01.000001"); select timestamp("2001-12-01", "25:01:01"); +select timestamp("2001-12-01 01:01:01.000100"); +select timestamp("2001-12-01"); select day("1997-12-31 23:59:59.000001"); select date("1997-12-31 23:59:59.000001"); select date("1997-13-31 23:59:59.000001"); @@ -75,7 +77,7 @@ select makedate(1997,1) as f1, timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, maketime(10,11,12) as f6, - timestamp("2001-12-01", "01:01:01") as f7, + timestamp(cast("2001-12-01" as date), "01:01:01") as f7, date("1997-12-31 23:59:59.000001") as f8, time("1997-12-31 23:59:59.000001") as f9; describe t1; diff --git a/sql/item_create.cc b/sql/item_create.cc index 402428d40cb..eaa27c1009d 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -709,12 +709,12 @@ Item *create_func_makedate(Item* a,Item* b) Item *create_func_addtime(Item* a,Item* b) { - return new Item_func_add_time(a, b, 0); + return new Item_func_add_time(a, b, 0, 0); } Item *create_func_subtime(Item* a,Item* b) { - return new Item_func_add_time(a, b, 1); + return new Item_func_add_time(a, b, 0, 1); } Item *create_func_timediff(Item* a,Item* b) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index fd2bca591a7..4fdb1b13d24 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -29,6 +29,8 @@ ** Todo: Move month and days to language files */ +#define MAX_DAY_NUMBER 3652424L + static String month_names[] = { String("January", &my_charset_latin1), @@ -55,10 +57,14 @@ static String day_names[] = String("Sunday", &my_charset_latin1) }; -enum date_time_format_types { TIME_ONLY= 0, TIME_MICROSECOND, - DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND}; +enum date_time_format_types +{ + TIME_ONLY= 0, TIME_MICROSECOND, + DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND +}; -typedef struct date_time_format { +typedef struct date_time_format +{ const char* format_str; uint length; }; @@ -73,6 +79,14 @@ static struct date_time_format date_time_formats[]= }; +/* + OPTIMIZATION TODO: + - Replace the switch with a function that should be called for each + date type. + - Remove sprintf and opencode the conversion, like we do in + Field_datetime. +*/ + String *make_datetime(String *str, TIME *ltime, enum date_time_format_types format) { @@ -898,8 +912,8 @@ String *Item_func_date_format::val_str(String *str) null_value=1; return 0; } - length= my_sprintf(intbuff, (intbuff,"%d",l_time.day)); - str->append(intbuff, length); + length= int10_to_str(l_time.day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); if (l_time.day >= 10 && l_time.day <= 19) str->append("th"); else @@ -921,45 +935,45 @@ String *Item_func_date_format::val_str(String *str) } break; case 'Y': - sprintf(intbuff,"%04d",l_time.year); - str->append(intbuff,4); + length= int10_to_str(l_time.year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); break; case 'y': - sprintf(intbuff,"%02d",l_time.year%100); - str->append(intbuff,2); + length= int10_to_str(l_time.year%100, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'm': - sprintf(intbuff,"%02d",l_time.month); - str->append(intbuff,2); + length= int10_to_str(l_time.month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'c': - sprintf(intbuff,"%d",l_time.month); - str->append(intbuff); + length= int10_to_str(l_time.month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'd': - sprintf(intbuff,"%02d",l_time.day); - str->append(intbuff,2); + length= int10_to_str(l_time.day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'e': - sprintf(intbuff,"%d",l_time.day); - str->append(intbuff); + length= int10_to_str(l_time.day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'f': - sprintf(intbuff,"%06ld",l_time.second_part); - str->append(intbuff); + length= int10_to_str(l_time.second_part, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 6, '0'); break; case 'H': - sprintf(intbuff,"%02d",l_time.hour); - str->append(intbuff,2); + length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'h': case 'I': - sprintf(intbuff,"%02d", (l_time.hour+11)%12+1); - str->append(intbuff,2); + length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'i': /* minutes */ - sprintf(intbuff,"%02d",l_time.minute); - str->append(intbuff,2); + length= int10_to_str(l_time.minute, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'j': if (date_or_time) @@ -967,52 +981,60 @@ String *Item_func_date_format::val_str(String *str) null_value=1; return 0; } - sprintf(intbuff,"%03d", - (int) (calc_daynr(l_time.year,l_time.month,l_time.day) - - calc_daynr(l_time.year,1,1)) + 1); - str->append(intbuff,3); + length= int10_to_str(calc_daynr(l_time.year,l_time.month,l_time.day) - + calc_daynr(l_time.year,1,1) + 1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 3, '0'); break; case 'k': - sprintf(intbuff,"%d",l_time.hour); - str->append(intbuff); + length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'l': - sprintf(intbuff,"%d", (l_time.hour+11)%12+1); - str->append(intbuff); + length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'p': str->append(l_time.hour < 12 ? "AM" : "PM",2); break; case 'r': - sprintf(intbuff,(l_time.hour < 12) ? "%02d:%02d:%02d AM" : - "%02d:%02d:%02d PM",(l_time.hour+11)%12+1,l_time.minute, - l_time.second); - str->append(intbuff); + length= my_sprintf(intbuff, + (intbuff, + (l_time.hour < 12) ? "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", + (l_time.hour+11)%12+1, + l_time.minute, + l_time.second)); + str->append(intbuff, length); break; case 'S': case 's': - sprintf(intbuff,"%02d",l_time.second); - str->append(intbuff); + length= int10_to_str(l_time.second, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'T': - sprintf(intbuff,"%02d:%02d:%02d", l_time.hour, l_time.minute, - l_time.second); - str->append(intbuff); + length= my_sprintf(intbuff, + (intbuff, + "%02d:%02d:%02d", + l_time.hour, + l_time.minute, + l_time.second)); + str->append(intbuff, length); break; case 'U': case 'u': { uint year; - sprintf(intbuff,"%02d",calc_week(&l_time, 0, (*ptr) == 'U', &year)); - str->append(intbuff,2); + length= int10_to_str(calc_week(&l_time, 0, (*ptr) == 'U', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); } break; case 'v': case 'V': { uint year; - sprintf(intbuff,"%02d",calc_week(&l_time, 1, (*ptr) == 'V', &year)); - str->append(intbuff,2); + length= int10_to_str(calc_week(&l_time, 1, (*ptr) == 'V', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); } break; case 'x': @@ -1020,14 +1042,15 @@ String *Item_func_date_format::val_str(String *str) { uint year; (void) calc_week(&l_time, 1, (*ptr) == 'X', &year); - sprintf(intbuff,"%04d",year); - str->append(intbuff,4); + length= int10_to_str(year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); } break; case 'w': weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1); - sprintf(intbuff,"%d",weekday); - str->append(intbuff,1); + length= int10_to_str(weekday, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; default: str->append(*ptr); @@ -1109,7 +1132,7 @@ void Item_date_add_interval::fix_length_and_dec() enum_field_types arg0_field_type; set_charset(default_charset()); maybe_null=1; - max_length=26*default_charset()->mbmaxlen; + max_length=26*MY_CHARSET_BIN_MB_MAXLEN; value.alloc(32); /* @@ -1197,13 +1220,13 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) ltime->hour=sec/3600; daynr= calc_daynr(ltime->year,ltime->month,1) + days; get_date_from_daynr(daynr,<ime->year,<ime->month,<ime->day); - if (daynr < 0 || daynr >= 3652424) // Day number from year 0 to 9999-12-31 + if (daynr < 0 || daynr >= MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31 goto null_date; break; case INTERVAL_DAY: period= calc_daynr(ltime->year,ltime->month,ltime->day) + sign*interval.day; - if (period < 0 || period >= 3652424) // Daynumber from year 0 to 9999-12-31 + if (period < 0 || period >= MAX_DAY_NUMBER) // Daynumber from year 0 to 9999-12-31 goto null_date; get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day); break; @@ -1375,6 +1398,63 @@ void Item_typecast::print(String *str) str->append(')'); } +String *Item_datetime_typecast::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_date(<ime,1) && + make_datetime(str, <ime, ltime.second_part ? + DATE_TIME_MICROSECOND : DATE_TIME)) + return str; + +null_date: + null_value=1; + return 0; +} + + +bool Item_time_typecast::get_time(TIME *ltime) +{ + bool res= get_arg0_time(ltime); + ltime->time_type= TIMESTAMP_TIME; + return res; +} + + +String *Item_time_typecast::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_time(<ime) && + make_datetime(str, <ime, ltime.second_part ? TIME_MICROSECOND : TIME_ONLY)) + return str; + + null_value=1; + return 0; +} + + +bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) +{ + bool res= get_arg0_date(ltime,1); + ltime->time_type= TIMESTAMP_DATE; + return res; +} + + +String *Item_date_typecast::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_date(<ime,1) && + make_datetime(str, <ime, DATE_ONLY)) + return str; + +null_date: + null_value=1; + return 0; +} + /* MAKEDATE(a,b) is a date function that creates a date value from a year and day value. @@ -1392,7 +1472,7 @@ String *Item_func_makedate::val_str(String *str) goto null_date; days= calc_daynr(yearnr,1,1) + daynr - 1; - if (days > 0 || days < 3652424L) // Day number from year 0 to 9999-12-31 + if (days > 0 || days < MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31 { null_value=0; get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); @@ -1410,7 +1490,7 @@ void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; decimals=0; - max_length=26*my_charset_bin.mbmaxlen; + max_length=26*MY_CHARSET_BIN_MB_MAXLEN; /* The field type for the result of an Item_func_add_time function is defined as @@ -1424,7 +1504,8 @@ void Item_func_add_time::fix_length_and_dec() cached_field_type= MYSQL_TYPE_STRING; arg0_field_type= args[0]->field_type(); - if (arg0_field_type == MYSQL_TYPE_DATETIME || + if (arg0_field_type == MYSQL_TYPE_DATE || + arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP) cached_field_type= MYSQL_TYPE_DATETIME; else if (arg0_field_type == MYSQL_TYPE_TIME) @@ -1443,20 +1524,28 @@ void Item_func_add_time::fix_length_and_dec() String *Item_func_add_time::val_str(String *str) { TIME l_time1, l_time2, l_time3; - bool is_time; + bool is_time= 0; long microseconds, seconds, days= 0; int l_sign= sign; null_value=0; - if (args[0]->get_time(&l_time1) || - args[1]->get_time(&l_time2) || - l_time2.time_type == TIMESTAMP_FULL) - goto null_date; - is_time= (l_time1.time_type == TIMESTAMP_TIME); l_time3.neg= 0; - if (is_time) + if (is_date) // TIMESTAMP function + { + if (get_arg0_date(&l_time1,1) || + args[1]->get_time(&l_time2) || + l_time1.time_type == TIMESTAMP_TIME || + l_time2.time_type != TIMESTAMP_TIME) + goto null_date; + } + else // ADDTIME function { - if ((l_time2.neg == l_time1.neg) && l_time1.neg) + if (args[0]->get_time(&l_time1) || + args[1]->get_time(&l_time2) || + l_time2.time_type == TIMESTAMP_FULL) + goto null_date; + is_time= (l_time1.time_type == TIMESTAMP_TIME); + if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg)) l_time3.neg= 1; } if (l_time1.neg != l_time2.neg) @@ -1504,13 +1593,17 @@ String *Item_func_add_time::val_str(String *str) { get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); if (l_time3.day && - make_datetime(str, &l_time3, DATE_TIME_MICROSECOND)) + make_datetime(str, &l_time3, + l_time1.second_part || l_time2.second_part ? + DATE_TIME_MICROSECOND : DATE_TIME)) return str; goto null_date; } l_time3.hour+= days*24; - if (make_datetime(str, &l_time3, TIME_MICROSECOND)) + if (make_datetime(str, &l_time3, + l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY)) return str; null_date: @@ -1578,7 +1671,9 @@ String *Item_func_timediff::val_str(String *str) l_time3.neg= l_time3.neg ? 0 : 1; calc_time_from_sec(&l_time3, seconds, microseconds); - if (make_datetime(str, &l_time3, TIME_MICROSECOND)) + if (make_datetime(str, &l_time3, + l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY)) return str; null_date: @@ -1624,99 +1719,6 @@ null_date: } /* - TIMESTAMP(a,b) is a function ( extraction) that calculates a datetime value - comprising a date value, time value. - - a: Date_or_datetime value - b: Time value - Result: Datetime value -*/ - -String *Item_func_timestamp::val_str(String *str) -{ - TIME l_time1 ,l_time2, l_time3; - long seconds; - long microseconds; - long days; - int l_sign; - - if (get_arg0_date(&l_time1,1) || - args[1]->get_time(&l_time2) || - l_time1.time_type == TIMESTAMP_TIME || - l_time2.time_type != TIMESTAMP_TIME) - goto null_date; - - l_sign= l_time2.neg ? -1 : 1; - days= (calc_daynr((uint) l_time1.year,(uint) l_time1.month, - (uint) l_time1.day) + l_sign*l_time2.day); - - microseconds= l_time1.second_part + l_sign*l_time2.second_part; - seconds= (l_time1.hour*3600L + l_time1.minute*60L + l_time1.second + - (l_time2.day*86400L + l_time2.hour*3600L + - l_time2.minute*60L + l_time2.second)*l_sign); - days+= seconds/86400L; - seconds%= 86400L; - if (microseconds < 0) - { - microseconds+= 1000000L; - seconds--; - } - if (seconds < 0) - { - days--; - seconds+= 86400L; - } - if (days < 0) - goto null_date; - - calc_time_from_sec(&l_time3, seconds, microseconds); - get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); - make_datetime(str, &l_time3, DATE_TIME_MICROSECOND); - return str; - -null_date: - null_value=1; - return 0; -} - -/* - DATE(a) is a function ( extraction) that calculates a date value. - - a: Datetime value - Result: Date value -*/ -String *Item_func_date::val_str(String *str) -{ - TIME ltime; - - if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, DATE_ONLY)) - return str; - -null_date: - null_value=1; - return 0; -} - -/* - TIME(a) is a function ( extraction) that calculates a time value. - - a: Datetime value - Result: Time value -*/ -String *Item_func_time::val_str(String *str) -{ - TIME ltime; - - if (!get_arg0_time(<ime) && - make_datetime(str, <ime, TIME_MICROSECOND)) - return str; - - null_value=1; - return 0; -} - -/* MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a. a: Datetime or time value diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index ea29731fe35..20b95f8e22d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -557,6 +557,8 @@ class Item_date_typecast :public Item_typecast { public: Item_date_typecast(Item *a) :Item_typecast(a) {} + String *val_str(String *str); + bool get_date(TIME *ltime, bool fuzzy_date); const char *func_name() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field() { return result_field; } @@ -571,6 +573,8 @@ class Item_time_typecast :public Item_typecast { public: Item_time_typecast(Item *a) :Item_typecast(a) {} + String *val_str(String *str); + bool get_time(TIME *ltime); const char *func_name() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field() { return result_field; } @@ -585,6 +589,7 @@ class Item_datetime_typecast :public Item_typecast { public: Item_datetime_typecast(Item *a) :Item_typecast(a) {} + String *val_str(String *str); const char *func_name() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field() { return result_field; } @@ -604,7 +609,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*my_charset_bin.mbmaxlen; + max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) @@ -613,18 +618,26 @@ public: } }; + class Item_func_add_time :public Item_str_func { + const bool is_date; int sign; enum_field_types cached_field_type; public: - Item_func_add_time(Item *a, Item *b, bool neg_arg) - :Item_str_func(a, b) { sign= neg_arg ? -1 : 1; } + Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg) + :Item_str_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } String *val_str(String *str); const char *func_name() const { return "addtime"; } enum_field_types field_type() const { return cached_field_type; } void fix_length_and_dec(); + +/* + TODO: + Change this when we support + microseconds in TIME/DATETIME +*/ Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { @@ -647,7 +660,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=17*my_charset_bin.mbmaxlen; + max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) @@ -667,66 +680,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*my_charset_bin.mbmaxlen; - } - Field *tmp_table_field() { return result_field; } - Field *tmp_table_field(TABLE *t_arg) - { - return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); - } -}; - -class Item_func_timestamp :public Item_str_func -{ -public: - Item_func_timestamp(Item *a, Item *b) :Item_str_func(a, b) {} - String *val_str(String *str); - const char *func_name() const { return "timestamp"; } - enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } - void fix_length_and_dec() - { - decimals=0; - max_length=26*my_charset_bin.mbmaxlen; - } - Field *tmp_table_field() { return result_field; } - Field *tmp_table_field(TABLE *t_arg) - { - return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); - } -}; - -class Item_func_date :public Item_str_func -{ -public: - Item_func_date(Item *a) - :Item_str_func(a) {} - String *val_str(String *str); - const char *func_name() const { return "date"; } - enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - void fix_length_and_dec() - { - decimals=0; - max_length=10*my_charset_bin.mbmaxlen; - } - Field *tmp_table_field() { return result_field; } - Field *tmp_table_field(TABLE *t_arg) - { - return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); - } -}; - -class Item_func_time :public Item_str_func -{ -public: - Item_func_time(Item *a) - :Item_str_func(a) {} - String *val_str(String *str); - const char *func_name() const { return "time"; } - enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - void fix_length_and_dec() - { - decimals=0; - max_length=15*my_charset_bin.mbmaxlen; + max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8aeb18dcf26..ea3c2d45333 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -224,6 +224,8 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define RAID_BLOCK_SIZE 1024 +#define MY_CHARSET_BIN_MB_MAXLEN 1 + #ifdef EXTRA_DEBUG /* Sync points allow us to force the server to reach a certain line of code diff --git a/sql/protocol.cc b/sql/protocol.cc index 3d214e6f86d..1b9256c7723 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -823,6 +823,13 @@ bool Protocol_simple::store(Field *field) } +/* + TODO: + Second_part format ("%06") needs to change when + we support 0-6 decimals for time. +*/ + + bool Protocol_simple::store(TIME *tm) { #ifndef DEBUG_OFF @@ -863,6 +870,12 @@ bool Protocol_simple::store_date(TIME *tm) } +/* + TODO: + Second_part format ("%06") needs to change when + we support 0-6 decimals for time. +*/ + bool Protocol_simple::store_time(TIME *tm) { #ifndef DEBUG_OFF diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 0a3e8d0db9f..e7d7b08c93c 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -390,6 +390,23 @@ bool String::append(IO_CACHE* file, uint32 arg_length) return FALSE; } +bool String::append_with_prefill(const char *s,uint32 arg_length, + uint32 full_length, char fill_char) +{ + int t_length= arg_length > full_length ? arg_length : full_length; + + if (realloc(str_length + t_length)) + return TRUE; + t_length= full_length - arg_length; + if (t_length > 0) + { + bfill(Ptr+str_length, t_length, fill_char); + str_length=str_length + t_length; + } + append(s, arg_length); + return FALSE; +} + uint32 String::numchars() { return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length); diff --git a/sql/sql_string.h b/sql/sql_string.h index e88c9389589..d446d26298b 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -189,6 +189,8 @@ public: bool append(const char *s,uint32 arg_length=0); bool append(const char *s,uint32 arg_length, CHARSET_INFO *cs); bool append(IO_CACHE* file, uint32 arg_length); + bool append_with_prefill(const char *s, uint32 arg_length, + uint32 full_length, char fill_char); int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1 int strstr_case(const String &s,uint32 offset=0); int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1 diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 873257116b9..4aa5b70407e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2381,7 +2381,7 @@ simple_expr: Lex->safe_to_cache_query=0; } | DATE_SYM '(' expr ')' - { $$= new Item_func_date($3); } + { $$= new Item_date_typecast($3); } | DAY_SYM '(' expr ')' { $$= new Item_func_dayofmonth($3); } | ELT_FUNC '(' expr ',' expr_list ')' @@ -2580,9 +2580,11 @@ simple_expr: | SUBSTRING_INDEX '(' expr ',' expr ',' expr ')' { $$= new Item_func_substr_index($3,$5,$7); } | TIME_SYM '(' expr ')' - { $$= new Item_func_time($3); } + { $$= new Item_time_typecast($3); } + | TIMESTAMP '(' expr ')' + { $$= new Item_datetime_typecast($3); } | TIMESTAMP '(' expr ',' expr ')' - { $$= new Item_func_timestamp($3, $5); } + { $$= new Item_func_add_time($3, $5, 1, 0); } | TRIM '(' expr ')' { $$= new Item_func_trim($3); } | TRIM '(' LEADING expr FROM expr ')' @@ -4427,6 +4429,7 @@ keyword: | MEDIUM_SYM {} | MERGE_SYM {} | MEMORY_SYM {} + | MICROSECOND_SYM {} | MINUTE_SYM {} | MIN_ROWS {} | MODIFY_SYM {} diff --git a/sql/time.cc b/sql/time.cc index 056adf050ce..70ae8dcd8ed 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -432,6 +432,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) l_time->minute=date[4]; l_time->second=date[5]; l_time->second_part=date[6]; + l_time->neg= 0; DBUG_RETURN(l_time->time_type= (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL)); } |