List:Commits« Previous MessageNext Message »
From:bar Date:November 1 2006 9:05am
Subject:bk commit into 5.1 tree (bar:1.2326)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of bar. When bar does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-11-01 13:05:24+04:00, bar@stripped +22 -0
  Merge mysql.com:/usr/home/bar/mysql-5.0-rpl
  into  mysql.com:/usr/home/bar/mysql-5.1-rpl
  MERGE: 1.1810.2078.45

  BitKeeper/etc/collapsed@stripped, 2006-11-01 13:00:45+04:00, bar@stripped +0 -0
    auto-union
    MERGE: 1.5.1.4

  include/m_ctype.h@stripped, 2006-11-01 13:00:58+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.114.1.9

  mysql-test/r/ctype_recoding.result@stripped, 2006-11-01 13:00:58+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.30.1.3

  mysql-test/r/ctype_utf8.result@stripped, 2006-11-01 13:00:58+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.85.5.12

  mysql-test/r/fulltext.result@stripped, 2006-11-01 13:00:59+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.83.1.3

  mysql-test/r/strict_autoinc_1myisam.result@stripped, 2006-11-01 13:00:59+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.1

  mysql-test/r/strict_autoinc_2innodb.result@stripped, 2006-11-01 13:00:59+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.1

  mysql-test/r/strict_autoinc_3heap.result@stripped, 2006-11-01 13:00:59+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.1

  mysql-test/r/strict_autoinc_4bdb.result@stripped, 2006-11-01 13:00:59+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.1

  mysql-test/r/strict_autoinc_5ndb.result@stripped, 2006-11-01 13:00:59+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.1

  mysql-test/t/rpl_ignore_table.test@stripped, 2006-11-01 13:05:19+04:00, bar@stripped +1 -0
    Adding sync_slave_with_master
    (like it was added in the end of previous test)
    MERGE: 1.1.1.1

  sql/field.cc@stripped, 2006-11-01 13:05:20+04:00, bar@stripped +0 -6
    After merge fix
    MERGE: 1.256.1.71

  sql/slave.cc@stripped, 2006-11-01 13:05:20+04:00, bar@stripped +0 -0
    After merge fix
    MERGE: 1.241.1.41

  sql/sql_parse.cc@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.426.1.158

  sql/sql_string.cc@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.91.1.3

  sql/sql_string.h@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.60.1.2

  storage/myisam/mi_open.c@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.90.8.3

  storage/myisam/mi_open.c@stripped, 2006-11-01 13:00:58+04:00, bar@stripped +0 -0
    Merge rename: myisam/mi_open.c -> storage/myisam/mi_open.c

  strings/ctype-bin.c@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.66.1.5

  strings/ctype-mb.c@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.47.1.5

  strings/ctype-simple.c@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.75.1.3

  strings/ctype-ucs2.c@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.50.1.13

  strings/ctype-utf8.c@stripped, 2006-11-01 13:01:00+04:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.97.1.4

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	bar
# Host:	bar.intranet.mysql.r18.ru
# Root:	/usr/home/bar/mysql-5.1-rpl/RESYNC

--- 1.128/include/m_ctype.h	2006-11-01 13:05:37 +04:00
+++ 1.129/include/m_ctype.h	2006-11-01 13:05:37 +04:00
@@ -190,8 +190,8 @@ typedef struct my_charset_handler_st
                const unsigned char *s, const unsigned char *e);
   
   /* Functions for case and sort conversion */
-  void    (*caseup_str)(struct charset_info_st *, char *);
-  void    (*casedn_str)(struct charset_info_st *, char *);
+  uint    (*caseup_str)(struct charset_info_st *, char *);
+  uint    (*casedn_str)(struct charset_info_st *, char *);
   uint    (*caseup)(struct charset_info_st *, char *src, uint srclen,
                                               char *dst, uint dstlen);
   uint    (*casedn)(struct charset_info_st *, char *src, uint srclen,
@@ -324,8 +324,8 @@ extern uint my_instr_simple(struct chars
 
 
 /* Functions for 8bit */
-extern void my_caseup_str_8bit(CHARSET_INFO *, char *);
-extern void my_casedn_str_8bit(CHARSET_INFO *, char *);
+extern uint my_caseup_str_8bit(CHARSET_INFO *, char *);
+extern uint my_casedn_str_8bit(CHARSET_INFO *, char *);
 extern uint my_caseup_8bit(CHARSET_INFO *, char *src, uint srclen,
                                            char *dst, uint dstlen);
 extern uint my_casedn_8bit(CHARSET_INFO *, char *src, uint srclen,
@@ -415,8 +415,8 @@ int my_mbcharlen_8bit(CHARSET_INFO *, ui
 
 
 /* Functions for multibyte charsets */
-extern void my_caseup_str_mb(CHARSET_INFO *, char *);
-extern void my_casedn_str_mb(CHARSET_INFO *, char *);
+extern uint my_caseup_str_mb(CHARSET_INFO *, char *);
+extern uint my_casedn_str_mb(CHARSET_INFO *, char *);
 extern uint my_caseup_mb(CHARSET_INFO *, char *src, uint srclen,
                                          char *dst, uint dstlen);
 extern uint my_casedn_mb(CHARSET_INFO *, char *src, uint srclen,

--- 1.90.8.2/myisam/mi_open.c	2006-11-01 13:05:37 +04:00
+++ 1.106/storage/myisam/mi_open.c	2006-11-01 13:05:37 +04:00
@@ -95,7 +95,8 @@ MI_INFO *mi_open(const char *name, int m
   head_length=sizeof(share_buff.state.header);
   bzero((byte*) &info,sizeof(info));
 
-  my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
+  my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,
+                                   MY_UNPACK_FILENAME),MYF(0));
   pthread_mutex_lock(&THR_LOCK_myisam);
   if (!(old_info=test_if_reopen(name_buff)))
   {
@@ -141,17 +142,27 @@ MI_INFO *mi_open(const char *name, int m
 	~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
 	  HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
 	  HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
-	  HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE))
+          HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
+          HA_OPTION_RELIES_ON_SQL_LAYER))
     {
       DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
       my_errno=HA_ERR_OLD_FILE;
       goto err;
     }
+    if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
+        ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
+    {
+      DBUG_PRINT("error", ("table cannot be openned from non-sql layer"));
+      my_errno= HA_ERR_UNSUPPORTED;
+      goto err;
+    }
     /* Don't call realpath() if the name can't be a link */
     if (!strcmp(name_buff, org_name) ||
         my_readlink(index_name, org_name, MYF(0)) == -1)
       (void) strmov(index_name, org_name);
-    (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,2+4+16);
+    *strrchr(org_name, '.')= '\0';
+    (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,
+                     MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
 
     info_length=mi_uint2korr(share->state.header.header_length);
     base_pos=mi_uint2korr(share->state.header.base_pos);
@@ -197,9 +208,9 @@ MI_INFO *mi_open(const char *name, int m
     if (len != MI_BASE_INFO_SIZE)
     {
       DBUG_PRINT("warning",("saved_base_info_length: %d  base_info_length: %d",
-			    len,MI_BASE_INFO_SIZE))
+			    len,MI_BASE_INFO_SIZE));
     }
-    disk_pos= (char*) 
+    disk_pos= (char*)
       my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base);
     share->state.state_length=base_pos;
 
@@ -287,10 +298,11 @@ MI_INFO *mi_open(const char *name, int m
 			 &share->data_file_name,strlen(data_name)+1,
 			 &share->state.key_root,keys*sizeof(my_off_t),
 			 &share->state.key_del,
-			 (share->state.header.max_block_size*sizeof(my_off_t)),
+			 (share->state.header.max_block_size_index*sizeof(my_off_t)),
 #ifdef THREAD
 			 &share->key_root_lock,sizeof(rw_lock_t)*keys,
 #endif
+			 &share->mmap_lock,sizeof(rw_lock_t),
 			 NullS))
       goto err;
     errpos=4;
@@ -301,7 +313,7 @@ MI_INFO *mi_open(const char *name, int m
 	   (char*) key_root, sizeof(my_off_t)*keys);
     memcpy((char*) share->state.key_del,
 	   (char*) key_del, (sizeof(my_off_t) *
-			     share->state.header.max_block_size));
+			     share->state.header.max_block_size_index));
     strmov(share->unique_file_name, name_buff);
     share->unique_name_length= strlen(name_buff);
     strmov(share->index_file_name,  index_name);
@@ -422,6 +434,7 @@ MI_INFO *mi_open(const char *name, int m
 	pos->flag=0;
 	pos++;
       }
+      share->ftparsers= 0;
     }
 
     disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
@@ -464,7 +477,6 @@ MI_INFO *mi_open(const char *name, int m
 					(keys ? MI_INDEX_BLOCK_MARGIN *
 					 share->blocksize * keys : 0));
     share->blocksize=min(IO_SIZE,myisam_block_size);
-
     share->data_file_type=STATIC_RECORD;
     if (share->options & HA_OPTION_COMPRESS_RECORD)
     {
@@ -482,11 +494,13 @@ MI_INFO *mi_open(const char *name, int m
       share->data_file_type = DYNAMIC_RECORD;
     my_afree((gptr) disk_cache);
     mi_setup_functions(share);
+    share->is_log_table= FALSE;
 #ifdef THREAD
     thr_lock_init(&share->lock);
     VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
     for (i=0; i<keys; i++)
       VOID(my_rwlock_init(&share->key_root_lock[i], NULL));
+    VOID(my_rwlock_init(&share->mmap_lock, NULL));
     if (!thr_lock_inited)
     {
       /* Probably a single threaded program; Don't use concurrent inserts */
@@ -741,6 +755,8 @@ void mi_setup_functions(register MYISAM_
     share->compare_unique=_mi_cmp_static_unique;
     share->calc_checksum= mi_static_checksum;
   }
+  share->file_read= mi_nommap_pread;
+  share->file_write= mi_nommap_pwrite;
   if (!(share->options & HA_OPTION_CHECKSUM))
     share->calc_checksum=0;
   return;
@@ -810,7 +826,7 @@ uint mi_state_info_write(File file, MI_S
   uchar  buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
   uchar *ptr=buff;
   uint	i, keys= (uint) state->header.keys,
-	key_blocks=state->header.max_block_size;
+	key_blocks=state->header.max_block_size_index;
   DBUG_ENTER("mi_state_info_write");
 
   memcpy_fixed(ptr,&state->header,sizeof(state->header));
@@ -876,7 +892,7 @@ uchar *mi_state_info_read(uchar *ptr, MI
   ptr +=sizeof(state->header);
   keys=(uint) state->header.keys;
   key_parts=mi_uint2korr(state->header.key_parts);
-  key_blocks=state->header.max_block_size;
+  key_blocks=state->header.max_block_size_index;
 
   state->open_count = mi_uint2korr(ptr);	ptr +=2;
   state->changed= (bool) *ptr++;
@@ -1049,9 +1065,11 @@ char *mi_keydef_read(char *ptr, MI_KEYDE
    keydef->keylength	= mi_uint2korr(ptr);	ptr +=2;
    keydef->minlength	= mi_uint2korr(ptr);	ptr +=2;
    keydef->maxlength	= mi_uint2korr(ptr);	ptr +=2;
-   keydef->block_size	= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
+   keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
    keydef->underflow_block_length=keydef->block_length/3;
    keydef->version	= 0;			/* Not saved */
+   keydef->parser       = &ft_default_parser;
+   keydef->ftparser_nr  = 0;
    return ptr;
 }
 

--- 1.346/sql/field.cc	2006-11-01 13:05:37 +04:00
+++ 1.347/sql/field.cc	2006-11-01 13:05:37 +04:00
@@ -5922,38 +5922,149 @@ void Field_datetime::sql_type(String &re
 ** A string may be varchar or binary
 ****************************************************************************/
 
+/*
+  Report "not well formed" or "cannot convert" error
+  after storing a character string info a field.
+
+  SYNOPSIS
+    check_string_copy_error()
+    field                    - Field
+    well_formed_error_pos    - where not well formed data was first met
+    cannot_convert_error_pos - where a not-convertable character was first met
+    end                      - end of the string
+
+  NOTES
+    As of version 5.0 both cases return the same error:
+  
+      "Invalid string value: 'xxx' for column 't' at row 1"
+  
+  Future versions will possibly introduce a new error message:
+
+      "Cannot convert character string: 'xxx' for column 't' at row 1"
+
+  RETURN
+    FALSE - If errors didn't happen
+    TRUE  - If an error happened
+*/
+
+static bool
+check_string_copy_error(Field_str *field,
+                        const char *well_formed_error_pos,
+                        const char *cannot_convert_error_pos,
+                        const char *end)
+{
+  const char *pos, *end_orig;
+  char tmp[64], *t;
+  
+  if (!(pos= well_formed_error_pos) &&
+      !(pos= cannot_convert_error_pos))
+    return FALSE;
+
+  end_orig= end;
+  set_if_smaller(end, pos + 6);
+
+  for (t= tmp; pos < end; pos++)
+  {
+    if (((unsigned char) *pos) >= 0x20 &&
+        ((unsigned char) *pos) <= 0x7F)
+    {
+      *t++= *pos;
+    }
+    else
+    {
+      *t++= '\\';
+      *t++= 'x';
+      *t++= _dig_vec_upper[((unsigned char) *pos) >> 4];
+      *t++= _dig_vec_upper[((unsigned char) *pos) & 15];
+    }
+  }
+  if (end_orig > end)
+  {
+    *t++= '.';
+    *t++= '.';
+    *t++= '.';
+  }
+  *t= '\0';
+  push_warning_printf(field->table->in_use, 
+                      field->table->in_use->abort_on_warning ?
+                      MYSQL_ERROR::WARN_LEVEL_ERROR :
+                      MYSQL_ERROR::WARN_LEVEL_WARN,
+                      ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, 
+                      ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+                      "string", tmp, field->field_name,
+                      (ulong) field->table->in_use->row_count);
+  return TRUE;
+}
+
+
+
+/*
+  Send a truncation warning or a truncation error
+  after storing a too long character string info a field.
+
+  SYNOPSIS
+    report_data_too_long()
+    field                    - Field
+
+  RETURN
+    N/A
+*/
+
+inline void
+report_data_too_long(Field_str *field)
+{
+  if (field->table->in_use->abort_on_warning)
+    field->set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+  else
+    field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+}
+
+
+/*
+  Test if the given string contains important data:
+  not spaces for character string,
+  or any data for binary string.
+
+  SYNOPSIS
+    test_if_important_data()
+    cs          Character set
+    str         String to test
+    strend      String end
+
+  RETURN
+    FALSE - If string does not have important data
+    TRUE  - If string has some important data
+*/
+
+static bool
+test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
+{
+  if (cs != &my_charset_bin)
+    str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
+  return (str < strend);
+}
+
+
 	/* Copy a string and fill with space */
 
 int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
 {
   ASSERT_COLUMN_MARKED_FOR_WRITE;
-  int error= 0, well_formed_error;
-  uint32 not_used;
-  char buff[STRING_BUFFER_USUAL_SIZE];
-  String tmpstr(buff,sizeof(buff), &my_charset_bin);
   uint copy_length;
+  const char *well_formed_error_pos;
+  const char *cannot_convert_error_pos;
+  const char *from_end_pos;
 
   /* See the comment for Field_long::store(long long) */
   DBUG_ASSERT(table->in_use == current_thd);
 
-  /* Convert character set if necessary */
-  if (String::needs_conversion(length, cs, field_charset, &not_used))
-  {
-    uint conv_errors;
-    tmpstr.copy(from, length, cs, field_charset, &conv_errors);
-    from= tmpstr.ptr();
-    length= tmpstr.length();
-    if (conv_errors)
-      error= 2;
-  }
-
-  /* Make sure we don't break a multibyte sequence or copy malformed data. */
-  copy_length= field_charset->cset->well_formed_len(field_charset,
-                                                    from,from+length,
-                                                    field_length/
-                                                    field_charset->mbmaxlen,
-                                                    &well_formed_error);
-  memmove(ptr, from, copy_length);
+  copy_length= well_formed_copy_nchars(field_charset,
+                                       ptr, field_length,
+                                       cs, from, length,
+                                       field_length / field_charset->mbmaxlen,
+                                       &well_formed_error_pos,
+                                       &cannot_convert_error_pos,
+                                       &from_end_pos);
 
   /* Append spaces if the string was shorter than the field. */
   if (copy_length < field_length)
@@ -5961,32 +6072,23 @@ int Field_string::store(const char *from
                               field_length-copy_length,
                               field_charset->pad_char);
 
+  if (check_string_copy_error(this, well_formed_error_pos,
+                              cannot_convert_error_pos, from + length))
+    return 2;
+
   /*
     Check if we lost any important data (anything in a binary string,
     or any non-space in others).
   */
-  if ((copy_length < length) && table->in_use->count_cuted_fields)
+  if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
   {
-    if (binary())
-      error= 2;
-    else
+    if (test_if_important_data(field_charset, from_end_pos, from + length))
     {
-      const char *end=from+length;
-      from+= copy_length;
-      from+= field_charset->cset->scan(field_charset, from, end,
-                                       MY_SEQ_SPACES);
-      if (from != end)
-        error= 2;
+      report_data_too_long(this);
+      return 2;
     }
   }
-  if (error)
-  {
-    if (table->in_use->abort_on_warning)
-      set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
-    else
-      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
-  }
-  return error;
+  return 0;
 }
 
 
@@ -6344,58 +6446,35 @@ Field *Field_string::new_field(MEM_ROOT 
 int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
 {
   ASSERT_COLUMN_MARKED_FOR_WRITE;
-  uint32 not_used, copy_length;
-  char buff[STRING_BUFFER_USUAL_SIZE];
-  String tmpstr(buff,sizeof(buff), &my_charset_bin);
-  int error_code= 0, well_formed_error;
-  enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN;
-
-  /* Convert character set if necessary */
-  if (String::needs_conversion(length, cs, field_charset, &not_used))
-  { 
-    uint conv_errors;
-    tmpstr.copy(from, length, cs, field_charset, &conv_errors);
-    from= tmpstr.ptr();
-    length=  tmpstr.length();
-    if (conv_errors)
-      error_code= WARN_DATA_TRUNCATED;
-  }
-  /* 
-    Make sure we don't break a multibyte sequence
-    as well as don't copy a malformed data.
-  */
-  copy_length= field_charset->cset->well_formed_len(field_charset,
-						    from,from+length,
-						    field_length/
-						    field_charset->mbmaxlen,
-                                                    &well_formed_error);
-  memmove(ptr + length_bytes, from, copy_length);
+  uint copy_length;
+  const char *well_formed_error_pos;
+  const char *cannot_convert_error_pos;
+  const char *from_end_pos;
+
+  copy_length= well_formed_copy_nchars(field_charset,
+                                       ptr + length_bytes, field_length,
+                                       cs, from, length,
+                                       field_length / field_charset->mbmaxlen,
+                                       &well_formed_error_pos,
+                                       &cannot_convert_error_pos,
+                                       &from_end_pos);
+
   if (length_bytes == 1)
     *ptr= (uchar) copy_length;
   else
     int2store(ptr, copy_length);
 
+  if (check_string_copy_error(this, well_formed_error_pos,
+                              cannot_convert_error_pos, from + length))
+    return 2;
+
   // Check if we lost something other than just trailing spaces
-  if ((copy_length < length) && table->in_use->count_cuted_fields &&
-      !error_code)
+  if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
   {
-    if (!binary())
-    {
-      const char *end= from + length;
-      from+= copy_length;
-      from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
-      /* If we lost only spaces then produce a NOTE, not a WARNING */
-      if (from == end)
-        level= MYSQL_ERROR::WARN_LEVEL_NOTE;
-    }
-    error_code= WARN_DATA_TRUNCATED;
-  }
-  if (error_code)
-  {
-    if (level == MYSQL_ERROR::WARN_LEVEL_WARN &&
-        table->in_use->abort_on_warning)
-      error_code= ER_DATA_TOO_LONG;
-    set_warning(level, error_code, 1);
+    if (test_if_important_data(field_charset, from_end_pos, from + length))
+      report_data_too_long(this);
+    else /* If we lost only spaces then produce a NOTE, not a WARNING */
+      set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
     return 2;
   }
   return 0;
@@ -7013,68 +7092,64 @@ void Field_blob::put_length(char *pos, u
 int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
 {
   ASSERT_COLUMN_MARKED_FOR_WRITE;
-  int error= 0, well_formed_error;
+
   if (!length)
   {
     bzero(ptr,Field_blob::pack_length());
+    return 0;
   }
-  else
+
+  if (from == value.ptr())
   {
-    bool was_conversion;
-    char buff[STRING_BUFFER_USUAL_SIZE];
-    String tmpstr(buff,sizeof(buff), &my_charset_bin);
-    uint copy_length;
-    uint32 not_used;
-
-    /* Convert character set if necessary */
-    if ((was_conversion= String::needs_conversion(length, cs, field_charset,
-						  &not_used)))
-    { 
-      uint conv_errors;
-      if (tmpstr.copy(from, length, cs, field_charset, &conv_errors))
-      {
-        /* Fatal OOM error */
-        bzero(ptr,Field_blob::pack_length());
-        return -1;
-      }
-      from= tmpstr.ptr();
-      length=  tmpstr.length();
-      if (conv_errors)
-        error= 2;
-    }
-    
-    copy_length= max_data_length();
-    /*
-      copy_length is OK as last argument to well_formed_len as this is never
-      used to limit the length of the data. The cut of long data is done with
-      the 'min()' call below.
-    */
-    copy_length= field_charset->cset->well_formed_len(field_charset,
-                                                      from,from +
-                                                      min(length, copy_length),
-                                                      copy_length,
-                                                      &well_formed_error);
-    if (copy_length < length)
-      error= 2;
-    Field_blob::store_length(copy_length);
-    if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH)
-    {						// Must make a copy
-      if (from != value.ptr())			// For valgrind
-      {
-	value.copy(from,copy_length,charset());
-	from=value.ptr();
-      }
+    uint32 dummy_offset;
+    if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
+    {
+      Field_blob::store_length(length);
+      bmove(ptr+packlength,(char*) &from,sizeof(char*));
+      return 0;
     }
-    bmove(ptr+packlength,(char*) &from,sizeof(char*));
+    if (tmpstr.copy(from, length, cs))
+      goto oom_error;
+    from= tmpstr.ptr();
   }
-  if (error)
+
+  new_length= min(max_data_length(), field_charset->mbmaxlen * length);
+  if (value.alloc(new_length))
+    goto oom_error;
+
+  /*
+    "length" is OK as "nchars" argument to well_formed_copy_nchars as this
+    is never used to limit the length of the data. The cut of long data
+    is done with the new_length value.
+  */
+  copy_length= well_formed_copy_nchars(field_charset,
+                                       (char*) value.ptr(), new_length,
+                                       cs, from, length,
+                                       length,
+                                       &well_formed_error_pos,
+                                       &cannot_convert_error_pos,
+                                       &from_end_pos);
+
+  Field_blob::store_length(copy_length);
+  tmp= value.ptr();
+  bmove(ptr+packlength,(char*) &tmp,sizeof(char*));
+
+  if (check_string_copy_error(this, well_formed_error_pos,
+                              cannot_convert_error_pos, from + length))
+    return 2;
+
+  if (copy_length < length)
   {
-    if (table->in_use->abort_on_warning)
-      set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
-    else
-      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+    report_data_too_long(this);
+    return 2;
   }
+
   return 0;
+
+oom_error:
+  /* Fatal OOM error */
+  bzero(ptr,Field_blob::pack_length());
+  return -1; 
 }
 
 

--- 1.585/sql/sql_parse.cc	2006-11-01 13:05:37 +04:00
+++ 1.586/sql/sql_parse.cc	2006-11-01 13:05:37 +04:00
@@ -2543,7 +2543,23 @@ mysql_execute_command(THD *thd)
     {
       /* we warn the slave SQL thread */
       my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
-      reset_one_shot_variables(thd);
+      if (thd->one_shot_set)
+      {
+        /*
+          It's ok to check thd->one_shot_set here:
+
+          The charsets in a MySQL 5.0 slave can change by both a binlogged
+          SET ONE_SHOT statement and the event-internal charset setting, 
+          and these two ways to change charsets do not seems to work
+          together.
+
+          At least there seems to be problems in the rli cache for
+          charsets if we are using ONE_SHOT.  Note that this is normally no
+          problem because either the >= 5.0 slave reads a 4.1 binlog (with
+          ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
+        */
+        reset_one_shot_variables(thd);
+      }
       DBUG_RETURN(0);
     }
   }
@@ -6358,7 +6374,7 @@ TABLE_LIST *st_select_lex::add_table_to_
 
   ptr->alias= alias_str;
   if (lower_case_table_names && table->table.length)
-    my_casedn_str(files_charset_info, table->table.str);
+    table->table.length= my_casedn_str(files_charset_info, table->table.str);
   ptr->table_name=table->table.str;
   ptr->table_name_length=table->table.length;
   ptr->lock_type=   lock_type;

--- 1.97/sql/sql_string.cc	2006-11-01 13:05:37 +04:00
+++ 1.98/sql/sql_string.cc	2006-11-01 13:05:37 +04:00
@@ -844,6 +844,162 @@ outp:
 }
 
 
+/*
+  copy a string,
+  with optional character set conversion,
+  with optional left padding (for binary -> UCS2 conversion)
+  
+  SYNOPSIS
+    well_formed_copy_nhars()
+    to			     Store result here
+    to_length                Maxinum length of "to" string
+    to_cs		     Character set of "to" string
+    from		     Copy from here
+    from_length		     Length of from string
+    from_cs		     From character set
+    nchars                   Copy not more that nchars characters
+    well_formed_error_pos    Return position when "from" is not well formed
+                             or NULL otherwise.
+    cannot_convert_error_pos Return position where a not convertable
+                             character met, or NULL otherwise.
+    from_end_pos             Return position where scanning of "from"
+                             string stopped.
+  NOTES
+
+  RETURN
+    length of bytes copied to 'to'
+*/
+
+
+uint32
+well_formed_copy_nchars(CHARSET_INFO *to_cs,
+                        char *to, uint to_length,
+                        CHARSET_INFO *from_cs,
+                        const char *from, uint from_length,
+                        uint nchars,
+                        const char **well_formed_error_pos,
+                        const char **cannot_convert_error_pos,
+                        const char **from_end_pos)
+{
+  uint res;
+
+  if ((to_cs == &my_charset_bin) || 
+      (from_cs == &my_charset_bin) ||
+      (to_cs == from_cs) ||
+      my_charset_same(from_cs, to_cs))
+  {
+    if (to_length < to_cs->mbminlen || !nchars)
+    {
+      *from_end_pos= from;
+      *cannot_convert_error_pos= NULL;
+      *well_formed_error_pos= NULL;
+      return 0;
+    }
+
+    if (to_cs == &my_charset_bin)
+    {
+      res= min(min(nchars, to_length), from_length);
+      memmove(to, from, res);
+      *from_end_pos= from + res;
+      *well_formed_error_pos= NULL;
+      *cannot_convert_error_pos= NULL;
+    }
+    else
+    {
+      int well_formed_error;
+      uint from_offset;
+
+      if ((from_offset= (from_length % to_cs->mbminlen)) &&
+          (from_cs == &my_charset_bin))
+      {
+        /*
+          Copying from BINARY to UCS2 needs to prepend zeros sometimes:
+          INSERT INTO t1 (ucs2_column) VALUES (0x01);
+          0x01 -> 0x0001
+        */
+        uint pad_length= to_cs->mbminlen - from_offset;
+        bzero(to, pad_length);
+        memmove(to + pad_length, from, from_offset);
+        nchars--;
+        from+= from_offset;
+        from_length-= from_offset;
+        to+= to_cs->mbminlen;
+        to_length-= to_cs->mbminlen;
+      }
+
+      set_if_smaller(from_length, to_length);
+      res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
+                                        nchars, &well_formed_error);
+      memmove(to, from, res);
+      *from_end_pos= from + res;
+      *well_formed_error_pos= well_formed_error ? from + res : NULL;
+      *cannot_convert_error_pos= NULL;
+      if (from_offset)
+        res+= to_cs->mbminlen;
+    }
+  }
+  else
+  {
+    int cnvres;
+    my_wc_t wc;
+    int (*mb_wc)(struct charset_info_st *, my_wc_t *,
+                 const uchar *, const uchar *)= from_cs->cset->mb_wc;
+    int (*wc_mb)(struct charset_info_st *, my_wc_t,
+                 uchar *s, uchar *e)= to_cs->cset->wc_mb;
+    const uchar *from_end= (const uchar*) from + from_length;
+    uchar *to_end= (uchar*) to + to_length;
+    char *to_start= to;
+    *well_formed_error_pos= NULL;
+    *cannot_convert_error_pos= NULL;
+
+    for ( ; nchars; nchars--)
+    {
+      const char *from_prev= from;
+      if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
+        from+= cnvres;
+      else if (cnvres == MY_CS_ILSEQ)
+      {
+        if (!*well_formed_error_pos)
+          *well_formed_error_pos= from;
+        from++;
+        wc= '?';
+      }
+      else if (cnvres > MY_CS_TOOSMALL)
+      {
+        /*
+          A correct multibyte sequence detected
+          But it doesn't have Unicode mapping.
+        */
+        if (!*cannot_convert_error_pos)
+          *cannot_convert_error_pos= from;
+        from+= (-cnvres);
+        wc= '?';
+      }
+      else
+        break;  // Not enough characters
+
+outp:
+      if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
+        to+= cnvres;
+      else if (cnvres == MY_CS_ILUNI && wc != '?')
+      {
+        if (!*cannot_convert_error_pos)
+          *cannot_convert_error_pos= from_prev;
+        wc= '?';
+        goto outp;
+      }
+      else
+        break;
+    }
+    *from_end_pos= from;
+    res= to - to_start;
+  }
+  return (uint32) res;
+}
+
+
+
+
 void String::print(String *str)
 {
   char *st= (char*)Ptr, *end= st+str_length;

--- 1.64/sql/sql_string.h	2006-11-01 13:05:37 +04:00
+++ 1.65/sql/sql_string.h	2006-11-01 13:05:38 +04:00
@@ -30,6 +30,14 @@ String *copy_if_not_alloced(String *a,St
 uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
 			const char *from, uint32 from_length,
 			CHARSET_INFO *from_cs, uint *errors);
+uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs,
+                               char *to, uint to_length,
+                               CHARSET_INFO *from_cs,
+                               const char *from, uint from_length,
+                               uint nchars,
+                               const char **well_formed_error_pos,
+                               const char **cannot_convert_error_pos,
+                               const char **from_end_pos);
 
 class String
 {

--- 1.2/mysql-test/r/strict_autoinc_1myisam.result	2006-11-01 13:05:38 +04:00
+++ 1.3/mysql-test/r/strict_autoinc_1myisam.result	2006-11-01 13:05:38 +04:00
@@ -1,3 +1,4 @@
+drop table if exists t1;
 set @org_mode=@@sql_mode;
 create table t1
 (

--- 1.2/mysql-test/r/strict_autoinc_2innodb.result	2006-11-01 13:05:38 +04:00
+++ 1.3/mysql-test/r/strict_autoinc_2innodb.result	2006-11-01 13:05:38 +04:00
@@ -1,3 +1,4 @@
+drop table if exists t1;
 set @org_mode=@@sql_mode;
 create table t1
 (

--- 1.2/mysql-test/r/strict_autoinc_3heap.result	2006-11-01 13:05:38 +04:00
+++ 1.3/mysql-test/r/strict_autoinc_3heap.result	2006-11-01 13:05:38 +04:00
@@ -1,3 +1,4 @@
+drop table if exists t1;
 set @org_mode=@@sql_mode;
 create table t1
 (

--- 1.2/mysql-test/r/strict_autoinc_4bdb.result	2006-11-01 13:05:38 +04:00
+++ 1.3/mysql-test/r/strict_autoinc_4bdb.result	2006-11-01 13:05:38 +04:00
@@ -1,3 +1,4 @@
+drop table if exists t1;
 set @org_mode=@@sql_mode;
 create table t1
 (

--- 1.2/mysql-test/r/strict_autoinc_5ndb.result	2006-11-01 13:05:38 +04:00
+++ 1.3/mysql-test/r/strict_autoinc_5ndb.result	2006-11-01 13:05:38 +04:00
@@ -1,3 +1,4 @@
+drop table if exists t1;
 set @org_mode=@@sql_mode;
 create table t1
 (

--- 1.2/mysql-test/t/rpl_ignore_table.test	2006-11-01 13:05:38 +04:00
+++ 1.3/mysql-test/t/rpl_ignore_table.test	2006-11-01 13:05:38 +04:00
@@ -28,3 +28,27 @@ connection master;
 DROP TABLE t1;
 DROP TABLE t4;
 sync_slave_with_master;
+
+
+#
+# bug#22877 replication character sets get out of sync
+# using replicate-wild-ignore-table
+#
+--disable_warnings
+DROP TABLE IF EXISTS t5;
+--enable_warnings
+CREATE TABLE t5 (
+ word varchar(50) collate utf8_unicode_ci NOT NULL default ''
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+SET @@session.character_set_client=33,@@session.collation_connection=192;
+CREATE TEMPORARY TABLE tmptbl504451f4258$1 (id INT NOT NULL) ENGINE=MEMORY;
+INSERT INTO t5 (word)  VALUES ('TEST’');
+SELECT HEX(word) FROM t5;
+sync_slave_with_master;
+connection slave;
+SELECT HEX(word) FROM t5;
+--error 1146
+SELECT * FROM tmptbl504451f4258$1;
+connection master;
+DROP TABLE t5;
+sync_slave_with_master;

--- 1.34/mysql-test/r/ctype_recoding.result	2006-11-01 13:05:38 +04:00
+++ 1.35/mysql-test/r/ctype_recoding.result	2006-11-01 13:05:38 +04:00
@@ -171,8 +171,8 @@ create table t1 (a char(10) character se
 insert into t1 values ('test','test');
 Warnings:
-Warning	1265	Data truncated for column 'a' at row 1
-Warning	1265	Data truncated for column 'b' at row 1
+Warning	1366	Incorrect string value: '\xCA\xC3\xD5\xCB' for column 'a' at row 1
+Warning	1366	Incorrect string value: '\xCA\xC3\xD5\xCB' for column 'b' at row 1
 drop table t1;
 set names koi8r;
 create table t1 (a char(10) character set cp1251);

--- 1.106/mysql-test/r/ctype_utf8.result	2006-11-01 13:05:38 +04:00
+++ 1.107/mysql-test/r/ctype_utf8.result	2006-11-01 13:05:38 +04:00
@@ -197,7 +197,7 @@ drop table t1;
 create table t1 (s1 char(10) character set utf8);
 insert into t1 values (0x41FF);
 Warnings:
-Warning	1265	Data truncated for column 's1' at row 1
+Warning	1366	Incorrect string value: '\xFF' for column 's1' at row 1
 select hex(s1) from t1;
 hex(s1)
 41
@@ -205,7 +205,7 @@ drop table t1;
 create table t1 (s1 varchar(10) character set utf8);
 insert into t1 values (0x41FF);
 Warnings:
-Warning	1265	Data truncated for column 's1' at row 1
+Warning	1366	Incorrect string value: '\xFF' for column 's1' at row 1
 select hex(s1) from t1;
 hex(s1)
 41
@@ -213,7 +213,7 @@ drop table t1;
 create table t1 (s1 text character set utf8);
 insert into t1 values (0x41FF);
 Warnings:
-Warning	1265	Data truncated for column 's1' at row 1
+Warning	1366	Incorrect string value: '\xFF' for column 's1' at row 1
 select hex(s1) from t1;
 hex(s1)
 41

--- 1.72/strings/ctype-bin.c	2006-11-01 13:05:38 +04:00
+++ 1.73/strings/ctype-bin.c	2006-11-01 13:05:38 +04:00
@@ -211,9 +211,10 @@ static int my_strnncollsp_8bit_bin(CHARS
 
 /* This function is used for all conversion functions */
 
-static void my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
+static uint my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
 			    char *str __attribute__((unused)))
 {
+  return 0;
 }
 
 static uint my_case_bin(CHARSET_INFO *cs __attribute__((unused)),

--- 1.63/strings/ctype-ucs2.c	2006-11-01 13:05:38 +04:00
+++ 1.64/strings/ctype-ucs2.c	2006-11-01 13:05:38 +04:00
@@ -159,13 +159,13 @@ static void my_hash_sort_ucs2(CHARSET_IN
 }
 
 
-static void my_caseup_str_ucs2(CHARSET_INFO * cs  __attribute__((unused)), 
+static uint my_caseup_str_ucs2(CHARSET_INFO * cs  __attribute__((unused)), 
 			       char * s __attribute__((unused)))
 {
+  return 0;
 }
 
 
-
 static uint my_casedn_ucs2(CHARSET_INFO *cs, char *src, uint srclen,
                            char *dst __attribute__((unused)),
                            uint dstlen __attribute__((unused)))
@@ -188,9 +188,11 @@ static uint my_casedn_ucs2(CHARSET_INFO 
   return srclen;
 }
 
-static void my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)), 
+
+static uint my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)), 
 			       char * s __attribute__((unused)))
 {
+  return 0;
 }
 
 

--- 1.53/strings/ctype-mb.c	2006-11-01 13:05:38 +04:00
+++ 1.54/strings/ctype-mb.c	2006-11-01 13:05:38 +04:00
@@ -21,40 +21,44 @@
 #ifdef USE_MB
 
 
-void my_caseup_str_mb(CHARSET_INFO * cs, char *str)
+uint my_caseup_str_mb(CHARSET_INFO * cs, char *str)
 {
   register uint32 l;
-  register uchar *map=cs->to_upper;
+  register uchar *map= cs->to_upper;
+  char *str_orig= str;
   
   while (*str)
   {
     /* Pointing after the '\0' is safe here. */
-    if ((l=my_ismbchar(cs, str, str + cs->mbmaxlen)))
-      str+=l;
+    if ((l= my_ismbchar(cs, str, str + cs->mbmaxlen)))
+      str+= l;
     else
     { 
-      *str=(char) map[(uchar)*str];
+      *str= (char) map[(uchar)*str];
       str++;
     }
   }
+  return str - str_orig;
 }
 
-void my_casedn_str_mb(CHARSET_INFO * cs, char *str)
+uint my_casedn_str_mb(CHARSET_INFO * cs, char *str)
 {
   register uint32 l;
-  register uchar *map=cs->to_lower;
+  register uchar *map= cs->to_lower;
+  char *str_orig= str;
   
   while (*str)
   {
     /* Pointing after the '\0' is safe here. */
-    if ((l=my_ismbchar(cs, str, str + cs->mbmaxlen)))
-      str+=l;
+    if ((l= my_ismbchar(cs, str, str + cs->mbmaxlen)))
+      str+= l;
     else
     {
-      *str=(char) map[(uchar)*str];
+      *str= (char) map[(uchar)*str];
       str++;
     }
   }
+  return str - str_orig;
 }
 
 uint my_caseup_mb(CHARSET_INFO * cs, char *src, uint srclen,

--- 1.80/strings/ctype-simple.c	2006-11-01 13:05:38 +04:00
+++ 1.81/strings/ctype-simple.c	2006-11-01 13:05:38 +04:00
@@ -188,19 +188,25 @@ int my_strnncollsp_simple(CHARSET_INFO *
 }
 
 
-void my_caseup_str_8bit(CHARSET_INFO * cs,char *str)
+uint my_caseup_str_8bit(CHARSET_INFO * cs,char *str)
 {
-  register uchar *map=cs->to_upper;
-  while ((*str = (char) map[(uchar) *str]) != 0)
+  register uchar *map= cs->to_upper;
+  char *str_orig= str;
+  while ((*str= (char) map[(uchar) *str]) != 0)
     str++;
+  return str - str_orig;
 }
 
-void my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
+
+uint my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
 {
-  register uchar *map=cs->to_lower;
-  while ((*str = (char) map[(uchar)*str]) != 0)
+  register uchar *map= cs->to_lower;
+  char *str_orig= str;
+  while ((*str= (char) map[(uchar) *str]) != 0)
     str++;
+  return str - str_orig;
 }
+
 
 uint my_caseup_8bit(CHARSET_INFO * cs, char *src, uint srclen,
                     char *dst __attribute__((unused)),

--- 1.105/strings/ctype-utf8.c	2006-11-01 13:05:38 +04:00
+++ 1.106/strings/ctype-utf8.c	2006-11-01 13:05:38 +04:00
@@ -2047,6 +2047,52 @@ static int my_utf8_uni(CHARSET_INFO *cs 
   return MY_CS_ILSEQ;
 }
 
+
+/*
+  The same as above, but without range check
+  for example, for a null-terminated string
+*/
+static int my_utf8_uni_no_range(CHARSET_INFO *cs __attribute__((unused)),
+                                my_wc_t * pwc, const uchar *s)
+{
+  unsigned char c;
+
+  c= s[0];
+  if (c < 0x80)
+  {
+    *pwc = c;
+    return 1;
+  }
+
+  if (c < 0xc2)
+    return MY_CS_ILSEQ;
+
+  if (c < 0xe0)
+  {
+    if (!((s[1] ^ 0x80) < 0x40))
+      return MY_CS_ILSEQ;
+
+    *pwc = ((my_wc_t) (c & 0x1f) << 6) | (my_wc_t) (s[1] ^ 0x80);
+    return 2;
+  }
+  
+  if (c < 0xf0)
+  {
+    if (!((s[1] ^ 0x80) < 0x40 &&
+          (s[2] ^ 0x80) < 0x40 &&
+          (c >= 0xe1 || s[1] >= 0xa0)))
+      return MY_CS_ILSEQ;
+
+    *pwc= ((my_wc_t) (c & 0x0f) << 12)   |
+          ((my_wc_t) (s[1] ^ 0x80) << 6) |
+           (my_wc_t) (s[2] ^ 0x80);
+
+    return 3;
+  }
+  return MY_CS_ILSEQ;
+}
+
+
 static int my_uni_utf8 (CHARSET_INFO *cs __attribute__((unused)) ,
                  my_wc_t wc, uchar *r, uchar *e)
 {
@@ -2093,6 +2139,34 @@ static int my_uni_utf8 (CHARSET_INFO *cs
 }
 
 
+/*
+  The same as above, but without range check.
+*/
+static int my_uni_utf8_no_range(CHARSET_INFO *cs __attribute__((unused)),
+                                my_wc_t wc, uchar *r)
+{
+  int count;
+
+  if (wc < 0x80)
+    count= 1;
+  else if (wc < 0x800)
+    count= 2;
+  else if (wc < 0x10000)
+    count= 3;
+  else
+    return MY_CS_ILUNI;
+
+  switch (count)
+  {
+    /* Fall through all cases!!! */
+    case 3: r[2]= (uchar) (0x80 | (wc & 0x3f)); wc= wc >> 6; wc |= 0x800;
+    case 2: r[1]= (uchar) (0x80 | (wc & 0x3f)); wc= wc >> 6; wc |= 0xc0;
+    case 1: r[0]= (uchar) wc;
+  }
+  return count;
+}
+
+
 static uint my_caseup_utf8(CHARSET_INFO *cs, char *src, uint srclen,
                                              char *dst, uint dstlen)
 {
@@ -2143,10 +2217,26 @@ static void my_hash_sort_utf8(CHARSET_IN
 }
 
 
-static void my_caseup_str_utf8(CHARSET_INFO * cs, char * s)
+static uint my_caseup_str_utf8(CHARSET_INFO *cs, char *src)
 {
-  uint len= (uint) strlen(s);
-  my_caseup_utf8(cs, s, len, s, len);
+  my_wc_t wc;
+  int srcres, dstres;
+  char *dst= src, *dst0= src;
+  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
+  DBUG_ASSERT(cs->caseup_multiply == 1);
+
+  while (*src &&
+         (srcres= my_utf8_uni_no_range(cs, &wc, (uchar *) src)) > 0)
+  {
+    int plane= (wc>>8) & 0xFF;
+    wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].toupper : wc;
+    if ((dstres= my_uni_utf8_no_range(cs, wc, (uchar*) dst)) <= 0)
+      break;
+    src+= srcres;
+    dst+= dstres;
+  }
+  *dst= '\0';
+  return (uint) (dst - dst0);
 }
 
 
@@ -2172,10 +2262,43 @@ static uint my_casedn_utf8(CHARSET_INFO 
   return (uint) (dst - dst0);
 }
 
-static void my_casedn_str_utf8(CHARSET_INFO *cs, char * s)
+
+static uint my_casedn_str_utf8(CHARSET_INFO *cs, char *src)
 {
-  uint len= (uint) strlen(s);
-  my_casedn_utf8(cs, s, len, s, len);
+  my_wc_t wc;
+  int srcres, dstres;
+  char *dst= src, *dst0= src;
+  MY_UNICASE_INFO **uni_plane= cs->caseinfo;
+  DBUG_ASSERT(cs->casedn_multiply == 1);
+
+  while (*src &&
+         (srcres= my_utf8_uni_no_range(cs, &wc, (uchar *) src)) > 0)
+  {
+    int plane= (wc>>8) & 0xFF;
+    wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].tolower : wc;
+    if ((dstres= my_uni_utf8_no_range(cs, wc, (uchar*) dst)) <= 0)
+      break;
+    src+= srcres;
+    dst+= dstres;
+  }
+
+  /*
+   In rare cases lower string can be shorter than
+   the original string, for example:
+
+   "U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE"
+   (which is 0xC4B0 in utf8, i.e. two bytes)
+
+   is converted into
+
+   "U+0069 LATIN SMALL LETTER I"
+   (which is 0x69 in utf8, i.e. one byte)
+
+   So, we need to put '\0' terminator after converting.
+  */
+
+  *dst= '\0';
+  return (uint) (dst - dst0);
 }
 
 

--- 1.9/BitKeeper/etc/collapsed	2006-11-01 13:05:38 +04:00
+++ 1.10/BitKeeper/etc/collapsed	2006-11-01 13:05:38 +04:00
@@ -7,3 +7,5 @@
 4513d8e4Af4dQWuk13sArwofRgFDQw
 4519a6c5BVUxEHTf5iJnjZkixMBs8g
 451ab499rgdjXyOnUDqHu-wBDoS-OQ
+452c6c6dAjuNghfc1ObZ_UQ5SCl85g
+4538a7b0EbDHHkWPbIwxO6ZIDdg6Dg

--- 1.90/mysql-test/r/fulltext.result	2006-11-01 13:05:38 +04:00
+++ 1.91/mysql-test/r/fulltext.result	2006-11-01 13:05:38 +04:00
@@ -381,10 +381,10 @@ t	collation(t)	FORMAT(MATCH t AGAINST ('
 alter table t1 modify t varchar(200) collate latin1_german2_ci not null;
 Warnings:
-Warning	1265	Data truncated for column 't' at row 3
-Warning	1265	Data truncated for column 't' at row 4
-Warning	1265	Data truncated for column 't' at row 5
-Warning	1265	Data truncated for column 't' at row 6
+Warning	1366	Incorrect string value: '\xD0\xAD\xD1\x82\xD0\xBE...' for column 't' at row 3
+Warning	1366	Incorrect string value: '\xD0\x9E\xD1\x82\xD0\xBB...' for column 't' at row 4
+Warning	1366	Incorrect string value: '\xD0\x9D\xD0\xB5 \xD0...' for column 't' at row 5
+Warning	1366	Incorrect string value: '\xD0\xB8 \xD0\xB1\xD1...' for column 't' at row 6
 t	collation(t)
Thread
bk commit into 5.1 tree (bar:1.2326)bar1 Nov