1 /* Copyright (c) 2006, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef SQL_TIME_INCLUDED
24 #define SQL_TIME_INCLUDED
25 
26 #include "my_global.h"                          /* ulong */
27 #include "my_time.h"
28 #include "mysql_time.h"                         /* timestamp_type */
29 #include "sql_error.h"                          /* Sql_condition */
30 #include "mysqld.h"                             /* current_thd */
31 
32 struct Date_time_format
33 {
34   uchar positions[8];
35   char  time_separator;			/* Separator between hour and minute */
36   uint flag;				/* For future */
37   LEX_STRING format;
38 };
39 
40 struct Interval
41 {
42   ulong year, month, day, hour;
43   ulonglong minute, second, second_part;
44   bool neg;
45 };
46 
47 struct Known_date_time_format
48 {
49   const char *format_name;
50   const char *date_format;
51   const char *datetime_format;
52   const char *time_format;
53 };
54 
55 /* Flags for calc_week() function.  */
56 #define WEEK_MONDAY_FIRST    1
57 #define WEEK_YEAR            2
58 #define WEEK_FIRST_WEEKDAY   4
59 
60 ulong convert_period_to_month(ulong period);
61 ulong convert_month_to_period(ulong month);
62 void mix_date_and_time(MYSQL_TIME *ldate, const MYSQL_TIME *ltime);
63 void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
64 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
65 bool datetime_with_no_zero_in_date_to_timeval(THD *thd, const MYSQL_TIME *t,
66                                               struct timeval *tm,
67                                               int *warnings);
68 bool datetime_to_timeval(THD *thd, const MYSQL_TIME *t,
69                          struct timeval *tm, int *warnings);
70 bool str_to_datetime_with_warn(String *str,  MYSQL_TIME *l_time,
71                                my_time_flags_t flags);
72 bool my_decimal_to_datetime_with_warn(const my_decimal *decimal,
73                                       MYSQL_TIME *ltime, my_time_flags_t flags);
74 bool my_double_to_datetime_with_warn(double nr, MYSQL_TIME *ltime,
75                                      my_time_flags_t flags);
76 bool my_longlong_to_datetime_with_warn(longlong nr, MYSQL_TIME *ltime,
77                                        my_time_flags_t flags);
78 bool my_decimal_to_time_with_warn(const my_decimal *decimal,
79                                   MYSQL_TIME *ltime);
80 bool my_double_to_time_with_warn(double nr, MYSQL_TIME *ltime);
81 bool my_longlong_to_time_with_warn(longlong nr, MYSQL_TIME *ltime);
82 bool str_to_time_with_warn(String *str, MYSQL_TIME *l_time);
83 void time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
datetime_to_time(MYSQL_TIME * ltime)84 inline void datetime_to_time(MYSQL_TIME *ltime)
85 {
86   ltime->year= ltime->month= ltime->day= 0;
87   ltime->time_type= MYSQL_TIMESTAMP_TIME;
88 }
datetime_to_date(MYSQL_TIME * ltime)89 inline void datetime_to_date(MYSQL_TIME *ltime)
90 {
91   ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
92   ltime->time_type= MYSQL_TIMESTAMP_DATE;
93 }
date_to_datetime(MYSQL_TIME * ltime)94 inline void date_to_datetime(MYSQL_TIME *ltime)
95 {
96   ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
97 }
98 void make_truncated_value_warning(THD *thd,
99                                   Sql_condition::enum_severity_level level,
100                                   ErrConvString val,
101                                   timestamp_type time_type,
102                                   const char *field_name);
make_truncated_value_warning(ErrConvString val,timestamp_type time_type)103 inline void make_truncated_value_warning(ErrConvString val,
104                                          timestamp_type time_type)
105 {
106   make_truncated_value_warning(current_thd, Sql_condition::SL_WARNING,
107                                val, time_type, NullS);
108 }
109 extern Date_time_format *date_time_format_copy(THD *thd,
110 					       Date_time_format *format);
111 const char *get_date_time_format_str(Known_date_time_format *format,
112 				     timestamp_type type);
113 void make_date(const Date_time_format *format, const MYSQL_TIME *l_time,
114                String *str);
115 void make_time(const Date_time_format *format, const MYSQL_TIME *l_time,
116                String *str, uint dec);
117 void make_datetime(const Date_time_format *format, const MYSQL_TIME *l_time,
118                    String *str, uint dec);
119 bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
120 
121 /* MYSQL_TIME operations */
122 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
123                        Interval interval);
124 bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
125                     int l_sign, longlong *seconds_out, long *microseconds_out);
126 int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
127 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
128 void calc_time_from_sec(MYSQL_TIME *to, longlong seconds, long microseconds);
129 uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
130 
131 int calc_weekday(long daynr,bool sunday_first_day_of_week);
132 
133 /* Character set-aware version of str_to_time() */
134 bool str_to_time(const CHARSET_INFO *cs, const char *str, size_t length,
135                  MYSQL_TIME *l_time, my_time_flags_t flags,
136                  MYSQL_TIME_STATUS *status);
str_to_time(const String * str,MYSQL_TIME * ltime,my_time_flags_t flags,MYSQL_TIME_STATUS * status)137 static inline bool str_to_time(const String *str, MYSQL_TIME *ltime,
138                                my_time_flags_t flags, MYSQL_TIME_STATUS *status)
139 {
140   return str_to_time(str->charset(), str->ptr(), str->length(),
141                      ltime, flags, status);
142 }
143 
144 bool time_add_nanoseconds_with_round(MYSQL_TIME *ltime, uint nanoseconds,
145                                      int *warnings);
146 /* Character set-aware version of str_to_datetime() */
147 bool str_to_datetime(const CHARSET_INFO *cs,
148                      const char *str, size_t length,
149                      MYSQL_TIME *l_time, my_time_flags_t flags,
150                      MYSQL_TIME_STATUS *status);
str_to_datetime(const String * str,MYSQL_TIME * ltime,my_time_flags_t flags,MYSQL_TIME_STATUS * status)151 static inline bool str_to_datetime(const String *str, MYSQL_TIME *ltime,
152                                    my_time_flags_t flags,
153                                    MYSQL_TIME_STATUS *status)
154 {
155   return str_to_datetime(str->charset(), str->ptr(), str->length(),
156                          ltime, flags, status);
157 }
158 
159 bool datetime_add_nanoseconds_with_round(MYSQL_TIME *ltime,
160                                          uint nanoseconds, int *warnings);
161 
162 bool parse_date_time_format(timestamp_type format_type,
163                             Date_time_format *date_time_format);
164 
165 extern Date_time_format global_date_format;
166 extern Date_time_format global_datetime_format;
167 extern Date_time_format global_time_format;
168 extern Known_date_time_format known_date_time_formats[];
169 extern LEX_STRING interval_type_to_name[];
170 
171 /* Date/time rounding and truncation functions */
my_time_fraction_remainder(long nr,uint decimals)172 inline long my_time_fraction_remainder(long nr, uint decimals)
173 {
174   assert(decimals <= DATETIME_MAX_DECIMALS);
175   return nr % (long) log_10_int[DATETIME_MAX_DECIMALS - decimals];
176 }
my_time_trunc(MYSQL_TIME * ltime,uint decimals)177 inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
178 {
179   ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
180 }
my_datetime_trunc(MYSQL_TIME * ltime,uint decimals)181 inline void my_datetime_trunc(MYSQL_TIME *ltime, uint decimals)
182 {
183   return my_time_trunc(ltime, decimals);
184 }
my_timeval_trunc(struct timeval * tv,uint decimals)185 inline void my_timeval_trunc(struct timeval *tv, uint decimals)
186 {
187   tv->tv_usec-= my_time_fraction_remainder(tv->tv_usec, decimals);
188 }
189 bool my_time_round(MYSQL_TIME *ltime, uint decimals);
190 bool my_datetime_round(MYSQL_TIME *ltime, uint decimals, int *warnings);
191 bool my_timeval_round(struct timeval *tv, uint decimals);
192 
193 
TIME_to_ulonglong_datetime_round(const MYSQL_TIME * ltime)194 inline ulonglong TIME_to_ulonglong_datetime_round(const MYSQL_TIME *ltime)
195 {
196   // Catch simple cases
197   if (ltime->second_part < 500000)
198     return TIME_to_ulonglong_datetime(ltime);
199   if (ltime->second < 59)
200     return TIME_to_ulonglong_datetime(ltime) + 1;
201   // Corner case e.g. 'YYYY-MM-DD hh:mm:59.5'. Proceed with slower method.
202   int warnings= 0;
203   MYSQL_TIME tmp= *ltime;
204   my_datetime_round(&tmp, 0, &warnings);
205   return TIME_to_ulonglong_datetime(&tmp);// + TIME_microseconds_round(ltime);
206 }
207 
208 
TIME_to_ulonglong_time_round(const MYSQL_TIME * ltime)209 inline ulonglong TIME_to_ulonglong_time_round(const MYSQL_TIME *ltime)
210 {
211   if (ltime->second_part < 500000)
212     return TIME_to_ulonglong_time(ltime);
213   if (ltime->second < 59)
214     return TIME_to_ulonglong_time(ltime) + 1;
215   // Corner case e.g. 'hh:mm:59.5'. Proceed with slower method.
216   MYSQL_TIME tmp= *ltime;
217   my_time_round(&tmp, 0);
218   return TIME_to_ulonglong_time(&tmp);
219 }
220 
221 
TIME_to_ulonglong_round(const MYSQL_TIME * ltime)222 inline ulonglong TIME_to_ulonglong_round(const MYSQL_TIME *ltime)
223 {
224   switch (ltime->time_type)
225   {
226   case MYSQL_TIMESTAMP_TIME:
227     return TIME_to_ulonglong_time_round(ltime);
228   case MYSQL_TIMESTAMP_DATETIME:
229     return TIME_to_ulonglong_datetime_round(ltime);
230   case MYSQL_TIMESTAMP_DATE:
231     return TIME_to_ulonglong_date(ltime);
232   default:
233     assert(0);
234     return 0;
235   }
236 }
237 
238 
TIME_microseconds(const MYSQL_TIME * ltime)239 inline double TIME_microseconds(const MYSQL_TIME *ltime)
240 {
241   return (double) ltime->second_part / 1000000;
242 }
243 
TIME_to_double_datetime(const MYSQL_TIME * ltime)244 inline double TIME_to_double_datetime(const MYSQL_TIME *ltime)
245 {
246   return (double) TIME_to_ulonglong_datetime(ltime) + TIME_microseconds(ltime);
247 }
248 
249 
TIME_to_double_time(const MYSQL_TIME * ltime)250 inline double TIME_to_double_time(const MYSQL_TIME *ltime)
251 {
252   return (double) TIME_to_ulonglong_time(ltime) + TIME_microseconds(ltime);
253 }
254 
255 
TIME_to_double(const MYSQL_TIME * ltime)256 inline double TIME_to_double(const MYSQL_TIME *ltime)
257 {
258   return (double) TIME_to_ulonglong(ltime) + TIME_microseconds(ltime);
259 }
260 
261 
check_fuzzy_date(const MYSQL_TIME * ltime,my_time_flags_t fuzzydate)262 static inline bool check_fuzzy_date(const MYSQL_TIME *ltime,
263                                     my_time_flags_t fuzzydate)
264 {
265   return !(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day);
266 }
267 
268 static inline bool
non_zero_date(const MYSQL_TIME * ltime)269 non_zero_date(const MYSQL_TIME *ltime)
270 {
271   return ltime->year || ltime->month || ltime->day;
272 }
273 
274 static inline bool
non_zero_time(const MYSQL_TIME * ltime)275 non_zero_time(const MYSQL_TIME *ltime)
276 {
277   return ltime->hour || ltime->minute || ltime->second || ltime->second_part;
278 }
279 
280 longlong TIME_to_longlong_packed(const MYSQL_TIME *tm,
281                                  enum enum_field_types type);
282 void TIME_from_longlong_packed(MYSQL_TIME *ltime,
283                                enum enum_field_types type,
284                                longlong packed_value);
285 my_decimal *my_decimal_from_datetime_packed(my_decimal *dec,
286                                             enum enum_field_types type,
287                                             longlong packed_value);
288 
289 longlong longlong_from_datetime_packed(enum enum_field_types type,
290                                        longlong packed_value);
291 
292 double double_from_datetime_packed(enum enum_field_types type,
293                                    longlong packed_value);
294 
295 static inline
field_type_to_timestamp_type(enum enum_field_types type)296 timestamp_type field_type_to_timestamp_type(enum enum_field_types type)
297 {
298   switch (type)
299   {
300   case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME;
301   case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE;
302   case MYSQL_TYPE_TIMESTAMP:
303   case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME;
304   default: return MYSQL_TIMESTAMP_NONE;
305   }
306 }
307 #endif /* SQL_TIME_INCLUDED */
308