1 /*
2    Copyright (c) 2004, 2011, Oracle and/or its affiliates.
3    Copyright (c) 2017, Monty Program Ab.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
17 
18 /*
19   This is a private header of sql-common library, containing
20   declarations for my_time.c
21 */
22 
23 #ifndef _my_time_h_
24 #define _my_time_h_
25 #include "mysql_time.h"
26 #include "my_decimal_limits.h"
27 
28 C_MODE_START
29 
30 extern ulonglong log_10_int[20];
31 extern uchar days_in_month[];
32 
33 #define MY_TIME_T_MAX LONG_MAX
34 #define MY_TIME_T_MIN LONG_MIN
35 
36 /* Time handling defaults */
37 #define TIMESTAMP_MAX_YEAR 2038
38 #define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1)
39 #define TIMESTAMP_MAX_VALUE INT_MAX32
40 #define TIMESTAMP_MIN_VALUE 0
41 
42 /* two-digit years < this are 20..; >= this are 19.. */
43 #define YY_PART_YEAR	   70
44 
45 /*
46   check for valid times only if the range of time_t is greater than
47   the range of my_time_t
48 */
49 #if SIZEOF_TIME_T > 4 || defined(TIME_T_UNSIGNED)
50 # define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \
51     ((x) <= TIMESTAMP_MAX_VALUE && \
52      (x) >= TIMESTAMP_MIN_VALUE)
53 #else
54 # define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \
55     ((x) >= TIMESTAMP_MIN_VALUE)
56 #endif
57 
58 /* Flags to str_to_datetime */
59 
60 /*
61   TIME_FUZZY_DATES is used for the result will only be used for comparison
62   purposes. Conversion is as relaxed as possible.
63 */
64 #define TIME_FUZZY_DATES        1U
65 #define TIME_DATETIME_ONLY	2U
66 #define TIME_TIME_ONLY	        4U
67 #define TIME_NO_ZERO_IN_DATE    (1UL << 23) /* == MODE_NO_ZERO_IN_DATE */
68 #define TIME_NO_ZERO_DATE	(1UL << 24) /* == MODE_NO_ZERO_DATE    */
69 #define TIME_INVALID_DATES	(1UL << 25) /* == MODE_INVALID_DATES   */
70 
71 #define MYSQL_TIME_WARN_TRUNCATED    1U
72 #define MYSQL_TIME_WARN_OUT_OF_RANGE 2U
73 #define MYSQL_TIME_NOTE_TRUNCATED    16U
74 
75 #define MYSQL_TIME_WARN_WARNINGS (MYSQL_TIME_WARN_TRUNCATED|MYSQL_TIME_WARN_OUT_OF_RANGE)
76 #define MYSQL_TIME_WARN_NOTES    (MYSQL_TIME_NOTE_TRUNCATED)
77 
78 #define MYSQL_TIME_WARN_HAVE_WARNINGS(x) MY_TEST((x) & MYSQL_TIME_WARN_WARNINGS)
79 #define MYSQL_TIME_WARN_HAVE_NOTES(x) MY_TEST((x) & MYSQL_TIME_WARN_NOTES)
80 
81 /* Useful constants */
82 #define SECONDS_IN_24H 86400L
83 
84 /* Limits for the TIME data type */
85 #define TIME_MAX_HOUR 838
86 #define TIME_MAX_MINUTE 59
87 #define TIME_MAX_SECOND 59
88 #define TIME_MAX_SECOND_PART 999999
89 #define TIME_SECOND_PART_FACTOR (TIME_MAX_SECOND_PART+1)
90 #define TIME_SECOND_PART_DIGITS 6
91 #define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)
92 #define TIME_MAX_VALUE_SECONDS (TIME_MAX_HOUR * 3600L + \
93                                 TIME_MAX_MINUTE * 60L + TIME_MAX_SECOND)
94 
95 /*
96   Structure to return status from
97     str_to_datetime(), str_to_time().
98 */
99 typedef struct st_mysql_time_status
100 {
101   int warnings;
102   uint precision;
103 } MYSQL_TIME_STATUS;
104 
my_time_status_init(MYSQL_TIME_STATUS * status)105 static inline void my_time_status_init(MYSQL_TIME_STATUS *status)
106 {
107   status->warnings= 0;
108   status->precision= 0;
109 }
110 
111 my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date,
112                    ulonglong flags, int *was_cut);
113 my_bool str_to_time(const char *str, size_t length, MYSQL_TIME *l_time,
114                     ulonglong flag, MYSQL_TIME_STATUS *status);
115 my_bool str_to_datetime(const char *str, size_t length, MYSQL_TIME *l_time,
116                         ulonglong flags, MYSQL_TIME_STATUS *status);
117 longlong number_to_datetime(longlong nr, ulong sec_part, MYSQL_TIME *time_res,
118                             ulonglong flags, int *was_cut);
119 
120 static inline
double_to_datetime(double nr,MYSQL_TIME * ltime,ulonglong flags,int * cut)121 longlong double_to_datetime(double nr, MYSQL_TIME *ltime, ulonglong flags, int *cut)
122 {
123   if (nr < 0 || nr > (double)LONGLONG_MAX)
124     nr= (double)LONGLONG_MAX;
125   return number_to_datetime((longlong) floor(nr),
126                             (ulong)((nr-floor(nr))*TIME_SECOND_PART_FACTOR),
127                             ltime, flags, cut);
128 }
129 
130 int number_to_time(my_bool neg, ulonglong nr, ulong sec_part,
131                    MYSQL_TIME *ltime, int *was_cut);
132 ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *);
133 ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *);
134 ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *);
135 ulonglong TIME_to_ulonglong(const MYSQL_TIME *);
136 double TIME_to_double(const MYSQL_TIME *my_time);
137 
138 int check_time_range(struct st_mysql_time *my_time, uint dec, int *warning);
139 my_bool check_datetime_range(const MYSQL_TIME *ltime);
140 
141 
142 long calc_daynr(uint year,uint month,uint day);
143 uint calc_days_in_year(uint year);
144 uint year_2000_handling(uint year);
145 
146 void my_init_time(void);
147 
148 
149 /*
150   Function to check sanity of a TIMESTAMP value
151 
152   DESCRIPTION
153     Check if a given MYSQL_TIME value fits in TIMESTAMP range.
154     This function doesn't make precise check, but rather a rough
155     estimate.
156 
157   RETURN VALUES
158     TRUE   The value seems sane
159     FALSE  The MYSQL_TIME value is definitely out of range
160 */
161 
validate_timestamp_range(const MYSQL_TIME * t)162 static inline my_bool validate_timestamp_range(const MYSQL_TIME *t)
163 {
164   if ((t->year > TIMESTAMP_MAX_YEAR || t->year < TIMESTAMP_MIN_YEAR) ||
165       (t->year == TIMESTAMP_MAX_YEAR && (t->month > 1 || t->day > 19)) ||
166       (t->year == TIMESTAMP_MIN_YEAR && (t->month < 12 || t->day < 31)))
167     return FALSE;
168 
169   return TRUE;
170 }
171 
172 /* Can't include mysqld_error.h, it needs mysys to build, thus hardcode 2 error values here. */
173 #ifndef ER_WARN_DATA_OUT_OF_RANGE
174 #define ER_WARN_DATA_OUT_OF_RANGE 1264
175 #define ER_WARN_INVALID_TIMESTAMP 1299
176 #endif
177 
178 my_time_t
179 my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, uint *error_code);
180 
181 void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type);
182 
183 /*
184   Required buffer length for my_time_to_str, my_date_to_str,
185   my_datetime_to_str and TIME_to_string functions. Note, that the
186   caller is still responsible to check that given TIME structure
187   has values in valid ranges, otherwise size of the buffer could
188   be not enough. We also rely on the fact that even wrong values
189   sent using binary protocol fit in this buffer.
190 */
191 #define MAX_DATE_STRING_REP_LENGTH 30
192 #define AUTO_SEC_PART_DIGITS DECIMAL_NOT_SPECIFIED
193 
194 int my_time_to_str(const MYSQL_TIME *l_time, char *to, uint digits);
195 int my_date_to_str(const MYSQL_TIME *l_time, char *to);
196 int my_datetime_to_str(const MYSQL_TIME *l_time, char *to, uint digits);
197 int my_TIME_to_str(const MYSQL_TIME *l_time, char *to, uint digits);
198 
199 int my_timeval_to_str(const struct timeval *tm, char *to, uint dec);
200 
sec_part_shift(longlong second_part,uint digits)201 static inline longlong sec_part_shift(longlong second_part, uint digits)
202 {
203   return second_part / (longlong)log_10_int[TIME_SECOND_PART_DIGITS - digits];
204 }
sec_part_unshift(longlong second_part,uint digits)205 static inline longlong sec_part_unshift(longlong second_part, uint digits)
206 {
207   return second_part * (longlong)log_10_int[TIME_SECOND_PART_DIGITS - digits];
208 }
209 
210 /* Date/time rounding and truncation functions */
my_time_fraction_remainder(long nr,uint decimals)211 static inline long my_time_fraction_remainder(long nr, uint decimals)
212 {
213   DBUG_ASSERT(decimals <= TIME_SECOND_PART_DIGITS);
214   return nr % (long) log_10_int[TIME_SECOND_PART_DIGITS - decimals];
215 }
my_time_trunc(MYSQL_TIME * ltime,uint decimals)216 static inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
217 {
218   ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
219 }
my_timeval_trunc(struct timeval * tv,uint decimals)220 static inline void my_timeval_trunc(struct timeval *tv, uint decimals)
221 {
222   tv->tv_usec-= my_time_fraction_remainder(tv->tv_usec, decimals);
223 }
224 
225 
226 #define hrtime_to_my_time(X) ((my_time_t)hrtime_to_time(X))
227 
228 /*
229   Available interval types used in any statement.
230 
231   'interval_type' must be sorted so that simple intervals comes first,
232   ie year, quarter, month, week, day, hour, etc. The order based on
233   interval size is also important and the intervals should be kept in a
234   large to smaller order. (get_interval_value() depends on this)
235 
236   Note: If you change the order of elements in this enum you should fix
237   order of elements in 'interval_type_to_name' and 'interval_names'
238   arrays
239 
240   See also interval_type_to_name, get_interval_value, interval_names, append_interval
241 */
242 
243 enum interval_type
244 {
245   INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_WEEK, INTERVAL_DAY,
246   INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND, INTERVAL_MICROSECOND,
247   INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
248   INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
249   INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
250   INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND, INTERVAL_LAST
251 };
252 
253 C_MODE_END
254 
255 #endif /* _my_time_h_ */
256