summaryrefslogtreecommitdiffstats
path: root/sql/sql_type.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_type.cc')
-rw-r--r--sql/sql_type.cc9437
1 files changed, 9437 insertions, 0 deletions
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
new file mode 100644
index 00000000..118dcaf9
--- /dev/null
+++ b/sql/sql_type.cc
@@ -0,0 +1,9437 @@
+/*
+ Copyright (c) 2015, 2020, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "mariadb.h"
+#include "sql_type.h"
+#include "sql_type_geom.h"
+#include "sql_const.h"
+#include "sql_class.h"
+#include "sql_time.h"
+#include "sql_string.h"
+#include "item.h"
+#include "log.h"
+#include "tztime.h"
+#include <mysql/plugin_data_type.h>
+
+
+const DTCollation &DTCollation_numeric::singleton()
+{
+ static const DTCollation_numeric tmp;
+ return tmp;
+}
+
+Named_type_handler<Type_handler_row> type_handler_row("row");
+
+Named_type_handler<Type_handler_null> type_handler_null("null");
+
+Named_type_handler<Type_handler_bool> type_handler_bool("boolean");
+Named_type_handler<Type_handler_tiny> type_handler_stiny("tinyint");
+Named_type_handler<Type_handler_short> type_handler_sshort("smallint");
+Named_type_handler<Type_handler_long> type_handler_slong("int");
+Named_type_handler<Type_handler_int24> type_handler_sint24("mediumint");
+Named_type_handler<Type_handler_longlong> type_handler_slonglong("bigint");
+Named_type_handler<Type_handler_utiny> type_handler_utiny("tiny unsigned");
+Named_type_handler<Type_handler_ushort> type_handler_ushort("smallint unsigned");
+Named_type_handler<Type_handler_ulong> type_handler_ulong("int unsigned");
+Named_type_handler<Type_handler_uint24> type_handler_uint24("mediumint unsigned");
+Named_type_handler<Type_handler_ulonglong> type_handler_ulonglong("bigint unsigned");
+Named_type_handler<Type_handler_vers_trx_id> type_handler_vers_trx_id("bigint unsigned");
+Named_type_handler<Type_handler_float> type_handler_float("float");
+Named_type_handler<Type_handler_double> type_handler_double("double");
+Named_type_handler<Type_handler_bit> type_handler_bit("bit");
+
+Named_type_handler<Type_handler_olddecimal> type_handler_olddecimal("decimal");
+Named_type_handler<Type_handler_newdecimal> type_handler_newdecimal("decimal");
+
+Named_type_handler<Type_handler_year> type_handler_year("year");
+Named_type_handler<Type_handler_year> type_handler_year2("year");
+Named_type_handler<Type_handler_time> type_handler_time("time");
+Named_type_handler<Type_handler_date> type_handler_date("date");
+Named_type_handler<Type_handler_timestamp> type_handler_timestamp("timestamp");
+Named_type_handler<Type_handler_timestamp2> type_handler_timestamp2("timestamp");
+Named_type_handler<Type_handler_datetime> type_handler_datetime("datetime");
+Named_type_handler<Type_handler_time2> type_handler_time2("time");
+Named_type_handler<Type_handler_newdate> type_handler_newdate("date");
+Named_type_handler<Type_handler_datetime2> type_handler_datetime2("datetime");
+
+Named_type_handler<Type_handler_enum> type_handler_enum("enum");
+Named_type_handler<Type_handler_set> type_handler_set("set");
+
+Named_type_handler<Type_handler_string> type_handler_string("char");
+Named_type_handler<Type_handler_var_string> type_handler_var_string("varchar");
+Named_type_handler<Type_handler_varchar> type_handler_varchar("varchar");
+Named_type_handler<Type_handler_hex_hybrid> type_handler_hex_hybrid("hex_hybrid");
+Named_type_handler<Type_handler_varchar_compressed> type_handler_varchar_compressed("varchar");
+
+Named_type_handler<Type_handler_tiny_blob> type_handler_tiny_blob("tinyblob");
+Named_type_handler<Type_handler_medium_blob> type_handler_medium_blob("mediumblob");
+Named_type_handler<Type_handler_long_blob> type_handler_long_blob("longblob");
+Named_type_handler<Type_handler_blob> type_handler_blob("blob");
+Named_type_handler<Type_handler_blob_compressed> type_handler_blob_compressed("blob");
+
+Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
+
+Vers_type_timestamp vers_type_timestamp;
+Vers_type_trx vers_type_trx;
+
+/***************************************************************************/
+
+
+
+class Type_collection_std: public Type_collection
+{
+public:
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return Type_handler::aggregate_for_result_traditional(a, b);
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+};
+
+
+static Type_collection_std type_collection_std;
+
+const Type_collection *Type_handler::type_collection() const
+{
+ return &type_collection_std;
+}
+
+
+bool Type_handler::is_traditional_scalar_type() const
+{
+ return type_collection() == &type_collection_std;
+}
+
+
+class Type_collection_row: public Type_collection
+{
+public:
+ bool init(Type_handler_data *data) override
+ {
+ return false;
+ }
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ DBUG_ASSERT(a == &type_handler_row);
+ DBUG_ASSERT(b == &type_handler_row);
+ return &type_handler_row;
+ }
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+};
+
+
+static Type_collection_row type_collection_row;
+
+const Type_collection *Type_handler_row::type_collection() const
+{
+ return &type_collection_row;
+}
+
+
+bool Type_handler_data::init()
+{
+#ifdef HAVE_SPATIAL
+ return type_collection_geometry.init(this);
+#endif
+ return false;
+}
+
+
+Schema *Type_handler::schema() const
+{
+ return &mariadb_schema;
+}
+
+
+const Type_handler *
+Type_handler::handler_by_name(THD *thd, const LEX_CSTRING &name)
+{
+ plugin_ref plugin;
+ if ((plugin= my_plugin_lock_by_name(thd, &name, MariaDB_DATA_TYPE_PLUGIN)))
+ {
+ /*
+ Data type plugins do not maintain ref_count yet.
+ For now we have only mandatory built-in plugins
+ and dynamic plugins for test purposes.
+ It should be safe to unlock the plugin immediately.
+ */
+ const Type_handler *ph= reinterpret_cast<st_mariadb_data_type*>
+ (plugin_decl(plugin)->info)->type_handler;
+ plugin_unlock(thd, plugin);
+ return ph;
+ }
+
+#ifdef HAVE_SPATIAL
+ const Type_handler *ha= type_collection_geometry.handler_by_name(name);
+ if (ha)
+ return ha;
+#endif
+ return NULL;
+}
+
+
+#ifndef DBUG_OFF
+static const Type_handler *frm_data_type_info_emulate(const LEX_CSTRING &name)
+{
+ if (Name(STRING_WITH_LEN("xchar")).eq(name))
+ return &type_handler_string;
+ if (Name(STRING_WITH_LEN("xblob")).eq(name))
+ return &type_handler_blob;
+ return NULL;
+}
+#endif
+
+
+const Type_handler *
+Type_handler::handler_by_name_or_error(THD *thd, const LEX_CSTRING &name)
+{
+ const Type_handler *h= handler_by_name(thd, name);
+ DBUG_EXECUTE_IF("emulate_handler_by_name_or_error_failure", h= NULL;);
+ if (!h)
+ {
+ DBUG_EXECUTE_IF("frm_data_type_info_emulate",
+ if ((h= frm_data_type_info_emulate(name)))
+ return h;
+ );
+ my_error(ER_UNKNOWN_DATA_TYPE, MYF(0),
+ ErrConvString(name.str, name.length, system_charset_info).ptr());
+ }
+ return h;
+}
+
+
+Type_handler_data *type_handler_data= NULL;
+
+
+bool Float::to_string(String *val_buffer, uint dec) const
+{
+ uint to_length= 70;
+ if (val_buffer->alloc(to_length))
+ return true;
+
+ char *to=(char*) val_buffer->ptr();
+ size_t len;
+
+ if (dec >= FLOATING_POINT_DECIMALS)
+ len= my_gcvt(m_value, MY_GCVT_ARG_FLOAT, to_length - 1, to, NULL);
+ else
+ {
+ /*
+ We are safe here because the buffer length is 70, and
+ fabs(float) < 10^39, dec < FLOATING_POINT_DECIMALS. So the resulting string
+ will be not longer than 69 chars + terminating '\0'.
+ */
+ len= my_fcvt(m_value, (int) dec, to, NULL);
+ }
+ val_buffer->length((uint) len);
+ val_buffer->set_charset(&my_charset_numeric);
+ return false;
+}
+
+
+String_ptr::String_ptr(Item *item, String *buffer)
+ :m_string_ptr(item->val_str(buffer))
+{ }
+
+
+Ascii_ptr::Ascii_ptr(Item *item, String *buffer)
+ :String_ptr(item->val_str_ascii(buffer))
+{ }
+
+
+void VDec::set(Item *item)
+{
+ m_ptr= item->val_decimal(&m_buffer);
+ DBUG_ASSERT((m_ptr == NULL) == item->null_value);
+}
+
+
+VDec::VDec(Item *item)
+{
+ m_ptr= item->val_decimal(&m_buffer);
+ DBUG_ASSERT((m_ptr == NULL) == item->null_value);
+}
+
+
+VDec_op::VDec_op(Item_func_hybrid_field_type *item)
+{
+ m_ptr= item->decimal_op(&m_buffer);
+ DBUG_ASSERT((m_ptr == NULL) == item->null_value);
+}
+
+
+date_conv_mode_t Temporal::sql_mode_for_dates(THD *thd)
+{
+ return ::sql_mode_for_dates(thd);
+}
+
+
+time_round_mode_t Temporal::default_round_mode(THD *thd)
+{
+ return thd->temporal_round_mode();
+}
+
+
+time_round_mode_t Timestamp::default_round_mode(THD *thd)
+{
+ return thd->temporal_round_mode();
+}
+
+
+my_decimal *Temporal::to_decimal(my_decimal *to) const
+{
+ return date2my_decimal(this, to);
+}
+
+
+my_decimal *Temporal::bad_to_decimal(my_decimal *to) const
+{
+ my_decimal_set_zero(to);
+ return NULL;
+}
+
+
+void Temporal::make_from_str(THD *thd, Warn *warn,
+ const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate)
+{
+ DBUG_EXECUTE_IF("str_to_datetime_warn",
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_YES, ErrConvString(str, length,cs).ptr()););
+
+ if (str_to_temporal(thd, warn, str, length, cs, fuzzydate))
+ make_fuzzy_date(&warn->warnings, date_conv_mode_t(fuzzydate));
+ if (warn->warnings)
+ warn->set_str(str, length, &my_charset_bin);
+}
+
+
+Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate)
+{
+ if (item->get_date(thd, this, fuzzydate))
+ time_type= MYSQL_TIMESTAMP_NONE;
+}
+
+
+uint Timestamp::binary_length_to_precision(uint length)
+{
+ switch (length) {
+ case 4: return 0;
+ case 5: return 2;
+ case 6: return 4;
+ case 7: return 6;
+ }
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+Timestamp::Timestamp(const Native &native)
+{
+ DBUG_ASSERT(native.length() >= 4 && native.length() <= 7);
+ uint dec= binary_length_to_precision(native.length());
+ my_timestamp_from_binary(this, (const uchar *) native.ptr(), dec);
+}
+
+
+bool Timestamp::to_native(Native *to, uint decimals) const
+{
+ uint len= my_timestamp_binary_length(decimals);
+ if (to->reserve(len))
+ return true;
+ my_timestamp_to_binary(this, (uchar *) to->ptr(), decimals);
+ to->length(len);
+ return false;
+}
+
+
+bool Timestamp::to_TIME(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) const
+{
+ return thd->timestamp_to_TIME(to, tv_sec, tv_usec, fuzzydate);
+}
+
+
+Timestamp::Timestamp(THD *thd, const MYSQL_TIME *ltime, uint *error_code)
+ :Timeval(TIME_to_timestamp(thd, ltime, error_code), ltime->second_part)
+{ }
+
+
+Timestamp_or_zero_datetime::Timestamp_or_zero_datetime(THD *thd,
+ const MYSQL_TIME *ltime,
+ uint *error_code)
+ :Timestamp(thd, ltime, error_code),
+ m_is_zero_datetime(*error_code == ER_WARN_DATA_OUT_OF_RANGE)
+{
+ if (m_is_zero_datetime)
+ {
+ if (!non_zero_date(ltime))
+ *error_code= 0; // ltime was '0000-00-00 00:00:00'
+ }
+ else if (*error_code == ER_WARN_INVALID_TIMESTAMP)
+ *error_code= 0; // ltime fell into spring time gap, adjusted.
+}
+
+
+bool Timestamp_or_zero_datetime::to_TIME(THD *thd, MYSQL_TIME *to,
+ date_mode_t fuzzydate) const
+{
+ if (m_is_zero_datetime)
+ {
+ set_zero_time(to, MYSQL_TIMESTAMP_DATETIME);
+ return false;
+ }
+ return Timestamp::to_TIME(thd, to, fuzzydate);
+}
+
+
+bool Timestamp_or_zero_datetime::to_native(Native *to, uint decimals) const
+{
+ if (m_is_zero_datetime)
+ {
+ to->length(0);
+ return false;
+ }
+ return Timestamp::to_native(to, decimals);
+}
+
+
+int Timestamp_or_zero_datetime_native::save_in_field(Field *field,
+ uint decimals) const
+{
+ field->set_notnull();
+ if (field->type_handler()->type_handler_for_native_format() ==
+ &type_handler_timestamp2)
+ return field->store_native(*this);
+ if (is_zero_datetime())
+ {
+ static Datetime zero(Datetime::zero());
+ return field->store_time_dec(zero.get_mysql_time(), decimals);
+ }
+ return field->store_timestamp_dec(Timestamp(*this).tv(), decimals);
+}
+
+
+void Sec6::make_from_decimal(const my_decimal *d, ulong *nanoseconds)
+{
+ m_neg= my_decimal2seconds(d, &m_sec, &m_usec, nanoseconds);
+ m_truncated= (m_sec >= LONGLONG_MAX);
+}
+
+
+void Sec6::make_from_double(double nr, ulong *nanoseconds)
+{
+ if ((m_neg= nr < 0))
+ nr= -nr;
+ if ((m_truncated= nr > (double) LONGLONG_MAX))
+ {
+ m_sec= LONGLONG_MAX;
+ m_usec= 0;
+ *nanoseconds= 0;
+ }
+ else
+ {
+ m_sec= (ulonglong) nr;
+ m_usec= (ulong) ((nr - floor(nr)) * 1000000000);
+ *nanoseconds= m_usec % 1000;
+ m_usec/= 1000;
+ }
+}
+
+
+void Sec6::make_truncated_warning(THD *thd, const char *type_str) const
+{
+ char buff[1 + MAX_BIGINT_WIDTH + 1 + 6 + 1]; // '-' int '.' frac '\0'
+ to_string(buff, sizeof(buff));
+ thd->push_warning_truncated_wrong_value(type_str, buff);
+}
+
+
+bool Sec6::convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ bool rc= fuzzydate & (TIME_INTERVAL_hhmmssff | TIME_INTERVAL_DAY) ?
+ to_datetime_or_to_interval_hhmmssff(ltime, warn) :
+ fuzzydate & TIME_TIME_ONLY ?
+ to_datetime_or_time(ltime, warn, date_conv_mode_t(fuzzydate)) :
+ to_datetime_or_date(ltime, warn, date_conv_mode_t(fuzzydate));
+ DBUG_ASSERT(*warn || !rc);
+ if (truncated())
+ *warn|= MYSQL_TIME_WARN_TRUNCATED;
+ return rc;
+}
+
+
+void Temporal::push_conversion_warnings(THD *thd, bool totally_useless_value,
+ int warn,
+ const char *typestr,
+ const char *db_name,
+ const char *table_name,
+ const char *field_name,
+ const char *value)
+{
+ if (MYSQL_TIME_WARN_HAVE_WARNINGS(warn))
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ totally_useless_value,
+ typestr, value,
+ db_name, table_name,
+ field_name);
+ else if (MYSQL_TIME_WARN_HAVE_NOTES(warn))
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE,
+ false, typestr, value,
+ db_name, table_name,
+ field_name);
+}
+
+
+VSec9::VSec9(THD *thd, Item *item, const char *type_str, ulonglong limit)
+{
+ if (item->decimals == 0)
+ { // optimize for an important special case
+ Longlong_hybrid nr(item->val_int(), item->unsigned_flag);
+ make_from_int(nr);
+ m_is_null= item->null_value;
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ ErrConvInteger err(nr);
+ thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ }
+ }
+ else if (item->cmp_type() == REAL_RESULT)
+ {
+ double nr= item->val_real();
+ make_from_double(nr, &m_nsec);
+ m_is_null= item->null_value;
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ }
+ if (m_truncated)
+ {
+ ErrConvDouble err(nr);
+ thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ }
+ }
+ else
+ {
+ VDec tmp(item);
+ (m_is_null= tmp.is_null()) ? reset() : make_from_decimal(tmp.ptr(), &m_nsec);
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ }
+ if (m_truncated)
+ {
+ ErrConvDecimal err(tmp.ptr());
+ thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ }
+ }
+}
+
+
+Year::Year(longlong value, bool unsigned_flag, uint length)
+{
+ if ((m_truncated= (value < 0))) // Negative or huge unsigned
+ m_year= unsigned_flag ? 9999 : 0;
+ else if (value > 9999)
+ {
+ m_truncated= true;
+ m_year= 9999;
+ }
+ else if (length == 2)
+ {
+ m_year= value < 70 ? (uint) value + 2000 :
+ value <= 1900 ? (uint) value + 1900 :
+ (uint) value;
+ }
+ else
+ m_year= (uint) value;
+ DBUG_ASSERT(m_year <= 9999);
+}
+
+
+uint Year::year_precision(const Item *item) const
+{
+ return item->type_handler() == &type_handler_year2 ? 2 : 4;
+}
+
+
+VYear::VYear(Item *item)
+ :Year_null(item->to_longlong_null(), item->unsigned_flag, year_precision(item))
+{ }
+
+
+VYear_op::VYear_op(Item_func_hybrid_field_type *item)
+ :Year_null(item->to_longlong_null_op(), item->unsigned_flag,
+ year_precision(item))
+{ }
+
+
+const LEX_CSTRING Interval_DDhhmmssff::m_type_name=
+ {STRING_WITH_LEN("INTERVAL DAY TO SECOND")};
+
+
+Interval_DDhhmmssff::Interval_DDhhmmssff(THD *thd, Status *st,
+ bool push_warnings,
+ Item *item, ulong max_hour,
+ time_round_mode_t mode, uint dec)
+{
+ switch (item->cmp_type()) {
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ time_type= MYSQL_TIMESTAMP_NONE;
+ break;
+ case TIME_RESULT:
+ {
+ // Rounding mode is not important here
+ if (item->get_date(thd, this, Options(TIME_TIME_ONLY, TIME_FRAC_NONE)))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (time_type != MYSQL_TIMESTAMP_TIME)
+ {
+ st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ push_warning_wrong_or_truncated_value(thd, ErrConvTime(this),
+ st->warnings);
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ break;
+ }
+ case INT_RESULT:
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ case STRING_RESULT:
+ {
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp;
+ String *str= item->val_str(&tmp);
+ if (!str)
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (str_to_DDhhmmssff(st, str->ptr(), str->length(), str->charset(),
+ UINT_MAX32))
+ {
+ if (push_warnings)
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str,
+ ErrConvString(str).ptr());
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ else
+ {
+ if (mode == TIME_FRAC_ROUND)
+ time_round_or_set_max(dec, &st->warnings, max_hour, st->nanoseconds);
+ if (hour > max_hour)
+ {
+ st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ // Warn if hour or nanosecond truncation happened
+ if (push_warnings)
+ push_warning_wrong_or_truncated_value(thd, ErrConvString(str),
+ st->warnings);
+ }
+ }
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+
+void
+Interval_DDhhmmssff::push_warning_wrong_or_truncated_value(THD *thd,
+ const ErrConv &str,
+ int warnings)
+{
+ if (warnings & MYSQL_TIME_WARN_OUT_OF_RANGE)
+ {
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str, str.ptr());
+ }
+ else if (MYSQL_TIME_WARN_HAVE_WARNINGS(warnings))
+ {
+ thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str, str.ptr());
+ }
+ else if (MYSQL_TIME_WARN_HAVE_NOTES(warnings))
+ {
+ thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_NOTE,
+ m_type_name.str, str.ptr());
+ }
+}
+
+
+uint Interval_DDhhmmssff::fsp(THD *thd, Item *item)
+{
+ switch (item->cmp_type()) {
+ case INT_RESULT:
+ case TIME_RESULT:
+ return item->decimals;
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ return 0;
+ case STRING_RESULT:
+ break;
+ }
+ if (!item->const_item() || item->is_expensive())
+ return TIME_SECOND_PART_DIGITS;
+ Status st;
+ Interval_DDhhmmssff it(thd, &st, false/*no warnings*/, item, UINT_MAX32,
+ TIME_FRAC_TRUNCATE, TIME_SECOND_PART_DIGITS);
+ return it.is_valid_interval_DDhhmmssff() ? st.precision :
+ TIME_SECOND_PART_DIGITS;
+}
+
+
+bool Time::to_native(Native *to, uint decimals) const
+{
+ if (!is_valid_time())
+ {
+ to->length(0);
+ return true;
+ }
+ uint len= my_time_binary_length(decimals);
+ if (to->reserve(len))
+ return true;
+ longlong tmp= TIME_to_longlong_time_packed(get_mysql_time());
+ my_time_packed_to_binary(tmp, (uchar*) to->ptr(), decimals);
+ to->length(len);
+ return false;
+}
+
+
+void Time::make_from_item(THD *thd, int *warn, Item *item, const Options opt)
+{
+ *warn= 0;
+ if (item->get_date(thd, this, opt))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else
+ valid_MYSQL_TIME_to_valid_value(thd, warn, opt);
+}
+
+
+static uint msec_round_add[7]=
+{
+ 500000000,
+ 50000000,
+ 5000000,
+ 500000,
+ 50000,
+ 5000,
+ 0
+};
+
+
+Sec9 & Sec9::round(uint dec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ if (Sec6::add_nanoseconds(m_nsec + msec_round_add[dec]))
+ m_sec++;
+ m_nsec= 0;
+ Sec6::trunc(dec);
+ return *this;
+}
+
+
+void Timestamp::round_or_set_max(uint dec, int *warn)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ if (add_nanoseconds_usec(msec_round_add[dec]) &&
+ tv_sec++ >= TIMESTAMP_MAX_VALUE)
+ {
+ tv_sec= TIMESTAMP_MAX_VALUE;
+ tv_usec= TIME_MAX_SECOND_PART;
+ *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ }
+ my_timeval_trunc(this, dec);
+}
+
+
+bool Temporal::add_nanoseconds_with_round(THD *thd, int *warn,
+ date_conv_mode_t mode,
+ ulong nsec)
+{
+ switch (time_type) {
+ case MYSQL_TIMESTAMP_TIME:
+ {
+ ulong max_hour= (mode & (TIME_INTERVAL_DAY | TIME_INTERVAL_hhmmssff)) ?
+ TIME_MAX_INTERVAL_HOUR : TIME_MAX_HOUR;
+ time_round_or_set_max(6, warn, max_hour, nsec);
+ return false;
+ }
+ case MYSQL_TIMESTAMP_DATETIME:
+ return datetime_round_or_invalidate(thd, 6, warn, nsec);
+ case MYSQL_TIMESTAMP_DATE:
+ return false;
+ case MYSQL_TIMESTAMP_NONE:
+ return false;
+ case MYSQL_TIMESTAMP_ERROR:
+ break;
+ }
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+void Temporal::time_round_or_set_max(uint dec, int *warn,
+ ulong max_hour, ulong nsec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ if (add_nanoseconds_mmssff(nsec) && ++hour > max_hour)
+ {
+ time_hhmmssff_set_max(max_hour);
+ *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ }
+ my_time_trunc(this, dec);
+}
+
+
+void Time::round_or_set_max(uint dec, int *warn, ulong nsec)
+{
+ Temporal::time_round_or_set_max(dec, warn, TIME_MAX_HOUR, nsec);
+ DBUG_ASSERT(is_valid_time_slow());
+}
+
+
+void Time::round_or_set_max(uint dec, int *warn)
+{
+ round_or_set_max(dec, warn, msec_round_add[dec]);
+}
+
+/**
+ Create from a DATETIME by subtracting a given number of days,
+ implementing an optimized version of calc_time_diff().
+*/
+void Time::make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
+ long days)
+{
+ *warn= 0;
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATETIME ||
+ from->time_type == MYSQL_TIMESTAMP_DATE);
+ long daynr= calc_daynr(from->year, from->month, from->day);
+ long daydiff= daynr - days;
+ if (!daynr) // Zero date
+ {
+ set_zero_time(this, MYSQL_TIMESTAMP_TIME);
+ neg= true;
+ hour= TIME_MAX_HOUR + 1; // to report "out of range" in "warn"
+ }
+ else if (daydiff >=0)
+ {
+ neg= false;
+ year= month= day= 0;
+ hhmmssff_copy(from);
+ hour+= daydiff * 24;
+ time_type= MYSQL_TIMESTAMP_TIME;
+ }
+ else
+ {
+ longlong timediff= ((((daydiff * 24LL +
+ from->hour) * 60LL +
+ from->minute) * 60LL +
+ from->second) * 1000000LL +
+ from->second_part);
+ unpack_time(timediff, this, MYSQL_TIMESTAMP_TIME);
+ if (year || month)
+ {
+ *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ year= month= day= 0;
+ hour= TIME_MAX_HOUR + 1;
+ }
+ }
+ // The above code can generate TIME values outside of the valid TIME range.
+ adjust_time_range_or_invalidate(warn);
+}
+
+
+void Time::make_from_datetime_move_day_to_hour(int *warn,
+ const MYSQL_TIME *from)
+{
+ *warn= 0;
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
+ from->time_type == MYSQL_TIMESTAMP_DATETIME);
+ time_type= MYSQL_TIMESTAMP_TIME;
+ neg= false;
+ year= month= day= 0;
+ hhmmssff_copy(from);
+ datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, from->year,
+ from->month, from->day);
+ adjust_time_range_or_invalidate(warn);
+}
+
+
+void Time::make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays)
+{
+ if (!curdays)
+ make_from_datetime_move_day_to_hour(warn, from);
+ else
+ make_from_datetime_with_days_diff(warn, from, curdays);
+}
+
+
+void Time::make_from_time(int *warn, const MYSQL_TIME *from)
+{
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
+ if (from->year || from->month)
+ make_from_out_of_range(warn);
+ else
+ {
+ *warn= 0;
+ DBUG_ASSERT(from->day == 0);
+ *(static_cast<MYSQL_TIME*>(this))= *from;
+ adjust_time_range_or_invalidate(warn);
+ }
+}
+
+
+uint Time::binary_length_to_precision(uint length)
+{
+ switch (length) {
+ case 3: return 0;
+ case 4: return 2;
+ case 5: return 4;
+ case 6: return 6;
+ }
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+Time::Time(const Native &native)
+{
+ uint dec= binary_length_to_precision(native.length());
+ longlong tmp= my_time_packed_from_binary((const uchar *) native.ptr(), dec);
+ TIME_from_longlong_time_packed(this, tmp);
+ DBUG_ASSERT(is_valid_time());
+}
+
+
+Time::Time(int *warn, const MYSQL_TIME *from, long curdays)
+{
+ switch (from->time_type) {
+ case MYSQL_TIMESTAMP_NONE:
+ case MYSQL_TIMESTAMP_ERROR:
+ make_from_out_of_range(warn);
+ break;
+ case MYSQL_TIMESTAMP_DATE:
+ case MYSQL_TIMESTAMP_DATETIME:
+ make_from_datetime(warn, from, curdays);
+ break;
+ case MYSQL_TIMESTAMP_TIME:
+ make_from_time(warn, from);
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+
+Time::Time(int *warn, bool neg, ulonglong hour, uint minute, const Sec6 &second)
+{
+ DBUG_ASSERT(second.sec() <= 59);
+ *warn= 0;
+ set_zero_time(this, MYSQL_TIMESTAMP_TIME);
+ MYSQL_TIME::neg= neg;
+ MYSQL_TIME::hour= hour > TIME_MAX_HOUR ? (uint) (TIME_MAX_HOUR + 1) :
+ (uint) hour;
+ MYSQL_TIME::minute= minute;
+ MYSQL_TIME::second= (uint) second.sec();
+ MYSQL_TIME::second_part= second.usec();
+ adjust_time_range_or_invalidate(warn);
+}
+
+
+void Temporal_with_date::make_from_item(THD *thd, Item *item,
+ date_mode_t fuzzydate)
+{
+ date_conv_mode_t flags= date_conv_mode_t(fuzzydate) & ~TIME_TIME_ONLY;
+ /*
+ Some TIME type items return error when trying to do get_date()
+ without TIME_TIME_ONLY set (e.g. Item_field for Field_time).
+ In the SQL standard time->datetime conversion mode we add TIME_TIME_ONLY.
+ In the legacy time->datetime conversion mode we do not add TIME_TIME_ONLY
+ and leave it to get_date() to check date.
+ */
+ date_conv_mode_t time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
+ !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
+ TIME_TIME_ONLY : TIME_CONV_NONE;
+ Options opt(flags | time_flag, time_round_mode_t(fuzzydate));
+ if (item->get_date(thd, this, opt))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (time_type == MYSQL_TIMESTAMP_TIME)
+ {
+ MYSQL_TIME tmp;
+ if (time_to_datetime_with_warn(thd, this, &tmp, flags))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else
+ *(static_cast<MYSQL_TIME*>(this))= tmp;
+ }
+}
+
+
+void Temporal_with_date::check_date_or_invalidate(int *warn,
+ date_conv_mode_t flags)
+{
+ if (::check_date(this, pack_time(this) != 0,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+}
+
+
+void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_conv_mode_t flags)
+{
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
+ if (time_to_datetime(thd, from, this))
+ make_from_out_of_range(warn);
+ else
+ {
+ *warn= 0;
+ check_date_or_invalidate(warn, flags);
+ }
+}
+
+
+void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_conv_mode_t flags)
+{
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
+ from->time_type == MYSQL_TIMESTAMP_DATETIME);
+ if (from->neg || check_datetime_range(from))
+ make_from_out_of_range(warn);
+ else
+ {
+ *warn= 0;
+ *(static_cast<MYSQL_TIME*>(this))= *from;
+ date_to_datetime(this);
+ check_date_or_invalidate(warn, flags);
+ }
+}
+
+
+Datetime::Datetime(THD *thd, const timeval &tv)
+{
+ thd->variables.time_zone->gmt_sec_to_TIME(this, tv.tv_sec);
+ second_part= tv.tv_usec;
+ thd->time_zone_used= 1;
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+
+Datetime::Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_conv_mode_t flags)
+{
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
+ switch (from->time_type) {
+ case MYSQL_TIMESTAMP_ERROR:
+ case MYSQL_TIMESTAMP_NONE:
+ make_from_out_of_range(warn);
+ break;
+ case MYSQL_TIMESTAMP_TIME:
+ make_from_time(thd, warn, from, flags);
+ break;
+ case MYSQL_TIMESTAMP_DATETIME:
+ case MYSQL_TIMESTAMP_DATE:
+ make_from_datetime(thd, warn, from, flags);
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+Datetime::Datetime(my_time_t unix_time, ulong second_part_arg,
+ const Time_zone* time_zone)
+{
+ time_zone->gmt_sec_to_TIME(this, unix_time);
+ second_part= second_part_arg;
+}
+
+
+bool Temporal::datetime_add_nanoseconds_or_invalidate(THD *thd, int *warn, ulong nsec)
+{
+ if (!add_nanoseconds_mmssff(nsec))
+ return false;
+ /*
+ Overflow happened on minutes. Now we need to add 1 hour to the value.
+ Catch a special case for the maximum possible date and hour==23, to
+ truncate '9999-12-31 23:59:59.9999999' (with 7 fractional digits)
+ to '9999-12-31 23:59:59.999999' (with 6 fractional digits),
+ with a warning, instead of returning an error, so this statement:
+ INSERT INTO (datetime_column) VALUES ('9999-12-31 23:59:59.9999999');
+ inserts a value truncated to 6 fractional digits, instead of zero
+ date '0000-00-00 00:00:00.000000'.
+ */
+ if (year == 9999 && month == 12 && day == 31 && hour == 23)
+ {
+ minute= 59;
+ second= 59;
+ second_part= 999999;
+ *warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ return false;
+ }
+ INTERVAL interval;
+ memset(&interval, 0, sizeof(interval));
+ interval.hour= 1;
+ /*
+ date_add_interval cannot handle bad dates with zero YYYY or MM.
+ Note, check_date(NO_ZERO_XX) does not check YYYY against zero,
+ so let's additionally check it.
+ */
+ if (year == 0 ||
+ check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE, warn) ||
+ date_add_interval(thd, this, INTERVAL_HOUR, interval, false/*no warn*/))
+ {
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ my_date_to_str(this, buf);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_TYPE,
+ ER_THD(thd, ER_WRONG_VALUE_FOR_TYPE),
+ "date", buf, "round(datetime)");
+ make_from_out_of_range(warn);
+ return true;
+ }
+ return false;
+}
+
+
+bool Temporal::datetime_round_or_invalidate(THD *thd, uint dec, int *warn, ulong nsec)
+{
+ DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
+ if (datetime_add_nanoseconds_or_invalidate(thd, warn, nsec))
+ return true;
+ my_datetime_trunc(this, dec);
+ return false;
+
+}
+
+
+bool Datetime::round_or_invalidate(THD *thd, uint dec, int *warn)
+{
+ return round_or_invalidate(thd, dec, warn, msec_round_add[dec]);
+}
+
+
+Datetime_from_temporal::Datetime_from_temporal(THD *thd, Item *temporal,
+ date_conv_mode_t fuzzydate)
+ :Datetime(thd, temporal, Options(fuzzydate, TIME_FRAC_NONE))
+{
+ // Exact rounding mode does not matter
+ DBUG_ASSERT(temporal->cmp_type() == TIME_RESULT);
+}
+
+
+Datetime_truncation_not_needed::Datetime_truncation_not_needed(THD *thd, Item *item,
+ date_conv_mode_t mode)
+ :Datetime(thd, item, Options(mode, TIME_FRAC_NONE))
+{
+ /*
+ The called Datetime() constructor only would truncate nanoseconds if they
+ existed (but we know there were no nanoseconds). Here we assert that there
+ are also no microsecond digits outside of the scale specified in "dec".
+ */
+ DBUG_ASSERT(!is_valid_datetime() ||
+ fraction_remainder(MY_MIN(item->decimals,
+ TIME_SECOND_PART_DIGITS)) == 0);
+}
+
+/********************************************************************/
+
+uint Type_numeric_attributes::find_max_decimals(Item **item, uint nitems)
+{
+ uint res= 0;
+ for (uint i= 0; i < nitems; i++)
+ set_if_bigger(res, item[i]->decimals);
+ return res;
+}
+
+
+uint Type_numeric_attributes::count_unsigned(Item **item, uint nitems)
+{
+ uint res= 0;
+ for (uint i= 0 ; i < nitems ; i++)
+ {
+ if (item[i]->unsigned_flag)
+ res++;
+ }
+ return res;
+}
+
+
+uint32 Type_numeric_attributes::find_max_char_length(Item **item, uint nitems)
+{
+ uint32 char_length= 0;
+ for (uint i= 0; i < nitems ; i++)
+ set_if_bigger(char_length, item[i]->max_char_length());
+ return char_length;
+}
+
+
+uint32 Type_numeric_attributes::find_max_octet_length(Item **item, uint nitems)
+{
+ uint32 octet_length= 0;
+ for (uint i= 0; i < nitems ; i++)
+ set_if_bigger(octet_length, item[i]->max_length);
+ return octet_length;
+}
+
+
+int Type_numeric_attributes::find_max_decimal_int_part(Item **item, uint nitems)
+{
+ int max_int_part= 0;
+ for (uint i=0 ; i < nitems ; i++)
+ set_if_bigger(max_int_part, item[i]->decimal_int_part());
+ return max_int_part;
+}
+
+
+/**
+ Set max_length/decimals of function if function is fixed point and
+ result length/precision depends on argument ones.
+*/
+
+void
+Type_numeric_attributes::aggregate_numeric_attributes_decimal(Item **item,
+ uint nitems,
+ bool unsigned_arg)
+{
+ int max_int_part= find_max_decimal_int_part(item, nitems);
+ decimals= find_max_decimals(item, nitems);
+ int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ (uint8) decimals,
+ unsigned_flag);
+}
+
+
+/**
+ Set max_length/decimals of function if function is floating point and
+ result length/precision depends on argument ones.
+*/
+
+void
+Type_numeric_attributes::aggregate_numeric_attributes_real(Item **items,
+ uint nitems)
+{
+ uint32 length= 0;
+ decimals= 0;
+ max_length= 0;
+ unsigned_flag= false;
+ for (uint i=0 ; i < nitems ; i++)
+ {
+ if (decimals < FLOATING_POINT_DECIMALS)
+ {
+ set_if_bigger(decimals, items[i]->decimals);
+ /* Will be ignored if items[i]->decimals >= FLOATING_POINT_DECIMALS */
+ set_if_bigger(length, (items[i]->max_length - items[i]->decimals));
+ }
+ set_if_bigger(max_length, items[i]->max_length);
+ }
+ if (decimals < FLOATING_POINT_DECIMALS)
+ {
+ max_length= length;
+ length+= decimals;
+ if (length < max_length) // If previous operation gave overflow
+ max_length= UINT_MAX32;
+ else
+ max_length= length;
+ }
+ // Corner case: COALESCE(DOUBLE(255,4), DOUBLE(255,3)) -> FLOAT(255, 4)
+ set_if_smaller(max_length, MAX_FIELD_CHARLENGTH);
+}
+
+
+/**
+ Calculate max_length and decimals for string functions.
+
+ @param field_type Field type.
+ @param items Argument array.
+ @param nitems Number of arguments.
+
+ @retval False on success, true on error.
+*/
+bool Type_std_attributes::aggregate_attributes_string(const char *func_name,
+ Item **items, uint nitems)
+{
+ if (agg_arg_charsets_for_string_result(collation, func_name,
+ items, nitems, 1))
+ return true;
+ if (collation.collation == &my_charset_bin)
+ max_length= find_max_octet_length(items, nitems);
+ else
+ fix_char_length(find_max_char_length(items, nitems));
+ unsigned_flag= false;
+ decimals= max_length ? NOT_FIXED_DEC : 0;
+ return false;
+}
+
+
+/*
+ Find a handler by its ODBC literal data type.
+
+ @param type_str - data type name, not necessarily 0-terminated
+ @retval - a pointer to data type handler if type_str points
+ to a known ODBC literal data type, or NULL otherwise
+*/
+const Type_handler *
+Type_handler::odbc_literal_type_handler(const LEX_CSTRING *type_str)
+{
+ if (type_str->length == 1)
+ {
+ if (type_str->str[0] == 'd') // {d'2001-01-01'}
+ return &type_handler_newdate;
+ else if (type_str->str[0] == 't') // {t'10:20:30'}
+ return &type_handler_time2;
+ }
+ else if (type_str->length == 2) // {ts'2001-01-01 10:20:30'}
+ {
+ if (type_str->str[0] == 't' && type_str->str[1] == 's')
+ return &type_handler_datetime2;
+ }
+ return NULL; // Not a known ODBC literal type
+}
+
+
+/**
+ This method is used by:
+ - Item_user_var_as_out_param::field_type()
+ - Item_func_udf_str::field_type()
+ - Item_empty_string::make_send_field()
+
+ TODO: type_handler_adjusted_to_max_octet_length() and string_type_handler()
+ provide very similar functionality, to properly choose between
+ VARCHAR/VARBINARY vs TEXT/BLOB variations taking into accoung maximum
+ possible octet length.
+
+ We should probably get rid of either of them and use the same method
+ all around the code.
+*/
+const Type_handler *
+Type_handler::string_type_handler(uint max_octet_length)
+{
+ if (max_octet_length >= 16777216)
+ return &type_handler_long_blob;
+ else if (max_octet_length >= 65536)
+ return &type_handler_medium_blob;
+ else if (max_octet_length >= MAX_FIELD_VARCHARLENGTH)
+ return &type_handler_blob;
+ return &type_handler_varchar;
+}
+
+
+const Type_handler *
+Type_handler::varstring_type_handler(const Item *item)
+{
+ if (!item->max_length)
+ return &type_handler_string;
+ if (item->too_big_for_varchar())
+ return blob_type_handler(item->max_length);
+ return &type_handler_varchar;
+}
+
+
+const Type_handler *
+Type_handler::blob_type_handler(uint max_octet_length)
+{
+ if (max_octet_length <= 255)
+ return &type_handler_tiny_blob;
+ if (max_octet_length <= 65535)
+ return &type_handler_blob;
+ if (max_octet_length <= 16777215)
+ return &type_handler_medium_blob;
+ return &type_handler_long_blob;
+}
+
+
+const Type_handler *
+Type_handler::blob_type_handler(const Item *item)
+{
+ return blob_type_handler(item->max_length);
+}
+
+/**
+ This method is used by:
+ - Item_sum_hybrid, e.g. MAX(item), MIN(item).
+ - Item_func_set_user_var
+*/
+const Type_handler *
+Type_handler_string_result::type_handler_adjusted_to_max_octet_length(
+ uint max_octet_length,
+ CHARSET_INFO *cs) const
+{
+ if (max_octet_length / cs->mbmaxlen <= CONVERT_IF_BIGGER_TO_BLOB)
+ return &type_handler_varchar; // See also Item::too_big_for_varchar()
+ if (max_octet_length >= 16777216)
+ return &type_handler_long_blob;
+ else if (max_octet_length >= 65536)
+ return &type_handler_medium_blob;
+ return &type_handler_blob;
+}
+
+
+CHARSET_INFO *Type_handler::charset_for_protocol(const Item *item) const
+{
+ /*
+ For backward compatibility, to make numeric
+ data types return "binary" charset in client-side metadata.
+ */
+ return &my_charset_bin;
+}
+
+
+bool
+Type_handler::Item_func_or_sum_illegal_param(const char *funcname) const
+{
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ name().ptr(), funcname);
+ return true;
+}
+
+
+bool
+Type_handler::Item_func_or_sum_illegal_param(const Item_func_or_sum *it) const
+{
+ return Item_func_or_sum_illegal_param(it->func_name());
+}
+
+
+CHARSET_INFO *
+Type_handler_string_result::charset_for_protocol(const Item *item) const
+{
+ return item->collation.collation;
+}
+
+
+const Type_handler *
+Type_handler::get_handler_by_cmp_type(Item_result type)
+{
+ switch (type) {
+ case REAL_RESULT: return &type_handler_double;
+ case INT_RESULT: return &type_handler_slonglong;
+ case DECIMAL_RESULT: return &type_handler_newdecimal;
+ case STRING_RESULT: return &type_handler_long_blob;
+ case TIME_RESULT: return &type_handler_datetime;
+ case ROW_RESULT: return &type_handler_row;
+ }
+ DBUG_ASSERT(0);
+ return &type_handler_string;
+}
+
+
+/*
+ If we have a mixture of:
+ - a MariaDB standard (built-in permanent) data type, and
+ - a non-standard (optionally compiled or pluggable) data type,
+ then we ask the type collection of the non-standard type to aggregate
+ the mixture.
+ The standard type collection type_collection_std knows nothing
+ about non-standard types, while non-standard type collections
+ know everything about standard data types.
+*/
+const Type_collection *
+Type_handler::type_collection_for_aggregation(const Type_handler *h0,
+ const Type_handler *h1)
+{
+ const Type_collection *c0= h0->type_collection();
+ const Type_collection *c1= h1->type_collection();
+ if (c0 == c1)
+ return c0;
+ if (c0 == &type_collection_std)
+ return c1;
+ if (c1 == &type_collection_std)
+ return c0;
+ /*
+ A mixture of two non-standard collections.
+ The caller code will continue to aggregate through
+ the type aggregators in Type_handler_data.
+ */
+ return NULL;
+}
+
+
+Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
+ :m_type_handler(&type_handler_double)
+{
+}
+
+
+/***************************************************************************/
+
+/* number of bytes to store second_part part of the TIMESTAMP(N) */
+uint Type_handler_timestamp::m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]=
+ { 0, 1, 1, 2, 2, 3, 3 };
+
+/* number of bytes to store DATETIME(N) */
+uint Type_handler_datetime::m_hires_bytes[MAX_DATETIME_PRECISION + 1]=
+ { 5, 6, 6, 7, 7, 7, 8 };
+
+/* number of bytes to store TIME(N) */
+uint Type_handler_time::m_hires_bytes[MAX_DATETIME_PRECISION + 1]=
+ { 3, 4, 4, 5, 5, 5, 6 };
+
+/***************************************************************************/
+
+const Name Type_handler::version() const
+{
+ static const Name ver(STRING_WITH_LEN(""));
+ return ver;
+}
+
+const Name & Type_handler::version_mariadb53()
+{
+ static const Name ver(STRING_WITH_LEN("mariadb-5.3"));
+ return ver;
+}
+
+const Name & Type_handler::version_mysql56()
+{
+ static const Name ver(STRING_WITH_LEN("mysql-5.6"));
+ return ver;
+}
+
+
+/***************************************************************************/
+
+const Type_limits_int *Type_handler_tiny::type_limits_int() const
+{
+ static const Type_limits_sint8 limits_sint8;
+ return &limits_sint8;
+}
+
+const Type_limits_int *Type_handler_utiny::type_limits_int() const
+{
+ static const Type_limits_uint8 limits_uint8;
+ return &limits_uint8;
+}
+
+const Type_limits_int *Type_handler_short::type_limits_int() const
+{
+ static const Type_limits_sint16 limits_sint16;
+ return &limits_sint16;
+}
+
+const Type_limits_int *Type_handler_ushort::type_limits_int() const
+{
+ static const Type_limits_uint16 limits_uint16;
+ return &limits_uint16;
+}
+
+const Type_limits_int *Type_handler_int24::type_limits_int() const
+{
+ static const Type_limits_sint24 limits_sint24;
+ return &limits_sint24;
+}
+
+const Type_limits_int *Type_handler_uint24::type_limits_int() const
+{
+ static const Type_limits_uint24 limits_uint24;
+ return &limits_uint24;
+}
+
+const Type_limits_int *Type_handler_long::type_limits_int() const
+{
+ static const Type_limits_sint32 limits_sint32;
+ return &limits_sint32;
+}
+
+const Type_limits_int *Type_handler_ulong::type_limits_int() const
+{
+ static const Type_limits_uint32 limits_uint32;
+ return &limits_uint32;
+}
+
+const Type_limits_int *Type_handler_longlong::type_limits_int() const
+{
+ static const Type_limits_sint64 limits_sint64;
+ return &limits_sint64;
+}
+
+const Type_limits_int *Type_handler_ulonglong::type_limits_int() const
+{
+ static const Type_limits_uint64 limits_uint64;
+ return &limits_uint64;
+}
+
+
+/***************************************************************************/
+const Type_handler *Type_handler_bool::type_handler_signed() const
+{
+ return &type_handler_bool;
+}
+
+const Type_handler *Type_handler_bool::type_handler_unsigned() const
+{
+ return &type_handler_bool;
+}
+
+const Type_handler *Type_handler_tiny::type_handler_signed() const
+{
+ return &type_handler_stiny;
+}
+
+const Type_handler *Type_handler_tiny::type_handler_unsigned() const
+{
+ return &type_handler_utiny;
+}
+
+const Type_handler *Type_handler_short::type_handler_signed() const
+{
+ return &type_handler_sshort;
+}
+
+const Type_handler *Type_handler_short::type_handler_unsigned() const
+{
+ return &type_handler_ushort;
+}
+
+const Type_handler *Type_handler_int24::type_handler_signed() const
+{
+ return &type_handler_sint24;
+}
+
+const Type_handler *Type_handler_int24::type_handler_unsigned() const
+{
+ return &type_handler_uint24;
+}
+
+const Type_handler *Type_handler_long::type_handler_signed() const
+{
+ return &type_handler_slong;
+}
+
+const Type_handler *Type_handler_long::type_handler_unsigned() const
+{
+ return &type_handler_ulong;
+}
+
+const Type_handler *Type_handler_longlong::type_handler_signed() const
+{
+ return &type_handler_slonglong;
+}
+
+const Type_handler *Type_handler_longlong::type_handler_unsigned() const
+{
+ return &type_handler_ulonglong;
+}
+
+/***************************************************************************/
+
+const Type_handler *Type_handler_null::type_handler_for_comparison() const
+{
+ return &type_handler_null;
+}
+
+
+const Type_handler *Type_handler_int_result::type_handler_for_comparison() const
+{
+ return &type_handler_slonglong;
+}
+
+
+const Type_handler *Type_handler_string_result::type_handler_for_comparison() const
+{
+ return &type_handler_long_blob;
+}
+
+
+const Type_handler *Type_handler_decimal_result::type_handler_for_comparison() const
+{
+ return &type_handler_newdecimal;
+}
+
+
+const Type_handler *Type_handler_real_result::type_handler_for_comparison() const
+{
+ return &type_handler_double;
+}
+
+
+const Type_handler *Type_handler_time_common::type_handler_for_comparison() const
+{
+ return &type_handler_time;
+}
+
+const Type_handler *Type_handler_date_common::type_handler_for_comparison() const
+{
+ return &type_handler_newdate;
+}
+
+
+const Type_handler *Type_handler_datetime_common::type_handler_for_comparison() const
+{
+ return &type_handler_datetime;
+}
+
+
+const Type_handler *Type_handler_timestamp_common::type_handler_for_comparison() const
+{
+ return &type_handler_timestamp;
+}
+
+
+const Type_handler *Type_handler_row::type_handler_for_comparison() const
+{
+ return &type_handler_row;
+}
+
+/***************************************************************************/
+
+const Type_handler *
+Type_handler_timestamp_common::type_handler_for_native_format() const
+{
+ return &type_handler_timestamp2;
+}
+
+
+const Type_handler *
+Type_handler_time_common::type_handler_for_native_format() const
+{
+ return &type_handler_time2;
+}
+
+
+/***************************************************************************/
+
+const Type_handler *Type_handler_typelib::type_handler_for_item_field() const
+{
+ return &type_handler_string;
+}
+
+
+const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
+{
+ return &type_handler_slonglong;
+}
+
+
+/***************************************************************************/
+
+bool
+Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
+{
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, other)) ||
+ !(hres= c->aggregate_for_result(m_type_handler, other)))
+ hres= type_handler_data->
+ m_type_aggregator_for_result.find_handler(m_type_handler, other);
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ return false;
+}
+
+
+const Type_handler *
+Type_handler::type_handler_long_or_longlong(uint max_char_length,
+ bool unsigned_flag)
+{
+ if (unsigned_flag)
+ {
+ if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
+ return &type_handler_ulong;
+ return &type_handler_ulonglong;
+ }
+ if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
+ return &type_handler_slong;
+ return &type_handler_slonglong;
+}
+
+
+/*
+ This method is called for CASE (and its abbreviations) and LEAST/GREATEST
+ when data type aggregation returned LONGLONG and there were some BIT
+ expressions. This helps to adjust the data type from LONGLONG to LONG
+ if all expressions fit.
+*/
+const Type_handler *
+Type_handler::bit_and_int_mixture_handler(uint max_char_length)
+{
+ if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS)
+ return &type_handler_slong;
+ return &type_handler_slonglong;
+}
+
+
+/**
+ @brief Aggregates field types from the array of items.
+
+ @param[in] items array of items to aggregate the type from
+ @param[in] nitems number of items in the array
+ @param[in] treat_bit_as_number - if BIT should be aggregated to a non-BIT
+ counterpart as a LONGLONG number or as a VARBINARY string.
+
+ Currently behaviour depends on the function:
+ - LEAST/GREATEST treat BIT as VARBINARY when
+ aggregating with a non-BIT counterpart.
+ Note, UNION also works this way.
+
+ - CASE, COALESCE, IF, IFNULL treat BIT as LONGLONG when
+ aggregating with a non-BIT counterpart;
+
+ This inconsistency may be changed in the future. See MDEV-8867.
+
+ Note, independently from "treat_bit_as_number":
+ - a single BIT argument gives BIT as a result
+ - two BIT couterparts give BIT as a result
+
+ @details This function aggregates field types from the array of items.
+ Found type is supposed to be used later as the result field type
+ of a multi-argument function.
+ Aggregation itself is performed by Type_handler::aggregate_for_result().
+
+ @note The term "aggregation" is used here in the sense of inferring the
+ result type of a function from its argument types.
+
+ @retval false - on success
+ @retval true - on error
+*/
+
+bool
+Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
+ Item **items, uint nitems,
+ bool treat_bit_as_number)
+{
+ bool bit_and_non_bit_mixture_found= false;
+ uint32 max_display_length;
+ if (!nitems || items[0]->result_type() == ROW_RESULT)
+ {
+ DBUG_ASSERT(0);
+ set_handler(&type_handler_null);
+ return true;
+ }
+ set_handler(items[0]->type_handler());
+ max_display_length= items[0]->max_display_length();
+ for (uint i= 1 ; i < nitems ; i++)
+ {
+ const Type_handler *cur= items[i]->type_handler();
+ set_if_bigger(max_display_length, items[i]->max_display_length());
+ if (treat_bit_as_number &&
+ ((type_handler() == &type_handler_bit) ^ (cur == &type_handler_bit)))
+ {
+ bit_and_non_bit_mixture_found= true;
+ if (type_handler() == &type_handler_bit)
+ set_handler(&type_handler_slonglong); // BIT + non-BIT
+ else
+ cur= &type_handler_slonglong; // non-BIT + BIT
+ }
+ if (aggregate_for_result(cur))
+ {
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
+ type_handler()->name().ptr(), cur->name().ptr(), funcname);
+ return true;
+ }
+ }
+ if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
+ set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
+ return false;
+}
+
+/**
+ Collect built-in data type handlers for comparison.
+ This method is very similar to item_cmp_type() defined in item.cc.
+ Now they coexist. Later item_cmp_type() will be removed.
+ In addition to item_cmp_type(), this method correctly aggregates
+ TIME with DATETIME/TIMESTAMP/DATE, so no additional find_date_time_item()
+ is needed after this call.
+*/
+
+bool
+Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
+{
+ DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
+ DBUG_ASSERT(h == h->type_handler_for_comparison());
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h)) ||
+ !(hres= c->aggregate_for_comparison(m_type_handler, h)))
+ hres= type_handler_data->
+ m_type_aggregator_for_comparison.find_handler(m_type_handler, h);
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
+ return false;
+}
+
+
+const Type_handler *
+Type_collection_std::aggregate_for_comparison(const Type_handler *ha,
+ const Type_handler *hb) const
+{
+ Item_result a= ha->cmp_type();
+ Item_result b= hb->cmp_type();
+ if (a == STRING_RESULT && b == STRING_RESULT)
+ return &type_handler_long_blob;
+ if (a == INT_RESULT && b == INT_RESULT)
+ return &type_handler_slonglong;
+ if (a == ROW_RESULT || b == ROW_RESULT)
+ return &type_handler_row;
+ if (a == TIME_RESULT || b == TIME_RESULT)
+ {
+ if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
+ {
+ /*
+ We're here if there's only one temporal data type:
+ either m_type_handler or h.
+ Temporal types bit non-temporal types.
+ */
+ const Type_handler *res= b == TIME_RESULT ? hb : ha;
+ /*
+ Compare TIMESTAMP to a non-temporal type as DATETIME.
+ This is needed to make queries with fuzzy dates work:
+ SELECT * FROM t1
+ WHERE
+ ts BETWEEN '0000-00-00' AND '2010-00-01 00:00:00';
+ */
+ if (res->type_handler_for_native_format() == &type_handler_timestamp2)
+ return &type_handler_datetime;
+ return res;
+ }
+ else
+ {
+ /*
+ We're here if both m_type_handler and h are temporal data types.
+ - If both data types are TIME, we preserve TIME.
+ - If both data types are DATE, we preserve DATE.
+ Preserving DATE is needed for EXPLAIN FORMAT=JSON,
+ to print DATE constants using proper format:
+ 'YYYY-MM-DD' rather than 'YYYY-MM-DD 00:00:00'.
+ */
+ if (ha->field_type() != hb->field_type())
+ return &type_handler_datetime;
+ return ha;
+ }
+ }
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ return &type_handler_newdecimal;
+ return &type_handler_double;
+}
+
+
+/**
+ Aggregate data type handler for LEAST/GRATEST.
+ aggregate_for_min_max() is close to aggregate_for_comparison(),
+ but tries to preserve the exact type handler for string, int and temporal
+ data types (instead of converting to super-types).
+ FLOAT is not preserved and is converted to its super-type (DOUBLE).
+ This should probably fixed eventually, for symmetry.
+*/
+
+bool
+Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
+{
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h))||
+ !(hres= c->aggregate_for_min_max(m_type_handler, h)))
+ {
+ /*
+ For now we suppose that these two expressions:
+ - LEAST(type1, type2)
+ - COALESCE(type1, type2)
+ return the same data type (or both expressions return error)
+ if type1 and/or type2 are non-traditional.
+ This may change in the future.
+ */
+ hres= type_handler_data->
+ m_type_aggregator_for_result.find_handler(m_type_handler, h);
+ }
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ return false;
+}
+
+
+const Type_handler *
+Type_collection_std::aggregate_for_min_max(const Type_handler *ha,
+ const Type_handler *hb) const
+{
+ Item_result a= ha->cmp_type();
+ Item_result b= hb->cmp_type();
+ DBUG_ASSERT(a != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
+ DBUG_ASSERT(b != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
+
+ if (a == STRING_RESULT && b == STRING_RESULT)
+ return Type_collection_std::aggregate_for_result(ha, hb);
+ if (a == INT_RESULT && b == INT_RESULT)
+ {
+ // BIT aggregates with non-BIT as BIGINT
+ if (ha != hb)
+ {
+ if (ha == &type_handler_bit)
+ ha= &type_handler_slonglong;
+ else if (hb == &type_handler_bit)
+ hb= &type_handler_slonglong;
+ }
+ return Type_collection_std::aggregate_for_result(ha, hb);
+ }
+ if (a == TIME_RESULT || b == TIME_RESULT)
+ {
+ if ((ha->type_handler_for_native_format() == &type_handler_timestamp2) +
+ (hb->type_handler_for_native_format() == &type_handler_timestamp2) == 1)
+ {
+ /*
+ Handle LEAST(TIMESTAMP, non-TIMESTAMP) as DATETIME,
+ to make sure fuzzy dates work in this context:
+ LEAST('2001-00-00', timestamp_field)
+ */
+ return &type_handler_datetime2;
+ }
+ if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
+ {
+ /*
+ We're here if there's only one temporal data type:
+ either m_type_handler or h.
+ Temporal types bit non-temporal types.
+ */
+ return (b == TIME_RESULT) ? hb : ha;
+ }
+ /*
+ We're here if both m_type_handler and h are temporal data types.
+ */
+ return Type_collection_std::aggregate_for_result(ha, hb);
+ }
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ {
+ return &type_handler_newdecimal;
+ }
+ // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
+ if (ha == &type_handler_float && hb == &type_handler_float)
+ return &type_handler_float;
+ return &type_handler_double;
+}
+
+
+bool
+Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
+ Item **items, uint nitems)
+{
+ bool bit_and_non_bit_mixture_found= false;
+ // LEAST/GREATEST require at least two arguments
+ DBUG_ASSERT(nitems > 1);
+ set_handler(items[0]->type_handler());
+ for (uint i= 1; i < nitems; i++)
+ {
+ const Type_handler *cur= items[i]->type_handler();
+ // Check if BIT + non-BIT, or non-BIT + BIT
+ bit_and_non_bit_mixture_found|= (m_type_handler == &type_handler_bit) !=
+ (cur == &type_handler_bit);
+ if (aggregate_for_min_max(cur))
+ {
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
+ type_handler()->name().ptr(), cur->name().ptr(), funcname);
+ return true;
+ }
+ }
+ if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
+ {
+ uint32 max_display_length= items[0]->max_display_length();
+ for (uint i= 1; i < nitems; i++)
+ set_if_bigger(max_display_length, items[i]->max_display_length());
+ set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
+ }
+ return false;
+}
+
+
+const Type_handler *
+Type_collection_std::aggregate_for_num_op(const Type_handler *h0,
+ const Type_handler *h1) const
+{
+ Item_result r0= h0->cmp_type();
+ Item_result r1= h1->cmp_type();
+
+ if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
+ r0 == STRING_RESULT || r1 ==STRING_RESULT)
+ return &type_handler_double;
+
+ if (r0 == TIME_RESULT || r1 == TIME_RESULT)
+ return &type_handler_datetime;
+
+ if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT)
+ return &type_handler_newdecimal;
+
+ DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
+ return &type_handler_slonglong;
+}
+
+
+const Type_aggregator::Pair*
+Type_aggregator::find_pair(const Type_handler *handler1,
+ const Type_handler *handler2) const
+{
+ for (uint i= 0; i < m_array.elements(); i++)
+ {
+ const Pair& el= m_array.at(i);
+ if (el.eq(handler1, handler2) ||
+ (m_is_commutative && el.eq(handler2, handler1)))
+ return &el;
+ }
+ return NULL;
+}
+
+
+bool
+Type_handler_hybrid_field_type::aggregate_for_num_op(const Type_aggregator *agg,
+ const Type_handler *h0,
+ const Type_handler *h1)
+{
+ const Type_handler *hres;
+ const Type_collection *c;
+ if (!(c= Type_handler::type_collection_for_aggregation(h0, h1)) ||
+ !(hres= c->aggregate_for_num_op(h0, h1)))
+ hres= agg->find_handler(h0, h1);
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ return false;
+}
+
+
+/***************************************************************************/
+
+const Type_handler *
+Type_handler::get_handler_by_field_type(enum_field_types type)
+{
+ switch (type) {
+ case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
+ case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
+ case MYSQL_TYPE_TINY: return &type_handler_stiny;
+ case MYSQL_TYPE_SHORT: return &type_handler_sshort;
+ case MYSQL_TYPE_LONG: return &type_handler_slong;
+ case MYSQL_TYPE_LONGLONG: return &type_handler_slonglong;
+ case MYSQL_TYPE_INT24: return &type_handler_sint24;
+ case MYSQL_TYPE_YEAR: return &type_handler_year;
+ case MYSQL_TYPE_BIT: return &type_handler_bit;
+ case MYSQL_TYPE_FLOAT: return &type_handler_float;
+ case MYSQL_TYPE_DOUBLE: return &type_handler_double;
+ case MYSQL_TYPE_NULL: return &type_handler_null;
+ case MYSQL_TYPE_VARCHAR: return &type_handler_varchar;
+ case MYSQL_TYPE_TINY_BLOB: return &type_handler_tiny_blob;
+ case MYSQL_TYPE_MEDIUM_BLOB: return &type_handler_medium_blob;
+ case MYSQL_TYPE_LONG_BLOB: return &type_handler_long_blob;
+ case MYSQL_TYPE_BLOB: return &type_handler_blob;
+ case MYSQL_TYPE_VAR_STRING: return &type_handler_varchar; // Map to VARCHAR
+ case MYSQL_TYPE_STRING: return &type_handler_string;
+ case MYSQL_TYPE_ENUM: return &type_handler_varchar; // Map to VARCHAR
+ case MYSQL_TYPE_SET: return &type_handler_varchar; // Map to VARCHAR
+ case MYSQL_TYPE_GEOMETRY:
+#ifdef HAVE_SPATIAL
+ return &type_handler_geometry;
+#else
+ return NULL;
+#endif
+ case MYSQL_TYPE_TIMESTAMP: return &type_handler_timestamp2;// Map to timestamp2
+ case MYSQL_TYPE_TIMESTAMP2: return &type_handler_timestamp2;
+ case MYSQL_TYPE_DATE: return &type_handler_newdate; // Map to newdate
+ case MYSQL_TYPE_TIME: return &type_handler_time2; // Map to time2
+ case MYSQL_TYPE_TIME2: return &type_handler_time2;
+ case MYSQL_TYPE_DATETIME: return &type_handler_datetime2; // Map to datetime2
+ case MYSQL_TYPE_DATETIME2: return &type_handler_datetime2;
+ case MYSQL_TYPE_NEWDATE:
+ /*
+ NEWDATE is actually a real_type(), not a field_type(),
+ but it's used around the code in field_type() context.
+ We should probably clean up the code not to use MYSQL_TYPE_NEWDATE
+ in field_type() context and add DBUG_ASSERT(0) here.
+ */
+ return &type_handler_newdate;
+ case MYSQL_TYPE_VARCHAR_COMPRESSED:
+ case MYSQL_TYPE_BLOB_COMPRESSED:
+ break;
+ };
+ DBUG_ASSERT(0);
+ return &type_handler_string;
+}
+
+
+const Type_handler *
+Type_handler::get_handler_by_real_type(enum_field_types type)
+{
+ switch (type) {
+ case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
+ case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
+ case MYSQL_TYPE_TINY: return &type_handler_stiny;
+ case MYSQL_TYPE_SHORT: return &type_handler_sshort;
+ case MYSQL_TYPE_LONG: return &type_handler_slong;
+ case MYSQL_TYPE_LONGLONG: return &type_handler_slonglong;
+ case MYSQL_TYPE_INT24: return &type_handler_sint24;
+ case MYSQL_TYPE_YEAR: return &type_handler_year;
+ case MYSQL_TYPE_BIT: return &type_handler_bit;
+ case MYSQL_TYPE_FLOAT: return &type_handler_float;
+ case MYSQL_TYPE_DOUBLE: return &type_handler_double;
+ case MYSQL_TYPE_NULL: return &type_handler_null;
+ case MYSQL_TYPE_VARCHAR: return &type_handler_varchar;
+ case MYSQL_TYPE_VARCHAR_COMPRESSED: return &type_handler_varchar_compressed;
+ case MYSQL_TYPE_TINY_BLOB: return &type_handler_tiny_blob;
+ case MYSQL_TYPE_MEDIUM_BLOB: return &type_handler_medium_blob;
+ case MYSQL_TYPE_LONG_BLOB: return &type_handler_long_blob;
+ case MYSQL_TYPE_BLOB: return &type_handler_blob;
+ case MYSQL_TYPE_BLOB_COMPRESSED: return &type_handler_blob_compressed;
+ case MYSQL_TYPE_VAR_STRING: return &type_handler_var_string;
+ case MYSQL_TYPE_STRING: return &type_handler_string;
+ case MYSQL_TYPE_ENUM: return &type_handler_enum;
+ case MYSQL_TYPE_SET: return &type_handler_set;
+ case MYSQL_TYPE_GEOMETRY:
+#ifdef HAVE_SPATIAL
+ return &type_handler_geometry;
+#else
+ return NULL;
+#endif
+ case MYSQL_TYPE_TIMESTAMP: return &type_handler_timestamp;
+ case MYSQL_TYPE_TIMESTAMP2: return &type_handler_timestamp2;
+ case MYSQL_TYPE_DATE: return &type_handler_date;
+ case MYSQL_TYPE_TIME: return &type_handler_time;
+ case MYSQL_TYPE_TIME2: return &type_handler_time2;
+ case MYSQL_TYPE_DATETIME: return &type_handler_datetime;
+ case MYSQL_TYPE_DATETIME2: return &type_handler_datetime2;
+ case MYSQL_TYPE_NEWDATE: return &type_handler_newdate;
+ };
+ return NULL;
+}
+
+
+/**
+ Create a DOUBLE field by default.
+*/
+Field *
+Type_handler::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
+ const Item *item) const
+{
+ return new(mem_root)
+ Field_double(NULL, item->max_length,
+ (uchar *) (item->maybe_null ? "" : 0),
+ item->maybe_null ? 1 : 0, Field::NONE,
+ &item->name, (uint8) item->decimals,
+ 0, item->unsigned_flag);
+}
+
+
+Field *
+Type_handler_float::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
+ const Item *item)
+ const
+{
+ return new(mem_root)
+ Field_float(NULL, item->max_length,
+ (uchar *) (item->maybe_null ? "" : 0),
+ item->maybe_null ? 1 : 0, Field::NONE,
+ &item->name, (uint8) item->decimals,
+ 0, item->unsigned_flag);
+}
+
+
+Field *
+Type_handler_decimal_result::make_num_distinct_aggregator_field(
+ MEM_ROOT *mem_root,
+ const Item *item)
+ const
+{
+ DBUG_ASSERT(item->decimals <= DECIMAL_MAX_SCALE);
+ return new (mem_root)
+ Field_new_decimal(NULL, item->max_length,
+ (uchar *) (item->maybe_null ? "" : 0),
+ item->maybe_null ? 1 : 0, Field::NONE,
+ &item->name, (uint8) item->decimals,
+ 0, item->unsigned_flag);
+}
+
+
+Field *
+Type_handler_int_result::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
+ const Item *item)
+ const
+{
+ /**
+ Make a longlong field for all INT-alike types. It could create
+ smaller fields for TINYINT, SMALLINT, MEDIUMINT, INT though.
+ */
+ return new(mem_root)
+ Field_longlong(NULL, item->max_length,
+ (uchar *) (item->maybe_null ? "" : 0),
+ item->maybe_null ? 1 : 0, Field::NONE,
+ &item->name, 0, item->unsigned_flag);
+}
+
+
+/***********************************************************************/
+
+Field *Type_handler_tiny::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ /*
+ As we don't know if the integer was signed or not on the master,
+ assume we have same sign on master and slave. This is true when not
+ using conversions so it should be true also when using conversions.
+ */
+ bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
+ return new (root)
+ Field_tiny(NULL, 4 /*max_length*/, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*zerofill*/, unsigned_flag);
+}
+
+
+Field *Type_handler_short::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
+ return new (root)
+ Field_short(NULL, 6 /*max_length*/, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*zerofill*/, unsigned_flag);
+}
+
+
+Field *Type_handler_int24::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
+ return new (root)
+ Field_medium(NULL, 9 /*max_length*/, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*zerofill*/, unsigned_flag);
+}
+
+
+Field *Type_handler_long::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
+ return new (root)
+ Field_long(NULL, 11 /*max_length*/, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*zerofill*/, unsigned_flag);
+}
+
+
+Field *Type_handler_longlong::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
+ return new (root)
+ Field_longlong(NULL, 20 /*max_length*/,(uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*zerofill*/, unsigned_flag);
+}
+
+
+
+Field *Type_handler_float::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new (root)
+ Field_float(NULL, 12 /*max_length*/, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
+}
+
+
+Field *Type_handler_double::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new (root)
+ Field_double(NULL, 22 /*max_length*/, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
+}
+
+
+Field *Type_handler_newdecimal::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ int precision= metadata >> 8;
+ uint8 decimals= metadata & 0x00ff;
+ uint32 max_length= my_decimal_precision_to_length(precision, decimals, false);
+ DBUG_ASSERT(decimals <= DECIMAL_MAX_SCALE);
+ return new (root)
+ Field_new_decimal(NULL, max_length, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, decimals, 0/*zerofill*/, 0/*unsigned*/);
+}
+
+
+Field *Type_handler_olddecimal::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ sql_print_error("In RBR mode, Slave received incompatible DECIMAL field "
+ "(old-style decimal field) from Master while creating "
+ "conversion table. Please consider changing datatype on "
+ "Master to new style decimal by executing ALTER command for"
+ " column Name: %s.%s.%s.",
+ target->table->s->db.str,
+ target->table->s->table_name.str,
+ target->field_name.str);
+ return NULL;
+}
+
+
+Field *Type_handler_year::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_year(NULL, 4, (uchar *) "", 1, Field::NONE, &empty_clex_str);
+}
+
+
+Field *Type_handler_null::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_null(NULL, 0, Field::NONE, &empty_clex_str, target->charset());
+}
+
+
+Field *Type_handler_timestamp::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new_Field_timestamp(root, NULL, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str,
+ table->s, target->decimals());
+}
+
+
+Field *Type_handler_timestamp2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_timestampf(NULL, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str, table->s, metadata);
+}
+
+
+Field *Type_handler_newdate::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_newdate(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
+}
+
+
+Field *Type_handler_date::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_date(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
+}
+
+
+Field *Type_handler_time::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new_Field_time(root, NULL, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str, target->decimals());
+}
+
+
+Field *Type_handler_time2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_timef(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, metadata);
+}
+
+
+Field *Type_handler_datetime::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new_Field_datetime(root, NULL, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str, target->decimals());
+}
+
+
+Field *Type_handler_datetime2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_datetimef(NULL, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str, metadata);
+}
+
+
+Field *Type_handler_bit::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ DBUG_ASSERT((metadata & 0xff) <= 7);
+ uint32 max_length= 8 * (metadata >> 8U) + (metadata & 0x00ff);
+ return new(root)
+ Field_bit_as_char(NULL, max_length, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str);
+}
+
+
+Field *Type_handler_string::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ /* This is taken from Field_string::unpack. */
+ uint32 max_length= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
+ return new(root)
+ Field_string(NULL, max_length, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str, target->charset());
+}
+
+
+Field *Type_handler_varchar::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(metadata) <= MAX_FIELD_VARCHARLENGTH);
+ return new(root)
+ Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata),
+ (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ table->s, target->charset());
+}
+
+
+Field *Type_handler_varchar_compressed::make_conversion_table_field(
+ MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ return new(root)
+ Field_varstring_compressed(NULL, metadata,
+ HA_VARCHAR_PACKLENGTH(metadata),
+ (uchar *) "", 1, Field::NONE,
+ &empty_clex_str,
+ table->s, target->charset(),
+ zlib_compression_method);
+}
+
+
+
+Field *Type_handler_blob_compressed::make_conversion_table_field(
+ MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ uint pack_length= metadata & 0x00ff;
+ if (pack_length < 1 || pack_length > 4)
+ return NULL; // Broken binary log?
+ return new(root)
+ Field_blob_compressed(NULL, (uchar *) "", 1, Field::NONE,
+ &empty_clex_str,
+ table->s, pack_length, target->charset(),
+ zlib_compression_method);
+}
+
+
+Field *Type_handler_enum::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
+ DBUG_ASSERT(target->real_type() == MYSQL_TYPE_ENUM);
+ return new(root)
+ Field_enum(NULL, target->field_length,
+ (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ metadata & 0x00ff/*pack_length()*/,
+ ((const Field_enum*) target)->typelib, target->charset());
+}
+
+
+Field *Type_handler_set::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
+ DBUG_ASSERT(target->real_type() == MYSQL_TYPE_SET);
+ return new(root)
+ Field_set(NULL, target->field_length,
+ (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ metadata & 0x00ff/*pack_length()*/,
+ ((const Field_enum*) target)->typelib, target->charset());
+}
+
+
+Field *Type_handler_enum::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ const Typelib *typelib= def.typelib();
+ DBUG_ASSERT(typelib);
+ /*
+ Assume I_S columns don't have non-ASCII characters in names.
+ If we eventually want to, Typelib::max_char_length() must be implemented.
+ */
+ return new (root)
+ Field_enum(addr.ptr(), (uint32) typelib->max_octet_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ get_enum_pack_length(typelib->count),
+ typelib, system_charset_info);
+
+}
+
+
+/*************************************************************************/
+
+bool Type_handler::
+ Column_definition_validate_check_constraint(THD *thd,
+ Column_definition * c) const
+{
+ return c->validate_check_constraint(thd);
+}
+
+
+/*************************************************************************/
+
+bool
+Type_handler::Column_definition_set_attributes(THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const
+{
+ def->charset= cs;
+ def->set_length_and_dec(attr);
+ return false;
+}
+
+
+/*
+ In sql_mode=ORACLE, real size of VARCHAR and CHAR with no length
+ in SP parameters is fixed at runtime with the length of real args.
+ Let's translate VARCHAR to VARCHAR(4000) for return value.
+
+ Since Oracle 9, maximum size for VARCHAR in PL/SQL is 32767.
+
+ In MariaDB the limit for VARCHAR is 65535 bytes.
+ We could translate VARCHAR with no length to VARCHAR(65535), but
+ it would mean that for multi-byte character sets we'd have to translate
+ VARCHAR to MEDIUMTEXT, to guarantee 65535 characters.
+
+ Also we could translate VARCHAR to VARCHAR(16383), where 16383 is
+ the maximum possible length in characters in case of mbmaxlen=4
+ (e.g. utf32, utf16, utf8mb4). However, we'll have character sets with
+ mbmaxlen=5 soon (e.g. gb18030).
+*/
+
+bool
+Type_handler_string::Column_definition_set_attributes(
+ THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const
+{
+ Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
+ if (attr.length())
+ return false;
+ switch (type) {
+ case COLUMN_DEFINITION_ROUTINE_PARAM:
+ case COLUMN_DEFINITION_FUNCTION_RETURN:
+ if (thd->variables.sql_mode & MODE_ORACLE)
+ {
+ // See Type_handler_varchar::Column_definition_set_attributes()
+ def->length= def->decimals= 2000;
+ def->set_handler(&type_handler_varchar);
+ return false;
+ }
+ break;
+ case COLUMN_DEFINITION_ROUTINE_LOCAL:
+ case COLUMN_DEFINITION_TABLE_FIELD:
+ break;
+ }
+ def->length= 1;
+ return false;
+}
+
+
+bool
+Type_handler_varchar::Column_definition_set_attributes(
+ THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type)
+ const
+{
+ Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
+ if (attr.length())
+ return false;
+ switch (type) {
+ case COLUMN_DEFINITION_ROUTINE_PARAM:
+ case COLUMN_DEFINITION_FUNCTION_RETURN:
+ if (thd->variables.sql_mode & MODE_ORACLE)
+ {
+ /*
+ Type_handler_varchar::adjust_spparam_type() tests "decimals"
+ to detect if the formal parameter length needs to be adjusted to
+ the actual parameter length. Non-zero decimals means that the length
+ was set implicitly to the default value and needs to be adjusted.
+ */
+ def->length= def->decimals= 4000;
+ return false;
+ }
+ break;
+ case COLUMN_DEFINITION_ROUTINE_LOCAL:
+ case COLUMN_DEFINITION_TABLE_FIELD:
+ break;
+ }
+ thd->parse_error();
+ return true;
+}
+
+
+/*************************************************************************/
+bool Type_handler_null::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return false;
+}
+
+bool Type_handler_tiny::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_int(MAX_TINYINT_WIDTH + def->sign_length());
+}
+
+bool Type_handler_short::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_int(MAX_SMALLINT_WIDTH + def->sign_length());
+}
+
+bool Type_handler_int24::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_int(MAX_MEDIUMINT_WIDTH + def->sign_length());
+}
+
+bool Type_handler_long::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_int(MAX_INT_WIDTH + def->sign_length());
+}
+
+bool Type_handler_longlong::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_int(MAX_BIGINT_WIDTH/*no sign_length() added*/);
+}
+
+bool Type_handler_newdecimal::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_decimal();
+}
+
+bool Type_handler_olddecimal::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ DBUG_ASSERT(0); // Obsolete
+ return true;
+}
+
+bool Type_handler_var_string::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ DBUG_ASSERT(0); // Obsolete
+ return true;
+}
+
+bool Type_handler_varchar::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ /*
+ Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
+ if they don't have a default value
+ */
+ return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH);
+}
+
+bool Type_handler_string::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->check_length(ER_TOO_BIG_FIELDLENGTH, MAX_FIELD_CHARLENGTH);
+}
+
+bool Type_handler_blob_common::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ def->flags|= BLOB_FLAG;
+ return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH);
+}
+
+
+bool Type_handler_year::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ if (!def->length || def->length != 2)
+ def->length= 4; // Default length
+ def->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
+ return false;
+}
+
+bool Type_handler_float::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_real(MAX_FLOAT_STR_LENGTH);
+}
+
+
+bool Type_handler_double::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_real(DBL_DIG + 7);
+}
+
+bool Type_handler_timestamp_common::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ def->flags|= UNSIGNED_FLAG;
+ return def->fix_attributes_temporal_with_time(MAX_DATETIME_WIDTH);
+}
+
+bool Type_handler_date_common::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ // We don't support creation of MYSQL_TYPE_DATE anymore
+ def->set_handler(&type_handler_newdate);
+ def->length= MAX_DATE_WIDTH;
+ return false;
+}
+
+bool Type_handler_time_common::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_temporal_with_time(MIN_TIME_WIDTH);
+}
+
+bool Type_handler_datetime_common::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_temporal_with_time(MAX_DATETIME_WIDTH);
+}
+
+bool Type_handler_set::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ def->pack_length= get_set_pack_length(def->interval_list.elements);
+ return false;
+}
+
+bool Type_handler_enum::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ def->pack_length= get_enum_pack_length(def->interval_list.elements);
+ return false;
+}
+
+bool Type_handler_bit::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ return def->fix_attributes_bit();
+}
+
+/*************************************************************************/
+
+void Type_handler_typelib::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ DBUG_ASSERT(def->flags & (ENUM_FLAG | SET_FLAG));
+ def->interval= field->get_typelib();
+}
+
+
+void Type_handler_year::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ if (def->length != 4)
+ {
+ char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
+ my_snprintf(buff, sizeof(buff), "YEAR(%llu)", def->length);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
+ buff, "YEAR(4)");
+ }
+}
+
+
+void Type_handler_real_result::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ /*
+ Floating points are stored with FLOATING_POINT_DECIMALS but internally
+ in MariaDB used with NOT_FIXED_DEC, which is >= FLOATING_POINT_DECIMALS.
+ */
+ if (def->decimals >= FLOATING_POINT_DECIMALS)
+ def->decimals= NOT_FIXED_DEC;
+}
+
+
+/*************************************************************************/
+
+bool Type_handler::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->prepare_stage1_simple(&my_charset_bin);
+ return false;
+}
+
+bool Type_handler_null::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->prepare_charset_for_string(derived_attr);
+ def->create_length_to_internal_length_null();
+ return false;
+}
+
+bool Type_handler_row::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->charset= &my_charset_bin;
+ def->create_length_to_internal_length_null();
+ return false;
+}
+
+bool Type_handler_temporal_result::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->prepare_stage1_simple(&my_charset_numeric);
+ return false;
+}
+
+
+bool Type_handler_numeric::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->prepare_stage1_simple(&my_charset_numeric);
+ return false;
+}
+
+bool Type_handler_newdecimal::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->charset= &my_charset_numeric;
+ def->create_length_to_internal_length_newdecimal();
+ return false;
+}
+
+bool Type_handler_bit::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ def->charset= &my_charset_numeric;
+ return def->prepare_stage1_bit(thd, mem_root, file, table_flags);
+}
+
+bool Type_handler_typelib::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ return def->prepare_charset_for_string(derived_attr) ||
+ def->prepare_stage1_typelib(thd, mem_root, file, table_flags);
+}
+
+
+bool Type_handler_string_result::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const
+{
+ return def->prepare_charset_for_string(derived_attr) ||
+ def->prepare_stage1_string(thd, mem_root, file, table_flags);
+}
+
+
+/*************************************************************************/
+
+bool Type_handler_general_purpose_string::
+ Column_definition_bulk_alter(Column_definition *def,
+ const Column_derived_attributes
+ *derived_attr,
+ const Column_bulk_alter_attributes
+ *bulk_alter_attr)
+ const
+{
+ if (!bulk_alter_attr->alter_table_convert_to_charset())
+ return false; // No "CONVERT TO" clause.
+ CHARSET_INFO *defcs= def->explicit_or_derived_charset(derived_attr);
+ DBUG_ASSERT(defcs);
+ /*
+ Handle 'ALTER TABLE t1 CONVERT TO CHARACTER SET csname'.
+ Change character sets for all varchar/char/text columns,
+ but do not touch varbinary/binary/blob columns.
+ */
+ if (defcs != &my_charset_bin)
+ def->charset= bulk_alter_attr->alter_table_convert_to_charset();
+ return false;
+};
+
+
+/*************************************************************************/
+
+bool Type_handler::
+ Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const
+{
+ def->redefine_stage1_common(dup, file);
+ def->create_length_to_internal_length_simple();
+ return false;
+}
+
+
+bool Type_handler_null::
+ Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const
+{
+ def->redefine_stage1_common(dup, file);
+ def->create_length_to_internal_length_null();
+ return false;
+}
+
+
+bool Type_handler_newdecimal::
+ Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const
+{
+ def->redefine_stage1_common(dup, file);
+ def->create_length_to_internal_length_newdecimal();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const
+{
+ def->redefine_stage1_common(dup, file);
+ def->set_compression_method(dup->compression_method());
+ def->create_length_to_internal_length_string();
+ return false;
+}
+
+
+bool Type_handler_typelib::
+ Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const
+{
+ def->redefine_stage1_common(dup, file);
+ def->create_length_to_internal_length_typelib();
+ return false;
+}
+
+
+bool Type_handler_bit::
+ Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const
+{
+ def->redefine_stage1_common(dup, file);
+ /*
+ If we are replacing a field with a BIT field, we need
+ to initialize pack_flag.
+ */
+ def->pack_flag= FIELDFLAG_NUMBER;
+ if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD))
+ def->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
+ def->create_length_to_internal_length_bit();
+ return false;
+}
+
+
+/*************************************************************************/
+
+bool Type_handler::
+ Column_definition_prepare_stage2_legacy(Column_definition *def,
+ enum_field_types type) const
+{
+ def->pack_flag= f_settype((uint) type);
+ return false;
+}
+
+bool Type_handler::
+ Column_definition_prepare_stage2_legacy_num(Column_definition *def,
+ enum_field_types type) const
+{
+ def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
+ return false;
+}
+
+bool Type_handler::
+ Column_definition_prepare_stage2_legacy_real(Column_definition *def,
+ enum_field_types type) const
+{
+ uint dec= def->decimals;
+ /*
+ User specified FLOAT() or DOUBLE() without precision. Change to
+ FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB
+ versions.
+ */
+ if (dec >= FLOATING_POINT_DECIMALS)
+ dec= FLOATING_POINT_DECIMALS;
+ def->decimals= dec;
+ def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
+ return false;
+}
+
+bool Type_handler_newdecimal::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ def->pack_flag= def->pack_flag_numeric();
+ return false;
+}
+
+bool Type_handler_blob_common::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_BLOB);
+}
+
+bool Type_handler_varchar::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ return def->prepare_stage2_varchar(table_flags);
+}
+
+bool Type_handler_string::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ def->pack_flag= (def->charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0;
+ return false;
+}
+
+bool Type_handler_enum::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ uint dummy;
+ return def->prepare_stage2_typelib("ENUM", FIELDFLAG_INTERVAL, &dummy);
+}
+
+bool Type_handler_set::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ uint dup_count;
+ if (def->prepare_stage2_typelib("SET", FIELDFLAG_BITFIELD, &dup_count))
+ return true;
+ /* Check that count of unique members is not more then 64 */
+ if (def->interval->count - dup_count > sizeof(longlong)*8)
+ {
+ my_error(ER_TOO_BIG_SET, MYF(0), def->field_name.str);
+ return true;
+ }
+ return false;
+}
+
+bool Type_handler_bit::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ /*
+ We have sql_field->pack_flag already set here, see
+ mysql_prepare_create_table().
+ */
+ return false;
+}
+
+
+/*************************************************************************/
+bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_field_needed) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
+ return true;
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->check_primary_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ if (!(part->length*= def.charset->mbmaxlen))
+ *hash_field_needed= true;
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->init_multiple_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->check_foreign_key_for_blob(file);
+}
+
+
+
+/*************************************************************************/
+
+uint32 Type_handler_time::calc_pack_length(uint32 length) const
+{
+ return length > MIN_TIME_WIDTH ?
+ hires_bytes(length - 1 - MIN_TIME_WIDTH) : 3;
+}
+
+uint32 Type_handler_time2::calc_pack_length(uint32 length) const
+{
+ return length > MIN_TIME_WIDTH ?
+ my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3;
+}
+
+uint32 Type_handler_timestamp::calc_pack_length(uint32 length) const
+{
+ return length > MAX_DATETIME_WIDTH ?
+ 4 + sec_part_bytes(length - 1 - MAX_DATETIME_WIDTH) : 4;
+}
+
+uint32 Type_handler_timestamp2::calc_pack_length(uint32 length) const
+{
+ return length > MAX_DATETIME_WIDTH ?
+ my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4;
+}
+
+uint32 Type_handler_datetime::calc_pack_length(uint32 length) const
+{
+ return length > MAX_DATETIME_WIDTH ?
+ hires_bytes(length - 1 - MAX_DATETIME_WIDTH) : 8;
+}
+
+uint32 Type_handler_datetime2::calc_pack_length(uint32 length) const
+{
+ return length > MAX_DATETIME_WIDTH ?
+ my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5;
+}
+
+uint32 Type_handler_tiny_blob::calc_pack_length(uint32 length) const
+{
+ return 1 + portable_sizeof_char_ptr;
+}
+
+uint32 Type_handler_blob::calc_pack_length(uint32 length) const
+{
+ return 2 + portable_sizeof_char_ptr;
+}
+
+uint32 Type_handler_medium_blob::calc_pack_length(uint32 length) const
+{
+ return 3 + portable_sizeof_char_ptr;
+}
+
+uint32 Type_handler_long_blob::calc_pack_length(uint32 length) const
+{
+ return 4 + portable_sizeof_char_ptr;
+}
+
+uint32 Type_handler_newdecimal::calc_pack_length(uint32 length) const
+{
+ abort(); // This shouldn't happen
+ return 0;
+}
+
+uint32 Type_handler_set::calc_pack_length(uint32 length) const
+{
+ abort(); // This shouldn't happen
+ return 0;
+}
+
+uint32 Type_handler_enum::calc_pack_length(uint32 length) const
+{
+ abort(); // This shouldn't happen
+ return 0;
+}
+
+
+/*************************************************************************/
+uint Type_handler::calc_key_length(const Column_definition &def) const
+{
+ DBUG_ASSERT(def.pack_length == calc_pack_length((uint32) def.length));
+ return def.pack_length;
+}
+
+uint Type_handler_bit::calc_key_length(const Column_definition &def) const
+{
+ if (f_bit_as_char(def.pack_flag))
+ return def.pack_length;
+ /* We need one extra byte to store the bits we save among the null bits */
+ return def.pack_length + MY_TEST(def.length & 7);
+}
+
+uint Type_handler_newdecimal::calc_key_length(const Column_definition &def) const
+{
+ return def.pack_length;
+}
+
+uint
+Type_handler_string_result::calc_key_length(const Column_definition &def) const
+{
+ return (uint) def.length;
+}
+
+uint Type_handler_enum::calc_key_length(const Column_definition &def) const
+{
+ DBUG_ASSERT(def.interval);
+ return get_enum_pack_length(def.interval->count);
+}
+
+uint Type_handler_set::calc_key_length(const Column_definition &def) const
+{
+ DBUG_ASSERT(def.interval);
+ return get_set_pack_length(def.interval->count);
+}
+
+uint Type_handler_blob_common::calc_key_length(const Column_definition &def) const
+{
+ return 0;
+}
+
+/*************************************************************************/
+Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE *table) const
+{
+ Field *field= make_table_field(root, name, addr, attr, table->s);
+ if (field)
+ field->init(table);
+ return field;
+}
+
+
+Field *Type_handler_int_result::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ Column_definition_attributes dattr(attr);
+ return make_table_field_from_def(share, root, name, addr,
+ Bit_addr(), &dattr, 0);
+}
+
+
+Field *Type_handler_vers_trx_id::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
+ Field_vers_trx_id(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name,
+ 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *
+Type_handler_real_result::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ Column_definition_attributes dattr(attr);
+ return make_table_field_from_def(share, root, name, addr,
+ Bit_addr(), &dattr, 0);
+}
+
+
+Field *
+Type_handler_olddecimal::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ /*
+ Currently make_table_field() is used for Item purpose only.
+ On Item level we have type_handler_newdecimal only.
+ For now we have DBUG_ASSERT(0).
+ It will be removed when we reuse Type_handler::make_table_field()
+ in make_field() in field.cc, to open old tables with old decimal.
+ */
+ DBUG_ASSERT(0);
+ Column_definition_attributes dattr(attr);
+ return make_table_field_from_def(share, root, name, addr,
+ Bit_addr(), &dattr, 0);
+}
+
+
+Field *
+Type_handler_newdecimal::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ uint8 dec= (uint8) attr.decimals;
+ uint8 intg= (uint8) (attr.decimal_precision() - dec);
+ uint32 len= attr.max_char_length();
+
+ /*
+ Trying to put too many digits overall in a DECIMAL(prec,dec)
+ will always throw a warning. We must limit dec to
+ DECIMAL_MAX_SCALE however to prevent an assert() later.
+ */
+
+ if (dec > 0)
+ {
+ signed int overflow;
+
+ dec= MY_MIN(dec, DECIMAL_MAX_SCALE);
+
+ /*
+ If the value still overflows the field with the corrected dec,
+ we'll throw out decimals rather than integers. This is still
+ bad and of course throws a truncation warning.
+ +1: for decimal point
+ */
+
+ const int required_length=
+ my_decimal_precision_to_length(intg + dec, dec, attr.unsigned_flag);
+
+ overflow= required_length - len;
+
+ if (overflow > 0)
+ dec= MY_MAX(0, dec - overflow); // too long, discard fract
+ else
+ /* Corrected value fits. */
+ len= required_length;
+ }
+ return new (root)
+ Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name,
+ dec, 0/*zerofill*/, attr.unsigned_flag);
+}
+
+
+Field *Type_handler_null::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_null(addr.ptr(), attr.max_length,
+ Field::NONE, name, attr.collation.collation);
+}
+
+
+Field *Type_handler_timestamp::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new_Field_timestamp(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share, attr.decimals);
+}
+
+
+Field *Type_handler_timestamp2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ /*
+ Will be changed to "new Field_timestampf" when we reuse
+ make_table_field() for make_field() purposes in field.cc.
+ */
+ return new_Field_timestamp(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share, attr.decimals);
+}
+
+
+Field *Type_handler_newdate::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name);
+}
+
+
+Field *Type_handler_date::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ /*
+ DBUG_ASSERT will be removed when we reuse make_table_field()
+ for make_field() in field.cc
+ */
+ DBUG_ASSERT(0);
+ return new (root)
+ Field_date(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name);
+}
+
+
+Field *Type_handler_time::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new_Field_time(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, attr.decimals);
+}
+
+
+Field *Type_handler_time2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+
+{
+ /*
+ Will be changed to "new Field_timef" when we reuse
+ make_table_field() for make_field() purposes in field.cc.
+ */
+ return new_Field_time(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, attr.decimals);
+}
+
+
+Field *Type_handler_datetime::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new_Field_datetime(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, attr.decimals);
+}
+
+
+Field *Type_handler_datetime2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ /*
+ Will be changed to "new Field_datetimef" when we reuse
+ make_table_field() for make_field() purposes in field.cc.
+ */
+ return new_Field_datetime(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, attr.decimals);
+}
+
+
+Field *Type_handler_bit::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_bit_as_char(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name);
+}
+
+
+Field *Type_handler_string::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_string(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, attr.collation);
+}
+
+
+Field *Type_handler_varchar::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(attr.max_length) <=
+ MAX_FIELD_VARCHARLENGTH);
+ return new (root)
+ Field_varstring(addr.ptr(), attr.max_length,
+ HA_VARCHAR_PACKLENGTH(attr.max_length),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name,
+ share, attr.collation);
+}
+
+
+Field *Type_handler_tiny_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share,
+ 1, attr.collation);
+}
+
+
+Field *Type_handler_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share,
+ 2, attr.collation);
+}
+
+
+Field *
+Type_handler_medium_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share,
+ 3, attr.collation);
+}
+
+
+Field *Type_handler_long_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, share,
+ 4, attr.collation);
+}
+
+
+Field *Type_handler_enum::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ const TYPELIB *typelib= attr.get_typelib();
+ DBUG_ASSERT(typelib);
+ return new (root)
+ Field_enum(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name,
+ get_enum_pack_length(typelib->count), typelib,
+ attr.collation);
+}
+
+
+Field *Type_handler_set::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+
+{
+ const TYPELIB *typelib= attr.get_typelib();
+ DBUG_ASSERT(typelib);
+ return new (root)
+ Field_set(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name,
+ get_enum_pack_length(typelib->count), typelib,
+ attr.collation);
+}
+
+
+/*************************************************************************/
+
+Field *Type_handler_float::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_float(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) NOT_FIXED_DEC,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_double::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_double(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) NOT_FIXED_DEC,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_decimal_result::make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ uint dec= def.decimal_scale();
+ uint prec= def.decimal_precision();
+ DBUG_ASSERT(dec <= DECIMAL_MAX_SCALE);
+ uint32 len= my_decimal_precision_to_length(prec, dec, def.unsigned_flag());
+ return new (root)
+ Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) dec, 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_blob_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, table->s,
+ length_bytes(),
+ &my_charset_bin);
+}
+
+
+Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ DBUG_ASSERT(def.char_length());
+ LEX_CSTRING name= def.name();
+ uint32 octet_length= (uint32) def.char_length() * 3;
+ if (octet_length > MAX_FIELD_VARCHARLENGTH)
+ {
+ Field *field= new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE,
+ &name, table->s, 4, system_charset_info);
+ if (field)
+ field->field_length= octet_length;
+ return field;
+ }
+ else
+ {
+ return new (root)
+ Field_varstring(addr.ptr(), octet_length,
+ HA_VARCHAR_PACKLENGTH(octet_length),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ table->s, system_charset_info);
+ }
+}
+
+
+Field *Type_handler_tiny::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_tiny(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_short::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_short(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_long::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_long(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_longlong::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_longlong(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_date_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name);
+}
+
+
+Field *Type_handler_time_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new_Field_time(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, def.fsp());
+}
+
+
+Field *Type_handler_datetime_common::make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root) Field_datetimef(addr.ptr(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, def.fsp());
+}
+
+
+/*************************************************************************/
+
+/*
+ If length is not specified for a varchar parameter, set length to the
+ maximum length of the actual argument. Goals are:
+ - avoid to allocate too much unused memory for m_var_table
+ - allow length check inside the callee rather than during copy of
+ returned values in output variables.
+ - allow varchar parameter size greater than 4000
+ Default length has been stored in "decimal" member during parse.
+*/
+bool Type_handler_varchar::adjust_spparam_type(Spvar_definition *def,
+ Item *from) const
+{
+ if (def->decimals)
+ {
+ uint def_max_char_length= MAX_FIELD_VARCHARLENGTH / def->charset->mbmaxlen;
+ uint arg_max_length= from->max_char_length();
+ set_if_smaller(arg_max_length, def_max_char_length);
+ def->length= arg_max_length > 0 ? arg_max_length : def->decimals;
+ def->create_length_to_internal_length_string();
+ }
+ return false;
+}
+
+/*************************************************************************/
+
+uint32 Type_handler_decimal_result::max_display_length(const Item *item) const
+{
+ return item->max_length;
+}
+
+
+uint32 Type_handler_temporal_result::max_display_length(const Item *item) const
+{
+ return item->max_length;
+}
+
+uint32 Type_handler_string_result::max_display_length(const Item *item) const
+{
+ return item->max_length;
+}
+
+
+uint32 Type_handler_year::max_display_length(const Item *item) const
+{
+ return item->max_length;
+}
+
+
+uint32 Type_handler_bit::max_display_length(const Item *item) const
+{
+ return item->max_length;
+}
+
+/*************************************************************************/
+
+uint32
+Type_handler_decimal_result::Item_decimal_notation_int_digits(const Item *item)
+ const
+{
+ return item->decimal_int_part();
+}
+
+
+uint32
+Type_handler_temporal_result::Item_decimal_notation_int_digits(const Item *item)
+ const
+{
+ return item->decimal_int_part();
+}
+
+
+uint32
+Type_handler_bit::Item_decimal_notation_int_digits(const Item *item)
+ const
+{
+ return Bit_decimal_notation_int_digits_by_nbits(item->max_length);
+}
+
+
+uint32
+Type_handler_general_purpose_int::Item_decimal_notation_int_digits(
+ const Item *item) const
+{
+ return type_limits_int()->precision();
+}
+
+/*************************************************************************/
+
+/*
+ Binary to Decimal digits ratio converges to log2(10) thus using 3 as
+ a divisor.
+*/
+uint32
+Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(uint nbits)
+{
+ DBUG_ASSERT(nbits > 0);
+ DBUG_ASSERT(nbits <= 64);
+ set_if_smaller(nbits, 64); // Safety
+ static uint ndigits[65]=
+ {0,
+ 1,1,1,2,2,2,3,3, // 1..8 bits
+ 3,4,4,4,4,5,5,5, // 9..16 bits
+ 6,6,6,7,7,7,7,8, // 17..24 bits
+ 8,8,9,9,9,10,10,10, // 25..32 bits
+ 10,11,11,11,12,12,12,13, // 33..40 bits
+ 13,13,13,14,14,14,15,15, // 41..48 bits
+ 15,16,16,16,16,17,17,17, // 49..56 bits
+ 18,18,18,19,19,19,19,20 // 57..64 bits
+ };
+ return ndigits[nbits];
+}
+
+/*************************************************************************/
+
+void Type_handler_row::Item_update_null_value(Item *item) const
+{
+ DBUG_ASSERT(0);
+ item->null_value= true;
+}
+
+
+void Type_handler_time_common::Item_update_null_value(Item *item) const
+{
+ MYSQL_TIME ltime;
+ THD *thd= current_thd;
+ (void) item->get_date(thd, &ltime, Time::Options(TIME_TIME_ONLY, thd));
+}
+
+
+void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const
+{
+ MYSQL_TIME ltime;
+ THD *thd= current_thd;
+ (void) item->get_date(thd, &ltime, Datetime::Options(thd));
+}
+
+bool
+Type_handler_timestamp_common::
+Column_definition_set_attributes(THD *thd,
+ Column_definition *def,
+ const Lex_field_type_st &attr,
+ CHARSET_INFO *cs,
+ column_definition_type_t type) const
+{
+ Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
+ if (!opt_explicit_defaults_for_timestamp)
+ def->flags|= NOT_NULL_FLAG;
+ return false;
+}
+
+void Type_handler_string_result::Item_update_null_value(Item *item) const
+{
+ StringBuffer<MAX_FIELD_WIDTH> tmp;
+ (void) item->val_str(&tmp);
+}
+
+
+void Type_handler_real_result::Item_update_null_value(Item *item) const
+{
+ (void) item->val_real();
+}
+
+
+void Type_handler_decimal_result::Item_update_null_value(Item *item) const
+{
+ my_decimal tmp;
+ (void) item->val_decimal(&tmp);
+}
+
+
+void Type_handler_int_result::Item_update_null_value(Item *item) const
+{
+ (void) item->val_int();
+}
+
+
+void Type_handler_bool::Item_update_null_value(Item *item) const
+{
+ (void) item->val_bool();
+}
+
+
+/*************************************************************************/
+
+int Type_handler_time_common::Item_save_in_field(Item *item, Field *field,
+ bool no_conversions) const
+{
+ return item->save_time_in_field(field, no_conversions);
+}
+
+int Type_handler_temporal_with_date::Item_save_in_field(Item *item,
+ Field *field,
+ bool no_conversions)
+ const
+{
+ return item->save_date_in_field(field, no_conversions);
+}
+
+
+int Type_handler_timestamp_common::Item_save_in_field(Item *item,
+ Field *field,
+ bool no_conversions)
+ const
+{
+ Timestamp_or_zero_datetime_native_null tmp(field->table->in_use, item, true);
+ if (tmp.is_null())
+ return set_field_to_null_with_conversions(field, no_conversions);
+ return tmp.save_in_field(field, item->decimals);
+}
+
+
+int Type_handler_string_result::Item_save_in_field(Item *item, Field *field,
+ bool no_conversions) const
+{
+ return item->save_str_in_field(field, no_conversions);
+}
+
+
+int Type_handler_real_result::Item_save_in_field(Item *item, Field *field,
+ bool no_conversions) const
+{
+ return item->save_real_in_field(field, no_conversions);
+}
+
+
+int Type_handler_decimal_result::Item_save_in_field(Item *item, Field *field,
+ bool no_conversions) const
+{
+ return item->save_decimal_in_field(field, no_conversions);
+}
+
+
+int Type_handler_int_result::Item_save_in_field(Item *item, Field *field,
+ bool no_conversions) const
+{
+ return item->save_int_in_field(field, no_conversions);
+}
+
+
+/***********************************************************************/
+
+bool Type_handler_row::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_row();
+}
+
+bool Type_handler_int_result::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_int();
+}
+
+bool Type_handler_real_result::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_real();
+}
+
+bool Type_handler_decimal_result::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_decimal();
+}
+
+bool Type_handler_string_result::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_string();
+}
+
+bool Type_handler_time_common::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_time();
+}
+
+bool
+Type_handler_temporal_with_date::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_datetime();
+}
+
+bool
+Type_handler_timestamp_common::set_comparator_func(Arg_comparator *cmp) const
+{
+ return cmp->set_cmp_func_native();
+}
+
+
+/*************************************************************************/
+
+bool Type_handler_temporal_result::
+ can_change_cond_ref_to_const(Item_bool_func2 *target,
+ Item *target_expr, Item *target_value,
+ Item_bool_func2 *source,
+ Item *source_expr, Item *source_const)
+ const
+{
+ if (source->compare_type_handler()->cmp_type() != TIME_RESULT)
+ return false;
+
+ /*
+ Can't rewrite:
+ WHERE COALESCE(time_column)='00:00:00'
+ AND COALESCE(time_column)=DATE'2015-09-11'
+ to
+ WHERE DATE'2015-09-11'='00:00:00'
+ AND COALESCE(time_column)=DATE'2015-09-11'
+ because the left part will erroneously try to parse '00:00:00'
+ as DATE, not as TIME.
+
+ TODO: It could still be rewritten to:
+ WHERE DATE'2015-09-11'=TIME'00:00:00'
+ AND COALESCE(time_column)=DATE'2015-09-11'
+ i.e. we need to replace both target_expr and target_value
+ at the same time. This is not supported yet.
+ */
+ return target_value->cmp_type() == TIME_RESULT;
+}
+
+
+bool Type_handler_string_result::
+ can_change_cond_ref_to_const(Item_bool_func2 *target,
+ Item *target_expr, Item *target_value,
+ Item_bool_func2 *source,
+ Item *source_expr, Item *source_const)
+ const
+{
+ if (source->compare_type_handler()->cmp_type() != STRING_RESULT)
+ return false;
+ /*
+ In this example:
+ SET NAMES utf8 COLLATE utf8_german2_ci;
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a CHAR(10) CHARACTER SET utf8);
+ INSERT INTO t1 VALUES ('o-umlaut'),('oe');
+ SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci AND a='oe';
+
+ the query should return only the row with 'oe'.
+ It should not return 'o-umlaut', because 'o-umlaut' does not match
+ the right part of the condition: a='oe'
+ ('o-umlaut' is not equal to 'oe' in utf8mb3_general_ci,
+ which is the collation of the field "a").
+
+ If we change the right part from:
+ ... AND a='oe'
+ to
+ ... AND 'oe' COLLATE utf8_german2_ci='oe'
+ it will be evalulated to TRUE and removed from the condition,
+ so the overall query will be simplified to:
+
+ SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci;
+
+ which will erroneously start to return both 'oe' and 'o-umlaut'.
+ So changing "expr" to "const" is not possible if the effective
+ collations of "target" and "source" are not exactly the same.
+
+ Note, the code before the fix for MDEV-7152 only checked that
+ collations of "source_const" and "target_value" are the same.
+ This was not enough, as the bug report demonstrated.
+ */
+ return
+ target->compare_collation() == source->compare_collation() &&
+ target_value->collation.collation == source_const->collation.collation;
+}
+
+
+bool Type_handler_numeric::
+ can_change_cond_ref_to_const(Item_bool_func2 *target,
+ Item *target_expr, Item *target_value,
+ Item_bool_func2 *source,
+ Item *source_expr, Item *source_const)
+ const
+{
+ /*
+ The collations of "target" and "source" do not make sense for numeric
+ data types.
+ */
+ return target->compare_type_handler() == source->compare_type_handler();
+}
+
+
+/*************************************************************************/
+
+Item_cache *
+Type_handler_row::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_row(thd);
+}
+
+Item_cache *
+Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_int(thd, item->type_handler());
+}
+
+Item_cache *
+Type_handler_year::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_year(thd, item->type_handler());
+}
+
+Item_cache *
+Type_handler_double::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_double(thd);
+}
+
+Item_cache *
+Type_handler_float::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_float(thd);
+}
+
+Item_cache *
+Type_handler_decimal_result::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_decimal(thd);
+}
+
+Item_cache *
+Type_handler_string_result::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_str(thd, item);
+}
+
+Item_cache *
+Type_handler_timestamp_common::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_timestamp(thd);
+}
+
+Item_cache *
+Type_handler_datetime_common::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_datetime(thd);
+}
+
+Item_cache *
+Type_handler_time_common::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_time(thd);
+}
+
+Item_cache *
+Type_handler_date_common::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_date(thd);
+}
+
+
+/*************************************************************************/
+
+Item_copy *
+Type_handler::create_item_copy(THD *thd, Item *item) const
+{
+ return new (thd->mem_root) Item_copy_string(thd, item);
+}
+
+
+Item_copy *
+Type_handler_timestamp_common::create_item_copy(THD *thd, Item *item) const
+{
+ return new (thd->mem_root) Item_copy_timestamp(thd, item);
+}
+
+/*************************************************************************/
+
+bool Type_handler_int_result::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ bool unsigned_flag= items[0]->unsigned_flag;
+ for (uint i= 1; i < nitems; i++)
+ {
+ if (unsigned_flag != items[i]->unsigned_flag)
+ {
+ // Convert a mixture of signed and unsigned int to decimal
+ handler->set_handler(&type_handler_newdecimal);
+ func->aggregate_attributes_decimal(items, nitems, false);
+ return false;
+ }
+ }
+ func->aggregate_attributes_int(items, nitems);
+ handler->set_handler(func->unsigned_flag ?
+ handler->type_handler()->type_handler_unsigned() :
+ handler->type_handler()->type_handler_signed());
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ func->aggregate_attributes_real(items, nitems);
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ uint unsigned_count= func->count_unsigned(items, nitems);
+ func->aggregate_attributes_decimal(items, nitems, unsigned_count == nitems);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ return func->aggregate_attributes_string(func_name, items, nitems);
+}
+
+
+
+/*
+ We can have enum/set type after merging only if we have one enum|set
+ field (or MIN|MAX(enum|set field)) and number of NULL fields
+*/
+bool Type_handler_typelib::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ const TYPELIB *typelib= NULL;
+ for (uint i= 0; i < nitems; i++)
+ {
+ const TYPELIB *typelib2;
+ if ((typelib2= items[i]->get_typelib()))
+ {
+ if (typelib)
+ {
+ /*
+ Two ENUM/SET columns found. We convert such combinations to VARCHAR.
+ This may change in the future to preserve ENUM/SET
+ if typelib definitions are equal.
+ */
+ handler->set_handler(&type_handler_varchar);
+ return func->aggregate_attributes_string(func_name, items, nitems);
+ }
+ typelib= typelib2;
+ }
+ }
+ DBUG_ASSERT(typelib); // There must be at least one typelib
+ func->set_typelib(typelib);
+ return func->aggregate_attributes_string(func_name, items, nitems);
+}
+
+
+bool Type_handler_blob_common::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ if (func->aggregate_attributes_string(func_name, items, nitems))
+ return true;
+ handler->set_handler(blob_type_handler(func->max_length));
+ return false;
+}
+
+
+bool Type_handler_date_common::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ func->fix_attributes_date();
+ return false;
+}
+
+
+bool Type_handler_time_common::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ func->aggregate_attributes_temporal(MIN_TIME_WIDTH, items, nitems);
+ return false;
+}
+
+
+bool Type_handler_datetime_common::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
+ return false;
+}
+
+
+bool Type_handler_timestamp_common::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
+ return false;
+}
+
+/*************************************************************************/
+
+bool Type_handler::
+ Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const
+{
+ /*
+ Aggregating attributes for LEAST/GREATES is exactly the same
+ with aggregating for CASE-alike functions (e.g. COALESCE)
+ for the majority of data type handlers.
+ */
+ return Item_hybrid_func_fix_attributes(thd, func->func_name(),
+ func, func, items, nitems);
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const
+{
+ DBUG_ASSERT(func->field_type() != MYSQL_TYPE_DATE);
+ bool rc= Type_handler::Item_func_min_max_fix_attributes(thd, func,
+ items, nitems);
+ bool is_time= func->field_type() == MYSQL_TYPE_TIME;
+ func->decimals= 0;
+ for (uint i= 0; i < nitems; i++)
+ {
+ uint deci= is_time ? items[i]->time_precision(thd) :
+ items[i]->datetime_precision(thd);
+ set_if_bigger(func->decimals, deci);
+ }
+
+ if (rc || func->maybe_null)
+ return rc;
+ /*
+ LEAST/GREATES(non-temporal, temporal) can return NULL.
+ CAST functions Item_{time|datetime|date}_typecast always set maybe_full
+ to true. Here we try to detect nullability more thoroughly.
+ Perhaps CAST functions should also reuse this idea eventually.
+ */
+ const Type_handler *hf= func->type_handler();
+ for (uint i= 0; i < nitems; i++)
+ {
+ /*
+ If items[i] does not need conversion to the current temporal data
+ type, then we trust items[i]->maybe_null, which was already ORred
+ to func->maybe_null in the argument loop in fix_fields().
+ If items[i] requires conversion to the current temporal data type,
+ then conversion can fail and return NULL even for NOT NULL items.
+ */
+ const Type_handler *ha= items[i]->type_handler();
+ if (hf == ha)
+ continue; // No conversion.
+ if (ha->cmp_type() != TIME_RESULT)
+ {
+ func->maybe_null= true; // Conversion from non-temporal is not safe
+ break;
+ }
+ timestamp_type tf= hf->mysql_timestamp_type();
+ timestamp_type ta= ha->mysql_timestamp_type();
+ if (tf == ta ||
+ (tf == MYSQL_TIMESTAMP_DATETIME && ta == MYSQL_TIMESTAMP_DATE))
+ {
+ /*
+ If handlers have the same mysql_timestamp_type(),
+ then conversion is NULL safe. Conversion from DATE to DATETIME
+ is also safe. This branch includes data type pairs:
+ Function return type Argument type Comment
+ -------------------- ------------- -------------
+ TIMESTAMP TIMESTAMP no conversion
+ TIMESTAMP DATETIME not possible
+ TIMESTAMP DATE not possible
+ DATETIME DATETIME no conversion
+ DATETIME TIMESTAMP safe conversion
+ DATETIME DATE safe conversion
+ TIME TIME no conversion
+
+ Note, a function cannot return TIMESTAMP if it has non-TIMESTAMP
+ arguments (it would return DATETIME in such case).
+ */
+ DBUG_ASSERT(hf->field_type() != MYSQL_TYPE_TIMESTAMP || tf == ta);
+ continue;
+ }
+ /*
+ Here we have the following data type pairs that did not match
+ the condition above:
+
+ Function return type Argument type Comment
+ -------------------- ------------- -------
+ TIMESTAMP TIME Not possible
+ DATETIME TIME depends on OLD_MODE_ZERO_DATE_TIME_CAST
+ TIME TIMESTAMP Not possible
+ TIME DATETIME Not possible
+ TIME DATE Not possible
+
+ Most pairs are not possible, because the function data type
+ would be DATETIME (according to LEAST/GREATEST aggregation rules).
+ Conversion to DATETIME from TIME is not safe when
+ OLD_MODE_ZERO_DATE_TIME_CAST is set:
+ - negative TIME values cannot be converted to not-NULL DATETIME values
+ - TIME values can produce DATETIME values that do not pass
+ NO_ZERO_DATE and NO_ZERO_IN_DATE tests.
+ */
+ DBUG_ASSERT(hf->field_type() == MYSQL_TYPE_DATETIME);
+ if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST))
+ continue;
+ func->maybe_null= true;
+ break;
+ }
+ return rc;
+}
+
+
+bool Type_handler_date_common::
+ Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const
+{
+ func->fix_attributes_date();
+ if (func->maybe_null)
+ return false;
+ /*
+ We cannot trust the generic maybe_null value calculated during fix_fields().
+ If a conversion from non-temoral types to DATE happens,
+ then the result can be NULL (even if all arguments are not NULL).
+ */
+ for (uint i= 0; i < nitems; i++)
+ {
+ if (items[i]->type_handler()->cmp_type() != TIME_RESULT)
+ {
+ func->maybe_null= true;
+ break;
+ }
+ }
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const
+{
+ /*
+ DOUBLE is an exception and aggregates attributes differently
+ for LEAST/GREATEST vs CASE-alike functions. See the comment in
+ Item_func_min_max::aggregate_attributes_real().
+ */
+ func->aggregate_attributes_real(items, nitems);
+ return false;
+}
+
+/*************************************************************************/
+
+bool Type_handler_int_result::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ /*
+ "this" is equal func->args[0]->type_handler() here, e.g. for MIN()/MAX().
+ func->unsigned_flag is not reliably set yet.
+ It will be set by the call below (copied from args[0]).
+ */
+ const Type_handler *h= is_unsigned()
+ ? (Type_handler *)&type_handler_ulonglong
+ : (Type_handler *)&type_handler_slonglong;
+ return func->fix_length_and_dec_numeric(h);
+}
+
+
+bool Type_handler_bool::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ return func->fix_length_and_dec_numeric(&type_handler_bool);
+}
+
+
+bool Type_handler_real_result::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ (void) func->fix_length_and_dec_numeric(&type_handler_double);
+ func->max_length= func->float_length(func->decimals);
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ return func->fix_length_and_dec_numeric(&type_handler_newdecimal);
+}
+
+
+bool Type_handler_string_result::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ return func->fix_length_and_dec_string();
+}
+
+
+bool Type_handler_temporal_result::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ return func->fix_length_and_dec_generic();
+}
+
+
+/*************************************************************************/
+
+bool Type_handler_int_result::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+
+
+/*************************************************************************/
+
+bool Type_handler_int_result::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+
+
+/*************************************************************************/
+
+bool Type_handler_int_result::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+/*************************************************************************/
+
+bool Type_handler_real_result::Item_val_bool(Item *item) const
+{
+ return item->val_real() != 0.0;
+}
+
+bool Type_handler_int_result::Item_val_bool(Item *item) const
+{
+ return item->val_int() != 0;
+}
+
+bool Type_handler_temporal_result::Item_val_bool(Item *item) const
+{
+ return item->val_real() != 0.0;
+}
+
+bool Type_handler_string_result::Item_val_bool(Item *item) const
+{
+ return item->val_real() != 0.0;
+}
+
+
+/*************************************************************************/
+
+
+bool Type_handler::Item_get_date_with_warn(THD *thd, Item *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ const TABLE_SHARE *s= item->field_table_or_null();
+ Temporal::Warn_push warn(thd, s ? s->db.str : nullptr,
+ s ? s->table_name.str : nullptr,
+ item->field_name_or_null(), ltime, fuzzydate);
+ Item_get_date(thd, item, &warn, ltime, fuzzydate);
+ return ltime->time_type < 0;
+}
+
+
+bool Type_handler::Item_func_hybrid_field_type_get_date_with_warn(THD *thd,
+ Item_func_hybrid_field_type *item,
+ MYSQL_TIME *ltime,
+ date_mode_t mode) const
+{
+ const TABLE_SHARE *s= item->field_table_or_null();
+ Temporal::Warn_push warn(thd, s ? s->db.str : nullptr,
+ s ? s->table_name.str : nullptr,
+ item->field_name_or_null(), ltime, mode);
+ Item_func_hybrid_field_type_get_date(thd, item, &warn, ltime, mode);
+ return ltime->time_type < 0;
+}
+
+
+/************************************************************************/
+void Type_handler_decimal_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ new(ltime) Temporal_hybrid(thd, warn, VDec(item).ptr(), fuzzydate);
+}
+
+
+void Type_handler_int_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *to,
+ date_mode_t mode) const
+{
+ new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null(), mode);
+}
+
+
+void Type_handler_year::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ VYear year(item);
+ DBUG_ASSERT(!year.truncated());
+ Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()),
+ item->unsigned_flag);
+ new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate);
+}
+
+
+void Type_handler_real_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ new(ltime) Temporal_hybrid(thd, warn, item->to_double_null(), fuzzydate);
+}
+
+
+void Type_handler_string_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t mode) const
+{
+ StringBuffer<40> tmp;
+ new(ltime) Temporal_hybrid(thd, warn, item->val_str(&tmp), mode);
+}
+
+
+void Type_handler_temporal_result::Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ DBUG_ASSERT(0); // Temporal type items must implement native get_date()
+ item->null_value= true;
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
+}
+
+
+/*************************************************************************/
+
+longlong Type_handler_real_result::
+ Item_val_int_signed_typecast(Item *item) const
+{
+ return item->val_int_signed_typecast_from_real();
+}
+
+longlong Type_handler_int_result::
+ Item_val_int_signed_typecast(Item *item) const
+{
+ return item->val_int();
+}
+
+longlong Type_handler_decimal_result::
+ Item_val_int_signed_typecast(Item *item) const
+{
+ return VDec(item).to_longlong(false);
+}
+
+longlong Type_handler_temporal_result::
+ Item_val_int_signed_typecast(Item *item) const
+{
+ return item->val_int();
+}
+
+longlong Type_handler_string_result::
+ Item_val_int_signed_typecast(Item *item) const
+{
+ return item->val_int_signed_typecast_from_str();
+}
+
+/*************************************************************************/
+
+longlong Type_handler_real_result::
+ Item_val_int_unsigned_typecast(Item *item) const
+{
+ return item->val_int_unsigned_typecast_from_real();
+}
+
+longlong Type_handler_int_result::
+ Item_val_int_unsigned_typecast(Item *item) const
+{
+ return item->val_int_unsigned_typecast_from_int();
+}
+
+longlong Type_handler_temporal_result::
+ Item_val_int_unsigned_typecast(Item *item) const
+{
+ return item->val_int_unsigned_typecast_from_int();
+}
+
+longlong Type_handler_time_common::
+ Item_val_int_unsigned_typecast(Item *item) const
+{
+ /*
+ TODO: this should eventually be fixed to do rounding
+ when TIME_ROUND_FRACTIONAL is enabled, together with
+ Field_{tiny|short|long|longlong}::store_time_dec().
+ See MDEV-19502.
+ */
+ THD *thd= current_thd;
+ Time tm(thd, item);
+ DBUG_ASSERT(!tm.is_valid_time() == item->null_value);
+ if (!tm.is_valid_time())
+ return 0;
+ longlong res= tm.to_longlong();
+ if (res < 0)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DATA_OVERFLOW, ER_THD(thd, ER_DATA_OVERFLOW),
+ ErrConvTime(tm.get_mysql_time()).ptr(),
+ "UNSIGNED BIGINT");
+ return 0;
+ }
+ return res;
+}
+
+longlong Type_handler_string_result::
+ Item_val_int_unsigned_typecast(Item *item) const
+{
+ return item->val_int_unsigned_typecast_from_str();
+}
+
+/*************************************************************************/
+
+String *
+Type_handler_real_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
+ String *str) const
+{
+ return item->val_str_ascii_from_val_real(str);
+}
+
+
+String *
+Type_handler_decimal_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
+ String *str) const
+{
+ return item->val_str_ascii_from_val_real(str);
+}
+
+
+String *
+Type_handler_int_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
+ String *str) const
+{
+ return item->val_str_ascii_from_val_int(str);
+}
+
+
+String *
+Type_handler_temporal_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
+ String *str) const
+{
+ return item->val_str_ascii_from_val_str(str);
+}
+
+
+String *
+Type_handler_string_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
+ String *str) const
+{
+ return item->val_str_ascii_from_val_str(str);
+}
+
+/***************************************************************************/
+
+String *
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ return VDec_op(item).to_string_round(str, item->decimals);
+}
+
+
+double
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_real(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return VDec_op(item).to_double();
+}
+
+
+longlong
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_int(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return VDec_op(item).to_longlong(item->unsigned_flag);
+}
+
+
+my_decimal *
+Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *item,
+ my_decimal *dec) const
+{
+ return VDec_op(item).to_decimal(dec);
+}
+
+
+void
+Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ new (ltime) Temporal_hybrid(thd, warn, VDec_op(item).ptr(), fuzzydate);
+}
+
+
+void
+Type_handler_year::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ VYear_op year(item);
+ DBUG_ASSERT(!year.truncated());
+ Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()),
+ item->unsigned_flag);
+ new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate);
+}
+
+
+/***************************************************************************/
+
+
+String *
+Type_handler_int_result::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ return item->val_str_from_int_op(str);
+}
+
+
+double
+Type_handler_int_result::Item_func_hybrid_field_type_val_real(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_real_from_int_op();
+}
+
+
+longlong
+Type_handler_int_result::Item_func_hybrid_field_type_val_int(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_int_from_int_op();
+}
+
+
+my_decimal *
+Type_handler_int_result::Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *item,
+ my_decimal *dec) const
+{
+ return item->val_decimal_from_int_op(dec);
+}
+
+
+void
+Type_handler_int_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *to,
+ date_mode_t mode) const
+{
+ new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null_op(), mode);
+}
+
+
+/***************************************************************************/
+
+String *
+Type_handler_double::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ return item->val_str_from_real_op(str);
+}
+
+String *
+Type_handler_float::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ Float nr(item->real_op());
+ if (item->null_value)
+ return 0;
+ nr.to_string(str, item->decimals);
+ return str;
+}
+
+double
+Type_handler_real_result::Item_func_hybrid_field_type_val_real(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_real_from_real_op();
+}
+
+
+longlong
+Type_handler_real_result::Item_func_hybrid_field_type_val_int(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_int_from_real_op();
+}
+
+
+my_decimal *
+Type_handler_real_result::Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *item,
+ my_decimal *dec) const
+{
+ return item->val_decimal_from_real_op(dec);
+}
+
+
+void
+Type_handler_real_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *to,
+ date_mode_t mode) const
+{
+ new(to) Temporal_hybrid(thd, warn, item->to_double_null_op(), mode);
+}
+
+
+/***************************************************************************/
+
+String *
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ return item->val_str_from_date_op(str);
+}
+
+
+double
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_real(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_real_from_date_op();
+}
+
+
+longlong
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_int(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_int_from_date_op();
+}
+
+
+my_decimal *
+Type_handler_temporal_result::Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *item,
+ my_decimal *dec) const
+{
+ return item->val_decimal_from_date_op(dec);
+}
+
+
+void
+Type_handler_temporal_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ if (item->date_op(thd, ltime, fuzzydate))
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
+}
+
+
+/***************************************************************************/
+
+String *
+Type_handler_time_common::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ return item->val_str_from_time_op(str);
+}
+
+
+double
+Type_handler_time_common::Item_func_hybrid_field_type_val_real(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_real_from_time_op();
+}
+
+
+longlong
+Type_handler_time_common::Item_func_hybrid_field_type_val_int(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_int_from_time_op();
+}
+
+
+my_decimal *
+Type_handler_time_common::Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *item,
+ my_decimal *dec) const
+{
+ return item->val_decimal_from_time_op(dec);
+}
+
+
+void
+Type_handler_time_common::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ if (item->time_op(thd, ltime))
+ set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
+}
+
+
+/***************************************************************************/
+
+String *
+Type_handler_string_result::Item_func_hybrid_field_type_val_str(
+ Item_func_hybrid_field_type *item,
+ String *str) const
+{
+ return item->val_str_from_str_op(str);
+}
+
+
+double
+Type_handler_string_result::Item_func_hybrid_field_type_val_real(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_real_from_str_op();
+}
+
+
+longlong
+Type_handler_string_result::Item_func_hybrid_field_type_val_int(
+ Item_func_hybrid_field_type *item)
+ const
+{
+ return item->val_int_from_str_op();
+}
+
+
+my_decimal *
+Type_handler_string_result::Item_func_hybrid_field_type_val_decimal(
+ Item_func_hybrid_field_type *item,
+ my_decimal *dec) const
+{
+ return item->val_decimal_from_str_op(dec);
+}
+
+
+void
+Type_handler_string_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ Temporal::Warn *warn,
+ MYSQL_TIME *ltime,
+ date_mode_t mode) const
+{
+ StringBuffer<40> tmp;
+ String *res= item->str_op(&tmp);
+ DBUG_ASSERT((res == NULL) == item->null_value);
+ new(ltime) Temporal_hybrid(thd, warn, res, mode);
+}
+
+/***************************************************************************/
+
+bool Type_handler_numeric::
+ Item_func_between_fix_length_and_dec(Item_func_between *func) const
+{
+ return func->fix_length_and_dec_numeric(current_thd);
+}
+
+bool Type_handler_temporal_result::
+ Item_func_between_fix_length_and_dec(Item_func_between *func) const
+{
+ return func->fix_length_and_dec_temporal(current_thd);
+}
+
+bool Type_handler_string_result::
+ Item_func_between_fix_length_and_dec(Item_func_between *func) const
+{
+ return func->fix_length_and_dec_string(current_thd);
+}
+
+
+longlong Type_handler_row::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ DBUG_ASSERT(0);
+ func->null_value= true;
+ return 0;
+}
+
+longlong Type_handler_string_result::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_string();
+}
+
+longlong Type_handler_temporal_with_date::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_datetime();
+}
+
+longlong Type_handler_time_common::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_time();
+}
+
+longlong Type_handler_timestamp_common::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_native();
+}
+
+longlong Type_handler_int_result::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_int();
+}
+
+longlong Type_handler_real_result::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_real();
+}
+
+longlong Type_handler_decimal_result::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_decimal();
+}
+
+/***************************************************************************/
+
+cmp_item *Type_handler_int_result::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_int;
+}
+
+cmp_item *Type_handler_real_result::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_real;
+}
+
+cmp_item *Type_handler_decimal_result::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_decimal;
+}
+
+
+cmp_item *Type_handler_string_result::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_sort_string(cs);
+}
+
+cmp_item *Type_handler_row::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_row;
+}
+
+cmp_item *Type_handler_time_common::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_time;
+}
+
+cmp_item *Type_handler_temporal_with_date::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_datetime;
+}
+
+cmp_item *Type_handler_timestamp_common::make_cmp_item(THD *thd,
+ CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_timestamp;
+}
+
+/***************************************************************************/
+
+static int srtcmp_in(const void *cs_, const void *x_, const void *y_)
+{
+ const CHARSET_INFO *cs= static_cast<const CHARSET_INFO *>(cs_);
+ const String *x= static_cast<const String *>(x_);
+ const String *y= static_cast<const String *>(y_);
+ return cs->strnncollsp(x->ptr(), x->length(), y->ptr(), y->length());
+}
+
+in_vector *Type_handler_string_result::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_string(thd, nargs, (qsort2_cmp) srtcmp_in,
+ func->compare_collation());
+
+}
+
+
+in_vector *Type_handler_int_result::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_longlong(thd, nargs);
+}
+
+
+in_vector *Type_handler_real_result::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_double(thd, nargs);
+}
+
+
+in_vector *Type_handler_decimal_result::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_decimal(thd, nargs);
+}
+
+
+in_vector *Type_handler_time_common::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_time(thd, nargs);
+}
+
+
+in_vector *
+Type_handler_temporal_with_date::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_datetime(thd, nargs);
+}
+
+
+in_vector *
+Type_handler_timestamp_common::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_timestamp(thd, nargs);
+}
+
+
+in_vector *Type_handler_row::make_in_vector(THD *thd,
+ const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_row(thd, nargs, 0);
+}
+
+/***************************************************************************/
+
+bool Type_handler_string_result::
+ Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func) const
+{
+ if (func->agg_all_arg_charsets_for_comparison())
+ return true;
+ if (func->compatible_types_scalar_bisection_possible())
+ {
+ return func->value_list_convert_const_to_int(thd) ||
+ func->fix_for_scalar_comparison_using_bisection(thd);
+ }
+ return
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) STRING_RESULT);
+}
+
+
+bool Type_handler_int_result::
+ Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func) const
+{
+ /*
+ Does not need to call value_list_convert_const_to_int()
+ as already handled by int handler.
+ */
+ return func->compatible_types_scalar_bisection_possible() ?
+ func->fix_for_scalar_comparison_using_bisection(thd) :
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) INT_RESULT);
+}
+
+
+bool Type_handler_real_result::
+ Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func) const
+{
+ return func->compatible_types_scalar_bisection_possible() ?
+ (func->value_list_convert_const_to_int(thd) ||
+ func->fix_for_scalar_comparison_using_bisection(thd)) :
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) REAL_RESULT);
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func) const
+{
+ return func->compatible_types_scalar_bisection_possible() ?
+ (func->value_list_convert_const_to_int(thd) ||
+ func->fix_for_scalar_comparison_using_bisection(thd)) :
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) DECIMAL_RESULT);
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func) const
+{
+ return func->compatible_types_scalar_bisection_possible() ?
+ (func->value_list_convert_const_to_int(thd) ||
+ func->fix_for_scalar_comparison_using_bisection(thd)) :
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) TIME_RESULT);
+}
+
+
+bool Type_handler_row::Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func) const
+{
+ return func->compatible_types_row_bisection_possible() ?
+ func->fix_for_row_comparison_using_bisection(thd) :
+ func->fix_for_row_comparison_using_cmp_items(thd);
+}
+
+/***************************************************************************/
+
+String *Type_handler_string_result::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return func->val_str_native(str);
+}
+
+
+String *Type_handler_time_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return Time(func).to_string(str, func->decimals);
+}
+
+
+String *Type_handler_date_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return Date(func).to_string(str);
+}
+
+
+String *Type_handler_datetime_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return Datetime(func).to_string(str, func->decimals);
+}
+
+
+String *Type_handler_timestamp_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ THD *thd= current_thd;
+ return Timestamp_or_zero_datetime_native_null(thd, func).
+ to_datetime(thd).to_string(str, func->decimals);
+}
+
+
+String *Type_handler_int_result::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return func->val_string_from_int(str);
+}
+
+
+String *Type_handler_decimal_result::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return VDec(func).to_string_round(str, func->decimals);
+}
+
+
+String *Type_handler_double::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return func->val_string_from_real(str);
+}
+
+
+String *Type_handler_float::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ Float nr(func->val_real());
+ if (func->null_value)
+ return 0;
+ nr.to_string(str, func->decimals);
+ return str;
+}
+
+
+double Type_handler_string_result::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return func->val_real_native();
+}
+
+
+double Type_handler_time_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Time(current_thd, func).to_double();
+}
+
+
+double Type_handler_date_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Date(current_thd, func).to_double();
+}
+
+
+double Type_handler_datetime_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_double();
+}
+
+
+double Type_handler_timestamp_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ THD *thd= current_thd;
+ return Timestamp_or_zero_datetime_native_null(thd, func).
+ to_datetime(thd).to_double();
+}
+
+
+double Type_handler_numeric::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return func->val_real_native();
+}
+
+
+longlong Type_handler_string_result::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return func->val_int_native();
+}
+
+
+longlong Type_handler_time_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Time(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_date_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Date(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_datetime_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_timestamp_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ THD *thd= current_thd;
+ return Timestamp_or_zero_datetime_native_null(thd, func).
+ to_datetime(thd).to_longlong();
+}
+
+
+longlong Type_handler_numeric::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return func->val_int_native();
+}
+
+
+my_decimal *Type_handler_string_result::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return func->val_decimal_native(dec);
+}
+
+
+my_decimal *Type_handler_numeric::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return func->val_decimal_native(dec);
+}
+
+
+my_decimal *Type_handler_time_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Time(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_date_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Date(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_datetime_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Datetime(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_timestamp_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ THD *thd= current_thd;
+ return Timestamp_or_zero_datetime_native_null(thd, func).
+ to_datetime(thd).to_decimal(dec);
+}
+
+
+bool Type_handler_string_result::
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
+{
+ /*
+ just like ::val_int() method of a string item can be called,
+ for example, SELECT CONCAT("10", "12") + 1,
+ ::get_date() can be called for non-temporal values,
+ for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09"))
+ */
+ return func->get_date_from_string(thd, ltime, fuzzydate);
+}
+
+
+bool Type_handler_numeric::
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
+{
+ return Item_get_date_with_warn(thd, func, ltime, fuzzydate);
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
+{
+ /*
+ - If the caller specified TIME_TIME_ONLY, then it's going to convert
+ a DATETIME or DATE to TIME. So we pass the default flags for date. This is
+ exactly the same with what Item_func_min_max_val_{int|real|decimal|str} or
+ Item_send_datetime() do. We return the value in accordance with the
+ current session date flags and let the caller further convert it to TIME.
+ - If the caller did not specify TIME_TIME_ONLY, then return the value
+ according to the flags supplied by the caller.
+ */
+ return func->get_date_native(thd, ltime,
+ fuzzydate & TIME_TIME_ONLY ?
+ Datetime::Options(thd) :
+ fuzzydate);
+}
+
+bool Type_handler_time_common::
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
+{
+ return func->get_time_native(thd, ltime);
+}
+
+
+bool Type_handler_timestamp_common::
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
+{
+ return Timestamp_or_zero_datetime_native_null(thd, func).
+ to_datetime(thd).copy_to_mysql_time(ltime);
+}
+
+/***************************************************************************/
+
+/**
+ Get a string representation of the Item value.
+ See sql_type.h for details.
+*/
+String *Type_handler_row::
+ print_item_value(THD *thd, Item *item, String *str) const
+{
+ CHARSET_INFO *cs= thd->variables.character_set_client;
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> val(cs);
+ str->append(STRING_WITH_LEN("ROW("));
+ for (uint i= 0 ; i < item->cols(); i++)
+ {
+ if (i > 0)
+ str->append(',');
+ Item *elem= item->element_index(i);
+ String *tmp= elem->type_handler()->print_item_value(thd, elem, &val);
+ if (tmp)
+ str->append(*tmp);
+ else
+ str->append(STRING_WITH_LEN("NULL"));
+ }
+ str->append(STRING_WITH_LEN(")"));
+ return str;
+}
+
+
+/**
+ Get a string representation of the Item value,
+ using the character string format with its charset and collation, e.g.
+ latin1 'string' COLLATE latin1_german2_ci
+*/
+String *Type_handler::
+ print_item_value_csstr(THD *thd, Item *item, String *str) const
+{
+ String *result= item->val_str(str);
+
+ if (!result)
+ return NULL;
+
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> buf(result->charset());
+ CHARSET_INFO *cs= thd->variables.character_set_client;
+
+ buf.append('_');
+ buf.append(result->charset()->csname);
+ if (cs->escape_with_backslash_is_dangerous)
+ buf.append(' ');
+ append_query_string(cs, &buf, result->ptr(), result->length(),
+ thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
+ buf.append(" COLLATE '");
+ buf.append(item->collation.collation->name);
+ buf.append('\'');
+ str->copy(buf);
+
+ return str;
+}
+
+
+String *Type_handler_numeric::
+ print_item_value(THD *thd, Item *item, String *str) const
+{
+ return item->val_str(str);
+}
+
+
+String *Type_handler::
+ print_item_value_temporal(THD *thd, Item *item, String *str,
+ const Name &type_name, String *buf) const
+{
+ String *result= item->val_str(buf);
+ return !result ||
+ str->realloc(type_name.length() + result->length() + 2) ||
+ str->copy(type_name.ptr(), type_name.length(), &my_charset_latin1) ||
+ str->append('\'') ||
+ str->append(result->ptr(), result->length()) ||
+ str->append('\'') ?
+ NULL :
+ str;
+}
+
+
+String *Type_handler_time_common::
+ print_item_value(THD *thd, Item *item, String *str) const
+{
+ StringBuffer<MAX_TIME_FULL_WIDTH+1> buf;
+ return print_item_value_temporal(thd, item, str,
+ Name(STRING_WITH_LEN("TIME")), &buf);
+}
+
+
+String *Type_handler_date_common::
+ print_item_value(THD *thd, Item *item, String *str) const
+{
+ StringBuffer<MAX_DATE_WIDTH+1> buf;
+ return print_item_value_temporal(thd, item, str,
+ Name(STRING_WITH_LEN("DATE")), &buf);
+}
+
+
+String *Type_handler_datetime_common::
+ print_item_value(THD *thd, Item *item, String *str) const
+{
+ StringBuffer<MAX_DATETIME_FULL_WIDTH+1> buf;
+ return print_item_value_temporal(thd, item, str,
+ Name(STRING_WITH_LEN("TIMESTAMP")), &buf);
+}
+
+
+String *Type_handler_timestamp_common::
+ print_item_value(THD *thd, Item *item, String *str) const
+{
+ StringBuffer<MAX_DATETIME_FULL_WIDTH+1> buf;
+ return print_item_value_temporal(thd, item, str,
+ Name(STRING_WITH_LEN("TIMESTAMP")), &buf);
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_int(this, item->arguments()[0],
+ field_type() == MYSQL_TYPE_LONGLONG);
+ return false;
+}
+
+
+bool Type_handler_year::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_int(&type_handler_ulong, item->arguments()[0], false);
+ return false;
+}
+
+
+bool Type_handler_hex_hybrid::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_hex_hybrid();
+ return false;
+}
+
+
+bool Type_handler_bit::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ uint nbits= item->arguments()[0]->max_length;
+ item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits);
+ return false;
+}
+
+
+bool Type_handler_typelib::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_length_and_dec_long_or_longlong(5, true);
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_decimal();
+ return false;
+}
+
+
+bool Type_handler_date_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ static const Type_std_attributes attr(Type_numeric_attributes(8, 0, true),
+ DTCollation_numeric());
+ item->fix_arg_int(&type_handler_ulong, &attr, false);
+ return false;
+}
+
+
+bool Type_handler_time_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_time();
+ return false;
+}
+
+
+bool Type_handler_datetime_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_datetime();
+ return false;
+}
+
+
+bool Type_handler_timestamp_common::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_datetime();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ item->fix_arg_double();
+ return false;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->Type_std_attributes::set(item->arguments()[0]);
+ item->set_handler(this);
+ return false;
+}
+
+
+bool Type_handler_year::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->Type_std_attributes::set(item->arguments()[0]);
+ item->set_handler(&type_handler_ulong);
+ return false;
+}
+
+
+bool Type_handler_bit::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ uint nbits= item->arguments()[0]->max_length;
+ item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits);
+ return false;
+}
+
+
+bool Type_handler_typelib::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_long_or_longlong(5, true);
+ return false;
+}
+
+
+bool Type_handler_hex_hybrid::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ uint nchars= item->arguments()[0]->decimal_precision();
+ item->fix_length_and_dec_long_or_longlong(nchars, true);
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_int_or_decimal();
+ return false;
+}
+
+
+bool Type_handler_date_common::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ static const Type_numeric_attributes attr(8, 0/*dec*/, true/*unsigned*/);
+ item->Type_std_attributes::set(attr, DTCollation_numeric());
+ item->set_handler(&type_handler_ulong);
+ return false;
+}
+
+
+bool Type_handler_time_common::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_time();
+ return false;
+}
+
+
+bool Type_handler_datetime_common::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_datetime();
+ return false;
+}
+
+
+bool Type_handler_timestamp_common::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_datetime();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler::
+ Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+{
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
+bool Type_handler::
+ Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+{
+ const Item *arg= item->arguments()[0];
+ if (!arg->unsigned_flag && arg->val_int_min() < 0)
+ {
+ /*
+ Negative arguments produce long results:
+ CAST(1-2 AS UNSIGNED) -> 18446744073709551615
+ */
+ item->max_length= MAX_BIGINT_WIDTH;
+ return false;
+ }
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+{
+ item->fix_length_and_dec_string();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+{
+ const Item *arg= item->arguments()[0];
+ if (!arg->unsigned_flag && // Not HEX hybrid
+ arg->max_char_length() > 1) // Can be negative
+ {
+ // String arguments can give long results: '-1' -> 18446744073709551614
+ item->max_length= MAX_BIGINT_WIDTH;
+ return false;
+ }
+ item->fix_length_and_dec_string();
+ return false;
+}
+
+bool Type_handler_real_result::
+ Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler::
+ Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const
+{
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
+bool Type_handler::
+ Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const
+{
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
+bool Type_handler::
+ Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const
+{
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
+bool Type_handler::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ item->fix_length_and_dec_generic();
+ return false;
+}
+
+
+bool Type_handler_numeric::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ item->fix_length_and_dec_numeric();
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ item->fix_length_and_dec_str();
+ return false;
+}
+
+
+bool Type_handler::
+ Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
+{
+ uint dec= item->decimals == NOT_FIXED_DEC ?
+ item->arguments()[0]->time_precision(current_thd) :
+ item->decimals;
+ item->fix_attributes_temporal(MIN_TIME_WIDTH, dec);
+ item->maybe_null= true;
+ return false;
+}
+
+
+bool Type_handler::
+ Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
+{
+ item->fix_attributes_temporal(MAX_DATE_WIDTH, 0);
+ item->maybe_null= true;
+ return false;
+}
+
+
+bool Type_handler::
+ Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
+ const
+{
+ uint dec= item->decimals == NOT_FIXED_DEC ?
+ item->arguments()[0]->datetime_precision(current_thd) :
+ item->decimals;
+ item->fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
+ item->maybe_null= true;
+ return false;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
+{
+ DBUG_ASSERT(0);
+ return true;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
+{
+ item->fix_length_and_dec_temporal(true);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
+{
+ DBUG_ASSERT(0);
+ return true;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
+{
+ item->fix_length_and_dec_temporal(true);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
+{
+ DBUG_ASSERT(0);
+ return true;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
+{
+ item->fix_length_and_dec_temporal(true);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const
+{
+ DBUG_ASSERT(0);
+ return true;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const
+{
+ item->fix_length_and_dec_temporal(false);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
+{
+ DBUG_ASSERT(0);
+ return true;
+}
+
+
+bool Type_handler_int_result::
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
+{
+ item->fix_length_and_dec_int();
+ return false;
+}
+
+
+bool Type_handler_real_result::
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
+{
+ item->fix_length_and_dec_decimal();
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
+{
+ item->fix_length_and_dec_temporal(true);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
+{
+ item->fix_length_and_dec_double();
+ return false;
+}
+
+/***************************************************************************/
+
+const Vers_type_handler* Type_handler_temporal_result::vers() const
+{
+ return &vers_type_timestamp;
+}
+
+const Vers_type_handler* Type_handler_string_result::vers() const
+{
+ return &vers_type_timestamp;
+}
+
+const Vers_type_handler* Type_handler_blob_common::vers() const
+
+{
+ return &vers_type_timestamp;
+}
+
+/***************************************************************************/
+
+uint Type_handler::Item_time_precision(THD *thd, Item *item) const
+{
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+}
+
+
+uint Type_handler::Item_datetime_precision(THD *thd, Item *item) const
+{
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+}
+
+
+uint Type_handler_string_result::Item_temporal_precision(THD *thd, Item *item,
+ bool is_time) const
+{
+ StringBuffer<64> buf;
+ String *tmp;
+ MYSQL_TIME_STATUS status;
+ DBUG_ASSERT(item->is_fixed());
+ // Nanosecond rounding is not needed here, for performance purposes
+ if ((tmp= item->val_str(&buf)) &&
+ (is_time ?
+ Time(thd, &status, tmp->ptr(), tmp->length(), tmp->charset(),
+ Time::Options(TIME_TIME_ONLY, TIME_FRAC_TRUNCATE,
+ Time::DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)).
+ is_valid_time() :
+ Datetime(thd, &status, tmp->ptr(), tmp->length(), tmp->charset(),
+ Datetime::Options(TIME_FUZZY_DATES, TIME_FRAC_TRUNCATE)).
+ is_valid_datetime()))
+ return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+}
+
+/***************************************************************************/
+
+uint Type_handler::Item_decimal_scale(const Item *item) const
+{
+ return item->decimals < NOT_FIXED_DEC ?
+ item->decimals :
+ MY_MIN(item->max_length, DECIMAL_MAX_SCALE);
+}
+
+uint Type_handler_temporal_result::
+ Item_decimal_scale_with_seconds(const Item *item) const
+{
+ return item->decimals < NOT_FIXED_DEC ?
+ item->decimals :
+ TIME_SECOND_PART_DIGITS;
+}
+
+uint Type_handler::Item_divisor_precision_increment(const Item *item) const
+{
+ return item->decimals;
+}
+
+uint Type_handler_temporal_result::
+ Item_divisor_precision_increment_with_seconds(const Item *item) const
+{
+ return item->decimals < NOT_FIXED_DEC ?
+ item->decimals :
+ TIME_SECOND_PART_DIGITS;
+}
+
+/***************************************************************************/
+
+uint Type_handler_string_result::Item_decimal_precision(const Item *item) const
+{
+ uint res= item->max_char_length();
+ /*
+ Return at least one decimal digit, even if Item::max_char_length()
+ returned 0. This is important to avoid attempts to create fields of types
+ INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
+ CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
+ */
+ return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
+}
+
+uint Type_handler_real_result::Item_decimal_precision(const Item *item) const
+{
+ uint res= item->max_char_length();
+ return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
+}
+
+uint Type_handler_decimal_result::Item_decimal_precision(const Item *item) const
+{
+ uint prec= my_decimal_length_to_precision(item->max_char_length(),
+ item->decimals,
+ item->unsigned_flag);
+ return MY_MIN(prec, DECIMAL_MAX_PRECISION);
+}
+
+uint Type_handler_int_result::Item_decimal_precision(const Item *item) const
+{
+ uint prec= my_decimal_length_to_precision(item->max_char_length(),
+ item->decimals,
+ item->unsigned_flag);
+ return MY_MIN(prec, DECIMAL_MAX_PRECISION);
+}
+
+uint Type_handler_time_common::Item_decimal_precision(const Item *item) const
+{
+ return 7 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+}
+
+uint Type_handler_date_common::Item_decimal_precision(const Item *item) const
+{
+ return 8;
+}
+
+uint Type_handler_datetime_common::Item_decimal_precision(const Item *item) const
+{
+ return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+}
+
+uint Type_handler_timestamp_common::Item_decimal_precision(const Item *item) const
+{
+ return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+}
+
+/***************************************************************************/
+
+bool Type_handler_real_result::
+ subquery_type_allows_materialization(const Item *inner,
+ const Item *outer,
+ bool is_in_predicate) const
+{
+ DBUG_ASSERT(inner->cmp_type() == REAL_RESULT);
+ return outer->cmp_type() == REAL_RESULT;
+}
+
+
+bool Type_handler_int_result::
+ subquery_type_allows_materialization(const Item *inner,
+ const Item *outer,
+ bool is_in_predicate) const
+{
+ DBUG_ASSERT(inner->cmp_type() == INT_RESULT);
+ return outer->cmp_type() == INT_RESULT;
+}
+
+
+bool Type_handler_decimal_result::
+ subquery_type_allows_materialization(const Item *inner,
+ const Item *outer,
+ bool is_in_predicate) const
+{
+ DBUG_ASSERT(inner->cmp_type() == DECIMAL_RESULT);
+ return outer->cmp_type() == DECIMAL_RESULT;
+}
+
+
+bool Type_handler_string_result::
+ subquery_type_allows_materialization(const Item *inner,
+ const Item *outer,
+ bool is_in_predicate) const
+{
+ DBUG_ASSERT(inner->cmp_type() == STRING_RESULT);
+ if (outer->cmp_type() == STRING_RESULT &&
+ /*
+ Materialization also is unable to work when create_tmp_table() will
+ create a blob column because item->max_length is too big.
+ The following test is copied from varstring_type_handler().
+ */
+ !inner->too_big_for_varchar())
+ {
+ if (outer->collation.collation == inner->collation.collation)
+ return true;
+ if (is_in_predicate)
+ {
+ Charset inner_col(inner->collation.collation);
+ if (inner_col.encoding_allows_reinterpret_as(outer->
+ collation.collation) &&
+ inner_col.eq_collation_specific_names(outer->collation.collation))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Type_handler_temporal_result::
+ subquery_type_allows_materialization(const Item *inner,
+ const Item *outer,
+ bool is_in_predicate) const
+{
+ DBUG_ASSERT(inner->cmp_type() == TIME_RESULT);
+ return mysql_timestamp_type() ==
+ outer->type_handler()->mysql_timestamp_type();
+}
+
+/***************************************************************************/
+
+
+const Type_handler *
+Type_handler_null::type_handler_for_tmp_table(const Item *item) const
+{
+ return &type_handler_string;
+}
+
+
+const Type_handler *
+Type_handler_null::type_handler_for_union(const Item *item) const
+{
+ return &type_handler_string;
+}
+
+
+const Type_handler *
+Type_handler_olddecimal::type_handler_for_tmp_table(const Item *item) const
+{
+ return &type_handler_newdecimal;
+}
+
+const Type_handler *
+Type_handler_olddecimal::type_handler_for_union(const Item *item) const
+{
+ return &type_handler_newdecimal;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler::check_null(const Item *item, st_value *value) const
+{
+ if (item->null_value)
+ {
+ value->m_type= DYN_COL_NULL;
+ return true;
+ }
+ return false;
+}
+
+
+bool Type_handler_null::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= DYN_COL_NULL;
+ return true;
+}
+
+
+bool Type_handler_row::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ DBUG_ASSERT(0);
+ value->m_type= DYN_COL_NULL;
+ return true;
+}
+
+
+bool Type_handler_int_result::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= item->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
+ value->value.m_longlong= item->val_int();
+ return check_null(item, value);
+}
+
+
+bool Type_handler_real_result::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= DYN_COL_DOUBLE;
+ value->value.m_double= item->val_real();
+ return check_null(item, value);
+}
+
+
+bool Type_handler_decimal_result::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= DYN_COL_DECIMAL;
+ my_decimal *dec= item->val_decimal(&value->m_decimal);
+ if (dec != &value->m_decimal && !item->null_value)
+ my_decimal2decimal(dec, &value->m_decimal);
+ return check_null(item, value);
+}
+
+
+bool Type_handler_string_result::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= DYN_COL_STRING;
+ String *str= item->val_str(&value->m_string);
+ if (str != &value->m_string && !item->null_value)
+ value->m_string.set(str->ptr(), str->length(), str->charset());
+ return check_null(item, value);
+}
+
+
+bool Type_handler_temporal_with_date::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= DYN_COL_DATETIME;
+ item->get_date(thd, &value->value.m_time,
+ Datetime::Options(thd, TIME_FRAC_NONE));
+ return check_null(item, value);
+}
+
+
+bool Type_handler_time_common::
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
+{
+ value->m_type= DYN_COL_DATETIME;
+ item->get_time(thd, &value->value.m_time);
+ return check_null(item, value);
+}
+
+/***************************************************************************/
+
+bool Type_handler_row::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ DBUG_ASSERT(0);
+ param->set_null();
+ return true;
+}
+
+
+bool Type_handler_real_result::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= attr->unsigned_flag;
+ param->set_double(val->value.m_double);
+ return false;
+}
+
+
+bool Type_handler_int_result::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= attr->unsigned_flag;
+ param->set_int(val->value.m_longlong, attr->max_length);
+ return false;
+}
+
+
+bool Type_handler_decimal_result::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= attr->unsigned_flag;
+ param->set_decimal(&val->m_decimal, attr->unsigned_flag);
+ return false;
+}
+
+
+bool Type_handler_string_result::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= false;
+ param->setup_conversion_string(thd, attr->collation.collation);
+ /*
+ Exact value of max_length is not known unless data is converted to
+ charset of connection, so we have to set it later.
+ */
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ attr->collation.collation,
+ attr->collation.collation);
+}
+
+
+bool Type_handler_temporal_result::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= attr->unsigned_flag;
+ param->set_time(&val->value.m_time, attr->max_length, attr->decimals);
+ return false;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_null::
+ Item_send(Item *item, Protocol *protocol, st_value *buf) const
+{
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_str(Item *item, Protocol *protocol, st_value *buf) const
+{
+ String *res;
+ if ((res= item->val_str(&buf->m_string)))
+ {
+ DBUG_ASSERT(!item->null_value);
+ return protocol->store(res->ptr(), res->length(), res->charset());
+ }
+ DBUG_ASSERT(item->null_value);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_tiny(Item *item, Protocol *protocol, st_value *buf) const
+{
+ longlong nr= item->val_int();
+ if (!item->null_value)
+ return protocol->store_tiny(nr);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_short(Item *item, Protocol *protocol, st_value *buf) const
+{
+ longlong nr= item->val_int();
+ if (!item->null_value)
+ return protocol->store_short(nr);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_long(Item *item, Protocol *protocol, st_value *buf) const
+{
+ longlong nr= item->val_int();
+ if (!item->null_value)
+ return protocol->store_long(nr);
+ return protocol->store_null();
+}
+
+bool Type_handler::
+ Item_send_longlong(Item *item, Protocol *protocol, st_value *buf) const
+{
+ longlong nr= item->val_int();
+ if (!item->null_value)
+ return protocol->store_longlong(nr, item->unsigned_flag);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_float(Item *item, Protocol *protocol, st_value *buf) const
+{
+ float nr= (float) item->val_real();
+ if (!item->null_value)
+ return protocol->store_float(nr, item->decimals);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_double(Item *item, Protocol *protocol, st_value *buf) const
+{
+ double nr= item->val_real();
+ if (!item->null_value)
+ return protocol->store_double(nr, item->decimals);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::Item_send_timestamp(Item *item,
+ Protocol *protocol,
+ st_value *buf) const
+{
+ Timestamp_or_zero_datetime_native_null native(protocol->thd, item);
+ if (native.is_null())
+ return protocol->store_null();
+ native.to_TIME(protocol->thd, &buf->value.m_time);
+ return protocol->store(&buf->value.m_time, item->decimals);
+}
+
+
+bool Type_handler::
+ Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const
+{
+ item->get_date(protocol->thd, &buf->value.m_time,
+ Datetime::Options(protocol->thd));
+ if (!item->null_value)
+ return protocol->store(&buf->value.m_time, item->decimals);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_date(Item *item, Protocol *protocol, st_value *buf) const
+{
+ item->get_date(protocol->thd, &buf->value.m_time,
+ Date::Options(protocol->thd));
+ if (!item->null_value)
+ return protocol->store_date(&buf->value.m_time);
+ return protocol->store_null();
+}
+
+
+bool Type_handler::
+ Item_send_time(Item *item, Protocol *protocol, st_value *buf) const
+{
+ item->get_time(protocol->thd, &buf->value.m_time);
+ if (!item->null_value)
+ return protocol->store_time(&buf->value.m_time, item->decimals);
+ return protocol->store_null();
+}
+
+/***************************************************************************/
+
+Item *Type_handler_int_result::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ longlong result= item->val_int();
+ if (item->null_value)
+ return new (thd->mem_root) Item_null(thd, item->name.str);
+ return new (thd->mem_root) Item_int(thd, item->name.str, result,
+ item->max_length);
+}
+
+
+Item *Type_handler_real_result::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ double result= item->val_real();
+ if (item->null_value)
+ return new (thd->mem_root) Item_null(thd, item->name.str);
+ return new (thd->mem_root) Item_float(thd, item->name.str, result,
+ item->decimals, item->max_length);
+}
+
+
+Item *Type_handler_decimal_result::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ VDec result(item);
+ if (result.is_null())
+ return new (thd->mem_root) Item_null(thd, item->name.str);
+ return new (thd->mem_root) Item_decimal(thd, item->name.str, result.ptr(),
+ item->max_length, item->decimals);
+}
+
+
+Item *Type_handler_string_result::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ StringBuffer<MAX_FIELD_WIDTH> tmp;
+ String *result= item->val_str(&tmp);
+ if (item->null_value)
+ return new (thd->mem_root) Item_null(thd, item->name.str);
+ LEX_CSTRING value;
+ thd->make_lex_string(&value, result->ptr(), result->length());
+ return new (thd->mem_root) Item_string(thd, item->name, value,
+ result->charset());
+}
+
+
+Item *Type_handler_time_common::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ Item_cache_temporal *cache;
+ longlong value= item->val_time_packed(thd);
+ if (item->null_value)
+ return new (thd->mem_root) Item_null(thd, item->name.str);
+ cache= new (thd->mem_root) Item_cache_time(thd);
+ if (cache)
+ cache->store_packed(value, item);
+ return cache;
+}
+
+
+Item *Type_handler_temporal_with_date::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ Item_cache_temporal *cache;
+ longlong value= item->val_datetime_packed(thd);
+ if (item->null_value)
+ return new (thd->mem_root) Item_null(thd, item->name.str);
+ cache= new (thd->mem_root) Item_cache_datetime(thd);
+ if (cache)
+ cache->store_packed(value, item);
+ return cache;
+}
+
+
+Item *Type_handler_row::
+ make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
+{
+ if (item->type() == Item::ROW_ITEM && cmp->type() == Item::ROW_ITEM)
+ {
+ /*
+ Substitute constants only in Item_row's. Don't affect other Items
+ with ROW_RESULT (eg Item_singlerow_subselect).
+
+ For such Items more optimal is to detect if it is constant and replace
+ it with Item_row. This would optimize queries like this:
+ SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
+ */
+ Item_row *item_row= (Item_row*) item;
+ Item_row *comp_item_row= (Item_row*) cmp;
+ uint col;
+ /*
+ If item and comp_item are both Item_row's and have same number of cols
+ then process items in Item_row one by one.
+ We can't ignore NULL values here as this item may be used with <=>, in
+ which case NULL's are significant.
+ */
+ DBUG_ASSERT(item->result_type() == cmp->result_type());
+ DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
+ col= item_row->cols();
+ while (col-- > 0)
+ resolve_const_item(thd, item_row->addr(col),
+ comp_item_row->element_index(col));
+ }
+ return NULL;
+}
+
+/***************************************************************************/
+
+static const char* item_name(Item *a, String *str)
+{
+ if (a->name.str)
+ return a->name.str;
+ str->length(0);
+ a->print(str, QT_ORDINARY);
+ return str->c_ptr_safe();
+}
+
+
+static void wrong_precision_error(uint errcode, Item *a,
+ ulonglong number, uint maximum)
+{
+ StringBuffer<1024> buf(system_charset_info);
+ my_error(errcode, MYF(0), number, item_name(a, &buf), maximum);
+}
+
+
+/**
+ Get precision and scale for a declaration
+
+ return
+ 0 ok
+ 1 error
+*/
+
+bool get_length_and_scale(ulonglong length, ulonglong decimals,
+ uint *out_length, uint *out_decimals,
+ uint max_precision, uint max_scale,
+ Item *a)
+{
+ if (length > (ulonglong) max_precision)
+ {
+ wrong_precision_error(ER_TOO_BIG_PRECISION, a, length, max_precision);
+ return 1;
+ }
+ if (decimals > (ulonglong) max_scale)
+ {
+ wrong_precision_error(ER_TOO_BIG_SCALE, a, decimals, max_scale);
+ return 1;
+ }
+
+ *out_decimals= (uint) decimals;
+ my_decimal_trim(&length, out_decimals);
+ *out_length= (uint) length;
+
+ if (*out_length < *out_decimals)
+ {
+ my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
+ return 1;
+ }
+ return 0;
+}
+
+
+Item *Type_handler_longlong::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ if (this != &type_handler_ulonglong)
+ return new (thd->mem_root) Item_func_signed(thd, item);
+ return new (thd->mem_root) Item_func_unsigned(thd, item);
+
+}
+
+
+Item *Type_handler_date_common::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ return new (thd->mem_root) Item_date_typecast(thd, item);
+}
+
+
+
+Item *Type_handler_time_common::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ if (attr.decimals() > MAX_DATETIME_PRECISION)
+ {
+ wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(),
+ MAX_DATETIME_PRECISION);
+ return 0;
+ }
+ return new (thd->mem_root)
+ Item_time_typecast(thd, item, (uint) attr.decimals());
+}
+
+
+Item *Type_handler_datetime_common::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ if (attr.decimals() > MAX_DATETIME_PRECISION)
+ {
+ wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(),
+ MAX_DATETIME_PRECISION);
+ return 0;
+ }
+ return new (thd->mem_root)
+ Item_datetime_typecast(thd, item, (uint) attr.decimals());
+
+}
+
+
+Item *Type_handler_decimal_result::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ uint len, dec;
+ if (get_length_and_scale(attr.length(), attr.decimals(), &len, &dec,
+ DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE, item))
+ return NULL;
+ return new (thd->mem_root) Item_decimal_typecast(thd, item, len, dec);
+}
+
+
+Item *Type_handler_double::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ uint len, dec;
+ if (!attr.length_specified())
+ return new (thd->mem_root) Item_double_typecast(thd, item,
+ DBL_DIG + 7,
+ NOT_FIXED_DEC);
+
+ if (get_length_and_scale(attr.length(), attr.decimals(), &len, &dec,
+ DECIMAL_MAX_PRECISION, NOT_FIXED_DEC - 1, item))
+ return NULL;
+ return new (thd->mem_root) Item_double_typecast(thd, item, len, dec);
+}
+
+
+Item *Type_handler_float::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ DBUG_ASSERT(!attr.length_specified());
+ return new (thd->mem_root) Item_float_typecast(thd, item);
+}
+
+
+Item *Type_handler_long_blob::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ int len= -1;
+ CHARSET_INFO *real_cs= attr.charset() ?
+ attr.charset() :
+ thd->variables.collation_connection;
+ if (attr.length_specified())
+ {
+ if (attr.length() > MAX_FIELD_BLOBLENGTH)
+ {
+ char buff[1024];
+ String buf(buff, sizeof(buff), system_charset_info);
+ my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), item_name(item, &buf),
+ MAX_FIELD_BLOBLENGTH);
+ return NULL;
+ }
+ len= (int) attr.length();
+ }
+ return new (thd->mem_root) Item_char_typecast(thd, item, len, real_cs);
+}
+
+Item *Type_handler_interval_DDhhmmssff::
+ create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const
+{
+ if (attr.decimals() > MAX_DATETIME_PRECISION)
+ {
+ wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(),
+ MAX_DATETIME_PRECISION);
+ return 0;
+ }
+ return new (thd->mem_root) Item_interval_DDhhmmssff_typecast(thd, item,
+ (uint)
+ attr.decimals());
+}
+
+/***************************************************************************/
+
+void Type_handler_string_result::Item_param_setup_conversion(THD *thd,
+ Item_param *param)
+ const
+{
+ param->setup_conversion_string(thd, thd->variables.character_set_client);
+}
+
+
+void Type_handler_blob_common::Item_param_setup_conversion(THD *thd,
+ Item_param *param)
+ const
+{
+ param->setup_conversion_blob(thd);
+}
+
+
+void Type_handler_tiny::Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const
+{
+ param->set_param_tiny(pos, len);
+}
+
+
+void Type_handler_short::Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const
+{
+ param->set_param_short(pos, len);
+}
+
+
+void Type_handler_long::Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const
+{
+ param->set_param_int32(pos, len);
+}
+
+
+void Type_handler_longlong::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_int64(pos, len);
+}
+
+
+void Type_handler_float::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_float(pos, len);
+}
+
+
+void Type_handler_double::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_double(pos, len);
+}
+
+
+void Type_handler_decimal_result::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_decimal(pos, len);
+}
+
+
+void Type_handler_string_result::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_str(pos, len);
+}
+
+
+void Type_handler_time_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_time(pos, len);
+}
+
+
+void Type_handler_date_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_date(pos, len);
+}
+
+
+void Type_handler_datetime_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_datetime(pos, len);
+}
+
+Field *Type_handler_blob_common::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ uint pack_length= metadata & 0x00ff;
+ if (pack_length < 1 || pack_length > 4)
+ return NULL; // Broken binary log?
+ return new(root)
+ Field_blob(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ table->s, pack_length, target->charset());
+}
+
+
+void Type_handler_timestamp_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_datetime(pos, len);
+}
+
+
+void Type_handler::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+
+
+void Type_handler_typelib::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+
+
+/***************************************************************************/
+
+Field *Type_handler_row::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->length == 0);
+ DBUG_ASSERT(f_maybe_null(attr->pack_flag));
+ return new (mem_root) Field_row(rec.ptr(), name);
+}
+
+
+Field *Type_handler_olddecimal::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+ return new (mem_root)
+ Field_decimal(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ (uint8) attr->decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_newdecimal::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+ return new (mem_root)
+ Field_new_decimal(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ (uint8) attr->decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_float::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+ uint decimals= attr->decimals;
+ if (decimals == FLOATING_POINT_DECIMALS)
+ decimals= NOT_FIXED_DEC;
+ return new (mem_root)
+ Field_float(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag)== 0);
+}
+
+
+Field *Type_handler_double::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
+ uint decimals= attr->decimals;
+ if (decimals == FLOATING_POINT_DECIMALS)
+ decimals= NOT_FIXED_DEC;
+ return new (mem_root)
+ Field_double(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag)== 0);
+}
+
+
+Field *Type_handler_tiny::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_tiny(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_short::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_short(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_int24::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_medium(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_long::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_long(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_longlong::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG))
+ return new (mem_root)
+ Field_vers_trx_id(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+ return new (mem_root)
+ Field_longlong(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_timestamp::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
+ return new_Field_timestamp(mem_root,
+ rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_timestamp2::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
+ return new (mem_root)
+ Field_timestampf(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check,
+ name, share, attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_year::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_year(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name);
+}
+
+
+Field *Type_handler_date::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_date(rec.ptr(),rec.null_ptr(),rec.null_bit(),
+ attr->unireg_check, name);
+}
+
+
+Field *Type_handler_newdate::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_newdate(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name);
+}
+
+
+Field *Type_handler_time::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
+ return new_Field_time(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MIN_TIME_WIDTH));
+}
+
+
+Field *Type_handler_time2::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
+ return new (mem_root)
+ Field_timef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MIN_TIME_WIDTH));
+}
+
+
+Field *Type_handler_datetime::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
+ return new_Field_datetime(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_datetime2::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
+ return new (mem_root)
+ Field_datetimef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_null::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_null(rec.ptr(), (uint32) attr->length, attr->unireg_check,
+ name, attr->charset);
+}
+
+
+Field *Type_handler_bit::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return f_bit_as_char(attr->pack_flag) ?
+ new (mem_root) Field_bit_as_char(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name) :
+ new (mem_root) Field_bit(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ bit.ptr(), bit.offs(), attr->unireg_check, name);
+}
+
+
+
+
+Field *Type_handler_string::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_string(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, attr->charset);
+}
+
+
+Field *Type_handler_varchar::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ if (attr->unireg_check == Field::TMYSQL_COMPRESSED)
+ return new (mem_root)
+ Field_varstring_compressed(rec.ptr(), (uint32) attr->length,
+ HA_VARCHAR_PACKLENGTH((uint32) attr->length),
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share, attr->charset,
+ zlib_compression_method);
+ return new (mem_root)
+ Field_varstring(rec.ptr(), (uint32) attr->length,
+ HA_VARCHAR_PACKLENGTH((uint32) attr->length),
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share, attr->charset);
+}
+
+
+Field *Type_handler_blob_common::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ if (attr->unireg_check == Field::TMYSQL_COMPRESSED)
+ return new (mem_root)
+ Field_blob_compressed(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), attr->charset,
+ zlib_compression_method);
+ return new (mem_root)
+ Field_blob(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), attr->charset);
+}
+
+
+Field *Type_handler_enum::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_enum(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, attr->pack_flag_to_pack_length(),
+ attr->interval, attr->charset);
+}
+
+
+Field *Type_handler_set::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_set(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, attr->pack_flag_to_pack_length(),
+ attr->interval, attr->charset);
+}
+
+
+/***************************************************************************/
+
+void Type_handler::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_basic(buff);
+ def->frm_pack_charset(buff);
+}
+
+
+void Type_handler_real_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_numeric_with_dec(buff);
+}
+
+
+void Type_handler_decimal_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_numeric_with_dec(buff);
+}
+
+
+void Type_handler_int_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_date_common::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_bit::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_TREAT_BIT_AS_CHAR) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_blob_common::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BLOB) == 0);
+ DBUG_ASSERT(def->decimals == 0 ||
+ def->decimals == NOT_FIXED_DEC);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_null::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == NOT_FIXED_DEC);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_string_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ DBUG_ASSERT(def->decimals == 0 || def->decimals == NOT_FIXED_DEC);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_enum::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_INTERVAL) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_set::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BITFIELD) == 0);
+ DBUG_ASSERT(def->decimals == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+void Type_handler_temporal_result::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
+ Type_handler::Column_definition_attributes_frm_pack(def, buff);
+}
+
+
+/***************************************************************************/
+
+bool Type_handler::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ attr->frm_unpack_basic(buffer);
+ return attr->frm_unpack_charset(share, buffer);
+}
+
+
+bool Type_handler_real_result::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ return attr->frm_unpack_numeric_with_dec(share, buffer);
+}
+
+
+bool Type_handler_decimal_result::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ return attr->frm_unpack_numeric_with_dec(share, buffer);
+}
+
+
+bool Type_handler_time_common::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ return attr->frm_unpack_temporal_with_dec(share, MIN_TIME_WIDTH, buffer);
+}
+
+
+bool Type_handler_datetime_common::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
+}
+
+
+bool Type_handler_timestamp_common::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
+}
+
+
+bool Type_handler_null::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ return true;
+}
+
+
+bool Type_handler_real_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const double *va= a->const_ptr_double();
+ const double *vb= b->const_ptr_double();
+ return va[0] == vb[0];
+}
+
+
+bool Type_handler_int_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const longlong *va= a->const_ptr_longlong();
+ const longlong *vb= b->const_ptr_longlong();
+ bool res= va[0] == vb[0] &&
+ (va[0] >= 0 ||
+ (a->get_type_all_attributes_from_const()->unsigned_flag ==
+ b->get_type_all_attributes_from_const()->unsigned_flag));
+ return res;
+}
+
+
+bool Type_handler_string_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const String *sa= a->const_ptr_string();
+ const String *sb= b->const_ptr_string();
+ return binary_cmp ? sa->bin_eq(sb) :
+ a->get_type_all_attributes_from_const()->collation.collation ==
+ b->get_type_all_attributes_from_const()->collation.collation &&
+ sa->eq(sb, a->get_type_all_attributes_from_const()->collation.collation);
+}
+
+
+bool
+Type_handler_decimal_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const my_decimal *da= a->const_ptr_my_decimal();
+ const my_decimal *db= b->const_ptr_my_decimal();
+ return !da->cmp(db) &&
+ (!binary_cmp ||
+ a->get_type_all_attributes_from_const()->decimals ==
+ b->get_type_all_attributes_from_const()->decimals);
+}
+
+
+bool
+Type_handler_temporal_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const MYSQL_TIME *ta= a->const_ptr_mysql_time();
+ const MYSQL_TIME *tb= b->const_ptr_mysql_time();
+ return !my_time_compare(ta, tb) &&
+ (!binary_cmp ||
+ a->get_type_all_attributes_from_const()->decimals ==
+ b->get_type_all_attributes_from_const()->decimals);
+}
+
+/***************************************************************************/
+
+const Type_handler *
+Type_handler_hex_hybrid::cast_to_int_type_handler() const
+{
+ return &type_handler_ulonglong;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Type_handler_int_result::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ longlong value0= a->val_int();
+ longlong value1= b->val_int();
+ return !a->null_value && !b->null_value && value0 == value1 &&
+ (value0 >= 0 || a->unsigned_flag == b->unsigned_flag);
+}
+
+
+bool Type_handler_real_result::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ double value0= a->val_real();
+ double value1= b->val_real();
+ return !a->null_value && !b->null_value && value0 == value1;
+}
+
+
+bool Type_handler_time_common::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ longlong value0= a->val_time_packed(thd);
+ longlong value1= b->val_time_packed(thd);
+ return !a->null_value && !b->null_value && value0 == value1;
+}
+
+
+bool Type_handler_temporal_with_date::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ longlong value0= a->val_datetime_packed(thd);
+ longlong value1= b->val_datetime_packed(thd);
+ return !a->null_value && !b->null_value && value0 == value1;
+}
+
+
+bool Type_handler_timestamp_common::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ Timestamp_or_zero_datetime_native_null na(thd, a, true);
+ Timestamp_or_zero_datetime_native_null nb(thd, b, true);
+ return !na.is_null() && !nb.is_null() && !cmp_native(na, nb);
+}
+
+
+bool Type_handler_string_result::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ String *va, *vb;
+ StringBuffer<128> cmp_value1, cmp_value2;
+ return (va= a->val_str(&cmp_value1)) &&
+ (vb= b->val_str(&cmp_value2)) &&
+ va->eq(vb, attr->compare_collation());
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_string_result::union_element_finalize(Item_type_holder* item) const
+{
+ if (item->collation.derivation == DERIVATION_NONE)
+ {
+ my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), "UNION");
+ return true;
+ }
+ return false;
+}
+
+
+/***************************************************************************/
+
+void Type_handler_var_string::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ // Change old VARCHAR to new VARCHAR
+ c->set_handler(&type_handler_varchar);
+}
+
+
+void Type_handler_time_common::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ if (opt_mysql56_temporal_format)
+ c->set_handler(&type_handler_time2);
+ else
+ c->set_handler(&type_handler_time);
+}
+
+
+void Type_handler_datetime_common::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ if (opt_mysql56_temporal_format)
+ c->set_handler(&type_handler_datetime2);
+ else
+ c->set_handler(&type_handler_datetime);
+}
+
+
+void Type_handler_timestamp_common::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ if (opt_mysql56_temporal_format)
+ c->set_handler(&type_handler_timestamp2);
+ else
+ c->set_handler(&type_handler_timestamp);
+}
+
+
+/***************************************************************************/
+
+
+int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
+ field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd));
+ item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd));
+ if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
+ time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
+ return 1;
+ return my_time_compare(&field_time, item_time_cmp);
+}
+
+
+int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ MYSQL_TIME field_time, item_time;
+ field->get_date(&field_time, Time::Options(thd));
+ item->get_date(thd, &item_time, Time::Options(thd));
+ return my_time_compare(&field_time, &item_time);
+}
+
+
+int Type_handler_string_result::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ StringBuffer<MAX_FIELD_WIDTH> item_tmp;
+ StringBuffer<MAX_FIELD_WIDTH> field_tmp;
+ String *item_result= item->val_str(&item_tmp);
+ /*
+ Some implementations of Item::val_str(String*) actually modify
+ the field Item::null_value, hence we can't check it earlier.
+ */
+ if (item->null_value)
+ return 0;
+ String *field_result= field->val_str(&field_tmp);
+ return sortcmp(field_result, item_result, field->charset());
+}
+
+
+int Type_handler_int_result::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ DBUG_ASSERT(0); // Not used yet
+ return 0;
+}
+
+
+int Type_handler_real_result::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ /*
+ The patch for Bug#13463415 started using this function for comparing
+ BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
+ Prefixing the auto variables with volatile fixes the problem....
+ */
+ volatile double result= item->val_real();
+ if (item->null_value)
+ return 0;
+ volatile double field_result= field->val_real();
+ if (field_result < result)
+ return -1;
+ else if (field_result > result)
+ return 1;
+ return 0;
+}
+
+
+/***************************************************************************/
+
+
+static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status)
+{
+ return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0;
+}
+
+
+static void literal_warn(THD *thd, const Item *item,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ const MYSQL_TIME_STATUS *st,
+ const char *typestr, bool send_error)
+{
+ if (likely(item))
+ {
+ if (st->warnings) // e.g. a note on nanosecond truncation
+ {
+ ErrConvString err(str, length, cs);
+ thd->push_warning_wrong_or_truncated_value(
+ Sql_condition::time_warn_level(st->warnings),
+ false, typestr, err.ptr(),
+ nullptr, nullptr, nullptr);
+ }
+ }
+ else if (send_error)
+ {
+ ErrConvString err(str, length, cs);
+ my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr());
+ }
+}
+
+
+Item_literal *
+Type_handler_date_common::create_literal_item(THD *thd,
+ const char *str,
+ size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+{
+ Temporal::Warn st;
+ Item_literal *item= NULL;
+ Temporal_hybrid tmp(thd, &st, str, length, cs, Temporal_hybrid::Options(thd));
+ if (tmp.is_valid_temporal() &&
+ tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE &&
+ !have_important_literal_warnings(&st))
+ {
+ Date d(&tmp);
+ item= new (thd->mem_root) Item_date_literal(thd, &d);
+ }
+ literal_warn(thd, item, str, length, cs, &st, "DATE", send_error);
+ return item;
+}
+
+
+Item_literal *
+Type_handler_temporal_with_date::create_literal_item(THD *thd,
+ const char *str,
+ size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+{
+ Temporal::Warn st;
+ Item_literal *item= NULL;
+ Temporal_hybrid tmp(thd, &st, str, length, cs, Temporal_hybrid::Options(thd));
+ if (tmp.is_valid_temporal() &&
+ tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME &&
+ !have_important_literal_warnings(&st))
+ {
+ Datetime dt(&tmp);
+ item= new (thd->mem_root) Item_datetime_literal(thd, &dt, st.precision);
+ }
+ literal_warn(thd, item, str, length, cs, &st, "DATETIME", send_error);
+ return item;
+}
+
+
+Item_literal *
+Type_handler_time_common::create_literal_item(THD *thd,
+ const char *str,
+ size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+{
+ MYSQL_TIME_STATUS st;
+ Item_literal *item= NULL;
+ Time::Options opt(TIME_TIME_ONLY, thd, Time::DATETIME_TO_TIME_DISALLOW);
+ Time tmp(thd, &st, str, length, cs, opt);
+ if (tmp.is_valid_time() &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_time_literal(thd, &tmp, st.precision);
+ literal_warn(thd, item, str, length, cs, &st, "TIME", send_error);
+ return item;
+}
+
+
+bool
+Type_handler_time_common::Item_val_native_with_conversion(THD *thd,
+ Item *item,
+ Native *to) const
+{
+ if (item->type_handler()->type_handler_for_native_format() ==
+ &type_handler_time2)
+ return item->val_native(thd, to);
+ return Time(thd, item).to_native(to, item->time_precision(thd));
+}
+
+
+bool
+Type_handler_time_common::Item_val_native_with_conversion_result(THD *thd,
+ Item *item,
+ Native *to)
+ const
+{
+ if (item->type_handler()->type_handler_for_native_format() ==
+ &type_handler_time2)
+ return item->val_native_result(thd, to);
+ MYSQL_TIME ltime;
+ if (item->get_date_result(thd, &ltime, Time::Options(thd)))
+ return true;
+ int warn;
+ return Time(&warn, &ltime, 0).to_native(to, item->time_precision(thd));
+}
+
+
+int Type_handler_time_common::cmp_native(const Native &a,
+ const Native &b) const
+{
+ // Optimize a simple case: equal fractional precision:
+ if (a.length() == b.length())
+ return memcmp(a.ptr(), b.ptr(), a.length());
+ longlong lla= Time(a).to_packed();
+ longlong llb= Time(b).to_packed();
+ if (lla < llb)
+ return -1;
+ if (lla> llb)
+ return 1;
+ return 0;
+}
+
+
+bool Type_handler_timestamp_common::TIME_to_native(THD *thd,
+ const MYSQL_TIME *ltime,
+ Native *to,
+ uint decimals) const
+{
+ uint error_code;
+ Timestamp_or_zero_datetime tm(thd, ltime, &error_code);
+ if (error_code)
+ return true;
+ tm.trunc(decimals);
+ return tm.to_native(to, decimals);
+}
+
+
+bool
+Type_handler_timestamp_common::Item_val_native_with_conversion(THD *thd,
+ Item *item,
+ Native *to) const
+{
+ MYSQL_TIME ltime;
+ if (item->type_handler()->type_handler_for_native_format() ==
+ &type_handler_timestamp2)
+ return item->val_native(thd, to);
+ return
+ item->get_date(thd, &ltime, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) ||
+ TIME_to_native(thd, &ltime, to, item->datetime_precision(thd));
+}
+
+bool Type_handler_null::union_element_finalize(Item_type_holder *item) const
+{
+ item->set_handler(&type_handler_string);
+ return false;
+}
+
+
+bool
+Type_handler_timestamp_common::Item_val_native_with_conversion_result(THD *thd,
+ Item *item,
+ Native *to)
+ const
+{
+ MYSQL_TIME ltime;
+ if (item->type_handler()->type_handler_for_native_format() ==
+ &type_handler_timestamp2)
+ return item->val_native_result(thd, to);
+ return
+ item->get_date_result(thd, &ltime,
+ Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) ||
+ TIME_to_native(thd, &ltime, to, item->datetime_precision(thd));
+}
+
+
+int Type_handler_timestamp_common::cmp_native(const Native &a,
+ const Native &b) const
+{
+ /*
+ Optimize a simple case:
+ Either both timeatamp values have the same fractional precision,
+ or both values are zero datetime '0000-00-00 00:00:00.000000',
+ */
+ if (a.length() == b.length())
+ return memcmp(a.ptr(), b.ptr(), a.length());
+ return Timestamp_or_zero_datetime(a).cmp(Timestamp_or_zero_datetime(b));
+}
+
+
+Timestamp_or_zero_datetime_native_null::
+ Timestamp_or_zero_datetime_native_null(THD *thd, Item *item, bool conv)
+ :Null_flag(false)
+{
+ DBUG_ASSERT(item->type_handler()->type_handler_for_native_format() ==
+ &type_handler_timestamp2 || conv);
+ if (conv ?
+ type_handler_timestamp2.Item_val_native_with_conversion(thd, item, this) :
+ item->val_native(thd, this))
+ Null_flag::operator=(true);
+ // If no conversion, then is_null() should be equal to item->null_value
+ DBUG_ASSERT(is_null() == item->null_value || conv);
+ /*
+ is_null() can be true together with item->null_value==false, which means
+ a non-NULL item was evaluated, but then the conversion to TIMESTAMP failed.
+ But is_null() can never be false if item->null_value==true.
+ */
+ DBUG_ASSERT(is_null() >= item->null_value);
+}
+
+
+bool
+Type_handler::Item_param_val_native(THD *thd,
+ Item_param *item,
+ Native *to) const
+{
+ DBUG_ASSERT(0); // TODO-TYPE: MDEV-14271
+ return item->null_value= true;
+}
+
+
+bool
+Type_handler_timestamp_common::Item_param_val_native(THD *thd,
+ Item_param *item,
+ Native *to) const
+{
+ /*
+ The below code may not run well in corner cases.
+ This will be fixed under terms of MDEV-14271.
+ Item_param should:
+ - either remember @@time_zone at bind time
+ - or store TIMESTAMP in my_time_t format, rather than in MYSQL_TIME format.
+ */
+ MYSQL_TIME ltime;
+ return
+ item->get_date(thd, &ltime, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) ||
+ TIME_to_native(thd, &ltime, to, item->datetime_precision(thd));
+}
+
+
+bool
+Type_handler_time_common::Item_param_val_native(THD *thd,
+ Item_param *item,
+ Native *to) const
+{
+ return Time(thd, item).to_native(to, item->decimals);
+}
+
+
+/***************************************************************************/
+
+bool Type_handler::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ DBUG_EXECUTE_IF("validate_implicit_default_value_error", return true;);
+ return false;
+}
+
+
+bool Type_handler_date_common::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
+}
+
+
+bool Type_handler_datetime_common::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
+}
+
+
+/***************************************************************************/
+
+const Name & Type_handler_row::default_value() const
+{
+ DBUG_ASSERT(0);
+ static Name def(STRING_WITH_LEN(""));
+ return def;
+}
+
+const Name & Type_handler_numeric::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0"));
+ return def;
+}
+
+const Name & Type_handler_string_result::default_value() const
+{
+ static Name def(STRING_WITH_LEN(""));
+ return def;
+}
+
+const Name & Type_handler_time_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("00:00:00"));
+ return def;
+}
+
+const Name & Type_handler_date_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00"));
+ return def;
+}
+
+const Name & Type_handler_datetime_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
+ return def;
+}
+
+const Name & Type_handler_timestamp_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
+ return def;
+}
+
+/***************************************************************************/
+
+bool Type_handler::Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const
+{
+ // Have *some* columns write type info (let's use string fields as an example)
+ DBUG_EXECUTE_IF("frm_data_type_info_emulate",
+ if (cmp_type() == STRING_RESULT)
+ return to->append("x", 1) ||
+ to->append(name().lex_cstring()););
+ if (type_collection() != &type_collection_std)
+ return to->append(name().lex_cstring());
+ return false;
+}
+
+
+/***************************************************************************/
+
+void
+Type_handler::partition_field_type_not_allowed(const LEX_CSTRING &field_name)
+{
+ my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
+ field_name.str);
+}
+
+
+bool
+Type_handler::partition_field_check_result_type(Item *item,
+ Item_result expected_type)
+{
+ if (item->result_type() != expected_type)
+ {
+ my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ return TRUE;
+ }
+ return false;
+}
+
+
+bool
+Type_handler_blob_common::partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const
+{
+ my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
+ return true;
+}
+
+
+bool
+Type_handler_general_purpose_int::partition_field_append_value(
+ String *str,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const
+{
+ DBUG_ASSERT(item_expr->cmp_type() == INT_RESULT);
+ StringBuffer<21> tmp;
+ longlong value= item_expr->val_int();
+ tmp.set(value, system_charset_info);
+ return str->append(tmp);
+}
+
+
+/*
+ Append an Item value to a String using a desired mode.
+
+ @param [OUT] str The string to append the value to.
+ @param item_expr The item to get the value from
+ @param field_cs The character set of the value owner field.
+ @param mode The mode.
+ @retval true on error
+ @retval false on success
+
+ The value is added using system_charset_info (no matter what mode is).
+
+ (1) If mode is equal to PARTITION_VALUE_PRINT_MODE_FRM,
+ the value is appended as a pure ASCII string in the format '_latin1 0xdf',
+ i.e. a character set introducer followed by a hex hybrid.
+
+ Before appending, we value is first converted to field_cs.
+ a) If the conversion succeeds, the value is printed in its field_cs
+ represenation.
+ b) If the conversion fails, the value is printed without conversion,
+ using the original character set introducer followed by the original
+ string hex representation.
+ In this case, open_table_from_share() will later notice that
+ the value cannot be actually stored to the field, and report
+ the error. So here we don't need to report errors such as
+ ER_PARTITION_FUNCTION_IS_NOT_ALLOWED.
+
+ (2) If the mode is equal to PARTITION_VALUE_PRINT_SHOW,
+ then the value is needed for:
+ - SHOW CREATE TABLE, or
+ - the PARTITION_DESCRIPTION column in a
+ INFORMATION_SCHEMA.PARTITION query.
+
+ The value generated here will be later sent to the client and
+ therefore will be converted to the client character set in the protocol.
+
+ We try to generate the value as a simple quoted utf8 string without
+ introducers (e.g. 'utf8-string') when possible, to make it:
+ - as human readable as possible
+ - but still safe for mysqldump purposes.
+
+ Simple quoted utf8 string is generated when these two conditions are true
+ at the same time:
+ a) The value can be safely converted to utf8,
+ so we can return it without data loss from this function.
+ b) The value can be safely converted to the client character set,
+ so we can convert it later without data loss to the client character
+ set in the protocol.
+
+ If one of the conditions fail, the value is returned using
+ PARTITION_VALUE_PRINT_MODE_FRM representation. See (1).
+*/
+bool Type_handler::partition_field_append_value(
+ String *str,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const
+{
+ DBUG_ASSERT(cmp_type() != INT_RESULT);
+ StringBuffer<MAX_KEY_LENGTH> buf;
+ String *res;
+
+ if (!(res= item_expr->val_str(&buf)))
+ return str->append(STRING_WITH_LEN("NULL"), system_charset_info);
+
+ if (!res->length())
+ return str->append(STRING_WITH_LEN("''"), system_charset_info);
+
+ if (mode == PARTITION_VALUE_PRINT_MODE_FRM ||
+ !res->can_be_safely_converted_to(current_thd->
+ variables.character_set_client) ||
+ !res->can_be_safely_converted_to(system_charset_info))
+ {
+ StringBuffer<64> buf2;
+ uint cnverr2= 0;
+ buf2.copy(res->ptr(), res->length(), res->charset(), field_cs, &cnverr2);
+ if (!cnverr2)
+ return str->append_introducer_and_hex(&buf2);
+ return str->append_introducer_and_hex(res);
+ }
+
+ StringBuffer<64> val(system_charset_info);
+ uint cnverr= 0;
+ val.copy(res->ptr(), res->length(), res->charset(),
+ system_charset_info, &cnverr);
+ append_unescaped(str, val.ptr(), val.length());
+ return false;
+}
+
+
+bool Type_handler::can_return_extract_source(interval_type int_type) const
+{
+ return type_collection() == &type_collection_std;
+}
+
+/***************************************************************************/
+
+LEX_CSTRING Charset::collation_specific_name() const
+{
+ /*
+ User defined collations can provide arbitrary names
+ for character sets and collations, so a collation
+ name not necessarily starts with the character set name.
+ */
+ LEX_CSTRING retval;
+ size_t csname_length= strlen(m_charset->csname);
+ if (strncmp(m_charset->name, m_charset->csname, csname_length))
+ {
+ retval.str= NULL;
+ retval.length= 0;
+ return retval;
+ }
+ const char *ptr= m_charset->name + csname_length;
+ retval.str= ptr;
+ retval.length= strlen(ptr);
+ return retval;
+}
+
+
+bool
+Charset::encoding_allows_reinterpret_as(const CHARSET_INFO *cs) const
+{
+ if (!strcmp(m_charset->csname, cs->csname))
+ return true;
+
+ if (!strcmp(m_charset->csname, MY_UTF8MB3) &&
+ !strcmp(cs->csname, MY_UTF8MB4))
+ return true;
+
+ /*
+ Originally we allowed here instat ALTER for ASCII-to-LATIN1
+ and UCS2-to-UTF16, but this was wrong:
+ - MariaDB's ascii is not a subset for 8-bit character sets
+ like latin1, because it allows storing bytes 0x80..0xFF as
+ "unassigned" characters (see MDEV-19285).
+ - MariaDB's ucs2 (as in Unicode-1.1) is not a subset for UTF16,
+ because they treat surrogate codes differently (MDEV-19284).
+ */
+ return false;
+}
+
+
+bool
+Charset::eq_collation_specific_names(CHARSET_INFO *cs) const
+{
+ LEX_CSTRING name0= collation_specific_name();
+ LEX_CSTRING name1= Charset(cs).collation_specific_name();
+ return name0.length && !cmp(&name0, &name1);
+}
+
+int initialize_data_type_plugin(st_plugin_int *plugin)
+{
+ st_mariadb_data_type *data= (st_mariadb_data_type*) plugin->plugin->info;
+ data->type_handler->set_name(Name(plugin->name));
+ if (plugin->plugin->init && plugin->plugin->init(NULL))
+ {
+ sql_print_error("Plugin '%s' init function returned error.",
+ plugin->name.str);
+ return 1;
+ }
+ return 0;
+}