diff options
Diffstat (limited to 'sql/sql_type.cc')
-rw-r--r-- | sql/sql_type.cc | 9437 |
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 ⪙ + } + 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, <ime, 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, <ime, 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, <ime, Time::Options(thd))) + return true; + int warn; + return Time(&warn, <ime, 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, <ime, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) || + TIME_to_native(thd, <ime, 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, <ime, + Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) || + TIME_to_native(thd, <ime, 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, <ime, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) || + TIME_to_native(thd, <ime, 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; +} |