Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Impressum item_strfunc.cc   Sprache: C

 

/*
   Copyright (c) 2000, 2017, Oracle and/or its affiliates.
   Copyright (c) 2009, 2022, MariaDB Corporation.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA
*/


/**
  @file

  @brief
  This file defines all string functions

  @warning
    Some string functions don't always put and end-null on a String.
    (This shouldn't be needed)
*/


#include "mariadb.h"                          // HAVE_*

#include "sql_priv.h"
/*
  It is necessary to include set_var.h instead of item.h because there
  are dependencies on include order for set_var.h and item.h. This
  will be resolved later.
*/

#include "sql_class.h"                          // set_var.h: THD
#include "set_var.h"
#include "sql_base.h"
#include "sql_time.h"
#include "password.h"           // my_make_scrambled_password,
                                // my_make_scrambled_password_323
#include <m_ctype.h>
#include <my_md5.h>
C_MODE_START
#include "../mysys/my_static.h"   // For soundex_map
C_MODE_END
#include "sql_show.h"                           // append_identifier
#include <sql_repl.h>
#include "sql_statistics.h"
#include "strfunc.h"

#ifdef HAVE_hkdf
#include <openssl/kdf.h>
#endif

/* fmtlib include (https://fmt.dev/). */
#define FMT_HEADER_ONLY 1
#include "fmt/args.h"

/*
  an allocator that implements std::allocator interface.
  can be used with std or fmt.
  but it uses our memory accounting
  and allows to limit strings to max_allowed_packet
  to be more generic needs to take MY_THREAD_SPECIFIC and PSI key as arguments,
  and limit the amount of memory allocated, not just size of one allocation
*/

template <typename T> struct my_allocator {
  using value_type= T;
  std::size_t max_alloc;

  my_allocator(std::size_t max_alloc) : max_alloc(max_alloc) {};
  template <typename U> my_allocator(const my_allocator<U>&o)
    : max_alloc(o.max_alloc) {}

  T* allocate(std::size_t n)
  {
    void* p= n > max_alloc / sizeof(T)
             ? nullptr : my_malloc(PSI_INSTRUMENT_MEM, n * sizeof(T),
                                   MYF(MY_THREAD_SPECIFIC));
    if (!p)
      throw std::bad_alloc();
    return static_cast<T*>(p);
  }

  std::size_t max_size() { return max_alloc / sizeof(T); }
  void deallocate(T* p, std::size_t) noexcept { my_free(p); }
  bool operator==(const my_allocator&) const noexcept { return true; }
  bool operator!=(const my_allocator&) const noexcept { return false; }
};

size_t username_char_length= USERNAME_CHAR_LENGTH;

/*
  Calculate max length of string from length argument to LEFT and RIGHT
*/


static uint32 max_length_for_string(Item *item, bool *neg)
{
  *neg= false;
  ulonglong length= item->val_int();
  if (item->null_value)
    return 0;
  if (length > (ulonglong) LONGLONG_MAX && !item->unsigned_flag)
  {
    *neg= true;
    return 0; // Negative
  }
  if (length > (ulonglong) INT_MAX32)
  {
    /* Limit string length to maximum string length in MariaDB (2G) */
    length= (ulonglong) INT_MAX32;
  }
  return (uint32) length;
}


/*
  For the Items which have only val_str_ascii() method
  and don't have their own "native" val_str(),
  we provide a "wrapper" method to convert from ASCII
  to Item character set when it's necessary.
  Conversion happens only in case of "tricky" Item character set (e.g. UCS2).
  Normally conversion does not happen, and val_str_ascii() is immediately
  returned instead.

  No matter if conversion is needed or not needed,
  the result is always returned in "str" (see MDEV-10306 why).

  @param [OUT] str          - Store the result here
  @param [IN]  ascii_buffer - Use this temporary buffer to call val_str_ascii()
*/

String *Item_func::val_str_from_val_str_ascii(String *str, String *ascii_buffer)
{
  DBUG_ASSERT(fixed());

  if (!(collation.collation->state & MY_CS_NONASCII))
  {
    String *res= val_str_ascii(str);
    if (res)
      res->set_charset(collation.collation);
    return res;
  }

  DBUG_ASSERT(str != ascii_buffer);

  uint errors;
  String *res= val_str_ascii(ascii_buffer);
  if (!res)
    return 0;

  if ((null_value= str->copy(res->ptr(), res->length(),
                             &my_charset_latin1, collation.collation,
                             &errors)))
    return 0;

  return str;
}


bool Item_str_func::fix_fields(THD *thd, Item **ref)
{
  bool res= Item_func::fix_fields(thd, ref);
  /*
    In Item_str_func::check_well_formed_result() we may set null_value
    flag on the same condition as in test() below.
  */

  if (thd->is_strict_mode())
    set_maybe_null();
  return res;
}


my_decimal *Item_str_func::val_decimal(my_decimal *decimal_value)
{
  DBUG_ASSERT(fixed());
  StringBuffer<64> tmp;
  String *res= val_str(&tmp);
  return res ? decimal_from_string_with_check(decimal_value, res) : 0;
}


double Item_str_func::val_real()
{
  DBUG_ASSERT(fixed());
  StringBuffer<64> tmp;
  String *res= val_str(&tmp);
  return res ? double_from_string_with_check(res) : 0.0;
}


longlong Item_str_func::val_int()
{
  DBUG_ASSERT(!is_cond());
  DBUG_ASSERT(fixed());
  StringBuffer<22> tmp;
  String *res= val_str(&tmp);
  return res ? longlong_from_string_with_check(res) : 0;
}


String *Item_func_md5::val_str_ascii(String *str)
{
  DBUG_ASSERT(fixed());
  String * sptr= args[0]->val_str(str);
  if (sptr)
  {
    uchar digest[16];

    null_value=0;
    compute_md5_hash(digest, (const char *) sptr->ptr(), sptr->length());
    if (str->alloc(32))    // Ensure that memory is free
    {
      null_value=1;
      return 0;
    }
    array_to_hex((char *) str->ptr(), digest, 16);
    str->set_charset(&my_charset_numeric);
    str->length((uint) 32);
    return str;
  }
  null_value=1;
  return 0;
}


String *Item_func_sha::val_str_ascii(String *str)
{
  DBUG_ASSERT(fixed());
  String * sptr= args[0]->val_str(str);
  if (sptr)  /* If we got value different from NULL */
  {
    /* Temporary buffer to store 160bit digest */
    uint8 digest[MY_SHA1_HASH_SIZE];
    my_sha1(digest, (const char *) sptr->ptr(), sptr->length());
    /* Ensure that memory is free and we got result */
    if (!str->alloc(MY_SHA1_HASH_SIZE*2))
    {
      array_to_hex((char *) str->ptr(), digest, MY_SHA1_HASH_SIZE);
      str->set_charset(&my_charset_numeric);
      str->length((uint)  MY_SHA1_HASH_SIZE*2);
      null_value=0;
      return str;
    }
  }
  null_value=1;
  return 0;
}

bool Item_func_sha::fix_length_and_dec(THD *thd)
{
  // size of hex representation of hash
  fix_length_and_charset(MY_SHA1_HASH_SIZE * 2, default_charset());
  return FALSE;
}

String *Item_func_sha2::val_str_ascii(String *str)
{
  DBUG_ASSERT(fixed());
  unsigned char digest_buf[512/8]; // enough for SHA512
  String *input_string;
  const char *input_ptr;
  size_t input_len;

  input_string= args[0]->val_str(str);
  str->set_charset(&my_charset_bin);

  if (input_string == NULL)
  {
    null_value= TRUE;
    return (String *) NULL;
  }

  null_value= args[0]->null_value;
  if (null_value)
    return (String *) NULL;

  input_ptr= input_string->ptr();
  input_len= input_string->length();

  longlong digest_length= args[1]->val_int();
  switch (digest_length) {
  case 512:
    my_sha512(digest_buf, input_ptr, input_len);
    break;
  case 384:
    my_sha384(digest_buf, input_ptr, input_len);
    break;
  case 224:
    my_sha224(digest_buf, input_ptr, input_len);
    break;
  case 0: // SHA-256 is the default
    digest_length= 256;
    /* fall through */
  case 256:
    my_sha256(digest_buf, input_ptr, input_len);
    break;
  default:
    if (!args[1]->const_item())
    {
      THD *thd= current_thd;
      push_warning_printf(thd,
                          Sql_condition::WARN_LEVEL_WARN,
                          ER_WRONG_PARAMETERS_TO_NATIVE_FCT,
                          ER_THD(thd, ER_WRONG_PARAMETERS_TO_NATIVE_FCT),
                          "sha2");
    }
    null_value= TRUE;
    return NULL;
  }
  digest_length/= 8; /* bits to bytes */

  /*
    Since we're subverting the usual String methods, we must make sure that
    the destination has space for the bytes we're about to write.
  */

  str->alloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */

  /* Convert the large number to a string-hex representation. */
  array_to_hex((char *) str->ptr(), digest_buf, (uint)digest_length);

  /* We poked raw bytes in.  We must inform the String of its length. */
  str->length((uint) digest_length*2); /* Each byte as two nybbles */

  null_value= FALSE;
  return str;
}


bool Item_func_sha2::fix_length_and_dec(THD *thd)
{
  set_maybe_null();
  max_length = 0;

  int sha_variant= (int)(args[1]->const_item() ? args[1]->val_int() : 512);

  switch (sha_variant) {
  case 0: // SHA-256 is the default
    sha_variant= 256;
    /* fall through */
  case 512:
  case 384:
  case 256:
  case 224:
    fix_length_and_charset(sha_variant/8 * 2, default_charset());
    break;
  default:
    THD *thd= current_thd;
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_WRONG_PARAMETERS_TO_NATIVE_FCT,
                        ER_THD(thd, ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2");
  }
  return FALSE;
}

const char *block_encryption_mode_values[]= {
  "aes-128-ecb", "aes-192-ecb", "aes-256-ecb",
  "aes-128-cbc", "aes-192-cbc", "aes-256-cbc",
  "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
  NullS };
TYPELIB block_encryption_mode_typelib=
        CREATE_TYPELIB_FOR(block_encryption_mode_values);
static inline uint block_encryption_mode_to_key_length(ulong bem)
{ return (bem % 3 + 2) * 64; }
static inline my_aes_mode block_encryption_mode_to_aes_mode(ulong bem)
{ return (my_aes_mode)(bem / 3); }

/* Implementation of AES encryption routines */
int Item_aes_crypt::parse_mode()
{
  StringBuffer<80> buf;
  String *ptr= args[3]->val_str_ascii(&buf);
  ulong bem;

  if (ptr == NULL)
    goto err;

  bem= find_type(&block_encryption_mode_typelib, ptr->ptr(), ptr->length(), 0);
  if (!bem)
    goto err;

  aes_key_length= block_encryption_mode_to_key_length(bem - 1);
  aes_mode= block_encryption_mode_to_aes_mode(bem - 1);
  return 0;
err:
  return 1;
}


void Item_aes_crypt::create_key(String *user_key, uchar *real_key)
{
  uchar *real_key_end= real_key + aes_key_length / 8;
  uchar *ptr;
  const char *sptr= user_key->ptr();
  const char *key_end= sptr + user_key->length();

  bzero(real_key, aes_key_length / 8);

  for (ptr= real_key; sptr < key_end; ptr++, sptr++)
  {
    if (ptr == real_key_end)
      ptr= real_key;
    *ptr ^= (uchar) *sptr;
  }
}


String *Item_aes_crypt::val_str(String *str2)
{
  DBUG_ASSERT(fixed());
  StringBuffer<80> user_key_buf, iv_buf;
  String *sptr= args[0]->val_str(&tmp_value);
  String *user_key= args[1]->val_str(&user_key_buf);
  String *iv= NULL;
  uint32 aes_length;

  if (sptr && user_key) // we need both arguments to be not NULL
  {
    if (arg_count > 3 && (null_value= parse_mode()))
      return 0;

    if (aes_mode != MY_AES_ECB)
    {
      if (arg_count > 2)
        iv= args[2]->val_str(&iv_buf);
      if ((null_value= (!iv || iv->length() < MY_AES_BLOCK_SIZE)))
        return 0;
    }

    aes_length=my_aes_get_size(aes_mode, sptr->length());

    if (!str2->alloc(aes_length))  // Ensure that memory is free
    {
      uchar *rkey= (uchar*)alloca(aes_key_length / 8);
      create_key(user_key, rkey);

      if (!my_aes_crypt(aes_mode, what, (uchar*)sptr->ptr(), sptr->length(),
                 (uchar*)str2->ptr(), &aes_length,
                 rkey, aes_key_length / 8,
                 iv ? (uchar*)iv->ptr() : 0, iv ? iv->length() : 0))
      {
        str2->length((uint) aes_length);
        DBUG_ASSERT(collation.collation == &my_charset_bin);
        str2->set_charset(&my_charset_bin);
        null_value= 0;
        return str2;
      }
    }
  }
  null_value=1;
  return 0;
}

bool Item_aes_crypt::fix_fields(THD *thd, Item **ref)
{
  aes_key_length= block_encryption_mode_to_key_length(thd->variables.block_encryption_mode);
  aes_mode= block_encryption_mode_to_aes_mode(thd->variables.block_encryption_mode);
  return  Item_str_binary_checksum_func::fix_fields(thd, ref);
}

bool Item_func_aes_encrypt::fix_length_and_dec(THD *thd)
{
  max_length=my_aes_get_size(MY_AES_ECB, args[0]->max_length);
  return FALSE;
}

bool Item_func_aes_decrypt::fix_length_and_dec(THD *thd)
{
  max_length=args[0]->max_length;
  set_maybe_null();
  return FALSE;
}

bool Item_func_kdf::fix_length_and_dec(THD *thd)
{
  if (arg_count > 4 && args[4]->const_item())
  {
    if (((key_length= (uint)args[4]->val_int()) % 8) || key_length > 65536)
      key_length= 0;
  }
  else if (arg_count <= 4)
    key_length= block_encryption_mode_to_key_length(thd->variables.block_encryption_mode);
  else
    key_length= 0;
  key_length/= 8;
  max_length= key_length ? key_length : 256/8;
  set_maybe_null();
  return FALSE;
}

static void invalid_argument_error(const char *func, const char *val)
{
  THD *thd= current_thd;
  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
    ER_STD_INVALID_ARGUMENT, ER_THD(thd, ER_STD_INVALID_ARGUMENT),
    val, func);
}

String *Item_func_kdf::val_str(String *buf)
{
  // KDF(key_str, salt [, {info | iterations} [, kdf_name [, width ]]])
  DBUG_ASSERT(fixed());
  StringBuffer<80> key_buf, salt_buf;
  String *key= args[0]->val_str(&key_buf);
  String *salt= args[1]->val_str(&salt_buf);
  bool use_hkdf= false;
  size_t klen= key_length;
  bool ok= false;

  if (!key || !salt)
    goto ret_null;

  if (arg_count > 3)
  {
    if (String *s= args[3]->val_str(buf))
    {
      if (strcasecmp(s->c_ptr(), "hkdf") == 0)
        use_hkdf= true;
      else if (strcasecmp(s->c_ptr(), "pbkdf2_hmac") != 0)
      {
        invalid_argument_error(func_name(), ErrConvStringQ(s).ptr());
        goto ret_null;
      }
    }
    else
      goto ret_null;
  }
  if (!klen)
  {
    klen= args[4]->val_int();
    if (!klen || klen % 8 || klen > 65536)
    {
      if (!args[4]->null_value)
        invalid_argument_error(func_name(),
          ErrConvInteger({(ssize_t)klen, args[4]->unsigned_flag}).ptr());
      goto ret_null;
    }
    klen/= 8;
  }
  buf->reserve(klen);
  buf->length(klen);

  if (use_hkdf)
  {
#ifdef HAVE_hkdf
    StringBuffer<80> info_buf;
    String *info= arg_count > 2 ? args[2]->val_str(&info_buf) : 0;

    EVP_PKEY_CTX *ctx= EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
    ok= EVP_PKEY_derive_init(ctx) > 0 &&
        EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_sha512()) > 0 &&
        EVP_PKEY_CTX_set1_hkdf_key(ctx, (const uchar*)key->ptr(), key->length()) > 0 &&
        EVP_PKEY_CTX_set1_hkdf_salt(ctx, (const uchar*)salt->ptr(), salt->length()) > 0 &&
        (!info || EVP_PKEY_CTX_add1_hkdf_info(ctx, (const uchar*)info->ptr(), info->length()) > 0) &&
        EVP_PKEY_derive(ctx, (uchar*)buf->ptr(), &klen) > 0;

    EVP_PKEY_CTX_free(ctx);
#else
    THD *thd= current_thd;
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
      ER_NOT_SUPPORTED_YET, ER_THD(thd, ER_NOT_SUPPORTED_YET),
      "kdf(..., 'hkdf')");
#endif
  }
  else
  {
    longlong iter= arg_count > 2 ? args[2]->val_int() : 1000;
    if (iter <= 0)
    {
      if (!args[2]->null_value)
        invalid_argument_error(func_name(),
          ErrConvInteger({iter, args[2]->unsigned_flag}).ptr());
    }
    else
      ok= PKCS5_PBKDF2_HMAC(key->ptr(), key->length(),
                      (const uchar*)salt->ptr(), salt->length(), (int)iter,
                      EVP_sha512(), (int)klen, (uchar*)buf->ptr());
  }

  if (ok)
  {
    null_value= 0;
    return buf;
  }

ret_null:
  null_value=1;
  return 0;
}

bool Item_func_to_base64::fix_length_and_dec(THD *thd)
{
  base_flags|= args[0]->base_flags & item_base_t::MAYBE_NULL;
  collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
  if (args[0]->max_length > (uint) my_base64_encode_max_arg_length())
  {
    set_maybe_null();
    fix_char_length_ulonglong((ulonglong) my_base64_encode_max_arg_length());
  }
  else
  {
    int length= my_base64_needed_encoded_length((int) args[0]->max_length);
    DBUG_ASSERT(length > 0);
    fix_char_length_ulonglong((ulonglong) length - 1);
  }
  return FALSE;
}


String *Item_func_to_base64::val_str_ascii(String *str)
{
  String *res= args[0]->val_str(&tmp_value);
  bool too_long= false;
  int length;
  if (!res ||
      res->length() > (uint) my_base64_encode_max_arg_length() ||
      (too_long=
       ((uint) (length= my_base64_needed_encoded_length((int) res->length())) >
        current_thd->variables.max_allowed_packet)) ||
      str->alloc((uint) length))
  {
    null_value= 1; // NULL input, too long input, or OOM.
    if (too_long)
    {
      THD *thd= current_thd;
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(),
                          thd->variables.max_allowed_packet);
    }
    return 0;
  }
  my_base64_encode(res->ptr(), (int) res->length(), (char*) str->ptr());
  DBUG_ASSERT(length > 0);
  str->length((uint) length - 1); // Without trailing '\0'
  null_value= 0;
  return str;
}


bool Item_func_from_base64::fix_length_and_dec(THD *thd)
{
  if (args[0]->max_length > (uint) my_base64_decode_max_arg_length())
  {
    fix_char_length_ulonglong((ulonglong) my_base64_decode_max_arg_length());
  }
  else
  {
    int length= my_base64_needed_decoded_length((int) args[0]->max_length);
    fix_char_length_ulonglong((ulonglong) length);
  }
  // Can be NULL, e.g. in case of badly formed input string
  set_maybe_null();
  return FALSE;
}


String *Item_func_from_base64::val_str(String *str)
{
  String *res= args[0]->val_str_ascii(&tmp_value);
  int length;
  const char *end_ptr;

  if (!res)
    goto err;

  if (res->length() > (uint) my_base64_decode_max_arg_length() ||
      ((uint) (length= my_base64_needed_decoded_length((int) res->length())) >
       current_thd->variables.max_allowed_packet))
  {
    THD *thd= current_thd;
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                        ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                        func_name(),
                        thd->variables.max_allowed_packet);
    goto err;
  }

  if (str->alloc((uint) length))
    goto err;

  if ((length= my_base64_decode(res->ptr(), (int) res->length(),
                                (char *) str->ptr(), &end_ptr, 0)) < 0 ||
      end_ptr < res->ptr() + res->length())
  {
    THD *thd= current_thd;
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_BAD_BASE64_DATA, ER_THD(thd, ER_BAD_BASE64_DATA),
                        (int) (end_ptr - res->ptr()));
    goto err;
  }

  str->length((uint) length);
  null_value= 0;
  return str;
err:
  null_value= 1; // NULL input, too long input, OOM, or badly formed input
  return 0;
}
///////////////////////////////////////////////////////////////////////////////


const char *histogram_types[] =
    {"SINGLE_PREC_HB", "DOUBLE_PREC_HB", "JSON_HB", 0};
static TYPELIB histogram_types_typelib= CREATE_TYPELIB_FOR(histogram_types);
const char *representation_by_type[]= {"%.3f", "%.5f"};

String *Item_func_decode_histogram::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char buff[STRING_BUFFER_USUAL_SIZE];
  String *res, tmp(buff, sizeof(buff), &my_charset_bin);
  int type;

  tmp.length(0);
  if (!(res= args[0]->val_str(&tmp)) ||
      (type= find_type(res->c_ptr_safe(),
                       &histogram_types_typelib, MYF(0))) <= 0)
  {
    null_value= 1;
    return 0;
  }
  type--;

  tmp.length(0);
  if (!(res= args[1]->val_str(&tmp)))
  {
    null_value= 1;
    return 0;
  }

  if (type == JSON_HB)
  {
    // It's a JSON histogram. Return it as-is.
    null_value= 0;
    return res;
  }

  if (type == DOUBLE_PREC_HB && res->length() % 2 != 0)
    res->length(res->length() - 1); // one byte is unused

  double prev= 0.0;
  uint i;
  str->length(0);
  char numbuf[32];
  const uchar *p= (uchar*)res->c_ptr_safe();
  for (i= 0; i < res->length(); i++)
  {
    double val;
    switch (type)
    {
    case SINGLE_PREC_HB:
      val= p[i] / ((double)((1 << 8) - 1));
      break;
    case DOUBLE_PREC_HB:
      val= uint2korr(p + i) / ((double)((1 << 16) - 1));
      i++;
      break;
    default:
      val= 0;
      DBUG_ASSERT(0);
    }
    /* show delta with previous value */
    size_t size= my_snprintf(numbuf, sizeof(numbuf),
                          representation_by_type[type], val - prev);
    str->append(numbuf, size);
    str->append(',');
    prev= val;
  }
  /* show delta with max */
  size_t size= my_snprintf(numbuf, sizeof(numbuf),
                        representation_by_type[type], 1.0 - prev);
  str->append(numbuf, size);

  null_value=0;
  return str;
}


///////////////////////////////////////////////////////////////////////////////

/*
  Realloc the result buffer.
  NOTE: We should be prudent in the initial allocation unit -- the
  size of the arguments is a function of data distribution, which
  can be any. Instead of overcommitting at the first row, we grow
  the allocated amount by the factor of 2. This ensures that no
  more than 25% of memory will be overcommitted on average.

  @param IN/OUT str    - the result string
  @param IN     length - new total space required in "str"
  @retval       false  - on success
  @retval       true   - on error
*/


bool Item_func_concat::realloc_result(String *str, uint length) const
{
  if (str->alloced_length() >= length)
    return false; // Alloced space is big enough, nothing to do.

  if (str->alloced_length() == 0)
    return str->alloc(length);

  /*
    Item_func_concat::val_str() makes sure the result length does not grow
    higher than max_allowed_packet. So "length" is limited to 1G here.
    We can't say anything about the current value of str->alloced_length(),
    as str was initially set by args[0]->val_str(str).
    So multiplication by 2 can overflow, if args[0] for some reasons
    did not limit the result to max_alloced_packet. But it's not harmful,
    "str" will be reallocated exactly to "length" bytes in case of overflow.
  */

  uint new_length= MY_MAX(str->alloced_length() * 2, length);
  return str->realloc(new_length);
}


/**
  Concatenate args with the following premises:
  If only one arg (which is ok), return value of arg;
*/


String *Item_func_concat::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  THD *thd= current_thd;
  String *res;

  null_value=0;
  if (!(res= args[0]->val_str(str)))
    goto null;

  if (res != str)
    str->copy_or_move(res->ptr(), res->length(), res->charset());

  for (uint i= 1 ; i < arg_count ; i++)
  {
    if (!(res= args[i]->val_str(&tmp_value)) ||
        append_value(thd, str, res))
      goto null;
  }

  str->set_charset(collation.collation);
  return str;

null:
  null_value= true;
  return 0;
}


String *Item_func_concat_operator_oracle::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  THD *thd= current_thd;
  String *res= NULL;
  uint i;

  null_value=0;
  // Search first non null argument
  for (i= 0; i < arg_count; i++)
  {
    if ((res= args[i]->val_str(str)))
      break;
  }
  if (!res)
    goto null;

  if (res != str)
    str->copy_or_move(res->ptr(), res->length(), res->charset());

  for (i++ ; i < arg_count ; i++)
  {
    if (!(res= args[i]->val_str(&tmp_value)) || res->length() == 0)
     continue;
    if (append_value(thd, str, res))
      goto null;
  }

  str->set_charset(collation.collation);
  return str;

null:
  null_value= true;
  return 0;
}


bool Item_func_concat::append_value(THD *thd, String *res, const String *app)
{
  uint concat_len;
  if ((concat_len= res->length() + app->length()) >
      thd->variables.max_allowed_packet)
  {
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                        ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
                        thd->variables.max_allowed_packet);
    return true;
  }
  DBUG_ASSERT(!res->uses_buffer_owned_by(app));
  DBUG_ASSERT(!app->uses_buffer_owned_by(res));
  return realloc_result(res, concat_len) || res->append(*app);
}


bool Item_func_concat::fix_length_and_dec(THD *thd)
{
  ulonglong char_length= 0;

  if (agg_arg_charsets_for_string_result(collation, args, arg_count))
    return TRUE;

  for (uint i=0 ; i < arg_count ; i++)
    char_length+= args[i]->max_char_length();

  fix_char_length_ulonglong(char_length);
  return FALSE;
}


/**
  concat with separator. First arg is the separator
  concat_ws takes at least two arguments.
*/


String *Item_func_concat_ws::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char tmp_str_buff[10];
  String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info),
         *sep_str, *res, *res2,*use_as_buff;
  uint i;
  bool is_const= 0;
  THD *thd= 0;

  null_value=0;
  if (!(sep_str= args[0]->val_str(&tmp_sep_str)))
    goto null;

  use_as_buff= &tmp_value;
  str->length(0);    // QQ; Should be removed
  res=str;                                      // If 0 arg_count

  // Skip until non-null argument is found.
  // If not, return the empty string
  for (i=1; i < arg_count; i++)
    if ((res= args[i]->val_str(str)))
    {
      is_const= args[i]->const_item();
      break;
    }

  if (i ==  arg_count)
    return make_empty_result(str);

  for (i++; i < arg_count ; i++)
  {
    if (!(res2= args[i]->val_str(use_as_buff)))
      continue;     // Skip NULL

    if (!thd)
      thd= current_thd;
    if (res->length() + sep_str->length() + res2->length() >
 thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
     ER_WARN_ALLOWED_PACKET_OVERFLOWED,
     ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(),
     thd->variables.max_allowed_packet);
      goto null;
    }
    if (!is_const && res->alloced_length() >=
 res->length() + sep_str->length() + res2->length())
    {      // Use old buffer
      res->append(*sep_str);   // res->length() > 0 always
      res->append(*res2);
    }
    else if (str->alloced_length() >=
      res->length() + sep_str->length() + res2->length())
    {
      /* We have room in str;  We can't get any errors here */
      if (str->ptr() == res2->ptr())
      {      // This is quite uncommon!
 str->replace(0,0,*sep_str);
 str->replace(0,0,*res);
      }
      else
      {
 str->copy(*res);
 str->append(*sep_str);
 str->append(*res2);
      }
      res=str;
      use_as_buff= &tmp_value;
    }
    else if (res == &tmp_value)
    {
      if (res->append(*sep_str) || res->append(*res2))
 goto null; // Must be a blob
    }
    else if (res2 == &tmp_value)
    {      // This can happen only 1 time
      if (tmp_value.replace(0,0,*sep_str) || tmp_value.replace(0,0,*res))
 goto null;
      res= &tmp_value;
      use_as_buff=str;    // Put next arg here
    }
    else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
      res2->ptr() < tmp_value.ptr() + tmp_value.alloced_length())
    {
      /*
 This happens really seldom:
 In this case res2 is sub string of tmp_value.  We will
 now work in place in tmp_value to set it to res | sep_str | res2
      */

      /* Chop the last characters in tmp_value that isn't in res2 */
      tmp_value.length((uint32) (res2->ptr() - tmp_value.ptr()) +
         res2->length());
      /* Place res2 at start of tmp_value, remove chars before res2 */
      if (tmp_value.replace(0,(uint32) (res2->ptr() - tmp_value.ptr()),
       *res) ||
   tmp_value.replace(res->length(),0, *sep_str))
 goto null;
      res= &tmp_value;
      use_as_buff=str;   // Put next arg here
    }
    else
    {      // Two big const strings
      /*
        NOTE: We should be prudent in the initial allocation unit -- the
        size of the arguments is a function of data distribution, which can
        be any. Instead of overcommitting at the first row, we grow the
        allocated amount by the factor of 2. This ensures that no more than
        25% of memory will be overcommitted on average.
      */


      uint concat_len= res->length() + sep_str->length() + res2->length();

      if (tmp_value.alloced_length() < concat_len)
      {
        if (tmp_value.alloced_length() == 0)
        {
          if (tmp_value.alloc(concat_len))
            goto null;
        }
        else
        {
          uint new_len = MY_MAX(tmp_value.alloced_length() * 2, concat_len);

          if (tmp_value.alloc(new_len))
            goto null;
        }
      }

      if (tmp_value.copy(*res) ||
   tmp_value.append(*sep_str) ||
   tmp_value.append(*res2))
 goto null;
      res= &tmp_value;
      use_as_buff=str;
    }
  }
  res->set_charset(collation.collation);
  return res;

null:
  null_value=1;
  return 0;
}


bool Item_func_concat_ws::fix_length_and_dec(THD *thd)
{
  ulonglong char_length;

  if (agg_arg_charsets_for_string_result(collation, args, arg_count))
    return TRUE;

  /*
     arg_count cannot be less than 2,
     it is done on parser level in sql_yacc.yy
     so, (arg_count - 2) is safe here.
  */

  char_length= (ulonglong) args[0]->max_char_length() * (arg_count - 2);
  for (uint i=1 ; i < arg_count ; i++)
    char_length+= args[i]->max_char_length();

  fix_char_length_ulonglong(char_length);
  return FALSE;
}


String *Item_func_reverse::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(&tmp_value);
  const char *ptr, *end;
  char *tmp;

  if ((null_value=args[0]->null_value))
    return 0;
  /* An empty string is a special case as the string pointer may be null */
  if (!res->length())
    return make_empty_result(str);
  if (str->alloc(res->length()))
  {
    null_value= 1;
    return 0;
  }
  str->length(res->length());
  str->set_charset(res->charset());
  ptr= res->ptr();
  end= res->end();
  tmp= (char *) str->end();
#ifdef USE_MB
  if (res->use_mb())
  {
    uint32 l;
    while (ptr < end)
    {
      if ((l= my_ismbchar(res->charset(),ptr,end)))
      {
        tmp-= l;
        DBUG_ASSERT(tmp >= str->ptr());
        memcpy(tmp,ptr,l);
        ptr+= l;
      }
      else
        *--tmp= *ptr++;
    }
  }
  else
#endif /* USE_MB */
  {
    while (ptr < end)
      *--tmp= *ptr++;
  }
  return str;
}


bool Item_func_reverse::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  fix_char_length(args[0]->max_char_length());
  return FALSE;
}

/**
  Replace all occurrences of string2 in string1 with string3.

  Don't reallocate val_str() if not needed.

  @todo
    Fix that this works with binary strings when using USE_MB
*/


String *Item_func_replace::val_str_internal(String *str, bool null_to_empty)
{
  DBUG_ASSERT(fixed());
  String *res,*res2,*res3;
  int offset;
  uint from_length,to_length;
  bool alloced=0;
#ifdef USE_MB
  const char *ptr,*end,*strend,*search,*search_end;
  uint32 l;
  bool binary_cmp;
#endif
  THD *thd= 0;

  null_value=0;
  res=args[0]->val_str(str);
  if (args[0]->null_value)
    goto null;
  if (!(res2= args[1]->val_str_null_to_empty(&tmp_value, null_to_empty)))
    goto null;
  res->set_charset(collation.collation);

#ifdef USE_MB
  binary_cmp = ((res->charset()->state & MY_CS_BINSORT) || !res->use_mb());
#endif

  if (res2->length() == 0)
    return res;
#ifndef USE_MB
  if ((offset=res->strstr(*res2)) < 0)
    return res;
#else
  offset=0;
  if (binary_cmp && (offset=res->strstr(*res2)) < 0)
    return res;
#endif
  if (!(res3= args[2]->val_str_null_to_empty(&tmp_value2, null_to_empty)))
    goto null;
  from_length= res2->length();
  to_length=   res3->length();

#ifdef USE_MB
  if (!binary_cmp)
  {
    search=res2->ptr();
    search_end=search+from_length;
redo:
    DBUG_ASSERT(res->ptr() || !offset);
    ptr=res->ptr()+offset;
    strend=res->ptr()+res->length();
    /*
      In some cases val_str() can return empty string
      with ptr() == NULL and length() == 0.
      Let's check strend to avoid overflow.
    */

    end= strend ? strend - from_length + 1 : NULL;
    while (ptr < end)
    {
      if (*ptr == *search)
      {
        char *i,*j;
        i=(char*) ptr+1; j=(char*) search+1;
        while (j != search_end)
          if (*i++ != *j++) goto skip;
        offset= (int) (ptr-res->ptr());

        if (!thd)
          thd= current_thd;

        if (res->length()-from_length + to_length >
            thd->variables.max_allowed_packet)
        {
          push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                              ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                              ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                              func_name(),
                              thd->variables.max_allowed_packet);

          goto null;
        }
        if (!alloced)
        {
          alloced=1;
          res=copy_if_not_alloced(str,res,res->length()+to_length);
        }
        res->replace((uint) offset,from_length,*res3);
        offset+=(int) to_length;
        goto redo;
      }
  skip:
      if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
      else ++ptr;
    }
  }
  else
#endif /* USE_MB */
  {
    thd= current_thd;
    do
    {
      if (res->length()-from_length + to_length >
   thd->variables.max_allowed_packet)
      {
 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
       ER_WARN_ALLOWED_PACKET_OVERFLOWED,
       ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                            func_name(),
       thd->variables.max_allowed_packet);
        goto null;
      }
      if (!alloced)
      {
        alloced=1;
        res=copy_if_not_alloced(str,res,res->length()+to_length);
      }
      res->replace((uint) offset,from_length,*res3);
      offset+=(int) to_length;
    }
    while ((offset=res->strstr(*res2,(uint) offset)) >= 0);
  }
  if (null_to_empty && !res->length())
    goto null;

  return res;

null:
  null_value=1;
  return 0;
}


bool Item_func_replace::fix_length_and_dec(THD *thd)
{
  ulonglong char_length= (ulonglong) args[0]->max_char_length();
  int diff=(int) (args[2]->max_char_length() - 1);
  if (diff > 0)
  {      // Calculate of maxreplaces
    ulonglong max_substrs= char_length;
    char_length+= max_substrs * (uint) diff;
  }

  if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3))
    return TRUE;
  fix_char_length_ulonglong(char_length);
  return FALSE;
}

/*
  this is done in the constructor to be in the same memroot as
  the item itself
*/

void Item_func_sformat::alloc(THD *thd)
{
  val_arg= new (thd->mem_root) String[arg_count];
}


bool Item_func_sformat::fix_length_and_dec(THD *thd)
{
  if (!val_arg)
    return TRUE;

  uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
              MY_COLL_ALLOW_COERCIBLE_CONV |
              MY_COLL_ALLOW_NUMERIC_CONV;

  if (Type_std_attributes::agg_item_collations(collation, func_name_cstring(),
        args, arg_count, flags, 1))
    return TRUE;

  DTCollation c= collation;
  if (c.collation->mbminlen > 1)
    c.collation= &my_charset_utf8mb4_bin;

  for (uint i=0 ; i < arg_count ; i++)
  {
    if (args[i]->result_type() == STRING_RESULT &&
        Type_std_attributes::agg_item_set_converter(c, func_name_cstring(),
                                                    args+i, 1, flags, 1))
      return TRUE;
  }

  max_length= (uint32)MY_MIN((ulonglong)thd->variables.max_allowed_packet,
                             thd->variables.max_mem_used);
  return FALSE;
}

/*
  allow fmt to take String arguments directly.
  Inherit from string_view, so all string formatting works.
  but {:p} doesn't, because it's not char*, not a pointer.
*/

namespace fmt {
  template <> struct formatter<String>: formatter<string_view> {
    template <typename FormatContext>
    auto format(String c, FormatContext& ctx) const -> decltype(ctx.out()) {
      string_view name = { c.ptr(), c.length() };
      return formatter<string_view>::format(name, ctx);
    };
    /* needed below function for libfmt-7.1.3 compatibility, (not 9.1.0+) */
    template <typename FormatContext>
    auto format(String c, FormatContext& ctx) -> decltype(ctx.out()) {
      string_view name = { c.ptr(), c.length() };
      return formatter<string_view>::format(name, ctx);
    };
  };
};

struct fmt_locale_comma : std::numpunct<char>
{
  char do_thousands_sep() const override { return ','; }
  std::string do_grouping() const override { return "\3"; }
};
static std::locale fmt_locale(std::locale(), new fmt_locale_comma);

using fmt_buffer= fmt::basic_memory_buffer<char, fmt::inline_buffer_size,
                                           my_allocator<char> >;
/*
  SFORMAT(format_string, ...)
  This function receives a formatting specification string and N parameters
  (N >= 0), and it returns string formatted using the rules the user passed
  in the specification. It uses fmtlib (https://fmt.dev/).
*/

String *Item_func_sformat::val_str(String *res)
{
  DBUG_ASSERT(fixed());
  using         ArgStore= fmt::dynamic_format_arg_store<fmt::format_context>;
  String       *fmt_arg=  NULL;
  String       *parg=     NULL;
  ArgStore      arg_store;

  null_value= true;
  if (!(fmt_arg= args[0]->val_str(res)))
    return NULL;

  /* Creates the array of arguments for vformat */
  for (uint carg= 1; carg < arg_count; carg++)
  {
    switch (args[carg]->result_type())
    {
    case INT_RESULT:
      arg_store.push_back(args[carg]->val_int());
      break;
    case DECIMAL_RESULT: // TODO
    case REAL_RESULT:
      if (args[carg]->field_type() == MYSQL_TYPE_FLOAT)
        arg_store.push_back((float)args[carg]->val_real());
      else
        arg_store.push_back(args[carg]->val_real());
      break;
    case STRING_RESULT:
      if (!(parg= args[carg]->val_str(&val_arg[carg-1])))
      {
        return NULL;
      }
      arg_store.push_back(*parg);
      break;
    case TIME_RESULT: // TODO
    case ROW_RESULT: // TODO
    default:
      DBUG_ASSERT(0);
      return NULL;
    }
  }

  /* Create the string output  */
  try
  {
    /* have to use *1.5 to match fmt realloc strategy */
    fmt_buffer text{my_allocator<char>(max_length + max_length/2)};
    fmt::vformat_to(std::back_inserter(text), fmt_locale,
                    fmt_arg->c_ptr_safe(), arg_store);
    if (!((null_value= text.size() > max_length)))
    {
      res->length(0);
      res->set_charset(collation.collation);
      res->append(text.data(), text.size(), fmt_arg->charset());
    }
  }
  catch (const fmt::format_error &ex)
  {
    THD *thd= current_thd;
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        WARN_SFORMAT_ERROR,
                        ER_THD(thd, WARN_SFORMAT_ERROR), ex.what());
    null_value= true;
  }
  catch (const std::bad_alloc&)
  {
    null_value= true; // OOM
  }
  return null_value ? NULL : res;
}

#include"my_global.h"
#include <openssl/rand.h>
#include <openssl/err.h>

bool Item_func_random_bytes::fix_length_and_dec(THD *thd)
{
  set_maybe_null();
  used_tables_cache|= RAND_TABLE_BIT;
  if (args[0]->can_eval_in_optimize())
  {
    int32 v= (int32) args[0]->val_int();
    max_length= MY_MAX(0, MY_MIN(v, MAX_RANDOM_BYTES));
    return false;
  }
  max_length= MAX_RANDOM_BYTES;
  return false;
}


void Item_func_random_bytes::update_used_tables()
{
  Item_str_func::update_used_tables();
  used_tables_cache|= RAND_TABLE_BIT;
}


String *Item_func_random_bytes::val_str(String *str)
{
  longlong count= args[0]->val_int();

  if (args[0]->null_value)
    goto err;
  null_value= 0;

  if (count < 0 || count > MAX_RANDOM_BYTES)
    goto err;

  if (count == 0)
    return make_empty_result(str);

  if (str->alloc((uint) count))
    goto err;

  str->length(count);
  str->set_charset(&my_charset_bin);
  if (my_random_bytes((unsigned char *) str->ptr(), (int32) count))
  {
    ulong ssl_err;
    while ((ssl_err= ERR_get_error()))
    {
      char buf[256];
      ERR_error_string_n(ssl_err, buf, sizeof(buf));
      sql_print_warning("SSL error: %s", buf);
    }
    goto err;
  }

  return str;

err:
  null_value= 1;
  return 0;
}


/*********************************************************************/
bool Item_func_regexp_replace::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3))
    return TRUE;
  max_length= MAX_BLOB_WIDTH;
  re.init(collation.collation, 0);
  re.fix_owner(this, args[0], args[1]);
  return FALSE;
}


/*
  Traverse through the replacement string and append to "str".
  Sub-pattern references \0 .. \9 are recognized, which are replaced
  to the chunks of the source string.
*/

bool Item_func_regexp_replace::append_replacement(String *str,
                                                  const LEX_CSTRING *source,
                                                  const LEX_CSTRING *replace)
{
  const char *beg= replace->str;
  const char *end= beg + replace->length;
  CHARSET_INFO *cs= re.library_charset();

  for ( ; ; )
  {
    my_wc_t wc;
    int cnv, n;

    if ((cnv= cs->mb_wc(&wc, (const uchar *) beg,
                             (const uchar *) end)) < 1)
      break; /* End of line */
    beg+= cnv;

    if (wc != '\\')
    {
      if (str->append(beg - cnv, cnv, cs))
        return true;
      continue;
    }

    if ((cnv= cs->mb_wc(&wc, (const uchar *) beg,
                             (const uchar *) end)) < 1)
      break; /* End of line */
    beg+= cnv;

    if ((n= ((int) wc) - '0') >= 0 && n <= 9)
    {
      if (n < re.nsubpatterns())
      {
        /* A valid sub-pattern reference found */
        size_t pbeg= re.subpattern_start(n), plength= re.subpattern_end(n) - pbeg;
        if (str->append(source->str + pbeg, plength, cs))
          return true;
      }
    }
    else
    {
      /*
         A non-digit character following after '\'.
         Just add the character itself.
       */

      if (str->append(beg - cnv, cnv, cs))
        return false;
    }
  }
  return false;
}


String *Item_func_regexp_replace::val_str_internal(String *str,
                                                   bool null_to_empty)
{
  DBUG_ASSERT(fixed());
  char buff0[MAX_FIELD_WIDTH];
  char buff2[MAX_FIELD_WIDTH];
  String tmp0(buff0,sizeof(buff0),&my_charset_bin);
  String tmp2(buff2,sizeof(buff2),&my_charset_bin);
  String *source, *replace;
  LEX_CSTRING src, rpl;
  size_t startoffset= 0;

  source= args[0]->val_str(&tmp0);
  if (!source)
    goto err;
  replace= args[2]->val_str_null_to_empty(&tmp2, null_to_empty);
  if (!replace || re.recompile(args[1]))
    goto err;
  if (!(source= re.convert_if_needed(source, &re.subject_converter)) ||
      !(replace= re.convert_if_needed(replace, &re.replace_converter)))
    goto err;
  null_value= false;

  source->get_value(&src);
  replace->get_value(&rpl);

  str->length(0);
  str->set_charset(collation.collation);

  for ( ; ; ) // Iterate through all matches
  {

    if (re.exec(src.str, src.length, startoffset))
      goto err;

    if (!re.match() || re.subpattern_length(0) == 0)
    {
      /*
        No match or an empty match.
        Append the rest of the source string
        starting from startoffset until the end of the source.
      */

      if (str->append(src.str + startoffset, src.length - startoffset,
                      re.library_charset()))
        goto err;
      return str;
    }

    /*
      Append prefix, the part before the matching pattern.
      starting from startoffset until the next match
    */

    if (str->append(src.str + startoffset,
          re.subpattern_start(0) - startoffset, re.library_charset()))
      goto err;

    // Append replacement
    if (append_replacement(str, &src, &rpl))
      goto err;

    // Set the new start point as the end of previous match
    startoffset= re.subpattern_end(0);
  }
  return str;

err:
  null_value= true;
  return nullptr;
}


bool Item_func_regexp_substr::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
    return TRUE;
  fix_char_length(args[0]->max_char_length());
  re.init(collation.collation, 0);
  re.fix_owner(this, args[0], args[1]);
  return FALSE;
}


String *Item_func_regexp_substr::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char buff0[MAX_FIELD_WIDTH];
  String tmp0(buff0,sizeof(buff0),&my_charset_bin);
  String *source= args[0]->val_str(&tmp0);

  if ((null_value= (args[0]->null_value || re.recompile(args[1]))))
    return (String *) 0;

  if (!(source= re.convert_if_needed(source, &re.subject_converter)))
    goto err;

  str->length(0);
  str->set_charset(collation.collation);

  if (re.exec(source->ptr(), source->length(), 0))
    goto err;

  if (!re.match())
    return str;

  if (str->append(source->ptr() + re.subpattern_start(0),
                  re.subpattern_length(0), re.library_charset()))
    goto err;

  return str;

err:
  null_value= true;
  return (String *) 0;
}


/************************************************************************/


String *Item_func_insert::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res,*res2;
  longlong start, length;  /* must be longlong to avoid truncation */

  null_value=0;
  res=args[0]->val_str(str);
  res2=args[3]->val_str(&tmp_value);
  start= args[1]->val_int();
  length= args[2]->val_int();

  if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
      args[3]->null_value)
    goto null; /* purecov: inspected */

  if ((start <= 0) || (start > res->length()))
    return res;                                 // Wrong param; skip insert
  if ((length < 0) || (length > res->length()))
    length= res->length();
  start--;

  /*
    There is one exception not handled (intentionally) by the character set
    aggregation code. If one string is strong side and is binary, and
    another one is weak side and is a multi-byte character string,
    then we need to operate on the second string in terms on bytes when
    calling ::numchars() and ::charpos(), rather than in terms of characters.
    Lets substitute its character set to binary.
  */

  if (collation.collation == &my_charset_bin)
  {
    res->set_charset(&my_charset_bin);
    res2->set_charset(&my_charset_bin);
  }

  /* start and length are now sufficiently valid to pass to charpos function */
   start= res->charpos((int) start);
   length= res->charpos((int) length, (uint32) start);

  /* Re-testing with corrected params */
  if (start + 1 > res->length()) // remember, start = args[1].val_int() - 1
    return res; /* purecov: inspected */        // Wrong param; skip insert
  if (length > res->length() - start)
    length= res->length() - start;

  {
    THD *thd= current_thd;
    if ((ulonglong) (res->length() - length + res2->length()) >
        (ulonglong) thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(), thd->variables.max_allowed_packet);
      goto null;
    }
  }
  res=copy_if_not_alloced(str,res,res->length());
  res->replace((uint32) start,(uint32) length,*res2);
  return res;
null:
  null_value=1;
  return 0;
}


bool Item_func_insert::fix_length_and_dec(THD *thd)
{
  ulonglong char_length;

  // Handle character set for args[0] and args[3].
  if (agg_arg_charsets_for_string_result(collation, args, 2, 3))
    return TRUE;
  if (collation.collation == &my_charset_bin)
    char_length= (ulonglong) args[0]->max_length +
                 (ulonglong) args[3]->max_length;
  else
    char_length= ((ulonglong) args[0]->max_char_length() +
                  (ulonglong) args[3]->max_char_length());
  fix_char_length_ulonglong(char_length);
  return FALSE;
}


String *Item_str_conv::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(&tmp_value);

  if (!res)
  {
  err:
    null_value= true;
    return nullptr;
  }

  size_t alloced_length= res->length() * multiply, len;

  if (str->alloc((alloced_length)))
    goto err;

  null_value= false;
  len= converter(collation.collation, (char*) res->ptr(), res->length(),
                                      (char*) str->ptr(), alloced_length);
  DBUG_ASSERT(len <= alloced_length);
  str->set_charset(collation.collation);
  str->length(len);
  return str;
}


bool Item_func_lcase::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  multiply= collation.collation->casedn_multiply();
  converter= collation.collation->cset->casedn;
  fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * multiply);
  return FALSE;
}

bool Item_func_ucase::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  multiply= collation.collation->caseup_multiply();
  converter= collation.collation->cset->caseup;
  fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * multiply);
  return FALSE;
}


bool Item_func_left::hash_not_null(Hasher *hasher)
{
  StringBuffer<STRING_BUFFER_USUAL_SIZE> buf;
  String *str= val_str(&buf);
  DBUG_ASSERT((str == NULL) == null_value);
  if (!str)
    return true;
  hasher->add(collation.collation, str->ptr(), str->length());
  return false;
}


String *Item_func_left::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(str);

  /* must be longlong to avoid truncation */
  longlong length= args[1]->val_int();
  uint char_pos;

  if ((null_value=(args[0]->null_value || args[1]->null_value)))
    return 0;

  /* if "unsigned_flag" is set, we have a *huge* positive number. */
  if ((length <= 0) && (!args[1]->unsigned_flag))
    return make_empty_result(str);
  if ((res->length() <= (ulonglong) length) ||
      (res->length() <= (char_pos= res->charpos((int) length))))
    return res;

  tmp_value.set(*res, 0, char_pos);
  return &tmp_value;
}


void Item_str_func::left_right_max_length()
{
  uint32 char_length= args[0]->max_char_length();
  if (args[1]->can_eval_in_optimize())
  {
    bool neg;
    uint32 length= max_length_for_string(args[1], &neg);
    set_if_smaller(char_length, length);
  }
  fix_char_length(char_length);
}


bool Item_func_left::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  left_right_max_length();
  return FALSE;
}


String *Item_func_right::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(str);
  /* must be longlong to avoid truncation */
  longlong length= args[1]->val_int();

  if ((null_value=(args[0]->null_value || args[1]->null_value)))
    return 0; /* purecov: inspected */

  /* if "unsigned_flag" is set, we have a *huge* positive number. */
  if ((length <= 0) && (!args[1]->unsigned_flag))
    return make_empty_result(str); /* purecov: inspected */

  if (res->length() <= (ulonglong) length)
    return res; /* purecov: inspected */

  uint start=res->numchars();
  if (start <= (uint) length)
    return res;
  start=res->charpos(start - (uint) length);
  tmp_value.set(*res,start,res->length()-start);
  return &tmp_value;
}


bool Item_func_right::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  left_right_max_length();
  return FALSE;
}


String *Item_func_substr::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res  = args[0]->val_str(str);
  /* must be longlong to avoid truncation */
  longlong start= get_position();
  /* Assumes that the maximum length of a String is < INT_MAX32. */
  /* Limit so that code sees out-of-bound value properly. */
  longlong length= arg_count == 3 ? args[2]->val_int() : INT_MAX32;
  longlong tmp_length;

  if ((null_value=(args[0]->null_value || args[1]->null_value ||
     (arg_count == 3 && args[2]->null_value))))
    return 0; /* purecov: inspected */

  /* Negative or zero length, will return empty string. */
  if ((arg_count == 3) && (length <= 0) &&
      (length == 0 || !args[2]->unsigned_flag))
    return make_empty_result(str);

  /* Assumes that the maximum length of a String is < INT_MAX32. */
  /* Set here so that rest of code sees out-of-bound value as such. */
  if ((length <= 0) || (length > INT_MAX32))
    length= INT_MAX32;

  /* if "unsigned_flag" is set, we have a *huge* positive number. */
  /* Assumes that the maximum length of a String is < INT_MAX32. */
  if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) ||
      (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32)))
    return make_empty_result(str);

  start= ((start < 0) ? res->numchars() + start : start - 1);
  start= res->charpos((int) start);
  if ((start < 0) || ((uint) start + 1 > res->length()))
    return make_empty_result(str);

  length= res->charpos((int) length, (uint32) start);
  tmp_length= res->length() - start;
  length= MY_MIN(length, tmp_length);

  if (!start && (longlong) res->length() == length)
    return res;
  tmp_value.set(*res, (uint32) start, (uint32) length);
  return &tmp_value;
}


bool Item_func_substr::fix_length_and_dec(THD *thd)
{
  max_length=args[0]->max_length;

  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  if (args[1]->const_item())
  {
    int32 start= (int32) get_position();
    if (args[1]->null_value)
      max_length= 0;
    else if (start < 0)
      max_length= ((uint)(-start) > max_length) ? 0 : (uint)(-start);
    else
      max_length-= MY_MIN((uint)(start - 1), max_length);
  }
  if (arg_count == 3 && args[2]->const_item())
  {
    longlong length= args[2]->val_int();
    if (args[2]->null_value || (length <= 0 && !args[2]->unsigned_flag))
      max_length=0; /* purecov: inspected */
    else if (length < UINT32_MAX)
      set_if_smaller(max_length, (uint32) length);
  }
  max_length*= collation.collation->mbmaxlen;
  return FALSE;
}


bool Item_func_substr_index::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2))
    return TRUE;
  fix_char_length(args[0]->max_char_length());
  return FALSE;
}


String *Item_func_substr_index::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char buff[MAX_FIELD_WIDTH];
  String tmp(buff,sizeof(buff),system_charset_info);
  String *res= args[0]->val_str(&tmp_value);
  String *delimiter= args[1]->val_str(&tmp);
  int32 count= (int32) args[2]->val_int();
  uint offset;

  if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
  {     // string and/or delim are null
    null_value=1;
    return 0;
  }
  null_value=0;
  uint delimiter_length= delimiter->length();
  if (!res->length() || !delimiter_length || !count)
    return make_empty_result(str);      // Wrong parameters

  res->set_charset(collation.collation);

#ifdef USE_MB
  if (res->use_mb())
  {
    const char *ptr= res->ptr();
    const char *strend= ptr+res->length();
    const char *end= strend-delimiter_length+1;
    const char *search= delimiter->ptr();
    const char *search_end= search+delimiter_length;
    int32 n=0,c=count,pass;
    uint32 l;
    for (pass=(count>0);pass<2;++pass)
    {
      while (ptr < end)
      {
        if (*ptr == *search)
        {
   char *i,*j;
   i=(char*) ptr+1; j=(char*) search+1;
   while (j != search_end)
     if (*i++ != *j++) goto skip;
   if (pass==0) ++n;
   else if (!--c) break;
   ptr+= delimiter_length;
   continue;
 }
    skip:
        if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
        else ++ptr;
      } /* either not found or got total number when count<0 */
      if (pass == 0) /* count<0 */
      {
        c+=n+1;
        if (c<=0)
        {
          str->copy(res->ptr(), res->length(), collation.collation);
          return str; // not found, return the original string
        }
        ptr=res->ptr();
      }
      else
      {
        if (c)
        {
          str->copy(res->ptr(), res->length(), collation.collation);
          return str; // not found, return the original string
        }
        if (count>0) /* return left part */
        {
          str->copy(res->ptr(), (uint32) (ptr-res->ptr()), collation.collation);
          return str;
        }
        else /* return right part */
        {
          ptr+= delimiter_length;
          str->copy(res->ptr() + (ptr-res->ptr()), (uint32) (strend - ptr),
                    collation.collation);
          return str;
        }
      }
    }
  }
  else
#endif /* USE_MB */
  {
    if (count > 0)
    {     // start counting from the beginning
      for (offset=0; ; offset+= delimiter_length)
      {
        if ((int) (offset= res->strstr(*delimiter, offset)) < 0)
        {
          str->copy(res->ptr(), res->length(), collation.collation);
          return str; // not found, return the original string
        }
        if (!--count)
        {
          str->copy(res->ptr(), offset, collation.collation);
          return str;
        }
      }
    }
    else
    {
      /*
        Negative index, start counting at the end
      */

      for (offset=res->length(); offset ;)
      {
        /*
          this call will result in finding the position pointing to one
          address space less than where the found substring is located
          in res
        */

        if ((int) (offset= res->strrstr(*delimiter, offset)) < 0)
        {
          str->copy(res->ptr(), res->length(), collation.collation);
          return str; // not found, return the original string
        }
        /*
          At this point, we've searched for the substring
          the number of times as supplied by the index value
        */

        if (!++count)
        {
          offset+= delimiter_length;
          str->copy(res->ptr() + offset, res->length() - offset,
                    collation.collation);
          return str;
        }
      }
      if (count)
      {
        str->copy(res->ptr(), res->length(), collation.collation);
        return str; // not found, return the original string
      }
    }
  }
  DBUG_ASSERT(0);
  return NULL;
}

/*
** The trim functions are extension to ANSI SQL because they trim substrings
** They ltrim() and rtrim() functions are optimized for 1 byte strings
** They also return the original string if possible, else they return
** a substring that points at the original string.
*/



String *Item_func_ltrim::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char buff[MAX_FIELD_WIDTH], *ptr, *end;
  String tmp(buff,sizeof(buff),system_charset_info);
  String *res, *remove_str;
  uint UNINIT_VAR(remove_length);

  res= args[0]->val_str(str);
  if ((null_value=args[0]->null_value))
    return 0;
  remove_str= &remove;                          /* Default value. */
  if (arg_count == 2)
  {
    remove_str= args[1]->val_str(&tmp);
    if ((null_value= args[1]->null_value))
      return 0;
  }

  if ((remove_length= remove_str->length()) == 0 ||
      remove_length > res->length())
    return non_trimmed_value(res);

  ptr= (char*) res->ptr();
  end= ptr+res->length();
  if (remove_length == 1)
  {
    char chr=(*remove_str)[0];
    while (ptr != end && *ptr == chr)
      ptr++;
  }
  else
  {
    const char *r_ptr=remove_str->ptr();
    end-=remove_length;
    while (ptr <= end && !memcmp(ptr, r_ptr, remove_length))
      ptr+=remove_length;
    end+=remove_length;
  }
  if (ptr == res->ptr())
    return non_trimmed_value(res);
  return trimmed_value(res, (uint32) (ptr - res->ptr()), (uint32) (end - ptr));
}


String *Item_func_rtrim::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char buff[MAX_FIELD_WIDTH], *ptr, *end;
  String tmp(buff, sizeof(buff), system_charset_info);
  String *res, *remove_str;
  uint UNINIT_VAR(remove_length);

  res= args[0]->val_str(str);
  if ((null_value=args[0]->null_value))
    return 0;
  remove_str= &remove;                          /* Default value. */
  if (arg_count == 2)
  {
    remove_str= args[1]->val_str(&tmp);
    if ((null_value= args[1]->null_value))
      return 0;
  }

  if ((remove_length= remove_str->length()) == 0 ||
      remove_length > res->length())
    return non_trimmed_value(res);

  ptr= (char*) res->ptr();
  end= ptr+res->length();
#ifdef USE_MB
  char *p=ptr;
  uint32 l;
#endif
  if (remove_length == 1)
  {
    char chr=(*remove_str)[0];
#ifdef USE_MB
    if (collation.collation->use_mb())
    {
      while (ptr < end)
      {
 if ((l= my_ismbchar(collation.collation, ptr, end))) ptr+= l, p=ptr;
 else ++ptr;
      }
      ptr=p;
    }
#endif
    while (ptr != end  && end[-1] == chr)
      end--;
  }
  else
  {
    const char *r_ptr=remove_str->ptr();
#ifdef USE_MB
    if (collation.collation->use_mb())
    {
  loop:
      while (ptr + remove_length < end)
      {
 if ((l= my_ismbchar(collation.collation, ptr, end))) ptr+= l;
 else ++ptr;
      }
      if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
      {
 end-=remove_length;
 ptr=p;
 goto loop;
      }
    }
    else
#endif /* USE_MB */
    {
      while (ptr + remove_length <= end &&
      !memcmp(end-remove_length, r_ptr, remove_length))
 end-=remove_length;
    }
  }
  if (end == res->ptr()+res->length())
    return non_trimmed_value(res);
  return trimmed_value(res, 0, (uint32) (end - res->ptr()));
}


String *Item_func_trim::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  char buff[MAX_FIELD_WIDTH], *ptr, *end;
  const char *r_ptr;
  String tmp(buff, sizeof(buff), system_charset_info);
  String *res, *remove_str;
  uint UNINIT_VAR(remove_length);

  res= args[0]->val_str(str);
  if ((null_value=args[0]->null_value))
    return 0;
  remove_str= &remove;                          /* Default value. */
  if (arg_count == 2)
  {
    remove_str= args[1]->val_str(&tmp);
    if ((null_value= args[1]->null_value))
      return 0;
  }

  if ((remove_length= remove_str->length()) == 0 ||
      remove_length > res->length())
    return non_trimmed_value(res);

  ptr= (char*) res->ptr();
  end= ptr+res->length();
  r_ptr= remove_str->ptr();
  while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
    ptr+=remove_length;
#ifdef USE_MB
  if (collation.collation->use_mb())
  {
    char *p=ptr;
    uint32 l;
 loop:
    while (ptr + remove_length < end)
    {
      if ((l= my_ismbchar(collation.collation, ptr, end)))
        ptr+= l;
      else
        ++ptr;
    }
    if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
    {
      end-=remove_length;
      ptr=p;
      goto loop;
    }
    ptr=p;
  }
  else
#endif /* USE_MB */
  {
    while (ptr + remove_length <= end &&
    !memcmp(end-remove_length,r_ptr,remove_length))
      end-=remove_length;
  }
  if (ptr == res->ptr() && end == ptr+res->length())
    return non_trimmed_value(res);
  return trimmed_value(res, (uint32) (ptr - res->ptr()), (uint32) (end - ptr));
}

bool Item_func_trim::fix_length_and_dec(THD *thd)
{
  if (arg_count == 1)
  {
    if (agg_arg_charsets_for_string_result(collation, args, 1))
      return TRUE;
    DBUG_ASSERT(collation.collation != NULL);
    remove.set_charset(collation.collation);
    remove.set_ascii(" ",1);
  }
  else
  {
    // Handle character set for args[1] and args[0].
    // Note that we pass args[1] as the first item, and args[0] as the second.
    if (agg_arg_charsets_for_string_result_with_comparison(collation,
                                                           &args[1], 2, -1))
      return TRUE;
  }
  fix_char_length(args[0]->max_char_length());
  return FALSE;
}

void Item_func_trim::print(String *str, enum_query_type query_type)
{
  LEX_CSTRING suffix= {STRING_WITH_LEN("_oracle")};
  if (arg_count == 1)
  {
    if (query_type & QT_FOR_FRM)
    {
      // 10.3 downgrade compatibility for FRM
      str->append(func_name_cstring());
      if (schema() == &oracle_schema_ref)
        str->append(suffix);
    }
    else
      print_sql_mode_qualified_name(str, query_type, func_name_cstring());
    print_args_parenthesized(str, query_type);
    return;
  }

  if (query_type & QT_FOR_FRM)
  {
    // 10.3 downgrade compatibility for FRM
    str->append(Item_func_trim::func_name_cstring());
    if (schema() == &oracle_schema_ref)
      str->append(suffix);
  }
  else
    print_sql_mode_qualified_name(str, query_type, Item_func_trim::func_name_cstring());
  str->append('(');
  str->append(mode_name());
  str->append(' ');
  args[1]->print(str, query_type);
  str->append(STRING_WITH_LEN(" from "));
  args[0]->print(str, query_type);
  str->append(')');
}


/*
  RTRIM(expr)
  TRIM(TRAILING ' ' FROM expr)
  remove argument's soft dependency on PAD_CHAR_TO_FULL_LENGTH:
*/

Sql_mode_dependency Item_func_trim::value_depends_on_sql_mode() const
{
  DBUG_ASSERT(fixed());
  if (arg_count == 1) // RTRIM(expr)
    return (args[0]->value_depends_on_sql_mode() &
            Sql_mode_dependency(~0, ~MODE_PAD_CHAR_TO_FULL_LENGTH)).
           soft_to_hard();
  // TRIM(... FROM expr)
  DBUG_ASSERT(arg_count == 2);
  if (!args[1]->value_depends_on_sql_mode_const_item())
    return Item_func::value_depends_on_sql_mode();
  StringBuffer<64> trimstrbuf;
  String *trimstr= args[1]->val_str(&trimstrbuf);
  if (!trimstr)
    return Sql_mode_dependency();                  // will return NULL
  if (trimstr->length() == 0)
    return Item_func::value_depends_on_sql_mode(); // will trim nothing
  if (trimstr->lengthsp() != 0)
    return Item_func::value_depends_on_sql_mode(); // will trim not only spaces
  if (trimstr->length() > trimstr->charset()->mbminlen ||
      trimstr->numchars() > 1)
    return Item_func::value_depends_on_sql_mode(); // more than one space
  // TRIM(TRAILING ' ' FROM expr)
  return ((args[0]->value_depends_on_sql_mode() |
           args[1]->value_depends_on_sql_mode()) &
          Sql_mode_dependency(~0, ~MODE_PAD_CHAR_TO_FULL_LENGTH)).
         soft_to_hard();
}


/* Item_func_password */

bool Item_func_password::fix_fields(THD *thd, Item **ref)
{
  if (deflt)
    alg= (thd->variables.old_passwords ? OLD : NEW);
  return Item_str_ascii_func::fix_fields(thd, ref);
}

String *Item_func_password::val_str_ascii(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(str);
  switch (alg){
  case NEW:
    if (args[0]->null_value || res->length() == 0)
      return make_empty_result(str);
    my_make_scrambled_password(tmp_value, res->ptr(), res->length());
    str->copy(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
    break;
  case OLD:
    if ((null_value=args[0]->null_value))
      return 0;
    if (res->length() == 0)
      return make_empty_result(str);
    my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
    str->copy(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1);
    break;
  default:
    DBUG_ASSERT(0);
  }
  return str;
}

char *Item_func_password::alloc(THD *thd, const char *password,
                                size_t pass_len, enum PW_Alg al)
{
  char *buff= thd->alloc(al==NEW ? SCRAMBLED_PASSWORD_CHAR_LENGTH + 1
                                 : SCRAMBLED_PASSWORD_CHAR_LENGTH_323 + 1);
  if (!buff)
    return NULL;

  switch (al) {
  case NEW:
    my_make_scrambled_password(buff, password, pass_len);
    break;
  case OLD:
    my_make_scrambled_password_323(buff, password, pass_len);
    break;
  default:
    DBUG_ASSERT(0);
  }
  return buff;
}



#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')

String *Item_func_encrypt::val_str(String *str)
{
  DBUG_ASSERT(fixed());

#ifdef HAVE_CRYPT
  String *res  =args[0]->val_str(str);

  char salt[3],*salt_ptr;
  if ((null_value=args[0]->null_value))
    return 0;
  if (res->length() == 0)
    return make_empty_result(str);
  if (arg_count == 1)
  {     // generate random salt
    time_t timestamp=current_thd->query_start();
    salt[0] = bin_to_ascii( (ulong) timestamp & 0x3f);
    salt[1] = bin_to_ascii(( (ulong) timestamp >> 5) & 0x3f);
    salt[2] = 0;
    salt_ptr=salt;
  }
  else
  {     // obtain salt from the first two bytes
    String *salt_str=args[1]->val_str(&tmp_value);
    if ((null_value= (args[1]->null_value || salt_str->length() < 2)))
      return 0;
    salt_ptr= salt_str->c_ptr_safe();
  }
  mysql_mutex_lock(&LOCK_crypt);
  char *tmp= crypt(res->c_ptr_safe(),salt_ptr);
  if (!tmp)
  {
    mysql_mutex_unlock(&LOCK_crypt);
    null_value= 1;
    return 0;
  }
  str->set(tmp, (uint) strlen(tmp), &my_charset_bin);
  str->copy();
  mysql_mutex_unlock(&LOCK_crypt);
  return str;
#else
  null_value=1;
  return 0;
#endif /* HAVE_CRYPT */
}

bool Item_func_encode::seed()
{
  char buf[80];
  ulong rand_nr[2];
  String *key, tmp(buf, sizeof(buf), system_charset_info);

  if (!(key= args[1]->val_str(&tmp)))
    return TRUE;

  hash_password(rand_nr, key->ptr(), key->length());
  sql_crypt.init(rand_nr);

  return FALSE;
}

bool Item_func_encode::fix_length_and_dec(THD *thd)
{
  max_length=args[0]->max_length;
  base_flags|= ((args[0]->base_flags | args[1]->base_flags) &
                item_base_t::MAYBE_NULL);
  collation.set(&my_charset_bin);
  /* Precompute the seed state if the item is constant. */
  seeded= args[1]->const_item() &&
          (args[1]->result_type() == STRING_RESULT) && !seed();
  return FALSE;
}

String *Item_func_encode::val_str(String *str)
{
  String *res;
  DBUG_ASSERT(fixed());

  if (!(res=args[0]->val_str(str)))
  {
    null_value= 1;
    return NULL;
  }

  if (!seeded && seed())
  {
    null_value= 1;
    return NULL;
  }

  null_value= 0;
  res= copy_if_not_alloced(str, res, res->length());
  crypto_transform(res);
  sql_crypt.reinit();

  return res;
}

void Item_func_encode::crypto_transform(String *res)
{
  sql_crypt.encode((char*) res->ptr(),res->length());
  res->set_charset(&my_charset_bin);
}

void Item_func_decode::crypto_transform(String *res)
{
  sql_crypt.decode((char*) res->ptr(),res->length());
}


String *Item_func_database::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  THD *thd= current_thd;
  if (thd->db.str == NULL)
  {
    null_value= 1;
    return 0;
  }
  else
    str->copy(thd->db.str, thd->db.length, collation.collation);
  null_value= 0;
  return str;
}


String *Item_func_sqlerrm::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  DBUG_ASSERT(!null_value);
  Diagnostics_area::Sql_condition_iterator it=
    current_thd->get_stmt_da()->sql_conditions();
  const Sql_condition *err;
  if ((err= it++))
  {
    str->copy(err->get_message_text(), err->get_message_octet_length(),
              collation.collation);
    return str;
  }
  str->copy(STRING_WITH_LEN("normal, successful completion"),
            collation.collation);
  return str;
}


/**
  @note USER() is replicated correctly if binlog_format=ROW or (as of
  BUG#28086) binlog_format=MIXED, but is incorrectly replicated to ''
  if binlog_format=STATEMENT.
*/

bool Item_func_user::init(const char *user, const char *host)
{
  DBUG_ASSERT(fixed());

  // For system threads (e.g. replication SQL thread) user may be empty
  if (user)
  {
    CHARSET_INFO *cs= str_value.charset();
    size_t res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;

    if (str_value.alloc((uint) res_length))
    {
      null_value=1;
      return TRUE;
    }

    res_length=cs->cset->snprintf(cs, (char*)str_value.ptr(), (uint) res_length,
                                  "%s@%s", user, host);
    str_value.length((uint) res_length);
    str_value.mark_as_const();
  }
  return FALSE;
}


Item *Item_func_sysconst::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
  /*
   During view or prepared statement creation, the item should not
   make use of const_charset_converter as it would imply substitution
   with constant items which is not correct. Functions can have different
   values during view creation and view execution based on context.

   Return the identical item during view creation and prepare.
  */

  if (thd->lex->is_ps_or_view_context_analysis())
    return this;
  return const_charset_converter(thd, tocs, true, fully_qualified_func_name());
}

bool Item_func_sysconst::const_item() const
{
  if (current_thd->lex->is_ps_or_view_context_analysis())
    return false;
  return true;
}

bool Item_func_user::fix_fields(THD *thd, Item **ref)
{
  return (Item_func_sysconst::fix_fields(thd, ref) ||
          init(thd->main_security_ctx.user,
               thd->main_security_ctx.host_or_ip));
}


bool Item_func_current_user::fix_fields(THD *thd, Item **ref)
{
  if (Item_func_sysconst::fix_fields(thd, ref))
    return TRUE;

  Security_context *ctx= context && context->security_ctx
                          ? context->security_ctx : thd->security_ctx;
  return init(ctx->priv_user, ctx->priv_host);
}

bool Item_func_session_user::fix_fields(THD *thd, Item **ref)
{
  if (thd->variables.old_behavior & OLD_MODE_SESSION_USER_IS_USER)
    return Item_func_user::fix_fields(thd, ref);

  if (Item_func_sysconst::fix_fields(thd, ref))
    return TRUE;

  return init(thd->main_security_ctx.priv_user, thd->main_security_ctx.priv_host);
}

bool Item_func_current_role::fix_fields(THD *thd, Item **ref)
{
  if (Item_func_sysconst::fix_fields(thd, ref))
    return 1;

  Security_context *ctx= context && context->security_ctx
                          ? context->security_ctx : thd->security_ctx;
  if (ctx->priv_role[0])
  {
    if (str_value.copy(ctx->priv_role, strlen(ctx->priv_role),
                       collation.collation))
      return 1;
    str_value.mark_as_const();
    null_value= 0;
    base_flags&= ~item_base_t::MAYBE_NULL;
    return 0;
  }
  null_value= 1;
  set_maybe_null();
  return 0;
}

bool Item_func_soundex::fix_length_and_dec(THD *thd)
{
  uint32 char_length= args[0]->max_char_length();
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  set_if_bigger(char_length, 4);
  fix_char_length(char_length);
  return FALSE;
}


/**
  If alpha, map input letter to soundex code.
  If not alpha and remove_garbage is set then skip to next char
  else return 0
*/


static int soundex_toupper(int ch)
{
  return (ch >= 'a' && ch <= 'z') ? ch - 'a' + 'A' : ch;
}


static char get_scode(int wc)
{
  int ch= soundex_toupper(wc);
  if (ch < 'A' || ch > 'Z')
  {
     // Thread extended alfa (country spec)
    return '0';    // as vokal
  }
  return(soundex_map[ch-'A']);
}


static bool my_uni_isalpha(int wc)
{
  /*
    Return true for all Basic Latin letters: a..z A..Z.
    Return true for all Unicode characters with code higher than U+00C0:
    - characters between 'z' and U+00C0 are controls and punctuations.
    - "U+00C0 LATIN CAPITAL LETTER A WITH GRAVE" is the first letter after 'z'.
  */

  return (wc >= 'a' && wc <= 'z') ||
         (wc >= 'A' && wc <= 'Z') ||
         (wc >= 0xC0);
}


String *Item_func_soundex::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(&tmp_value);
  char last_ch,ch;
  CHARSET_INFO *cs= collation.collation;
  my_wc_t wc;
  uint nchars;
  int rc;

  if ((null_value= args[0]->null_value))
    return 0; /* purecov: inspected */

  if (str->alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
    return &tmp_value; /* purecov: inspected */
  str->set_charset(collation.collation);
  char *to= (char *) str->ptr();
  char *to_end= to + str->alloced_length();
  char *from= (char *) res->ptr(), *end= from + res->length();

  for ( ; ; ) /* Skip pre-space */
  {
    if ((rc= cs->mb_wc(&wc, (uchar*) from, (uchar*) end)) <= 0)
      return make_empty_result(str); /* EOL or invalid byte sequence */

    if (rc == 1 && cs->m_ctype)
    {
      /* Single byte letter found */
      if (my_isalpha(cs, *from))
      {
        last_ch= get_scode(*from);       // Code of the first letter
        *to++= soundex_toupper(*from++); // Copy first letter
        break;
      }
      from++;
    }
    else
    {
      from+= rc;
      if (my_uni_isalpha(wc))
      {
        /* Multibyte letter found */
        wc= soundex_toupper(wc);
        last_ch= get_scode(wc);     // Code of the first letter
        if ((rc= cs->wc_mb(wc, (uchar*) to, (uchar*) to_end)) <= 0)
        {
          /* Extra safety - should not really happen */
          DBUG_ASSERT(false);
          return make_empty_result(str);
        }
        to+= rc;
        break;
      }
    }
  }

  /*
     last_ch is now set to the first 'double-letter' check.
     loop on input letters until end of input
  */

  for (nchars= 1 ; ; )
  {
    if ((rc= cs->mb_wc(&wc, (uchar*) from, (uchar*) end)) <= 0)
      break; /* EOL or invalid byte sequence */

    if (rc == 1 && cs->m_ctype)
    {
      if (!my_isalpha(cs, *from++))
        continue;
    }
    else
    {
      from+= rc;
      if (!my_uni_isalpha(wc))
        continue;
    }

    ch= get_scode(wc);
    if ((ch != '0') && (ch != last_ch)) // if not skipped or double
    {
      // letter, copy to output
      if ((rc= cs->wc_mb((my_wc_t) ch, (uchar*) to, (uchar*) to_end)) <= 0)
      {
        // Extra safety - should not really happen
        DBUG_ASSERT(false);
        break;
      }
      to+= rc;
      nchars++;
      last_ch= ch;  // save code of last input letter
    }               // for next double-letter check
  }

  /* Pad up to 4 characters with DIGIT ZERO, if the string is shorter */
  if (nchars < 4)
  {
    uint nbytes= (4 - nchars) * cs->mbminlen;
    cs->fill(to, nbytes, '0');
    to+= nbytes;
  }

  str->length((uint) (to - str->ptr()));
  return str;
}


/**
  Change a number to format '3,333,333,333.000'.

  This should be 'internationalized' sometimes.
*/


/*
  The maximum supported decimal scale:
  38 - starting from 10.2.1
  30 - before 10.2.1
*/

const int FORMAT_MAX_DECIMALS= 38;


bool Item_func_format::fix_length_and_dec(THD *thd)
{
  uint32 char_length= args[0]->type_handler()->Item_decimal_notation_int_digits(args[0]);
  uint dec= FORMAT_MAX_DECIMALS;
  /*
    Format can require one more integer digit if rounding happens:
      FORMAT(9.9,0) -> '10'
    Set need_extra_digit_for_rounding to true by default
    if args[0] has some decimals: if args[1] is not
    a constant, then format can potentially reduce
    the number of decimals and round to the next integer.
  */

  bool need_extra_digit_for_rounding= args[0]->decimals > 0;
  if (args[1]->can_eval_in_optimize())
  {
    Longlong_hybrid tmp= args[1]->to_longlong_hybrid();
    if (!args[1]->null_value)
    {
      dec= tmp.to_uint(FORMAT_MAX_DECIMALS);
      need_extra_digit_for_rounding= (dec < args[0]->decimals);
    }
  }
  /*
    In case of a data type with zero integer digits, e.g. DECIMAL(4,4),
    we'll print at least one integer digit.
  */

  if (need_extra_digit_for_rounding || !char_length)
    char_length++;
  uint32 max_sep_count= (char_length / 3) + (dec ? 1 : 0) + /*sign*/1;
  collation.set(default_charset());
  fix_char_length(char_length + max_sep_count + dec);
  if (arg_count == 3)
    locale= args[2]->basic_const_item() ? args[2]->locale_from_val_str() : NULL;
  else
    locale= &my_locale_en_US; /* Two arguments */
  return FALSE;
}


/**
  @todo
  This needs to be fixed for multi-byte character set where numbers
  are stored in more than one byte
*/


String *Item_func_format::val_str_ascii(String *str)
{
  uint32 str_length;
  /* Number of decimal digits */
  int dec;
  /* Number of characters used to represent the decimals, including '.' */
  uint32 dec_length;
  const MY_LOCALE *lc;
  DBUG_ASSERT(fixed());

  dec= (int) args[1]->val_int();
  if (args[1]->null_value)
  {
    null_value=1;
    return NULL;
  }

  if (!(lc= locale ? locale : args[2]->locale_from_val_str()))
  {
    null_value= 1;
    return 0;
  }

  dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS);
  dec_length= dec ? dec+1 : 0;
  null_value=0;

  if (args[0]->result_type() == DECIMAL_RESULT ||
      args[0]->result_type() == INT_RESULT)
  {
    VDec res(args[0]);
    if ((null_value= res.is_null()))
      return 0; /* purecov: inspected */
    res.to_string_round(str, dec);
    str_length= str->length();
  }
  else
  {
    double nr= args[0]->val_real();
    if ((null_value=args[0]->null_value))
      return 0; /* purecov: inspected */
    nr= my_double_round(nr, (longlong) dec, FALSE, FALSE);
    str->set_fcvt(nr, dec);
    if (!std::isfinite(nr))
      return str;
    str_length=str->length();
  }
  /* We need this test to handle 'nan' and short values */
  if (lc->grouping[0] > 0 &&
      str_length >= dec_length + 1 + lc->grouping[0])
  {
    /* We need space for ',' between each group of digits as well. */
    char buf[2 * FLOATING_POINT_BUFFER];
    int count;
    const char *grouping= lc->grouping;
    char sign_length= *str->ptr() == '-' ? 1 : 0;
    const char *src= str->ptr() + str_length - dec_length - 1;
    const char *src_begin= str->ptr() + sign_length;
    char *dst= buf + sizeof(buf);

    /* Put the fractional part */
    if (dec)
    {
      dst-= (dec + 1);
      *dst= lc->decimal_point;
      memcpy(dst + 1, src + 2, dec);
    }

    /* Put the integer part with grouping */
    for (count= *grouping; src >= src_begin; count--)
    {
      /*
        When *grouping==0x80 (which means "end of grouping")
        count will be initialized to -1 and
        we'll never get into this "if" anymore.
      */

      if (count == 0)
      {
        *--dst= lc->thousand_sep;
        if (grouping[1])
          grouping++;
        count= *grouping;
      }
      DBUG_ASSERT(dst > buf);
      *--dst= *src--;
    }

    if (sign_length) /* Put '-' */
      *--dst= *str->ptr();

    /* Put the rest of the integer part without grouping */
    str->copy(dst, buf + sizeof(buf) - dst, &my_charset_latin1);
  }
  else if (dec_length && lc->decimal_point != '.')
  {
    /*
      For short values without thousands (<1000)
      replace decimal point to localized value.
    */

    DBUG_ASSERT(dec_length <= str_length);
    ((char*) str->ptr())[str_length - dec_length]= lc->decimal_point;
  }
  return str;
}


bool Item_func_elt::fix_length_and_dec(THD *thd)
{
  uint32 char_length= 0;
  decimals=0;

  if (agg_arg_charsets_for_string_result(collation, args + 1, arg_count - 1))
    return TRUE;

  for (uint i= 1 ; i < arg_count ; i++)
  {
    set_if_bigger(char_length, args[i]->max_char_length());
    set_if_bigger(decimals,args[i]->decimals);
  }
  fix_char_length(char_length);
  set_maybe_null(); // NULL if wrong first arg
  return FALSE;
}


double Item_func_elt::val_real()
{
  DBUG_ASSERT(fixed());
  uint tmp;
  null_value=1;
  if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
    return 0.0;
  double result= args[tmp]->val_real();
  null_value= args[tmp]->null_value;
  return result;
}


longlong Item_func_elt::val_int()
{
  DBUG_ASSERT(fixed());
  uint tmp;
  null_value=1;
  if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
    return 0;

  longlong result= args[tmp]->val_int();
  null_value= args[tmp]->null_value;
  return result;
}


String *Item_func_elt::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  uint tmp;
  null_value=1;
  if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
    return NULL;

  String *result= args[tmp]->val_str(str);
  if (result)
    result->set_charset(collation.collation);
  null_value= args[tmp]->null_value;
  return result;
}


bool Item_func_make_set::fix_length_and_dec(THD *thd)
{
  uint32 char_length= arg_count - 2; /* Separators */

  if (agg_arg_charsets_for_string_result(collation, args + 1, arg_count - 1))
    return TRUE;

  for (uint i=1 ; i < arg_count ; i++)
    char_length+= args[i]->max_char_length();
  fix_char_length(char_length);
  return FALSE;
}


String *Item_func_make_set::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  ulonglong bits;
  bool first_found=0;
  Item **ptr=args+1;
  String *result= make_empty_result(str);

  bits=args[0]->val_int();
  if ((null_value=args[0]->null_value))
    return NULL;

  if (arg_count < 65)
    bits &= ((ulonglong) 1 << (arg_count-1))-1;

  for (; bits; bits >>= 1, ptr++)
  {
    if (bits & 1)
    {
      String *res= (*ptr)->val_str(str);
      if (res)                                  // Skip nulls
      {
        if (!first_found)
        {                                       // First argument
          first_found=1;
          if (res->ptr() != str->ptr())
            result=res;                         // Use original string
          else
          {
            if (tmp_str.copy(*res))             // Don't use 'str'
              return make_empty_result(str);
            result= &tmp_str;
          }
        }
        else
        {
          if (result != &tmp_str)
          {                                     // Copy data to tmp_str
            if (tmp_str.alloc(result->length()+res->length()+1) ||
                tmp_str.copy(*result))
              return make_empty_result(str);
            result= &tmp_str;
          }
          if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res))
            return make_empty_result(str);
        }
      }
    }
  }
  return result;
}


void Item_func_char::print(String *str, enum_query_type query_type)
{
  str->append(Item_func_char::func_name_cstring());
  str->append('(');
  print_args(str, 0, query_type);
  if (collation.collation != &my_charset_bin)
  {
    str->append(STRING_WITH_LEN(" using "));
    str->append(collation.collation->cs_name);
  }
  str->append(')');
}


String *Item_func_char::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  str->length(0);
  str->set_charset(collation.collation);
  for (uint i=0 ; i < arg_count ; i++)
  {
    int32 num=(int32) args[i]->val_int();
    if (!args[i]->null_value)
      append_char(str, num);
  }
  str->realloc(str->length());   // Add end 0 (for Purify)
  return check_well_formed_result(str);
}


void Item_func_char::append_char(String *str, int32 num)
{
  char tmp[4];
  if (num & 0xFF000000L)
  {
    mi_int4store(tmp, num);
    str->append(tmp, 4, &my_charset_bin);
  }
  else if (num & 0xFF0000L)
  {
    mi_int3store(tmp, num);
    str->append(tmp, 3, &my_charset_bin);
  }
  else if (num & 0xFF00L)
  {
    mi_int2store(tmp, num);
    str->append(tmp, 2, &my_charset_bin);
  }
  else
  {
    tmp[0]= (char) num;
    str->append(tmp, 1, &my_charset_bin);
  }
}


String *Item_func_chr::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  str->length(0);
  str->set_charset(collation.collation);
  int32 num=(int32) args[0]->val_int();
  if (!args[0]->null_value)
    append_char(str, num);
  else
  {
    null_value= 1;
    return 0;
  }
  str->realloc(str->length());   // Add end 0 (for Purify)
  return check_well_formed_result(str);
}


inline String* alloc_buffer(String *res,String *str,String *tmp_value,
       ulong length)
{
  if (res->alloced_length() < length)
  {
    if (str->alloced_length() >= length)
    {
      (void) str->copy(*res);
      str->length(length);
      return str;
    }
    if (tmp_value->alloc(length))
      return 0;
    (void) tmp_value->copy(*res);
    tmp_value->length(length);
    return tmp_value;
  }
  res->length(length);
  return res;
}


bool Item_func_repeat::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return TRUE;
  DBUG_ASSERT(collation.collation != NULL);
  if (args[1]->can_eval_in_optimize())
  {
    bool neg;
    uint32 length= max_length_for_string(args[1], &neg);
    ulonglong char_length= (ulonglong) args[0]->max_char_length() * length;
    fix_char_length_ulonglong(char_length);
    return false;
  }
  max_length= MAX_BLOB_WIDTH;
  set_maybe_null();
  return false;
}

/**
  Item_func_repeat::str is carefully written to avoid reallocs
  as much as possible at the cost of a local buffer
*/


String *Item_func_repeat::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  uint length,tot_length;
  char *to;
  /* must be longlong to avoid truncation */
  longlong count= args[1]->val_int();
  String *res= args[0]->val_str(str);

  if (args[0]->null_value || args[1]->null_value)
    goto err;    // string and/or delim are null
  null_value= 0;

  if (count <= 0 && (count == 0 || !args[1]->unsigned_flag))
    return make_empty_result(str);

  /* Assumes that the maximum length of a String is < INT_MAX32. */
  /* Bounds check on count:  If this is triggered, we will error. */
  if ((ulonglong) count > INT_MAX32)
    count= INT_MAX32;
  if (count == 1)   // To avoid reallocs
    return res;
  length=res->length();

  // Safe length check
  {
    THD *thd= current_thd;
    if (length > thd->variables.max_allowed_packet / (uint) count)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(), thd->variables.max_allowed_packet);
      goto err;
    }
  }
  tot_length= length*(uint) count;
  if (!(res= alloc_buffer(res,str,&tmp_value,tot_length)))
    goto err;

  to=(char*) res->ptr()+length;
  while (--count)
  {
    memcpy(to,res->ptr(),length);
    to+=length;
  }
  return (res);

err:
  null_value=1;
  return 0;
}


bool Item_func_space::fix_length_and_dec(THD *thd)
{
  collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
  if (args[0]->can_eval_in_optimize())
  {
    bool neg;
    fix_char_length_ulonglong(max_length_for_string(args[0], &neg));
    return false;
  }
  max_length= MAX_BLOB_WIDTH;
  set_maybe_null();
  return false;
}


String *Item_func_space::val_str(String *str)
{
  uint tot_length;
  longlong count= args[0]->val_int();
  CHARSET_INFO *cs= collation.collation;

  if (args[0]->null_value)
    goto err;    // string and/or delim are null
  null_value= 0;

  if (count <= 0 && (count == 0 || !args[0]->unsigned_flag))
    return make_empty_result(str);
  /*
   Assumes that the maximum length of a String is < INT_MAX32.
   Bounds check on count:  If this is triggered, we will error.
  */

  if ((ulonglong) count > INT_MAX32)
    count= INT_MAX32;

  // Safe length check
  tot_length= (uint) count * cs->mbminlen;
  {
    THD *thd= current_thd;
    if (tot_length > thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(),
                          thd->variables.max_allowed_packet);
      goto err;
    }
  }
  if (str->alloc(tot_length))
    goto err;
  str->length(tot_length);
  str->set_charset(cs);
  cs->fill((char*) str->ptr(), tot_length, ' ');
  return str;

err:
  null_value= 1;
  return 0;
}


bool Item_func_binlog_gtid_pos::fix_length_and_dec(THD *thd)
{
  collation.set(system_charset_info_for_i_s);
  max_length= MAX_BLOB_WIDTH;
  set_maybe_null();
  return FALSE;
}


String *Item_func_binlog_gtid_pos::val_str(String *str)
{
  DBUG_ASSERT(fixed());
#ifndef HAVE_REPLICATION
  null_value= 0;
  str->copy("", 0, system_charset_info_for_i_s);
  return str;
#else
  String name_str, *name;
  longlong pos;

  if (opt_binlog_engine_hton)
  {
    my_error(ER_NOT_AVAILABLE_WITH_ENGINE_BINLOG, MYF(0), "BINLOG_GTID_POS()");
    goto err;
  }

  name= args[0]->val_str(&name_str);
  pos= args[1]->val_int();

  if (args[0]->null_value || args[1]->null_value)
    goto err;

  if (pos < 0 || (ulonglong) pos > UINT_MAX32)
    goto err;

  if (gtid_state_from_binlog_pos(name->c_ptr_safe(), (uint32)pos, str))
    goto err;
  null_value= 0;
  return str;

err:
  null_value= 1;
  return NULL;
#endif  /* !HAVE_REPLICATION */
}


static String *default_pad_str(String *pad_str, CHARSET_INFO *collation)
{
  pad_str->set_charset(collation);
  pad_str->length(0);
  pad_str->append(" ", 1);
  return pad_str;
}

bool Item_func_pad::fix_length_and_dec(THD *thd)
{
  if (arg_count == 3)
  {
    String *str;
    if (!args[2]->basic_const_item() || !(str= args[2]->val_str(&pad_str)) ||
        !str->length())
      set_maybe_null();
    // Handle character set for args[0] and args[2].
    if (agg_arg_charsets_for_string_result(collation, &args[0], 2, 2))
      return TRUE;
  }
  else
  {
    if (agg_arg_charsets_for_string_result(collation, &args[0], 1, 1))
      return TRUE;
    default_pad_str(&pad_str, collation.collation);
  }

  DBUG_ASSERT(collation.collation->mbmaxlen > 0);
  if (args[1]->can_eval_in_optimize())
  {
    bool neg;
    fix_char_length_ulonglong(max_length_for_string(args[1], &neg));
    if (neg)
      set_maybe_null();
    return false;
  }
  max_length= MAX_BLOB_WIDTH;
  set_maybe_null();
  return false;
}


/*
  PAD(expr,length,' ')
  removes argument's soft dependency on PAD_CHAR_TO_FULL_LENGTH if the result
  is longer than the argument's maximum possible length.
*/

Sql_mode_dependency Item_func_rpad::value_depends_on_sql_mode() const
{
  DBUG_ASSERT(fixed());
  DBUG_ASSERT(arg_count >= 2);
  if (!args[1]->value_depends_on_sql_mode_const_item() ||
          (arg_count == 3 && !args[2]->value_depends_on_sql_mode_const_item()))
    return Item_func::value_depends_on_sql_mode();
  Longlong_hybrid len= args[1]->to_longlong_hybrid();
  if (args[1]->null_value || len.neg())
    return Sql_mode_dependency();                  // will return NULL
  if (len.abs() > 0 && len.abs() < args[0]->max_char_length())
    return Item_func::value_depends_on_sql_mode();
  StringBuffer<64> padstrbuf;
  String *padstr= arg_count == 3 ? args[2]->val_str(&padstrbuf) :
                               default_pad_str(&padstrbuf, collation.collation);
  if (!padstr || !padstr->length())
    return Sql_mode_dependency();                  // will return NULL
  if (padstr->lengthsp() != 0)
    return Item_func::value_depends_on_sql_mode(); // will pad not only spaces
  // RPAD(expr, length, ' ')  -- with a long enough length
  return ((args[0]->value_depends_on_sql_mode() |
           args[1]->value_depends_on_sql_mode()) &
          Sql_mode_dependency(~0, ~MODE_PAD_CHAR_TO_FULL_LENGTH)).
         soft_to_hard();
}



String *Item_func_rpad::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  uint32 res_byte_length,res_char_length,pad_char_length,pad_byte_length;
  char *to;
  const char *ptr_pad;
  /* must be longlong to avoid truncation */
  longlong count= args[1]->val_int();
  longlong byte_count;
  String *res= args[0]->val_str(str);
  String *rpad= arg_count == 2 ? &pad_str : args[2]->val_str(&pad_str);

  if (!res || args[1]->null_value || !rpad ||
      ((count < 0) && !args[1]->unsigned_flag))
    goto err;

  null_value=0;

  if (count == 0)
    return make_empty_result(str);

  /* Assumes that the maximum length of a String is < INT_MAX32. */
  /* Set here so that rest of code sees out-of-bound value as such. */
  if ((ulonglong) count > INT_MAX32)
    count= INT_MAX32;
  /*
    There is one exception not handled (intentionally) by the character set
    aggregation code. If one string is strong side and is binary, and
    another one is weak side and is a multi-byte character string,
    then we need to operate on the second string in terms on bytes when
    calling ::numchars() and ::charpos(), rather than in terms of characters.
    Lets substitute its character set to binary.
  */

  if (collation.collation == &my_charset_bin)
  {
    res->set_charset(&my_charset_bin);
    rpad->set_charset(&my_charset_bin);
  }

  if (count <= (res_char_length= res->numchars()))
  {                                             // String to pad is big enough
    int len= res->charpos((int) count);
    res= copy_if_not_alloced(str, res, len);
    res->length(len);                           // Shorten result if longer
    return (res);
  }

  byte_count= count * collation.collation->mbmaxlen;
  {
    THD *thd= current_thd;
    if ((ulonglong) byte_count > thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(), thd->variables.max_allowed_packet);
      goto err;
    }
  }

  if (arg_count == 3)
  {
    if (args[2]->null_value || !(pad_char_length= rpad->numchars()))
      goto err;
  }
  else
    pad_char_length= 1; // Implicit space

  res_byte_length= res->length(); /* Must be done before alloc_buffer */
  if (!(res= alloc_buffer(res,str,&tmp_value, (ulong) byte_count)))
    goto err;

  to= (char*) res->ptr()+res_byte_length;
  ptr_pad=rpad->ptr();
  pad_byte_length= rpad->length();
  count-= res_char_length;
  for ( ; (uint32) count > pad_char_length; count-= pad_char_length)
  {
    memcpy(to,ptr_pad,pad_byte_length);
    to+= pad_byte_length;
  }
  if (count)
  {
    pad_byte_length= rpad->charpos((int) count);
    memcpy(to,ptr_pad,(size_t) pad_byte_length);
    to+= pad_byte_length;
  }
  res->length((uint) (to- (char*) res->ptr()));
  return (res);

 err:
  null_value=1;
  return 0;
}


String *Item_func_lpad::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  uint32 res_char_length,pad_char_length;
  /* must be longlong to avoid truncation */
  longlong count= args[1]->val_int();
  longlong byte_count;
  String *res= args[0]->val_str(&tmp_value);
  String *pad= arg_count == 2 ? &pad_str : args[2]->val_str(&pad_str);

  if (!res || args[1]->null_value || !pad ||
      ((count < 0) && !args[1]->unsigned_flag))
    goto err;

  null_value=0;

  if (count == 0)
    return make_empty_result(str);

  /* Assumes that the maximum length of a String is < INT_MAX32. */
  /* Set here so that rest of code sees out-of-bound value as such. */
  if ((ulonglong) count > INT_MAX32)
    count= INT_MAX32;

  /*
    There is one exception not handled (intentionally) by the character set
    aggregation code. If one string is strong side and is binary, and
    another one is weak side and is a multi-byte character string,
    then we need to operate on the second string in terms on bytes when
    calling ::numchars() and ::charpos(), rather than in terms of characters.
    Lets substitute its character set to binary.
  */

  if (collation.collation == &my_charset_bin)
  {
    res->set_charset(&my_charset_bin);
    pad->set_charset(&my_charset_bin);
  }

  res_char_length= res->numchars();

  if (count <= res_char_length)
  {
    int len= res->charpos((int) count);
    res= copy_if_not_alloced(str, res, len);
    res->length(len);
    return res;
  }

  byte_count= count * collation.collation->mbmaxlen;

  {
    THD *thd= current_thd;
    if ((ulonglong) byte_count > thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(), thd->variables.max_allowed_packet);
      goto err;
    }
  }

  if (str->alloc((uint32) byte_count))
    goto err;

  if (arg_count == 3)
  {
    if (args[2]->null_value || !(pad_char_length= pad->numchars()))
      goto err;
  }
  else
    pad_char_length= 1; // Implicit space

  str->length(0);
  str->set_charset(collation.collation);
  count-= res_char_length;
  while (count >= pad_char_length)
  {
    str->append(*pad);
    count-= pad_char_length;
  }
  if (count > 0)
    str->append(pad->ptr(), pad->charpos((int) count), collation.collation);

  str->append(*res);
  null_value= 0;
  return str;

err:
  null_value= 1;
  return 0;
}


String *Item_func_conv::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(str);
  char *endptr,ans[66],*ptr;
  longlong dec;
  int from_base= (int) args[1]->val_int();
  int to_base= (int) args[2]->val_int();
  int err;

  // Note that abs(INT_MIN) is undefined.
  if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
      from_base == INT_MIN || to_base == INT_MIN ||
      abs(to_base) > 62 || abs(to_base) < 2 ||
      abs(from_base) > 62 || abs(from_base) < 2 || !(res->length()))
  {
    null_value= 1;
    return NULL;
  }
  null_value= 0;
  unsigned_flag= !(from_base < 0);

  if (args[0]->field_type() == MYSQL_TYPE_BIT)
  {
    /*
     Special case: The string representation of BIT doesn't resemble the
     decimal representation, so we shouldn't change it to string and then to
     decimal.
    */

    dec= args[0]->val_int();
  }
  else
  {
    if (from_base < 0)
      dec= res->charset()->strntoll(res->ptr(), res->length(),
                                    -from_base, &endptr, &err);
    else
      dec= (longlong) res->charset()->strntoull(res->ptr(), res->length(),
                                                from_base, &endptr, &err);
  }

  uint dummy_errors;
  if (!(ptr= longlong2str(dec, ans, to_base)) ||
      (collation.collation->state & MY_CS_NONASCII) ?
       str->copy(ans, (uint32)  (ptr - ans), &my_charset_latin1,
                 collation.collation, &dummy_errors) :
       str->copy(ans, (uint32) (ptr - ans), collation.collation))
  {
    null_value= 1;
    return NULL;
  }
  return str;
}


/*
  This function is needed as Item_func_conc_charset stores cached values
  in str_value.
*/


int Item_func_conv_charset::save_in_field(Field *field, bool no_conversions)
{
  String *result;
  CHARSET_INFO *cs= collation.collation;

  result= val_str(&str_value);
  if (null_value)
    return set_field_to_null_with_conversions(field, no_conversions);

  /* NOTE: If null_value == FALSE, "result" must be not NULL.  */
  field->set_notnull();
  int error= field->store(result->ptr(),result->length(),cs);
  return error;
}


String *Item_func_conv_charset::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  if (use_cached_value)
    return null_value ? 0 : &str_value;
  String *arg= args[0]->val_str(&tmp_value);
  String_copier_for_item copier(current_thd);
  return ((null_value= args[0]->null_value ||
                       copier.copy_with_warn(collation.collation, str,
                                             arg->charset(), arg->ptr(),
                                             arg->length(), arg->length()))) ?
    0 : str;
}

bool Item_func_conv_charset::fix_length_and_dec(THD *thd)
{
  DBUG_ASSERT(collation.derivation == DERIVATION_CAST ||
              (collation.derivation == DERIVATION_IMPLICIT &&
               collation.collation == &my_charset_bin));
  fix_char_length(args[0]->max_char_length());
  return FALSE;
}

void Item_func_conv_charset::print(String *str, enum_query_type query_type)
{
  str->append(STRING_WITH_LEN("convert("));
  args[0]->print(str, query_type);
  str->append(STRING_WITH_LEN(" using "));
  str->append(collation.collation->cs_name);
  str->append(')');
}

String *Item_func_set_collation::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  str=args[0]->val_str(str);
  if ((null_value=args[0]->null_value))
    return 0;
  /*
    Let SCS be the character set of the source - args[0].
    Let TCS be the character set of the target - i.e. the character set
    of the collation specified in the COLLATE clause.

    It's OK to return SQL NULL if SCS is not equal to TCS.
    This is possible on the explicit NULL or expressions derived from
    the explicit NULL:
      SELECT NULL COLLATE utf8mb4_general_ci;
      SELECT COALESCE(NULL) COLLATE utf8mb4_general_ci;

    But for a non-NULL result SCS and TCS must be compatible:
    1. Either SCS==TCS
    2. Or SCS can be reinterpreted to TCS.
       This scenario is possible when args[0] is numeric and TCS->mbmaxlen==1.

    If SCS and TCS are not compatible here, then something went wrong during
    fix_fields(), e.g. an Item_func_conv_charset was not added two wrap args[0].
  */

  DBUG_ASSERT(my_charset_same(args[0]->collation.collation,
                              collation.collation) ||
              (args[0]->collation.repertoire == MY_REPERTOIRE_ASCII &&
               !(collation.collation->state & MY_CS_NONASCII)));
  str->set_charset(collation.collation);
  return str;
}

bool Item_func_set_collation::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1) ||
      collation.merge_collation(thd, thd->variables.character_set_collations,
                                m_set_collation,
                                args[0]->collation.repertoire,
                                with_param() &&
                                thd->lex->is_ps_or_view_context_analysis()))
    return true;
  ulonglong max_char_length= (ulonglong) args[0]->max_char_length();
  fix_char_length_ulonglong(max_char_length);

  return FALSE;
}


bool Item_func_set_collation::eq(const Item *item,
                                 const Eq_config &config) const
{
  return Item_func::eq(item, config) &&
         collation.collation == item->collation.collation;
}


void Item_func_set_collation::print(String *str, enum_query_type query_type)
{
  args[0]->print_parenthesised(str, query_type, precedence());
  str->append(STRING_WITH_LEN(" collate "));
  str->append(m_set_collation.collation_name_for_show());
}

String *Item_func_charset::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  uint dummy_errors;

  null_value= 0;
  str->copy(m_cached_charset_info.str, m_cached_charset_info.length,
     &my_charset_latin1, collation.collation, &dummy_errors);
  return str;
}

String *Item_func_collation::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  uint dummy_errors;
  CHARSET_INFO *cs= args[0]->charset_for_protocol();

  null_value= 0;
  str->copy(cs->coll_name.str, cs->coll_name.length, &my_charset_latin1,
            collation.collation, &dummy_errors);
  return str;
}


bool Item_func_weight_string::fix_length_and_dec(THD *thd)
{
  CHARSET_INFO *cs= args[0]->collation.collation;
  collation.set(&my_charset_bin, args[0]->collation.derivation);
  weigth_flags= my_strxfrm_flag_normalize(cs, weigth_flags);
  /*
    Use result_length if it was given explicitly in constructor,
    otherwise calculate max_length using argument's max_length
    and "nweights".
  */

  if (!(max_length= result_length))
  {
    size_t char_length;
    char_length= ((cs->state & MY_CS_STRNXFRM_BAD_NWEIGHTS) || !nweights) ?
                 args[0]->max_char_length() : nweights *
                 my_count_bits_uint32(cs->levels_for_order);
    max_length= (uint32) cs->strnxfrmlen(char_length * cs->mbmaxlen);
  }
  set_maybe_null();
  return FALSE;
}


/* Return a weight_string according to collation */
String *Item_func_weight_string::val_str(String *str)
{
  String *res;
  CHARSET_INFO *cs= args[0]->collation.collation;
  size_t tmp_length, frm_length;
  DBUG_ASSERT(fixed());

  if (args[0]->result_type() != STRING_RESULT ||
      !(res= args[0]->val_str(&tmp_value)))
    goto nl;

  /*
    Use result_length if it was given in constructor
    explicitly, otherwise calculate result length
    from argument and "nweights".
  */

  if (!(tmp_length= result_length))
  {
    size_t char_length;
    if (cs->state & MY_CS_STRNXFRM_BAD_NWEIGHTS)
    {
      /*
        latin2_czech_cs and cp1250_czech_cs do not support
        the "nweights" limit in strnxfrm(). Use the full length.
      */

      char_length= res->length();
    }
    else
    {
      /*
        If we don't need to pad the result with spaces, then it should be
        OK to calculate character length of the argument approximately:
        "res->length() / cs->mbminlen" can return a number that is
        bigger than the real number of characters in the string, so
        we'll allocate a little bit more memory but avoid calling
        the slow res->numchars().
        In case if we do need to pad with spaces, we call res->numchars()
        to know the true number of characters.
      */

      if (!(char_length= nweights))
        char_length= (weigth_flags & MY_STRXFRM_PAD_WITH_SPACE) ?
                      res->numchars() : (res->length() / cs->mbminlen);
    }
    tmp_length= cs->strnxfrmlen(char_length * cs->mbmaxlen);
  }

  {
    THD *thd= current_thd;
    if (tmp_length > current_thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(),
                          thd->variables.max_allowed_packet);
      goto nl;
    }
  }

  if (str->alloc(tmp_length))
    goto nl;

  frm_length= cs->strnxfrm((char*) str->ptr(), tmp_length,
                           nweights ? nweights : (uint) tmp_length,
                           res->ptr(), res->length(),
                           weigth_flags).m_result_length;
  DBUG_ASSERT(frm_length <= tmp_length);

  str->set_charset(&my_charset_bin);
  str->length(frm_length);
  null_value= 0;
  return str;

nl:
  null_value= 1;
  return 0;
}


void Item_func_weight_string::print(String *str, enum_query_type query_type)
{
  str->append(func_name_cstring());
  str->append('(');
  args[0]->print(str, query_type);
  str->append(',');
  str->append_ulonglong(result_length);
  str->append(',');
  str->append_ulonglong(nweights);
  str->append(',');
  str->append_ulonglong(weigth_flags);
  str->append(')');
}


String *Item_func_hex::val_str_ascii_from_val_real(String *str)
{
  ulonglong dec;
  double val= args[0]->val_real();
  if ((null_value= args[0]->null_value))
    return 0;
  if ((val <= (double) LONGLONG_MIN) ||
      (val >= (double) (ulonglong) ULONGLONG_MAX))
    dec= ULONGLONG_MAX;
  else if (val < 0)
    dec= (ulonglong) (longlong) (val - 0.5);
  else
    dec= (ulonglong) (val + 0.5);
  return str->set_hex(dec) ? make_empty_result(str) : str;
}


String *Item_func_hex::val_str_ascii_from_val_str(String *str)
{
  DBUG_ASSERT(&tmp_value != str);
  String *res= args[0]->val_str(&tmp_value);
  THD *thd= current_thd;

  if ((null_value= (res == NULL)))
    return NULL;

  if (res->length()*2 > thd->variables.max_allowed_packet)
  {
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                        ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                        func_name(), thd->variables.max_allowed_packet);
    null_value= true;
    return NULL;
  }

  return str->set_hex(res->ptr(), res->length()) ? make_empty_result(str) : str;
}


String *Item_func_hex::val_str_ascii_from_val_int(String *str)
{
  ulonglong dec= (ulonglong) args[0]->val_int();
  if ((null_value= args[0]->null_value))
    return 0;
  return str->set_hex(dec) ? make_empty_result(str) : str;
}


  /** Convert given hex string to a binary string. */

String *Item_func_unhex::val_str(String *str)
{
  const char *from, *end;
  char *to;
  String *res;
  uint length;
  DBUG_ASSERT(fixed());

  res= args[0]->val_str(&tmp_value);
  if (!res || str->alloc(length= (1+res->length())/2))
  {
    null_value=1;
    return 0;
  }

  from= res->ptr();
  null_value= 0;
  str->set_charset(&my_charset_bin);
  str->length(length);
  to= (char*) str->ptr();
  if (res->length() % 2)
  {
    int hex_char;
    *to++= hex_char= hexchar_to_int(*from++);
    if ((null_value= (hex_char == -1)))
      return 0;
  }
  for (end=res->ptr()+res->length(); from < end ; from+=2, to++)
  {
    int hex_char1, hex_char2;
    hex_char1= hexchar_to_int(from[0]);
    hex_char2= hexchar_to_int(from[1]);
    if ((null_value= (hex_char1 == -1 || hex_char2 == -1)))
      return 0;
    *to= (char) ((hex_char1 << 4) | hex_char2);
  }
  return str;
}


#ifndef DBUG_OFF
String *Item_func_like_range::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  longlong nbytes= args[1]->val_int();
  String *res= args[0]->val_str(str);
  size_t min_len, max_len;
  CHARSET_INFO *cs= collation.collation;

  if (!res || args[0]->null_value || args[1]->null_value ||
      nbytes < 0 || nbytes > MAX_BLOB_WIDTH ||
      min_str.alloc((size_t)nbytes) || max_str.alloc((size_t)nbytes))
    goto err;
  null_value=0;

  if (cs->like_range(res->ptr(), res->length(),
                     '\\', '_', '%', (size_t)nbytes,
                     (char*) min_str.ptr(), (char*) max_str.ptr(),
                     &min_len, &max_len))
    goto err;

  min_str.set_charset(collation.collation);
  max_str.set_charset(collation.collation);
  min_str.length(min_len);
  max_str.length(max_len);

  return is_min ? &min_str : &max_str;

err:
  null_value= 1;
  return 0;
}
#endif


void Item_func_binary::print(String *str, enum_query_type query_type)
{
  str->append(STRING_WITH_LEN("cast("));
  args[0]->print(str, query_type);
  str->append(STRING_WITH_LEN(" as binary)"));
}


#include <my_dir.h>    // For my_stat

String *Item_load_file::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *file_name;
  File file;
  MY_STAT stat_info;
  char path[FN_REFLEN];
  ulonglong file_size;
  DBUG_ENTER("load_file");

  if (!(file_name= args[0]->val_str(str))
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      || !(current_thd->security_ctx->master_access & FILE_ACL)
#endif
      )
    goto err;

  (void) fn_format(path, file_name->c_ptr_safe(), mysql_real_data_home, "",
     MY_RELATIVE_PATH | MY_UNPACK_FILENAME);

  /* Read only allowed from within dir specified by secure_file_priv */
  if (!is_secure_file_path(path))
    goto err;

  if (!mysql_file_stat(key_file_loadfile, path, &stat_info, MYF(0)))
    goto err;

  if (!(stat_info.st_mode & S_IROTH))
  {
    /* my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), file_name->c_ptr()); */
    goto err;
  }
  file_size= stat_info.st_size;

  {
    THD *thd= current_thd;
    if (file_size >= thd->variables.max_allowed_packet)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                          func_name(), thd->variables.max_allowed_packet);
      goto err;
    }
  }
  if (tmp_value.alloc((ulong)file_size))
    goto err;
  if ((file= mysql_file_open(key_file_loadfile,
                             file_name->ptr(), O_RDONLY, MYF(0))) < 0)
    goto err;
  if (mysql_file_read(file, (uchar*) tmp_value.ptr(), (size_t)stat_info.st_size,
                      MYF(MY_NABP)))
  {
    mysql_file_close(file, MYF(0));
    goto err;
  }
  tmp_value.length((uint32)stat_info.st_size);
  mysql_file_close(file, MYF(0));
  null_value = 0;
  DBUG_RETURN(&tmp_value);

err:
  null_value = 1;
  DBUG_RETURN(0);
}


String* Item_func_export_set::val_str(String* str)
{
  DBUG_ASSERT(fixed());
  String yes_buf, no_buf, sep_buf;
  const ulonglong the_set = (ulonglong) args[0]->val_int();
  const String *yes= args[1]->val_str(&yes_buf);
  const String *no= args[2]->val_str(&no_buf);
  const String *sep= NULL;

  uint num_set_values = 64;
  str->length(0);
  str->set_charset(collation.collation);

  /* Check if some argument is a NULL value */
  if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
  {
    null_value= true;
    return NULL;
  }
  /*
    Arg count can only be 3, 4 or 5 here. This is guaranteed from the
    grammar for EXPORT_SET()
  */

  switch(arg_count) {
  case 5:
    num_set_values = (uint) args[4]->val_int();
    if (num_set_values > 64)
      num_set_values=64;
    if (args[4]->null_value)
    {
      null_value= true;
      return NULL;
    }
    /* Fall through */
  case 4:
    if (!(sep = args[3]->val_str(&sep_buf))) // Only true if NULL
    {
      null_value= true;
      return NULL;
    }
    break;
  case 3:
    {
      /* errors is not checked - assume "," can always be converted */
      uint errors;
      sep_buf.copy(STRING_WITH_LEN(","), &my_charset_bin,
                   collation.collation, &errors);
      sep = &sep_buf;
    }
    break;
  default:
    DBUG_ASSERT(0); // cannot happen
  }
  null_value= false;

  THD *thd= current_thd;
  const ulong max_allowed_packet= thd->variables.max_allowed_packet;
  const uint num_separators= num_set_values > 0 ? num_set_values - 1 : 0;
  const ulonglong max_total_length=
    num_set_values * MY_MAX(yes->length(), no->length()) +
    num_separators * sep->length();

  if (unlikely(max_total_length > max_allowed_packet))
  {
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                        ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                        func_name(), max_allowed_packet);
    null_value= true;
    return NULL;
  }

  uint ix;
  ulonglong mask;
  for (ix= 0, mask=0x1; ix < num_set_values; ++ix, mask = (mask << 1))
  {
    if (the_set & mask)
      str->append(*yes);
    else
      str->append(*no);
    if (ix != num_separators)
      str->append(*sep);
  }
  return str;
}

bool Item_func_export_set::fix_length_and_dec(THD *thd)
{
  uint32 length= MY_MAX(args[1]->max_char_length(), args[2]->max_char_length());
  uint32 sep_length= (arg_count > 3 ? args[3]->max_char_length() : 1);

  if (agg_arg_charsets_for_string_result(collation,
                                         args + 1, MY_MIN(4, arg_count) - 1))
    return TRUE;
  fix_char_length(length * 64 + sep_length * 63);
  return FALSE;
}


#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7))

/**
  QUOTE() function returns argument string in single quotes suitable for
  using in a SQL statement.

  Adds a \\ before all characters that needs to be escaped in a SQL string.
  We also escape '^Z' (END-OF-FILE in windows) to avoid problems when
  running commands from a file in windows.

  This function is very useful when you want to generate SQL statements.

  @note
    QUOTE(NULL) returns the string 'NULL' (4 letters, without quotes).

  @retval
    str    Quoted string
  @retval
    NULL    Out of memory.
*/


String *Item_func_quote::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  /*
    Bit mask that has 1 for set for the position of the following characters:
    0, \, ' and ^Z
  */


  static uchar escmask[32]=
  {
    0x01, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  };

  ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
  char *from, *to, *end, *start;
  String *arg= args[0]->val_str(&tmp_value);
  size_t arg_length, new_length;
  if (!arg)     // Null argument
  {
    /* Return the string 'NULL' */
    str->copy(STRING_WITH_LEN("NULL"), collation.collation);
    null_value= 0;
    return str;
  }

  arg_length= arg->length();

  if (collation.collation->mbmaxlen == 1)
  {
    new_length= arg_length + 2; /* for beginning and ending ' signs */
    for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++)
      new_length+= get_esc_bit(escmask, (uchar) *from);
    if (new_length > max_allowed_packet)
      goto toolong;
  }
  else
  {
    new_length= (arg_length * 2) +  /* For string characters */
                (2 * collation.collation->mbmaxlen); /* For quotes */
    set_if_smaller(new_length, max_allowed_packet);
  }

  if (str->alloc(new_length))
    goto null;

  if (collation.collation->mbmaxlen > 1)
  {
    CHARSET_INFO *cs= collation.collation;
    int mblen;
    uchar *to_end;
    to= (char*) str->ptr();
    to_end= (uchar*) to + new_length;

    /* Put leading quote */
    if ((mblen= cs->wc_mb('\'', (uchar *) to, to_end)) <= 0)
      goto toolong;
    to+= mblen;

    for (start= (char*) arg->ptr(), end= start + arg_length; start < end; )
    {
      my_wc_t wc;
      bool escape;
      if ((mblen= cs->mb_wc(&wc, (uchar*) start, (uchar*) end)) <= 0)
        goto null;
      start+= mblen;
      switch (wc) {
        case 0:      escape= 1; wc= '0'; break;
        case '\032': escape= 1; wc= 'Z'; break;
        case '\'':   escape= 1; break;
        case '\\':   escape= 1; break;
        default:     escape= 0; break;
      }
      if (escape)
      {
        if ((mblen= cs->wc_mb('\\', (uchar*) to, to_end)) <= 0)
          goto toolong;
        to+= mblen;
      }
      if ((mblen= cs->wc_mb(wc, (uchar*) to, to_end)) <= 0)
        goto toolong;
      to+= mblen;
    }

    /* Put trailing quote */
    if ((mblen= cs->wc_mb('\'', (uchar *) to, to_end)) <= 0)
      goto toolong;
    to+= mblen;
    new_length= (uint)(to - str->ptr());
    goto ret;
  }

  /*
    We replace characters from the end to the beginning
  */

  to= (char*) str->ptr() + new_length - 1;
  *to--= '\'';
  for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--)
  {
    /*
      We can't use the bitmask here as we want to replace \O and ^Z with 0
      and Z
    */

    switch (*end)  {
    case 0:
      *to--= '0';
      *to=   '\\';
      break;
    case '\032':
      *to--= 'Z';
      *to=   '\\';
      break;
    case '\'':
    case '\\':
      *to--= *end;
      *to=   '\\';
      break;
    default:
      *to= *end;
      break;
    }
  }
  *to= '\'';

ret:
  str->length(new_length);
  str->set_charset(collation.collation);
  null_value= 0;
  return str;

toolong:
  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
                      ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                      ER_THD(current_thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
                      func_name(), max_allowed_packet);
null:
  null_value= 1;
  return 0;
}

longlong Item_func_uncompressed_length::val_int()
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(&value);
  if (!res)
  {
    null_value=1;
    return 0; /* purecov: inspected */
  }
  null_value=0;
  if (res->is_empty()) return 0;

  /*
    If length is <= 4 bytes, data is corrupt. This is the best we can do
    to detect garbage input without decompressing it.
  */

  if (res->length() <= 4)
  {
    THD *thd= current_thd;
    push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
                 ER_ZLIB_Z_DATA_ERROR,
                 ER_THD(thd, ER_ZLIB_Z_DATA_ERROR));
    null_value= 1;
    return 0;
  }

 /*
    res->ptr() using is safe because we have tested that string is at least
    5 bytes long.
    res->c_ptr() is not used because:
      - we do not need \0 terminated string to get first 4 bytes
      - c_ptr() tests symbol after string end (uninitialized memory) which
        confuse valgrind
  */

  return uint4korr(res->ptr()) & 0x3FFFFFFF;
}

longlong Item_func_crc32::val_int()
{
  DBUG_ASSERT(fixed());
  DBUG_ASSERT(arg_count == 1 || arg_count == 2);
  String *res;
  longlong crc;
  if (arg_count > 1)
  {
    crc= args[0]->val_int();
    null_value= args[0]->null_value;
    if (null_value)
      return 0;
    res= args[1]->val_str(&value);
  }
  else
  {
    crc= 0;
    null_value= 0;
    res= args[0]->val_str(&value);
  }

  if (!res)
  {
    null_value=1;
    return 0; /* purecov: inspected */
  }

  return static_cast<longlong>
    (ulonglong{crc_func(uint32_t(crc), res->ptr(), res->length())});
}

static bool check_xxh_arg_type(Item *arg, const LEX_CSTRING &func_name)
{
  const Type_handler *handler= arg->type_handler();
  if (handler == &type_handler_null ||
      dynamic_cast<const Type_handler_longstr *>(handler) != nullptr)
    return false;

  my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
           handler->name().ptr(), func_name.str);
  return true;
}


bool Item_func_xxh32::check_arguments() const
{
  return check_xxh_arg_type(args[0], func_name_cstring());
}

longlong Item_func_xxh32::val_int()
{
  DBUG_ASSERT(fixed());
  DBUG_ASSERT(arg_count == 1);

  Hasher hasher(my_hasher_xxh32());
  args[0]->hash_val_str(&hasher, &buffer);
  ulonglong h= hasher.finalize();
  return (null_value= args[0]->null_value) ? 0 : static_cast<longlong>(h);
}

bool Item_func_xxh3::check_arguments() const
{
  return check_xxh_arg_type(args[0], func_name_cstring());
}

longlong Item_func_xxh3::val_int()
{
  DBUG_ASSERT(fixed());
  DBUG_ASSERT(arg_count == 1);

  Hasher hasher(my_hasher_xxh3());
  args[0]->hash_val_str(&hasher, &buffer);
  ulonglong h= hasher.finalize();
  return (null_value= args[0]->null_value) ? 0 : static_cast<longlong>(h);
}

#ifdef HAVE_COMPRESS
#include "zlib.h"

String *Item_func_compress::val_str(String *str)
{
  int err= Z_OK, code;
  size_t new_size;
  String *res;
  Byte *body;
  char *tmp, *last_char;
  DBUG_ASSERT(fixed());

  if (!(res= args[0]->val_str(&tmp_value)))
  {
    null_value= 1;
    return 0;
  }
  null_value= 0;
  if (res->is_empty()) return res;

  /*
    Citation from zlib.h (comment for compress function):

    Compresses the source buffer into the destination buffer.  sourceLen is
    the byte length of the source buffer. Upon entry, destLen is the total
    size of the destination buffer, which must be at least 0.1% larger than
    sourceLen plus 12 bytes.
    We assume here that the buffer can't grow more than .25 %.
  */

  new_size= res->length() + res->length() / 5 + 12;

  // Check new_size overflow: new_size <= res->length()
  if (((uint32) (new_size+5) <= res->length()) ||
      str->alloc((uint32) new_size + 4 + 1))
  {
    null_value= 1;
    return 0;
  }

  body= ((Byte*)str->ptr()) + 4;

  // As far as we have checked res->is_empty() we can use ptr()
  if ((err= my_compress_buffer(body, &new_size, (const uchar *)res->ptr(),
                               res->length())) != Z_OK)
  {
    THD *thd= current_thd;
    code= err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_BUF_ERROR;
    push_warning(thd, Sql_condition::WARN_LEVEL_WARN, code,
                 ER_THD(thd, code));
    null_value= 1;
    return 0;
  }

  tmp= (char*) str->ptr(); // int4store is a macro; avoid side effects
  int4store(tmp, res->length() & 0x3FFFFFFF);

  /* This is to ensure that things works for CHAR fields, which trim ' ': */
  last_char= ((char*)body)+new_size-1;
  if (*last_char == ' ')
  {
    *++last_char= '.';
    new_size++;
  }

  str->length((uint32)new_size + 4);
  str->set_charset(&my_charset_bin);
  return str;
}


String *Item_func_uncompress::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  String *res= args[0]->val_str(&tmp_value);
  ulong new_size;
  int err;
  uint code;

  if (!res)
    goto err;
  null_value= 0;
  if (res->is_empty())
    return res;

  /* If length is less than 4 bytes, data is corrupt */
  if (res->length() <= 4)
  {
    THD *thd= current_thd;
    push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
   ER_ZLIB_Z_DATA_ERROR,
   ER_THD(thd, ER_ZLIB_Z_DATA_ERROR));
    goto err;
  }

  /* Size of uncompressed data is stored as first 4 bytes of field */
  new_size= uint4korr(res->ptr()) & 0x3FFFFFFF;
  if (new_size > current_thd->variables.max_allowed_packet)
  {
    THD *thd= current_thd;
    push_warning_printf(thd,Sql_condition::WARN_LEVEL_WARN,
   ER_TOO_BIG_FOR_UNCOMPRESS,
   ER_THD(thd, ER_TOO_BIG_FOR_UNCOMPRESS),
                        static_cast<int>(thd->variables.
                                         max_allowed_packet));
    goto err;
  }
  if (str->alloc((uint32)new_size))
    goto err;

  if ((err= uncompress((Byte*)str->ptr(), &new_size,
         ((const Bytef*)res->ptr())+4,res->length()-4)) == Z_OK)
  {
    str->length((uint32) new_size);
    return str;
  }

  code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR :
  ((err == Z_MEM_ERROR) ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR));
  {
    THD *thd= current_thd;
    push_warning(thd, Sql_condition::WARN_LEVEL_WARN, code, ER_THD(thd, code));
  }

err:
  null_value= 1;
  return 0;
}
#endif


Item_func_dyncol_create::Item_func_dyncol_create(THD *thd, List<Item> &args,
                                                 DYNCALL_CREATE_DEF *dfs):
  Item_str_func(thd, args), defs(dfs), vals(0), keys_num(NULL), keys_str(NULL),
  names(FALSE), force_names(FALSE)
{
  DBUG_ASSERT((args.elements & 0x1) == 0); // even number of arguments
}


bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref)
{
  uint i;
  bool res= Item_func::fix_fields(thd, ref); // no need Item_str_func here
  if (!res)
  {
    vals= (DYNAMIC_COLUMN_VALUE *) alloc_root(thd->mem_root,
                                              sizeof(DYNAMIC_COLUMN_VALUE) *
                                              (arg_count / 2));
    for (i= 0;
         i + 1 < arg_count && args[i]->result_type() == INT_RESULT;
         i+= 2)
      ;
    if (i + 1 < arg_count)
    {
      names= TRUE;
    }

    keys_num= (uint *) alloc_root(thd->mem_root,
                               (sizeof(LEX_STRING) > sizeof(uint) ?
                                sizeof(LEX_STRING) :
                                sizeof(uint)) *
                               (arg_count / 2));
    keys_str= (LEX_STRING *) keys_num;
    status_var_increment(thd->status_var.feature_dynamic_columns);
  }
  return res || vals == 0 || keys_num == 0;
}


bool Item_func_dyncol_create::fix_length_and_dec(THD *thd)
{
  max_length= MAX_BLOB_WIDTH;
  set_maybe_null();
  collation.set(&my_charset_bin);
  decimals= 0;
  return FALSE;
}

bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
{
  char buff[STRING_BUFFER_USUAL_SIZE];
  String *res, tmp(buff, sizeof(buff), &my_charset_bin);
  uint column_count= (arg_count / 2);
  uint i;
  my_decimal dtmp, *dres;
  force_names= force_names_arg;

  if (!(names || force_names))
  {
    for (i= 0; i < column_count; i++)
    {
      uint valpos= i * 2 + 1;
      DYNAMIC_COLUMN_TYPE type= defs[i].type;
      if (type == DYN_COL_NULL)
        type= args[valpos]->type_handler()->dyncol_type(args[valpos]);
      if (type == DYN_COL_STRING &&
          args[valpos]->type() == Item::FUNC_ITEM &&
          ((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
      {
        force_names= 1;
        break;
      }
    }
  }

  /* get values */
  for (i= 0; i < column_count; i++)
  {
    uint valpos= i * 2 + 1;
    DYNAMIC_COLUMN_TYPE type= defs[i].type;
    if (type == DYN_COL_NULL) // auto detect
      type= args[valpos]->type_handler()->dyncol_type(args[valpos]);
    if (type == DYN_COL_STRING &&
        args[valpos]->type() == Item::FUNC_ITEM &&
        ((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
    {
      DBUG_ASSERT(names || force_names);
      type= DYN_COL_DYNCOL;
    }
    if (names || force_names)
    {
      res= args[i * 2]->val_str(&tmp);
      if (res)
      {
        // guaranty UTF-8 string for names
        if (my_charset_same(res->charset(), DYNCOL_UTF))
        {
          keys_str[i].length= res->length();
          keys_str[i].str= thd->strmake(res->ptr(), res->length());
        }
        else
        {
          uint strlen= res->length() * DYNCOL_UTF->mbmaxlen + 1;
          uint dummy_errors;
          if (char *str= thd->alloc(strlen))
          {
            keys_str[i].length=
              copy_and_convert(str, strlen, DYNCOL_UTF,
                               res->ptr(), res->length(), res->charset(),
                               &dummy_errors);
              keys_str[i].str= str;
          }
          else
            keys_str[i].length= 0;

        }
      }
      else
      {
        keys_str[i].length= 0;
        keys_str[i].str= NULL;
      }
    }
    else
      keys_num[i]= (uint) args[i * 2]->val_int();
    if (args[i * 2]->null_value)
    {
      /* to make cleanup possible */
      for (; i < column_count; i++)
        vals[i].type= DYN_COL_NULL;
      return 1;
    }
    vals[i].type= type;
    switch (type) {
    case DYN_COL_NULL:
      DBUG_ASSERT(args[valpos]->field_type() == MYSQL_TYPE_NULL);
      break;
    case DYN_COL_INT:
      vals[i].x.long_value= args[valpos]->val_int();
      break;
    case DYN_COL_UINT:
      vals[i].x.ulong_value= args[valpos]->val_int();
      break;
    case DYN_COL_DOUBLE:
      vals[i].x.double_value= args[valpos]->val_real();
      break;
    case DYN_COL_DYNCOL:
    case DYN_COL_STRING:
      res= args[valpos]->val_str(&tmp);
      if (res && defs[i].cs)
        res->set_charset(defs[i].cs);
      if (res &&
          (vals[i].x.string.value.str= thd->strmake(res->ptr(), res->length())))
      {
 vals[i].x.string.value.length= res->length();
 vals[i].x.string.charset= res->charset();
      }
      else
      {
        args[valpos]->null_value= 1;            // In case of out of memory
        vals[i].x.string.value.str= NULL;
        vals[i].x.string.value.length= 0;         // just to be safe
      }
      break;
    case DYN_COL_DECIMAL:
      if ((dres= args[valpos]->val_decimal(&dtmp)))
      {
 mariadb_dyncol_prepare_decimal(&vals[i]);
        DBUG_ASSERT(vals[i].x.decimal.value.len == dres->len);
        vals[i].x.decimal.value.intg= dres->intg;
        vals[i].x.decimal.value.frac= dres->frac;
        vals[i].x.decimal.value.sign= dres->sign();
        memcpy(vals[i].x.decimal.buffer, dres->buf,
               sizeof(vals[i].x.decimal.buffer));
      }
      else
      {
 mariadb_dyncol_prepare_decimal(&vals[i]); // just to be safe
        DBUG_ASSERT(args[valpos]->null_value);
      }
      break;
    case DYN_COL_DATETIME:
    case DYN_COL_DATE:
      args[valpos]->get_date(thd, &vals[i].x.time_value,
                             Datetime::Options(thd));
      break;
    case DYN_COL_TIME:
      args[valpos]->get_time(thd, &vals[i].x.time_value);
      break;
    default:
      DBUG_ASSERT(0);
      vals[i].type= DYN_COL_NULL;
    }
    if (vals[i].type != DYN_COL_NULL && args[valpos]->null_value)
    {
      vals[i].type= DYN_COL_NULL;
    }
  }
  return FALSE;
}


String *Item_func_dyncol_create::val_str(String *str)
{
  DYNAMIC_COLUMN col;
  String *res;
  uint column_count= (arg_count / 2);
  enum enum_dyncol_func_result rc;
  DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments

  /* FIXME: add thd argument to Item::val_str() */
  if (prepare_arguments(current_thd, FALSE))
  {
    res= NULL;
    null_value= 1;
  }
  else
  {
    if ((rc= ((names || force_names) ?
              mariadb_dyncol_create_many_named(&col, column_count, keys_str,
                                               vals, TRUE) :
              mariadb_dyncol_create_many_num(&col, column_count, keys_num,
                                             vals, TRUE))))
    {
      dynamic_column_error_message(rc);
      mariadb_dyncol_free(&col);
      res= NULL;
      null_value= TRUE;
    }
    else
    {
      /* Move result from DYNAMIC_COLUMN to str_value */
      char *ptr;
      size_t length, alloc_length;
      dynstr_reassociate(&col, &ptr, &length, &alloc_length);
      str_value.reset(ptr, length, alloc_length, &my_charset_bin);
      res= &str_value;
      null_value= FALSE;
    }
  }

  return res;
}

void Item_func_dyncol_create::print_arguments(String *str,
                                              enum_query_type query_type)
{
  uint i;
  uint column_count= (arg_count / 2);
  for (i= 0; i < column_count; i++)
  {
    args[i*2]->print(str, query_type);
    str->append(',');
    args[i*2 + 1]->print(str, query_type);
    switch (defs[i].type) {
    case DYN_COL_NULL: // automatic type => write nothing
      break;
    case DYN_COL_INT:
      str->append(STRING_WITH_LEN(" AS int"));
      break;
    case DYN_COL_UINT:
      str->append(STRING_WITH_LEN(" AS unsigned int"));
      break;
    case DYN_COL_DOUBLE:
      str->append(STRING_WITH_LEN(" AS double"));
      break;
    case DYN_COL_DYNCOL:
    case DYN_COL_STRING:
      str->append(STRING_WITH_LEN(" AS char"));
      if (defs[i].cs)
      {
        str->append(STRING_WITH_LEN(" charset "));
        str->append(defs[i].cs->cs_name);
        if (Charset(defs[i].cs).can_have_collate_clause())
        {
          str->append(STRING_WITH_LEN(" collate "));
          str->append(defs[i].cs->coll_name);
        }
        str->append(' ');
      }
      break;
    case DYN_COL_DECIMAL:
      str->append(STRING_WITH_LEN(" AS decimal"));
      break;
    case DYN_COL_DATETIME:
      str->append(STRING_WITH_LEN(" AS datetime"));
      break;
    case DYN_COL_DATE:
      str->append(STRING_WITH_LEN(" AS date"));
      break;
    case DYN_COL_TIME:
      str->append(STRING_WITH_LEN(" AS time"));
      break;
    }
    if (i < column_count - 1)
      str->append(',');
  }
}


void Item_func_dyncol_create::print(String *str,
                                    enum_query_type query_type)
{
  DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments
  str->append(STRING_WITH_LEN("column_create("));
  print_arguments(str, query_type);
  str->append(')');
}

String *Item_func_dyncol_json::val_str(String *str)
{
  DYNAMIC_STRING json, col;
  String *res;
  enum enum_dyncol_func_result rc;

  res= args[0]->val_str(str);
  if (args[0]->null_value)
    goto null;

  col.str= (char *)res->ptr();
  col.length= res->length();
  if ((rc= mariadb_dyncol_json(&col, &json)))
  {
    dynamic_column_error_message(rc);
    dynstr_free(&json);
    goto null;
  }
  {
    /* Move result from DYNAMIC_COLUMN to str */
    char *ptr;
    size_t length, alloc_length;
    dynstr_reassociate(&json, &ptr, &length, &alloc_length);
    str->reset(ptr, length, alloc_length, DYNCOL_UTF);
    null_value= FALSE;
  }
  str->set_charset(DYNCOL_UTF);
  return str;

null:
  null_value= TRUE;
  return NULL;
}

String *Item_func_dyncol_add::val_str(String *str)
{
  DYNAMIC_COLUMN col;
  String *res;
  uint column_count=  (arg_count / 2);
  enum enum_dyncol_func_result rc;
  DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments

  /* We store the packed data last */
  res= args[arg_count - 1]->val_str(str);
  if (args[arg_count - 1]->null_value ||
      init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE,
                          STRING_BUFFER_USUAL_SIZE))
    goto null;

  col.length= res->length();
  memcpy(col.str, res->ptr(), col.length);

  /* FIXME: add thd argument to Item::val_str() */
  if (prepare_arguments(current_thd, mariadb_dyncol_has_names(&col)))
    goto null;

  if ((rc= ((names || force_names) ?
            mariadb_dyncol_update_many_named(&col, column_count,
                                             keys_str, vals) :
            mariadb_dyncol_update_many_num(&col, column_count,
                                           keys_num, vals))))
  {
    dynamic_column_error_message(rc);
    mariadb_dyncol_free(&col);
    goto null;
  }

  {
    /* Move result from DYNAMIC_COLUMN to str */
    char *ptr;
    size_t length, alloc_length;
    dynstr_reassociate(&col, &ptr, &length, &alloc_length);
    str->reset(ptr, length, alloc_length, &my_charset_bin);
    null_value= FALSE;
  }

  return str;

null:
  null_value= TRUE;
  return NULL;
}


void Item_func_dyncol_add::print(String *str,
                                 enum_query_type query_type)
{
  DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments
  str->append(STRING_WITH_LEN("column_add("));
  args[arg_count - 1]->print(str, query_type);
  str->append(',');
  print_arguments(str, query_type);
  str->append(')');
}


/**
  Get value for a column stored in a dynamic column

  @notes
  This function ensures that null_value is set correctly
*/


bool Item_dyncol_get::get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val,
                                    String *tmp)
{
  DYNAMIC_COLUMN dyn_str;
  String *res;
  longlong num= 0;
  LEX_STRING buf, *name= NULL;
  char nmstrbuf[11];
  String nmbuf(nmstrbuf, sizeof(nmstrbuf), system_charset_info);
  enum enum_dyncol_func_result rc;

  if (args[1]->result_type() == INT_RESULT)
    num= args[1]->val_int();
  else
  {
    String *nm= args[1]->val_str(&nmbuf);
    if (!nm || args[1]->null_value)
    {
      null_value= 1;
      return 1;
    }

    if (my_charset_same(nm->charset(), DYNCOL_UTF))
    {
      buf.str= (char *) nm->ptr();
      buf.length= nm->length();
    }
    else
    {
      uint strlen= nm->length() * DYNCOL_UTF->mbmaxlen + 1;
      uint dummy_errors;
      buf.str= thd->alloc(strlen);
      if (buf.str)
      {
        buf.length=
          copy_and_convert(buf.str, strlen, DYNCOL_UTF,
                           nm->ptr(), nm->length(), nm->charset(),
                           &dummy_errors);
      }
      else
        buf.length= 0;
    }
    name= &buf;
  }


  if (args[1]->null_value || num < 0 || num > INT_MAX)
  {
    null_value= 1;
    return 1;
  }

  res= args[0]->val_str(tmp);
  if (args[0]->null_value)
  {
    null_value= 1;
    return 1;
  }

  dyn_str.str=   (char*) res->ptr();
  dyn_str.length= res->length();
  if ((rc= ((name == NULL) ?
            mariadb_dyncol_get_num(&dyn_str, (uint) num, val) :
            mariadb_dyncol_get_named(&dyn_str, name, val))))
  {
    dynamic_column_error_message(rc);
    null_value= 1;
    return 1;
  }

  null_value= 0;
  return 0;                                     // ok
}


String *Item_dyncol_get::val_str(String *str_result)
{
  DYNAMIC_COLUMN_VALUE val;
  char buff[STRING_BUFFER_USUAL_SIZE];
  String tmp(buff, sizeof(buff), &my_charset_bin);

  if (get_dyn_value(current_thd, &val, &tmp))
    return NULL;

  switch (val.type) {
  case DYN_COL_NULL:
    goto null;
  case DYN_COL_INT:
  case DYN_COL_UINT:
    str_result->set_int(val.x.long_value, MY_TEST(val.type == DYN_COL_UINT),
                       &my_charset_latin1);
    break;
  case DYN_COL_DOUBLE:
    str_result->set_real(val.x.double_value, NOT_FIXED_DEC, &my_charset_latin1);
    break;
  case DYN_COL_DYNCOL:
  case DYN_COL_STRING:
    if ((char*) tmp.ptr() <= val.x.string.value.str &&
        (char*) tmp.ptr() + tmp.length() >= val.x.string.value.str)
    {
      /* value is allocated in tmp buffer; We have to make a copy */
      str_result->copy(val.x.string.value.str, val.x.string.value.length,
                      val.x.string.charset);
    }
    else
    {
      /*
        It's safe to use the current value because it's either pointing
        into a field or in a buffer for another item and this buffer
        is not going to be deleted during expression evaluation
      */

      str_result->set(val.x.string.value.str, val.x.string.value.length,
                      val.x.string.charset);
    }
    break;
  case DYN_COL_DECIMAL:
  {
    int res;
    int length= decimal_string_size(&val.x.decimal.value);
    if (str_result->alloc(length))
      goto null;
    if ((res= decimal2string(&val.x.decimal.value, (char*) str_result->ptr(),
                             &length, 0, 0, ' ')) != E_DEC_OK)
    {
      char buff[40];
      int len= sizeof(buff);
      DBUG_ASSERT(length < (int)sizeof(buff));
      decimal2string(&val.x.decimal.value, buff, &len, 0, 0, ' ');
      decimal_operation_results(res, buff, "CHAR");
    }
    str_result->set_charset(&my_charset_latin1);
    str_result->length(length);
    break;
  }
  case DYN_COL_DATETIME:
  case DYN_COL_DATE:
  case DYN_COL_TIME:
  {
    int length;
    /*
      We use AUTO_SEC_PART_DIGITS here to ensure that we do not loose
      any microseconds from the data. This is safe to do as we are
      asked to return the time argument as a string.
    */

    if (str_result->alloc(MAX_DATE_STRING_REP_LENGTH) ||
        !(length= my_TIME_to_str(&val.x.time_value, (char*) str_result->ptr(),
                                 AUTO_SEC_PART_DIGITS)))
      goto null;
    str_result->set_charset(&my_charset_latin1);
    str_result->length(length);
    break;
  }
  }
  return str_result;

null:
  null_value= TRUE;
  return 0;
}


longlong Item_dyncol_get::val_int()
{
  THD *thd= current_thd;
  DYNAMIC_COLUMN_VALUE val;
  char buff[STRING_BUFFER_USUAL_SIZE];
  String tmp(buff, sizeof(buff), &my_charset_bin);

  if (get_dyn_value(thd, &val, &tmp))
    return 0;

  switch (val.type) {
  case DYN_COL_DYNCOL:
  case DYN_COL_NULL:
    goto null;
  case DYN_COL_UINT:
    unsigned_flag= 1;            // Make it possible for caller to detect sign
    return val.x.long_value;
  case DYN_COL_INT:
    unsigned_flag= 0;            // Make it possible for caller to detect sign
    return val.x.long_value;
  case DYN_COL_DOUBLE:
    return Converter_double_to_longlong_with_warn(thd, val.x.double_value,
                                                  unsigned_flag).result();
  case DYN_COL_STRING:
  {
    int error;
    longlong num;
    char *end= val.x.string.value.str + val.x.string.value.length, *org_end= end;

    num= my_strtoll10(val.x.string.value.str, &end, &error);
    if (unlikely(end != org_end || error > 0))
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_BAD_DATA,
                          ER_THD(thd, ER_BAD_DATA),
                          ErrConvString(val.x.string.value.str,
                                        val.x.string.value.length,
                                        val.x.string.charset).ptr(),
                          unsigned_flag ? "UNSIGNED INT" : "INT");
    }
    unsigned_flag= error >= 0;
    return num;
  }
  case DYN_COL_DECIMAL:
  {
    longlong num;
    my_decimal2int(E_DEC_FATAL_ERROR, &val.x.decimal.value, unsigned_flag,
                   &num);
    return num;
  }
  case DYN_COL_DATETIME:
  case DYN_COL_DATE:
  case DYN_COL_TIME:
    unsigned_flag= !val.x.time_value.neg;
    if (unsigned_flag)
      return TIME_to_ulonglong(&val.x.time_value);
    else
      return -(longlong)TIME_to_ulonglong(&val.x.time_value);
  }

null:
  null_value= TRUE;
  return 0;
}


double Item_dyncol_get::val_real()
{
  THD *thd= current_thd;
  DYNAMIC_COLUMN_VALUE val;
  char buff[STRING_BUFFER_USUAL_SIZE];
  String tmp(buff, sizeof(buff), &my_charset_bin);

  if (get_dyn_value(thd, &val, &tmp))
    return 0.0;

  switch (val.type) {
  case DYN_COL_DYNCOL:
  case DYN_COL_NULL:
    goto null;
  case DYN_COL_UINT:
    return ulonglong2double(val.x.ulong_value);
  case DYN_COL_INT:
    return (double) val.x.long_value;
  case DYN_COL_DOUBLE:
    return (double) val.x.double_value;
  case DYN_COL_STRING:
  {
    int error;
    char *end;
    double res= val.x.string.charset->strntod((char*) val.x.string.value.str,
                                              val.x.string.value.length, &end, &error);

    if (end != (char*) val.x.string.value.str + val.x.string.value.length ||
        error)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_BAD_DATA,
                          ER_THD(thd, ER_BAD_DATA),
                          ErrConvString(val.x.string.value.str,
                                        val.x.string.value.length,
                                        val.x.string.charset).ptr(),
                          "DOUBLE");
    }
    return res;
  }
  case DYN_COL_DECIMAL:
  {
    double res;
    /* This will always succeed */
    decimal2double(&val.x.decimal.value, &res);
    return res;
  }
  case DYN_COL_DATETIME:
  case DYN_COL_DATE:
  case DYN_COL_TIME:
    return TIME_to_double(&val.x.time_value);
  }

null:
  null_value= TRUE;
  return 0.0;
}


my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value)
{
  THD *thd= current_thd;
  DYNAMIC_COLUMN_VALUE val;
  char buff[STRING_BUFFER_USUAL_SIZE];
  String tmp(buff, sizeof(buff), &my_charset_bin);

  if (get_dyn_value(thd, &val, &tmp))
    return NULL;

  switch (val.type) {
  case DYN_COL_DYNCOL:
  case DYN_COL_NULL:
    goto null;
  case DYN_COL_UINT:
    int2my_decimal(E_DEC_FATAL_ERROR, val.x.long_value, TRUE, decimal_value);
    break;
  case DYN_COL_INT:
    int2my_decimal(E_DEC_FATAL_ERROR, val.x.long_value, FALSE, decimal_value);
    break;
  case DYN_COL_DOUBLE:
    double2my_decimal(E_DEC_FATAL_ERROR, val.x.double_value, decimal_value);
    break;
  case DYN_COL_STRING:
  {
    const char *end;
    int rc;
    rc= str2my_decimal(0, val.x.string.value.str, val.x.string.value.length,
                       val.x.string.charset, decimal_value, &end);
    if (rc != E_DEC_OK ||
        end != val.x.string.value.str + val.x.string.value.length)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_BAD_DATA,
                          ER_THD(thd, ER_BAD_DATA),
                          ErrConvString(val.x.string.value.str,
                                        val.x.string.value.length,
                                        val.x.string.charset).ptr(),
                          "DECIMAL");
    }
    break;
  }
  case DYN_COL_DECIMAL:
    decimal2my_decimal(&val.x.decimal.value, decimal_value);
    break;
  case DYN_COL_DATETIME:
  case DYN_COL_DATE:
  case DYN_COL_TIME:
    decimal_value= TIME_to_my_decimal(&val.x.time_value, decimal_value);
    break;
  }
  return decimal_value;

null:
  null_value= TRUE;
  return 0;
}


bool Item_dyncol_get::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
  DYNAMIC_COLUMN_VALUE val;
  char buff[STRING_BUFFER_USUAL_SIZE];
  String tmp(buff, sizeof(buff), &my_charset_bin);
  bool signed_value= 0;

  if (get_dyn_value(current_thd, &val, &tmp))
    return 1;                                   // Error

  switch (val.type) {
  case DYN_COL_DYNCOL:
  case DYN_COL_NULL:
    goto null;
  case DYN_COL_INT:
    signed_value= 1;                                  // For error message
    /* fall through */
  case DYN_COL_UINT:
    if (signed_value || val.x.ulong_value <= LONGLONG_MAX)
    {
      longlong llval = (longlong)val.x.ulong_value;
      if (int_to_datetime_with_warn(thd, Longlong_hybrid(llval, !signed_value),
                                    ltime, fuzzydate, 0, 0 /* TODO */))
        goto null;
      return 0;
    }
    /* let double_to_datetime_with_warn() issue the warning message */
    val.x.double_value= static_cast<double>(ULONGLONG_MAX);
    /* fall through */
  case DYN_COL_DOUBLE:
    if (double_to_datetime_with_warn(thd, val.x.double_value, ltime, fuzzydate,
                                     0, 0 /* TODO */))
      goto null;
    return 0;
  case DYN_COL_DECIMAL:
    if (decimal_to_datetime_with_warn(thd, (my_decimal*)&val.x.decimal.value,
                                      ltime, fuzzydate, 0, 0 /* TODO */))
      goto null;
    return 0;
  case DYN_COL_STRING:
    if (str_to_datetime_with_warn(thd, &my_charset_numeric,
                                  val.x.string.value.str,
                                  val.x.string.value.length,
                                  ltime, fuzzydate))
      goto null;
    return 0;
  case DYN_COL_DATETIME:
  case DYN_COL_DATE:
  case DYN_COL_TIME:
    *ltime= val.x.time_value;
    return 0;
  }

null:
  null_value= TRUE;
  return 1;
}

void Item_dyncol_get::print(String *str, enum_query_type query_type)
{
  /*
    Parent cast doesn't exist yet, only print dynamic column name. This happens
    when called from create_func_cast() / wrong_precision_error().
  */

  if (!str->length())
  {
    args[1]->print(str, query_type);
    return;
  }

  /* see create_func_dyncol_get */
  DBUG_ASSERT(str->length() >= 5);
  DBUG_ASSERT(strncmp(str->ptr() + str->length() - 5, "cast(", 5) == 0);

  str->length(str->length() - 5);    // removing "cast("
  str->append(STRING_WITH_LEN("column_get("));
  args[0]->print(str, query_type);
  str->append(',');
  args[1]->print(str, query_type);
  /* let the parent cast item add " as <type>)" */
}


String *Item_func_dyncol_list::val_str(String *str)
{
  uint i;
  enum enum_dyncol_func_result rc;
  LEX_STRING *names= 0;
  uint count;
  DYNAMIC_COLUMN col;
  String *res= args[0]->val_str(str);

  if (args[0]->null_value)
    goto null;
  col.length= res->length();
  /* We do not change the string, so could do this trick */
  col.str= (char *)res->ptr();
  if ((rc= mariadb_dyncol_list_named(&col, &count, &names)))
  {
    bzero(&col, sizeof(col));
    dynamic_column_error_message(rc);
    goto null;
  }
  bzero(&col, sizeof(col));

  /*
    We estimate average name length as 10
  */

  if (str->alloc(count * 13))
    goto null;

  str->length(0);
  for (i= 0; i < count; i++)
  {
    append_identifier(current_thd, str, names[i].str, names[i].length);
    if (i < count - 1)
      str->qs_append(',');
  }
  null_value= FALSE;
  if (names)
    my_free(names);
  str->set_charset(DYNCOL_UTF);
  return str;

null:
  null_value= TRUE;
  if (names)
    my_free(names);
  return NULL;
}

Item_temptable_rowid::Item_temptable_rowid(TABLE *table_arg)
  : Item_str_func(table_arg->in_use), table(table_arg)
{
  max_length= table->file->ref_length;
}

bool Item_temptable_rowid::fix_length_and_dec(THD *thd)
{
  used_tables_cache= table->map;
  const_item_cache= false;
  return FALSE;
}

String *Item_temptable_rowid::val_str(String *str)
{
  if (!((null_value= table->null_row)))
    table->file->position(table->record[0]);
  str_value.set((char*)(table->file->ref), max_length, &my_charset_bin);
  return &str_value;
}

/**
  Helper routine to encode length prefix
  in natsort_encode_numeric_string().

  The idea is so that bigger input numbers correspond
  lexicographically bigger output strings.

  Note, that in real use the number would typically
  small, as it only computes variable *length prefixes*.

  @param[in] n - the number
  @param[in] s - output string

  @return - length of encoding

  Here is how encoding works

  - n is from 0 to 8
   Output string calculated as '0'+n (range '0' - '8')

  - n is from 9 to 17
    Output calculated as concat('9', '0' + n -9)'
    Output range: '90'-'98'

   -n is from 18 to 26
    Output calculated as concat('99', '0' + n -18)'
    Output range '990'-'998'

  - n is from 27 to SIZE_T_MAX
    Output starts with '999',
    then log10(n) is encoded as 2-digit decimal number
    then the number itself is added.
    Example : for 28 key is concat('999', '01' , '28')
    i.e '9990128'

    Key length is 5 + ceil(log10(n))

   Output range is
     (64bit)'9990128' - '9991918446744073709551615'
     (32bit)'9990128' - '999094294967295'
*/


/* Largest length of encoded string.*/
static size_t natsort_encode_length_max(size_t n)
{
  return (n < 27) ? n/9+1 : 26;
}

static void natsort_encode_length(size_t n, String* out)
{
  if (n < 27)
  {
    if (n >= 9)
      out->fill(out->length() + n/9,'9');
    out->append(char(n % 9 + '0'));
    return;
  }

  size_t log10n= 0;
  for (size_t tmp= n / 10; tmp; tmp/= 10)
    log10n++;
  out->fill(out->length() + 3, '9');
  out->append('0' + (char) (log10n / 10));
  out->append('0' + (char) (log10n % 10));
  out->append_ulonglong(n);
}

enum class NATSORT_ERR
{
  SUCCESS= 0,
  KEY_TOO_LARGE= 1,
  ALLOC_ERROR= 2
};

/*
   Encode numeric string for natural sorting.

   @param[in] in - start of the numeric string
   skipping leading zeros

   @param[in] n_digits - length of the string,
   in characters, not counting leading zeros.

   @param[out] out - String to write to. The string should
   have enough preallocated space to fit the encoded key.

   @return
     NATSORT_ERR::SUCCESS  - success
     NATSORT_ERR::KEY_TOO_LARGE  - out string does not have enough
     space left to accomodate the key.


   The resulting encoding of the numeric string is then

   CONCAT(natsort_encode_length(n_digits), in)
*/

static NATSORT_ERR natsort_encode_numeric_string(const char *in,
                                                 size_t n_digits,
                                                 String *out)
{
  DBUG_ASSERT(in);
  DBUG_ASSERT(n_digits);

  if (out->length() + natsort_encode_length_max(n_digits - 1) + n_digits >
      out->alloced_length())
    return NATSORT_ERR::KEY_TOO_LARGE;

  natsort_encode_length(n_digits - 1, out);
  out->append(in, n_digits);
  return NATSORT_ERR::SUCCESS;
}

/*
  Calculate max size of the natsort key.

  A digit in string expands to 2 chars  length_prefix , and  the digit

  With even length L=2N, the largest key corresponds to input string
  in form REPEAT(<digit><letter>,N) and the length of a key is
  2N + N = 3N

  With odd input length L=2N+1, largest key is built by appending
  a digit at the end, with key length 3N+2

*/

static size_t natsort_max_key_size(size_t input_size)
{
  return input_size + (input_size + 1)/2 ;
}

/**
  Convert a string to natural sort key.
  @param[in]   in - input string
  @param[out]  out - output string
  @param[in]   max_key_size - the maximum size of the output
               key, in bytes.
  @return NATSORT_ERR::SUCCESS - successful completion
          NATSORT_ERR::ALLOC_ERROR - memory allocation error
          NATSORT_ERR::KEY_TOO_LARGE - resulting key would exceed max_key_size
*/

static NATSORT_ERR to_natsort_key(const String *in, String *out,
                                  size_t max_key_size)
{
  size_t n_digits= 0;
  size_t n_lead_zeros= 0;
  size_t num_start= 0;
  size_t reserve_length= std::min(
      natsort_max_key_size(in->length()) + MAX_BIGINT_WIDTH + 2, max_key_size);

  out->length(0);
  out->set_charset(in->charset());

  if (out->alloc((uint32) reserve_length))
    return NATSORT_ERR::ALLOC_ERROR;

  for (size_t pos= 0;; pos++)
  {
    char c= pos < in->length() ? (*in)[pos] : 0;
    bool is_digit= (c >= '0' && c <= '9');
    if (!is_digit && (n_digits || n_lead_zeros))
    {
      /* Handle end of digits run.*/
      if (!n_digits)
      {
        /*We only have zeros.*/
        n_lead_zeros--;
        num_start= pos - 1;
        n_digits= 1;
      }
      NATSORT_ERR err= natsort_encode_numeric_string(
          in->ptr() + num_start, n_digits, out);
      if (err != NATSORT_ERR::SUCCESS)
        return err;

      /* Reset state.*/
      n_digits= 0;
      num_start= size_t(-1);
      n_lead_zeros= 0;
    }

    if (pos == in->length())
      break;

    if (!is_digit)
    {
      if (out->length() == max_key_size)
        return NATSORT_ERR::KEY_TOO_LARGE;
      out->append(c);
    }
    else if (c == '0' && !n_digits)
      n_lead_zeros++;
    else if (!n_digits++)
      num_start= pos;
  }
  return NATSORT_ERR::SUCCESS;
}

String *Item_func_natural_sort_key::val_str(String *out)
{
  String *in= args[0]->val_str();
  if (args[0]->null_value || !in)
  {
    null_value= true;
    return nullptr;
  }
  NATSORT_ERR err= NATSORT_ERR::SUCCESS;
  CHARSET_INFO *cs= in->charset();
  ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
  uint errs;
  String tmp;
  /*
    to_natsort_key() only support charsets where digits are represented by
    a single byte in range 0x30-0x39. Almost everything is OK, just utf16/32
    won't do. Full ASCII compatibility is not required, so that SJIS and SWE7
    are fine.
  */

  if (cs->mbminlen != 1)
  {
    if (tmp.copy(in, &my_charset_utf8mb4_bin, &errs))
      goto error_exit;
    in= &tmp;
  }

  err= to_natsort_key(in, out, max_allowed_packet / cs->mbminlen);

  if (err != NATSORT_ERR::SUCCESS)
  {
    if (err == NATSORT_ERR::KEY_TOO_LARGE)
    {
      push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
                          ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
                          max_allowed_packet);
    }
    goto error_exit;
  }

  if (cs->mbminlen != 1)
  {
    /* output string is now utf8, convert to input charset.*/
    if (tmp.copy(out, cs, &errs) || out->copy(tmp))
      goto error_exit;
  }
  null_value= false;
  return out;

error_exit:
  null_value= true;
  return nullptr;
}

bool Item_func_natural_sort_key::fix_length_and_dec(THD *thd)
{
  if (agg_arg_charsets_for_string_result(collation, args, 1))
    return true;
  DBUG_ASSERT(collation.collation != NULL);
  uint32 max_char_len=
      (uint32) natsort_max_key_size(args[0]->max_char_length());
  fix_char_length(max_char_len);

  set_maybe_null(args[0]->maybe_null() ||
                 max_char_len * collation.collation->mbmaxlen >
                     current_thd->variables.max_allowed_packet);
  return false;
}

/**
  Disable use in stored virtual functions. Temporarily(?), until
  the encoding is stable.
*/

bool Item_func_natural_sort_key::check_vcol_func_processor(void *arg)
{
  return mark_unsupported_function(func_name(), "()", arg,
                                   VCOL_NON_DETERMINISTIC);
}


String *Item_func_format_pico_time::val_str_ascii(String *)
{
  double time_val= args[0]->val_real();

  null_value= args[0]->null_value;
  if (null_value)
    return 0;

  constexpr ulonglong nano{1000};
  constexpr ulonglong micro{1000 * nano};
  constexpr ulonglong milli{1000 * micro};
  constexpr ulonglong sec{1000 * milli};
  constexpr ulonglong min{60 * sec};
  constexpr ulonglong hour{60 * min};
  constexpr ulonglong day{24 * hour};

  double time_abs= fabs(time_val);

  ulonglong divisor;
  size_t len;
  const char *unit;

  /* SI-approved time units. */
  if (time_abs >= day)
  {
    divisor= day;
    unit= "d";
  }
  else if (time_abs >= hour)
  {
    divisor= hour;
    unit= "h";
  }
  else if (time_abs >= min)
  {
    divisor= min;
    unit= "min";
  }
  else if (time_abs >= sec)
  {
    divisor= sec;
    unit= "s";
  }
  else if (time_abs >= milli)
  {
    divisor= milli;
    unit= "ms";
  }
  else if (time_abs >= micro)
  {
    divisor= micro;
    unit= "us";
  }
  else if (time_abs >= nano)
  {
    divisor= nano;
    unit= "ns";
  }
  else
  {
    divisor= 1;
    unit= "ps";
  }

  if (divisor == 1)
    len= my_snprintf(m_value_buffer, sizeof(m_value_buffer), "%3d %s", (int)time_val, unit);
  else
  {
    double value= time_val / divisor;
    if (fabs(value) >= 100000.0)
      len= snprintf(m_value_buffer, sizeof(m_value_buffer), "%4.2e %s", value, unit);
    else
      len= my_snprintf(m_value_buffer, sizeof(m_value_buffer), "%4.2f %s", value, unit);
  }
  m_value.length(len);
  return &m_value;
}


String *Item_func_format_bytes::val_str_ascii(String *)
{
  double bytes= args[0]->val_real();

  null_value = args[0]->null_value;
  if (null_value)
    return 0;

  /*
    snprintf below uses %4.2f, so 1023.99 MiB should be shown as 1.00 GiB
  */

  double bytes_abs= fabs(bytes)/1023.995*1024;

  constexpr uint64_t kib{1024};
  constexpr uint64_t mib{1024 * kib};
  constexpr uint64_t gib{1024 * mib};
  constexpr uint64_t tib{1024 * gib};
  constexpr uint64_t pib{1024 * tib};
  constexpr uint64_t eib{1024 * pib};

  uint64_t divisor;
  size_t len;
  const char *unit;

  if (bytes_abs >= eib)
  {
    divisor= eib;
    unit= "EiB";
  }
  else if (bytes_abs >= pib)
  {
    divisor= pib;
    unit= "PiB";
  }
  else if (bytes_abs >= tib)
  {
    divisor= tib;
    unit= "TiB";
  }
  else if (bytes_abs >= gib)
  {
    divisor= gib;
    unit= "GiB";
  }
  else if (bytes_abs >= mib)
  {
    divisor= mib;
    unit= "MiB";
  }
  else if (bytes_abs >= kib)
  {
    divisor= kib;
    unit= "KiB";
  }
  else
  {
    divisor= 1;
    unit= "bytes";
  }

  if (divisor == 1)
    len= snprintf(m_value_buffer, sizeof(m_value_buffer), "%4d %s", (int)bytes, unit);
  else
  {
    double value= bytes / divisor;
    if (fabs(value) >= 100000.0)
      len= snprintf(m_value_buffer, sizeof(m_value_buffer), "%4.2e %s", value, unit);
    else
      len= snprintf(m_value_buffer, sizeof(m_value_buffer), "%4.2f %s", value, unit);
  }
  m_value.length(len);
  return &m_value;
}

#ifdef WITH_WSREP
#include "wsrep_mysqld.h"
#include "wsrep_server_state.h"
/* Format is %d-%d-%llu */
#define WSREP_MAX_WSREP_SERVER_GTID_STR_LEN 10+1+10+1+20

String *Item_func_wsrep_last_written_gtid::val_str_ascii(String *str)
{
  if (gtid_str.alloc(WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1))
  {
    my_error(ER_OUTOFMEMORY, MYF(0), WSREP_MAX_WSREP_SERVER_GTID_STR_LEN);
    null_value= TRUE;
    return 0;
  }

  ssize_t gtid_len= my_snprintf((char*)gtid_str.ptr(),
                                WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1,
                                "%u-%u-%llu", wsrep_gtid_server.domain_id,
                                wsrep_gtid_server.server_id,
                                current_thd->wsrep_last_written_gtid_seqno);
  if (gtid_len < 0)
  {
    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
            "wsrep_gtid_print failed");
    null_value= TRUE;
    return 0;
  }
  gtid_str.length(gtid_len);
  return >id_str;
}

String *Item_func_wsrep_last_seen_gtid::val_str_ascii(String *str)
{
  if (gtid_str.alloc(WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1))
  {
    my_error(ER_OUTOFMEMORY, MYF(0), WSREP_MAX_WSREP_SERVER_GTID_STR_LEN);
    null_value= TRUE;
    return 0;
  }
  ssize_t gtid_len= my_snprintf((char*)gtid_str.ptr(),
                                WSREP_MAX_WSREP_SERVER_GTID_STR_LEN+1,
                                "%u-%u-%llu", wsrep_gtid_server.domain_id,
                                wsrep_gtid_server.server_id,
                                wsrep_gtid_server.seqno());
  if (gtid_len < 0)
  {
    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
             "wsrep_gtid_print failed");
    null_value= TRUE;
    return 0;
  }
  gtid_str.length(gtid_len);
  return >id_str;
}

longlong Item_func_wsrep_sync_wait_upto::val_int()
{
  String *gtid_str __attribute__((unused)) = args[0]->val_str(&value);
  null_value=0;
  uint timeout;
  rpl_gtid *gtid_list;
  uint32 count;
  int wait_gtid_ret= 0;
  int ret= 1;

  if (args[0]->null_value)
  {
    my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
    null_value= TRUE;
    return 0;
  }

  if (arg_count==2 && !args[1]->null_value)
    timeout= (uint)(args[1]->val_real());
  else
    timeout= (uint)-1;

  if (!(gtid_list= gtid_parse_string_to_list(gtid_str->ptr(), gtid_str->length(),
                                             &count)))
  {
    my_error(ER_INCORRECT_GTID_STATE, MYF(0));
    null_value= TRUE;
    return 0;
  }
  if (count == 1)
  {
    if (wsrep_check_gtid_seqno(gtid_list[0].domain_id, gtid_list[0].server_id,
                               gtid_list[0].seq_no))
    {
      wait_gtid_ret= wsrep_gtid_server.wait_gtid_upto(gtid_list[0].seq_no, timeout);
      if ((wait_gtid_ret == ETIMEDOUT) || (wait_gtid_ret == ETIME))
      {
        my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
        ret= 0;
      }
      else if (wait_gtid_ret == ENOMEM)
      {
        my_error(ER_OUTOFMEMORY, MYF(0), sizeof(std::pair<uint64, mysql_cond_t*>));
        ret= 0;
      }
    }
  }
  else
  {
    my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
    null_value= TRUE;
    ret= 0;
  }
  my_free(gtid_list);
  return ret;
}

#endif /* WITH_WSREP */


String *Item_func_current_path::val_str(String *str)
{
  DBUG_ASSERT(fixed());
  THD *thd= current_thd;

  auto length= thd->variables.path.text_format_nbytes_needed();
  if (str->realloc(length))
    return NULL;

  length= thd->variables.path.print(&(*str)[0], str->alloced_length());
  str->length(length);

  null_value= 0;
  return str;
}

Messung V0.5 in Prozent
C=95 H=85 G=90

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.501Bemerkung:  (vorverarbeitet am  2026-10-08) ¤

*Bot Zugriff






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126438
#Domains=1867298