  virtual void update_null_value ()
  {
    switch (cmp_type()) {
    case INT_RESULT:
      (void) val_int();
      break;
    case REAL_RESULT:
      (void) val_real();
      break;
    case DECIMAL_RESULT:
      {
        my_decimal tmp;
        (void) val_decimal(&tmp);
      }
      break;
    case TIME_RESULT:
      {
        MYSQL_TIME ltime;
        (void) get_temporal_with_sql_mode(&ltime);
      }
      break;
    case STRING_RESULT:
      {
        StringBuffer<MAX_FIELD_WIDTH> tmp;
        (void) val_str(&tmp);
      }
      break;
    case ROW_RESULT:
      DBUG_ASSERT(0);
      null_value= true;
    }
  }


  String *val_str_from_item(Item *item, String *str)
  {
    DBUG_ASSERT(fixed == 1);
    String *res= item->val_str(str);
    if (res)
      res->set_charset(collation.collation);
    if ((null_value= item->null_value))
      res= NULL;
    return res;
  }


  bool load_data_set_null(THD *thd, const Load_data_param *param)
  {
    return field->load_data_set_null(thd);
  }


  bool store(struct st_value *value, ulonglong fuzzydate)
  {
    switch (cmp_type()) {
    case INT_RESULT:
    {
      value->m_type= unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
      value->value.m_longlong= val_int();
      break;
    }
    case REAL_RESULT:
    {
      value->m_type= DYN_COL_DOUBLE;
      value->value.m_double= val_real();
      break;
    }
    case DECIMAL_RESULT:
    {
      value->m_type= DYN_COL_DECIMAL;
      my_decimal *dec= val_decimal(&value->m_decimal);
      if (dec != &value->m_decimal && !null_value)
        my_decimal2decimal(dec, &value->m_decimal);
      break;
    }
    case STRING_RESULT:
    {
      value->m_type= DYN_COL_STRING;
      String *str= val_str(&value->m_string);
      if (str != &value->m_string && !null_value)
        value->m_string.set(str->ptr(), str->length(), str->charset());
      break;
    }
    case TIME_RESULT:
    {
      value->m_type= DYN_COL_DATETIME;
      get_date(&value->value.m_time, fuzzydate);
      break;
    }
    case ROW_RESULT:
      DBUG_ASSERT(false);
      null_value= true;
      break;
    }
    if (null_value)
    {
      value->m_type= DYN_COL_NULL;
      return true;
    }
    return false;
  }


virtual void restore_to_before_no_rows_in_result() {}


  bool vcol_assignment_allowed_value() const
  {
    switch (state) {
    case NULL_VALUE:
    case DEFAULT_VALUE:
    case IGNORE_VALUE:
      return true;
    case NO_VALUE:
    case INT_VALUE:
    case REAL_VALUE:
    case STRING_VALUE:
    case TIME_VALUE:
    case LONG_DATA_VALUE:
    case DECIMAL_VALUE:
      break;
    }
    return false;
  }


  String *val_str(String* tmp)
  {
    if (check_null_ref())
      return NULL;
    else
      return Item_direct_ref::val_str(tmp);
  }


  Item_hex_constant(THD *thd, const char *str, uint str_length):
    Item_basic_constant(thd)
  {
    hex_string_init(thd, str, str_length);
  }


  longlong val_int()
  {
    // following assert is redundant, because fixed=1 assigned in constructor
    DBUG_ASSERT(fixed == 1);
    return longlong_from_hex_hybrid(str_value.ptr(), str_value.length());
  }


  int save_in_field(Field *field, bool no_conversions)
  {
    field->set_notnull();
    return field->store_hex_hybrid(str_value.ptr(), str_value.length());
  }


int ha_maria::write_row(const uchar * buf)
{
  /*
     If we have an auto_increment column and we are writing a changed row
     or a new row, then update the auto_increment value in the record.
  */
  if (table->next_number_field && buf == table->record[0])
  {
    int error;
    if ((error= update_auto_increment()))
      return error;
  }
  return maria_write(file, buf);
}


int ha_maria::create(const char *name, TABLE *table_arg,
                     HA_CREATE_INFO *ha_create_info)
{
  int error;
  uint create_flags= 0, record_count= 0, i;
  char buff[FN_REFLEN];
  MARIA_KEYDEF *keydef;
  MARIA_COLUMNDEF *recinfo;
  MARIA_CREATE_INFO create_info;
  TABLE_SHARE *share= table_arg->s;
  uint options= share->db_options_in_use;
  ha_table_option_struct *table_options= table_arg->s->option_struct;
  enum data_file_type row_type;
  THD *thd= current_thd;
  DBUG_ENTER("ha_maria::create");

  for (i= 0; i < share->keys; i++)
  {
    if (table_arg->key_info[i].flags & HA_USES_PARSER)
    {
      create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
      break;
    }
  }
  /* Note: BLOCK_RECORD is used if table is transactional */
  row_type= maria_row_type(ha_create_info);
  if (ha_create_info->transactional == HA_CHOICE_YES &&
      ha_create_info->row_type != ROW_TYPE_PAGE &&
      ha_create_info->row_type != ROW_TYPE_NOT_USED &&
      ha_create_info->row_type != ROW_TYPE_DEFAULT)
    push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
                 ER_ILLEGAL_HA_CREATE_OPTION,
                 "Row format set to PAGE because of TRANSACTIONAL=1 option");

  if (share->table_type == TABLE_TYPE_SEQUENCE)
  {
    /* For sequences, the simples record type is appropriate */
    row_type= STATIC_RECORD;
    ha_create_info->transactional= HA_CHOICE_NO;
  }

  bzero((char*) &create_info, sizeof(create_info));
  if ((error= table2maria(table_arg, row_type, &keydef, &recinfo,
                          &record_count, &create_info)))
    DBUG_RETURN(error); /* purecov: inspected */
  create_info.max_rows= share->max_rows;
  create_info.reloc_rows= share->min_rows;
  create_info.with_auto_increment= share->next_number_key_offset == 0;
  create_info.auto_increment= (ha_create_info->auto_increment_value ?
                               ha_create_info->auto_increment_value -1 :
                               (ulonglong) 0);
  create_info.data_file_length= ((ulonglong) share->max_rows *
                                 share->avg_row_length);
  create_info.data_file_name= ha_create_info->data_file_name;
  create_info.index_file_name= ha_create_info->index_file_name;
  create_info.language= share->table_charset->number;
  if (ht != maria_hton)
  {
    /* S3 engine */
    create_info.s3_block_size= (ulong) table_options->s3_block_size;
    create_info.compression_algorithm= table_options->compression_algorithm;
  }

  /*
    Table is transactional:
    - If the user specify that table is transactional (in this case
      row type is forced to BLOCK_RECORD)
    - If they specify BLOCK_RECORD without specifying transactional behaviour

    Shouldn't this test be pushed down to maria_create()? Because currently,
    ma_test1 -T crashes: it creates a table with DYNAMIC_RECORD but has
    born_transactional==1, which confuses some recovery-related code.
  */
  create_info.transactional= (row_type == BLOCK_RECORD &&
                              ha_create_info->transactional != HA_CHOICE_NO);

  if (ha_create_info->tmp_table())
  {
    create_flags|= HA_CREATE_TMP_TABLE | HA_CREATE_DELAY_KEY_WRITE;
    create_info.transactional= 0;
  }
  if (ha_create_info->options & HA_CREATE_KEEP_FILES)
    create_flags|= HA_CREATE_KEEP_FILES;
  if (options & HA_OPTION_PACK_RECORD)
    create_flags|= HA_PACK_RECORD;
  if (options & HA_OPTION_CHECKSUM)
    create_flags|= HA_CREATE_CHECKSUM;
  if (options & HA_OPTION_DELAY_KEY_WRITE)
    create_flags|= HA_CREATE_DELAY_KEY_WRITE;
  if ((ha_create_info->page_checksum == HA_CHOICE_UNDEF &&
       maria_page_checksums) ||
       ha_create_info->page_checksum ==  HA_CHOICE_YES)
    create_flags|= HA_CREATE_PAGE_CHECKSUM;

  (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
                                 (uchar*) thd->query(), thd->query_length());

  create_info.encrypted= maria_encrypt_tables && ht == maria_hton;
  /* TODO: Check that the following fn_format is really needed */
  error=
    maria_create(fn_format(buff, name, "", "",
                           MY_UNPACK_FILENAME | MY_APPEND_EXT),
                 row_type, share->keys, keydef,
                 record_count,  recinfo,
                 0, (MARIA_UNIQUEDEF *) 0,
                 &create_info, create_flags);

  my_free(recinfo);
  DBUG_RETURN(error);
}


my_bool ha_maria::register_query_cache_table(THD *thd, const char *table_name,
					     uint table_name_len,
					     qc_engine_callback
					     *engine_callback,
					     ulonglong *engine_data)
{
  ulonglong actual_data_file_length;
  ulonglong current_data_file_length;
  DBUG_ENTER("ha_maria::register_query_cache_table");

  /*
    No call back function is needed to determine if a cached statement
    is valid or not.
  */
  *engine_callback= 0;

  /*
    No engine data is needed.
  */
  *engine_data= 0;

  if (file->s->now_transactional && file->s->have_versioning)
    DBUG_RETURN(file->trn->trid >= file->s->state.last_change_trn);

  /*
    If a concurrent INSERT has happened just before the currently processed
    SELECT statement, the total size of the table is unknown.

    To determine if the table size is known, the current thread's snap shot of
    the table size with the actual table size are compared.

    If the table size is unknown the SELECT statement can't be cached.
  */

  /*
    POSIX visibility rules specify that "2. Whatever memory values a
    thread can see when it unlocks a mutex <...> can also be seen by any
    thread that later locks the same mutex". In this particular case,
    concurrent insert thread had modified the data_file_length in
    MYISAM_SHARE before it has unlocked (or even locked)
    structure_guard_mutex. So, here we're guaranteed to see at least that
    value after we've locked the same mutex. We can see a later value
    (modified by some other thread) though, but it's ok, as we only want
    to know if the variable was changed, the actual new value doesn't matter
  */
  actual_data_file_length= file->s->state.state.data_file_length;
  current_data_file_length= file->state->data_file_length;

  /* Return whether is ok to try to cache current statement. */
  DBUG_RETURN(!(file->s->non_transactional_concurrent_insert &&
                current_data_file_length != actual_data_file_length));
}


int ha_maria::external_lock(THD *thd, int lock_type)
{
  int result= 0, result2;
  DBUG_ENTER("ha_maria::external_lock");
  file->external_ref= (void*) table;            // For ma_killed()
  /*
    We don't test now_transactional because it may vary between lock/unlock
    and thus confuse our reference counting.
    It is critical to skip non-transactional tables: user-visible temporary
    tables get an external_lock() when read/written for the first time, but no
    corresponding unlock (they just stay locked and are later dropped while
    locked); if a tmp table was transactional, "SELECT FROM non_tmp, tmp"
    would never commit as its "locked_tables" count would stay 1.
    When Maria has has_transactions()==TRUE, open_temporary_table()
    (sql_base.cc) will use TRANSACTIONAL_TMP_TABLE and thus the
    external_lock(F_UNLCK) will happen and we can then allow the user to
    create transactional temporary tables.
  */
  if (file->s->base.born_transactional)
  {
    /* Transactional table */
    if (lock_type != F_UNLCK)
    {
      if (file->trn)
      {
        /* This can only happen with tables created with clone() */
        DBUG_PRINT("info",("file->trn: %p", file->trn));
        trnman_increment_locked_tables(file->trn);
      }

      if (!thd->transaction->on)
      {
        /*
          No need to log REDOs/UNDOs. If this is an internal temporary table
          which will be renamed to a permanent table (like in ALTER TABLE),
          the rename happens after unlocking so will be durable (and the table
          will get its create_rename_lsn).
          Note: if we wanted to enable users to have an old backup and apply
          tons of archived logs to roll-forward, we could then not disable
          REDOs/UNDOs in this case.
        */
        DBUG_PRINT("info", ("Disabling logging for table"));
        _ma_tmp_disable_logging_for_table(file, TRUE);
        file->autocommit= 0;
      }
      else
        file->autocommit= !(thd->variables.option_bits &
                            (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
#ifndef ARIA_HAS_TRANSACTIONS
      /*
        Until Aria has full transactions support, including MVCC support for
        delete and update and purging of old states, we have to commit for
        every statement.
      */
      file->autocommit=1;
#endif
    }
    else
    {
      /* We have to test for THD_TRN to protect against implicit commits */
      TRN *trn= (file->trn != &dummy_transaction_object && THD_TRN ? file->trn : 0);
      /* End of transaction */

      /*
        We always re-enable, don't rely on thd->transaction.on as it is
        sometimes reset to true after unlocking (see mysql_truncate() for a
        partitioned table based on Maria).
        Note that we can come here without having an exclusive lock on the
        table, for example in this case:
        external_lock(F_(WR|RD)LCK); thr_lock() which fails due to lock
        abortion; external_lock(F_UNLCK). Fortunately, the re-enabling happens
        only if we were the thread which disabled logging.
      */
      if (_ma_reenable_logging_for_table(file, TRUE))
        DBUG_RETURN(1);
      _ma_reset_trn_for_table(file);
      /*
        Ensure that file->state points to the current number of rows. This
        is needed if someone calls maria_info() without first doing an
        external lock of the table
      */
      file->state= &file->s->state.state;
      if (trn)
      {
        DBUG_PRINT("info",
                   ("locked_tables: %u", trnman_has_locked_tables(trn)));
        DBUG_ASSERT(trnman_has_locked_tables(trn) > 0);
        if (trnman_has_locked_tables(trn) &&
            !trnman_decrement_locked_tables(trn))
        {
          /*
            OK should not have been sent to client yet (ACID).
            This is a bit excessive, ACID requires this only if there are some
            changes to commit (rollback shouldn't be tested).
          */
          DBUG_ASSERT(!thd->get_stmt_da()->is_sent() ||
                      thd->killed);
          /*
            If autocommit, commit transaction. This can happen when open and
            lock tables as part of creating triggers, in which case commit
            is not called.
            Until ARIA_HAS_TRANSACTIONS is not defined, always commit.
          */
          if (file->autocommit)
          {
            if (ma_commit(trn))
              result= HA_ERR_COMMIT_ERROR;
            thd_set_ha_data(thd, maria_hton, 0);
          }
        }
        trnman_set_flags(trn, trnman_get_flags(trn) & ~ TRN_STATE_INFO_LOGGED);
      }
    }
  } /* if transactional table */
  if ((result2= maria_lock_database(file, !table->s->tmp_table ?
                                    lock_type : ((lock_type == F_UNLCK) ?
                                                 F_UNLCK : F_EXTRA_LCK))))
    result= result2;
  if (!file->s->base.born_transactional)
    file->state= &file->s->state.state;         // Restore state if clone

  /* Remember stack end for this thread */
  file->stack_end_ptr= &ha_thd()->mysys_var->stack_ends_here;
  DBUG_RETURN(result);
}


void ha_maria::drop_table(const char *name)
{
  DBUG_ASSERT(!file || file->s->temporary);
  (void) ha_close();
  (void) maria_delete_table_files(name, 1, MY_WME);
}


int ha_maria::check_for_upgrade(HA_CHECK_OPT *check)
{
  if (table->s->mysql_version && table->s->mysql_version <= 100509 &&
      (file->s->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED))
  {
    /*
      Encrypted tables before 10.5.9 had a bug where LSN was not
      stored on the pages. These must be repaired!
    */
    return HA_ADMIN_NEEDS_ALTER;
  }
  return HA_ADMIN_OK;
}


const char *ha_maria::index_type(uint key_number)
{
  return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
          "FULLTEXT" :
          (table->key_info[key_number].flags & HA_SPATIAL) ?
          "SPATIAL" :
          (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
          "RTREE" : "BTREE");
}


int ha_maria::extra(enum ha_extra_function operation)
{
  int tmp;
  TRN *old_trn= file->trn;
  if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
    return 0;
#ifdef NOT_USED
  if (operation == HA_EXTRA_MMAP && !opt_maria_use_mmap)
    return 0;
#endif
  if (operation == HA_EXTRA_WRITE_CACHE && has_long_unique())
    return 0;

  /*
    We have to set file->trn here because in some cases we call
    extern_lock(F_UNLOCK) (which resets file->trn) followed by maria_close()
    without calling commit/rollback in between.  If file->trn is not set
    we can't remove file->share from the transaction list in the extra() call.

    In current code we don't have to do this for HA_EXTRA_PREPARE_FOR_RENAME
    as this is only used the intermediate table used by ALTER TABLE which
    is not part of the transaction (it's not in the TRN list). Better to
    keep this for now, to not break anything in a stable release.
    When HA_EXTRA_PREPARE_FOR_RENAME is not handled below, we can change
    the warnings in _ma_remove_table_from_trnman() to asserts.

    table->in_use is not set in the case this is a done as part of closefrm()
    as part of drop table.
  */

  if (file->s->now_transactional && table->in_use &&
      (operation == HA_EXTRA_PREPARE_FOR_DROP ||
       operation == HA_EXTRA_PREPARE_FOR_RENAME ||
       operation == HA_EXTRA_PREPARE_FOR_FORCED_CLOSE))
  {
    THD *thd= table->in_use;
    file->trn= THD_TRN;
  }
  DBUG_ASSERT(file->s->base.born_transactional || file->trn == 0 ||
              file->trn == &dummy_transaction_object);

  tmp= maria_extra(file, operation, 0);
  /*
    Restore trn if it was changed above.
    Note that table could be removed from trn->used_tables and
    trn->used_instances if trn was set and some of the above operations
    was used. This is ok as the table should not be part of any transaction
    after this and thus doesn't need to be part of any of the above lists.
  */
  file->trn= old_trn;
  return tmp;
}


int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
{
  int error;
  HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
  TRN *old_trn;
  MARIA_SHARE *share= file->s;

  if (!file || !param)
    return HA_ADMIN_INTERNAL_ERROR;

  unmap_file(file);
  old_trn= file->trn;
  maria_chk_init(param);
  param->thd= thd;
  param->op_name= "zerofill";
  param->testflag= check_opt->flags | T_SILENT | T_ZEROFILL;
  param->orig_sort_buffer_length= THDVAR(thd, sort_buffer_size);
  param->db_name= table->s->db.str;
  param->table_name= table->alias.c_ptr();

  error=maria_zerofill(param, file, share->open_file_name.str);

  /* Reset trn, that may have been set by repair */
  if (old_trn && old_trn != file->trn)
    _ma_set_trn_for_table(file, old_trn);

  if (!error)
  {
    TrID create_trid= trnman_get_min_safe_trid();
    mysql_mutex_lock(&share->intern_lock);
    share->state.changed|= STATE_NOT_MOVABLE;
    maria_update_state_info(param, file, UPDATE_TIME | UPDATE_OPEN_COUNT);
    _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE, create_trid,
                              TRUE, TRUE);
    mysql_mutex_unlock(&share->intern_lock);
  }
  return error;
}


bool maria_flush_logs(handlerton *hton)
{
  return MY_TEST(translog_purge_at_flush());
}


Item *ha_maria::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
{
  /*
    Check if the key contains a blob field. If it does then MyISAM
    should not accept the pushed index condition since MyISAM will not
    read the blob field from the index entry during evaluation of the
    pushed index condition and the BLOB field might be part of the
    range evaluation done by the ICP code.
  */
  const KEY *key= &table_share->key_info[keyno_arg];

  for (uint k= 0; k < key->user_defined_key_parts; ++k)
  {
    const KEY_PART_INFO *key_part= &key->key_part[k];
    if (key_part->key_part_flag & HA_BLOB_PART)
    {
      /* Let the server handle the index condition */
      return idx_cond_arg;
    }
  }

  pushed_idx_cond_keyno= keyno_arg;
  pushed_idx_cond= idx_cond_arg;
  in_range_check_pushed_down= TRUE;
  if (active_index == pushed_idx_cond_keyno)
    ma_set_index_cond_func(file, handler_index_cond_check, this);
  return NULL;
}


Item *Item_string::clone_item(THD *thd)
{
  return new (thd->mem_root)
    Item_string(thd, name.str, str_value.ptr(),
                str_value.length(), collation.collation);
}


Item_case_expr::this_item() const
{
  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);

  return m_thd->spcont->get_case_expr(m_case_expr_id);
}


my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
{
  DBUG_ASSERT(fixed == 1);
  if (!has_value())
    return NULL;
  return value ? decimal_from_string_with_check(decimal_val, value) : 0;
}


Item_splocal::this_item() const
{
  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
  DBUG_ASSERT(fixed);
  return get_variable(m_thd->spcont);
}


TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
                               const char *key, uint key_length)
{
  MEM_ROOT mem_root;
  TABLE_SHARE *share;
  char *key_buff, *path_buff;
  char path[FN_REFLEN];
  uint path_length;
  DBUG_ENTER("alloc_table_share");
  DBUG_PRINT("enter", ("table: '%s'.'%s'", db, table_name));

  path_length= build_table_filename(path, sizeof(path) - 1,
                                    db, table_name, "", 0);
  init_sql_alloc(&mem_root, "table_share", TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
  if (multi_alloc_root(&mem_root,
                       &share, sizeof(*share),
                       &key_buff, key_length,
                       &path_buff, path_length + 1,
                       NULL))
  {
    bzero((char*) share, sizeof(*share));

    share->set_table_cache_key(key_buff, key, key_length);

    share->path.str= path_buff;
    share->path.length= path_length;
    strmov(path_buff, path);
    share->normalized_path.str=    share->path.str;
    share->normalized_path.length= path_length;
    share->table_category= get_table_category(& share->db, & share->table_name);
    share->open_errno= ENOENT;
    /* The following will be updated in open_table_from_share */
    share->can_do_row_logging= 1;
    if (share->table_category == TABLE_CATEGORY_LOG)
      share->no_replicate= 1;
    if (key_length > 6 &&
        my_strnncoll(table_alias_charset, (const uchar*) key, 6,
                     (const uchar*) "mysql", 6) == 0)
      share->not_usable_by_query_cache= 1;

    init_sql_alloc(&share->stats_cb.mem_root, "share_stats",
                   TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));

    memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
    mysql_mutex_init(key_TABLE_SHARE_LOCK_share,
                     &share->LOCK_share, MY_MUTEX_INIT_SLOW);
    mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
                     &share->LOCK_ha_data, MY_MUTEX_INIT_FAST);

    DBUG_EXECUTE_IF("simulate_big_table_id",
                    if (last_table_id < UINT_MAX32)
                      last_table_id= UINT_MAX32 - 1;);
    /*
      There is one reserved number that cannot be used. Remember to
      change this when 6-byte global table id's are introduced.
    */
    do
    {
      share->table_map_id=(ulong) my_atomic_add64_explicit(&last_table_id, 1,
                                                    MY_MEMORY_ORDER_RELAXED);
    } while (unlikely(share->table_map_id == ~0UL ||
                      share->table_map_id == 0));
  }
  DBUG_RETURN(share);
}


bool TABLE_LIST::init_derived(THD *thd, bool init_view)
{
  SELECT_LEX *first_select= get_single_select();
  SELECT_LEX_UNIT *unit= get_unit();

  if (!unit)
    return FALSE;
  /*
    Check whether we can merge this derived table into main select.
    Depending on the result field translation will or will not
    be created.
  */
  TABLE_LIST *first_table= (TABLE_LIST *) first_select->table_list.first;
  if (first_select->table_list.elements > 1 ||
      (first_table && first_table->is_multitable()))
    set_multitable();

  if (!unit->derived)
    unit->derived= this;
  else if (!is_with_table_recursive_reference() && unit->derived != this)
  {
    if (unit->derived->is_with_table_recursive_reference())
      unit->derived= this;
    else if (vers_conditions.eq(unit->derived->vers_conditions))
      vers_conditions.empty();
    else
    {
      my_error(ER_CONFLICTING_FOR_SYSTEM_TIME, MYF(0));
      return TRUE;
    }
  }

  if (init_view && !view &&
      !derived_table_optimization_done(this))
  {
    /* This is all what we can do for a derived table for now. */
    set_derived();
  }

  if (!is_view() &&
      !derived_table_optimization_done(this))
  {
    /* A subquery might be forced to be materialized due to a side-effect. */
    if (!is_materialized_derived() && first_select->is_mergeable() &&
        optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_MERGE) &&
        !thd->lex->can_not_use_merged() &&
        !(thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
          thd->lex->sql_command == SQLCOM_DELETE_MULTI) &&
        !is_recursive_with_table())
      set_merged_derived();
    else
      set_materialized_derived();
  }
  /*
    Derived tables/view are materialized prior to UPDATE, thus we can skip
    them from table uniqueness check
  */
  if (is_materialized_derived())
  {
    set_check_materialized();
  }

  /*
    Create field translation for mergeable derived tables/views.
    For derived tables field translation can be created only after
    unit is prepared so all '*' are get unrolled.
  */
  if (is_merged_derived())
  {
    if (is_view() ||
        (unit->prepared &&
	!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)))
      create_field_translation(thd);
  }

  return FALSE;
}


Item_splocal_row_field::this_item() const
{
  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
  DBUG_ASSERT(fixed);
  return get_variable(m_thd->spcont)->element_index(m_field_idx);
}


fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
            bool ignore_errors, bool update)
{
  List_iterator_fast<Item> f(fields),v(values);
  Item *value, *fld;
  Item_field *field;
  Field *rfield;
  TABLE *table;
  bool only_unvers_fields= update && table_arg->versioned();
  bool save_abort_on_warning= thd->abort_on_warning;
  bool save_no_errors= thd->no_errors;
  DBUG_ENTER("fill_record");

  thd->no_errors= ignore_errors;
  /*
    Reset the table->auto_increment_field_not_null as it is valid for
    only one row.
  */
  if (fields.elements)
    table_arg->auto_increment_field_not_null= FALSE;

  while ((fld= f++))
  {
    if (!(field= fld->field_for_view_update()))
    {
      my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name.str);
      goto err;
    }
    value=v++;
    DBUG_ASSERT(value);
    rfield= field->field;
    table= rfield->table;
    if (table->next_number_field &&
        rfield->field_index ==  table->next_number_field->field_index)
      table->auto_increment_field_not_null= TRUE;
    const bool skip_sys_field= rfield->vers_sys_field(); // TODO: && !thd->vers_modify_history() [MDEV-16546]
    if ((rfield->vcol_info || skip_sys_field) &&
        !value->vcol_assignment_allowed_value() &&
        table->s->table_category != TABLE_CATEGORY_TEMPORARY)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,
                          ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN),
                          rfield->field_name.str, table->s->table_name.str);
    }
    if (only_unvers_fields && !rfield->vers_update_unversioned())
      only_unvers_fields= false;

    if (rfield->stored_in_db())
    {
      if (!skip_sys_field &&
          unlikely(value->save_in_field(rfield, 0) < 0) && !ignore_errors)
      {
        my_message(ER_UNKNOWN_ERROR, ER_THD(thd, ER_UNKNOWN_ERROR), MYF(0));
        goto err;
      }
      /*
        In sql MODE_SIMULTANEOUS_ASSIGNMENT,
        move field pointer on value stored in record[1]
        which contains row before update (see MDEV-13417)
      */
      if (update && thd->variables.sql_mode & MODE_SIMULTANEOUS_ASSIGNMENT)
        rfield->move_field_offset((my_ptrdiff_t) (table->record[1] -
                                                  table->record[0]));
    }
    rfield->set_has_explicit_value();
  }

  if (update && thd->variables.sql_mode & MODE_SIMULTANEOUS_ASSIGNMENT)
  {
    // restore fields pointers on record[0]
    f.rewind();
    while ((fld= f++))
    {
      rfield= fld->field_for_view_update()->field;
      if (rfield->stored_in_db())
      {
        table= rfield->table;
        rfield->move_field_offset((my_ptrdiff_t) (table->record[0] -
                                                  table->record[1]));
      }
    }
  }

  if (update)
    table_arg->evaluate_update_default_function();
  else
    if (table_arg->default_field &&
        table_arg->update_default_fields(ignore_errors))
      goto err;

  /* Update virtual fields */
  if (table_arg->vfield &&
      table_arg->update_virtual_fields(table_arg->file, VCOL_UPDATE_FOR_WRITE))
    goto err;
  if (table_arg->versioned() && !only_unvers_fields)
    table_arg->vers_update_fields();
  thd->abort_on_warning= save_abort_on_warning;
  thd->no_errors=        save_no_errors;
  DBUG_RETURN(thd->is_error());
err:
  DBUG_PRINT("error",("got error"));
  thd->abort_on_warning= save_abort_on_warning;
  thd->no_errors=        save_no_errors;
  if (fields.elements)
    table_arg->auto_increment_field_not_null= FALSE;
  DBUG_RETURN(TRUE);
}


bool extend_table_list(THD *thd, TABLE_LIST *tables,
                       Prelocking_strategy *prelocking_strategy,
                       bool has_prelocking_list)
{
  bool error= false;
  LEX *lex= thd->lex;
  bool maybe_need_prelocking=
    (tables->updating && tables->lock_type >= TL_WRITE_ALLOW_WRITE)
    || thd->lex->default_used;

  if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
      ! has_prelocking_list && maybe_need_prelocking)
  {
    bool need_prelocking= FALSE;
    TABLE_LIST **save_query_tables_last= lex->query_tables_last;
    /*
      Extend statement's table list and the prelocking set with
      tables and routines according to the current prelocking
      strategy.

      For example, for DML statements we need to add tables and routines
      used by triggers which are going to be invoked for this element of
      table list and also add tables required for handling of foreign keys.
    */
    error= prelocking_strategy->handle_table(thd, lex, tables,
                                             &need_prelocking);

    if (need_prelocking && ! lex->requires_prelocking())
      lex->mark_as_requiring_prelocking(save_query_tables_last);
  }
  return error;
}


int Item::save_int_in_field(Field *field, bool no_conversions)
{
  longlong nr= val_int();
  if (null_value)
    return set_field_to_null_with_conversions(field, no_conversions);
  field->set_notnull();
  return field->store(nr, unsigned_flag);
}


Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg,
                       const char *db_name_arg,const char *table_name_arg,
		       const LEX_CSTRING *field_name_arg)
  :Item_result_field(thd), orig_db_name(db_name_arg),
   orig_table_name(table_name_arg),
   orig_field_name(*field_name_arg), context(context_arg),
   db_name(db_name_arg), table_name(table_name_arg),
   field_name(*field_name_arg),
   alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
   cached_table(0), depended_from(0), can_be_depended(TRUE)
{
  name= *field_name_arg;
}


static TABLE_LIST *internal_table_exists(TABLE_LIST *global_list,
                                         const char *table_name)
{
  do
  {
    if (global_list->table_name.str == table_name)
      return global_list;
  } while ((global_list= global_list->next_global));
  return 0;
}


Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str)
{
  append(str->str, (uint32) str->length);
  if (!(collation.repertoire & MY_REPERTOIRE_EXTENDED))
  {
    // If the string has been pure ASCII so far, check the new part.
    CHARSET_INFO *cs= thd->variables.collation_connection;
    collation.repertoire|= my_string_repertoire(cs, str->str, str->length);
  }
  return this;
}


Open_table_context::
request_backoff_action(enum_open_table_action action_arg,
                       TABLE_LIST *table)
{
  /*
    A back off action may be one of three kinds:

    * We met a broken table that needs repair, or a table that
      is not present on this MySQL server and needs re-discovery.
      To perform the action, we need an exclusive metadata lock on
      the table. Acquiring X lock while holding other shared
      locks can easily lead to deadlocks. We rely on MDL deadlock
      detector to discover them. If this is a multi-statement
      transaction that holds metadata locks for completed statements,
      we should keep these locks after discovery/repair.
      The action type in this case is OT_DISCOVER or OT_REPAIR.
    * Our attempt to acquire an MDL lock lead to a deadlock,
      detected by the MDL deadlock detector. The current
      session was chosen a victim. If this is a multi-statement
      transaction that holds metadata locks taken by completed
      statements, restarting locking for the current statement
      may lead to a livelock. Releasing locks of completed
      statements can not be done as will lead to violation
      of ACID. Thus, again, if m_has_locks is set,
      we report an error. Otherwise, when there are no metadata
      locks other than which belong to this statement, we can
      try to recover from error by releasing all locks and
      restarting the pre-locking.
      Similarly, a deadlock error can occur when the
      pre-locking process met a TABLE_SHARE that is being
      flushed, and unsuccessfully waited for the flush to
      complete. A deadlock in this case can happen, e.g.,
      when our session is holding a metadata lock that
      is being waited on by a session which is using
      the table which is being flushed. The only way
      to recover from this error is, again, to close all
      open tables, release all locks, and retry pre-locking.
      Action type name is OT_REOPEN_TABLES. Re-trying
      while holding some locks may lead to a livelock,
      and thus we don't do it.
    * Finally, this session has open TABLEs from different
      "generations" of the table cache. This can happen, e.g.,
      when, after this session has successfully opened one
      table used for a statement, FLUSH TABLES interfered and
      expelled another table used in it. FLUSH TABLES then
      blocks and waits on the table already opened by this
      statement.
      We detect this situation by ensuring that table cache
      version of all tables used in a statement is the same.
      If it isn't, all tables needs to be reopened.
      Note, that we can always perform a reopen in this case,
      even if we already have metadata locks, since we don't
      keep tables open between statements and a livelock
      is not possible.
  */
  if (action_arg == OT_BACKOFF_AND_RETRY && m_has_locks)
  {
    my_error(ER_LOCK_DEADLOCK, MYF(0));
    m_thd->mark_transaction_to_rollback(true);
    return TRUE;
  }
  /*
    If auto-repair or discovery are requested, a pointer to table
    list element must be provided.
  */
  if (table)
  {
    DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR);
    m_failed_table= (TABLE_LIST*) m_thd->alloc(sizeof(TABLE_LIST));
    if (m_failed_table == NULL)
      return TRUE;
    m_failed_table->init_one_table(&table->db, &table->table_name, &table->alias, TL_WRITE);
    m_failed_table->open_strategy= table->open_strategy;
    m_failed_table->mdl_request.set_type(MDL_EXCLUSIVE);
  }
  m_action= action_arg;
  return FALSE;
}


bool TR_table::query(ulonglong trx_id)
{
  if (!table && open())
    return false;
  SQL_SELECT_auto select;
  READ_RECORD info;
  int error;
  List<TABLE_LIST> dummy;
  SELECT_LEX &slex= thd->lex->select_lex;
  Name_resolution_context_backup backup(slex.context, *this);
  Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]);
  Item *value= newx Item_int(thd, trx_id);
  COND *conds= newx Item_func_eq(thd, field, value);
  if (unlikely((error= setup_conds(thd, this, dummy, &conds))))
    return false;
  select= make_select(table, 0, 0, conds, NULL, 0, &error);
  if (unlikely(error || !select))
  {
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
    return false;
  }
  // FIXME: (performance) force index 'transaction_id'
  error= init_read_record(&info, thd, table, select, NULL,
                          1 /* use_record_cache */, true /* print_error */,
                          false /* disable_rr_cache */);
  while (!(error= info.read_record()) && !thd->killed && !thd->is_error())
  {
    if (select->skip_record(thd) > 0)
      return true;
  }
  my_error(ER_VERS_NO_TRX_ID, MYF(0), (longlong) trx_id);
  return false;
}


void Item::init_make_send_field(Send_field *tmp_field,
                                enum enum_field_types field_type_arg)
{
  tmp_field->db_name=		"";
  tmp_field->org_table_name=	"";
  tmp_field->org_col_name=	empty_clex_str;
  tmp_field->table_name=	"";
  tmp_field->col_name=	        name;
  tmp_field->flags=             (maybe_null ? 0 : NOT_NULL_FLAG) |
                                (my_binary_compare(charset_for_protocol()) ?
                                 BINARY_FLAG : 0);
  tmp_field->type=              field_type_arg;
  tmp_field->length=max_length;
  tmp_field->decimals=decimals;
  if (unsigned_flag)
    tmp_field->flags |= UNSIGNED_FLAG;
}


bool Item_cache_time::cache_value()
{
  if (!example)
    return false;
  value_cached= true;
  value= example->val_time_packed_result();
  null_value_inside= null_value= example->null_value;
  return true;
}


int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
                COND **conds)
{
  SELECT_LEX *select_lex= thd->lex->current_select;
  TABLE_LIST *table= NULL;	// For HP compilers
  /*
    it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX
    which belong to LEX, i.e. most up SELECT) will be updated by
    INSERT/UPDATE/LOAD
    NOTE: using this condition helps to prevent call of prepare_check_option()
    from subquery of VIEW, because tables of subquery belongs to VIEW
    (see condition before prepare_check_option() call)
  */
  bool it_is_update= (select_lex == &thd->lex->select_lex) &&
    thd->lex->which_check_option_applicable();
  bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
  TABLE_LIST *derived= select_lex->master_unit()->derived;
  DBUG_ENTER("setup_conds");

  select_lex->is_item_list_lookup= 0;

  thd->column_usage= MARK_COLUMNS_READ;
  DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage));
  select_lex->cond_count= 0;
  select_lex->between_count= 0;
  select_lex->max_equal_elems= 0;

  for (table= tables; table; table= table->next_local)
  {
    if (select_lex == &thd->lex->select_lex &&
        select_lex->first_cond_optimization &&
        table->merged_for_insert &&
        table->prepare_where(thd, conds, FALSE))
      goto err_no_arena;
  }

  if (*conds)
  {
    thd->where="where clause";
    DBUG_EXECUTE("where",
                 print_where(*conds,
                             "WHERE in setup_conds",
                             QT_ORDINARY););
    /*
      Wrap alone field in WHERE clause in case it will be outer field of subquery
      which need persistent pointer on it, but conds could be changed by optimizer
    */
    if ((*conds)->type() == Item::FIELD_ITEM && !derived)
      wrap_ident(thd, conds);
    (*conds)->mark_as_condition_AND_part(NO_JOIN_NEST);
    if ((*conds)->fix_fields_if_needed_for_bool(thd, conds))
      goto err_no_arena;
  }

  /*
    Apply fix_fields() to all ON clauses at all levels of nesting,
    including the ones inside view definitions.
  */
  if (setup_on_expr(thd, tables, it_is_update))
    goto err_no_arena;

  if (!thd->stmt_arena->is_conventional())
  {
    /*
      We are in prepared statement preparation code => we should store
      WHERE clause changing for next executions.

      We do this ON -> WHERE transformation only once per PS/SP statement.
    */
    select_lex->where= *conds;
  }
  thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
  DBUG_RETURN(MY_TEST(thd->is_error()));

err_no_arena:
  select_lex->is_item_list_lookup= save_is_item_list_lookup;
  DBUG_RETURN(1);
}


void Item_date_literal::print(String *str, enum_query_type query_type)
{
  str->append("DATE'");
  char buf[MAX_DATE_STRING_REP_LENGTH];
  my_date_to_str(&cached_time, buf);
  str->append(buf);
  str->append('\'');
}


bool TABLE_LIST::is_leaf_for_name_resolution()
{
  return (is_merged_derived() || is_natural_join || is_join_columns_complete ||
          !nested_join);
}


Item* Item::set_expr_cache(THD *thd)
{
  DBUG_ENTER("Item::set_expr_cache");
  Item_cache_wrapper *wrapper;
  if (likely((wrapper= new (thd->mem_root) Item_cache_wrapper(thd, this))) &&
      likely(!wrapper->fix_fields(thd, (Item**)&wrapper)))
  {
    if (likely(!wrapper->set_cache(thd)))
      DBUG_RETURN(wrapper);
  }
  DBUG_RETURN(NULL);
}


static void set_indicator_in_key_fields(KEY *key_info)
{
  KEY_PART_INFO *key_part;
  uint key_parts= key_info->user_defined_key_parts, i;
  for (i= 0, key_part=key_info->key_part; i < key_parts; i++, key_part++)
    key_part->field->flags|= GET_FIXED_FIELDS_FLAG;
}


Item_case_expr::this_item()
{
  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);

  return m_thd->spcont->get_case_expr(m_case_expr_id);
}


static void mysql57_calculate_null_position(TABLE_SHARE *share,
                                            uchar **null_pos,
                                            uint *null_bit_pos,
                                            const uchar *strpos,
                                            const uchar *vcol_screen_pos)
{
  uint field_pack_length= 17;

  for (uint i=0 ; i < share->fields; i++, strpos+= field_pack_length)
  {
    uint field_length, pack_flag;
    enum_field_types field_type;

    if ((strpos[10] & MYSQL57_GENERATED_FIELD))
    {
      /* Skip virtual (not stored) generated field */
      bool stored_in_db= vcol_screen_pos[3];
      vcol_screen_pos+= (uint2korr(vcol_screen_pos + 1) +
                         MYSQL57_GCOL_HEADER_SIZE);
      if (! stored_in_db)
        continue;
    }
    field_length= uint2korr(strpos+3);
    pack_flag=    uint2korr(strpos+8);
    field_type=   (enum_field_types) (uint) strpos[13];
    if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
    {
      if (((*null_bit_pos)+= field_length & 7) > 7)
      {
        (*null_pos)++;
        (*null_bit_pos)-= 8;
      }
    }
    if (f_maybe_null(pack_flag))
    {
      if (!((*null_bit_pos)= ((*null_bit_pos) + 1) & 7))
        (*null_pos)++;
    }
  }
}


bool Item_cache_row::setup(THD *thd, Item *item)
{
  example= item;
  null_value= true;

  if (!values && allocate(thd, item->cols()))
    return 1;
  for (uint i= 0; i < item_count; i++)
  {
    Item *el= item->element_index(i);
    Item_cache *tmp;
    if (!(tmp= values[i]= el->get_cache(thd)))
      return 1;
    tmp->setup(thd, el);
  }
  return 0;
}


st_select_lex *TABLE_LIST::get_single_select()
{
  SELECT_LEX_UNIT *unit= get_unit();
  return (unit ? unit->first_select() : 0);
}


bool Item_cache_wrapper::send(Protocol *protocol, st_value *buffer)
{
  if (result_field)
    return protocol->store(result_field);
  return Item::send(protocol, buffer);
}


int TABLE::verify_constraints(bool ignore_failure)
{
  /*
    We have to check is_error() first as we are checking it for each
    constraint to catch fatal warnings.
  */
  if (in_use->is_error())
    return (VIEW_CHECK_ERROR);

  /* go trough check option clauses for fields and table */
  if (check_constraints &&
      !(in_use->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS))
  {
    if (versioned() && !vers_end_field()->is_max())
      return VIEW_CHECK_OK;
    for (Virtual_column_info **chk= check_constraints ; *chk ; chk++)
    {
      /*
        yes! NULL is ok.
        see 4.23.3.4 Table check constraints, part 2, SQL:2016
      */
      if (((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value) ||
          in_use->is_error())
      {
        StringBuffer<MAX_FIELD_WIDTH> field_error(system_charset_info);
        enum_vcol_info_type vcol_type= (*chk)->get_vcol_type();
        DBUG_ASSERT(vcol_type == VCOL_CHECK_TABLE ||
                    vcol_type == VCOL_CHECK_FIELD);
        if (vcol_type == VCOL_CHECK_FIELD)
        {
          field_error.append(s->table_name.str);
          field_error.append(".");
        }
        field_error.append((*chk)->name.str);
        my_error(ER_CONSTRAINT_FAILED,
                 MYF(ignore_failure ? ME_JUST_WARNING : 0), field_error.c_ptr(),
                 s->db.str, s->table_name.str);
        return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR;
      }
    }
  }
  /*
    We have to check in_use() as checking constraints may have generated
    warnings that should be treated as errors
  */
  return(!in_use->is_error() ? VIEW_CHECK_OK : VIEW_CHECK_ERROR);
}


void mark_select_range_as_dependent(THD *thd,
                                    SELECT_LEX *last_select,
                                    SELECT_LEX *current_sel,
                                    Field *found_field, Item *found_item,
                                    Item_ident *resolved_item,
                                    bool suppress_warning_output)
{
  /*
    Go from current SELECT to SELECT where field was resolved (it
    have to be reachable from current SELECT, because it was already
    done once when we resolved this field and cached result of
    resolving)
  */
  SELECT_LEX *previous_select= current_sel;
  for (; previous_select->outer_select() != last_select;
       previous_select= previous_select->outer_select())
  {
    Item_subselect *prev_subselect_item=
      previous_select->master_unit()->item;
    prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
    prev_subselect_item->const_item_cache= 0;
  }
  {
    Item_subselect *prev_subselect_item=
      previous_select->master_unit()->item;
    Item_ident *dependent= resolved_item;
    if (found_field == view_ref_found)
    {
      Item::Type type= found_item->type();
      prev_subselect_item->used_tables_cache|=
        found_item->used_tables();
      dependent= ((type == Item::REF_ITEM || type == Item::FIELD_ITEM) ?
                  (Item_ident*) found_item :
                  0);
    }
    else
      prev_subselect_item->used_tables_cache|=
        found_field->table->map;
    prev_subselect_item->const_item_cache= 0;
    mark_as_dependent(thd, last_select, current_sel, resolved_item,
                      dependent, suppress_warning_output);
  }
}


bool Item_param::set_from_item(THD *thd, Item *item)
{
  DBUG_ENTER("Item_param::set_from_item");
  m_is_settable_routine_parameter= item->get_settable_routine_parameter();
  if (limit_clause_param)
  {
    longlong val= item->val_int();
    if (item->null_value)
    {
      set_null();
      DBUG_RETURN(false);
    }
    else
    {
      unsigned_flag= item->unsigned_flag;
      set_handler(item->type_handler());
      DBUG_RETURN(set_limit_clause_param(val));
    }
  }
  struct st_value tmp;
  if (!item->save_in_value(&tmp))
  {
    const Type_handler *h= item->type_handler();
    set_handler(h);
    DBUG_RETURN(set_value(thd, item, &tmp, h));
  }
  else
    set_null();

  DBUG_RETURN(0);
}


void TABLE_LIST::reset_const_table()
{
  table->const_table= 0;
  if (is_merged_derived())
  {
    SELECT_LEX *select_lex= get_unit()->first_select();
    TABLE_LIST *tl;
    List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
    while ((tl= ti++))
      tl->reset_const_table();
  }
}


bool TR_table::update(ulonglong start_id, ulonglong end_id)
{
  if (!table && open())
    return true;

  store(FLD_BEGIN_TS, thd->transaction_time());
  thd->set_time();
  timeval end_time= {thd->query_start(), int(thd->query_start_sec_part())};
  store(FLD_TRX_ID, start_id);
  store(FLD_COMMIT_ID, end_id);
  store(FLD_COMMIT_TS, end_time);
  store_iso_level(thd->tx_isolation);

  int error= table->file->ha_write_row(table->record[0]);
  if (unlikely(error))
    table->file->print_error(error, MYF(0));
  return error;
}


static bool is_name_in_list(const char *name, List<const char> list_names)
{
  List_iterator<const char> names_it(list_names);
  uint num_names= list_names.elements;
  uint i= 0;

  do
  {
    const char *list_name= names_it++;
    if (!(my_strcasecmp(system_charset_info, name, list_name)))
      return TRUE;
  } while (++i < num_names);
  return FALSE;
}


bool TABLE_LIST::check_single_table(TABLE_LIST **table_arg,
                                       table_map map,
                                       TABLE_LIST *view_arg)
{
  if (!select_lex)
    return FALSE;
  DBUG_ASSERT(is_merged_derived());
  for (TABLE_LIST *tbl= get_single_select()->get_table_list();
       tbl;
       tbl= tbl->next_local)
  {
    /*
      Merged view has also temporary table attached (in 5.2 if it has table
      then it was real table), so we have filter such temporary tables out
      by checking that it is not merged view
    */
    if (tbl->table &&
        !(tbl->is_view() &&
          tbl->is_merged_derived()))
    {
      if (tbl->table->map & map)
      {
	if (*table_arg)
	  return TRUE;
        *table_arg= tbl;
        tbl->check_option= view_arg->check_option;
      }
    }
    else if (tbl->check_single_table(table_arg, map, view_arg))
      return TRUE;
  }
  return FALSE;
}


void Field_iterator_table_ref::set_field_iterator()
{
  DBUG_ENTER("Field_iterator_table_ref::set_field_iterator");
  /*
    If the table reference we are iterating over is a natural join, or it is
    an operand of a natural join, and TABLE_LIST::join_columns contains all
    the columns of the join operand, then we pick the columns from
    TABLE_LIST::join_columns, instead of the  orginial container of the
    columns of the join operator.
  */
  if (table_ref->is_join_columns_complete)
  {
    /* Necesary, but insufficient conditions. */
    DBUG_ASSERT(table_ref->is_natural_join ||
                table_ref->nested_join ||
                (table_ref->join_columns &&
                 /* This is a merge view. */
                 ((table_ref->field_translation &&
                   table_ref->join_columns->elements ==
                   (ulong)(table_ref->field_translation_end -
                           table_ref->field_translation)) ||
                  /* This is stored table or a tmptable view. */
                  (!table_ref->field_translation &&
                   table_ref->join_columns->elements ==
                   table_ref->table->s->fields))));
    field_it= &natural_join_it;
    DBUG_PRINT("info",("field_it for '%s' is Field_iterator_natural_join",
                       table_ref->alias.str));
  }
  /* This is a merge view, so use field_translation. */
  else if (table_ref->field_translation)
  {
    DBUG_ASSERT(table_ref->is_merged_derived());
    field_it= &view_field_it;
    DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_view",
                        table_ref->alias.str));
  }
  /* This is a base table or stored view. */
  else
  {
    DBUG_ASSERT(table_ref->table || table_ref->view);
    field_it= &table_field_it;
    DBUG_PRINT("info", ("field_it for '%s' is Field_iterator_table",
                        table_ref->alias.str));
  }
  field_it->set(table_ref);
  DBUG_VOID_RETURN;
}


void Item_ref::print(String *str, enum_query_type query_type)
{
  if (ref)
  {
    if ((*ref)->type() != Item::CACHE_ITEM &&
        (*ref)->type() != Item::WINDOW_FUNC_ITEM &&
        ref_type() != VIEW_REF &&
        !table_name && name.str && alias_name_used)
    {
      THD *thd= current_thd;
      append_identifier(thd, str, &(*ref)->real_item()->name);
    }
    else
      (*ref)->print(str, query_type);
  }
  else
    Item_ident::print(str, query_type);
}


Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length):
  Item_int(thd, str_arg, i, length)
{
  unsigned_flag= 1;
}


TR_table::~TR_table()
{
  if (table)
  {
    thd->temporary_tables= NULL;
    close_log_table(thd, open_tables_backup);
  }
  delete open_tables_backup;
}


void Item_time_literal::print(String *str, enum_query_type query_type)
{
  str->append("TIME'");
  char buf[MAX_DATE_STRING_REP_LENGTH];
  my_time_to_str(&cached_time, buf, decimals);
  str->append(buf);
  str->append('\'');
}


void get_full_part_id_from_key(const TABLE *table, uchar *buf,
                               KEY *key_info,
                               const key_range *key_spec,
                               part_id_range *part_spec)
{
  bool result;
  partition_info *part_info= table->part_info;
  uchar *rec0= table->record[0];
  longlong func_value;
  DBUG_ENTER("get_full_part_id_from_key");

  key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
  if (likely(rec0 == buf))
  {
    result= part_info->get_partition_id(part_info, &part_spec->start_part,
                                        &func_value);
  }
  else
  {
    Field **part_field_array= part_info->full_part_field_array;
    part_info->table->move_fields(part_field_array, buf, rec0);
    result= part_info->get_partition_id(part_info, &part_spec->start_part,
                                        &func_value);
    part_info->table->move_fields(part_field_array, rec0, buf);
  }
  part_spec->end_part= part_spec->start_part;
  if (unlikely(result))
    part_spec->start_part++;
  DBUG_VOID_RETURN;
}


void prune_partition_set(const TABLE *table, part_id_range *part_spec)
{
  int last_partition= -1;
  uint i;
  partition_info *part_info= table->part_info;

  DBUG_ENTER("prune_partition_set");
  for (i= part_spec->start_part; i <= part_spec->end_part; i++)
  {
    if (bitmap_is_set(&(part_info->read_partitions), i))
    {
      DBUG_PRINT("info", ("Partition %d is set", i));
      if (last_partition == -1)
        /* First partition found in set and pruned bitmap */
        part_spec->start_part= i;
      last_partition= i;
    }
  }
  if (last_partition == -1)
    /* No partition found in pruned bitmap */
    part_spec->start_part= part_spec->end_part + 1;
  else //if (last_partition != -1)
    part_spec->end_part= last_partition;

  DBUG_VOID_RETURN;
}


void Item_param::set_ignore()
{
  m_is_settable_routine_parameter= false;
  state= IGNORE_VALUE;
  fixed= true;
  null_value= true;
}


bool Item_field::add_field_to_set_processor(void *arg)
{
  DBUG_ENTER("Item_field::add_field_to_set_processor");
  DBUG_PRINT("info", ("%s", field->field_name.str ? field->field_name.str :
                      "noname"));
  TABLE *table= (TABLE *) arg;
  if (field->table == table)
    bitmap_set_bit(&table->tmp_set, field->field_index);
  DBUG_RETURN(FALSE);
}


bool Item::find_item_processor(void *arg)
{
  return (this == ((Item *) arg));
}


String *Item::check_well_formed_result(String *str, bool send_error)
{
  /* Check whether we got a well-formed string */
  CHARSET_INFO *cs= str->charset();
  uint wlen= str->well_formed_length();
  null_value= false;
  if (unlikely(wlen < str->length()))
  {
    THD *thd= current_thd;
    char hexbuf[7];
    uint diff= str->length() - wlen;
    set_if_smaller(diff, 3);
    octet2hex(hexbuf, str->ptr() + wlen, diff);
    if (send_error)
    {
      my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
               cs->csname,  hexbuf);
      return 0;
    }
    if (thd->is_strict_mode())
    {
      null_value= 1;
      str= 0;
    }
    else
    {
      str->length(wlen);
    }
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_INVALID_CHARACTER_STRING,
                        ER_THD(thd, ER_INVALID_CHARACTER_STRING), cs->csname,
                        hexbuf);
  }
  return str;
}


void TABLE_LIST::hide_view_error(THD *thd)
{
  if ((thd->killed && !thd->is_error())|| thd->get_internal_handler())
    return;
  /* Hide "Unknown column" or "Unknown function" error */
  DBUG_ASSERT(thd->is_error());
  switch (thd->get_stmt_da()->sql_errno()) {
    case ER_BAD_FIELD_ERROR:
    case ER_SP_DOES_NOT_EXIST:
    case ER_FUNC_INEXISTENT_NAME_COLLISION:
    case ER_PROCACCESS_DENIED_ERROR:
    case ER_COLUMNACCESS_DENIED_ERROR:
    case ER_TABLEACCESS_DENIED_ERROR:
    case ER_TABLE_NOT_LOCKED:
    case ER_NO_SUCH_TABLE:
    {
      TABLE_LIST *top= top_table();
      thd->clear_error();
      my_error(ER_VIEW_INVALID, MYF(0),
               top->view_db.str, top->view_name.str);
      break;
    }

    case ER_NO_DEFAULT_FOR_FIELD:
    {
      TABLE_LIST *top= top_table();
      thd->clear_error();
      // TODO: make correct error message
      my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0),
               top->view_db.str, top->view_name.str);
      break;
    }
  }
}


Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
  if (!example)
    return Item::safe_charset_converter(thd, tocs);
  Item *conv= example->safe_charset_converter(thd, tocs);
  if (conv == example)
    return this;
  Item_cache *cache;
  if (!conv || conv->fix_fields(thd, (Item **) NULL) ||
      unlikely(!(cache= new (thd->mem_root) Item_cache_str(thd, conv))))
    return NULL; // Safe conversion is not possible, or OEM
  cache->setup(thd, conv);
  cache->fixed= false; // Make Item::fix_fields() happy
  return cache;
}


bool Item_field::collect_item_field_processor(void *arg)
{
  DBUG_ENTER("Item_field::collect_item_field_processor");
  DBUG_PRINT("info", ("%s", field->field_name.str ?
                      field->field_name.str : "noname"));
  List<Item_field> *item_list= (List<Item_field>*) arg;
  List_iterator<Item_field> item_list_it(*item_list);
  Item_field *curr_item;
  while ((curr_item= item_list_it++))
  {
    if (curr_item->eq(this, 1))
      DBUG_RETURN(FALSE); /* Already in the set. */
  }
  item_list->push_back(this);
  DBUG_RETURN(FALSE);
}


Item *Item_time_literal::clone_item(THD *thd)
{
  return new (thd->mem_root) Item_time_literal(thd, &cached_time, decimals);
}


void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr,
                                 bool merge)
{
  (*ref)->fix_after_pullout(new_parent, ref, merge);
  if (get_depended_from() == new_parent)
    depended_from= NULL;
}


Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
{
  uint i;
  my_bool error= FALSE;
  const TABLE_FIELD_TYPE *field_def= table_def->field;
  DBUG_ENTER("table_check_intact");
  DBUG_PRINT("info",("table: %s  expected_count: %d",
                     table->alias.c_ptr(), table_def->count));

  /* Whether the table definition has already been validated. */
  if (table->s->table_field_def_cache == table_def)
    goto end;

  if (table->s->fields != table_def->count)
  {
    THD *thd= current_thd;
    DBUG_PRINT("info", ("Column count has changed, checking the definition"));

    /* previous MySQL version */
    if (MYSQL_VERSION_ID > table->s->mysql_version)
    {
      report_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE,
                   ER_THD(thd, ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
                   table->alias.c_ptr(), table_def->count, table->s->fields,
                   static_cast<int>(table->s->mysql_version),
                   MYSQL_VERSION_ID);
      DBUG_RETURN(TRUE);
    }
    else if (MYSQL_VERSION_ID == table->s->mysql_version)
    {
      report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2,
                   ER_THD(thd, ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2),
                   table->s->db.str, table->s->table_name.str,
                   table_def->count, table->s->fields);
      DBUG_RETURN(TRUE);
    }
    /*
      Something has definitely changed, but we're running an older
      version of MySQL with new system tables.
      Let's check column definitions. If a column was added at
      the end of the table, then we don't care much since such change
      is backward compatible.
    */
  }
  else
  {
  StringBuffer<1024> sql_type(system_charset_info);
  sql_type.extra_allocation(256); // Allocate min 256 characters at once
  for (i=0 ; i < table_def->count; i++, field_def++)
  {
    sql_type.length(0);
    if (i < table->s->fields)
    {
      Field *field= table->field[i];

      if (strncmp(field->field_name.str, field_def->name.str,
                  field_def->name.length))
      {
        /*
          Name changes are not fatal, we use ordinal numbers to access columns.
          Still this can be a sign of a tampered table, output an error
          to the error log.
        */
        report_error(0, "Incorrect definition of table %s.%s: "
                     "expected column '%s' at position %d, found '%s'.",
                     table->s->db.str, table->alias.c_ptr(),
                     field_def->name.str, i,
                     field->field_name.str);
      }
      field->sql_type(sql_type);
      /*
        Generally, if column types don't match, then something is
        wrong.

        However, we only compare column definitions up to the
        length of the original definition, since we consider the
        following definitions compatible:

        1. DATETIME and DATETIM
        2. INT(11) and INT(11
        3. SET('one', 'two') and SET('one', 'two', 'more')

        For SETs or ENUMs, if the same prefix is there it's OK to
        add more elements - they will get higher ordinal numbers and
        the new table definition is backward compatible with the
        original one.
       */
      if (strncmp(sql_type.c_ptr_safe(), field_def->type.str,
                  field_def->type.length - 1))
      {
        report_error(0, "Incorrect definition of table %s.%s: "
                     "expected column '%s' at position %d to have type "
                     "%s, found type %s.", table->s->db.str,
                     table->alias.c_ptr(),
                     field_def->name.str, i, field_def->type.str,
                     sql_type.c_ptr_safe());
        error= TRUE;
      }
      else if (field_def->cset.str && !field->has_charset())
      {
        report_error(0, "Incorrect definition of table %s.%s: "
                     "expected the type of column '%s' at position %d "
                     "to have character set '%s' but the type has no "
                     "character set.", table->s->db.str,
                     table->alias.c_ptr(),
                     field_def->name.str, i, field_def->cset.str);
        error= TRUE;
      }
      else if (field_def->cset.str &&
               strcmp(field->charset()->csname, field_def->cset.str))
      {
        report_error(0, "Incorrect definition of table %s.%s: "
                     "expected the type of column '%s' at position %d "
                     "to have character set '%s' but found "
                     "character set '%s'.", table->s->db.str,
                     table->alias.c_ptr(),
                     field_def->name.str, i, field_def->cset.str,
                     field->charset()->csname);
        error= TRUE;
      }
    }
    else
    {
      report_error(0, "Incorrect definition of table %s.%s: "
                   "expected column '%s' at position %d to have type %s "
                   " but the column is not found.",
                   table->s->db.str, table->alias.c_ptr(),
                   field_def->name.str, i, field_def->type.str);
      error= TRUE;
    }
  }
  }

  if (table_def->primary_key_parts)
  {
    if (table->s->primary_key == MAX_KEY)
    {
      report_error(0, "Incorrect definition of table %s.%s: "
                   "missing primary key.", table->s->db.str,
                   table->alias.c_ptr());
      error= TRUE;
    }
    else
    {
      KEY *pk= &table->s->key_info[table->s->primary_key];
      if (pk->user_defined_key_parts != table_def->primary_key_parts)
      {
        report_error(0, "Incorrect definition of table %s.%s: "
                     "Expected primary key to have %u columns, but instead "
                     "found %u columns.", table->s->db.str,
                     table->alias.c_ptr(), table_def->primary_key_parts,
                     pk->user_defined_key_parts);
        error= TRUE;
      }
      else
      {
        for (i= 0; i < pk->user_defined_key_parts; ++i)
        {
          if (table_def->primary_key_columns[i] + 1 != pk->key_part[i].fieldnr)
          {
            report_error(0, "Incorrect definition of table %s.%s: Expected "
                         "primary key part %u to refer to column %u, but "
                         "instead found column %u.", table->s->db.str,
                         table->alias.c_ptr(), i + 1,
                         table_def->primary_key_columns[i] + 1,
                         pk->key_part[i].fieldnr);
            error= TRUE;
          }
        }
      }
    }
  }

  if (likely(! error))
    table->s->table_field_def_cache= table_def;

end:

  if (has_keys && !error && !table->key_info)
  {
    report_error(0, "Incorrect definition of table %s.%s: "
                 "indexes are missing",
                 table->s->db.str, table->alias.c_ptr());
    error= TRUE;
  }

  DBUG_RETURN(error);
}


enum_tx_isolation TR_table::iso_level() const
{
  enum_tx_isolation res= (enum_tx_isolation) ((*this)[FLD_ISO_LEVEL]->val_int() - 1);
  DBUG_ASSERT(res <= ISO_SERIALIZABLE);
  return res;
}


static int add_part_field_list(THD *thd, String *str, List<const char> field_list)
{
  int err= 0;
  const char *field_name;
  List_iterator<const char> part_it(field_list);

  err+= str->append('(');
  while ((field_name= part_it++))
  {
    err+= append_identifier(thd, str, field_name, strlen(field_name));
    err+= str->append(',');
  }
  if (field_list.elements)
    str->length(str->length()-1);
  err+= str->append(')');
  return err;
}


bool Locked_tables_list::restore_lock(THD *thd, TABLE_LIST *dst_table_list,
                                      TABLE *table, MYSQL_LOCK *lock)
{
  MYSQL_LOCK *merged_lock;
  DBUG_ENTER("restore_lock");
  DBUG_ASSERT(!strcmp(dst_table_list->table_name.str, table->s->table_name.str));

  /* Ensure we have the memory to add the table back */
  if (!(merged_lock= mysql_lock_merge(thd->lock, lock)))
    DBUG_RETURN(1);
  thd->lock= merged_lock;

  /* Link to the new table */
  dst_table_list->table= table;
  /*
    The lock type may have changed (normally it should not as create
    table will lock the table in write mode
  */
  dst_table_list->lock_type= table->reginfo.lock_type;
  table->pos_in_locked_tables= dst_table_list;

  add_back_last_deleted_lock(dst_table_list);

  table->mdl_ticket->downgrade_lock(table->reginfo.lock_type >=
                                    TL_WRITE_ALLOW_WRITE ?
                                    MDL_SHARED_NO_READ_WRITE :
                                    MDL_SHARED_READ);

  DBUG_RETURN(0);
}


bool TABLE::check_virtual_columns_marked_for_write()
{
  if (vfield)
  {
    Field **vfield_ptr;
    for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
    {
      Field *tmp_vfield= *vfield_ptr;
      if (bitmap_is_set(write_set, tmp_vfield->field_index) &&
                        tmp_vfield->vcol_info->stored_in_db)
        return TRUE;
    }
  }
  return FALSE;
}


longlong Item_cache_temporal::val_time_packed()
{
  DBUG_ASSERT(fixed == 1);
  if (Item_cache_temporal::field_type() != MYSQL_TYPE_TIME)
    return Item::val_time_packed(); // DATETIME-to-TIME conversion needed
  if ((!value_cached && !cache_value()) || null_value)
  {
    null_value= TRUE;
    return 0;
  }
  return value;
}


TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find)
{
  /* is this real table and table which we are looking for? */
  if (table == table_to_find && view == 0)
    return this;
  if (!view)
    return 0;

  for (TABLE_LIST *tbl= view->select_lex.get_table_list();
       tbl;
       tbl= tbl->next_local)
  {
    TABLE_LIST *result;
    if ((result= tbl->find_underlying_table(table_to_find)))
      return result;
  }
  return 0;
}


static int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
                           bool is_subpart, uint32 *store_length_array,
                           uchar *min_value, uchar *max_value,
                           uint min_len, uint max_len,
                           uint flags, PARTITION_ITERATOR *part_iter)
{
  bool can_match_multiple_values;
  uint32 nparts;
  get_col_endpoint_func  UNINIT_VAR(get_col_endpoint);
  uint full_length= 0;
  DBUG_ENTER("get_part_iter_for_interval_cols_via_map");

  if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION)
  {
    get_col_endpoint= get_partition_id_cols_range_for_endpoint;
    part_iter->get_next= get_next_partition_id_range;
  }
  else if (part_info->part_type == LIST_PARTITION)
  {
    if (part_info->has_default_partititon() &&
        part_info->num_parts == 1)
      DBUG_RETURN(-1); //only DEFAULT partition
    get_col_endpoint= get_partition_id_cols_list_for_endpoint;
    part_iter->get_next= get_next_partition_id_list;
    part_iter->part_info= part_info;
    DBUG_ASSERT(part_info->num_list_values);
  }
  else
    assert(0);

  for (uint32 i= 0; i < part_info->num_columns; i++)
    full_length+= store_length_array[i];

  can_match_multiple_values= ((flags &
                               (NO_MIN_RANGE | NO_MAX_RANGE | NEAR_MIN |
                                NEAR_MAX)) ||
                              (min_len != max_len) ||
                              (min_len != full_length) ||
                              memcmp(min_value, max_value, min_len));
  DBUG_ASSERT(can_match_multiple_values || (flags & EQ_RANGE) || flags == 0);
  if (can_match_multiple_values && part_info->has_default_partititon())
    part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;

  if (flags & NO_MIN_RANGE)
    part_iter->part_nums.start= part_iter->part_nums.cur= 0;
  else
  {
    // Copy from min_value to record
    nparts= store_tuple_to_record(part_info->part_field_array,
                                  store_length_array,
                                  min_value,
                                  min_value + min_len);
    part_iter->part_nums.start= part_iter->part_nums.cur=
      get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN),
                       nparts);
  }
  if (flags & NO_MAX_RANGE)
  {
    if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION)
      part_iter->part_nums.end= part_info->num_parts;
    else /* LIST_PARTITION */
    {
      DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
      part_iter->part_nums.end= part_info->num_list_values;
    }
  }
  else
  {
    // Copy from max_value to record
    nparts= store_tuple_to_record(part_info->part_field_array,
                                  store_length_array,
                                  max_value,
                                  max_value + max_len);
    part_iter->part_nums.end= get_col_endpoint(part_info, FALSE,
                                               !(flags & NEAR_MAX),
                                               nparts);
  }
  if (part_iter->part_nums.start == part_iter->part_nums.end)
  {
    // No matching partition found.
    if (part_info->has_default_partititon())
    {
      part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
      DBUG_RETURN(1);
    }
    DBUG_RETURN(0);
  }
  DBUG_RETURN(1);
}


longlong Item_ref::val_datetime_packed()
{
  DBUG_ASSERT(fixed);
  longlong tmp= (*ref)->val_datetime_packed_result();
  null_value= (*ref)->null_value;
  return tmp;
}


void free_blobs(TABLE *table)
{
  uint *ptr, *end;
  for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
       ptr != end ;
       ptr++)
  {
    /*
      Reduced TABLE objects which are used by row-based replication for
      type conversion might have some fields missing. Skip freeing BLOB
      buffers for such missing fields.
    */
    if (table->field[*ptr])
      ((Field_blob*) table->field[*ptr])->free();
  }
}


void Item::set_name_no_truncate(THD *thd, const char *str, uint length,
                                CHARSET_INFO *cs)
{
  name= make_name(thd, str, length, cs, UINT_MAX - 1);
}


sp_acquire_mdl(THD *thd, Sroutine_hash_entry *rt, Open_table_context *ot_ctx)
{
  DBUG_ENTER("sp_acquire_mdl");
  /*
    Since we acquire only shared lock on routines we don't
    need to care about global intention exclusive locks.
  */
  DBUG_ASSERT(rt->mdl_request.type == MDL_SHARED);

  /*
    Waiting for a conflicting metadata lock to go away may
    lead to a deadlock, detected by MDL subsystem.
    If possible, we try to resolve such deadlocks by releasing all
    metadata locks and restarting the pre-locking process.
    To prevent the error from polluting the diagnostics area
    in case of successful resolution, install a special error
    handler for ER_LOCK_DEADLOCK error.
  */
  MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);

  thd->push_internal_handler(&mdl_deadlock_handler);
  bool result= thd->mdl_context.acquire_lock(&rt->mdl_request,
                                             ot_ctx->get_timeout());
  thd->pop_internal_handler();

  DBUG_RETURN(result);
}


longlong Item::val_int_signed_typecast_from_str()
{
  int error;
  longlong value= val_int_from_str(&error);
  if (unlikely(!null_value && value < 0 && error == 0))
    push_note_converted_to_negative_complement(current_thd);
  return value;
}


bool Item_field::find_item_in_field_list_processor(void *arg)
{
  KEY_PART_INFO *first_non_group_part= *((KEY_PART_INFO **) arg);
  KEY_PART_INFO *last_part= *(((KEY_PART_INFO **) arg) + 1);
  KEY_PART_INFO *cur_part;

  for (cur_part= first_non_group_part; cur_part != last_part; cur_part++)
  {
    if (field->eq(cur_part->field))
      return TRUE;
  }
  return FALSE;
}


enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
{
  bool error_given= false;
  File file;
  uchar *buf;
  uchar head[FRM_HEADER_SIZE];
  char	path[FN_REFLEN];
  size_t frmlen, read_length;
  uint length;
  DBUG_ENTER("open_table_def");
  DBUG_PRINT("enter", ("table: '%s'.'%s'  path: '%s'", share->db.str,
                       share->table_name.str, share->normalized_path.str));

  share->error= OPEN_FRM_OPEN_ERROR;

  length=(uint) (strxmov(path, share->normalized_path.str, reg_ext, NullS) -
                 path);
  if (flags & GTS_FORCE_DISCOVERY)
  {
    DBUG_ASSERT(flags & GTS_TABLE);
    DBUG_ASSERT(flags & GTS_USE_DISCOVERY);
    mysql_file_delete_with_symlink(key_file_frm, path, "", MYF(0));
    file= -1;
  }
  else
    file= mysql_file_open(key_file_frm, path, O_RDONLY | O_SHARE, MYF(0));

  if (file < 0)
  {
    if ((flags & GTS_TABLE) && (flags & GTS_USE_DISCOVERY))
    {
      ha_discover_table(thd, share);
      error_given= true;
    }
    goto err_not_open;
  }

  if (mysql_file_read(file, head, sizeof(head), MYF(MY_NABP)))
  {
    share->error = my_errno == HA_ERR_FILE_TOO_SHORT
                      ? OPEN_FRM_CORRUPTED : OPEN_FRM_READ_ERROR;
    goto err;
  }

  if (memcmp(head, STRING_WITH_LEN("TYPE=VIEW\n")) == 0)
  {
    share->is_view= 1;
    if (flags & GTS_VIEW)
    {
      LEX_CSTRING pathstr= { path, length };
      /*
        Create view file parser and hold it in TABLE_SHARE member
        view_def.
      */
      share->view_def= sql_parse_prepare(&pathstr, &share->mem_root, true);
      if (!share->view_def)
        share->error= OPEN_FRM_ERROR_ALREADY_ISSUED;
      else
        share->error= OPEN_FRM_OK;
    }
    else
      share->error= OPEN_FRM_NOT_A_TABLE;
    goto err;
  }
  if (!is_binary_frm_header(head))
  {
    /* No handling of text based files yet */
    share->error = OPEN_FRM_CORRUPTED;
    goto err;
  }
  if (!(flags & GTS_TABLE))
  {
    share->error = OPEN_FRM_NOT_A_VIEW;
    goto err;
  }

  frmlen= uint4korr(head+10);
  set_if_smaller(frmlen, FRM_MAX_SIZE); // safety

  if (!(buf= (uchar*)my_malloc(frmlen, MYF(MY_THREAD_SPECIFIC|MY_WME))))
    goto err;

  memcpy(buf, head, sizeof(head));

  read_length= mysql_file_read(file, buf + sizeof(head),
                               frmlen - sizeof(head), MYF(MY_WME));
  if (read_length == 0 || read_length == (size_t)-1)
  {
    share->error = OPEN_FRM_READ_ERROR;
    my_free(buf);
    goto err;
  }
  mysql_file_close(file, MYF(MY_WME));

  frmlen= read_length + sizeof(head);

  share->init_from_binary_frm_image(thd, false, buf, frmlen);
  /*
    Don't give any additional errors. If there would be a problem,
    init_from_binary_frm_image would call my_error() itself.
  */
  error_given= true;
  my_free(buf);

  goto err_not_open;

err:
  mysql_file_close(file, MYF(MY_WME));

err_not_open:
  /* Mark that table was created earlier and thus should have been logged */
  share->table_creation_was_logged= 1;

  if (unlikely(share->error && !error_given))
  {
    share->open_errno= my_errno;
    open_table_error(share, share->error, share->open_errno);
  }

  DBUG_RETURN(share->error);
}


Item_decimal::Item_decimal(THD *thd, const uchar *bin, int precision, int scale):
  Item_num(thd)
{
  binary2my_decimal(E_DEC_FATAL_ERROR, bin,
                    &decimal_value, precision, scale);
  decimals= (uint8) decimal_value.frac;
  fixed= 1;
  max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
                                                           unsigned_flag);
}


my_time_t Field_timestamp::get_timestamp(const uchar *pos,
                                         ulong *sec_part) const
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  *sec_part= 0;
  return sint4korr(pos);
}


uint repertoire(void) const { return field_repertoire; }


  int store(const LEX_CSTRING *ls, CHARSET_INFO *cs)
  {
    DBUG_ASSERT(ls->length < UINT_MAX32);
    return store(ls->str, (uint) ls->length, cs);
  }


  inline bool is_null(my_ptrdiff_t row_offset= 0) const
  {
    /*
      The table may have been marked as containing only NULL values
      for all fields if it is a NULL-complemented row of an OUTER JOIN
      or if the query is an implicitly grouped query (has aggregate
      functions but no GROUP BY clause) with no qualifying rows. If
      this is the case (in which TABLE::null_row is true), the field
      is considered to be NULL.

      Note that if a table->null_row is set then also all null_bits are
      set for the row.

      In the case of the 'result_field' for GROUP BY, table->null_row might
      refer to the *next* row in the table (when the algorithm is: read the
      next row, see if any of group column values have changed, send the
      result - grouped - row to the client if yes). So, table->null_row might
      be wrong, but such a result_field is always nullable (that's defined by
      original_field->maybe_null()) and we trust its null bit.
    */
    return null_ptr ? null_ptr[row_offset] & null_bit : table->null_row;
  }


  bool val_bool()
  {
    my_decimal decimal_value;
    my_decimal *val= val_decimal(&decimal_value);
    return val ? !my_decimal_is_zero(val) : 0;
  }


  void set_column_type_ref(Qualified_column_ident *ref)
  {
    m_column_type_ref= ref;
  }


longlong Field_blob::val_int(void)
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  char *blob;
  memcpy(&blob, ptr+packlength, sizeof(char*));
  if (!blob)
    return 0;
  THD *thd= get_thd();
  return Converter_strntoll_with_warn(thd, Warn_filter(thd),
                                      Field_blob::charset(),
                                      blob, get_length(ptr)).result();
}


bool Field_new_decimal::store_value(const my_decimal *decimal_value)
{
  int native_error;
  bool rc= store_value(decimal_value, &native_error);
  if (unlikely(!rc && native_error == E_DEC_TRUNCATED))
    set_note(WARN_DATA_TRUNCATED, 1);
  return rc;
}


sql_mode_t Field_string::can_handle_sql_mode_dependency_on_store() const
{
  return has_charset() ? MODE_PAD_CHAR_TO_FULL_LENGTH : sql_mode_t(0);
}


  virtual const uchar *unpack(uchar* to, const uchar *from,
                              const uchar *from_end, uint param_data)
  {
    if (from == from_end)
      return 0;
    *to= *from;
    return from + 1;
  }


  uint32 pack_length() const
  { return (uint32) (packlength + portable_sizeof_char_ptr); }


  DTCollation dtcollation() const
  {
    return DTCollation(charset(), derivation(), repertoire());
  }


bool Field_timestamp::load_data_set_null(THD *thd)
{
  if (!maybe_null())
  {
    /*
      Timestamp fields that are NOT NULL are autoupdated if there is no
      corresponding value in the data file.
    */
    set_time();
  }
  else
  {
    reset();
    set_null();
  }
  set_has_explicit_value(); // Do not auto-update this field
  return false;
}


virtual uint32 pack_length() const { return (uint32) field_length; }


bool Field_date::send_binary(Protocol *protocol)
{
  longlong tmp= Field_date::val_int();
  MYSQL_TIME tm;
  tm.year= (uint32) tmp/10000L % 10000;
  tm.month= (uint32) tmp/100 % 100;
  tm.day= (uint32) tmp % 100;
  return protocol->store_date(&tm);
}


int Field_medium::store(longlong nr, bool unsigned_val)
{
  ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
  int error= 0;

  if (unsigned_flag)
  {
    if (nr < 0 && !unsigned_val)
    {
      int3store(ptr,0);
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else if ((ulonglong) nr >= (ulonglong) (long) (1L << 24))
    {
      long tmp= (long) (1L << 24)-1L;
      int3store(ptr,tmp);
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else
      int3store(ptr,(uint32) nr);
  }
  else
  {
    if (nr < 0 && unsigned_val)
      nr= (ulonglong) (long) (1L << 24);        // Generate overflow

    if (nr < (longlong) INT_MIN24)
    {
      long tmp= (long) INT_MIN24;
      int3store(ptr,tmp);
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else if (nr > (longlong) INT_MAX24)
    {
      long tmp=(long) INT_MAX24;
      int3store(ptr,tmp);
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else
      int3store(ptr,(long) nr);
  }
  return error;
}


  inline uchar *record_ptr() // record[0] or wherever the field was moved to
  {
    my_ptrdiff_t offset= table->s->field[field_index]->ptr - table->s->default_values;
    return ptr - offset;
  }


static int cmp_str_prefix(const uchar *ua, size_t alen, const uchar *ub,
                          size_t blen, size_t prefix, CHARSET_INFO *cs)
{
  const char *a= (char*)ua, *b= (char*)ub;
  MY_STRCOPY_STATUS status;
  prefix/= cs->mbmaxlen;
  alen= cs->cset->well_formed_char_length(cs, a, a + alen, prefix, &status);
  blen= cs->cset->well_formed_char_length(cs, b, b + blen, prefix, &status);
  return cs->coll->strnncollsp(cs, ua, alen, ub, blen);
}


  virtual enum_field_types type() const
  {
    return type_handler()->field_type();
  }


Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
                                 uchar *null_ptr_arg, uchar null_bit_arg,
				 enum utype unireg_check_arg,
				 const LEX_CSTRING *field_name_arg,
				 TABLE_SHARE *share)
  :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
                  unireg_check_arg, field_name_arg)
{
  /* For 4.0 MYD and 4.0 InnoDB compatibility */
  flags|= UNSIGNED_FLAG;
  if (unireg_check != NONE)
  {
    /*
      We mark the flag with TIMESTAMP_FLAG to indicate to the client that
      this field will be automatically updated on insert.
    */
    flags|= TIMESTAMP_FLAG;
    if (unireg_check != TIMESTAMP_DN_FIELD)
      flags|= ON_UPDATE_NOW_FLAG;
  }
}


  uchar *pack(uchar *to, const uchar *from,
              uint max_length __attribute__((unused)))
  {
    return pack_int32(to, from);
  }


my_decimal *Field_timestamp_with_dec::val_decimal(my_decimal *d)
{
  MYSQL_TIME ltime;
  get_date(&ltime, 0);
  return TIME_to_my_decimal(&ltime, d);
}


  bool can_optimize_keypart_ref(const Item_bool_func *cond,
                                      const Item *item) const
  {
    return true;
  }


uint32 key_length() const { return (uint32) (field_length + 7) / 8; }


void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused)))
{
  if (unsigned_flag)
    to[0] = ptr[7];
  else
    to[0] = (char) (ptr[7] ^ 128);		/* Revers signbit */
  to[1]   = ptr[6];
  to[2]   = ptr[5];
  to[3]   = ptr[4];
  to[4]   = ptr[3];
  to[5]   = ptr[2];
  to[6]   = ptr[1];
  to[7]   = ptr[0];
}


void close_thread_table(THD *thd, TABLE **table_ptr)
{
  TABLE *table= *table_ptr;
  DBUG_ENTER("close_thread_table");
  DBUG_PRINT("tcache", ("table: '%s'.'%s' %p", table->s->db.str,
                        table->s->table_name.str, table));
  DBUG_ASSERT(!table->file->keyread_enabled());
  DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);

  /*
    The metadata lock must be released after giving back
    the table to the table cache.
  */
  DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
                                             table->s->db.str,
                                             table->s->table_name.str,
                                             MDL_SHARED));

  table->vcol_cleanup_expr(thd);
  table->mdl_ticket= NULL;

  if (table->file)
  {
    table->file->update_global_table_stats();
    table->file->update_global_index_stats();
  }

  /*
    This look is needed to allow THD::notify_shared_lock() to
    traverse the thd->open_tables list without having to worry that
    some of the tables are removed from under it
  */

  mysql_mutex_lock(&thd->LOCK_thd_data);
  *table_ptr=table->next;
  mysql_mutex_unlock(&thd->LOCK_thd_data);

  if (! table->needs_reopen())
  {
    /* Avoid having MERGE tables with attached children in table cache. */
    table->file->extra(HA_EXTRA_DETACH_CHILDREN);
    /* Free memory and reset for next loop. */
    free_field_buffers_larger_than(table, MAX_TDC_BLOB_SIZE);
    table->file->ha_reset();
  }

  /*
    Do this *before* entering the TABLE_SHARE::tdc.LOCK_table_share
    critical section.
  */
  MYSQL_UNBIND_TABLE(table->file);

  tc_release_table(table);
  DBUG_VOID_RETURN;
}


  inline void set_ptr(uint32 length, uchar *data)
  {
    set_ptr_offset(0, length, data);
  }


void Field_timestampf::set_max()
{
  DBUG_ENTER("Field_timestampf::set_max");
  ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
  DBUG_ASSERT(dec == TIME_SECOND_PART_DIGITS);

  set_notnull();
  mi_int4store(ptr, TIMESTAMP_MAX_VALUE);
  mi_int3store(ptr + 4, TIME_MAX_SECOND_PART);

  DBUG_VOID_RETURN;
}


double Field_varstring_compressed::val_real(void)
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  THD *thd= get_thd();
  String buf;
  val_str(&buf, &buf);
  return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
                                     buf.ptr(), buf.length()).result();
}


bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
  if (check_zero_in_date_with_warn(fuzzydate))
    return true;
  longlong tmp= my_time_packed_from_binary(ptr, dec);
  TIME_from_longlong_time_packed(ltime, tmp);
  return false;
}


int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
{
  if (!length)
    bzero(ptr, Field_blob::pack_length());
  else
  {
    if (from == Geometry::bad_geometry_data.ptr())
      goto err;
    // Check given WKB
    uint32 wkb_type;
    if (length < SRID_SIZE + WKB_HEADER_SIZE + 4)
      goto err;
    wkb_type= uint4korr(from + SRID_SIZE + 1);
    if (wkb_type < (uint32) Geometry::wkb_point ||
	wkb_type > (uint32) Geometry::wkb_last)
      goto err;

    if (geom_type != Field::GEOM_GEOMETRY &&
        geom_type != Field::GEOM_GEOMETRYCOLLECTION &&
        (uint32) geom_type != wkb_type)
    {
      const char *db= table->s->db.str;
      const char *tab_name= table->s->table_name.str;
      Geometry_buffer buffer;
      Geometry *geom= NULL;
      String wkt;
      const char *dummy;

      if (!db)
        db= "";
      if (!tab_name)
        tab_name= "";
      wkt.set_charset(&my_charset_latin1);
      if (!(geom= Geometry::construct(&buffer, from, uint32(length))) ||
          geom->as_wkt(&wkt, &dummy))
        goto err;

      my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0),
               Geometry::ci_collection[geom_type]->m_name.str,
               wkt.c_ptr_safe(), db, tab_name, field_name.str,
               (ulong) table->in_use->get_stmt_da()->
               current_row_for_warning());

      goto err_exit;
    }

    Field_blob::store_length(length);
    if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
        from != value.ptr())
    {						// Must make a copy
      value.copy(from, length, cs);
      from= value.ptr();
    }
    bmove(ptr + packlength, &from, sizeof(char*));
  }
  return 0;

err:
  my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
             ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
err_exit:
  bzero(ptr, Field_blob::pack_length());
  return -1;
}


  Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
	      uchar null_bit_arg,
	      enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
	      bool zero_arg, bool unsigned_arg)
    :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
               unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
    {}


bool match_collation_to_optimize_range() const { return true; }


String *Field_int::val_str_from_long(String *val_buffer,
                                     uint max_char_length,
                                     int radix, long nr)
{
  CHARSET_INFO *cs= &my_charset_numeric;
  uint length;
  uint mlength= MY_MAX(field_length + 1, max_char_length * cs->mbmaxlen);
  val_buffer->alloc(mlength);
  char *to=(char*) val_buffer->ptr();
  length= (uint) cs->cset->long10_to_str(cs, to, mlength, radix, nr);
  val_buffer->length(length);
  if (zerofill)
    prepend_zeros(val_buffer); /* purecov: inspected */
  val_buffer->set_charset(cs);
  return val_buffer;
}


Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
                     uint param_data)
{
  uint from_length, length;

  /*
    Compute the declared length of the field on the master. This is
    used to decide if one or two bytes should be read as length.
   */
  if (param_data)
    from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data & 0x00ff);
  else
    from_length= field_length;

  DBUG_PRINT("debug",
             ("param_data: 0x%x, field_length: %u, from_length: %u",
              param_data, field_length, from_length));
  /*
    Compute the actual length of the data by reading one or two bits
    (depending on the declared field length on the master).
   */
  if (from_length > 255)
  {
    if (from + 2 > from_end)
      return 0;
    length= uint2korr(from);
    from+= 2;
  }
  else
  {
    if (from + 1 > from_end)
      return 0;
    length= (uint) *from++;
  }
  if (from + length > from_end || length > field_length)
    return 0;

  memcpy(to, from, length);
  // Pad the string with the pad character of the fields charset
  field_charset->cset->fill(field_charset, (char*) to + length, field_length - length, field_charset->pad_char);
  return from+length;
}


  const Type_limits_int *type_limits_int() const
  {
    return type_handler_long.type_limits_int_by_unsigned_flag(is_unsigned());
  }


String *Field_short::val_str(String *val_buffer,
			     String *val_ptr __attribute__((unused)))
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  short j= sint2korr(ptr);
  long nr= unsigned_flag ? (long) (unsigned short) j : (long) j;
  return val_str_from_long(val_buffer, 7, -10, nr);
}


  const uchar *ptr_in_record(const uchar *record) const
  {
    my_ptrdiff_t l_offset= (my_ptrdiff_t) (ptr -  table->record[0]);
    DBUG_ASSERT(l_offset >= 0 && table->s->rec_buff_length - l_offset > 0);
    return record + l_offset;
  }


Field::unpack(uchar* to, const uchar *from, const uchar *from_end,
              uint param_data)
{
  uint length=pack_length(), len;
  int from_type= 0;
  /*
    If from length is > 255, it has encoded data in the upper bits. Need
    to mask it out.
  */
  if (param_data > 255)
  {
    from_type= (param_data & 0xff00) >> 8U;  // real_type.
    param_data= param_data & 0x00ff;        // length.
  }

  if ((param_data == 0) ||
      (length == param_data) ||
      (from_type != real_type()))
  {
    if (from + length > from_end)
      return 0;                                 // Error in data

    memcpy(to, from, length);
    return from+length;
  }

  len= (param_data && (param_data < length)) ? param_data : length;

  if (from + len > from_end)
    return 0;                                   // Error in data

  memcpy(to, from, len);
  return from+len;
}


enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }


String *Field_long::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  long nr= unsigned_flag ? (long) uint4korr(ptr) : sint4korr(ptr);
  return val_str_from_long(val_buffer, 12, unsigned_flag ? 10 : -10, nr);
}


Event_db_repository::
update_timing_fields_for_event(THD *thd,
                               const LEX_CSTRING *event_db_name,
                               const LEX_CSTRING *event_name,
                               my_time_t last_executed,
                               ulonglong status)
{
  TABLE *table= NULL;
  Field **fields;
  int ret= 1;
  enum_binlog_format save_binlog_format;
  MYSQL_TIME time;
  DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");

  /*
    Turn off row binlogging of event timing updates. These are not used
    for RBR of events replicated to the slave.
  */
  save_binlog_format= thd->set_current_stmt_binlog_format_stmt();

  DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);

  if (open_event_table(thd, TL_WRITE, &table))
    goto end;

  fields= table->field;

  if (find_named_event(event_db_name, event_name, table))
    goto end;

  store_record(table, record[1]);

  my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
  fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
  fields[ET_FIELD_LAST_EXECUTED]->store_time(&time);

  fields[ET_FIELD_STATUS]->set_notnull();
  fields[ET_FIELD_STATUS]->store(status, TRUE);

  if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
  {
    table->file->print_error(ret, MYF(0));
    goto end;
  }

  ret= 0;

end:
  if (table)
    close_mysql_tables(thd);

  thd->restore_stmt_binlog_format(save_binlog_format);

  DBUG_RETURN(MY_TEST(ret));
}


uint32 key_length() const { return packlength; }


int Field_bit::store_decimal(const my_decimal *val)
{
  int err= 0;
  longlong i= convert_decimal2longlong(val, 1, &err);
  return MY_TEST(err | store(i, TRUE));
}


virtual bool has_charset(void) const { return FALSE; }


  enum_field_types real_type() const
  {
    return MYSQL_TYPE_GEOMETRY;
  }


void Field_enum::store_type(ulonglong value)
{
  store_lowendian(value, ptr, packlength);
}


bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record)
{
    MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set);
  bool rc;
  if ((rc= validate_value_in_record(thd, record)))
  {
    // Get and report val_str() for the DEFAULT value
    StringBuffer<MAX_FIELD_WIDTH> tmp;
    val_str(&tmp, ptr_in_record(record));
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_INVALID_DEFAULT_VALUE_FOR_FIELD,
                        ER_THD(thd, ER_INVALID_DEFAULT_VALUE_FOR_FIELD),
                        ErrConvString(&tmp).ptr(), field_name.str);
  }
  dbug_tmp_restore_column_map(&table->read_set, old_map);
  return rc;
}


int Field_bit::cmp_prefix(const uchar *a, const uchar *b, size_t prefix_len)
{
  my_ptrdiff_t a_diff= a - ptr;
  my_ptrdiff_t b_diff= b - ptr;
  if (bit_len)
  {
    int flag;
    uchar bits_a= get_rec_bits(bit_ptr+a_diff, bit_ofs, bit_len);
    uchar bits_b= get_rec_bits(bit_ptr+b_diff, bit_ofs, bit_len);
    if ((flag= (int) (bits_a - bits_b)))
      return flag;
  }
  if (!bytes_in_rec)
    return 0;
  return memcmp(a, b, bytes_in_rec);
}


int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs)
{
  MYSQL_TIME ltime;
  MYSQL_TIME_STATUS status;
  THD *thd= get_thd();
  ErrConvString str(from, len, cs);
  bool func_res= !str_to_datetime(cs, from, len, &ltime,
                                  sql_mode_for_dates(thd),
                                  &status);
  return store_TIME_with_warning(&ltime, &str, status.warnings, func_res);
}


void Field_new_decimal::sql_type(String &str) const
{
  CHARSET_INFO *cs= str.charset();
  str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(),
                                "decimal(%d,%d)", precision, (int)dec));
  add_zerofill_and_unsigned(str);
}


uint length_size() { return length_bytes; }


  virtual uchar *pack(uchar* to, const uchar *from,
                      uint max_length  __attribute__((unused)))
  {
    return pack_int64(to, from);
  }


  virtual bool validate_value_in_record(THD *thd, const uchar *record) const
  { return false; }


uint32 pack_length() const { return 2; }


int Field_float::store(double nr)
{
  ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
  int error= truncate_double(&nr, field_length,
                             not_fixed ? NOT_FIXED_DEC : dec,
                             unsigned_flag, FLT_MAX);
  if (unlikely(error))
  {
    set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
    if (error < 0)                                // Wrong double value
    {
      error= 1;
      set_null();
    }
  }
  float j= (float)nr;

  float4store(ptr,j);
  return error;
}


virtual uint32 key_length() const { return pack_length(); }


uint Field_num::is_equal(Create_field *new_field)
{
  return ((new_field->type_handler() == type_handler()) &&
          ((new_field->flags & UNSIGNED_FLAG) ==
           (uint) (flags & UNSIGNED_FLAG)) &&
	  ((new_field->flags & AUTO_INCREMENT_FLAG) ==
	   (uint) (flags & AUTO_INCREMENT_FLAG)) &&
          (new_field->pack_length == pack_length()));
}


  Field_datetime_with_dec(uchar *ptr_arg, uchar *null_ptr_arg,
                          uchar null_bit_arg, enum utype unireg_check_arg,
                          const LEX_CSTRING *field_name_arg, uint dec_arg)
    :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg),
                    null_ptr_arg, null_bit_arg, unireg_check_arg,
                    field_name_arg), dec(dec_arg)
  {
    DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
  }