mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-25529 Extract vers_set_starts() and add starts_clause
Extracts the STARTS-alignment logic into vers_set_starts() so it can be reused. If the aligned local time falls into a DST gap (e.g. a midnight that does not exist), the start of the gap is used instead of failing with ER_PART_WRONG_VALUE. If it falls before the TIMESTAMP range (e.g. a local midnight before 1970), the timestamp itself is used. Also adds the Vers_part_info::starts_clause flag in preparation for later commits. The flag records whether STARTS was given explicitly (by the user or in the unpacked frm), which the auto-partitioning code uses to decide whether to re-align STARTS to the existing history.
This commit is contained in:
@@ -2842,6 +2842,7 @@ bool partition_info::vers_set_interval(THD* thd, Item* interval,
|
||||
/* 2. assign STARTS to interval.start */
|
||||
if (starts)
|
||||
{
|
||||
vers_info->starts_clause= true;
|
||||
if (starts->fix_fields_if_needed_for_scalar(thd, &starts))
|
||||
return true;
|
||||
switch (starts->result_type())
|
||||
@@ -2885,21 +2886,8 @@ bool partition_info::vers_set_interval(THD* thd, Item* interval,
|
||||
}
|
||||
else // calculate default STARTS depending on INTERVAL
|
||||
{
|
||||
thd->variables.time_zone->gmt_sec_to_TIME(<ime, thd->query_start());
|
||||
if (vers_info->interval.step.second)
|
||||
goto interval_set_starts;
|
||||
ltime.second= 0;
|
||||
if (vers_info->interval.step.minute)
|
||||
goto interval_set_starts;
|
||||
ltime.minute= 0;
|
||||
if (vers_info->interval.step.hour)
|
||||
goto interval_set_starts;
|
||||
ltime.hour= 0;
|
||||
|
||||
interval_set_starts:
|
||||
vers_info->interval.start= TIME_to_timestamp(thd, <ime, &err);
|
||||
if (err)
|
||||
goto interval_starts_error;
|
||||
if (vers_set_starts(thd, thd->query_start(), table_name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -2910,6 +2898,61 @@ interval_starts_error:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set STARTS to @p ts with the time-of-day parts below the finest time unit
|
||||
of the INTERVAL cleared.
|
||||
|
||||
Converts @p ts to broken-down local time in the current session time zone,
|
||||
then clears time components in order (second, then minute, then hour),
|
||||
stopping at the finest (smallest) non-zero unit present in
|
||||
@c vers_info->interval.step. Day, month and year are never cleared, so
|
||||
this is not a multiple of the interval: INTERVAL 2 HOUR keeps an odd hour
|
||||
and a month interval keeps the day. If the truncated local time falls into
|
||||
a DST gap, the start of the gap is used; if it falls before the TIMESTAMP
|
||||
range, @p ts itself is used. The result is stored in
|
||||
@c vers_info->interval.start.
|
||||
|
||||
@param thd Current thread.
|
||||
@param ts Timestamp to align.
|
||||
@param table_name Table name, for the ER_PART_WRONG_VALUE message.
|
||||
|
||||
@retval false Success.
|
||||
@retval true Error, reported as ER_PART_WRONG_VALUE.
|
||||
*/
|
||||
bool partition_info::vers_set_starts(THD *thd, my_time_t ts,
|
||||
const char *table_name)
|
||||
{
|
||||
MYSQL_TIME ltime;
|
||||
uint err;
|
||||
thd->variables.time_zone->gmt_sec_to_TIME(<ime, ts);
|
||||
if (vers_info->interval.step.second)
|
||||
goto interval_set_starts;
|
||||
ltime.second= 0;
|
||||
if (vers_info->interval.step.minute)
|
||||
goto interval_set_starts;
|
||||
ltime.minute= 0;
|
||||
if (vers_info->interval.step.hour)
|
||||
goto interval_set_starts;
|
||||
ltime.hour= 0;
|
||||
|
||||
interval_set_starts:
|
||||
vers_info->interval.start= TIME_to_timestamp(thd, <ime, &err);
|
||||
/* Truncated below the TIMESTAMP range (e.g. local midnight before 1970) */
|
||||
if (err == ER_WARN_DATA_OUT_OF_RANGE)
|
||||
{
|
||||
vers_info->interval.start= ts;
|
||||
err= 0;
|
||||
}
|
||||
/* In a DST gap TIME_to_timestamp() returns the start of the gap */
|
||||
if (err && err != ER_WARN_INVALID_TIMESTAMP)
|
||||
{
|
||||
my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "STARTS");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool partition_info::vers_set_limit(ulonglong limit, bool auto_hist,
|
||||
const char *table_name)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@ struct Vers_part_info : public Sql_alloc
|
||||
Vers_part_info() :
|
||||
limit(0),
|
||||
auto_hist(false),
|
||||
starts_clause(false),
|
||||
now_part(NULL),
|
||||
hist_part(NULL)
|
||||
{
|
||||
@@ -46,6 +47,7 @@ struct Vers_part_info : public Sql_alloc
|
||||
interval(src.interval),
|
||||
limit(src.limit),
|
||||
auto_hist(src.auto_hist),
|
||||
starts_clause(src.starts_clause),
|
||||
now_part(NULL),
|
||||
hist_part(NULL)
|
||||
{
|
||||
@@ -55,6 +57,7 @@ struct Vers_part_info : public Sql_alloc
|
||||
interval= src.interval;
|
||||
limit= src.limit;
|
||||
auto_hist= src.auto_hist;
|
||||
starts_clause= src.starts_clause;
|
||||
now_part= src.now_part;
|
||||
hist_part= src.hist_part;
|
||||
return *this;
|
||||
@@ -87,6 +90,12 @@ struct Vers_part_info : public Sql_alloc
|
||||
} interval;
|
||||
ulonglong limit;
|
||||
bool auto_hist;
|
||||
/*
|
||||
STARTS was given explicitly. Always true for INTERVAL partitioning
|
||||
unpacked from the frm, so only in a parsed statement it tells that the
|
||||
user gave STARTS.
|
||||
*/
|
||||
bool starts_clause;
|
||||
partition_element *now_part;
|
||||
partition_element *hist_part;
|
||||
};
|
||||
@@ -433,6 +442,7 @@ public:
|
||||
bool vers_set_interval(THD *thd, Item *interval,
|
||||
interval_type int_type, Item *starts,
|
||||
bool auto_part, const char *table_name);
|
||||
bool vers_set_starts(THD *thd, my_time_t ts, const char *table_name);
|
||||
bool vers_set_limit(ulonglong limit, bool auto_part, const char *table_name);
|
||||
bool vers_set_hist_part(THD* thd, uint *create_count);
|
||||
bool range_interval_set_count(THD* thd, uint *create_count);
|
||||
|
||||
Reference in New Issue
Block a user