Extends 64 bit windows to support timestamps up to year 2106.

MDEV-32188 make TIMESTAMP use whole 32-bit unsigned range

This is done by changing my_time_t from long to unsigned long.
The effect of this is that on windows compling old clients may
get warnings of if they compare my_time_t with as signed variable.

Other things
- Removed my_time_t from include/*.pp files as it is different on windows
  and linux.
- Changed do_abi_check.cmake to first print abi_check and then the
  conflicting file (this makes it easier to find the cause of the error).
This commit is contained in:
Monty 2023-09-18 12:05:41 +03:00 committed by Sergei Golubchik
parent dfdedd46e4
commit b8ffd99cee
14 changed files with 60 additions and 46 deletions

View file

@ -82,7 +82,7 @@ FOREACH(file ${ABI_HEADERS})
EXECUTE_PROCESS(COMMAND mv -v ${abi_check_out} ${file}.pp)
ELSE(ABI_UPDATE)
MESSAGE(FATAL_ERROR
"ABI check found difference between ${file}.pp and ${abi_check_out}")
"ABI check found difference between ${abi_check_out} and ${file}.pp")
ENDIF(ABI_UPDATE)
ENDIF()
FILE(REMOVE ${abi_check_out})

View file

@ -30,7 +30,8 @@ C_MODE_START
extern MYSQL_PLUGIN_IMPORT ulonglong log_10_int[20];
extern uchar days_in_month[];
#if SIZEOF_LONG == 4
#if SIZEOF_VOIDP == 4
/* 32 bit system, using old timestamp */
#define MY_TIME_T_MAX LONG_MAX
#define MY_TIME_T_MIN LONG_MIN
#define TIMESTAMP_MAX_YEAR 2038
@ -39,7 +40,7 @@ extern uchar days_in_month[];
#define TIMESTAMP_MAX_VALUE INT_MAX32
#define TIMESTAMP_MIN_VALUE 0
#else
/* Use 4 byte unsigned timestamp */
/* 64 bit system. Use 4 byte unsigned timestamp */
#define MY_TIME_T_MAX ((longlong) UINT_MAX32)
#define MY_TIME_T_MIN 0
#define TIMESTAMP_MAX_YEAR 2106
@ -47,7 +48,7 @@ extern uchar days_in_month[];
#define TIMESTAMP_MAX_VALUE ((longlong) UINT_MAX32)
#define TIMESTAMP_MAX_MONTH 2
#define TIMESTAMP_MAX_DAY 7
#endif /* SIZEOF_LONG */
#endif /* SIZEOF_VOIDP */
#define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1)
/* two-digit years < this are 20..; >= this are 19.. */

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -385,7 +385,6 @@ void thd_key_delete(MYSQL_THD_KEY_T *key);
void* thd_getspecific(THD* thd, MYSQL_THD_KEY_T key);
int thd_setspecific(THD* thd, MYSQL_THD_KEY_T key, void *value);
}
typedef long my_time_t;
enum enum_mysql_timestamp_type
{
MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1,

View file

@ -19,13 +19,26 @@
/*
Portable time_t replacement.
For 32 bit systems holds seconds for 1970 - 2038-01-19 range
For 64 bit systems (where long is 64 bit) holds seconds for 1970 - 2106
For 32 bit systems holds seconds for 1970 - 2038-01-19
For 64 bit systems holds seconds for 1970 - 2106-02-07
Using the system built in time_t is not an option as
we rely on the above requirements in the time functions
*/
#ifndef MYSQL_ABI_CHECK
/*
long is 64bit on all 64bit systems, except Windows where it is 32 bit.
long is 32bit on all 32bit systems.
The following code ensures that my_time_t is 64 bit on all 64 bit
systems.
*/
#ifdef _WIN64
typedef long long my_time_t;
#else
typedef long my_time_t;
#endif
#endif /* MYSQL_ABI_CHECK */
/*
Time declarations shared between the server and client API:

View file

@ -829,7 +829,7 @@ int Log_event_writer::write_footer()
bool Log_event::write_header(Log_event_writer *writer, size_t event_data_length)
{
uchar header[LOG_EVENT_HEADER_LEN];
ulong now;
my_time_t now;
DBUG_ENTER("Log_event::write_header");
DBUG_PRINT("enter", ("filepos: %lld length: %zu type: %d",
(longlong) writer->pos(), event_data_length,

View file

@ -784,7 +784,7 @@ void Timestamp::round_or_set_max(uint dec, int *warn)
if (add_nanoseconds_usec(msec_round_add[dec]) &&
(ulonglong) tv_sec++ >= TIMESTAMP_MAX_VALUE)
{
tv_sec= TIMESTAMP_MAX_VALUE;
tv_sec= (time_t) TIMESTAMP_MAX_VALUE;
tv_usec= TIME_MAX_SECOND_PART;
*warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
}

View file

@ -1039,7 +1039,7 @@ protected:
public:
Timeval(my_time_t sec, ulong usec)
{
tv_sec= sec;
tv_sec= (time_t) sec;
/*
Since tv_usec is not always of type ulong, cast usec parameter
explicitly to uint to avoid compiler warnings about losing

View file

@ -52,6 +52,13 @@
#include <mysql/psi/mysql_file.h>
#include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH,
// MYSQL_LOCK_IGNORE_TIMEOUT
/*
Internal server time. Needed to interface with my_time_t, which can
be either long, ulong or long long depending on hardware or os.
*/
typedef longlong my_int_time_t;
/* Structure describing local time type (e.g. Moscow summer time (MSD)) */
typedef struct ttinfo
{
@ -67,7 +74,7 @@ typedef struct ttinfo
/* Structure describing leap-second corrections. */
typedef struct lsinfo
{
my_time_t ls_trans; // Transition time
my_int_time_t ls_trans; // Transition time
long ls_corr; // Correction to apply
} LS_INFO;
@ -101,7 +108,7 @@ typedef struct st_time_zone_info
uint charcnt; // Number of characters used for abbreviations
uint revcnt; // Number of transition descr. for TIME->my_time_t conversion
/* The following are dynamical arrays are allocated in MEM_ROOT */
my_time_t *ats; // Times of transitions between time types
my_int_time_t *ats; // Times of transitions between time types
uchar *types; // Local time types for transitions
TRAN_TYPE_INFO *ttis; // Local time types descriptions
/* Storage for local time types abbreviations. They are stored as ASCIIZ */
@ -116,7 +123,7 @@ typedef struct st_time_zone_info
ranges on which shifted my_time_t -> my_time_t mapping is linear or undefined.
Used for tm -> my_time_t conversion.
*/
my_time_t *revts;
my_int_time_t *revts;
REVT_INFO *revtis;
/*
Time type which is used for times smaller than first transition or if
@ -159,7 +166,7 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
union
{
struct tzhead tzhead;
uchar buf[sizeof(struct tzhead) + sizeof(my_time_t) * TZ_MAX_TIMES +
uchar buf[sizeof(struct tzhead) + sizeof(my_int_time_t) * TZ_MAX_TIMES +
TZ_MAX_TIMES + sizeof(TRAN_TYPE_INFO) * TZ_MAX_TYPES +
MY_MAX(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1))) +
sizeof(LS_INFO) * TZ_MAX_LEAPS];
@ -210,8 +217,8 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
sp->leapcnt * sizeof(LS_INFO))))
return 1;
sp->ats= (my_time_t *)tzinfo_buf;
tzinfo_buf+= ALIGN_SIZE(sp->timecnt * sizeof(my_time_t));
sp->ats= (my_int_time_t*) tzinfo_buf;
tzinfo_buf+= ALIGN_SIZE(sp->timecnt * sizeof(sp->ats[0]));
sp->types= (uchar *)tzinfo_buf;
tzinfo_buf+= ALIGN_SIZE(sp->timecnt);
sp->ttis= (TRAN_TYPE_INFO *)tzinfo_buf;
@ -302,9 +309,9 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
static my_bool
prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
{
my_time_t cur_t= MY_TIME_T_MIN;
my_time_t cur_l, end_t, UNINIT_VAR(end_l);
my_time_t cur_max_seen_l= MY_TIME_T_MIN;
my_int_time_t cur_t= MY_TIME_T_MIN;
my_int_time_t cur_l, end_t, UNINIT_VAR(end_l);
my_int_time_t cur_max_seen_l= MY_TIME_T_MIN;
long cur_offset, cur_corr, cur_off_and_corr;
uint next_trans_idx, next_leap_idx;
uint i;
@ -313,7 +320,7 @@ prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
we don't know table sizes ahead. (Well we can estimate their
upper bound but this will take extra space.)
*/
my_time_t revts[TZ_MAX_REV_RANGES];
my_int_time_t revts[TZ_MAX_REV_RANGES];
REVT_INFO revtis[TZ_MAX_REV_RANGES];
/*
@ -472,15 +479,15 @@ prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
revts[sp->revcnt]= end_l;
/* Allocate arrays of proper size in sp and copy result there */
if (!(sp->revts= (my_time_t *)alloc_root(storage,
if (!(sp->revts= (my_int_time_t*) alloc_root(storage,
sizeof(*sp->revts) *
(sp->revcnt + 1))) ||
!(sp->revtis= (REVT_INFO *)alloc_root(storage,
sizeof(REVT_INFO) * sp->revcnt)))
return 1;
memcpy(sp->revts, revts, sizeof(my_time_t) * (sp->revcnt + 1));
memcpy(sp->revtis, revtis, sizeof(REVT_INFO) * sp->revcnt);
memcpy(sp->revts, revts, sizeof(sp->revts[0]) * (sp->revcnt + 1));
memcpy(sp->revtis, revtis, sizeof(sp->revtis[0]) * sp->revcnt);
return 0;
}
@ -610,7 +617,7 @@ sec_to_TIME(MYSQL_TIME * tmp, my_time_t t, long offset)
Index of range to which t belongs
*/
static uint
find_time_range(my_time_t t, const my_time_t *range_boundaries,
find_time_range(my_int_time_t t, const my_int_time_t *range_boundaries,
uint higher_bound)
{
uint i, lower_bound= 0;
@ -875,7 +882,7 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
static my_time_t
TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp, uint *error_code)
{
longlong local_t;
my_int_time_t local_t;
uint saved_seconds;
uint i;
int shift= 0;
@ -1375,7 +1382,7 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
my_time_t
Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const
{
my_time_t local_t;
my_int_time_t local_t;
int shift= 0;
/*
@ -1408,7 +1415,7 @@ Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, uint *error_code) const
}
if (local_t >= TIMESTAMP_MIN_VALUE && local_t <= TIMESTAMP_MAX_VALUE)
return local_t;
return (my_time_t) local_t;
/* range error*/
*error_code= ER_WARN_DATA_OUT_OF_RANGE;
@ -1880,7 +1887,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Time_zone *return_val= 0;
int res;
uint tzid, ttid;
my_time_t ttime;
my_int_time_t ttime;
char buff[MAX_FIELD_WIDTH];
uchar keybuff[32];
Field *field;
@ -1891,7 +1898,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Temporary arrays that are used for loading of data for filling
TIME_ZONE_INFO structure
*/
my_time_t ats[TZ_MAX_TIMES];
my_int_time_t ats[TZ_MAX_TIMES];
uchar types[TZ_MAX_TIMES];
TRAN_TYPE_INFO ttis[TZ_MAX_TYPES];
char chars[MY_MAX(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
@ -2056,7 +2063,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
(key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
ttime= (my_time_t)table->field[1]->val_int();
ttime= (my_int_time_t) table->field[1]->val_int();
ttid= (uint)table->field[2]->val_int();
if (tmp_tz_info.timecnt + 1 > TZ_MAX_TIMES)
@ -2131,7 +2138,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Now we will allocate memory and init TIME_ZONE_INFO structure.
*/
if (!(alloc_buff= (char*) alloc_root(&tz_storage,
ALIGN_SIZE(sizeof(my_time_t) *
ALIGN_SIZE(sizeof(my_int_time_t) *
tz_info->timecnt) +
ALIGN_SIZE(tz_info->timecnt) +
ALIGN_SIZE(tz_info->charcnt) +
@ -2142,9 +2149,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
goto end;
}
tz_info->ats= (my_time_t *) alloc_buff;
memcpy(tz_info->ats, ats, tz_info->timecnt * sizeof(my_time_t));
alloc_buff+= ALIGN_SIZE(sizeof(my_time_t) * tz_info->timecnt);
tz_info->ats= (my_int_time_t *) alloc_buff;
memcpy(tz_info->ats, ats, tz_info->timecnt * sizeof(tz_info->ats[0]));
alloc_buff+= ALIGN_SIZE(sizeof(tz_info->ats[0]) * tz_info->timecnt);
tz_info->types= (uchar *)alloc_buff;
memcpy(tz_info->types, types, tz_info->timecnt);
alloc_buff+= ALIGN_SIZE(tz_info->timecnt);
@ -2482,8 +2489,8 @@ print_tz_as_sql(const char* tz_name, const TIME_ZONE_INFO *sp)
printf("INSERT INTO time_zone_transition \
(Time_zone_id, Transition_time, Transition_type_id) VALUES\n");
for (i= 0; i < sp->timecnt; i++)
printf("%s(@time_zone_id, %ld, %u)\n", (i == 0 ? " " : ","), sp->ats[i],
(uint)sp->types[i]);
printf("%s(@time_zone_id, %lld, %u)\n", (i == 0 ? " " : ","),
(longlong) sp->ats[i], (uint)sp->types[i]);
printf(";\n");
}
@ -2534,8 +2541,8 @@ print_tz_leaps_as_sql(const TIME_ZONE_INFO *sp)
printf("INSERT INTO time_zone_leap_second \
(Transition_time, Correction) VALUES\n");
for (i= 0; i < sp->leapcnt; i++)
printf("%s(%ld, %ld)\n", (i == 0 ? " " : ","),
sp->lsis[i].ls_trans, sp->lsis[i].ls_corr);
printf("%s(%lld, %ld)\n", (i == 0 ? " " : ","),
(longlong) sp->lsis[i].ls_trans, sp->lsis[i].ls_corr);
printf(";\n");
}