List:Internals« Previous MessageNext Message »
From:Heikki Tuuri Date:March 15 2005 10:03pm
Subject:bk commit into 5.0 tree (heikki:1.1817)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of heikki. When heikki 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
  1.1817 05/03/16 00:03:34 heikki@stripped +11 -0
  Many files:
    InnoDB true VARCHAR

  innobase/trx/trx0trx.c
    1.53 05/03/16 00:01:44 heikki@stripped +1 -1
    InnoDB true VARCHAR

  innobase/row/row0sel.c
    1.77 05/03/16 00:00:57 heikki@stripped +72 -59
    InnoDB true VARCHAR

  innobase/row/row0mysql.c
    1.103 05/03/16 00:00:57 heikki@stripped +230 -22
    InnoDB true VARCHAR

  innobase/row/row0ins.c
    1.65 05/03/16 00:00:57 heikki@stripped +4 -0
    InnoDB true VARCHAR

  innobase/include/row0mysql.ic
    1.9 05/03/16 00:00:07 heikki@stripped +0 -146
    InnoDB true VARCHAR

  innobase/include/data0type.ic
    1.20 05/03/16 00:00:06 heikki@stripped +13 -0
    InnoDB true VARCHAR

  innobase/include/row0mysql.h
    1.39 05/03/16 00:00:02 heikki@stripped +61 -41
    InnoDB true VARCHAR

  innobase/include/que0que.h
    1.12 05/03/16 00:00:02 heikki@stripped +2 -1
    InnoDB true VARCHAR

  innobase/include/data0type.h
    1.18 05/03/16 00:00:01 heikki@stripped +20 -1
    InnoDB true VARCHAR

  sql/ha_innodb.cc
    1.176 05/03/15 23:59:47 heikki@stripped +236 -110
    InnoDB true VARCHAR

  sql/ha_innodb.h
    1.88 05/03/15 23:59:43 heikki@stripped +13 -8
    InnoDB true VARCHAR

# 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:	heikki
# Host:	hundin.mysql.fi
# Root:	/home/heikki/mysql-5.0

--- 1.17/innobase/include/data0type.h	Thu Feb 17 17:15:21 2005
+++ 1.18/innobase/include/data0type.h	Wed Mar 16 00:00:01 2005
@@ -24,7 +24,11 @@
 /*-------------------------------------------*/
 /* The 'MAIN TYPE' of a column */
 #define	DATA_VARCHAR	1	/* character varying of the
-				latin1_swedish_ci charset-collation */
+				latin1_swedish_ci charset-collation; note
+				that the MySQL format for this, DATA_BINARY,
+				DATA_VARMYSQL, is also affected by whether the
+				'precise type' contains
+				DATA_MYSQL_TRUE_VARCHAR */
 #define DATA_CHAR	2	/* fixed length character of the
 				latin1_swedish_ci charset-collation */
 #define DATA_FIXBINARY	3	/* binary string of fixed length */
@@ -102,6 +106,8 @@
 
 #define DATA_MYSQL_TYPE_MASK 255 /* AND with this mask to extract the MySQL
 				 type from the precise type */
+#define DATA_MYSQL_TRUE_VARCHAR 15 /* MySQL type code for the >= 5.0.3
+				   format true VARCHAR */
 
 /* Precise data types for system columns and the length of those columns;
 NOTE: the values must run from 0 up in the order given! All codes must
@@ -134,6 +140,10 @@
 				In earlier versions this was set for some
 				BLOB columns.
 */
+#define	DATA_LONG_TRUE_VARCHAR 4096	/* this is ORed to the precise data
+				type when the column is true VARCHAR where
+				MySQL uses 2 bytes to store the data len;
+				for shorter VARCHARs MySQL uses only 1 byte */
 /*-------------------------------------------*/
 
 /* This many bytes we need to store the type information affecting the
@@ -144,6 +154,15 @@
 store the charset-collation number; one byte is left unused, though */
 #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE	6
 
+/*************************************************************************
+Gets the MySQL type code from a dtype. */
+UNIV_INLINE
+ulint
+dtype_get_mysql_type(
+/*=================*/
+				/* out: MySQL type code; this is NOT an InnoDB
+				type code! */
+	dtype_t*	type);	/* in: type struct */
 /*************************************************************************
 Determine how many bytes the first n characters of the given string occupy.
 If the string is shorter than n characters, returns the number of bytes

--- 1.19/innobase/include/data0type.ic	Thu Feb 17 18:40:36 2005
+++ 1.20/innobase/include/data0type.ic	Wed Mar 16 00:00:06 2005
@@ -33,6 +33,19 @@
 }
 
 /*************************************************************************
+Gets the MySQL type code from a dtype. */
+UNIV_INLINE
+ulint
+dtype_get_mysql_type(
+/*=================*/
+				/* out: MySQL type code; this is NOT an InnoDB
+				type code! */
+	dtype_t*	type)	/* in: type struct */
+{
+	return(type->prtype & 0xFFUL);
+}
+
+/*************************************************************************
 Sets the mbminlen and mbmaxlen members of a data type structure. */
 UNIV_INLINE
 void

--- 1.11/innobase/include/que0que.h	Fri Dec 24 14:03:08 2004
+++ 1.12/innobase/include/que0que.h	Wed Mar 16 00:00:02 2005
@@ -359,7 +359,8 @@
 					the control came */
 	ulint		resource;	/* resource usage of the query thread
 					thus far */
-  ulint   lock_state;	/* lock state of thread (table or row) */
+  	ulint   	lock_state;	/* lock state of thread (table or
+					row) */
 };
 
 #define QUE_THR_MAGIC_N		8476583

--- 1.38/innobase/include/row0mysql.h	Thu Feb 17 17:15:21 2005
+++ 1.39/innobase/include/row0mysql.h	Wed Mar 16 00:00:02 2005
@@ -22,36 +22,6 @@
 typedef struct row_prebuilt_struct row_prebuilt_t;
 
 /***********************************************************************
-Stores a variable-length field (like VARCHAR) length to dest, in the
-MySQL format. */
-UNIV_INLINE
-byte*
-row_mysql_store_var_len(
-/*====================*/
-			/* out: dest + 2 */
-	byte*	dest,	/* in: where to store */
-	ulint	len);	/* in: length, must fit in two bytes */
-/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. */
-UNIV_INLINE
-byte*
-row_mysql_read_var_ref(
-/*===================*/
-			/* out: field + 2 */
-	ulint*	len,	/* out: variable-length field length */
-	byte*	field);	/* in: field */
-/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. */
-
-byte*
-row_mysql_read_var_ref_noninline(
-/*=============================*/
-			/* out: field + 2 */
-	ulint*	len,	/* out: variable-length field length */
-	byte*	field);	/* in: field */
-/***********************************************************************
 Frees the blob heap in prebuilt when no longer needed. */
 
 void
@@ -60,6 +30,30 @@
 	row_prebuilt_t*	prebuilt);	/* in: prebuilt struct of a
 					ha_innobase:: table handle */
 /***********************************************************************
+Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
+format. */
+
+byte*
+row_mysql_store_true_var_len(
+/*=========================*/
+			/* out: pointer to the data, we skip the 1 or 2 bytes
+			at the start that are used to store the len */
+	byte*	dest,	/* in: where to store */
+	ulint	len,	/* in: length, must fit in two bytes */
+	ulint	lenlen);/* in: storage length of len: either 1 or 2 bytes */
+/***********************************************************************
+Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
+returns a pointer to the data. */
+
+byte*
+row_mysql_read_true_varchar(
+/*========================*/
+			/* out: pointer to the data, we skip the 1 or 2 bytes
+			at the start that are used to store the len */
+	ulint*	len,	/* out: variable-length field length */
+	byte*	field,	/* in: field in the MySQL format */
+	ulint	lenlen);/* in: storage length of len: either 1 or 2 bytes */
+/***********************************************************************
 Stores a reference to a BLOB in the MySQL format. */
 
 void
@@ -83,24 +77,40 @@
 	ulint	col_len);	/* in: BLOB reference length (not BLOB
 				length) */
 /******************************************************************
-Stores a non-SQL-NULL field given in the MySQL format in the Innobase
-format. */
-UNIV_INLINE
-void
+Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
+The counterpart of this function is row_sel_field_store_in_mysql_format() in
+row0sel.c. */
+
+byte*
 row_mysql_store_col_in_innobase_format(
 /*===================================*/
-	dfield_t*	dfield,		/* in/out: dfield */
-	byte*		buf,		/* in/out: buffer for the converted
-					value */
+					/* out: up to which byte we used
+					buf in the conversion */
+	dfield_t*	dfield,		/* in/out: dfield where dtype
+					information must be already set when
+					this function is called! */
+	byte*		buf,		/* in/out: buffer for a converted
+					integer value; this must be at least
+					col_len long then! */
+	ibool		row_format_col,	/* TRUE if the mysql_data is from
+					a MySQL row, FALSE if from a MySQL
+					key value;
+					in MySQL, a true VARCHAR storage
+					format differs in a row and in a
+					key value: in a key value the length
+					is always stored in 2 bytes! */
 	byte*		mysql_data,	/* in: MySQL column value, not
 					SQL NULL; NOTE that dfield may also
 					get a pointer to mysql_data,
 					therefore do not discard this as long
 					as dfield is used! */
-	ulint		col_len,	/* in: MySQL column length */
-	ulint		type,		/* in: data type */
-	bool		comp,		/* in: TRUE=compact format */
-	ulint		is_unsigned);	/* in: != 0 if unsigned integer type */
+	ulint		col_len,	/* in: MySQL column length; NOTE that
+					this is the storage length of the
+					column in the MySQL format row, not
+					necessarily the length of the actual
+					payload data; if the column is a true
+					VARCHAR then this is irrelevant */
+	ibool		comp);		/* in: TRUE = compact format */
 /********************************************************************
 Handles user errors and lock waits detected by the database engine. */
 
@@ -457,6 +467,16 @@
 					zero if column cannot be NULL */
 	ulint	type;			/* column type in Innobase mtype
 					numbers DATA_CHAR... */
+	ulint	mysql_type;		/* MySQL type code; this is always
+					< 256 */
+	ulint	mysql_length_bytes;	/* if mysql_type
+					== DATA_MYSQL_TRUE_VARCHAR, this tells
+					whether we should use 1 or 2 bytes to
+					store the MySQL true VARCHAR data
+					length at the start of row in the MySQL
+					format (NOTE that the MySQL key value
+					format always uses 2 bytes for the data
+					len) */ 
 	ulint	charset;		/* MySQL charset-collation code
 					of the column, or zero */
 	ulint	mbminlen;		/* minimum length of a char, in bytes,

--- 1.8/innobase/include/row0mysql.ic	Thu Feb 17 17:15:21 2005
+++ 1.9/innobase/include/row0mysql.ic	Wed Mar 16 00:00:07 2005
@@ -5,149 +5,3 @@
 
 Created 1/23/2001 Heikki Tuuri
 *******************************************************/
-
-/***********************************************************************
-Stores a variable-length field (like VARCHAR) length to dest, in the
-MySQL format. No real var implemented in MySQL yet! */
-UNIV_INLINE
-byte*
-row_mysql_store_var_len(
-/*====================*/
-			/* out: dest + 2 */
-	byte*	dest,	/* in: where to store */
-	ulint	len __attribute__((unused)))  /* in: length, must fit in two
-                                                 bytes */
-{
-	ut_ad(len < 256 * 256);
-/*	
-	mach_write_to_2_little_endian(dest, len);
-
-	return(dest + 2);
-*/
-	return(dest);	/* No real var implemented in MySQL yet! */
-}
-
-/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. No real var implemented in MySQL yet! */
-UNIV_INLINE
-byte*
-row_mysql_read_var_ref(
-/*===================*/
-			/* out: field + 2 */
-	ulint*	len,	/* out: variable-length field length; does not work
-			yet! */
-	byte*	field)	/* in: field */
-{
-/*	
-	*len = mach_read_from_2_little_endian(field);
-
-	return(field + 2);
-*/
-	UT_NOT_USED(len);
-
-	return(field);	/* No real var implemented in MySQL yet! */
-}
-
-/******************************************************************
-Stores a non-SQL-NULL field given in the MySQL format in the Innobase
-format. */
-UNIV_INLINE
-void
-row_mysql_store_col_in_innobase_format(
-/*===================================*/
-	dfield_t*	dfield,		/* in/out: dfield */
-	byte*		buf,		/* in/out: buffer for the converted
-					value; this must be at least col_len
-					long! */
-	byte*		mysql_data,	/* in: MySQL column value, not
-					SQL NULL; NOTE that dfield may also
-					get a pointer to mysql_data,
-					therefore do not discard this as long
-					as dfield is used! */
-	ulint		col_len,	/* in: MySQL column length */
-	ulint		type,		/* in: data type */
-	bool		comp,		/* in: TRUE=compact format */
-	ulint		is_unsigned)	/* in: != 0 if unsigned integer type */
-{
-	byte*	ptr 	= mysql_data;
-
-	if (type == DATA_INT) {
-		/* Store integer data in Innobase in a big-endian format,
-		sign bit negated */
-
-		ptr = buf + col_len;
-
-		for (;;) {
-			ptr--;
-			*ptr = *mysql_data;
-			if (ptr == buf) {
-				break;
-			}
-			mysql_data++;
-		}
-
-		if (!is_unsigned) {
-			*ptr = (byte) (*ptr ^ 128);
-		}
-	} else if (type == DATA_VARCHAR || type == DATA_VARMYSQL
-						|| type == DATA_BINARY) {
-		/* Remove trailing spaces. */
-
-		/* Handle UCS2 strings differently. */
-		ulint	mbminlen	= dtype_get_mbminlen(
-						dfield_get_type(dfield));
-		ptr = row_mysql_read_var_ref(&col_len, mysql_data);
-		if (mbminlen == 2) {
-			/* space=0x0020 */
-			/* Trim "half-chars", just in case. */
-			col_len &= ~1;
-
-			while (col_len >= 2 && ptr[col_len - 2] == 0x00
-					&& ptr[col_len - 1] == 0x20) {
-				col_len -= 2;
-			}
-		} else {
-			ut_a(mbminlen == 1);
-			/* space=0x20 */
-			while (col_len > 0 && ptr[col_len - 1] == 0x20) {
-				col_len--;
-			}
-		}
-	} else if (comp && type == DATA_MYSQL
-			&& dtype_get_mbminlen(dfield_get_type(dfield)) == 1
-			&& dtype_get_mbmaxlen(dfield_get_type(dfield)) > 1) {
-		/* We assume that this CHAR field is encoded in a
-		variable-length character set where spaces have
-		1:1 correspondence to 0x20 bytes, such as UTF-8.
-
-		Consider a CHAR(n) field, a field of n characters.
-		It will contain between n*mbminlen and n*mbmaxlen bytes.
-		We will try to truncate it to n bytes by stripping
-		space padding.  If the field contains single-byte
-		characters only, it will be truncated to n characters.
-		Consider a CHAR(5) field containing the string ".a   "
-		where "." denotes a 3-byte character represented by
-		the bytes "$%&".  After our stripping, the string will
-		be stored as "$%&a " (5 bytes).  The string ".abc "
-		will be stored as "$%&abc" (6 bytes).
-
-		The space padding will be restored in row0sel.c, function
-		row_sel_field_store_in_mysql_format(). */
-
-		ulint		n_chars;
-		dtype_t*	dtype = dfield_get_type(dfield);
-
-		ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
-		n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
-
-		/* Strip space padding. */
-		while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
-			col_len--;
-		}
-	} else if (type == DATA_BLOB) {
-		ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
-	}
-
-	dfield_set_data(dfield, ptr, col_len);
-}

--- 1.64/innobase/row/row0ins.c	Thu Mar 10 15:16:00 2005
+++ 1.65/innobase/row/row0ins.c	Wed Mar 16 00:00:57 2005
@@ -521,6 +521,10 @@
 
 				fixed_size = dtype_get_fixed_size(type);
 
+				/* TODO: pad in UCS-2 with 0x0020.
+				TODO: How does the special truncation of
+				UTF-8 CHAR cols affect this? */
+
 				if (fixed_size
 				    && ufield->new_val.len != UNIV_SQL_NULL
 				    && ufield->new_val.len < fixed_size) {

--- 1.102/innobase/row/row0mysql.c	Sun Mar 13 22:46:36 2005
+++ 1.103/innobase/row/row0mysql.c	Wed Mar 16 00:00:57 2005
@@ -106,20 +106,6 @@
 }
 
 /***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. */
-
-byte*
-row_mysql_read_var_ref_noninline(
-/*=============================*/
-			/* out: field + 2 */
-	ulint*	len,	/* out: variable-length field length */
-	byte*	field)	/* in: field */
-{
-	return(row_mysql_read_var_ref(len, field));
-}
-
-/***********************************************************************
 Frees the blob heap in prebuilt when no longer needed. */
 
 void
@@ -133,6 +119,61 @@
 }
 
 /***********************************************************************
+Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
+format. */
+
+byte*
+row_mysql_store_true_var_len(
+/*=========================*/
+			/* out: pointer to the data, we skip the 1 or 2 bytes
+			at the start that are used to store the len */
+	byte*	dest,	/* in: where to store */
+	ulint	len,	/* in: length, must fit in two bytes */
+	ulint	lenlen)	/* in: storage length of len: either 1 or 2 bytes */
+{
+	if (lenlen == 2) {
+		ut_a(len < 256 * 256);
+
+		mach_write_to_2_little_endian(dest, len);
+
+		return(dest + 2);
+	}
+
+	ut_a(lenlen == 1);
+	ut_a(len < 256);
+
+	mach_write_to_1(dest, len);
+
+	return(dest + 1);
+}
+
+/***********************************************************************
+Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
+returns a pointer to the data. */
+
+byte*
+row_mysql_read_true_varchar(
+/*========================*/
+			/* out: pointer to the data, we skip the 1 or 2 bytes
+			at the start that are used to store the len */
+	ulint*	len,	/* out: variable-length field length */
+	byte*	field,	/* in: field in the MySQL format */
+	ulint	lenlen)	/* in: storage length of len: either 1 or 2 bytes */
+{
+	if (lenlen == 2) {
+		*len = mach_read_from_2_little_endian(field);
+
+		return(field + 2);
+	}
+
+	ut_a(lenlen == 1);
+
+	*len = mach_read_from_1(field);
+
+	return(field + 1);
+}
+
+/***********************************************************************
 Stores a reference to a BLOB in the MySQL format. */
 
 void
@@ -191,15 +232,177 @@
 }
 
 /******************************************************************
-Convert a row in the MySQL format to a row in the Innobase format. */
+Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
+The counterpart of this function is row_sel_field_store_in_mysql_format() in
+row0sel.c. */
+
+byte*
+row_mysql_store_col_in_innobase_format(
+/*===================================*/
+					/* out: up to which byte we used
+					buf in the conversion */
+	dfield_t*	dfield,		/* in/out: dfield where dtype
+					information must be already set when
+					this function is called! */
+	byte*		buf,		/* in/out: buffer for a converted
+					integer value; this must be at least
+					col_len long then! */
+	ibool		row_format_col,	/* TRUE if the mysql_data is from
+					a MySQL row, FALSE if from a MySQL
+					key value;
+					in MySQL, a true VARCHAR storage
+					format differs in a row and in a
+					key value: in a key value the length
+					is always stored in 2 bytes! */
+	byte*		mysql_data,	/* in: MySQL column value, not
+					SQL NULL; NOTE that dfield may also
+					get a pointer to mysql_data,
+					therefore do not discard this as long
+					as dfield is used! */
+	ulint		col_len,	/* in: MySQL column length; NOTE that
+					this is the storage length of the
+					column in the MySQL format row, not
+					necessarily the length of the actual
+					payload data; if the column is a true
+					VARCHAR then this is irrelevant */
+	ibool		comp)		/* in: TRUE = compact format */
+{
+	byte*		ptr 	= mysql_data;
+	dtype_t*	dtype;
+	ulint		type;
+	ulint		lenlen;
+
+	dtype = dfield_get_type(dfield);
+
+	type = dtype->mtype;
+
+	if (type == DATA_INT) {
+		/* Store integer data in Innobase in a big-endian format,
+		sign bit negated if the data is a signed integer. In MySQL,
+		integers are stored in a little-endian format. */
+
+		ptr = buf + col_len;
+
+		for (;;) {
+			ptr--;
+			*ptr = *mysql_data;
+			if (ptr == buf) {
+				break;
+			}
+			mysql_data++;
+		}
+
+		if (!(dtype->prtype & DATA_UNSIGNED)) {
+
+			*ptr = (byte) (*ptr ^ 128);
+		}
+
+		buf += col_len;
+	} else if ((type == DATA_VARCHAR
+		    || type == DATA_VARMYSQL
+		    || type == DATA_BINARY)) {
+
+		if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
+			/* The length of the actual data is stored to 1 or 2
+			bytes at the start of the field */
+			
+			if (row_format_col) {
+				if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
+					lenlen = 2;
+				} else {
+					lenlen = 1;
+				}
+			} else {
+				/* In a MySQL key value, lenlen is always 2 */
+				lenlen = 2;
+			}
+
+			ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
+								      lenlen);
+		} else {
+			/* Remove trailing spaces from old style VARCHAR
+			columns. */
+
+			/* Handle UCS2 strings differently. */
+			ulint	mbminlen	= dtype_get_mbminlen(dtype);
+
+			ptr = mysql_data;
+
+			if (mbminlen == 2) {
+				/* space=0x0020 */
+				/* Trim "half-chars", just in case. */
+				col_len &= ~1;
+
+				while (col_len >= 2 && ptr[col_len - 2] == 0x00
+						&& ptr[col_len - 1] == 0x20) {
+					col_len -= 2;
+				}
+			} else {
+				ut_a(mbminlen == 1);
+				/* space=0x20 */
+				while (col_len > 0
+						&& ptr[col_len - 1] == 0x20) {
+					col_len--;
+				}
+			}
+		}
+	} else if (comp && type == DATA_MYSQL
+			&& dtype_get_mbminlen(dtype) == 1
+			&& dtype_get_mbmaxlen(dtype) > 1) {
+		/* In some cases we strip trailing spaces from UTF-8 and other
+		multibyte charsets, from FIXED-length CHAR columns, to save
+		space. UTF-8 would otherwise normally use 3 * the string length
+		bytes to store a latin1 string! */
+
+		/* We assume that this CHAR field is encoded in a
+		variable-length character set where spaces have
+		1:1 correspondence to 0x20 bytes, such as UTF-8.
+
+		Consider a CHAR(n) field, a field of n characters.
+		It will contain between n * mbminlen and n * mbmaxlen bytes.
+		We will try to truncate it to n bytes by stripping
+		space padding.  If the field contains single-byte
+		characters only, it will be truncated to n characters.
+		Consider a CHAR(5) field containing the string ".a   "
+		where "." denotes a 3-byte character represented by
+		the bytes "$%&".  After our stripping, the string will
+		be stored as "$%&a " (5 bytes).  The string ".abc "
+		will be stored as "$%&abc" (6 bytes).
+
+		The space padding will be restored in row0sel.c, function
+		row_sel_field_store_in_mysql_format(). */
+
+		ulint		n_chars;
+
+		ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
+
+		n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
+
+		/* Strip space padding. */
+		while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
+			col_len--;
+		}
+	} else if (type == DATA_BLOB && row_format_col) {
+
+		ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
+	}
+
+	dfield_set_data(dfield, ptr, col_len);
+
+	return(buf);
+}
+
+/******************************************************************
+Convert a row in the MySQL format to a row in the Innobase format. Note that
+the function to convert a MySQL format key value to an InnoDB dtuple is
+row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
 static
 void
 row_mysql_convert_row_to_innobase(
 /*==============================*/
 	dtuple_t*	row,		/* in/out: Innobase row where the
 					field type information is already
-					copied there, or will be copied
-					later */
+					copied there! */
 	row_prebuilt_t*	prebuilt,	/* in: prebuilt struct where template
 					must be of type ROW_MYSQL_WHOLE_ROW */
 	byte*		mysql_rec)	/* in: row in the MySQL format;
@@ -236,10 +439,10 @@
 		row_mysql_store_col_in_innobase_format(dfield,
 					prebuilt->ins_upd_rec_buff
 						+ templ->mysql_col_offset,
+					TRUE, /* MySQL row format data */
 					mysql_rec + templ->mysql_col_offset,
 					templ->mysql_col_len,
-					templ->type, prebuilt->table->comp,
-					templ->is_unsigned);
+					prebuilt->table->comp);
 next_column:
 		;
 	} 
@@ -594,7 +797,8 @@
 dtuple_t*
 row_get_prebuilt_insert_row(
 /*========================*/
-					/* out: prebuilt dtuple */
+					/* out: prebuilt dtuple; the column
+					type information is also set in it */ 
 	row_prebuilt_t*	prebuilt)	/* in: prebuilt struct in MySQL
 					handle */
 {
@@ -784,6 +988,7 @@
 	lock_release_tables_off_kernel(trx);
 	mutex_exit(&kernel_mutex);
 }
+
 /*************************************************************************
 Sets a table lock on the table mentioned in prebuilt. */
 
@@ -962,10 +1167,13 @@
 
 	if (err != DB_SUCCESS) {
 		que_thr_stop_for_mysql(thr);
-    thr->lock_state= QUE_THR_LOCK_ROW;
+
+/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
+
 		was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
 								&savept);
-    thr->lock_state= QUE_THR_LOCK_NOLOCK;
+		thr->lock_state= QUE_THR_LOCK_NOLOCK;
+
 		if (was_lock_wait) {
 			goto run_again;
 		}

--- 1.76/innobase/row/row0sel.c	Fri Mar 11 17:23:52 2005
+++ 1.77/innobase/row/row0sel.c	Wed Mar 16 00:00:57 2005
@@ -2119,10 +2119,10 @@
 				   + 256 * key_ptr[data_offset + 1];
 			data_field_len = data_offset + 2 + field->prefix_len;
 			data_offset += 2;
-			
-			type = DATA_CHAR; /* now that we know the length, we
-					  store the column value like it would
-					  be a fixed char field */
+
+			/* now that we know the length, we store the column
+			value like it would be a fixed char field */
+
 		} else if (field->prefix_len > 0) {
 			/* Looks like MySQL pads unused end bytes in the
 			prefix with space. Therefore, also in UTF-8, it is ok
@@ -2146,11 +2146,12 @@
 		
 		if (!is_null) {
 		        row_mysql_store_col_in_innobase_format(
-					dfield, buf, key_ptr + data_offset,
-					data_len, type,
-					index->table->comp,
-					dfield_get_type(dfield)->prtype
-							& DATA_UNSIGNED);
+					dfield,
+					buf,
+					FALSE, /* MySQL key value format col */
+					key_ptr + data_offset,
+					data_len,
+					index->table->comp);
 			buf += data_len;
 		}
 
@@ -2225,7 +2226,7 @@
 		dict_index_name_print(stderr, prebuilt->trx, index);
 		fprintf(stderr, "\n"
 "InnoDB: Field number %lu, record:\n",
-			(ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID));
+		    (ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID));
 		rec_print_new(stderr, index_rec, offsets);
 		putc('\n', stderr);
 		ut_error;
@@ -2235,8 +2236,9 @@
 }
 
 /******************************************************************
-Stores a non-SQL-NULL field in the MySQL format. */
-UNIV_INLINE
+Stores a non-SQL-NULL field in the MySQL format. The counterpart of this
+function is row_mysql_store_col_in_innobase_format() in row0mysql.c. */
+static
 void
 row_sel_field_store_in_mysql_format(
 /*================================*/
@@ -2251,6 +2253,8 @@
 	ulint	len)	/* in: length of the data */
 {
 	byte*	ptr;
+	byte*	field_end;
+	byte*	pad_ptr;
 
 	ut_ad(len != UNIV_SQL_NULL);
 
@@ -2274,25 +2278,66 @@
 		}
 
 		ut_ad(templ->mysql_col_len == len);
-	} else if (templ->type == DATA_VARCHAR || templ->type == DATA_VARMYSQL
-					|| templ->type == DATA_BINARY) {
-		/* Store the length of the data to the first two bytes of
-		dest; does not do anything yet because MySQL has
-		no real vars! */
+	} else if (templ->type == DATA_VARCHAR
+	           || templ->type == DATA_VARMYSQL
+		   || templ->type == DATA_BINARY) {
+
+		field_end = dest + templ->mysql_col_len;
+
+		if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
+			/* This is a >= 5.0.3 type true VARCHAR. Store the
+			length of the data to the first byte or the first
+			two bytes of dest. */
 		
-		dest = row_mysql_store_var_len(dest, len);
+			dest = row_mysql_store_true_var_len(dest, len,
+						templ->mysql_length_bytes);
+		}
+
+		/* Copy the actual data */
 		ut_memcpy(dest, data, len);
-#if 0
-		/* No real var implemented in MySQL yet! */
-		ut_ad(templ->mysql_col_len >= len + 2);
-#endif
 		
+		/* Pad with trailing spaces. We pad with spaces also the
+		unused end of a >= 5.0.3 true VARCHAR column, just in case
+		MySQL expects its contents to be deterministic. */
+			
+		pad_ptr = dest + len;
+
+		ut_ad(templ->mbminlen <= templ->mbmaxlen);
+
+		/* We handle UCS2 charset strings differently. */
+		if (templ->mbminlen == 2) {
+			/* A space char is two bytes, 0x0020 in UCS2 */
+
+			if (len & 1) {
+				/* A 0x20 has been stripped from the column.
+				Pad it back. */
+				
+				if (pad_ptr < field_end) {
+					*pad_ptr = 0x20;
+					pad_ptr++;
+				}
+			}
+			
+			/* Pad the rest of the string with 0x0020 */
+
+			while (pad_ptr < field_end) {
+				*pad_ptr = 0x00;
+				pad_ptr++;
+				*pad_ptr = 0x20;
+				pad_ptr++;
+			}
+		} else {
+			ut_ad(templ->mbminlen == 1);
+			/* space=0x20 */
+
+			memset(pad_ptr, 0x20, field_end - pad_ptr);
+		}
 	} else if (templ->type == DATA_BLOB) {
 		/* Store a pointer to the BLOB buffer to dest: the BLOB was
 		already copied to the buffer in row_sel_store_mysql_rec */
 
-		row_mysql_store_blob_ref(dest, templ->mysql_col_len,
-							data, len);
+		row_mysql_store_blob_ref(dest, templ->mysql_col_len, data,
+									len);
 	} else if (templ->type == DATA_MYSQL) {
 		memcpy(dest, data, len);
 
@@ -2306,9 +2351,10 @@
 		ut_a(len * templ->mbmaxlen >= templ->mysql_col_len);
 
 		if (templ->mbminlen != templ->mbmaxlen) {
-			/* Pad with spaces.  This undoes the stripping
+			/* Pad with spaces. This undoes the stripping
 			done in row0mysql.ic, function
 			row_mysql_store_col_in_innobase_format(). */
+
 			memset(dest + len, 0x20, templ->mysql_col_len - len);
 		}
 	} else {
@@ -2320,6 +2366,7 @@
 			|| templ->type == DATA_DOUBLE
 			|| templ->type == DATA_DECIMAL);
 		ut_ad(templ->mysql_col_len == len);
+
 		memcpy(dest, data, len);
 	}
 }
@@ -2435,40 +2482,6 @@
 			row_sel_field_store_in_mysql_format(
 				mysql_rec + templ->mysql_col_offset,
 				templ, data, len);
-
-			if (templ->type == DATA_VARCHAR
-					|| templ->type == DATA_VARMYSQL
-					|| templ->type == DATA_BINARY) {
-				/* Pad with trailing spaces */
-				data = mysql_rec + templ->mysql_col_offset;
-
-				ut_ad(templ->mbminlen <= templ->mbmaxlen);
-				/* Handle UCS2 strings differently. */
-				if (templ->mbminlen == 2) {
-					/* space=0x0020 */
-					ulint	col_len = templ->mysql_col_len;
-
-					ut_a(!(col_len & 1));
-					if (len & 1) {
-						/* A 0x20 has been stripped
-						from the column.
-						Pad it back. */
-						goto pad_0x20;
-					}
-					/* Pad the rest of the string
-					with 0x0020 */
-					while (len < col_len) {
-						data[len++] = 0x00;
-					pad_0x20:
-						data[len++] = 0x20;
-					}
-				} else {
-					ut_ad(templ->mbminlen == 1);
-					/* space=0x20 */
-					memset(data + len, 0x20,
-						templ->mysql_col_len - len);
-				}
-			}
 
 			/* Cleanup */
 			if (extern_field_heap) {

--- 1.52/innobase/trx/trx0trx.c	Sun Mar 13 12:47:21 2005
+++ 1.53/innobase/trx/trx0trx.c	Wed Mar 16 00:01:44 2005
@@ -1958,7 +1958,7 @@
 
 	ut_print_timestamp(stderr);
 	fprintf(stderr,
-"  InnoDB: %d transactions in prepare state after recovery\n",
+"  InnoDB: %d transactions in prepared state after recovery\n",
 		count);
 
 	return (count);			

--- 1.175/sql/ha_innodb.cc	Mon Mar 14 15:47:36 2005
+++ 1.176/sql/ha_innodb.cc	Tue Mar 15 23:59:47 2005
@@ -1074,6 +1074,8 @@
 
   	DBUG_ENTER("innobase_init");
 
+	ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
+
   	os_innodb_umask = (ulint)my_umask;
 
 	/* First calculate the default path for innodb_data_home_dir etc.,
@@ -2244,7 +2246,9 @@
 }
 
 /******************************************************************
-Converts a MySQL type to an InnoDB type. */
+Converts a MySQL type to an InnoDB type. Note that this function returns
+the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
+VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'. */
 inline
 ulint
 get_innobase_type_from_mysql_type(
@@ -2259,8 +2263,9 @@
 	switch (field->type()) {
 	        /* NOTE that we only allow string types in DATA_MYSQL
 		and DATA_VARMYSQL */
-                case MYSQL_TYPE_VAR_STRING:
-                case MYSQL_TYPE_VARCHAR: if (field->binary()) {
+                case MYSQL_TYPE_VAR_STRING: /* old <= 4.1 VARCHAR */
+                case MYSQL_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
+					if (field->binary()) {
 						return(DATA_BINARY);
 					} else if (strcmp(
 						  field->charset()->name,
@@ -2314,6 +2319,35 @@
 }
 
 /***********************************************************************
+Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
+storage format. */
+inline
+void
+innobase_write_to_2_little_endian(
+/*==============================*/
+	byte*	buf,	/* in: where to store */
+	ulint	val)	/* in: value to write, must be < 64k */
+{
+	ut_a(val < 256 * 256);
+
+	buf[0] = (byte)(val & 0xFF);
+	buf[1] = (byte)(val / 256);
+}
+
+/***********************************************************************
+Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
+storage format. */
+inline
+uint
+innobase_read_from_2_little_endian(
+/*===============================*/
+			/* out: value */
+	const mysql_byte*	buf)	/* in: from where to read */
+{
+	return((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
+}
+
+/***********************************************************************
 Stores a key value for a row to a buffer. */
 
 uint
@@ -2352,9 +2386,14 @@
 	3. In a column prefix field, prefix_len next bytes are reserved for
 	data. In a normal field the max field length next bytes are reserved
 	for data. For a VARCHAR(n) the max field length is n. If the stored
-	value is the SQL NULL then these data bytes are set to 0. */	
+	value is the SQL NULL then these data bytes are set to 0.
+
+	4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
+	in the MySQL row format, the length is stored in 1 or 2 bytes,
+	depending on the maximum allowed length. But in the MySQL key value
+	format, the length always takes 2 bytes.
 
-	/* We have to zero-fill the buffer so that MySQL is able to use a
+	We have to zero-fill the buffer so that MySQL is able to use a
 	simple memcmp to compare two key values to determine if they are
 	equal. MySQL does this to compare contents of two 'ref' values. */
 
@@ -2377,7 +2416,43 @@
 		field = key_part->field;
 		mysql_type = field->type();
 
-		if (mysql_type == FIELD_TYPE_TINY_BLOB
+		if (mysql_type == MYSQL_TYPE_VARCHAR) {
+						/* >= 5.0.3 true VARCHAR */
+			ulint	lenlen;
+			ulint	len;
+			byte*	data;
+
+			if (is_null) {
+				buff += key_part->length + 2;
+				
+				continue;
+			}
+
+			lenlen = (ulint)
+				(((Field_varstring*)field)->length_bytes);
+
+			data = row_mysql_read_true_varchar(&len, 
+				(byte*) (record
+				+ (ulint)get_field_offset(table, field)),
+				lenlen);
+		
+			/* The length in a key value is always stored in 2
+			bytes */
+
+			row_mysql_store_true_var_len((byte*)buff, len, 2);
+			buff += 2;
+
+			memcpy(buff, data, len);
+
+			/* Note that we always reserve the maximum possible
+			length of the true VARCHAR in the key value, though
+			only len first bytes after the 2 length bytes contain
+			actual data. The rest of the space was reset to zero
+			in the bzero() call above. */
+
+			buff += key_part->length;
+
+		} else if (mysql_type == FIELD_TYPE_TINY_BLOB
 		    || mysql_type == FIELD_TYPE_MEDIUM_BLOB
 		    || mysql_type == FIELD_TYPE_BLOB
 		    || mysql_type == FIELD_TYPE_LONG_BLOB) {
@@ -2385,9 +2460,9 @@
 			ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
 
 		        if (is_null) {
-				 buff += key_part->length + 2;
+				buff += key_part->length + 2;
 				 
-				 continue;
+				continue;
 			}
 		    
 		        blob_data = row_mysql_read_blob_ref(&blob_len,
@@ -2404,12 +2479,15 @@
 			/* MySQL reserves 2 bytes for the length and the
 			storage of the number is little-endian */
 
-			ut_a(blob_len < 256);
-			*((byte*)buff) = (byte)blob_len;
+			innobase_write_to_2_little_endian(
+					(byte*)buff, (ulint)blob_len);
 			buff += 2;
 
 			memcpy(buff, blob_data, blob_len);
 
+			/* Note that we always reserve the maximum possible
+			length of the BLOB prefix in the key value. */
+
 			buff += key_part->length;
 		} else {
 		        if (is_null) {
@@ -2573,6 +2651,13 @@
 
 		templ->mysql_col_len = (ulint) field->pack_length();
 		templ->type = get_innobase_type_from_mysql_type(field);
+		templ->mysql_type = (ulint)field->type();
+
+		if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
+			templ->mysql_length_bytes = (ulint)
+				    (((Field_varstring*)field)->length_bytes);
+		}
+	
 		templ->charset = dtype_get_charset_coll_noninline(
 				index->table->cols[i].type.prtype);
 		templ->mbminlen = index->table->cols[i].type.mbminlen;
@@ -2810,54 +2895,6 @@
   	DBUG_RETURN(error);
 }
 
-/******************************************************************
-Converts field data for storage in an InnoDB update vector. */
-inline
-mysql_byte*
-innobase_convert_and_store_changed_col(
-/*===================================*/
-				/* out: pointer to the end of the converted
-				data in the buffer */
-	upd_field_t*	ufield,	/* in/out: field in the update vector */
-	mysql_byte*	buf,	/* in: buffer we can use in conversion */
-	mysql_byte*	data,	/* in: column data to store */
-	ulint		len,	/* in: data len */
-	ulint		col_type,/* in: data type in InnoDB type numbers */
-	ulint		is_unsigned)/* in: != 0 if an unsigned integer type */
-{
-	uint	i;
-
-	if (len == UNIV_SQL_NULL) {
-		data = NULL;
-        } else if (col_type == DATA_VARCHAR || col_type == DATA_BINARY
-                   || col_type == DATA_VARMYSQL) {
-                /* Remove trailing spaces */
-                while (len > 0 && data[len - 1] == ' ') {
-                        len--;
-                }
-	} else if (col_type == DATA_INT) {
-		/* Store integer data in InnoDB in a big-endian
-		format, sign bit negated, if signed */
-
-		for (i = 0; i < len; i++) {
-			buf[len - 1 - i] = data[i];
-		}
-
-		if (!is_unsigned) {
-			buf[0] = buf[0] ^ 128;
-		}
-
-		data = buf;
-
-		buf += len;
-	}
-
-	ufield->new_val.data = data;
-	ufield->new_val.len = len;
-
-	return(buf);
-}
-
 /**************************************************************************
 Checks which fields have changed in a row and stores information
 of them to an update vector. */
@@ -2878,9 +2915,11 @@
 {
 	mysql_byte*	original_upd_buff = upd_buff;
 	Field*		field;
+	enum_field_types field_mysql_type;
 	uint		n_fields;
 	ulint		o_len;
 	ulint		n_len;
+	ulint		col_pack_len;
 	byte*	        o_ptr;
         byte*	        n_ptr;
         byte*	        buf;
@@ -2888,6 +2927,7 @@
 	ulint		col_type;
 	ulint		is_unsigned;
 	ulint		n_changed = 0;
+	dfield_t	dfield;
 	uint		i;
 
 	n_fields = table->s->fields;
@@ -2907,9 +2947,13 @@
 
 		o_ptr = (byte*) old_row + get_field_offset(table, field);
 		n_ptr = (byte*) new_row + get_field_offset(table, field);
-		o_len = field->pack_length();
-		n_len = field->pack_length();
+		
+		col_pack_len = field->pack_length();
+		o_len = col_pack_len;
+		n_len = col_pack_len;
 
+		field_mysql_type = field->type();
+	
 		col_type = get_innobase_type_from_mysql_type(field);
 		is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG);
 
@@ -2918,14 +2962,29 @@
 		case DATA_BLOB:
 			o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
 			n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
+
 			break;
+
 		case DATA_VARCHAR:
 		case DATA_BINARY:
 		case DATA_VARMYSQL:
-			o_ptr = row_mysql_read_var_ref_noninline(&o_len,
-								o_ptr);
-			n_ptr = row_mysql_read_var_ref_noninline(&n_len,
-								n_ptr);
+			if (field_mysql_type == MYSQL_TYPE_VARCHAR) {
+				/* This is a >= 5.0.3 type true VARCHAR where
+				the real payload data length is stored in
+				1 or 2 bytes */
+			
+				o_ptr = row_mysql_read_true_varchar(
+						&o_len, o_ptr,
+				    (ulint)
+				    (((Field_varstring*)field)->length_bytes));
+								
+				n_ptr = row_mysql_read_true_varchar(
+						&n_len, n_ptr,
+				    (ulint)
+				    (((Field_varstring*)field)->length_bytes));
+			}
+
+			break;
 		default:
 			;
 		}
@@ -2947,12 +3006,29 @@
 			/* The field has changed */
 
 			ufield = uvect->fields + n_changed;
+	
+			/* Let us use a dummy dfield to make the conversion
+			from the MySQL column format to the InnoDB format */
+
+			dfield.type = (prebuilt->table->cols + i)->type;
+
+			if (n_len != UNIV_SQL_NULL) {
+				buf = row_mysql_store_col_in_innobase_format(
+						&dfield,
+						(byte*)buf,
+						TRUE,
+						n_ptr,
+						col_pack_len,
+						prebuilt->table->comp);
+				ufield->new_val.data =
+						dfield_get_data(&dfield);
+				ufield->new_val.len =
+						dfield_get_len(&dfield);
+			} else {
+				ufield->new_val.data = NULL;
+				ufield->new_val.len = UNIV_SQL_NULL;
+			}
 
-			buf = (byte*)
-                          innobase_convert_and_store_changed_col(ufield,
-					  (mysql_byte*)buf,
-					  (mysql_byte*)n_ptr, n_len, col_type,
-						is_unsigned);
 			ufield->exp = NULL;
 			ufield->field_no =
 					(prebuilt->table->cols + i)->clust_pos;
@@ -3701,7 +3777,7 @@
 	}
 
 	if (error) {
-	        DBUG_PRINT("error",("Got error: %ld",error));
+	        DBUG_PRINT("error", ("Got error: %ld", error));
 		DBUG_RETURN(error);
 	}
 
@@ -3709,10 +3785,11 @@
         for the table, and it is == ref_length */
 
 	error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
-	if (error)
-	{
-	  DBUG_PRINT("error",("Got error: %ld",error));
+
+	if (error) {
+		DBUG_PRINT("error", ("Got error: %ld", error));
 	}
+
 	change_active_index(keynr);
 
   	DBUG_RETURN(error);
@@ -3752,12 +3829,11 @@
 							 ref_length, record);
 	}
 
-	/* Since we do not store len to the buffer 'ref', we must assume
-	that len is always fixed for this table. The following assertion
-	checks this. */
+	/* We assume that the 'ref' value len is always fixed for the same
+	table. */
   
 	if (len != ref_length) {
-	        fprintf(stderr,
+		fprintf(stderr,
 	 "InnoDB: Error: stored ref len is %lu, but table ref len is %lu\n",
 		  (ulong)len, (ulong)ref_length);
 	}
@@ -3788,9 +3864,11 @@
 	ulint		n_cols;
   	int 		error;
   	ulint		col_type;
+	ulint		col_len;
   	ulint		nulls_allowed;
 	ulint		unsigned_type;
 	ulint		binary_type;
+	ulint		long_true_varchar;
 	ulint		charset_no;
   	ulint		i;
 
@@ -3837,17 +3915,40 @@
 
 			charset_no = (ulint)field->charset()->number;
 
-			ut_a(charset_no < 256); /* in ut0type.h we assume that
-						the number fits in one byte */
+			ut_a(charset_no < 256); /* in data0type.h we assume
+						that the number fits in one
+						byte */
 		}
 
-		dict_mem_table_add_col(table, (char*) field->field_name,
-					col_type, dtype_form_prtype( 
-					(ulint)field->type()
-					| nulls_allowed | unsigned_type
-					| binary_type,
-					+ charset_no),
-					field->pack_length(), 0);
+		ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
+					   that this fits in one byte */
+		col_len = field->pack_length();
+
+		/* The MySQL pack length contains 1 or 2 bytes length field
+		for a true VARCHAR. Let us subtract that, so that the InnoDB
+		column length in the InnoDB data dictionary is the real
+		maximum byte length of the actual data. */
+	
+		long_true_varchar = 0;
+
+		if (field->type() == MYSQL_TYPE_VARCHAR) {
+			col_len -= ((Field_varstring*)field)->length_bytes;
+
+			if (((Field_varstring*)field)->length_bytes == 2) {
+				long_true_varchar = DATA_LONG_TRUE_VARCHAR;
+			}
+		}
+
+		dict_mem_table_add_col(table,
+					(char*) field->field_name,
+					col_type,
+					dtype_form_prtype( 
+					    (ulint)field->type()
+					     | nulls_allowed | unsigned_type
+					     | binary_type | long_true_varchar,
+					    charset_no),
+					col_len,
+					0);
 	}
 
 	error = row_create_table_for_mysql(table, trx);
@@ -6125,54 +6226,79 @@
 	return((ulonglong) nr);
 }
 
+/***********************************************************************
+Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
+If there is no explicitly declared non-null unique key or a primary key, then
+InnoDB internally uses the row id as the primary key. */
 
 int
 ha_innobase::cmp_ref(
-	const mysql_byte *ref1,
-	const mysql_byte *ref2)
+/*=================*/
+				/* out: < 0 if ref1 < ref2, 0 if equal, else
+				> 0 */
+	const mysql_byte* ref1,	/* in: an (internal) primary key value in the
+				MySQL key value format */
+	const mysql_byte* ref2)	/* in: an (internal) primary key value in the
+				MySQL key value format */
 {
-	row_prebuilt_t*	 prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+	row_prebuilt_t*	prebuilt = (row_prebuilt_t*) innobase_prebuilt;
 	enum_field_types mysql_type;
-	Field*		 field;
-	int result;
+	Field*		field;
+	KEY_PART_INFO*	key_part;
+	KEY_PART_INFO*	key_part_end;
+	uint		len1;
+	uint		len2;
+	int 		result;
+
+	if (prebuilt->clust_index_was_generated) {
+		/* The 'ref' is an InnoDB row id */
+
+		return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
+	}
 
-	if (prebuilt->clust_index_was_generated)
-		return memcmp(ref1, ref2, DATA_ROW_ID_LEN);
+	/* Do a type-aware comparison of primary key fields. PK fields
+	are always NOT NULL, so no checks for NULL are performed. */
+
+	key_part = table->key_info[table->s->primary_key].key_part;
+
+	key_part_end = key_part
+			+ table->key_info[table->s->primary_key].key_parts;
 
-	/* Do type-aware comparison of Primary Key members. PK members
-	are always NOT NULL, so no checks for NULL are performed */
-	KEY_PART_INFO *key_part=
-			table->key_info[table->s->primary_key].key_part;
-	KEY_PART_INFO *key_part_end= 
-	  key_part + table->key_info[table->s->primary_key].key_parts;
 	for (; key_part != key_part_end; ++key_part) {
 		field = key_part->field;
 		mysql_type = field->type();
+
 		if (mysql_type == FIELD_TYPE_TINY_BLOB
 		    || mysql_type == FIELD_TYPE_MEDIUM_BLOB
 		    || mysql_type == FIELD_TYPE_BLOB
 		    || mysql_type == FIELD_TYPE_LONG_BLOB) {
 		    
-			ut_a(!ref1[1]);
-			ut_a(!ref2[1]);
-			byte len1= *ref1;
-			byte len2= *ref2;
+			/* In the MySQL key value format, a column prefix of
+			a BLOB is preceded by a 2-byte length field */
+
+			len1 = innobase_read_from_2_little_endian(ref1);
+			len2 = innobase_read_from_2_little_endian(ref2);
+
 			ref1 += 2;
 			ref2 += 2;
-			result =
-			  ((Field_blob*)field)->cmp((const char*)ref1, len1,
+			result = ((Field_blob*)field)->cmp(
+						    (const char*)ref1, len1,
 			                            (const char*)ref2, len2);
 		} else {
-			result = 
-			  field->cmp((const char*)ref1, (const char*)ref2);
+			result = field->cmp((const char*)ref1,
+					    (const char*)ref2);
+		}
+
+		if (result) {
+
+			return(result);
 		}
 
-		if (result)
-			return result;
 		ref1 += key_part->length;
 		ref2 += key_part->length;
 	}
-	return 0;
+
+	return(0);
 }
 
 char*

--- 1.87/sql/ha_innodb.h	Wed Mar  2 11:56:12 2005
+++ 1.88/sql/ha_innodb.h	Tue Mar 15 23:59:43 2005
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB && Innobase Oy
+/* Copyright (C) 2000-2005 MySQL AB && Innobase Oy
 
    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
@@ -40,9 +40,10 @@
 /* The class defining a handle to an Innodb table */
 class ha_innobase: public handler
 {
-	void*	innobase_prebuilt;	/* (row_prebuilt_t*) prebuilt
-					struct in Innodb, used to save
-					CPU */
+	void*		innobase_prebuilt;/* (row_prebuilt_t*) prebuilt
+					struct in InnoDB, used to save
+					CPU time with prebuilt data
+					structures*/
 	THD*		user_thd;	/* the thread handle of the user
 					currently using the handle; this is
 					set in external_lock function */
@@ -83,12 +84,12 @@
  public:
   	ha_innobase(TABLE *table): handler(table),
 	  int_table_flags(HA_REC_NOT_IN_SEQ |
-			  HA_NULL_IN_KEY | HA_FAST_KEY_READ |
+			  HA_NULL_IN_KEY |
+			  HA_FAST_KEY_READ |
 			  HA_CAN_INDEX_BLOBS |
 			  HA_CAN_SQL_HANDLER |
 			  HA_NOT_EXACT_COUNT |
 			  HA_PRIMARY_KEY_IN_READ_INDEX |
-                          HA_NO_VARCHAR |
 			  HA_TABLE_SCAN_ON_INDEX),
 	  last_dup_key((uint) -1),
 	  start_of_scan(0),
@@ -108,7 +109,10 @@
  	ulong table_flags() const { return int_table_flags; }
 	ulong index_flags(uint idx, uint part, bool all_parts) const
 	{
-	  return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE |
+	  return (HA_READ_NEXT |
+		  HA_READ_PREV |
+		  HA_READ_ORDER |
+		  HA_READ_RANGE |
                   HA_KEYREAD_ONLY);
 	}
   	uint max_supported_keys()          const { return MAX_KEY; }
@@ -163,7 +167,8 @@
 	int start_stmt(THD *thd);
 
   	void position(byte *record);
-  	ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
+  	ha_rows records_in_range(uint inx, key_range *min_key, key_range
+								*max_key);
 	ha_rows estimate_rows_upper_bound();
 
   	int create(const char *name, register TABLE *form,
Thread
bk commit into 5.0 tree (heikki:1.1817)Heikki Tuuri15 Mar