summaryrefslogtreecommitdiff
path: root/sql/sql_type.h
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-02-23 08:43:34 +0100
committerSergei Golubchik <serg@mariadb.org>2018-02-23 08:43:34 +0100
commit2732fcc608eb98345f79ba805842ab02272d49cf (patch)
treee7273c809f44432e5f60a55d5b8f35253d49963d /sql/sql_type.h
parent131d9a5d0cb51fa88a0461c939dfd2a7c68d5664 (diff)
parentb8af22af15d159b32256f7d5be8324871ae1a104 (diff)
downloadmariadb-git-2732fcc608eb98345f79ba805842ab02272d49cf.tar.gz
Merge branch 'bb-10.2-ext' into 10.3
Diffstat (limited to 'sql/sql_type.h')
-rw-r--r--sql/sql_type.h251
1 files changed, 244 insertions, 7 deletions
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 0446c93f88f..0738ef40ce8 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -95,6 +95,47 @@ struct SORT_FIELD_ATTR;
*/
class Time: private MYSQL_TIME
{
+public:
+ enum datetime_to_time_mode_t
+ {
+ DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS,
+ DATETIME_TO_TIME_YYYYMMDD_TRUNCATE
+ };
+ class Options
+ {
+ sql_mode_t m_get_date_flags;
+ datetime_to_time_mode_t m_datetime_to_time_mode;
+ public:
+ Options()
+ :m_get_date_flags(flags_for_get_date()),
+ m_datetime_to_time_mode(DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
+ { }
+ Options(sql_mode_t flags)
+ :m_get_date_flags(flags),
+ m_datetime_to_time_mode(DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
+ { }
+ Options(sql_mode_t flags, datetime_to_time_mode_t dtmode)
+ :m_get_date_flags(flags),
+ m_datetime_to_time_mode(dtmode)
+ { }
+ sql_mode_t get_date_flags() const
+ { return m_get_date_flags; }
+ datetime_to_time_mode_t datetime_to_time_mode() const
+ { return m_datetime_to_time_mode; }
+ };
+ /*
+ CAST(AS TIME) historically does not mix days to hours.
+ This is different comparing to how implicit conversion
+ in Field::store_time_dec() works (e.g. on INSERT).
+ */
+ class Options_for_cast: public Options
+ {
+ public:
+ Options_for_cast()
+ :Options(flags_for_get_date(), DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)
+ { }
+ };
+private:
bool is_valid_value_slow() const
{
return time_type == MYSQL_TIMESTAMP_NONE || is_valid_time_slow();
@@ -114,7 +155,7 @@ class Time: private MYSQL_TIME
e.g. returned from Item::get_date().
After this call, "this" is a valid TIME value.
*/
- void valid_datetime_to_valid_time()
+ void valid_datetime_to_valid_time(const Options opt)
{
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE ||
time_type == MYSQL_TIMESTAMP_DATETIME);
@@ -124,7 +165,9 @@ class Time: private MYSQL_TIME
*/
DBUG_ASSERT(day < 32);
DBUG_ASSERT(hour < 24);
- if (year == 0 && month == 0)
+ if (year == 0 && month == 0 &&
+ opt.datetime_to_time_mode() ==
+ DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
{
/*
The maximum hour value after mixing days will be 31*24+23=767,
@@ -149,12 +192,12 @@ class Time: private MYSQL_TIME
- either a valid TIME (within the supported TIME range),
- or MYSQL_TIMESTAMP_NONE
*/
- void valid_MYSQL_TIME_to_valid_value()
+ void valid_MYSQL_TIME_to_valid_value(const Options opt)
{
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
case MYSQL_TIMESTAMP_DATETIME:
- valid_datetime_to_valid_time();
+ valid_datetime_to_valid_time(opt);
break;
case MYSQL_TIMESTAMP_NONE:
break;
@@ -166,19 +209,35 @@ class Time: private MYSQL_TIME
break;
}
}
- void make_from_item(class Item *item);
+ void make_from_item(class Item *item, const Options opt);
public:
Time() { time_type= MYSQL_TIMESTAMP_NONE; }
- Time(Item *item) { make_from_item(item); }
+ Time(Item *item) { make_from_item(item, Options()); }
+ Time(Item *item, const Options opt) { make_from_item(item, opt); }
+ static sql_mode_t flags_for_get_date()
+ { return TIME_TIME_ONLY | TIME_INVALID_DATES; }
+ static sql_mode_t comparison_flags_for_get_date()
+ { return TIME_TIME_ONLY | TIME_INVALID_DATES | TIME_FUZZY_DATES; }
bool is_valid_time() const
{
DBUG_ASSERT(is_valid_value_slow());
return time_type == MYSQL_TIMESTAMP_TIME;
}
- void copy_to_mysql_time(MYSQL_TIME *ltime) const
+ const MYSQL_TIME *get_mysql_time() const
{
DBUG_ASSERT(is_valid_time_slow());
+ return this;
+ }
+ bool copy_to_mysql_time(MYSQL_TIME *ltime) const
+ {
+ if (time_type == MYSQL_TIMESTAMP_NONE)
+ {
+ ltime->time_type= MYSQL_TIMESTAMP_NONE;
+ return true;
+ }
+ DBUG_ASSERT(is_valid_time_slow());
*ltime= *this;
+ return false;
}
int cmp(const Time *other) const
{
@@ -192,9 +251,175 @@ public:
return 1;
return 0;
}
+ longlong to_seconds_abs() const
+ {
+ DBUG_ASSERT(is_valid_time_slow());
+ return hour * 3600L + minute * 60 + second;
+ }
+ longlong to_seconds() const
+ {
+ return neg ? -to_seconds_abs() : to_seconds_abs();
+ }
};
+/**
+ Class Temporal_with_date is designed to store valid DATE or DATETIME values.
+ See also class Time.
+
+ 1. Valid value:
+ a. MYSQL_TIMESTAMP_{DATE|DATETIME} - a valid DATE or DATETIME value
+ b. MYSQL_TIMESTAMP_NONE - an undefined value
+
+ 2. Invalid value (internally only):
+ a. MYSQL_TIMESTAMP_{DATE|DATETIME} - a DATE or DATETIME value, but with
+ MYSQL_TIME members outside of the
+ valid/supported range
+ b. MYSQL_TIMESTAMP_TIME - a TIME value
+ c. MYSQL_TIMESTAMP_ERROR - error
+
+ Temporarily is allowed to have an invalid value, but only internally,
+ during initialization time. All constructors and modification methods must
+ leave the value as described above (see "Valid value").
+
+ Derives from MYSQL_TIME using "protected" inheritance to make sure
+ it is accessed externally only in the valid state.
+*/
+
+class Temporal_with_date: protected MYSQL_TIME
+{
+protected:
+ void make_from_item(THD *thd, Item *item, sql_mode_t flags);
+ Temporal_with_date(THD *thd, Item *item, sql_mode_t flags)
+ {
+ make_from_item(thd, item, flags);
+ }
+};
+
+
+/**
+ Class Date is designed to store valid DATE values.
+ All constructors and modification methods leave instances
+ of this class in one of the following valid states:
+ a. MYSQL_TIMESTAMP_DATE - a DATE with all MYSQL_TIME members properly set
+ b. MYSQL_TIMESTAMP_NONE - an undefined value.
+ Other MYSQL_TIMESTAMP_XXX are not possible.
+ MYSQL_TIMESTAMP_DATE with MYSQL_TIME members improperly set is not possible.
+*/
+class Date: public Temporal_with_date
+{
+ bool is_valid_value_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE || is_valid_date_slow();
+ }
+ bool is_valid_date_slow() const
+ {
+ DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE);
+ return !check_datetime_range(this);
+ }
+public:
+ Date(THD *thd, Item *item, sql_mode_t flags)
+ :Temporal_with_date(thd, item, flags)
+ {
+ if (time_type == MYSQL_TIMESTAMP_DATETIME)
+ datetime_to_date(this);
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Date(const Temporal_with_date *d)
+ :Temporal_with_date(*d)
+ {
+ datetime_to_date(this);
+ DBUG_ASSERT(is_valid_date_slow());
+ }
+ bool is_valid_date() const
+ {
+ DBUG_ASSERT(is_valid_value_slow());
+ return time_type == MYSQL_TIMESTAMP_DATE;
+ }
+ const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return this;
+ }
+};
+
+
+/**
+ Class Datetime is designed to store valid DATETIME values.
+ All constructors and modification methods leave instances
+ of this class in one of the following valid states:
+ a. MYSQL_TIMESTAMP_DATETIME - a DATETIME with all members properly set
+ b. MYSQL_TIMESTAMP_NONE - an undefined value.
+ Other MYSQL_TIMESTAMP_XXX are not possible.
+ MYSQL_TIMESTAMP_DATETIME with MYSQL_TIME members
+ improperly set is not possible.
+*/
+class Datetime: public Temporal_with_date
+{
+ bool is_valid_value_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE || is_valid_datetime_slow();
+ }
+ bool is_valid_datetime_slow() const
+ {
+ DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME);
+ return !check_datetime_range(this);
+ }
+public:
+ Datetime(THD *thd, Item *item, sql_mode_t flags)
+ :Temporal_with_date(thd, item, flags)
+ {
+ if (time_type == MYSQL_TIMESTAMP_DATE)
+ date_to_datetime(this);
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ bool is_valid_datetime() const
+ {
+ /*
+ Here we quickly check for the type only.
+ If the type is valid, the rest of value must also be valid.
+ */
+ DBUG_ASSERT(is_valid_value_slow());
+ return time_type == MYSQL_TIMESTAMP_DATETIME;
+ }
+ bool hhmmssff_is_zero() const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return hour == 0 && minute == 0 && second == 0 && second_part == 0;
+ }
+ const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return this;
+ }
+ bool copy_to_mysql_time(MYSQL_TIME *ltime) const
+ {
+ if (time_type == MYSQL_TIMESTAMP_NONE)
+ {
+ ltime->time_type= MYSQL_TIMESTAMP_NONE;
+ return true;
+ }
+ DBUG_ASSERT(is_valid_datetime_slow());
+ *ltime= *this;
+ return false;
+ }
+ /**
+ Copy without data loss, with an optional DATETIME to DATE conversion.
+ If the value of the "type" argument is MYSQL_TIMESTAMP_DATE,
+ then "this" must be a datetime with a zero hhmmssff part.
+ */
+ bool copy_to_mysql_time(MYSQL_TIME *ltime, timestamp_type type)
+ {
+ DBUG_ASSERT(type == MYSQL_TIMESTAMP_DATE ||
+ type == MYSQL_TIMESTAMP_DATETIME);
+ if (copy_to_mysql_time(ltime))
+ return true;
+ DBUG_ASSERT(type != MYSQL_TIMESTAMP_DATE || hhmmssff_is_zero());
+ ltime->time_type= type;
+ return false;
+ }
+};
+
/*
Flags for collation aggregation modes, used in TDCollation::agg():
@@ -2234,6 +2459,18 @@ public:
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
+ String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
+ String *) const;
+ double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+ const;
+ longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+ const;
+ my_decimal *Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *,
+ my_decimal *) const;
+ bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ MYSQL_TIME *,
+ ulonglong fuzzydate) const;
bool Item_func_min_max_get_date(Item_func_min_max*,
MYSQL_TIME *, ulonglong fuzzydate) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;