1 /* Copyright (c) 2006, 2010, Oracle and/or its affiliates.
2 Copyright (c) 2011, 2020, MariaDB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
16
17 #ifndef SQL_TIME_INCLUDED
18 #define SQL_TIME_INCLUDED
19
20 #include "my_time.h"
21 #include "mysql_time.h" /* timestamp_type */
22 #include "sql_error.h" /* Sql_condition */
23 #include "structs.h" /* INTERVAL */
24
25 typedef enum enum_mysql_timestamp_type timestamp_type;
26 typedef struct st_date_time_format DATE_TIME_FORMAT;
27 typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
28
29 /* Flags for calc_week() function. */
30 #define WEEK_MONDAY_FIRST 1
31 #define WEEK_YEAR 2
32 #define WEEK_FIRST_WEEKDAY 4
33
34 ulong convert_period_to_month(ulong period);
35 ulong convert_month_to_period(ulong month);
36 void set_current_date(THD *thd, MYSQL_TIME *to);
37 bool time_to_datetime(MYSQL_TIME *ltime);
38 void time_to_daytime_interval(MYSQL_TIME *l_time);
39 bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
40 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
41 bool str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *l_time,
42 ulonglong flags);
43 bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
44 ulonglong fuzzydate,
45 const TABLE_SHARE *s, const char *name);
46 bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
47 ulonglong fuzzydate,
48 const TABLE_SHARE *s, const char *name);
49 bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
50 ulonglong fuzzydate,
51 const TABLE_SHARE *s, const char *name);
52
53 bool time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
54 bool time_to_datetime_with_warn(THD *thd,
55 const MYSQL_TIME *tm, MYSQL_TIME *dt,
56 ulonglong fuzzydate);
57 /*
58 Simply truncate the YYYY-MM-DD part to 0000-00-00
59 and change time_type to MYSQL_TIMESTAMP_TIME
60 */
datetime_to_time(MYSQL_TIME * ltime)61 inline void datetime_to_time(MYSQL_TIME *ltime)
62 {
63 DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
64 ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
65 DBUG_ASSERT(ltime->neg == 0);
66 ltime->year= ltime->month= ltime->day= 0;
67 ltime->time_type= MYSQL_TIMESTAMP_TIME;
68 }
69
70
71 /**
72 Convert DATE/DATETIME to TIME(dec)
73 using CURRENT_DATE in a non-old mode,
74 or using simple truncation in old mode (OLD_MODE_ZERO_DATE_TIME_CAST).
75
76 @param thd - the thread to get the variables.old_behaviour value from
77 @param dt - the DATE of DATETIME value to convert
78 @param[out] tm - store result here
79 @param dec - the desired scale. The fractional part of the result
80 is checked according to this parameter before returning
81 the conversion result. "dec" is important in the corner
82 cases near the max/min limits.
83 If the result is '838:59:59.999999' and the desired scale
84 is less than 6, an error is returned.
85 Note, dec is not important in the
86 OLD_MODE_ZERO_DATE_TIME_CAST old mode.
87
88 - in case of OLD_MODE_ZERO_DATE_TIME_CAST
89 the TIME part is simply truncated and "false" is returned.
90 - otherwise, the result is calculated effectively similar to:
91 TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME))
92 If the difference fits into the supported TIME range, "false" is returned,
93 otherwise a warning is issued and "true" is returned.
94
95 @return false - on success
96 @return true - on error
97 */
98 bool datetime_to_time_with_warn(THD *, const MYSQL_TIME *dt,
99 MYSQL_TIME *tm, uint dec);
100
101
datetime_to_date(MYSQL_TIME * ltime)102 inline void datetime_to_date(MYSQL_TIME *ltime)
103 {
104 DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
105 ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
106 DBUG_ASSERT(ltime->neg == 0);
107 ltime->second_part= ltime->hour= ltime->minute= ltime->second= 0;
108 ltime->time_type= MYSQL_TIMESTAMP_DATE;
109 }
date_to_datetime(MYSQL_TIME * ltime)110 inline void date_to_datetime(MYSQL_TIME *ltime)
111 {
112 DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
113 ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
114 DBUG_ASSERT(ltime->neg == 0);
115 ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
116 }
117 void make_truncated_value_warning(THD *thd,
118 Sql_condition::enum_warning_level level,
119 const ErrConv *str_val,
120 timestamp_type time_type,
121 const char *db_name, const char *table_name,
122 const char *field_name);
123
make_truncated_value_warning(THD * thd,Sql_condition::enum_warning_level level,const char * str_val,size_t str_length,timestamp_type time_type,const char * db_name,const char * table_name,const char * field_name)124 static inline void make_truncated_value_warning(THD *thd,
125 Sql_condition::enum_warning_level level, const char *str_val,
126 size_t str_length, timestamp_type time_type,
127 const char *db_name, const char *table_name,
128 const char *field_name)
129 {
130 const ErrConvString str(str_val, str_length, &my_charset_bin);
131 make_truncated_value_warning(thd, level, &str, time_type, db_name, table_name,
132 field_name);
133 }
134
135 extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
136 const char *format_str,
137 uint format_length);
138 extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
139 DATE_TIME_FORMAT *format);
140 const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
141 timestamp_type type);
142 bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
143
144 /* MYSQL_TIME operations */
145 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
146 const INTERVAL &interval);
147 bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
148 int l_sign, longlong *seconds_out, long *microseconds_out);
149 int append_interval(String *str, interval_type int_type,
150 const INTERVAL &interval);
151 /**
152 Calculate time difference between two MYSQL_TIME values and
153 store the result as an out MYSQL_TIME value in MYSQL_TIMESTAMP_TIME format.
154
155 The result can be outside of the supported TIME range.
156 For example, calc_time_diff('2002-01-01 00:00:00', '2001-01-01 00:00:00')
157 returns '8760:00:00'. So the caller might want to do check_time_range() or
158 adjust_time_range_with_warn() on the result of a calc_time_diff() call.
159
160 @param l_time1 - the minuend (TIME/DATE/DATETIME value)
161 @param l_time2 - the subtrahend TIME/DATE/DATETIME value
162 @param l_sign - +1 if absolute values are to be subtracted,
163 or -1 if absolute values are to be added.
164 @param[out] l_time3 - the result
165 @param fuzzydate - flags
166
167 @return true - if TIME_NO_ZERO_DATE was passed in flags and
168 the result appeared to be '00:00:00.000000'.
169 This is important when calc_time_diff() is called
170 when calculating DATE_ADD(TIMEDIFF(...),...)
171 @return false - otherwise
172 */
173 bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
174 int lsign, MYSQL_TIME *l_time3, ulonglong fuzzydate);
175 int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
176 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
177
178 void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
179 uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
180
181 int calc_weekday(long daynr,bool sunday_first_day_of_week);
182 bool parse_date_time_format(timestamp_type format_type,
183 const char *format, uint format_length,
184 DATE_TIME_FORMAT *date_time_format);
185 /* Character set-aware version of str_to_time() */
186 bool str_to_time(CHARSET_INFO *cs, const char *str,size_t length,
187 MYSQL_TIME *l_time, ulonglong fuzzydate,
188 MYSQL_TIME_STATUS *status);
189 /* Character set-aware version of str_to_datetime() */
190 bool str_to_datetime(CHARSET_INFO *cs,
191 const char *str, size_t length,
192 MYSQL_TIME *l_time, ulonglong flags,
193 MYSQL_TIME_STATUS *status);
194
195 /* convenience wrapper */
parse_date_time_format(timestamp_type format_type,DATE_TIME_FORMAT * date_time_format)196 inline bool parse_date_time_format(timestamp_type format_type,
197 DATE_TIME_FORMAT *date_time_format)
198 {
199 return parse_date_time_format(format_type,
200 date_time_format->format.str,
201 (uint) date_time_format->format.length,
202 date_time_format);
203 }
204
205
206 extern DATE_TIME_FORMAT global_date_format;
207 extern DATE_TIME_FORMAT global_datetime_format;
208 extern DATE_TIME_FORMAT global_time_format;
209 extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
210 extern LEX_CSTRING interval_type_to_name[];
211
212 static inline bool
non_zero_hhmmssuu(const MYSQL_TIME * ltime)213 non_zero_hhmmssuu(const MYSQL_TIME *ltime)
214 {
215 return ltime->hour || ltime->minute || ltime->second || ltime->second_part;
216 }
217 static inline bool
non_zero_YYMMDD(const MYSQL_TIME * ltime)218 non_zero_YYMMDD(const MYSQL_TIME *ltime)
219 {
220 return ltime->year || ltime->month || ltime->day;
221 }
222 static inline bool
non_zero_date(const MYSQL_TIME * ltime)223 non_zero_date(const MYSQL_TIME *ltime)
224 {
225 return non_zero_YYMMDD(ltime) ||
226 (ltime->time_type == MYSQL_TIMESTAMP_DATETIME &&
227 non_zero_hhmmssuu(ltime));
228 }
229 static inline bool
check_date(const MYSQL_TIME * ltime,ulonglong flags,int * was_cut)230 check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
231 {
232 return check_date(ltime, non_zero_date(ltime), flags, was_cut);
233 }
234 bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
235 timestamp_type ts_type);
236 bool make_date_with_warn(MYSQL_TIME *ltime,
237 ulonglong fuzzy_date, timestamp_type ts_type);
238 bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
239
240 longlong pack_time(const MYSQL_TIME *my_time);
241 void unpack_time(longlong packed, MYSQL_TIME *my_time,
242 enum_mysql_timestamp_type ts_type);
243
244 #endif /* SQL_TIME_INCLUDED */
245