1
0
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:
Aleksey Midenkov
2026-06-29 14:00:02 +03:00
parent e1f06d1760
commit 3374ab18b2
2 changed files with 68 additions and 15 deletions

View File

@@ -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(&ltime, 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, &ltime, &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(&ltime, 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, &ltime, &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)
{

View File

@@ -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);