mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			9829 lines
		
	
	
		
			307 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			9829 lines
		
	
	
		
			307 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
   Copyright (c) 2015, 2022, 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_type_vector.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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
DTCollation::merge_charset_and_collation(Sql_used *used,
 | 
						|
                                         const Charset_collation_map_st &map,
 | 
						|
                                         CHARSET_INFO *cs,
 | 
						|
                                         const Lex_extended_collation_st &cl,
 | 
						|
                                         my_repertoire_t repertoire)
 | 
						|
{
 | 
						|
  Lex_exact_charset_opt_extended_collate cscl(cs, true);
 | 
						|
  if (cscl.merge_collation_override(used, map, cl))
 | 
						|
    return true;
 | 
						|
  set(cscl.collation().charset_info(), DERIVATION_EXPLICIT, repertoire);
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool DTCollation::merge_collation(Sql_used *used,
 | 
						|
                                  const Charset_collation_map_st &map,
 | 
						|
                                  const Lex_extended_collation_st &cl,
 | 
						|
                                  my_repertoire_t repertoire,
 | 
						|
                                  bool allow_ignorable_with_context_collation)
 | 
						|
{
 | 
						|
  if (derivation != DERIVATION_IGNORABLE)
 | 
						|
  {
 | 
						|
    // A known character set + an extended collation
 | 
						|
    return merge_charset_and_collation(used, map, collation, cl, repertoire);
 | 
						|
  }
 | 
						|
 | 
						|
  if (cl.type() == Lex_extended_collation::TYPE_EXACT)
 | 
						|
  {
 | 
						|
    /*
 | 
						|
      An unknown character set + an exact collation.
 | 
						|
      Just use this exact collation.
 | 
						|
      Examples:
 | 
						|
      - Expressions derived from an explicit NULL:
 | 
						|
          SELECT NULL         COLLATE utf8mb4_general_ci;
 | 
						|
          SELECT CONCAT(NULL) COLLATE utf8mb4_general_ci;
 | 
						|
        Any collation is applicable to an explicit NULL.
 | 
						|
 | 
						|
      - Expressions with PS parameters (at PREPARE time, not bound yet)
 | 
						|
          SELECT ?         COLLATE utf8mb4_general_ci;
 | 
						|
          SELECT CONCAT(?) COLLATE utf8mb4_general_ci;
 | 
						|
        The collation will be checked for applicability to the
 | 
						|
        character set of the actual bound parameter at the EXECUTE time.
 | 
						|
        We're now in PREPARE: let's assume it will be applicable.
 | 
						|
    */
 | 
						|
    set(cl.charset_info(), DERIVATION_EXPLICIT, repertoire);
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // An unknown character set + a contextually typed collation
 | 
						|
  if (allow_ignorable_with_context_collation)
 | 
						|
  {
 | 
						|
    /*
 | 
						|
      Expressions with non-bound PS parameters, PREPARE time.
 | 
						|
        SELECT ?         COLLATE uca1400_ai_ci;
 | 
						|
        SELECT CONCAT(?) COLLATE uca1400_ai_ci;
 | 
						|
      There is a chance the character set of the actual bound parameter
 | 
						|
      will be known at the EXECUTE time (unless an explicit NULL is bound).
 | 
						|
 | 
						|
      For now let's use utf8mb4 to resolve collations like uca1400_ai_ci.
 | 
						|
      The real character set of the actual bound parameter expression will be
 | 
						|
      later used to resolve the collation again, during the EXECUTE time.
 | 
						|
    */
 | 
						|
    return merge_charset_and_collation(used, map,
 | 
						|
                                       &my_charset_utf8mb4_general_ci,
 | 
						|
                                       cl, repertoire);
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
    Expressions with an unknown character set:
 | 
						|
    - Either without PS parameters at all:
 | 
						|
        SELECT NULL         COLLATE uca1400_ai_ci;
 | 
						|
        SELECT CONCAT(NULL) COLLATE uca1400_ai_ci;
 | 
						|
    - Or with PS parameters bound to NULL at EXECUTE time:
 | 
						|
        EXECUTE IMMEDIATE
 | 
						|
          'SELECT ? COLLATE uca1400_ai_ci' USING NULL;
 | 
						|
        EXECUTE IMMEDIATE
 | 
						|
          'SELECT CONCAT(?) COLLATE uca1400_ai_ci' USING NULL;
 | 
						|
        EXECUTE IMMEDIATE
 | 
						|
          'SELECT ? COLLATE uca1400_ai_ci' USING CONCAT(NULL);
 | 
						|
  */
 | 
						|
  my_error(ER_NOT_ALLOWED_IN_THIS_CONTEXT, MYF(0), "NULL");
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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_long_ge0> type_handler_slong_ge0("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("tinyint 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 *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 *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()
 | 
						|
{
 | 
						|
  return type_collection_geometry.init(this);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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;
 | 
						|
  }
 | 
						|
 | 
						|
  const Type_handler *ha= Type_collection_geometry_handler_by_name(name);
 | 
						|
  if (!ha && type_handler_vector.name().eq(name))
 | 
						|
    return &type_handler_vector;
 | 
						|
  return ha;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#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
 | 
						|
{
 | 
						|
  return val_buffer->set_real(m_value, dec, &my_charset_numeric);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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))
 | 
						|
  {
 | 
						|
    to->length(0); // Safety: set to '0000-00-00 00:00:00' on falures
 | 
						|
    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, (my_time_t) 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), 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());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
decimal_digits_t 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->can_eval_in_optimize())
 | 
						|
    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 my_timeval &tv)
 | 
						|
{
 | 
						|
  thd->variables.time_zone->gmt_sec_to_TIME(this, (my_time_t) tv.tv_sec);
 | 
						|
  second_part= tv.tv_usec;
 | 
						|
  thd->used|= THD::TIME_ZONE_USED;
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/********************************************************************/
 | 
						|
 | 
						|
decimal_digits_t Type_numeric_attributes::find_max_decimals(Item **item, uint nitems)
 | 
						|
{
 | 
						|
  decimal_digits_t 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]->character_octet_length());
 | 
						|
  return octet_length;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
decimal_digits_t Type_numeric_attributes::
 | 
						|
find_max_decimal_int_part(Item **item, uint nitems)
 | 
						|
{
 | 
						|
  decimal_digits_t 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)
 | 
						|
{
 | 
						|
  decimal_digits_t max_int_part= find_max_decimal_int_part(item, nitems);
 | 
						|
  decimals= find_max_decimals(item, nitems);
 | 
						|
  decimal_digits_t precision= (decimal_digits_t)
 | 
						|
    MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
 | 
						|
  max_length= my_decimal_precision_to_length_no_truncation(precision,
 | 
						|
                                                           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 LEX_CSTRING &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 LEX_CSTRING &funcname) const
 | 
						|
{
 | 
						|
  my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
 | 
						|
           name().ptr(), funcname.str);
 | 
						|
  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_cstring());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
CHARSET_INFO *
 | 
						|
Type_handler_string_result::charset_for_protocol(const Item *item) const
 | 
						|
{
 | 
						|
  return item->collation.collation;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  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_varchar;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
  Type_handler_pair tp(m_type_handler, other);
 | 
						|
  do
 | 
						|
  {
 | 
						|
    const Type_handler *hres;
 | 
						|
    const Type_collection *c;
 | 
						|
    if (((c= Type_handler::type_collection_for_aggregation(tp.a(), tp.b())) &&
 | 
						|
         (hres= c->aggregate_for_result(tp.a(), tp.b()))) ||
 | 
						|
        (hres= type_handler_data->
 | 
						|
                m_type_aggregator_for_result.find_handler(tp.a(), tp.b())))
 | 
						|
    {
 | 
						|
      m_type_handler= hres;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } while (tp.to_base());
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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
 | 
						|
             - (BIT + explicit NULL) or (explicit NULL + BIT) give BIT
 | 
						|
 | 
						|
  @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 LEX_CSTRING &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());
 | 
						|
    uint bit_count= (type_handler() == &type_handler_bit) +
 | 
						|
                    (cur == &type_handler_bit);
 | 
						|
    uint null_count= (type_handler() == &type_handler_null) +
 | 
						|
                     (cur == &type_handler_null);
 | 
						|
    if (treat_bit_as_number && bit_count == 1 && null_count == 0)
 | 
						|
    {
 | 
						|
      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.str);
 | 
						|
      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 && b == STRING_RESULT) ||
 | 
						|
      (b == INT_RESULT && a == STRING_RESULT))
 | 
						|
    return &type_handler_newdecimal;
 | 
						|
  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)
 | 
						|
{
 | 
						|
  Type_handler_pair tp(m_type_handler, h);
 | 
						|
  do
 | 
						|
  {
 | 
						|
    const Type_handler *hres;
 | 
						|
    const Type_collection *c;
 | 
						|
    if (((c= Type_handler::type_collection_for_aggregation(tp.a(), tp.b())) &&
 | 
						|
         (hres= c->aggregate_for_min_max(tp.a(), tp.b()))) ||
 | 
						|
        (hres= type_handler_data->
 | 
						|
                m_type_aggregator_for_result.find_handler(tp.a(), tp.b())))
 | 
						|
    {
 | 
						|
      /*
 | 
						|
        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.
 | 
						|
      */
 | 
						|
      m_type_handler= hres;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } while (tp.to_base());
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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 LEX_CSTRING &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.str);
 | 
						|
      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)
 | 
						|
{
 | 
						|
  Type_handler_pair tp(h0, h1);
 | 
						|
  do
 | 
						|
  {
 | 
						|
    const Type_handler *hres;
 | 
						|
    const Type_collection *c;
 | 
						|
    if (((c= Type_handler::type_collection_for_aggregation(tp.a(), tp.b())) &&
 | 
						|
         (hres= c->aggregate_for_num_op(tp.a(), tp.b()))) ||
 | 
						|
        (hres= agg->find_handler(tp.a(), tp.b())))
 | 
						|
    {
 | 
						|
      m_type_handler= hres;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } while (tp.to_base());
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
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:    return &type_handler_geometry;
 | 
						|
  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:    return &type_handler_geometry;
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
const Type_handler *
 | 
						|
Type_handler::handler_by_log_event_data_type(THD *thd,
 | 
						|
                                             const Log_event_data_type &type)
 | 
						|
{
 | 
						|
  if (type.data_type_name().length)
 | 
						|
  {
 | 
						|
    const Type_handler *th= handler_by_name(thd, type.data_type_name());
 | 
						|
    if (th)
 | 
						|
      return th;
 | 
						|
  }
 | 
						|
  switch (type.type()) {
 | 
						|
  case STRING_RESULT:
 | 
						|
  case ROW_RESULT:
 | 
						|
  case TIME_RESULT:
 | 
						|
    break;
 | 
						|
  case REAL_RESULT:
 | 
						|
    return &type_handler_double;
 | 
						|
  case INT_RESULT:
 | 
						|
    if (type.is_unsigned())
 | 
						|
      return &type_handler_ulonglong;
 | 
						|
    return &type_handler_slonglong;
 | 
						|
  case DECIMAL_RESULT:
 | 
						|
    return &type_handler_newdecimal;
 | 
						|
  }
 | 
						|
  return &type_handler_long_blob;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
{
 | 
						|
  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_for_i_s);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*************************************************************************/
 | 
						|
 | 
						|
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,
 | 
						|
                                               column_definition_type_t type)
 | 
						|
                                               const
 | 
						|
{
 | 
						|
  def->set_charset_collation_attrs(thd,
 | 
						|
                                   thd->variables.character_set_collations,
 | 
						|
                                   attr.charset_collation_attrs());
 | 
						|
  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,
 | 
						|
                                                 column_definition_type_t type)
 | 
						|
                                                 const
 | 
						|
{
 | 
						|
  Type_handler::Column_definition_set_attributes(thd, def, attr, type);
 | 
						|
  if (attr.has_explicit_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,
 | 
						|
                                                 column_definition_type_t type)
 | 
						|
                                                 const
 | 
						|
{
 | 
						|
  Type_handler::Column_definition_set_attributes(thd, def, attr, type);
 | 
						|
  if (attr.has_explicit_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));
 | 
						|
  const Field_enum *field_enum= static_cast<const Field_enum*>(field);
 | 
						|
  field_enum->Type_typelib_attributes::store(def);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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);
 | 
						|
    warn_deprecated<1007>(thd, 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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        const Column_derived_attributes
 | 
						|
                                              *derived_attr)
 | 
						|
                                        const
 | 
						|
{
 | 
						|
  def->prepare_charset_for_string(thd,
 | 
						|
                                  thd->variables.character_set_collations,
 | 
						|
                                  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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        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,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        const Column_derived_attributes
 | 
						|
                                              *derived_attr)
 | 
						|
                                        const
 | 
						|
{
 | 
						|
  def->charset= &my_charset_numeric;
 | 
						|
  return def->prepare_stage1_bit(thd, mem_root);
 | 
						|
}
 | 
						|
 | 
						|
bool Type_handler_typelib::
 | 
						|
       Column_definition_prepare_stage1(THD *thd,
 | 
						|
                                        MEM_ROOT *mem_root,
 | 
						|
                                        Column_definition *def,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        const Column_derived_attributes
 | 
						|
                                              *derived_attr)
 | 
						|
                                        const
 | 
						|
{
 | 
						|
  return def->prepare_charset_for_string(thd,
 | 
						|
                                         thd->variables.
 | 
						|
                                           character_set_collations,
 | 
						|
                                         derived_attr) ||
 | 
						|
         def->prepare_stage1_typelib(thd, mem_root, type);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Type_handler_string_result::
 | 
						|
       Column_definition_prepare_stage1(THD *thd,
 | 
						|
                                        MEM_ROOT *mem_root,
 | 
						|
                                        Column_definition *def,
 | 
						|
                                        column_definition_type_t type,
 | 
						|
                                        const Column_derived_attributes
 | 
						|
                                              *derived_attr)
 | 
						|
                                        const
 | 
						|
{
 | 
						|
  return def->prepare_charset_for_string(thd,
 | 
						|
                                         thd->variables.
 | 
						|
                                           character_set_collations,
 | 
						|
                                         derived_attr) ||
 | 
						|
         def->prepare_stage1_string(thd, mem_root);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*************************************************************************/
 | 
						|
 | 
						|
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 (!(def->flags & CONTEXT_COLLATION_FLAG) && 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->typelib()->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
 | 
						|
{
 | 
						|
  if (!(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::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.typelib());
 | 
						|
  return get_enum_pack_length(def.typelib()->count);
 | 
						|
}
 | 
						|
 | 
						|
uint Type_handler_set::calc_key_length(const Column_definition &def) const
 | 
						|
{
 | 
						|
  DBUG_ASSERT(def.typelib());
 | 
						|
  return get_set_pack_length(def.typelib()->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 Type_typelib_attributes typelib_attr(attr.type_extra_attributes());
 | 
						|
  DBUG_ASSERT(typelib_attr.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_attr.typelib()->count),
 | 
						|
                    typelib_attr.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 Type_typelib_attributes typelib_attr(attr.type_extra_attributes());
 | 
						|
  DBUG_ASSERT(typelib_attr.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_attr.typelib()->count),
 | 
						|
                   typelib_attr.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();
 | 
						|
  uint32 len= def.char_length();
 | 
						|
  uint dec= NOT_FIXED_DEC;
 | 
						|
  if (len >= 100)
 | 
						|
  {
 | 
						|
    dec= def.decimal_scale();
 | 
						|
    uint prec= def.decimal_precision();
 | 
						|
    /* Field defined in sql_show.cc with decimals */
 | 
						|
    len= my_decimal_precision_to_length(prec, dec, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  return new (root)
 | 
						|
    Field_float(addr.ptr(), len,
 | 
						|
                addr.null_ptr(), addr.null_bit(),
 | 
						|
                Field::NONE, &name,
 | 
						|
                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_for_i_s);
 | 
						|
    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_for_i_s);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int Type_handler_bool::Item_save_in_field(Item *item, Field *field,
 | 
						|
                                          bool no_conversions) const
 | 
						|
{
 | 
						|
  return item->save_bool_in_field(field, no_conversions);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
 | 
						|
bool Type_handler_row::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_row(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool Type_handler_int_result::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_int(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool Type_handler_real_result::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_real(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool Type_handler_decimal_result::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_decimal(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool Type_handler_string_result::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_string(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool Type_handler_time_common::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_time(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
Type_handler_temporal_with_date::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_datetime(thd);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
Type_handler_timestamp_common::
 | 
						|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
 | 
						|
{
 | 
						|
  return cmp->set_cmp_func_native(thd);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*************************************************************************/
 | 
						|
 | 
						|
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_bool::Item_get_cache(THD *thd, const Item *item) const
 | 
						|
{
 | 
						|
  return new (thd->mem_root) Item_cache_bool(thd);
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
  This method handles YEAR and BIT data types.
 | 
						|
  It does not switch the data type to DECIAMAL on a
 | 
						|
  unsigned_flag mistmatch. This important for combinations
 | 
						|
  like YEAR+NULL, BIT+NULL.
 | 
						|
*/
 | 
						|
bool Type_handler_int_result::
 | 
						|
       Item_hybrid_func_fix_attributes(THD *thd,
 | 
						|
                                       const LEX_CSTRING &name,
 | 
						|
                                       Type_handler_hybrid_field_type *handler,
 | 
						|
                                       Type_all_attributes *func,
 | 
						|
                                       Item **items, uint nitems) const
 | 
						|
{
 | 
						|
  func->aggregate_attributes_int(items, nitems);
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  This method handles general purpose integer data types
 | 
						|
    TINYINT, SHORTINT, MEDIUNINT, BIGINT.
 | 
						|
  It switches to DECIMAL in case if a mismatch in unsigned_flag found.
 | 
						|
 | 
						|
  Note, we should fix this to ignore all items with
 | 
						|
  type_handler()==&type_handler_null.
 | 
						|
  It's too late for 10.4. Let's do it eventually in a higher version.
 | 
						|
*/
 | 
						|
bool Type_handler_general_purpose_int::
 | 
						|
       Item_hybrid_func_fix_attributes(THD *thd,
 | 
						|
                                       const LEX_CSTRING &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++)
 | 
						|
  {
 | 
						|
    /*
 | 
						|
       TODO: avoid creating DECIMAL for a mix of ulong and slong_ge0.
 | 
						|
       It's too late for 10.5. Let's do it in a higher version.
 | 
						|
    */
 | 
						|
    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);
 | 
						|
  for (uint i= 0; i < nitems; i++)
 | 
						|
  {
 | 
						|
    if (items[i]->type_handler() == &type_handler_slong_ge0)
 | 
						|
    {
 | 
						|
      /*
 | 
						|
        A slong_ge0 argument found.
 | 
						|
        We need to add an extra character for the sign.
 | 
						|
        TODO: rewrite aggregate_attributes_int() to find
 | 
						|
        the maximum decimal_precision() instead of the maximum max_length.
 | 
						|
        This change is too late for 10.5, so let's do it in a higher version.
 | 
						|
      */
 | 
						|
      uint digits_and_sign= items[i]->decimal_precision() + 1;
 | 
						|
      set_if_bigger(func->max_length, digits_and_sign);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  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 LEX_CSTRING &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 LEX_CSTRING &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 LEX_CSTRING &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 LEX_CSTRING &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 Type_extra_attributes eattr2= items[i]->type_extra_attributes();
 | 
						|
    if (eattr2.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= eattr2.typelib();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBUG_ASSERT(typelib); // There must be at least one typelib
 | 
						|
  Type_extra_attributes *eattr_addr= func->type_extra_attributes_addr();
 | 
						|
  if (eattr_addr)
 | 
						|
    eattr_addr->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 LEX_CSTRING &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 LEX_CSTRING &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 LEX_CSTRING &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 LEX_CSTRING &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 LEX_CSTRING &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_cstring(),
 | 
						|
                                         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)
 | 
						|
    {
 | 
						|
      // Conversion from non-temporal is not safe
 | 
						|
      func->set_maybe_null();
 | 
						|
      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->set_maybe_null();
 | 
						|
    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->set_maybe_null();
 | 
						|
      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_long_ge0::
 | 
						|
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func)  const
 | 
						|
{
 | 
						|
  return func->fix_length_and_dec_sint_ge0();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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
 | 
						|
{
 | 
						|
  /*
 | 
						|
    Some Item descendants have DBUG_ASSERT(!is_cond()) is their
 | 
						|
    val_int() implementations, which means val_int() must not be used
 | 
						|
    to evaluate a condition: val_bool() must be used instead.
 | 
						|
    If we come here, it means item's class does not override val_bool()
 | 
						|
    and we need to evaluate the boolean value from the integer value
 | 
						|
    as a fall-back method. To avoid the assert, let's hide the IS_COND flag.
 | 
						|
    Eventually we'll need to implement val_bool() in all Item descendants and
 | 
						|
    remove the trick with flags. This change would be too ricky for 10.6.
 | 
						|
    Let's do it in a later version.
 | 
						|
  */
 | 
						|
  item_base_t flags= item->base_flags;
 | 
						|
  item->base_flags &= ~item_base_t::IS_COND;
 | 
						|
  bool rc= item->val_int() != 0;
 | 
						|
  item->base_flags= flags;
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
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_bool_from_str();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*************************************************************************/
 | 
						|
 | 
						|
 | 
						|
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::Item_bool_rowready_func2_fix_length_and_dec(THD *thd,
 | 
						|
                                          Item_bool_rowready_func2 *func) const
 | 
						|
{
 | 
						|
  return func->fix_length_and_dec_generic(thd, this);
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
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(void *cs_, const void *x_, const void *y_)
 | 
						|
{
 | 
						|
  CHARSET_INFO *cs= static_cast<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, 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 is_unsigned() ? func->val_uint_native() : 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(NULL_clex_str);
 | 
						|
  }
 | 
						|
  str->append(')');
 | 
						|
  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()->cs_name);
 | 
						|
  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(STRING_WITH_LEN(" COLLATE '"));
 | 
						|
  buf.append(item->collation.collation->coll_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_long_ge0::
 | 
						|
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
 | 
						|
{
 | 
						|
  item->fix_arg_slong_ge0();
 | 
						|
  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_long_ge0::
 | 
						|
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
 | 
						|
{
 | 
						|
  item->fix_length_and_dec_sint_ge0();
 | 
						|
  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_long_ge0::
 | 
						|
       Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
 | 
						|
{
 | 
						|
  item->fix_length_and_dec_sint_ge0();
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool Type_handler_long_ge0::
 | 
						|
       Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
 | 
						|
{
 | 
						|
  item->fix_length_and_dec_sint_ge0();
 | 
						|
  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->set_maybe_null();
 | 
						|
  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->set_maybe_null();
 | 
						|
  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->set_maybe_null();
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
decimal_digits_t Type_handler::Item_time_precision(THD *thd, Item *item) const
 | 
						|
{
 | 
						|
  return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
decimal_digits_t Type_handler::Item_datetime_precision(THD *thd, Item *item) const
 | 
						|
{
 | 
						|
  return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
decimal_digits_t 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->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 (decimal_digits_t) MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
 | 
						|
  return (decimal_digits_t) MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
decimal_digits_t Type_handler::Item_decimal_scale(const Item *item) const
 | 
						|
{
 | 
						|
  return (item->decimals < NOT_FIXED_DEC ?
 | 
						|
          item->decimals :
 | 
						|
          (decimal_digits_t) MY_MIN(item->max_length, DECIMAL_MAX_SCALE));
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t 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);
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler::Item_divisor_precision_increment(const Item *item) const
 | 
						|
{
 | 
						|
  return item->decimals;
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t 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;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
decimal_digits_t 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 ? (decimal_digits_t) MY_MIN(res, DECIMAL_MAX_PRECISION) : (decimal_digits_t) 1;
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler_real_result::Item_decimal_precision(const Item *item) const
 | 
						|
{
 | 
						|
  uint res= item->max_char_length();
 | 
						|
  return res ? (decimal_digits_t) MY_MIN(res, DECIMAL_MAX_PRECISION) : (decimal_digits_t) 1;
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t 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 (decimal_digits_t) MY_MIN(prec, DECIMAL_MAX_PRECISION);
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t 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 (decimal_digits_t) MY_MIN(prec, DECIMAL_MAX_PRECISION);
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler_long_ge0::Item_decimal_precision(const Item *item) const
 | 
						|
{
 | 
						|
  DBUG_ASSERT(item->max_length);
 | 
						|
  DBUG_ASSERT(!item->decimals);
 | 
						|
  /*
 | 
						|
    Unlinke in Type_handler_long, Type_handler_long_ge does
 | 
						|
    not reserve one character for the sign. All max_length
 | 
						|
    characters are digits.
 | 
						|
  */
 | 
						|
  return MY_MIN(item->max_length, DECIMAL_MAX_PRECISION);
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler_time_common::Item_decimal_precision(const Item *item) const
 | 
						|
{
 | 
						|
  return (decimal_digits_t) (7 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS));
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler_date_common::Item_decimal_precision(const Item *item) const
 | 
						|
{
 | 
						|
  return 8;
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler_datetime_common::
 | 
						|
Item_decimal_precision(const Item *item) const
 | 
						|
{
 | 
						|
  return (decimal_digits_t) (14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS));
 | 
						|
}
 | 
						|
 | 
						|
decimal_digits_t Type_handler_timestamp_common::
 | 
						|
Item_decimal_precision(const Item *item) const
 | 
						|
{
 | 
						|
  return (decimal_digits_t) (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_datetime(&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_datetime(&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;
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
  Check if in a predicate like:
 | 
						|
 | 
						|
     WHERE timestamp_arg=datetime_arg
 | 
						|
 | 
						|
  we can replace DATETIME comparison to TIMESTAMP comparison,
 | 
						|
  to avoid slow TIMESTAMP->DATETIME data type conversion per row.
 | 
						|
 | 
						|
  TIMESTAMP and DATETIME are compared as DATETIME historically.
 | 
						|
  This may be inefficient, because involves a conversion of
 | 
						|
  the TIMESTAMP side to DATETIME per row.
 | 
						|
  The conversion happens in Timezone::gmt_sec_to_TIME().
 | 
						|
  E.g. in case of the SYSTEM timezone, it calls localtime_r(),
 | 
						|
  which is known to be slow.
 | 
						|
 | 
						|
  It's generally not possible to compare TIMESTAMP and DATETIME
 | 
						|
  as TIMESTAMP without behavior change, because:
 | 
						|
  - DATETIME has a wider range.
 | 
						|
  - Two different TIMESTAMP values can have the same DATETIME value
 | 
						|
    near the "fall back" DST change, as well as for leap seconds.
 | 
						|
  - There are DATETIME gaps during the "spring forward" DST switch.
 | 
						|
 | 
						|
  However, if the DATETIME side is a constant, then we can compare
 | 
						|
  it to TIMESTAMP as TIMESTAMP in many cases. The DATETIME argument can
 | 
						|
  be converted once to TIMESTAMP, so no data type conversion will
 | 
						|
  happen per row. This is faster for big tables.
 | 
						|
 | 
						|
  The comparison predicates must satisfy the following conditions:
 | 
						|
    1. There must be a proper data type combination:
 | 
						|
       - other must be of the TIMESTAMP data type
 | 
						|
       - subject must be of the DATETIME data type,
 | 
						|
         or can convert to DATETIME.
 | 
						|
    2. subject must be a constant
 | 
						|
    3. subject must convert to TIMESTAMP safely
 | 
						|
       (without time zone anomalies near its value)
 | 
						|
*/
 | 
						|
 | 
						|
Item *
 | 
						|
Type_handler_datetime_common::convert_item_for_comparison(
 | 
						|
                                                        THD *thd,
 | 
						|
                                                        Item *subject,
 | 
						|
                                                        const Item *counterpart)
 | 
						|
                                                        const
 | 
						|
{
 | 
						|
  if (!dynamic_cast<const Type_handler_timestamp_common*>(
 | 
						|
                                                 counterpart->type_handler()) ||
 | 
						|
      !subject->type_handler()->can_return_date())
 | 
						|
    return subject;
 | 
						|
 | 
						|
  struct Count_handler : public Internal_error_handler
 | 
						|
  {
 | 
						|
    uint hit= 0;
 | 
						|
    bool handle_condition(THD *thd,
 | 
						|
                          uint sql_errno,
 | 
						|
                          const char *sqlstate,
 | 
						|
                          Sql_condition::enum_warning_level *level,
 | 
						|
                          const char *msg,
 | 
						|
                          Sql_condition **cond_hdl) override
 | 
						|
    {
 | 
						|
      if (sql_errno == ER_TRUNCATED_WRONG_VALUE ||
 | 
						|
          sql_errno == ER_DATETIME_FUNCTION_OVERFLOW)
 | 
						|
      {
 | 
						|
        hit++;
 | 
						|
        return *level >= Sql_condition::WARN_LEVEL_WARN;
 | 
						|
      }
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  } cnt_handler;
 | 
						|
 | 
						|
  // Suppress and count warnings
 | 
						|
  thd->push_internal_handler(&cnt_handler);
 | 
						|
  Datetime dt(thd, subject, Timestamp::DatetimeOptions(thd));
 | 
						|
  thd->pop_internal_handler();
 | 
						|
 | 
						|
  if (!dt.is_valid_datetime() || cnt_handler.hit)
 | 
						|
  {
 | 
						|
    /*
 | 
						|
      SQL NULL DATETIME, or a DATETIME with zeros in YYYYMMDD,
 | 
						|
      or warnings during DATETIME evaluation.
 | 
						|
    */
 | 
						|
    return subject;
 | 
						|
  }
 | 
						|
 | 
						|
  // '0000-00-00 00:00:00' is a special valid MariaDB TIMESTAMP value
 | 
						|
  if (!non_zero_date(dt.get_mysql_time()))
 | 
						|
    return new (thd->mem_root) Item_timestamp_literal(thd,
 | 
						|
                                          Timestamp_or_zero_datetime::zero(),
 | 
						|
                                          subject->datetime_precision(thd));
 | 
						|
 | 
						|
  const Timeval_null tv(thd->safe_timeval_replacement_for_nonzero_datetime(dt));
 | 
						|
  if (tv.is_null())
 | 
						|
    return subject; // Time zone anomalies found around "dt"
 | 
						|
 | 
						|
  // Should be safe to convert
 | 
						|
  const Timestamp_or_zero_datetime ts(Timestamp(tv.to_timeval()));
 | 
						|
  return new (thd->mem_root) Item_timestamp_literal(thd,
 | 
						|
                                          ts,
 | 
						|
                                          subject->datetime_precision(thd));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
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, uint maximum)
 | 
						|
{
 | 
						|
  StringBuffer<1024> buf(system_charset_info);
 | 
						|
  my_error(errcode, MYF(0), 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, decimal_digits_t *out_decimals,
 | 
						|
                          uint max_precision, uint max_scale,
 | 
						|
                          Item *a)
 | 
						|
{
 | 
						|
  if (length > (ulonglong) max_precision)
 | 
						|
  {
 | 
						|
    wrong_precision_error(ER_TOO_BIG_PRECISION, a, max_precision);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  if (decimals > (ulonglong) max_scale)
 | 
						|
  {
 | 
						|
    wrong_precision_error(ER_TOO_BIG_SCALE, a, max_scale);
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  *out_decimals=  (decimal_digits_t)  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, 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, 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;
 | 
						|
  decimal_digits_t 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;
 | 
						|
  decimal_digits_t 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, MAX_DATETIME_PRECISION);
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  return new (thd->mem_root) Item_interval_DDhhmmssff_typecast(thd, item,
 | 
						|
                                                               (uint)
 | 
						|
                                                               attr.decimals());
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
Item_literal *Type_handler::create_boolean_false_item(THD *thd) const
 | 
						|
{
 | 
						|
  return new (thd->mem_root) Item_int(thd, 0);
 | 
						|
}
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
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_long_ge0::
 | 
						|
  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
 | 
						|
{
 | 
						|
  /*
 | 
						|
    We're converting signed long_ge0 to signed long.
 | 
						|
    So add one character for the sign.
 | 
						|
  */
 | 
						|
  return new (mem_root)
 | 
						|
    Field_long(rec.ptr(), (uint32) attr->length + 1/*sign*/,
 | 
						|
               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_ROW_START|VERS_ROW_END))
 | 
						|
    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->typelib(), 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->typelib(), 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);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  @brief
 | 
						|
    Check if two costant timestamp values are identical.
 | 
						|
 | 
						|
  @return
 | 
						|
    true <=> *a and *b are identical
 | 
						|
*/
 | 
						|
bool
 | 
						|
Type_handler_timestamp_common::Item_const_eq(const Item_const *a,
 | 
						|
                                             const Item_const *b,
 | 
						|
                                             bool binary_cmp) const
 | 
						|
{
 | 
						|
  /*
 | 
						|
    In a condition like:
 | 
						|
      WHERE IF(a='2001-01-01 00:00:00',1,0)=IF(a='2001-01-01 00:00:00',1,0);
 | 
						|
    Item_func_eq::fix_length_and_dec() calls get_timestamp_item_for_comparison()
 | 
						|
    which replaces string literals '2001-01-01 00:00:00' with
 | 
						|
    Item_timestamp_literal instances, which later during remove_eq_conds()
 | 
						|
    come to here.
 | 
						|
 | 
						|
    Note, Item_param bound to TIMESTAMP is not detected here,
 | 
						|
    so trivial conditions of this kind do not get eliminated:
 | 
						|
      DECLARE ts TIMESTAMP DEFAULT (SELECT MAX(ts_col) FROM t1);
 | 
						|
      EXECUTE IMMEDIATE
 | 
						|
        'SELECT * FROM t1 WHERE COALESCE(ts_col,?)<=>COALESCE(ts_col,?)'
 | 
						|
         USING ts, ts;
 | 
						|
    It should be fixed by MDEV-14271.
 | 
						|
  */
 | 
						|
  const Item_timestamp_literal *ta, *tb;
 | 
						|
  if (!(ta= dynamic_cast<const Item_timestamp_literal*>(a)) ||
 | 
						|
      !(tb= dynamic_cast<const Item_timestamp_literal*>(b)))
 | 
						|
    return false;
 | 
						|
  return !ta->value().cmp(tb->value());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/***************************************************************************/
 | 
						|
 | 
						|
 | 
						|
const Type_handler *
 | 
						|
Type_handler_var_string::type_handler_for_implicit_upgrade() const
 | 
						|
{
 | 
						|
  return &type_handler_varchar;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Type_handler::
 | 
						|
  Column_definition_implicit_upgrade_to_this(Column_definition *old) const
 | 
						|
{
 | 
						|
  old->set_handler(this);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Type_handler_time_common::
 | 
						|
  Column_definition_implicit_upgrade_to_this(Column_definition *old) const
 | 
						|
{
 | 
						|
  if (opt_mysql56_temporal_format)
 | 
						|
    old->set_handler(&type_handler_time2);
 | 
						|
  else
 | 
						|
    old->set_handler(&type_handler_time);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Type_handler_datetime_common::
 | 
						|
  Column_definition_implicit_upgrade_to_this(Column_definition *old) const
 | 
						|
{
 | 
						|
  if (opt_mysql56_temporal_format)
 | 
						|
    old->set_handler(&type_handler_datetime2);
 | 
						|
  else
 | 
						|
    old->set_handler(&type_handler_datetime);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Type_handler_timestamp_common::
 | 
						|
  Column_definition_implicit_upgrade_to_this(Column_definition *old) const
 | 
						|
{
 | 
						|
  if (opt_mysql56_temporal_format)
 | 
						|
    old->set_handler(&type_handler_timestamp2);
 | 
						|
  else
 | 
						|
    old->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
 | 
						|
{
 | 
						|
  if (item->type_handler()->type_handler_for_native_format() ==
 | 
						|
      &type_handler_timestamp2)
 | 
						|
    return item->val_native(thd, to);
 | 
						|
  Datetime dt(thd, item, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd));
 | 
						|
  return
 | 
						|
    !dt.is_valid_datetime() ||
 | 
						|
    dt.check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE) ||
 | 
						|
    TIME_to_native(thd, dt.get_mysql_time(), 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_char('x') ||
 | 
						|
                           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<LONGLONG_BUFFER_SIZE> 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(NULL_clex_str, 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.
 | 
						|
  */
 | 
						|
  size_t cs_name_length= m_charset->cs_name.length;
 | 
						|
  if (strncmp(m_charset->coll_name.str, m_charset->cs_name.str,
 | 
						|
              cs_name_length))
 | 
						|
    return {NULL, 0};
 | 
						|
  const char *ptr= m_charset->coll_name.str + cs_name_length;
 | 
						|
  return {ptr, m_charset->coll_name.length - cs_name_length };
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
Charset::encoding_allows_reinterpret_as(const CHARSET_INFO *cs) const
 | 
						|
{
 | 
						|
  if (my_charset_same(m_charset, cs))
 | 
						|
    return true;
 | 
						|
 | 
						|
  if (!strcmp(m_charset->cs_name.str, MY_UTF8MB3) &&
 | 
						|
      !strcmp(cs->cs_name.str, MY_UTF8MB4))
 | 
						|
    return true;
 | 
						|
 | 
						|
  /*
 | 
						|
    Originally we allowed here instant 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(void *plugin_)
 | 
						|
{
 | 
						|
  st_plugin_int *plugin= static_cast<st_plugin_int *>(plugin_);
 | 
						|
  st_mariadb_data_type *data=
 | 
						|
      static_cast<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;
 | 
						|
}
 |