String *Item_func_insert::val_str(String *str)
{
  DBUG_ASSERT(fixed == 1);
  String *res,*res2;
  longlong start, length, orig_len;  /* 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 */

  orig_len= static_cast<longlong>(res->length());

  if ((start < 1) || (start > orig_len))
    return res;                                 // Wrong param; skip insert

  --start;    // Internal start from '0'

  if ((length < 0) || (length > orig_len))
    length= orig_len;

  /*
    There is one exception not handled (intentionaly) 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 > orig_len)
    return res; /* purecov: inspected */        // Wrong param; skip insert
  if (length > orig_len - start)
    length= orig_len - start;

  if ((ulonglong) (orig_len - length + res2->length()) >
      (ulonglong) current_thd->variables.max_allowed_packet)
  {
    push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
			ER_WARN_ALLOWED_PACKET_OVERFLOWED,
			ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
			func_name(), current_thd->variables.max_allowed_packet);
    goto null;
  }
  if (res->uses_buffer_owned_by(str))
  {
    if (tmp_value_res.alloc(orig_len) ||
        tmp_value_res.copy(*res))
      goto null;
    res= &tmp_value_res;
  }
  else
    res= copy_if_not_alloced(str, res, orig_len);

  res->replace((uint32) start,(uint32) length,*res2);
  return res;
null:
  null_value=1;
  return 0;
}
String *Item_func_insert::val_str(String *str)
{
  DBUG_ASSERT(fixed == 1);
  String *res,*res2;
  longlong start, length, orig_len;   

  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;  

  orig_len= static_cast<longlong>(res->length());

  if ((start < 1) || (start > orig_len))
    return res;                                  

  --start;     

  if ((length < 0) || (length > orig_len))
    length= orig_len;

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

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

   
  if (start > orig_len)
    return res;           
  if (length > orig_len - start)
    length= orig_len - start;

  if ((ulonglong) (orig_len - length + res2->length()) >
      (ulonglong) current_thd->variables.max_allowed_packet)
  {
    push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
			ER_WARN_ALLOWED_PACKET_OVERFLOWED,
			ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
			func_name(), current_thd->variables.max_allowed_packet);
    goto null;
  }
  if (res->uses_buffer_owned_by(str))
  {
    if (tmp_value_res.alloc(orig_len) ||
        tmp_value_res.copy(*res))
      goto null;
    res= &tmp_value_res;
  }
  else
    res= copy_if_not_alloced(str, res, orig_len);

  res->replace((uint32) start,(uint32) length,*res2);
  return res;
null:
  null_value=1;
  return 0;
}