← Back to team overview

maria-developers team mailing list archive

Dynamic column for review

 

Hi!

Here is 2 patches: one cut version - to review, other one full version.
=== added file 'include/ma_dyncol.h'
--- include/ma_dyncol.h	1970-01-01 00:00:00 +0000
+++ include/ma_dyncol.h	2011-04-29 09:52:28 +0000
@@ -0,0 +1,101 @@
+#ifndef ma_dyncol_h
+#define ma_dyncol_h
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <decimal.h>
+#include <my_decimal_limits.h>
+#include <mysql_time.h>
+
+#define ER_DYNCOL_YES 1
+/* NO and OK is the same used just to show semantics */
+#define ER_DYNCOL_NO 0
+#define ER_DYNCOL_OK 0
+/* Wrong format of the string with encoded columns */
+#define ER_DYNCOL_FORMAT -1
+/* Some limit reached */
+#define ER_DYNCOL_LIMIT -2
+/* Out of resourses */
+#define ER_DYNCOL_RESOURCE -3
+/* Incorrect input data */
+#define ER_DYNCOL_DATA -4
+
+typedef DYNAMIC_STRING DYNAMIC_COLUMN;
+
+enum enum_dynamic_column_type
+{
+  DYN_COL_NULL= 0,
+  DYN_COL_INT,
+  DYN_COL_UINT,
+  DYN_COL_DOUBLE,
+  DYN_COL_STRING,
+  DYN_COL_DECIMAL,
+  DYN_COL_DATETIME,
+  DYN_COL_DATE,
+  DYN_COL_TIME
+};
+
+typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE;
+
+struct st_dynamic_column_value
+{
+  DYNAMIC_COLUMN_TYPE type;
+  union
+  {
+    long long long_value;
+    unsigned long long ulong_value;
+    double double_value;
+    struct {
+      LEX_STRING string_value;
+      CHARSET_INFO *charset;
+    };
+    struct {
+      decimal_digit_t decimal_buffer[DECIMAL_BUFF_LENGTH];
+      decimal_t decimal_value;
+    };
+    MYSQL_TIME time_value;
+  };
+};
+
+typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;
+
+int dynamic_column_create(DYNAMIC_COLUMN *str,
+                          uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value);
+
+int dynamic_column_create_many(DYNAMIC_COLUMN *str,
+                               uint column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values);
+
+int dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value);
+int dynamic_column_update_many(DYNAMIC_COLUMN *str,
+                               uint add_column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values);
+
+int dynamic_column_delete(DYNAMIC_COLUMN *org, uint column_nr);
+
+int dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr);
+
+/* List of not NULL columns */
+int dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint);
+
+/*
+   if the column do not exists it is NULL
+*/
+int dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr,
+                       DYNAMIC_COLUMN_VALUE *store_it_here);
+
+#define dynamic_column_column_free(V) dynstr_free(V)
+
+#define dynamic_column_value_init(V) (V)->type= DYN_COL_NULL
+
+/*
+  Prepare value for using as decimal
+*/
+void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value);
+
+#endif

=== added file 'mysql-test/r/dyncol.result'
--- mysql-test/r/dyncol.result	1970-01-01 00:00:00 +0000
+++ mysql-test/r/dyncol.result	2011-04-29 11:07:51 +0000
[skip]
+# column add
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer));
+hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer))
+00020001000002001078097809
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer));
+hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer))
+0001000100007809
+select hex(column_add(column_create(1, 1212 as integer), 1, NULL as integer));
+hex(column_add(column_create(1, 1212 as integer), 1, NULL as integer))
+000000
+select hex(column_add(column_create(1, 1212 as integer), 2, NULL as integer));
+hex(column_add(column_create(1, 1212 as integer), 2, NULL as integer))
+0001000100007809
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer));
+hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer))
+000200010000020008167809
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 1 as integer);
+column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 1 as integer)
+11
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 2 as integer);
+column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 2 as integer)
+1212
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer, 2, 11 as integer));
+hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer, 2, 11 as integer))
+000200010000020010780916
+select hex(column_add(column_create(1, NULL as integer), 1, 1212 as integer, 2, 11 as integer));
+hex(column_add(column_create(1, NULL as integer), 1, 1212 as integer, 2, 11 as integer))
+000200010000020010780916
+select hex(column_add(column_create(1, 1212 as integer, 2, 1212 as integer), 1, 11 as integer));
+hex(column_add(column_create(1, 1212 as integer, 2, 1212 as integer), 1, 11 as integer))
+000200010000020008167809
+# column delete
+select hex(column_delete(column_create(1, 1212 as integer, 2, 1212 as integer), 1));
+hex(column_delete(column_create(1, 1212 as integer, 2, 1212 as integer), 1))
+0001000200007809
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2))
+0002000100000300080206
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 3));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 3))
+0002000100000200080204
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 4));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 4))
+000300010000020008030010020406
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 1));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 1))
+00010003000006
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 3));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 3))
+00010001000002
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3))
+000000
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3, 10));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3, 10))
+000000
+# column exists
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 1);
+column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 1)
+1
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4);
+column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4)
+0
+# column list
+select column_list(column_create(1, 1212 as integer, 2, 1212 as integer));
+column_list(column_create(1, 1212 as integer, 2, 1212 as integer))
+1,2
+select column_list(column_create(1, 1212 as integer));
+column_list(column_create(1, 1212 as integer))
+1
+select column_list(column_create(1, NULL as integer));
+column_list(column_create(1, NULL as integer))
+

=== added file 'mysql-test/t/dyncol.test'
--- mysql-test/t/dyncol.test	1970-01-01 00:00:00 +0000
+++ mysql-test/t/dyncol.test	2011-04-29 11:02:53 +0000
[skip]
+-- echo # column add
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer));
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer));
+select hex(column_add(column_create(1, 1212 as integer), 1, NULL as integer));
+select hex(column_add(column_create(1, 1212 as integer), 2, NULL as integer));
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer));
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 1 as integer);
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 2 as integer);
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer, 2, 11 as integer));
+select hex(column_add(column_create(1, NULL as integer), 1, 1212 as integer, 2, 11 as integer));
+select hex(column_add(column_create(1, 1212 as integer, 2, 1212 as integer), 1, 11 as integer));
+
+-- echo # column delete
+select hex(column_delete(column_create(1, 1212 as integer, 2, 1212 as integer), 1));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 3));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 4));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 1));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 3));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3, 10));
+
+-- echo # column exists
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 1);
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4);
+
+-- echo # column list
+select column_list(column_create(1, 1212 as integer, 2, 1212 as integer));
+select column_list(column_create(1, 1212 as integer));
+select column_list(column_create(1, NULL as integer));

=== added file 'mysys/ma_dyncol.c'
--- mysys/ma_dyncol.c	1970-01-01 00:00:00 +0000
+++ mysys/ma_dyncol.c	2011-04-29 09:52:28 +0000
@@ -0,0 +1,1831 @@
+#include <ma_dyncol.h>
+
+/*
+  Flag byte bits
+
+  2 bits which determinate size of offset in the header -1
+*/
+/* mask to get above bits */
+#define DYNCOL_FLG_OFFSET  3
+/* All known flags mask */
+#define DYNCOL_FLG_KNOWN  3
+
+/* dynamic column size reserve */
+#define DYNCOL_SYZERESERVE 80
+
+/* length of fixed string header 1 byte - flags, 2 bytes - columns counter */
+#define FIXED_HEADER_SIZE 3
+
+#define COLUMN_NUMBER_SIZE 2
+
+
+static int dynamic_column_time_add(DYNAMIC_COLUMN *str,
+                                   MYSQL_TIME *value);
+static int dynamic_column_date_add(DYNAMIC_COLUMN *str,
+                                   MYSQL_TIME *value);
+static int
+dynamic_column_time_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data, size_t length);
+static int
+dynamic_column_date_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data, size_t length);
+
+/**
+  Initialize dynamic column string with (make it empty but correct format)
+
+  @param str             The string to initialize
+  @param size            Amount of preallocated memory for the string
+
+  @retval FALSE OK
+  @retval TRUE  error
+*/
+
+my_bool dynamic_column_init_str(DYNAMIC_COLUMN *str, size_t size)
+{
+  if (!size)
+    size= DYNCOL_SYZERESERVE;
+  /*
+    Make string with no fields (empty header)
+    - First \0 is flags
+    - other four \0 is 0 fileds counter
+  */
+  if (init_dynamic_string(str, NULL,
+                              size + FIXED_HEADER_SIZE, DYNCOL_SYZERESERVE))
+    return TRUE;
+  bzero(str->str, FIXED_HEADER_SIZE);
+  str->length= FIXED_HEADER_SIZE;
+  return FALSE;
+}
+
+
+/**
+  Calculate how many bytes needed to store val as variable length integer
+  where fist bit indicate continuation of the sequence.
+
+  @param val             The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+static size_t dynamic_column_var_uint_bytes(ulonglong val)
+{
+  size_t len= 0;
+  do
+  {
+    len++;
+    val>>= 7;
+  } while (val);
+  return len;
+}
+
+
+/**
+  Add variable value int to the string.
+
+  @param str             The string where to put the value
+  @param val             The value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_var_uint_add(DYNAMIC_COLUMN *str, ulonglong val)
+{
+  if (dynstr_realloc(str, 10)) // max what we can use
+    return ER_DYNCOL_RESOURCE;
+
+  do
+  {
+    ulonglong rest= val >> 7;
+    str->str[str->length++]= ((val & 0x7f) | (rest ? 0x80 : 0x00));
+    val= rest;
+  } while (val);
+  return ER_DYNCOL_OK;
+}
+
+/**
+  Reads variable length unsigned int value from the string
+
+  @param data            The string which should be read
+  @param len             Where to put length of the string read in bytes
+
+  @return value of the unsigned integer read from the string
+*/
+
+ulonglong dynamic_column_var_uint_get(uchar *data, size_t *len)
+{
+  ulonglong val= 0;
+  *len= 0;
+  for(;;)
+  {
+    val+= (((ulonglong)(data[len[0]] & 0x7f)) << (len[0]*7));
+    if (!(data[len[0]] & 0x80))
+      break;
+    len[0]++;
+  }
+  len[0]++;
+  return val;
+}
+
+/**
+  Calculate how many bytes needed to store val as unsigned.
+
+  @param val             The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_uint_bytes(ulonglong val)
+{
+  size_t len= 0;
+  do
+  {
+    len++;
+    val>>= 8;
+  } while (val);
+  return len;
+}
+
+
+/**
+  Append the string with given unsigned int value.
+
+  @param str             The string where to put the value
+  @param val             The value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_uint_add(DYNAMIC_COLUMN *str, ulonglong val)
+{
+  if (dynstr_realloc(str, 8)) // max what we can use
+    return ER_DYNCOL_RESOURCE;
+  do
+  {
+    str->str[str->length++]= val & 0xff;
+    val>>= 8;
+  } while (val);
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read unsigned int value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_uint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data,
+                             size_t length)
+{
+  ulonglong value= 0;
+  size_t i;
+  for (i= 0; i < length; i++)
+  {
+    value+= ((ulonglong)data[i]) << (i*8);
+  }
+  store_it_here->ulong_value= value;
+  return ER_DYNCOL_OK;
+}
+
+/**
+  Calculate how many bytes needed to store val as signed in following encoding:
+    0 -> 0
+   -1 -> 1
+    1 -> 2
+   -2 -> 3
+    2 -> 4
+   ...
+
+  @param val             The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_sint_bytes(longlong val)
+{
+  return dynamic_column_uint_bytes((val << 1) ^
+                                   (val < 0 ? ULL(0xffffffffffffffff) : 0));
+}
+
+
+/**
+  Append the string with given signed int value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_sint_add(DYNAMIC_COLUMN *str, longlong val)
+{
+  return dynamic_column_uint_add(str,
+                                 (val << 1) ^
+                                 (val < 0 ? ULL(0xffffffffffffffff) : 0));
+}
+
+
+/**
+  Read signed int value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_sint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data,
+                             size_t length)
+{
+  ulonglong val;
+  dynamic_column_uint_read(store_it_here, data, length);
+  val= store_it_here->ulong_value;
+  if (val & 1)
+    val= (val >> 1) ^ ULL(0xffffffffffffffff);
+  else
+    val>>= 1;
+  store_it_here->long_value= (longlong)(val);
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Calculate how many bytes needed to store the value.
+
+  @param value          The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_value_len(DYNAMIC_COLUMN_VALUE *value)
+{
+  switch (value->type) {
+  case DYN_COL_NULL:
+    return 0;
+  case DYN_COL_INT:
+    return dynamic_column_sint_bytes(value->long_value);
+  case DYN_COL_UINT:
+    return dynamic_column_uint_bytes(value->ulong_value);
+  case DYN_COL_DOUBLE:
+    return 8;
+  case DYN_COL_STRING:
+    return (dynamic_column_var_uint_bytes(value->charset->number) +
+            value->string_value.length);
+  case DYN_COL_DECIMAL:
+    return (dynamic_column_var_uint_bytes(value->decimal_value.intg) +
+            dynamic_column_var_uint_bytes(value->decimal_value.frac) +
+            decimal_bin_size(value->decimal_value.intg +
+                             value->decimal_value.frac,
+                             value->decimal_value.frac));
+  case DYN_COL_DATETIME:
+    /* date+time in bits: 14 + 4 + 5 + 10 + 6 + 6 + 20 + 1 66bits ~= 9 bytes */
+    return 9;
+  case DYN_COL_DATE:
+    /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
+    return 3;
+  case DYN_COL_TIME:
+    /* time in bits: 10 + 6 + 6 + 20 + 1 = 43bits ~= 6bytes*/
+    return 6;
+  default:
+    DBUG_ASSERT(0);
+    return 0;
+  }
+}
+
+
+/**
+  Append the string with given double value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_double_add(DYNAMIC_COLUMN *str, double val)
+{
+   if (dynstr_realloc(str, 8))
+     return ER_DYNCOL_RESOURCE;
+   float8store(str->str + str->length, val);
+   str->length+= 8;
+   return ER_DYNCOL_OK;
+}
+
+/**
+  Read double value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_double_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                               uchar *data,
+                               size_t length)
+{
+  if (length != 8)
+    return ER_DYNCOL_FORMAT;
+  float8get(store_it_here->double_value, data);
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Append the string with given string value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_string_add(DYNAMIC_COLUMN *str, LEX_STRING *string,
+                              CHARSET_INFO *charset)
+{
+  int rc;
+  if ((rc= dynamic_column_var_uint_add(str, charset->number)))
+    return rc;
+  if (dynstr_append_mem(str, string->str, string->length))
+    return ER_DYNCOL_RESOURCE;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read string value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_string_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                               uchar *data,
+                               size_t length)
+{
+  size_t len;
+  store_it_here->charset= get_charset(dynamic_column_var_uint_get(data, &len),
+                                      MYF(0));
+  if (store_it_here->charset == NULL || len > length)
+    return ER_DYNCOL_FORMAT;
+  data+= len;
+  store_it_here->string_value.length= (length-= len);
+  store_it_here->string_value.str= (char*)data;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Append the string with given decimal value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_decimal_add(DYNAMIC_COLUMN *str,
+                               decimal_t *value)
+{
+  int rc;
+  uint bin_size= decimal_bin_size(value->intg + value->frac, value->frac);
+  if ((rc= dynamic_column_var_uint_add(str, value->intg)) ||
+      (rc= dynamic_column_var_uint_add(str, value->frac)))
+    return rc;
+  if (dynstr_realloc(str, bin_size))
+    return ER_DYNCOL_RESOURCE;
+  decimal2bin(value, (uchar *)str->str + str->length, value->intg + value->frac,
+              value->frac);
+  str->length+= bin_size;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Prepare the value to be used as decimal.
+
+  @param value           The value structure which sould be setup.
+*/
+
+void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
+{
+  value->decimal_value.buf= value->decimal_buffer;
+  value->decimal_value.len= DECIMAL_BUFF_LENGTH;
+  // just to be safe
+  value->type= DYN_COL_DECIMAL;
+  decimal_make_zero(&value->decimal_value);
+}
+
+
+/**
+  Read decimal value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_decimal_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                uchar *data,
+                                size_t length __attribute__((unused)))
+{
+  size_t len;
+  uint intg, frac;
+
+  dynamic_column_prepare_decimal(store_it_here);
+  intg= dynamic_column_var_uint_get(data, &len);
+  data+= len;
+  frac= dynamic_column_var_uint_get(data, &len);
+  data+= len;
+  if (bin2decimal(data, &store_it_here->decimal_value, intg + frac, frac) !=
+      E_DEC_OK)
+    return ER_DYNCOL_FORMAT;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Append the string with given datetime value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_time_add(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+  int rc;
+  /*
+    0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
+     12345678901234123412345     1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456><123456><123456><123456>
+  */
+  if ((rc= dynamic_column_date_add(str, value)) ||
+      (rc= dynamic_column_time_add(str, value)))
+    return rc;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read datetime value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                  uchar *data,
+                                  size_t length)
+{
+  uint rc= ER_DYNCOL_FORMAT;
+  /*
+    0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
+     12345678901234123412345     1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456><123456><123456><123456>
+  */
+  if (length != 9)
+    goto err;
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+  if ((rc= dynamic_column_date_read_int(store_it_here, data, 3)) ||
+      (rc= dynamic_column_time_read_int(store_it_here, data + 3, 6)))
+    goto err;
+  return ER_DYNCOL_OK;
+
+err:
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+  return rc;
+}
+
+
+/**
+  Append the string with given time value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_time_add(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+  uchar *buf= ((uchar *)str->str) + str->length;
+  if (dynstr_realloc(str, 6))
+    return ER_DYNCOL_RESOURCE;
+  if (value->time_type == MYSQL_TIMESTAMP_NONE ||
+      value->time_type == MYSQL_TIMESTAMP_ERROR ||
+      value->time_type == MYSQL_TIMESTAMP_DATE)
+    value->neg= value->second_part= value->hour=
+      value->minute= value->second= 0;
+  DBUG_ASSERT(value->hour <= 838);
+  DBUG_ASSERT(value->minute <= 59);
+  DBUG_ASSERT(value->second <= 59);
+  DBUG_ASSERT(value->second_part <= 999999);
+  /*
+    00000!<-hours--><min-><sec-><---microseconds--->
+         1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456>
+  */
+  buf[0]= (value->second_part & 0xff);
+  buf[1]= ((value->second_part & 0xff00) >> 8);
+  buf[2]= (((value->second & 0xf) << 4) |
+           ((value->second_part & 0xf0000) >> 16));
+  buf[3]= ((value->minute << 2) | ((value->second & 0x30) >> 4));
+  buf[4]= (value->hour & 0xff);
+  buf[5]= ((value->neg ? 0x4 : 0) | (value->hour >> 8));
+  str->length+= 6;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read time value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data,
+                             size_t length)
+{
+  store_it_here->time_value.year= store_it_here->time_value.month=
+    store_it_here->time_value.day= 0;
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_TIME;
+  return dynamic_column_time_read_int(store_it_here, data, length);
+}
+
+/**
+  Internal function for reading time part from the string.
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_time_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                 uchar *data,
+                                 size_t length)
+{
+  if (length != 6)
+    goto err;
+  /*
+    00000!<-hours--><min-><sec-><---microseconds--->
+         1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456>
+  */
+  store_it_here->time_value.second_part= (data[0] |
+                                          (data[1] << 8) |
+                                          ((data[2] & 0xf) << 16));
+  store_it_here->time_value.second= ((data[2] >> 4) |
+                                     ((data[3] & 0x3) << 4));
+  store_it_here->time_value.minute= (data[3] >> 2);
+  store_it_here->time_value.hour= (((((uint)data[5]) & 0x3 ) << 8) | data[4]);
+  store_it_here->time_value.neg= ((data[5] & 0x4) ? 1 : 0);
+  if (store_it_here->time_value.second > 59 ||
+      store_it_here->time_value.minute > 59 ||
+      store_it_here->time_value.hour > 838 ||
+      store_it_here->time_value.second_part > 999999)
+    goto err;
+  return ER_DYNCOL_OK;
+
+err:
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+  return ER_DYNCOL_FORMAT;
+}
+
+
+/**
+  Append the string with given date value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_add(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+  uchar *buf= ((uchar *)str->str) + str->length;
+  if (dynstr_realloc(str, 3))
+    return ER_DYNCOL_RESOURCE;
+  if (value->time_type == MYSQL_TIMESTAMP_NONE ||
+      value->time_type == MYSQL_TIMESTAMP_ERROR ||
+      value->time_type == MYSQL_TIMESTAMP_TIME)
+    value->year= value->month= value->day = 0;
+  DBUG_ASSERT(value->year <= 9999);
+  DBUG_ASSERT(value->month <= 12);
+  DBUG_ASSERT(value->day <= 31);
+  /*
+    0<----year----><mn><day>
+    012345678901234123412345
+    <123456><123456><123456>
+  */
+  buf[0]= (value->day |
+           ((value->month & 0x7) << 5));
+  buf[1]= ((value->month >> 3) | ((value->year & 0x7F) << 1));
+  buf[2]= (value->year >> 7);
+  str->length+= 3;
+  return ER_DYNCOL_OK;
+}
+
+
+
+/**
+  Read date value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+my_bool dynamic_column_date_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                 uchar *data,
+                                 size_t length)
+{
+  store_it_here->time_value.neg= store_it_here->time_value.second_part=
+    store_it_here->time_value.hour= store_it_here->time_value.minute=
+    store_it_here->time_value.second= 0;
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_DATE;
+  return dynamic_column_date_read_int(store_it_here, data, length);
+}
+
+/**
+  Internal function for reading date part from the string.
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                 uchar *data,
+                                 size_t length)
+{
+  if (length != 3)
+    goto err;
+  /*
+    0<----year----><mn><day>
+     12345678901234123412345
+    <123456><123456><123456>
+  */
+  store_it_here->time_value.day= (data[0] & 0x1f);
+  store_it_here->time_value.month= (((data[1] & 0x1) << 3) |
+                                    (data[0] >> 5));
+  store_it_here->time_value.year= ((((uint)data[2]) << 7) |
+                                    (data[1] >> 1));
+  if (store_it_here->time_value.day > 31 ||
+      store_it_here->time_value.month > 12 ||
+      store_it_here->time_value.year > 9999)
+    goto err;
+  return ER_DYNCOL_OK;
+
+err:
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+  return ER_DYNCOL_FORMAT;
+}
+
+
+/**
+  Append the string with given value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int data_add(DYNAMIC_COLUMN *str, DYNAMIC_COLUMN_VALUE *value)
+{
+  switch (value->type) {
+  case DYN_COL_INT:
+    return dynamic_column_sint_add(str, value->long_value);
+  case DYN_COL_UINT:
+    return dynamic_column_uint_add(str, value->ulong_value);
+  case DYN_COL_DOUBLE:
+    return dynamic_column_double_add(str, value->double_value);
+  case DYN_COL_STRING:
+    return dynamic_column_string_add(str, &value->string_value,
+                                     value->charset);
+  case DYN_COL_DECIMAL:
+    return dynamic_column_decimal_add(str, &value->decimal_value);
+  case DYN_COL_DATETIME:
+    /* date+time in bits: 14 + 4 + 5 + 5 + 6 + 6 40bits = 5 bytes */
+    return dynamic_column_date_time_add(str, &value->time_value);
+  case DYN_COL_DATE:
+    /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
+    return dynamic_column_date_add(str, &value->time_value);
+  case DYN_COL_TIME:
+    /* time in bits: 5 + 6 + 6 = 17bits ~= 3bytes*/
+    return dynamic_column_time_add(str, &value->time_value);
+  default:
+    DBUG_ASSERT(0);
+    return ER_DYNCOL_DATA;
+  }
+}
+
+
+/**
+  Calculate length of offset field for given data length
+
+  @param data_length     Length of the data segment
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_offset_bytes(size_t data_length)
+{
+  if (data_length < 0x1f)  // all 1 value is reserved
+    return 1;
+  if (data_length < 0x1fff)  // all 1 value is reserved
+    return 2;
+  if (data_length < 0x1fffff)  // all 1 value is reserved
+    return 3;
+  if (data_length < 0x1fffffff)  // all 1 value is reserved
+    return 4;
+  return 5;
+}
+
+/**
+  Store offset and type information in the given place
+
+  @param place           Beginning of the index entry
+  @param offset_size     Size of offset field in bytes
+  @param type            Type to be written
+  @param offset          Offset to be written
+*/
+
+void type_and_offset_store(uchar *place, size_t offset_size,
+                          DYNAMIC_COLUMN_TYPE type,
+                          size_t offset)
+{
+  ulong val = (((ulong) offset) << 3) | (type - 1);;
+  place+= COLUMN_NUMBER_SIZE;
+  DBUG_ASSERT(type != DYN_COL_NULL);
+  DBUG_ASSERT(((type - 1) & (~7)) == 0); // fit in 3 bits
+  switch (offset_size) {
+  case 1:
+    DBUG_ASSERT(offset < 0x1f); // all 1 value is reserved
+    place[0]= (uchar)val;
+    break;
+  case 2:
+    DBUG_ASSERT(offset < 0x1fff); // all 1 value is reserved
+    int2store(place, val);
+    break;
+  case 3:
+    DBUG_ASSERT(offset < 0x1fffff); // all 1 value is reserved
+    int3store(place, val);
+    break;
+  case 4:
+    DBUG_ASSERT(offset < 0x1fffffff); // all 1 value is reserved
+    int4store(place, val);
+    break;
+  default:
+    DBUG_ASSERT(0); // impossible
+  }
+}
+
+
+/**
+  Read offset and type information from index entry
+
+  @param type            Where to put type info
+  @param offset          Where to put offset info
+  @param place           Beginning of the index entry
+  @param offset_size     Size of offset field in bytes
+*/
+
+void type_and_offset_read(DYNAMIC_COLUMN_TYPE *type,
+                          size_t *offset,
+                          uchar *place, size_t offset_size)
+{
+  ulong val;
+  place+= COLUMN_NUMBER_SIZE; // skip column number
+  switch (offset_size) {
+  case 1:
+    val= (ulong)place[0];
+    break;
+  case 2:
+    val= uint2korr(place);
+    break;
+  case 3:
+    val= uint3korr(place);
+    break;
+  case 4:
+    val= uint4korr(place);
+    break;
+  default:
+    DBUG_ASSERT(0); // impossible
+  }
+  *type= (val & 0x7) + 1;
+  *offset= val >> 3;
+}
+
+/**
+  Comparator function for references on column numbers for qsort
+*/
+
+int column_sort(const void *a, const void *b)
+{
+  return **((uint **)a) - **((uint **)b);
+}
+
+/**
+  Write information to the fixed header
+
+  @param str             String where to write the header
+  @param offset_size     Size of offset field in bytes
+  @param column_count    Number of columns
+*/
+
+static void set_fixed_header(DYNAMIC_COLUMN *str,
+                             uint offset_size,
+                             uint column_count)
+{
+  DBUG_ASSERT(column_count <= 0xffff);
+  DBUG_ASSERT(offset_size <= 4);
+  str->str[0]= ((str->str[0] & ~DYNCOL_FLG_OFFSET) |
+                (offset_size - 1)); // size of offset
+  int2store(str->str + 1, column_count); // columns number
+  DBUG_ASSERT((str->str[0] & (~DYNCOL_FLG_KNOWN)) == 0);
+}
+
+
+/*
+  Read offset size (O) and column count (C) from string (S)
+*/
+
+#define read_fixed_header(S,O,C) do {         \
+  (O)= ((S)->str[0] & DYNCOL_FLG_OFFSET) + 1; \
+  (C)= uint2korr((S)->str + 1);               \
+}while(0);
+
+
+/*
+  Calculete entry size (E) and header size (H) by offset size (O) and column
+  count (C).
+*/
+
+#define calc_param(E,H,O,C) do { \
+  (E)= (O) + COLUMN_NUMBER_SIZE; \
+  (H)= (E) * (C);                \
+}while(0);
+
+
+/**
+  Adds columns into the empty string
+
+  @param str             String where to write the data
+  @param header_size     Size of the header without fixed part
+  @param offset_size     Size of offset field in bytes
+  @param column_count    Number of columns in the arrays
+  @parem non_null_count  Number of non-null columns in the arrays
+  @param data_size       Size of the data segment
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+  @param new_str         True if we need allocate new string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_new_column_add(DYNAMIC_COLUMN *str,
+                           size_t header_size,
+                           size_t offset_size,
+                           uint column_count,
+                           uint non_null_count,
+                           size_t data_size,
+                           uint *column_numbers,
+                           DYNAMIC_COLUMN_VALUE *values,
+                           my_bool new_str)
+{
+  uchar *header_end;
+  uint **columns_order;
+  uint i;
+  uint entry_size= COLUMN_NUMBER_SIZE + offset_size;
+  int err= ER_DYNCOL_RESOURCE;
+  if (!(columns_order= malloc(sizeof(uint*)*column_count)))
+    return ER_DYNCOL_RESOURCE;
+  if (new_str)
+  {
+    if (dynamic_column_init_str(str,
+                                data_size + header_size + DYNCOL_SYZERESERVE))
+      goto err;
+  }
+  else
+  {
+    str->length= 0;
+    bzero(str->str, FIXED_HEADER_SIZE);
+    str->length= FIXED_HEADER_SIZE;
+    if (dynstr_realloc(str, data_size + header_size + DYNCOL_SYZERESERVE))
+      goto err;
+  }
+
+  /* sort columns for the header */
+  for (i= 0; i < column_count; i++)
+    columns_order[i]= column_numbers + i;
+  qsort(columns_order, (size_t)column_count, sizeof(uint*), &column_sort);
+  /* check numbers */
+  for (i= 0; i < column_count - 1; i++)
+  {
+    if (columns_order[i][0] == columns_order[i + 1][0])
+    {
+      err= ER_DYNCOL_DATA;
+      goto err;
+    }
+  }
+
+  DBUG_ASSERT(str->length == FIXED_HEADER_SIZE);
+  set_fixed_header(str, offset_size, non_null_count);
+  DBUG_ASSERT(str->max_length > str->length + header_size);
+  str->length+= header_size; // reserve place for header
+  header_end= (uchar *)str->str + FIXED_HEADER_SIZE;
+  for (i= 0; i < column_count; i++)
+  {
+    uint ord= columns_order[i] - column_numbers;
+    if (values[ord].type != DYN_COL_NULL)
+    {
+      int2store(header_end, column_numbers[ord]);
+      type_and_offset_store(header_end, offset_size,
+                            values[ord].type,
+                            str->length - header_size - FIXED_HEADER_SIZE);
+      if ((err= data_add(str, values + ord)))
+        goto err;
+      header_end+= entry_size;
+    }
+  }
+  err= ER_DYNCOL_OK;
+err:
+  free(columns_order);
+  return err;
+}
+
+/**
+  Create packed string which contains given columns (internal)
+
+  @param str             String where to write the data
+  @param column_count    Number of columns in the arrays
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+  @param new_str         True if we need allocate new string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_create_many_int(DYNAMIC_COLUMN *str,
+                                   uint column_count,
+                                   uint *column_numbers,
+                                   DYNAMIC_COLUMN_VALUE *values,
+                                   my_bool new_str)
+{
+  size_t data_size= 0;
+  size_t header_size, offset_size;
+  uint i;
+  int not_null_column_count= column_count;
+  if (new_str)
+    bzero(str, sizeof(DYNAMIC_COLUMN)); // to make dynstr_free() working;
+  for (i= 0; i < column_count; i++)
+  {
+    data_size+= dynamic_column_value_len(values + i);
+    if (values[i].type == DYN_COL_NULL)
+      not_null_column_count--;
+  }
+
+  if ((offset_size= dynamic_column_offset_bytes(data_size)) >= 5)
+    return ER_DYNCOL_LIMIT;
+
+  /* header entry is column number + offset&type */
+  header_size= not_null_column_count * (offset_size + 2);
+
+  return dynamic_new_column_add(str,
+                                header_size, offset_size,
+                                column_count,
+                                not_null_column_count,
+                                data_size,
+                                column_numbers, values,
+                                new_str);
+}
+
+
+/**
+  Create packed string which contains given columns
+
+  @param str             String where to write the data
+  @param column_count    Number of columns in the arrays
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_create_many(DYNAMIC_COLUMN *str,
+                               uint column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values)
+{
+  return dynamic_column_create_many_int(str, column_count,
+                                        column_numbers, values,
+                                        TRUE);
+}
+
+
+/**
+  Create packed string which contains given column
+
+  @param str             String where to write the data
+  @param column_number   Column number
+  @param value           The columns value
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value)
+{
+  return dynamic_column_create_many(str, 1, &column_nr, value);
+}
+
+
+/**
+  Calculate length of data between given two header entries
+
+  @param entry           Pointer to the first entry
+  @param entry_next      Pointer to the last entry
+  @param header_end      Pointer to the header end
+  @param offset_size     Size of offset field in bytes
+  @param last_offset     Size of the data segment
+
+  @return number of bytes
+*/
+
+size_t get_length_interval (uchar *entry, uchar *entry_next,
+                            uchar *header_end, size_t offset_size,
+                            size_t last_offset)
+{
+  size_t offset, offset_next;
+  DYNAMIC_COLUMN_TYPE type, type_next;
+  DBUG_ASSERT(entry < entry_next);
+  type_and_offset_read(&type, &offset, entry, offset_size);
+  if (entry_next >= header_end)
+    return last_offset - offset;
+  type_and_offset_read(&type_next, &offset_next, entry_next, offset_size);
+  return offset_next - offset;
+}
+
+/*
+  Calculate length of data of one column
+
+
+  @param entry           Pointer to the first entry
+  @param header_end      Pointer to the header end
+  @param offset_size     Size of offset field in bytes
+  @param last_offset     Size of the data segment
+
+  @return number of bytes
+*/
+
+size_t get_length(uchar *entry, uchar *header_end,
+                  size_t offset_size,
+                  size_t last_offset)
+{
+  return get_length_interval(entry,
+                             entry + offset_size + COLUMN_NUMBER_SIZE,
+                             header_end, offset_size, last_offset);
+}
+
+
+/**
+  Comparator function for references to header entries for qsort
+*/
+
+int header_compar(const void *a, const void *b)
+{
+  uint va= uint2korr((uchar*)a), vb= uint2korr((uchar*)b);
+  return (va > vb ? 1 : (va < vb ? -1 : 0));
+}
+
+
+/**
+  Find column and fill information about it
+
+  @param type            Returns type of the column
+  @param data            Returns a pointer to the data
+  @param length          Returns length of the data
+  @param offset_size     Size of offset field in bytes
+  @param column_count    Number of column in the packed string
+  @param data_end        Pointer to the data end
+  @param num             Number of the column we want to fetch
+  @param entry_pos       NULL or place where to put reference to the entry
+*/
+
+void find_column(DYNAMIC_COLUMN_TYPE *type, uchar **data, size_t *length,
+                 uchar *header, size_t offset_size, uint column_count,
+                 uchar *data_end, uint num, uchar **entry_pos)
+{
+  uchar *entry;
+  size_t offset;
+  size_t header_size, entry_size;
+  uchar key[2+4];
+  if (!entry_pos)
+    entry_pos= &entry;
+
+  calc_param(entry_size, header_size, offset_size, column_count);
+  int2store(key, num);
+  entry= bsearch(key, header, (size_t)column_count, entry_size,
+                 &header_compar);
+  if (!entry)
+  {
+    *type= DYN_COL_NULL;
+    *entry_pos= NULL;
+    return;
+  }
+  type_and_offset_read(type, &offset, entry, offset_size);
+  *data= header + header_size + offset;
+  DBUG_ASSERT(*data < data_end);
+  *length= get_length(entry, header + header_size, offset_size,
+                      data_end - (header + header_size));
+  *entry_pos= entry;
+  return;
+}
+
+
+/**
+  Make simple check of the packed string format
+
+  @param str             The string to check
+
+  @retval FALSE OK
+  @retval TRUE  error
+*/
+
+static my_bool dynamic_column_str_check(DYNAMIC_COLUMN *str)
+{
+  if (str == NULL)
+    return TRUE;
+  if (str->length == 0)
+    return FALSE;
+  return ((str->length < FIXED_HEADER_SIZE) ||
+          (str->str[0] & (~DYNCOL_FLG_KNOWN)));
+}
+
+/**
+  Get dynamic column value
+
+  @param str             The packed string to extract the column
+  @param column_nr       Number of column to fetch
+  @param store_it_here   Where to store the extracted value
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_get(DYNAMIC_COLUMN *str, uint column_nr,
+                       DYNAMIC_COLUMN_VALUE *store_it_here)
+{
+  uchar *data;
+  size_t offset_size, length;
+  uint column_count;
+  int rc= ER_DYNCOL_FORMAT;
+
+  if (dynamic_column_str_check(str))
+    goto err;
+
+  if (str->length == 0)
+    goto null;
+
+  read_fixed_header(str, offset_size, column_count);
+  if (column_count == 0)
+    goto null;
+
+  find_column(&store_it_here->type, &data, &length,
+              (uchar*)str->str + FIXED_HEADER_SIZE,
+              offset_size, column_count, (uchar*)str->str + str->length,
+              column_nr, NULL);
+
+  switch (store_it_here->type)
+  {
+  case DYN_COL_INT:
+    rc= dynamic_column_sint_read(store_it_here, data, length);
+    break;
+  case DYN_COL_UINT:
+    rc= dynamic_column_uint_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DOUBLE:
+    rc= dynamic_column_double_read(store_it_here, data, length);
+    break;
+  case DYN_COL_STRING:
+    rc= dynamic_column_string_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DECIMAL:
+    rc= dynamic_column_decimal_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DATETIME:
+    rc= dynamic_column_date_time_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DATE:
+    rc= dynamic_column_date_read(store_it_here, data, length);
+    break;
+  case DYN_COL_TIME:
+    rc= dynamic_column_time_read(store_it_here, data, length);
+    break;
+  case DYN_COL_NULL:
+    rc= ER_DYNCOL_OK;
+    break;
+  default:
+    goto err;
+  }
+  return rc;
+
+null:
+    rc= ER_DYNCOL_OK;
+err:
+    store_it_here->type= DYN_COL_NULL;
+    return rc;
+}
+
+/**
+  Delete column with given number from the packed string
+
+  @param str             The packed string to delete the column
+  @param column_nr       Number of column to delete
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_delete(DYNAMIC_COLUMN *str, uint column_nr)
+{
+  uchar *data, *header_entry, *read, *write;
+  size_t offset_size, new_offset_size, length, entry_size, new_entry_size,
+         header_size, new_header_size, data_size, new_data_size,
+         deleted_entry_offset;
+  uint column_count, i;
+  DYNAMIC_COLUMN_TYPE type;
+
+  if (dynamic_column_str_check(str))
+    return ER_DYNCOL_FORMAT;
+
+  if (str->length == 0)
+    return ER_DYNCOL_OK;  // no columns
+
+  read_fixed_header(str, offset_size, column_count);
+
+  if (column_count == 0)
+     return ER_DYNCOL_OK;  // no columns
+
+  find_column(&type, &data, &length, (uchar*)str->str + FIXED_HEADER_SIZE,
+              offset_size, column_count, (uchar*)str->str + str->length,
+              column_nr, &header_entry);
+
+  if (type == DYN_COL_NULL)
+    return ER_DYNCOL_OK;  // no such column
+
+  if (column_count == 1)
+  {
+    /* delete the only column */
+    str->length= FIXED_HEADER_SIZE;
+    bzero(str->str, FIXED_HEADER_SIZE);
+    return ER_DYNCOL_OK;
+  }
+
+  calc_param(entry_size, header_size, offset_size, column_count);
+  entry_size= 2 + offset_size;
+  header_size= entry_size * column_count;
+  data_size= str->length - FIXED_HEADER_SIZE - header_size;
+
+  new_data_size= data_size - length;
+  if ((new_offset_size= dynamic_column_offset_bytes(new_data_size)) >= 5)
+    return ER_DYNCOL_LIMIT;
+  DBUG_ASSERT(new_offset_size <= offset_size);
+  calc_param(new_entry_size, new_header_size,
+             new_offset_size, column_count - 1);
+
+  deleted_entry_offset= (data - (uchar*)str->str) -
+    header_size - FIXED_HEADER_SIZE;
+
+
+  /* rewrite header*/
+  set_fixed_header(str, new_offset_size, column_count - 1);
+  for (i= 0, write= read= (uchar *)str->str + FIXED_HEADER_SIZE;
+       i < column_count;
+       i++, read+= entry_size, write+= new_entry_size)
+  {
+    size_t offs;
+    uint nm;
+    DYNAMIC_COLUMN_TYPE tp;
+    if (read == header_entry)
+    {
+#ifndef DBUG_OFF
+      nm= uint2korr(read);
+      type_and_offset_read(&tp, &offs, read,
+                           offset_size);
+      DBUG_ASSERT(nm == column_nr);
+      DBUG_ASSERT(offs == deleted_entry_offset);
+#endif
+      write-= new_entry_size; // do not move writer
+      continue; // skip removed field
+    }
+
+    nm= uint2korr(read),
+    type_and_offset_read(&tp, &offs, read,
+                         offset_size);
+
+    if (offs > deleted_entry_offset)
+      offs-= length; // data stored after removed data
+
+    int2store(write, nm);
+    type_and_offset_store(write, new_offset_size, tp, offs);
+  }
+
+  /* move data */
+  {
+    size_t first_chunk_len= (data - (uchar *)str->str) -
+      FIXED_HEADER_SIZE - header_size;
+    size_t second_chunk_len= new_data_size - first_chunk_len;
+    if (first_chunk_len)
+      memmove(str->str + FIXED_HEADER_SIZE + new_header_size,
+              str->str + FIXED_HEADER_SIZE + header_size,
+              first_chunk_len);
+    if (second_chunk_len)
+      memmove(str->str +
+              FIXED_HEADER_SIZE + new_header_size + first_chunk_len,
+              str->str +
+              FIXED_HEADER_SIZE + header_size + first_chunk_len + length,
+              second_chunk_len);
+  }
+
+  /* fix str length */
+  DBUG_ASSERT(str->length >=
+              FIXED_HEADER_SIZE + new_header_size + new_data_size);
+  str->length= FIXED_HEADER_SIZE + new_header_size + new_data_size;
+
+  return FALSE;
+}
+
+
+/**
+  Check existence of the column in the packed string
+
+  @param str             The packed string to check the column
+  @param column_nr       Number of column to check
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_exists(DYNAMIC_COLUMN *str, uint column_nr)
+{
+  uchar *data;
+  size_t offset_size, length;
+  uint column_count;
+  DYNAMIC_COLUMN_TYPE type;
+
+  if (dynamic_column_str_check(str))
+    return ER_DYNCOL_FORMAT;
+
+  if (str->length == 0)
+    return ER_DYNCOL_NO; // no columns
+
+  read_fixed_header(str, offset_size, column_count);
+
+  if (column_count == 0)
+     return ER_DYNCOL_NO;  // no columns
+
+  find_column(&type, &data, &length, (uchar*)str->str + FIXED_HEADER_SIZE,
+              offset_size, column_count, (uchar*)str->str + str->length,
+              column_nr, NULL);
+
+  return (type != DYN_COL_NULL ? ER_DYNCOL_YES : ER_DYNCOL_NO);
+}
+
+/**
+  List not-null columns in the packed string
+
+  @param str             The packed string
+  @param array_of_uint   Where to put reference on created array
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_list(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_uint)
+{
+  uchar *read;
+  size_t offset_size, entry_size;
+  uint column_count, i;
+
+  if (dynamic_column_str_check(str))
+    return ER_DYNCOL_FORMAT;
+
+  if (str->length == 0)
+  {
+    if (init_dynamic_array(array_of_uint, sizeof(uint),
+                           0, 10 CALLER_INFO))
+      return ER_DYNCOL_RESOURCE;
+    return ER_DYNCOL_OK; // no columns
+  }
+
+
+  read_fixed_header(str, offset_size, column_count);
+  entry_size= COLUMN_NUMBER_SIZE + offset_size;
+
+  if (init_dynamic_array(array_of_uint, sizeof(uint),
+                         column_count, 10 CALLER_INFO))
+    return ER_DYNCOL_RESOURCE;
+
+  for (i= 0, read= (uchar *)str->str + FIXED_HEADER_SIZE;
+       i < column_count;
+       i++, read+= entry_size)
+  {
+    uint nm= uint2korr(read);
+    if (insert_dynamic(array_of_uint, (uchar *)&nm))
+    {
+      delete_dynamic(array_of_uint);
+      return ER_DYNCOL_RESOURCE;
+    }
+  }
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Find the place of the column in the header or place where it should be put
+
+  @param num             Number of the column
+  @param header          Pointer to the header
+  @param entry_size      Size of a header entry
+  @param column_count    Number of columns in the packed string
+  @param entry           Return pointer to the entry or next entry
+
+  @retval TRUE found
+  @retval FALSE pointer set to the next row
+*/
+
+my_bool find_place(uint num,
+                   uchar *header, size_t entry_size, uint column_count,
+                   uchar **entry)
+{
+  uint mid, start, end, val;
+  int flag;
+
+  start= 0;
+  end= column_count -1;
+  mid= 1;
+  while (start != end)
+  {
+   uint val;
+   mid= (start + end) / 2;
+   val= uint2korr(header + mid * entry_size);
+   if ((flag= CMP_NUM(num, val)) <= 0)
+     end= mid;
+   else
+     start= mid + 1;
+  }
+  if (start != mid)
+  {
+    val= uint2korr(header + start * entry_size);
+    flag= CMP_NUM(num, val);
+  }
+  *entry= header + start * entry_size;
+  if (flag > 0)
+    *entry+= entry_size;        /* Point at next bigger key */
+  return flag == 0;
+}
+
+/*
+  Description of plan of adding/removing/updating a packed string
+*/
+
+typedef enum {PLAN_REPLACE, PLAN_ADD, PLAN_DELETE, PLAN_NOP} PLAN_ACT;
+
+struct st_plan {
+  DYNAMIC_COLUMN_VALUE *val;
+  uint *num;
+  uchar *place;
+  size_t length;
+  int hdelta, ddelta;
+  PLAN_ACT act;
+};
+typedef struct st_plan PLAN;
+
+
+int plan_sort(const void *a, const void *b)
+{
+  return ((PLAN *)a)->num[0] - ((PLAN *)b)->num[0];
+}
+
+#define DELTA_CHECK(S, D, C)        \
+  if ((S) == 0)                     \
+    (S)= (D);                       \
+  else if (((S) > 0 && (D) < 0) ||  \
+            ((S) < 0 && (D) > 0))   \
+  {                                 \
+    (C)= TRUE;                      \
+    break;                          \
+  }                                 \
+
+/**
+  Update the packed string with the given columns
+
+  @param str             String where to write the data
+  @param add_column_count Number of columns in the arrays
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_update_many(DYNAMIC_COLUMN *str,
+                               uint add_column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values)
+{
+  PLAN *plan;
+  uchar *header_end;
+  long data_delta= 0;
+  uint i, j, k;
+  uint new_column_count, column_count,
+       not_null= add_column_count;
+  int rc;
+  int header_delta= 0;
+  int header_delta_sign, data_delta_sign;
+  size_t offset_size, entry_size, header_size, data_size;
+  size_t new_offset_size, new_entry_size, new_header_size, new_data_size;
+  size_t max_offset;
+  my_bool copy;
+
+
+  if (add_column_count == 0)
+    return ER_DYNCOL_OK;
+
+  if (!(plan= malloc(sizeof(PLAN) * (add_column_count + 1))))
+    return ER_DYNCOL_RESOURCE;
+
+  for (i= 0; i < add_column_count; i++)
+  {
+    plan[i].val= values + i;
+    plan[i].num= column_numbers + i;
+    if (values[i].type == DYN_COL_NULL)
+      not_null--;
+  }
+  qsort(plan, (size_t)add_column_count, sizeof(PLAN), &plan_sort);
+
+  if (str->length == 0)
+  {
+    /* There is no columns so we just add them */
+    if (not_null == 0)
+    {
+      if (str->str)
+      {
+        if (dynstr_realloc(str, FIXED_HEADER_SIZE + DYNCOL_SYZERESERVE))
+          return ER_DYNCOL_RESOURCE;
+        bzero(str->str, FIXED_HEADER_SIZE);
+        str->length= FIXED_HEADER_SIZE;
+      }
+      else
+      {
+        if (dynamic_column_init_str(str,
+                                    FIXED_HEADER_SIZE + DYNCOL_SYZERESERVE))
+          return ER_DYNCOL_RESOURCE;
+      }
+      return  ER_DYNCOL_OK;
+    }
+    return dynamic_column_create_many_int(str, add_column_count,
+                                          column_numbers, values,
+                                          str->str == NULL);
+  }
+
+  read_fixed_header(str, offset_size, column_count);
+  new_column_count= column_count;
+
+  if (column_count == 0)
+  {
+    /* There is no columns so we just add them */
+    if (not_null == 0)
+      return  ER_DYNCOL_OK;
+    return dynamic_column_create_many_int(str, add_column_count,
+                                          column_numbers, values,
+                                          FALSE);
+  }
+
+  calc_param(entry_size, header_size, offset_size, column_count);
+  max_offset= str->length - (FIXED_HEADER_SIZE + header_size);
+  header_end= (uchar *)str->str + FIXED_HEADER_SIZE + header_size;
+
+  /* check numbers */
+  for (i= 0; i < add_column_count; i++)
+  {
+    uchar *entry;
+    if (i < add_column_count - 1 && plan[i].num[0] == plan[i + 1].num[0])
+    {
+      rc= ER_DYNCOL_DATA;
+      goto err;
+    }
+
+    if (find_place(plan[i].num[0],
+                   (uchar *)str->str + FIXED_HEADER_SIZE,
+                   entry_size, column_count, &entry))
+    {
+      if (plan[i].val->type == DYN_COL_NULL)
+      {
+        size_t entry_data_size;
+        new_column_count--;
+        /* replace the value */
+        plan[i].act= PLAN_DELETE;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta--;
+        /* get data delta in bytes */
+        entry_data_size= get_length(entry, header_end,
+                                    offset_size, max_offset);
+        plan[i].length= 0;
+        plan[i].ddelta= data_delta;
+        data_delta-= entry_data_size;
+      }
+      else
+      {
+        size_t entry_data_size;
+        /* replace the value */
+        plan[i].act= PLAN_REPLACE;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta;
+        /* get data delta in bytes */
+        entry_data_size= get_length(entry, header_end,
+                                    offset_size, max_offset);
+        plan[i].length= dynamic_column_value_len(plan[i].val);
+        plan[i].ddelta= data_delta;
+        data_delta+= plan[i].length - entry_data_size;
+      }
+    }
+    else
+    {
+      if (plan[i].val->type == DYN_COL_NULL)
+      {
+        plan[i].act= PLAN_NOP;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta;
+        /* get data delta in bytes */
+        plan[i].length= 0;
+        plan[i].ddelta= data_delta;
+      }
+      else
+      {
+        new_column_count++;
+        /* replace the value */
+        plan[i].act= PLAN_ADD;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta++;
+        /* get data delta in bytes */
+        plan[i].length= dynamic_column_value_len(plan[i].val);
+        plan[i].ddelta= data_delta;
+        data_delta+= plan[i].length;
+      }
+    }
+    plan[i].place= entry;
+  }
+  plan[add_column_count].hdelta= header_delta;
+  plan[add_column_count].ddelta= data_delta;
+  /*
+    check if it is only "incising" or only "decreasing" plan for (header
+    and data separately).
+  */
+  data_size= str->length - header_size - FIXED_HEADER_SIZE;
+  new_data_size= data_size + data_delta;
+  if ((new_offset_size= dynamic_column_offset_bytes(new_data_size)) >= 5)
+    return ER_DYNCOL_LIMIT;
+  //if (new_offset_size != offset_size) rewrite_header= TRUE;
+  header_delta_sign= new_offset_size - offset_size;
+  data_delta_sign= 0;
+  copy= FALSE;
+  for (i= 0; i < add_column_count; i++)
+  {
+    DELTA_CHECK(header_delta_sign, plan[i].hdelta, copy);
+    DELTA_CHECK(data_delta_sign, plan[i].ddelta, copy);
+  }
+
+  calc_param(new_entry_size, new_header_size,
+             new_offset_size, new_column_count);
+
+  //if (copy)
+  {
+    DYNAMIC_COLUMN tmp;
+    uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE,
+          *write;
+    if (dynamic_column_init_str(&tmp,
+                                (FIXED_HEADER_SIZE + new_header_size +
+                                 new_data_size + DYNCOL_SYZERESERVE)))
+    {
+      rc= ER_DYNCOL_RESOURCE;
+      goto err;
+    }
+    write= (uchar *)tmp.str + FIXED_HEADER_SIZE;
+    tmp.length= FIXED_HEADER_SIZE + new_header_size;
+    set_fixed_header(&tmp, new_offset_size, new_column_count);
+    data_delta= 0;
+    /* Copy data to the new string */
+    for (i= 0, j= 0; i < add_column_count || j < column_count; i++)
+    {
+      size_t first_offset;
+      uint start= j, end;
+      /* skip NOP */
+      while (i < add_column_count && plan[i].act == PLAN_NOP)
+        i++;
+      /* old data portion */
+      while (j < column_count &&
+             (i >= add_column_count ||
+              header_base + j * entry_size < plan[i].place))
+        j++;
+      end= j;
+      if (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE)
+        j++;
+      for (k= start; k < end; k++)
+      {
+        uchar *read= header_base + k * entry_size;
+        size_t offs;
+        uint nm;
+        DYNAMIC_COLUMN_TYPE tp;
+        nm= uint2korr(read);
+        type_and_offset_read(&tp, &offs, read,
+                             offset_size);
+        if (k == start)
+          first_offset= offs;
+        offs+= plan[i].ddelta;
+        int2store(write, nm);
+        type_and_offset_store(write, new_offset_size, tp, offs);
+        write+= new_entry_size;
+      }
+      if (start < end)
+      {
+        size_t data_size=
+          get_length_interval(header_base + start * entry_size,
+                              header_base + end * entry_size,
+                              header_end, offset_size, max_offset);
+        memcpy(tmp.str + tmp.length, (char *)header_end + first_offset,
+               data_size);
+        tmp.length+= data_size;
+      }
+
+      /* new data adding */
+      if (i < add_column_count)
+      {
+        if(plan[i].act == PLAN_ADD ||
+           plan[i].act == PLAN_REPLACE)
+        {
+          int2store(write, plan[i].num[0]);
+          type_and_offset_store(write, new_offset_size,
+                                plan[i].val[0].type,
+                                tmp.length -
+                                (FIXED_HEADER_SIZE + new_header_size));
+          write+= new_entry_size;
+          data_add(&tmp, plan[i].val);
+        }
+        data_delta= plan[i].ddelta;
+      }
+    }
+    dynamic_column_column_free(str);
+    *str= tmp;
+  }
+
+  rc= ER_DYNCOL_OK;
+err:
+    free(plan);
+    return rc;
+}
+
+
+/**
+  Update the packed string with the given column
+
+  @param str             String where to write the data
+  @param column_number   Array of columns number
+  @param values          Array of columns values
+
+  @return ER_DYNCOL_* return code
+*/
+
+
+int dynamic_column_update(DYNAMIC_COLUMN *str, uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value)
+{
+  return dynamic_column_update_many(str, 1, &column_nr, value);
+}

=== modified file 'sql/item.h'
--- sql/item.h	2011-04-27 04:11:06 +0000
+++ sql/item.h	2011-04-29 09:52:28 +0000
@@ -18,6 +18,10 @@
 #pragma interface			/* gcc class implementation */
 #endif
 
+C_MODE_START
+#include <ma_dyncol.h>
+C_MODE_END
+
 inline
 bool trace_unsupported_func(const char *where, const char *processor_name)
 {
@@ -471,6 +475,17 @@
 };
 
 
+struct st_dyncall_create_def
+{
+  Item  *num, *value;
+  CHARSET_INFO *cs;
+  uint len, frac;
+  DYNAMIC_COLUMN_TYPE type;
+};
+
+typedef struct st_dyncall_create_def DYNCALL_CREATE_DEF;
+
+
 typedef bool (Item::*Item_processor) (uchar *arg);
 /*
   Analyzer function
@@ -804,7 +819,11 @@
   { return val_decimal(val); }
   virtual bool val_bool_result() { return val_bool(); }
   virtual bool is_null_result() { return is_null(); }
-
+  /*
+    Returns 1 if result type and collation for val_str() can change between
+    calls
+  */
+  virtual bool dynamic_result() { return 0; }
   /* 
     Bitmap of tables used by item
     (note: if you need to check dependencies on individual columns, check out

=== modified file 'sql/item_cmpfunc.cc'
--- sql/item_cmpfunc.cc	2011-04-27 04:11:06 +0000
+++ sql/item_cmpfunc.cc	2011-04-29 09:52:28 +0000
@@ -6074,3 +6074,34 @@
   DBUG_ASSERT(0);
   return NULL;
 }
+
+
+longlong Item_func_dyncol_exists::val_int()
+{
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+  DYNAMIC_COLUMN col;
+  String *str;
+  uint num;
+  int rc;
+
+  num= args[1]->val_int();
+  str= args[0]->val_str(&tmp);
+  if (args[0]->null_value || args[1]->null_value)
+    goto null;
+  col.length= str->length();
+  /* We do not change the string, so could do this trick */
+  col.str= (char *)str->ptr();
+  rc= dynamic_column_exists(&col, num);
+  if (rc < 0)
+  {
+    dynamic_column_error_message(rc);
+    goto null;
+  }
+  null_value= FALSE;
+  return rc == ER_DYNCOL_YES;
+
+null:
+  null_value= TRUE;
+  return 0;
+}

=== modified file 'sql/item_cmpfunc.h'
--- sql/item_cmpfunc.h	2011-04-27 04:11:06 +0000
+++ sql/item_cmpfunc.h	2011-04-29 09:52:28 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+/*dyncol_exists Copyright (c) 2000, 2010, Oracle and/or its affiliates.
 
    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
@@ -1869,3 +1869,11 @@
 
 bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, 
                              const char *warn_name, MYSQL_TIME *l_time);
+
+class Item_func_dyncol_exists :public Item_bool_func
+{
+public:
+  Item_func_dyncol_exists(Item *str, Item *num) :Item_bool_func(str, num) {}
+  longlong val_int();
+  const char *func_name() const { return "column_exists"; }
+};

=== modified file 'sql/item_create.cc'
--- sql/item_create.cc	2011-02-20 16:51:43 +0000
+++ sql/item_create.cc	2011-04-29 09:52:28 +0000
@@ -27,6 +27,50 @@
 
 /*
 =============================================================================
+  HELPER FUNCTIONS
+=============================================================================
+*/
+
+/*
+  Get precision and scale for a declaration
+ 
+  return
+    0  ok
+    1  error
+*/
+
+bool get_length_and_scale(ulonglong length, ulonglong decimals,
+                          ulong *out_length, uint *out_decimals,
+                          uint max_precision, uint max_scale,
+                          const char *name)
+{
+  if (length > (ulonglong) max_precision)
+  {
+    my_error(ER_TOO_BIG_PRECISION, MYF(0), (int) length, name,
+             max_precision);
+    return 1;
+  }
+  if (decimals > (ulonglong) max_scale)
+  {
+    my_error(ER_TOO_BIG_SCALE, MYF(0), (int) decimals, name,
+             DECIMAL_MAX_SCALE);
+    return 1;
+  }
+
+  *out_length=  (ulong) length;
+  *out_decimals=  (uint) decimals;
+  my_decimal_trim(out_length, out_decimals);
+  
+  if (*out_length < *out_decimals)
+  {
+    my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
+    return 1;
+  }
+  return 0;
+}
+
+/*
+=============================================================================
   LOCAL DECLARATIONS
 =============================================================================
 */
@@ -5054,6 +5098,17 @@
                  CHARSET_INFO *cs)
 {
   Item *UNINIT_VAR(res);
+  ulonglong length= 0, decimals= 0;
+  int error;
+  
+  /*
+    We don't have to check for error here as sql_yacc.yy has guaranteed
+    that the values are in range of ulonglong
+  */
+  if (c_len)
+    length= (ulonglong) my_strtoll10(c_len, NULL, &error);
+  if (c_dec)
+    decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error);
 
   switch (cast_type) {
   case ITEM_CAST_BINARY:
@@ -5076,72 +5131,45 @@
     break;
   case ITEM_CAST_DECIMAL:
   {
-    ulong len= 0;
-    uint dec= 0;
-
-    if (c_len)
-    {
-      ulong decoded_size;
-      errno= 0;
-      decoded_size= strtoul(c_len, NULL, 10);
-      if (errno != 0)
-      {
-        my_error(ER_TOO_BIG_PRECISION, MYF(0), c_len, a->name,
-                 DECIMAL_MAX_PRECISION);
-        return NULL;
-      }
-      len= decoded_size;
-    }
-
-    if (c_dec)
-    {
-      ulong decoded_size;
-      errno= 0;
-      decoded_size= strtoul(c_dec, NULL, 10);
-      if ((errno != 0) || (decoded_size > UINT_MAX))
-      {
-        my_error(ER_TOO_BIG_SCALE, MYF(0), c_dec, a->name,
-                 DECIMAL_MAX_SCALE);
-        return NULL;
-      }
-      dec= decoded_size;
-    }
-    my_decimal_trim(&len, &dec);
-    if (len < dec)
-    {
-      my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
-      return 0;
-    }
-    if (len > DECIMAL_MAX_PRECISION)
-    {
-      my_error(ER_TOO_BIG_PRECISION, MYF(0), len, a->name,
-               DECIMAL_MAX_PRECISION);
-      return 0;
-    }
-    if (dec > DECIMAL_MAX_SCALE)
-    {
-      my_error(ER_TOO_BIG_SCALE, MYF(0), dec, a->name,
-               DECIMAL_MAX_SCALE);
-      return 0;
-    }
+    ulong len;
+    uint dec;
+    if (get_length_and_scale(length, decimals, &len, &dec,
+                             DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE,
+                             a->name))
+      return NULL;
     res= new (thd->mem_root) Item_decimal_typecast(a, len, dec);
     break;
   }
+  case ITEM_CAST_DOUBLE:
+  {
+    ulong len;
+    uint dec;
+
+    if (!c_len)
+    {
+      length=   DBL_DIG+7;
+      decimals= NOT_FIXED_DEC;
+    }
+    else if (get_length_and_scale(length, decimals, &len, &dec,
+                                  DECIMAL_MAX_PRECISION, NOT_FIXED_DEC-1,
+                                  a->name))
+      return NULL;
+    res= new (thd->mem_root) Item_double_typecast(a, length, decimals);
+    break;
+  }
   case ITEM_CAST_CHAR:
   {
     int len= -1;
     CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection);
     if (c_len)
     {
-      ulong decoded_size;
-      errno= 0;
-      decoded_size= strtoul(c_len, NULL, 10);
-      if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH))
+      if (length > MAX_FIELD_BLOBLENGTH)
       {
-        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH);
+        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char",
+                 MAX_FIELD_BLOBLENGTH);
         return NULL;
       }
-      len= (int) decoded_size;
+      len= (int) length;
     }
     res= new (thd->mem_root) Item_char_typecast(a, len, real_cs);
     break;
@@ -5155,3 +5183,99 @@
   }
   return res;
 }
+
+
+static List<Item> *create_func_dyncol_prepare(THD *thd,
+                                              DYNCALL_CREATE_DEF **dfs,
+                                              List<DYNCALL_CREATE_DEF> &list)
+{
+  List_iterator_fast<DYNCALL_CREATE_DEF> li(list);
+  List<Item> *args= new (thd->mem_root) List<Item>;
+
+  *dfs=
+    (DYNCALL_CREATE_DEF *)alloc_root(thd->mem_root,
+                                     sizeof(DYNCALL_CREATE_DEF) *
+                                     list.elements);
+  DYNCALL_CREATE_DEF *def;
+  uint i= 0;
+
+  if (!args || !dfs)
+    return NULL;
+
+  while ((def= li++))
+  {
+    dfs[0][i++]= *def;
+    args->push_back(def->num);
+    args->push_back(def->value);
+  }
+  return args;
+}
+
+Item *create_func_dyncol_create(THD *thd, List<DYNCALL_CREATE_DEF> &list)
+{
+  List<Item> *args;
+  DYNCALL_CREATE_DEF *dfs;
+  if (!(args= create_func_dyncol_prepare(thd, &dfs, list)))
+    return NULL;
+
+  return new (thd->mem_root) Item_func_dyncol_create(*args, dfs);
+}
+
+
+Item *create_func_dyncol_add(THD *thd, Item *str,
+                             List<DYNCALL_CREATE_DEF> &list)
+{
+  List<Item> *args;
+  DYNCALL_CREATE_DEF *dfs;
+
+  if (!(args= create_func_dyncol_prepare(thd, &dfs, list)))
+    return NULL;
+
+  args->push_back(str);
+
+  return new (thd->mem_root) Item_func_dyncol_add(*args, dfs);
+}
+
+
+
+Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums)
+{
+  DYNCALL_CREATE_DEF *dfs;
+  List<Item> *args= new (thd->mem_root) List<Item>;
+  List_iterator_fast<Item> it(nums);
+  Item *num;
+  uint i;
+
+  dfs=
+    (DYNCALL_CREATE_DEF *)alloc_root(thd->mem_root,
+                                     sizeof(DYNCALL_CREATE_DEF) *
+                                     nums.elements);
+  if (!args || !dfs)
+    return NULL;
+
+  for (i= 0; (num= it++); i++)
+  {
+    dfs[i].num= num;
+    dfs[i].value= new Item_null();
+    dfs[i].type= DYN_COL_INT;
+    args->push_back(dfs[i].num);
+    args->push_back(dfs[i].value);
+  }
+
+  args->push_back(str);
+
+  return new (thd->mem_root) Item_func_dyncol_add(*args, dfs);
+}
+
+
+Item *create_func_dyncol_get(THD *thd,  Item *str, Item *num,
+                             Cast_target cast_type,
+                             const char *c_len, const char *c_dec,
+                             CHARSET_INFO *cs)
+{
+  Item *res;
+
+  if (!(res= new (thd->mem_root) Item_dyncol_get(str, num)))
+    return res;                                 // Return NULL
+  return create_func_cast(thd, res, cast_type, c_len, c_dec, cs);
+}

=== modified file 'sql/item_create.h'
--- sql/item_create.h	2011-02-20 16:51:43 +0000
+++ sql/item_create.h	2011-04-29 09:52:28 +0000
@@ -164,5 +164,15 @@
 create_func_cast(THD *thd, Item *a, Cast_target cast_type,
                  const char *len, const char *dec,
                  CHARSET_INFO *cs);
+
+Item *create_func_dyncol_create(THD *thd, List<DYNCALL_CREATE_DEF> &list);
+Item *create_func_dyncol_add(THD *thd, Item *str,
+                             List<DYNCALL_CREATE_DEF> &list);
+Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums);
+Item *create_func_dyncol_get(THD *thd, Item *num, Item *str,
+                             Cast_target cast_type,
+                             const char *c_len, const char *c_dec,
+                             CHARSET_INFO *cs);
+
 #endif
 

=== modified file 'sql/item_func.cc'
--- sql/item_func.cc	2011-03-24 14:34:06 +0000
+++ sql/item_func.cc	2011-04-29 09:52:28 +0000
@@ -989,9 +989,24 @@
     null_value= args[0]->null_value; 
     return value;
   }
+  else if (args[0]->dynamic_result())
+  {
+    /* We come here when argument has an unknown type */
+    args[0]->unsigned_flag= 0;   // Mark that we want to have a signed value
+    value= args[0]->val_int();
+    null_value= args[0]->null_value; 
+    if (!null_value && args[0]->unsigned_flag && value < 0)
+      goto err;                                 // Warn about overflow
+    return value;
+  }
 
   value= val_int_from_str(&error);
   if (value < 0 && error == 0)
+    goto err;
+  return value;
+
+err:
+  if (value < 0 && error == 0)
   {
     push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
                  "Cast to signed converted positive out-of-range integer to "
@@ -1024,19 +1039,36 @@
       value= 0;
     return value;
   }
+  else if (args[0]->dynamic_result())
+  {
+    /* We come here when argument has an unknown type */
+    args[0]->unsigned_flag= 1;   // Mark that we want to have an unsigned value
+    value= args[0]->val_int();
+    null_value= args[0]->null_value; 
+    if (!null_value && args[0]->unsigned_flag == 0 && value < 0)
+      goto err;                                 // Warn about overflow
+    return value;
+  }
   else if (args[0]->cast_to_int_type() != STRING_RESULT ||
            args[0]->result_as_longlong())
   {
     value= args[0]->val_int();
     null_value= args[0]->null_value; 
+    if (!null_value && args[0]->unsigned_flag == 0 && value < 0)
+      goto err;                                 // Warn about overflow
     return value;
   }
 
   value= val_int_from_str(&error);
   if (error < 0)
-    push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
-                 "Cast to unsigned converted negative integer to it's "
-                 "positive complement");
+    goto err;
+
+  return value;
+
+err:
+  push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+               "Cast to unsigned converted negative integer to it's "
+               "positive complement");
   return value;
 }
 
@@ -1134,6 +1166,51 @@
 }
 
 
+double Item_double_typecast::val_real()
+{
+  int error;
+  double tmp= args[0]->val_real();
+  if ((null_value= args[0]->null_value))
+    return 0.0;
+
+  if ((error= truncate_double(&tmp, max_length, decimals, 0, DBL_MAX)))
+  {
+    push_warning_printf(current_thd,
+                        MYSQL_ERROR::WARN_LEVEL_WARN,
+                        ER_WARN_DATA_OUT_OF_RANGE,
+                        ER(ER_WARN_DATA_OUT_OF_RANGE),
+                        name, 1);
+    if (error < 0)
+    {
+      null_value= 1;                            // Illegal value
+      tmp= 0.0;
+    }
+  }
+  return tmp;
+}
+
+
+void Item_double_typecast::print(String *str, enum_query_type query_type)
+{
+  char len_buf[20*3 + 1];
+  char *end;
+
+  str->append(STRING_WITH_LEN("cast("));
+  args[0]->print(str, query_type);
+  str->append(STRING_WITH_LEN(" as double"));
+  if (decimals != NOT_FIXED_DEC)
+  {
+    str->append('(');
+    end= int10_to_str(max_length, len_buf,10);
+    str->append(len_buf, (uint32) (end - len_buf));
+    str->append(',');
+    end= int10_to_str(decimals, len_buf,10);
+    str->append(len_buf, (uint32) (end - len_buf));
+    str->append(')');
+  }
+  str->append(')');
+}
+
 double Item_func_plus::real_op()
 {
   double value= args[0]->val_real() + args[1]->val_real();

=== modified file 'sql/item_func.h'
--- sql/item_func.h	2011-03-24 14:34:06 +0000
+++ sql/item_func.h	2011-04-29 09:52:28 +0000
@@ -470,12 +470,29 @@
   my_decimal *val_decimal(my_decimal*);
   enum Item_result result_type () const { return DECIMAL_RESULT; }
   enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
-  void fix_length_and_dec() {};
+  void fix_length_and_dec() {}
   const char *func_name() const { return "decimal_typecast"; }
   virtual void print(String *str, enum_query_type query_type);
 };
 
 
+class Item_double_typecast :public Item_real_func
+{
+public:
+  Item_double_typecast(Item *a, int len, int dec) :Item_real_func(a)
+  {
+    decimals= dec;
+    max_length= len;
+  }
+  double val_real();
+  enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+  void fix_length_and_dec() { maybe_null= 1; }
+  const char *func_name() const { return "double_typecast"; }
+  virtual void print(String *str, enum_query_type query_type);
+};
+
+
+
 class Item_func_additive_op :public Item_num_op
 {
 public:
@@ -1713,7 +1730,7 @@
 {
   ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
   ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR,
-  ITEM_CAST_DECIMAL
+  ITEM_CAST_DECIMAL, ITEM_CAST_DOUBLE
 };
 
 
@@ -1877,4 +1894,3 @@
     return trace_unsupported_by_check_vcol_func_processor(func_name());
   }
 };
-

=== modified file 'sql/item_strfunc.cc'
--- sql/item_strfunc.cc	2011-03-24 14:34:06 +0000
+++ sql/item_strfunc.cc	2011-04-29 09:52:28 +0000
@@ -3451,3 +3451,740 @@
 
   return str;
 }
+
+
+Item_func_dyncol_create::Item_func_dyncol_create(List<Item> &args,
+                                                 DYNCALL_CREATE_DEF *dfs)
+  : Item_str_func(args), defs(dfs), vals(0), nums(0)
+{
+  DBUG_ASSERT((args.elements & 0x1) == 0); // even number of arguments
+}
+
+
+bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref)
+{
+  bool res= Item_func::fix_fields(thd, ref); // no need Item_str_func here
+  vals= (DYNAMIC_COLUMN_VALUE *) alloc_root(thd->mem_root,
+                                            sizeof(DYNAMIC_COLUMN_VALUE) *
+                                            (arg_count / 2));
+  nums= (uint *) alloc_root(thd->mem_root,
+                            sizeof(uint) * (arg_count / 2));
+  return res || vals == 0 || nums == 0;
+}
+
+
+void Item_func_dyncol_create::fix_length_and_dec()
+{
+  maybe_null= TRUE;
+  collation.set(&my_charset_bin);
+  decimals= 0;
+}
+
+void Item_func_dyncol_create::prepare_arguments()
+{
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String *res, tmp(buff, sizeof(buff), &my_charset_bin);
+  uint column_count= (arg_count / 2);
+  uint i;
+  my_decimal dtmp, *dres;
+
+  /* get values */
+  for (i= 0; i < column_count; i++)
+  {
+    uint valpos= i * 2 + 1;
+    DYNAMIC_COLUMN_TYPE type= defs[i].type;
+    if (type == DYN_COL_NULL) // auto detect
+    {
+      switch (args[valpos]->field_type()) {
+      case MYSQL_TYPE_DECIMAL:
+      case MYSQL_TYPE_NEWDECIMAL:
+        type= DYN_COL_DECIMAL;
+        break;
+      case MYSQL_TYPE_TINY:
+      case MYSQL_TYPE_SHORT:
+      case MYSQL_TYPE_LONG:
+      case MYSQL_TYPE_LONGLONG:
+      case MYSQL_TYPE_INT24:
+      case MYSQL_TYPE_YEAR:
+      case MYSQL_TYPE_BIT:
+        type= DYN_COL_INT;
+        break;
+      case MYSQL_TYPE_FLOAT:
+      case MYSQL_TYPE_DOUBLE:
+        type= DYN_COL_DOUBLE;
+        break;
+      case MYSQL_TYPE_NULL:
+        type= DYN_COL_NULL;
+        break;
+      case MYSQL_TYPE_TIMESTAMP:
+      case MYSQL_TYPE_DATETIME:
+        type= DYN_COL_DATETIME;
+	break;
+      case MYSQL_TYPE_DATE:
+      case MYSQL_TYPE_NEWDATE:
+        type= DYN_COL_DATE;
+        break;
+      case MYSQL_TYPE_TIME:
+        type= DYN_COL_TIME;
+        break;
+      case MYSQL_TYPE_VARCHAR:
+      case MYSQL_TYPE_ENUM:
+      case MYSQL_TYPE_SET:
+      case MYSQL_TYPE_TINY_BLOB:
+      case MYSQL_TYPE_MEDIUM_BLOB:
+      case MYSQL_TYPE_LONG_BLOB:
+      case MYSQL_TYPE_BLOB:
+      case MYSQL_TYPE_VAR_STRING:
+      case MYSQL_TYPE_STRING:
+      case MYSQL_TYPE_GEOMETRY:
+        type= DYN_COL_STRING;
+        break;
+      default:
+        DBUG_ASSERT(0);
+        type= DYN_COL_STRING;
+      }
+    }
+    nums[i]= args[i * 2]->val_int();
+    vals[i].type= type;
+    switch (type) {
+    case DYN_COL_NULL:
+      break;
+    case DYN_COL_INT:
+      vals[i].long_value= args[valpos]->val_int();
+      break;
+    case DYN_COL_UINT:
+      vals[i].ulong_value= args[valpos]->val_int();
+      break;
+    case DYN_COL_DOUBLE:
+      vals[i].double_value= args[valpos]->val_real();
+      break;
+    case DYN_COL_STRING:
+      res= args[valpos]->val_str(&tmp);
+      if (res)
+      {
+	vals[i].string_value.str= (char *)my_malloc(res->length(), MYF(0));
+	if (vals[i].string_value.str)
+	  memcpy(vals[i].string_value.str, res->ptr(), res->length());
+	vals[i].string_value.length= res->length();
+	vals[i].charset= res->charset();
+      }
+      else
+      {
+        vals[i].string_value.str= NULL;
+        vals[i].string_value.length= 0; // just to be safe
+	DBUG_ASSERT(args[valpos]->null_value);
+      }
+      break;
+    case DYN_COL_DECIMAL:
+      dres= args[valpos]->val_decimal(&dtmp);
+      if (dres)
+      {
+	dynamic_column_prepare_decimal(&vals[i]);
+        DBUG_ASSERT(vals[i].decimal_value.len == dres->len);
+        vals[i].decimal_value.intg= dres->intg;
+        vals[i].decimal_value.frac= dres->frac;
+        vals[i].decimal_value.sign= dres->sign();
+        memcpy(vals[i].decimal_buffer, dres->buf,
+               sizeof(vals[i].decimal_buffer));
+      }
+      else
+      {
+	dynamic_column_prepare_decimal(&vals[i]); // just to be safe
+        DBUG_ASSERT(args[valpos]->null_value);
+      }
+      break;
+    case DYN_COL_DATETIME:
+      args[valpos]->get_date(&vals[i].time_value, TIME_FUZZY_DATE);
+      break;
+    case DYN_COL_DATE:
+      args[valpos]->get_date(&vals[i].time_value, TIME_FUZZY_DATE);
+      break;
+    case DYN_COL_TIME:
+      args[valpos]->get_time(&vals[i].time_value);
+      break;
+    default:
+      DBUG_ASSERT(0);
+      vals[i].type= DYN_COL_NULL;
+    }
+    if (vals[i].type != DYN_COL_NULL && args[valpos]->null_value)
+    {
+      if (vals[i].type == DYN_COL_STRING)
+        my_free(vals[i].string_value.str, MYF(MY_ALLOW_ZERO_PTR));
+      vals[i].type= DYN_COL_NULL;
+    }
+  }
+}
+
+void Item_func_dyncol_create::cleanup_arguments()
+{
+  uint column_count= (arg_count / 2);
+  uint i;
+
+  for (i= 0; i < column_count; i++)
+  {
+    if (vals[i].type == DYN_COL_STRING)
+      my_free(vals[i].string_value.str, MYF(MY_ALLOW_ZERO_PTR));
+  }
+}
+
+String *Item_func_dyncol_create::val_str(String *str)
+{
+  DYNAMIC_COLUMN col;
+  String *res;
+  uint column_count= (arg_count / 2);
+  int rc;
+  DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments
+
+  prepare_arguments();
+
+  if ((rc= dynamic_column_create_many(&col, column_count, nums, vals)))
+  {
+    dynamic_column_error_message(rc);
+    res= NULL;
+    null_value= TRUE;
+  }
+  else
+  {
+    res= str;
+    str->copy(col.str, col.length, &my_charset_bin);
+  }
+
+  /* cleanup */
+  dynamic_column_column_free(&col);
+  cleanup_arguments();
+
+  return res;
+}
+
+void Item_func_dyncol_create::print_arguments(String *str,
+                                              enum_query_type query_type)
+{
+  uint i;
+  uint column_count= (arg_count / 2);
+  for (i= 0; i < column_count; i++)
+  {
+    args[i*2]->print(str, query_type);
+    str->append(',');
+    args[i*2 + 1]->print(str, query_type);
+    switch (defs[i].type) {
+    case DYN_COL_NULL: // automatic type => write nothing
+      break;
+    case DYN_COL_INT:
+      str->append(STRING_WITH_LEN(" AS int"));
+      break;
+    case DYN_COL_UINT:
+      str->append(STRING_WITH_LEN(" AS unsigned int"));
+      break;
+    case DYN_COL_DOUBLE:
+      str->append(STRING_WITH_LEN(" AS double"));
+      break;
+    case DYN_COL_STRING:
+      str->append(STRING_WITH_LEN(" AS char"));
+      if (defs[i].cs)
+      {
+        str->append(STRING_WITH_LEN(" charset "));
+        str->append(defs[i].cs->csname);
+        str->append(' ');
+      }
+      break;
+    case DYN_COL_DECIMAL:
+      str->append(STRING_WITH_LEN(" AS decimal"));
+      break;
+    case DYN_COL_DATETIME:
+      str->append(STRING_WITH_LEN(" AS datetime"));
+      break;
+    case DYN_COL_DATE:
+      str->append(STRING_WITH_LEN(" AS date"));
+      break;
+    case DYN_COL_TIME:
+      str->append(STRING_WITH_LEN(" AS time"));
+      break;
+    }
+    if (i < column_count - 1)
+      str->append(',');
+  }
+}
+
+
+void Item_func_dyncol_create::print(String *str,
+                                    enum_query_type query_type)
+{
+  DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments
+  str->append(STRING_WITH_LEN("column_create("));
+  print_arguments(str, query_type);
+  str->append(')');
+}
+
+
+String *Item_func_dyncol_add::val_str(String *str)
+{
+  DYNAMIC_COLUMN col;
+  String *res;
+  uint column_count=  (arg_count / 2);
+  int rc;
+  DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments
+
+  prepare_arguments();
+
+  res= args[arg_count - 1]->val_str(str);
+  if (args[arg_count - 1]->null_value)
+    goto null;
+  init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE,
+                      STRING_BUFFER_USUAL_SIZE);
+  col.length= res->length();
+  memcpy(col.str, res->ptr(), col.length);
+  if ((rc= dynamic_column_update_many(&col, column_count, nums, vals)))
+  {
+    dynamic_column_error_message(rc);
+    goto null;
+  }
+
+  str->copy(col.str, col.length, &my_charset_bin);
+
+  /* cleanup */
+  dynamic_column_column_free(&col);
+  cleanup_arguments();
+
+  return str;
+
+null:
+  null_value= TRUE;
+  return NULL;
+}
+
+
+void Item_func_dyncol_add::print(String *str,
+                                 enum_query_type query_type)
+{
+  DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments
+  str->append(STRING_WITH_LEN("column_create("));
+  args[arg_count - 1]->print(str, query_type);
+  str->append(',');
+  print_arguments(str, query_type);
+  str->append(')');
+}
+
+bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp)
+{
+  DYNAMIC_COLUMN dyn_str;
+  String *res;
+  longlong num;
+  int rc;
+
+  num= args[1]->val_int();
+  if (args[1]->null_value || num < 0 || num > INT_MAX)
+  {
+    null_value= 1;
+    return 1;
+  }
+
+  res= args[0]->val_str(tmp);
+  if (args[0]->null_value)
+  {
+    null_value= 1;
+    return 1;
+  }
+
+  dyn_str.str=   (char*) res->ptr();
+  dyn_str.length= res->length();
+  if ((rc= dynamic_column_get(&dyn_str, (uint) num, val)))
+  {
+    dynamic_column_error_message(rc);
+    null_value= 1;
+    return 1;
+  }
+
+  null_value= 0;
+  return 0;                                     // ok
+}
+
+
+String *Item_dyncol_get::val_str(String *str_result)
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return NULL;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_INT:
+  case DYN_COL_UINT:
+    str_result->set_int(val.long_value, test(val.type == DYN_COL_UINT),
+                       &my_charset_latin1);
+    break;
+  case DYN_COL_DOUBLE:
+    str_result->set_real(val.double_value, NOT_FIXED_DEC, &my_charset_latin1);
+    break;
+  case DYN_COL_STRING:
+    if ((char*) tmp.ptr() <= val.string_value.str &&
+        (char*) tmp.ptr() + tmp.length() >= val.string_value.str)
+    {
+      /* value is allocated in tmp buffer; We have to make a copy */
+      str_result->copy(val.string_value.str, val.string_value.length,
+                      val.charset);
+    }
+    else
+    {
+      /*
+        It's safe to use the current value because it's either pointing
+        into a field or in a buffer for another item and this buffer
+        is not going to be deleted during expression evulation
+      */
+      str_result->set(val.string_value.str, val.string_value.length,
+                      val.charset);
+    }
+    break;
+  case DYN_COL_DECIMAL:
+  {
+    int res;
+    int length=
+      my_decimal_string_length((const my_decimal*)&val.decimal_value);
+    if (str_result->alloc(length))
+      goto null;
+    if ((res= decimal2string(&val.decimal_value, (char*) str_result->ptr(),
+                             &length, 0, 0, ' ')) != E_DEC_OK)
+    {
+      char buff[40];
+      int len= sizeof(buff);
+      DBUG_ASSERT(length < (int)sizeof(buff[40]));
+      decimal2string(&val.decimal_value, buff, &len, 0, 0, ' ');
+      decimal_operation_results(res, buff, "CHAR");
+    }
+    str_result->set_charset(&my_charset_latin1);
+    str_result->length(length);
+    break;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+  {
+    int length;
+    if (str_result->alloc(MAX_DATE_STRING_REP_LENGTH) ||
+        !(length= my_TIME_to_str(&val.time_value, (char*) str_result->ptr())))
+      goto null;
+    str_result->set_charset(&my_charset_latin1);
+    str_result->length(length);
+    break;
+  }
+  }
+  return str_result;
+
+null:
+  null_value= TRUE;
+  return 0;
+}
+
+
+longlong Item_dyncol_get::val_int()
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return 0;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_UINT:
+    unsigned_flag= 1;            // Make it possible for caller to detect sign
+    return val.long_value;
+  case DYN_COL_INT:
+    unsigned_flag= 0;            // Make it possible for caller to detect sign
+    return val.long_value;
+  case DYN_COL_DOUBLE:
+  {
+    bool error;
+    longlong num;
+
+    num= double_to_longlong(val.double_value, unsigned_flag, &error);
+    if (error)
+    {
+      char buff[30];
+      sprintf(buff, "%lg", val.double_value);
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_DATA_OVERFLOW,
+                          ER(ER_DATA_OVERFLOW),
+                          buff,
+                          unsigned_flag ? "UNSIGNED INT" : "INT");
+    }
+    return num;
+  }
+  case DYN_COL_STRING:
+  {
+    int error;
+    longlong num;
+    char *end= val.string_value.str + val.string_value.length, *org_end= end;
+
+    num= my_strtoll10(val.string_value.str, &end, &error);
+    if (end != org_end || error > 0)
+    {
+      char buff[80];
+      strmake(buff, val.string_value.str, min(sizeof(buff)-1,
+                                              val.string_value.length));
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BAD_DATA,
+                          ER(ER_BAD_DATA),
+                          buff,
+                          unsigned_flag ? "UNSIGNED INT" : "INT");
+    }
+    unsigned_flag= error >= 0;
+    return num;
+  }
+  case DYN_COL_DECIMAL:
+  {
+    longlong num;
+    my_decimal2int(E_DEC_FATAL_ERROR, &val.decimal_value, unsigned_flag,
+                   &num);
+    return num;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+    unsigned_flag= 1;
+    return TIME_to_ulonglong(&val.time_value);
+  }
+
+null:
+  null_value= TRUE;
+  return 0;
+}
+
+
+double Item_dyncol_get::val_real()
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return 0.0;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_UINT:
+    return ulonglong2double(val.ulong_value);
+  case DYN_COL_INT:
+    return (double) val.long_value;
+  case DYN_COL_DOUBLE:
+    return (double) val.double_value;
+  case DYN_COL_STRING:
+  {
+    int error;
+    char *end;
+    double res= my_strntod(val.charset, (char*) val.string_value.str,
+                           val.string_value.length, &end, &error);
+
+    if (end != (char*) val.string_value.str + val.string_value.length ||
+        error)
+    {
+      char buff[80];
+      strmake(buff, val.string_value.str, min(sizeof(buff)-1,
+                                              val.string_value.length));
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BAD_DATA,
+                          ER(ER_BAD_DATA),
+                          buff, "DOUBLE");
+    }
+    return res;
+  }
+  case DYN_COL_DECIMAL:
+  {
+    double res;
+    /* This will always succed */
+    decimal2double(&val.decimal_value, &res);
+    return res;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+    return (ulonglong2double(TIME_to_ulonglong(&val.time_value)) +
+            val.time_value.second_part / (double) TIME_SUBSECOND_RANGE);
+  }
+
+null:
+  null_value= TRUE;
+  return 0.0;
+}
+
+
+my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value)
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return NULL;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_UINT:
+    int2my_decimal(E_DEC_FATAL_ERROR, val.long_value, TRUE, decimal_value);
+    break;
+  case DYN_COL_INT:
+    int2my_decimal(E_DEC_FATAL_ERROR, val.long_value, FALSE, decimal_value);
+    break;
+  case DYN_COL_DOUBLE:
+    double2my_decimal(E_DEC_FATAL_ERROR, val.double_value, decimal_value);
+    break;
+  case DYN_COL_STRING:
+  {
+    int rc;
+    rc= str2my_decimal(0, val.string_value.str, val.string_value.length,
+                       val.charset, decimal_value);
+    char buff[80];
+    strmake(buff, val.string_value.str, min(sizeof(buff)-1,
+                                            val.string_value.length));
+    if (rc != E_DEC_OK)
+    {
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BAD_DATA,
+                          ER(ER_BAD_DATA),
+                          buff, "DECIMAL");
+    }
+    break;
+  }
+  case DYN_COL_DECIMAL:
+  {
+    int length= STRING_BUFFER_USUAL_SIZE;
+    decimal2string(&val.decimal_value, buff, &length, 0,0, 0);
+    decimal2my_decimal(&val.decimal_value, decimal_value);
+
+    break;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+  {
+    double tmp= (ulonglong2double(TIME_to_ulonglong(&val.time_value)) +
+                 val.time_value.second_part / (double) TIME_SUBSECOND_RANGE);
+    /* This can't overflow as time is always in the range of decimal */
+    double2my_decimal(E_DEC_FATAL_ERROR, tmp, decimal_value);
+    break;
+  }
+  }
+  return decimal_value;
+
+null:
+  null_value= TRUE;
+  return 0;
+}
+
+
+bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+  bool signed_value= 0;
+
+  if (get_dyn_value(&val, &tmp))
+    return 0;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_INT:
+    signed_value= 1;                                  // For error message
+    /* fall_trough */
+  case DYN_COL_UINT:
+  {
+    ulonglong num;
+    int error;
+
+    num= val.ulong_value;
+    number_to_datetime(num, ltime, fuzzy_date, &error);
+    if (error)
+    {
+      char buff[65];
+      int errnum= error == 2 ? ER_DATA_OVERFLOW : ER_BAD_DATA;
+      longlong2str(num, buff, signed_value ? -10 : 10, 1);
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          errnum,
+                          ER(errnum),
+                          buff, "DATE or DATETIME");
+      goto null;
+    }
+    return 0;
+  }
+  case DYN_COL_DOUBLE:
+  {
+    if (double_to_datetime_with_warn(val.double_value, ltime, fuzzy_date))
+      goto null;
+    return 0;
+  }
+  case DYN_COL_DECIMAL:
+    if (decimal_to_datetime_with_warn(&val.decimal_value, ltime, fuzzy_date))
+      goto null;
+    return 0;
+  case DYN_COL_STRING:
+  {
+    if (str_to_datetime_with_warn(val.string_value.str,
+                                  val.string_value.length,
+                                  ltime, fuzzy_date) <= MYSQL_TIMESTAMP_ERROR)
+      goto null;
+    return 0;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+    *ltime= val.time_value;
+    return 0;
+  }
+
+null:
+  null_value= TRUE;
+  return 1;
+}
+
+void Item_dyncol_get::print(String *str, enum_query_type query_type)
+{
+  str->append(STRING_WITH_LEN("column_get("));
+  args[0]->print(str, query_type);
+  str->append(',');
+  args[1]->print(str, query_type);
+  str->append(')');
+}
+
+String *Item_func_dyncol_list::val_str(String *str)
+{
+  DYNAMIC_ARRAY arr;
+  DYNAMIC_COLUMN col;
+  String *res= args[0]->val_str(str);
+  uint i;
+  int rc;
+
+  if (args[0]->null_value)
+    goto null;
+  col.length= res->length();
+  /* We do not change the string, so could do this trick */
+  col.str= (char *)res->ptr();
+  if ((rc= dynamic_column_list(&col, &arr)))
+  {
+    dynamic_column_error_message(rc);
+    delete_dynamic(&arr);
+    goto null;
+  }
+
+  str->length(0);
+  for (i= 0; i < arr.elements; i++)
+  {
+    str->qs_append(*dynamic_element(&arr, i, uint*));
+    if (i < arr.elements - 1)
+      str->append(',');
+  }
+
+  delete_dynamic(&arr);
+  return str;
+null:
+  null_value= TRUE;
+  return NULL;
+}

=== modified file 'sql/item_strfunc.h'
--- sql/item_strfunc.h	2010-06-01 19:52:20 +0000
+++ sql/item_strfunc.h	2011-04-29 09:52:28 +0000
@@ -871,3 +871,71 @@
   }
 };
 
+
+class Item_func_dyncol_create: public Item_str_func
+{
+protected:
+  DYNCALL_CREATE_DEF *defs;
+  DYNAMIC_COLUMN_VALUE *vals;
+  uint *nums;
+  void prepare_arguments();
+  void cleanup_arguments();
+  void print_arguments(String *str, enum_query_type query_type);
+public:
+  Item_func_dyncol_create(List<Item> &args, DYNCALL_CREATE_DEF *dfs);
+  bool fix_fields(THD *thd, Item **ref);
+  void fix_length_and_dec();
+  const char *func_name() const{ return "column_create"; }
+  String *val_str(String *);
+  virtual void print(String *str, enum_query_type query_type);
+};
+
+
+class Item_func_dyncol_add: public Item_func_dyncol_create
+{
+public:
+  Item_func_dyncol_add(List<Item> &args, DYNCALL_CREATE_DEF *dfs)
+    :Item_func_dyncol_create(args, dfs)
+  {}
+  const char *func_name() const{ return "column_add"; }
+  String *val_str(String *);
+  virtual void print(String *str, enum_query_type query_type);
+};
+
+
+/*
+  The following functions is always called from an Item_cast function
+*/
+
+class Item_dyncol_get: public Item_str_func
+{
+public:
+  Item_dyncol_get(Item *str, Item *num)
+    :Item_str_func(str, num)
+  {
+    max_length= MAX_FIELD_BLOBLENGTH;
+  }
+  void fix_length_and_dec()
+  { maybe_null= 1; }
+  /* Mark that collation can change between calls */
+  bool dynamic_result() { return 1; }
+
+  const char *func_name() const { return "column_get"; }
+  String *val_str(String *);
+  longlong val_int();
+  double val_real();
+  my_decimal *val_decimal(my_decimal *);
+  bool get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp);
+  bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+  void print(String *str, enum_query_type query_type);
+};
+
+
+class Item_func_dyncol_list: public Item_str_func
+{
+public:
+  Item_func_dyncol_list(Item *str) :Item_str_func(str) {};
+  void fix_length_and_dec() { maybe_null= 1; max_length= MAX_BLOB_WIDTH; };
+  const char *func_name() const{ return "column_list"; }
+  String *val_str(String *);
+};

=== modified file 'sql/lex.h'
--- sql/lex.h	2011-04-28 16:56:10 +0000
+++ sql/lex.h	2011-04-29 09:52:28 +0000
@@ -116,6 +116,12 @@
   { "COLLATION",	SYM(COLLATION_SYM)},
   { "COLUMN",		SYM(COLUMN_SYM)},
   { "COLUMNS",		SYM(COLUMNS)},
+  { "COLUMN_ADD",       SYM(COLUMN_ADD_SYM)},
+  { "COLUMN_CREATE",    SYM(COLUMN_CREATE_SYM)},
+  { "COLUMN_DELETE",    SYM(COLUMN_DELETE_SYM)},
+  { "COLUMN_EXISTS",    SYM(COLUMN_EXISTS_SYM)},
+  { "COLUMN_GET",       SYM(COLUMN_GET_SYM)},
+  { "COLUMN_LIST",      SYM(COLUMN_LIST_SYM)},
   { "COMMENT",		SYM(COMMENT_SYM)},
   { "COMMIT",		SYM(COMMIT_SYM)},
   { "COMMITTED",	SYM(COMMITTED_SYM)},

=== modified file 'sql/my_decimal.cc'
--- sql/my_decimal.cc	2011-02-20 16:51:43 +0000
+++ sql/my_decimal.cc	2011-04-29 09:52:28 +0000
@@ -30,21 +30,20 @@
     result
 */
 
-int decimal_operation_results(int result)
+int decimal_operation_results(int result, const char *value, const char *type)
 {
   switch (result) {
   case E_DEC_OK:
     break;
   case E_DEC_TRUNCATED:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-			WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED),
-			"", (ulong) 0);
+			ER_DATA_TRUNCATED, ER(ER_DATA_TRUNCATED),
+			value, type);
     break;
   case E_DEC_OVERFLOW:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
-                        ER_TRUNCATED_WRONG_VALUE,
-                        ER(ER_TRUNCATED_WRONG_VALUE),
-			"DECIMAL", "");
+                        ER_DATA_OVERFLOW, ER(ER_DATA_OVERFLOW),
+			value, type);
     break;
   case E_DEC_DIV_ZERO:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
@@ -52,9 +51,8 @@
     break;
   case E_DEC_BAD_NUM:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
-			ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
-			ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
-			"decimal", "", "", (ulong) 0);
+			ER_BAD_DATA, ER(ER_BAD_DATA),
+			value, type);
     break;
   case E_DEC_OOM:
     my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -283,6 +281,35 @@
   return buff;
 }
 
+
+/*
+  Convert a decimal to an ulong with a descreptive error message
+*/
+
+int my_decimal2int(uint mask, const decimal_t *d, my_bool unsigned_flag,
+		   longlong *l)
+{
+  int res;
+  my_decimal rounded;
+  /* decimal_round can return only E_DEC_TRUNCATED */
+  decimal_round(d, &rounded, 0, HALF_UP);
+  res= (unsigned_flag ?
+        decimal2ulonglong(&rounded, (ulonglong *) l) :
+        decimal2longlong(&rounded, l));
+  if (res & mask)
+  {
+    char buff[DECIMAL_MAX_STR_LENGTH];
+    int length= sizeof(buff);
+    decimal2string(d, buff, &length, 0, 0, 0);
+
+    decimal_operation_results(res, buff,
+                              unsigned_flag ? "UNSIGNED INT" :
+                              "INT");
+  }
+  return res;
+}
+
+
 #endif /*DBUG_OFF*/
 
 

=== modified file 'sql/my_decimal.h'
--- sql/my_decimal.h	2010-11-24 22:57:34 +0000
+++ sql/my_decimal.h	2011-04-29 09:52:28 +0000
@@ -32,32 +32,7 @@
 #include <decimal.h>
 C_MODE_END
 
-#define DECIMAL_LONGLONG_DIGITS 22
-#define DECIMAL_LONG_DIGITS 10
-#define DECIMAL_LONG3_DIGITS 8
-
-/** maximum length of buffer in our big digits (uint32). */
-#define DECIMAL_BUFF_LENGTH 9
-
-/* the number of digits that my_decimal can possibly contain */
-#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)
-
-
-/**
-  maximum guaranteed precision of number in decimal digits (number of our
-  digits * number of decimal digits in one our big digit - number of decimal
-  digits in one our big digit decreased by 1 (because we always put decimal
-  point on the border of our big digits))
-*/
-#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
-#define DECIMAL_MAX_SCALE 30
-#define DECIMAL_NOT_SPECIFIED 31
-
-/**
-  maximum length of string representation (number of maximum decimal
-  digits + 1 position for sign + 1 position for decimal point)
-*/
-#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
+#include <my_decimal_limits.h>
 
 /**
   maximum size of packet length.
@@ -134,9 +109,10 @@
 #endif
 
 #ifndef MYSQL_CLIENT
-int decimal_operation_results(int result);
+int decimal_operation_results(int result, const char *value, const char *type);
 #else
-inline int decimal_operation_results(int result)
+inline int decimal_operation_results(int result, const char *value,
+                                     const char *type)
 {
   return result;
 }
@@ -158,7 +134,7 @@
 inline int check_result(uint mask, int result)
 {
   if (result & mask)
-    decimal_operation_results(result);
+    decimal_operation_results(result, "", "DECIMAL");
   return result;
 }
 
@@ -294,24 +270,14 @@
 		      uint fixed_dec, char filler, String *str);
 #endif
 
-inline
-int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
-		   longlong *l)
-{
-  my_decimal rounded;
-  /* decimal_round can return only E_DEC_TRUNCATED */
-  decimal_round((decimal_t*)d, &rounded, 0, HALF_UP);
-  return check_result(mask, (unsigned_flag ?
-			     decimal2ulonglong(&rounded, (ulonglong *)l) :
-			     decimal2longlong(&rounded, l)));
-}
-
-
-inline
-int my_decimal2double(uint, const my_decimal *d, double *result)
+int my_decimal2int(uint mask, const decimal_t *d, my_bool unsigned_flag,
+		   longlong *l);
+
+inline
+int my_decimal2double(uint, const decimal_t *d, double *result)
 {
   /* No need to call check_result as this will always succeed */
-  return decimal2double((decimal_t*) d, result);
+  return decimal2double(d, result);
 }
 
 
@@ -354,6 +320,18 @@
 			     longlong2decimal(i, d)));
 }
 
+inline
+void decimal2my_decimal(decimal_t *from, my_decimal *to)
+{
+  DBUG_ASSERT(to->len >= from->len);
+  to->intg= from->intg;
+  to->frac= from->frac;
+  to->sign(from->sign);
+  memcpy(to->buf, from->buf, to->len*sizeof(decimal_digit_t));
+}
+
+
+
 
 inline
 void my_decimal_neg(decimal_t *arg)

=== modified file 'sql/mysql_priv.h'
--- sql/mysql_priv.h	2011-04-28 16:56:10 +0000
+++ sql/mysql_priv.h	2011-04-29 09:52:28 +0000
@@ -1412,6 +1412,7 @@
 Field *
 find_field_in_table_sef(TABLE *table, const char *name);
 int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE);
+int dynamic_column_error_message(int rc);
 
 #endif /* MYSQL_SERVER */
 
@@ -2322,16 +2323,22 @@
 void get_date_from_daynr(long daynr,uint *year, uint *month,
 			 uint *day);
 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
-bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time);
+bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time,
+                           ulong fuzzydate);
 timestamp_type str_to_datetime_with_warn(const char *str, uint length,
-                                         MYSQL_TIME *l_time, uint flags);
+                                         MYSQL_TIME *l_time, ulong flags);
 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
 void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
 
-void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+void make_truncated_value_warning(THD *thd,
+                                  MYSQL_ERROR::enum_warning_level level,
                                   const char *str_val,
 				  uint str_length, timestamp_type time_type,
                                   const char *field_name);
+bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
+                                  ulong fuzzy_date);
+bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
+                                   ulong fuzzy_date);
 
 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval);
 bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,

=== modified file 'sql/share/errmsg.txt'
--- sql/share/errmsg.txt	2011-04-28 16:56:10 +0000
+++ sql/share/errmsg.txt	2011-04-29 09:55:41 +0000
@@ -5321,7 +5321,7 @@
 ER_DIVISION_BY_ZERO 22012 
         eng "Division by 0"
         ger "Division durch 0"
-ER_TRUNCATED_WRONG_VALUE_FOR_FIELD  
+ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 22007
         eng "Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %lu"
         ger "Falscher %-.32s-Wert: '%-.128s' für Feld '%.192s' in Zeile %lu"
 ER_ILLEGAL_VALUE_FOR_TYPE 22007 
@@ -6251,4 +6251,15 @@
         eng "Incorrect value '%-.64s' for option '%-.64s'"
 ER_CANT_DO_ONLINE
         eng "Can't execute the given '%s' command as online"
-
+ER_DATA_OVERFLOW 22003
+        eng "Got overflow when converting '%-.128s' to %-.32s. Value truncated."
+ER_DATA_TRUNCATED 22003
+        eng "Truncated value '%-.128s' when converting to %-.32s"
+ER_BAD_DATA 22007
+        eng "Encountered illegal value '%-.128s' when converting to %-.32s"
+ER_DYN_COL_WRONG_FORMAT
+        eng "Encountered illegal format of dynamic column string"
+ER_DYN_COL_IMPLEMENTATION_LIMIT
+        eng "Dynamic column implementation limit reached"
+ER_DYN_COL_DATA 22007
+        eng "Illegal value used as argument of dynamic column function"

=== modified file 'sql/sql_base.cc'
--- sql/sql_base.cc	2011-03-31 15:35:57 +0000
+++ sql/sql_base.cc	2011-04-29 09:52:28 +0000
@@ -9406,6 +9406,39 @@
   thd->restore_backup_open_tables_state(backup);
 }
 
+
+/**
+  Check result of dynamic column function and issue error if it is needed
+
+  @param rc              The result code of dynamic column function
+
+  @return the result code which was get as an argument\
+*/
+
+int dynamic_column_error_message(int rc)
+{
+  switch (rc) {
+  case ER_DYNCOL_YES:
+  case ER_DYNCOL_OK:
+    break; // it is not an error
+  case ER_DYNCOL_FORMAT:
+    my_error(ER_DYN_COL_WRONG_FORMAT, MYF(0));
+    break;
+  case ER_DYNCOL_LIMIT:
+    my_error(ER_DYN_COL_IMPLEMENTATION_LIMIT, MYF(0));
+    break;
+  case ER_DYNCOL_RESOURCE:
+    my_error(ER_OUT_OF_RESOURCES, MYF(0));
+    break;
+  case ER_DYNCOL_DATA:
+    my_error(ER_DYN_COL_DATA, MYF(0));
+    break;
+  default:
+    DBUG_ASSERT(0);
+  }
+  return rc;
+}
+
 /**
   @} (end of group Data_Dictionary)
 */

=== modified file 'sql/sql_yacc.yy'
--- sql/sql_yacc.yy	2011-04-28 16:56:10 +0000
+++ sql/sql_yacc.yy	2011-04-29 09:56:51 +0000
@@ -34,6 +34,7 @@
 #define YYINITDEPTH 100
 #define YYMAXDEPTH 3200                        /* Because of 64K stack */
 #define Lex (YYTHD->lex)
+
 #define Select Lex->current_select
 #include "mysql_priv.h"
 #include "slave.h"
@@ -671,6 +672,8 @@
   sp_head *sphead;
   struct p_elem_val *p_elem_value;
   enum index_hint_type index_hint;
+  DYNCALL_CREATE_DEF *dyncol_def;
+  List<DYNCALL_CREATE_DEF> *dyncol_def_list;
 }
 
 %{
@@ -770,6 +773,12 @@
 %token  COLLATE_SYM                   /* SQL-2003-R */
 %token  COLLATION_SYM                 /* SQL-2003-N */
 %token  COLUMNS
+%token  COLUMN_ADD_SYM
+%token  COLUMN_CREATE_SYM
+%token  COLUMN_DELETE_SYM
+%token  COLUMN_EXISTS_SYM
+%token  COLUMN_GET_SYM
+%token  COLUMN_LIST_SYM
 %token  COLUMN_SYM                    /* SQL-2003-R */
 %token  COMMENT_SYM
 %token  COMMITTED_SYM                 /* SQL-2003-N */
@@ -1338,7 +1347,7 @@
         opt_natural_language_mode opt_query_expansion
         opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
         ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
-        optional_flush_tables_arguments
+        optional_flush_tables_arguments opt_dyncol_type dyncol_type
 
 %type <ulong_num>
         ulong_num real_ulong_num merge_insert_types
@@ -1438,6 +1447,10 @@
 
 %type <boolfunc2creator> comp_op
 
+%type <dyncol_def> dyncall_create_element
+
+%type <dyncol_def_list> dyncall_create_list
+
 %type <NONE>
         query verb_clause create change select do drop insert replace insert2
         insert_values update delete truncate rename
@@ -7506,6 +7519,131 @@
         | ANY_SYM { $$ = 0; }
         ;
 
+opt_dyncol_type:
+          /* empty */ 
+          {
+            LEX *lex= Lex;
+	    $$= DYN_COL_NULL; /* automatic type */
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+	  }
+        | AS dyncol_type { $$= $2; }
+        ;
+
+dyncol_type:
+          INT_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_INT;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | UNSIGNED INT_SYM 
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_UINT;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | DOUBLE_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DOUBLE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | REAL
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DOUBLE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | FLOAT_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DOUBLE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | DECIMAL_SYM float_options
+          {
+            $$= DYN_COL_DECIMAL;
+            Lex->charset= NULL;
+          }
+        | char opt_binary
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_STRING;
+            lex->length= lex->dec= 0;
+          }
+        | nchar
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_STRING;
+            lex->charset= national_charset_info;
+            lex->length= lex->dec= 0;
+          }
+        | DATE_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DATE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | TIME_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_TIME;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | DATETIME
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DATETIME;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        ;
+
+dyncall_create_element:
+   expr ',' expr opt_dyncol_type
+   {
+     LEX *lex= Lex;
+     $$= (DYNCALL_CREATE_DEF *)
+       alloc_root(YYTHD->mem_root, sizeof(DYNCALL_CREATE_DEF));
+     if ($$ == NULL)
+       MYSQL_YYABORT;
+     $$->num= $1;
+     $$->value= $3;
+     $$->type= (DYNAMIC_COLUMN_TYPE)$4;
+     $$->cs= lex->charset;
+     if (lex->length)
+       $$->len= strtoul(lex->length, NULL, 10);
+     else
+       $$->len= 0;
+     if (lex->dec)
+       $$->frac= strtoul(lex->dec, NULL, 10);
+     else
+       $$->len= 0;
+   }
+
+dyncall_create_list:
+     dyncall_create_element
+       {
+         $$= new (YYTHD->mem_root) List<DYNCALL_CREATE_DEF>;
+         if ($$ == NULL)
+           MYSQL_YYABORT;
+         $$->push_back($1);
+       }
+   | dyncall_create_list ',' dyncall_create_element
+       {
+         $1->push_back($3);
+         $$= $1;
+       }
+   ;
+
 simple_expr:
           simple_ident
         | function_call_keyword
@@ -8040,6 +8178,51 @@
               MYSQL_YYABORT;
             Lex->safe_to_cache_query=0;
           }
+        |
+          COLUMN_ADD_SYM '(' expr ',' dyncall_create_list ')'
+          {
+            $$= create_func_dyncol_add(YYTHD, $3, *$5);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_DELETE_SYM '(' expr ',' expr_list ')'
+          {
+            $$= create_func_dyncol_delete(YYTHD, $3, *$5);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_EXISTS_SYM '(' expr ',' expr ')'
+          {
+            $$= new (YYTHD->mem_root) Item_func_dyncol_exists($3, $5);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_LIST_SYM '(' expr ')'
+          {
+            $$= new (YYTHD->mem_root) Item_func_dyncol_list($3);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_CREATE_SYM '(' dyncall_create_list ')'
+          {
+            $$= create_func_dyncol_create(YYTHD, *$3);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')'
+          {
+            LEX *lex= Lex;
+            $$= create_func_dyncol_get(YYTHD, $3, $5, $7,
+                                        lex->length, lex->dec,
+                                        lex->charset);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
         ;
 
 /*
@@ -8641,6 +8824,8 @@
           { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
         | NCHAR_SYM opt_field_length
           { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; }
+        | INT_SYM
+          { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
         | SIGNED_SYM
           { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
         | SIGNED_SYM INT_SYM
@@ -8657,7 +8842,10 @@
           { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
         | DECIMAL_SYM float_options
           { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
-        ;
+        | DOUBLE_SYM
+          { Lex->charset= NULL; Lex->length= Lex->dec= 0;}
+          opt_precision
+          { $$=ITEM_CAST_DOUBLE; }
 
 opt_expr_list:
           /* empty */ { $$= NULL; }
@@ -11887,6 +12075,12 @@
         | CHECKSUM_SYM          {}
         | CHECKPOINT_SYM        {}
         | CLOSE_SYM             {}
+        | COLUMN_ADD_SYM        {}
+        | COLUMN_CREATE_SYM     {}
+        | COLUMN_DELETE_SYM     {}
+        | COLUMN_EXISTS_SYM     {}
+        | COLUMN_GET_SYM        {}
+        | COLUMN_LIST_SYM       {}
         | COMMENT_SYM           {}
         | COMMIT_SYM            {}
         | CONTAINS_SYM          {}

=== added file 'unittest/mysys/ma_dyncol-t.c'
--- unittest/mysys/ma_dyncol-t.c	1970-01-01 00:00:00 +0000
+++ unittest/mysys/ma_dyncol-t.c	2011-04-29 09:52:28 +0000
@@ -0,0 +1,767 @@
+#include <my_global.h>
+#include <ma_dyncol.h>
+#include <tap.h>
+
+
+
+void test_value_single_null()
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_NULL;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_NULL);
+err:
+  ok(rc, "%s", "NULL");
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_uint(ulonglong num, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_UINT;
+  val.ulong_value= num;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_UINT) && (res.ulong_value == num);
+  num= res.ulong_value;
+err:
+  ok(rc, "%s - %llu", name, num);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_sint(longlong num, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_INT;
+  val.long_value= num;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_INT) && (res.long_value == num);
+  num= res.ulong_value;
+err:
+  ok(rc, "%s - %lld", name, num);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_single_double(double num, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_DOUBLE;
+  val.double_value= num;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_DOUBLE) && (res.double_value == num);
+  num= res.ulong_value;
+err:
+  ok(rc, "%s - %lf", name, num);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_decimal(const char *num)
+{
+  char *end= (((char*)num) + strlen(num));
+  char buff[80];
+  int rc= FALSE;
+  int length= 80;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+
+  /* init values */
+  dynamic_column_prepare_decimal(&val); // special procedure for decimal!!!
+  if (string2decimal(num, &val.decimal_value, &end) != E_DEC_OK)
+    goto err;
+  dynamic_column_value_init(&res);
+
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_DECIMAL) &&
+       (decimal_cmp(&res.decimal_value, &val.decimal_value) == 0));
+  decimal2string(&res.decimal_value, buff, &length, 0, 0, ' ');
+err:
+  ok(rc, "%s - %s", num, buff);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+static CHARSET_INFO *charset_list[]=
+{
+#ifdef HAVE_CHARSET_big5
+  &my_charset_big5_chinese_ci,
+  &my_charset_big5_bin,
+#endif
+#ifdef HAVE_CHARSET_euckr
+  &my_charset_euckr_korean_ci,
+  &my_charset_euckr_bin,
+#endif
+#ifdef HAVE_CHARSET_gb2312
+  &my_charset_gb2312_chinese_ci,
+  &my_charset_gb2312_bin,
+#endif
+#ifdef HAVE_CHARSET_gbk
+  &my_charset_gbk_chinese_ci,
+  &my_charset_gbk_bin,
+#endif
+#ifdef HAVE_CHARSET_latin1
+  &my_charset_latin1,
+  &my_charset_latin1_bin,
+#endif
+#ifdef HAVE_CHARSET_sjis
+  &my_charset_sjis_japanese_ci,
+  &my_charset_sjis_bin,
+#endif
+#ifdef HAVE_CHARSET_tis620
+  &my_charset_tis620_thai_ci,
+  &my_charset_tis620_bin,
+#endif
+#ifdef HAVE_CHARSET_ujis
+  &my_charset_ujis_japanese_ci,
+  &my_charset_ujis_bin,
+#endif
+#ifdef HAVE_CHARSET_utf8
+  &my_charset_utf8_general_ci,
+#ifdef HAVE_HAVE_UCA_COLLATIONS
+  &my_charset_utf8_unicode_ci,
+#endif
+  &my_charset_utf8_bin,
+#endif
+};
+
+
+void test_value_single_string(const char *string, size_t len,
+                              CHARSET_INFO *cs)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+
+  /* init values */
+  val.type= DYN_COL_STRING;
+  val.string_value.str= (char*)string;
+  val.string_value.length= len;
+  val.charset= cs;
+  dynamic_column_value_init(&res);
+
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_STRING) &&
+       (res.string_value.length == len) &&
+       (memcmp(res.string_value.str, string, len) == 0) &&
+       (res.charset->number == cs->number));
+err:
+  ok(rc, "'%s' - '%s' %u %u-%s", string,
+     res.string_value.str, (uint)res.string_value.length,
+     (uint)res.charset->number, res.charset->name);
+  /* cleanup */
+  val.string_value.str= NULL; // we did not allocated it
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_date(uint year, uint month, uint day, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_DATE;
+  val.time_value.time_type= MYSQL_TIMESTAMP_DATE;
+  val.time_value.year= year;
+  val.time_value.month= month;
+  val.time_value.day= day;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_DATE) &&
+       (res.time_value.time_type == MYSQL_TIMESTAMP_DATE) &&
+       (res.time_value.year == year) &&
+       (res.time_value.month == month) &&
+       (res.time_value.day == day));
+err:
+  ok(rc, "%s - %04u-%02u-%02u", name, year, month, day);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_time(uint neg, uint hour, uint minute, uint second,
+                            uint mic, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_TIME;
+  val.time_value.time_type= MYSQL_TIMESTAMP_TIME;
+  val.time_value.neg= neg;
+  val.time_value.hour= hour;
+  val.time_value.minute= minute;
+  val.time_value.second= second;
+  val.time_value.second_part= mic;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_TIME) &&
+       (res.time_value.time_type == MYSQL_TIMESTAMP_TIME) &&
+       (res.time_value.neg == (int)neg) &&
+       (res.time_value.hour == hour) &&
+       (res.time_value.minute == minute) &&
+       (res.time_value.second == second) &&
+       (res.time_value.second_part == mic));
+err:
+  ok(rc, "%s - %c%02u:%02u:%02u.%06u", name, (neg ? '-' : '+'),
+     hour, minute, second, mic);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_single_datetime(uint neg, uint year, uint month, uint day,
+                                uint hour, uint minute, uint second,
+                                uint mic, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_DATETIME;
+  val.time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+  val.time_value.neg= neg;
+  val.time_value.year= year;
+  val.time_value.month= month;
+  val.time_value.day= day;
+  val.time_value.hour= hour;
+  val.time_value.minute= minute;
+  val.time_value.second= second;
+  val.time_value.second_part= mic;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_DATETIME) &&
+       (res.time_value.time_type == MYSQL_TIMESTAMP_DATETIME) &&
+       (res.time_value.neg == (int)neg) &&
+       (res.time_value.year == year) &&
+       (res.time_value.month == month) &&
+       (res.time_value.day == day) &&
+       (res.time_value.hour == hour) &&
+       (res.time_value.minute == minute) &&
+       (res.time_value.second == second) &&
+       (res.time_value.second_part == mic));
+err:
+  ok(rc, "%s - %c %04u-%02u-%02u %02u:%02u:%02u.%06u", name, (neg ? '-' : '+'),
+     year, month, day, hour, minute, second, mic);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_multi(ulonglong num0,
+                      longlong num1,
+                      double num2,
+                      const char *num3,
+                      const char *string4, size_t len4, CHARSET_INFO *cs4,
+                      uint year5, uint month5, uint day5,
+                      uint neg6, uint hour6, uint minute6,
+                      uint second6, uint mic6,
+                      uint neg7, uint year7, uint month7, uint day7,
+                      uint hour7, uint minute7, uint second7,
+                      uint mic7,
+                      uint *column_numbers,
+                      const char *name)
+{
+  char *end3= (((char*)num3) + strlen(num3));
+  int rc= FALSE;
+  uint i;
+  DYNAMIC_COLUMN_VALUE val[9], res[9];
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val[0].type= DYN_COL_UINT;
+  val[0].ulong_value= num0;
+  val[1].type= DYN_COL_INT;
+  val[1].long_value= num1;
+  val[2].type= DYN_COL_DOUBLE;
+  val[2].double_value= num2;
+  dynamic_column_prepare_decimal(val + 3); // special procedure for decimal!!!
+  if (string2decimal(num3, &val[3].decimal_value, &end3) != E_DEC_OK)
+    goto err;
+  val[4].type= DYN_COL_STRING;
+  val[4].string_value.str= (char*)string4;
+  val[4].string_value.length= len4;
+  val[4].charset= cs4;
+  val[5].type= DYN_COL_DATE;
+  val[5].time_value.time_type= MYSQL_TIMESTAMP_DATE;
+  val[5].time_value.year= year5;
+  val[5].time_value.month= month5;
+  val[5].time_value.day= day5;
+  val[6].type= DYN_COL_TIME;
+  val[6].time_value.time_type= MYSQL_TIMESTAMP_TIME;
+  val[6].time_value.neg= neg6;
+  val[6].time_value.hour= hour6;
+  val[6].time_value.minute= minute6;
+  val[6].time_value.second= second6;
+  val[6].time_value.second_part= mic6;
+  val[7].type= DYN_COL_DATETIME;
+  val[7].time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+  val[7].time_value.neg= neg7;
+  val[7].time_value.year= year7;
+  val[7].time_value.month= month7;
+  val[7].time_value.day= day7;
+  val[7].time_value.hour= hour7;
+  val[7].time_value.minute= minute7;
+  val[7].time_value.second= second7;
+  val[7].time_value.second_part= mic7;
+  val[8].type= DYN_COL_NULL;
+  for (i= 0; i < 9; i++)
+    dynamic_column_value_init(res + i);
+  /* create column */
+  if (dynamic_column_create_many(&str, 9, column_numbers, val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  for (i= 0; i < 9; i++)
+    if (dynamic_column_get(&str, column_numbers[i], res + i))
+      goto err;
+  rc= ((res[0].type == DYN_COL_UINT) &&
+       (res[0].ulong_value == num0) &&
+       (res[1].type == DYN_COL_INT) &&
+       (res[1].long_value == num1) &&
+       (res[2].type == DYN_COL_DOUBLE) &&
+       (res[2].double_value == num2) &&
+       (res[3].type == DYN_COL_DECIMAL) &&
+       (decimal_cmp(&res[3].decimal_value, &val[3].decimal_value) == 0) &&
+       (res[4].type == DYN_COL_STRING) &&
+       (res[4].string_value.length == len4) &&
+       (memcmp(res[4].string_value.str, string4, len4) == 0) &&
+       (res[4].charset->number == cs4->number) &&
+       (res[5].type == DYN_COL_DATE) &&
+       (res[5].time_value.time_type == MYSQL_TIMESTAMP_DATE) &&
+       (res[5].time_value.year == year5) &&
+       (res[5].time_value.month == month5) &&
+       (res[5].time_value.day == day5) &&
+       (res[6].type == DYN_COL_TIME) &&
+       (res[6].time_value.time_type == MYSQL_TIMESTAMP_TIME) &&
+       (res[6].time_value.neg == (int)neg6) &&
+       (res[6].time_value.hour == hour6) &&
+       (res[6].time_value.minute == minute6) &&
+       (res[6].time_value.second == second6) &&
+       (res[6].time_value.second_part == mic6) &&
+       (res[7].type == DYN_COL_DATETIME) &&
+       (res[7].time_value.time_type == MYSQL_TIMESTAMP_DATETIME) &&
+       (res[7].time_value.neg == (int)neg7) &&
+       (res[7].time_value.year == year7) &&
+       (res[7].time_value.month == month7) &&
+       (res[7].time_value.day == day7) &&
+       (res[7].time_value.hour == hour7) &&
+       (res[7].time_value.minute == minute7) &&
+       (res[7].time_value.second == second7) &&
+       (res[7].time_value.second_part == mic7) &&
+       (res[8].type == DYN_COL_NULL));
+err:
+  ok(rc, "%s", name);
+  /* cleanup */
+  val[4].string_value.str= NULL; // we did not allocated it
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_multi_same_num()
+{
+  int rc= FALSE;
+  uint i;
+  DYNAMIC_COLUMN_VALUE val[5];
+  uint column_numbers[]= {3,4,5,3,6}; // same column numbers
+  DYNAMIC_COLUMN str;
+  /* init values */
+  for (i= 0; i < 5; i++)
+    val[i].type= DYN_COL_NULL;
+  /* create column */
+  if (!dynamic_column_create_many(&str, 5, column_numbers, val))
+    goto err;
+  rc= TRUE;
+err:
+  ok(rc, "%s", "same column numbers check");
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_update_multi(uint *column_numbers, uint *column_values,
+                       my_bool *null_values, int only_add, int all)
+{
+  int rc= FALSE;
+  int i, j;
+  DYNAMIC_COLUMN str;
+  DYNAMIC_COLUMN_VALUE val;
+
+  val.type= DYN_COL_UINT;
+  val.ulong_value= column_values[0];
+  if (dynamic_column_create(&str, column_numbers[0], &val))
+    goto err;
+  for (i= 1; i < all; i++)
+  {
+    val.type= (null_values[i] ? DYN_COL_NULL : DYN_COL_UINT);
+    val.ulong_value= column_values[i];
+    if (dynamic_column_update(&str, column_numbers[i], &val))
+      goto err;
+
+    /* check value(s) */
+    for (j= i; j >= (i < only_add ? 0 : i); j--)
+    {
+      if (dynamic_column_get(&str, column_numbers[j], &val))
+        goto err;
+      if (null_values[j])
+      {
+        if (val.type != DYN_COL_NULL ||
+            dynamic_column_exists(&str, column_numbers[j]) == ER_DYNCOL_YES)
+          goto err;
+      }
+      else
+      {
+        if (val.type != DYN_COL_UINT ||
+            val.ulong_value != column_values[j] ||
+            dynamic_column_exists(&str, column_numbers[j]) == ER_DYNCOL_NO)
+          goto err;
+      }
+    }
+    if (i < only_add)
+    {
+      DYNAMIC_ARRAY num;
+      if (dynamic_column_list(&str, &num))
+        goto err;
+      /* cross check arrays */
+      if ((int)num.elements != i + 1)
+      {
+        delete_dynamic(&num);
+        goto err;
+      }
+      for(j= 0; j < i + 1; j++)
+      {
+        int k;
+        for(k= 0;
+            k < i + 1 && column_numbers[j] !=
+            *dynamic_element(&num, k, uint*);
+            k++);
+        if (k >= i + 1)
+        {
+          delete_dynamic(&num);
+          goto err;
+        }
+        for(k= 0;
+            k < i + 1 && column_numbers[k] !=
+            *dynamic_element(&num, j, uint*);
+            k++);
+        if (k >= i + 1)
+        {
+          delete_dynamic(&num);
+          goto err;
+        }
+      }
+      delete_dynamic(&num);
+    }
+  }
+
+  rc= TRUE;
+err:
+  ok(rc, "%s", "add/delete/update");
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_empty_string()
+{
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  DYNAMIC_ARRAY array_of_uint;
+  int rc;
+  /* empty string */
+  bzero(&str, sizeof(str));
+
+  rc= dynamic_column_get(&str, 1, &res);
+  ok( (rc == ER_DYNCOL_OK) && (res.type == DYN_COL_NULL), "%s", "empty get");
+
+  rc= dynamic_column_delete(&str, 1);
+  ok( (rc == ER_DYNCOL_OK), "%s", "empty delete");
+
+  rc= dynamic_column_exists(&str, 1);
+  ok( (rc == ER_DYNCOL_NO), "%s", "empty exists");
+
+  rc= dynamic_column_list(&str, &array_of_uint);
+  ok( (rc == ER_DYNCOL_OK) && (array_of_uint.elements == 0),
+      "%s", "empty list");
+
+  val.type= DYN_COL_UINT;
+  val.ulong_value= 1212;
+  rc= dynamic_column_update(&str, 1, &val);
+  if (rc == ER_DYNCOL_OK)
+    rc= dynamic_column_get(&str, 1, &res);
+  ok( (rc == ER_DYNCOL_OK) &&
+      (res.type == DYN_COL_UINT) && (res.ulong_value == val.ulong_value),
+      "%s", "empty update");
+}
+
+
+void test_update_many(uint *column_numbers, uint *column_values,
+                      uint column_count,
+                      uint *update_numbers, uint *update_values,
+                      my_bool *update_nulls, uint update_count,
+                      uint *result_numbers, uint *result_values,
+                      uint result_count)
+{
+  int rc= FALSE;
+  uint i;
+  DYNAMIC_COLUMN str1;
+  DYNAMIC_COLUMN str2;
+  DYNAMIC_COLUMN_VALUE *val, *upd, *res;
+
+  val= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE) *
+                                      column_count);
+  upd= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE) *
+                                      update_count);
+  res= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE) *
+                                      result_count);
+
+
+  for (i= 0; i < column_count; i++)
+  {
+    val[i].type= DYN_COL_UINT;
+    val[i].ulong_value= column_values[i];
+  }
+  for (i= 0; i < update_count; i++)
+  {
+    if (update_nulls[i])
+      upd[i].type= DYN_COL_NULL;
+    else
+    {
+      upd[i].type= DYN_COL_UINT;
+      upd[i].ulong_value= update_values[i];
+    }
+  }
+  for (i= 0; i < result_count; i++)
+  {
+    res[i].type= DYN_COL_UINT;
+    res[i].ulong_value= result_values[i];
+  }
+  if (dynamic_column_create_many(&str1, column_count, column_numbers, val))
+    goto err;
+  if (dynamic_column_update_many(&str1, update_count, update_numbers, upd))
+    goto err;
+  if (dynamic_column_create_many(&str2, result_count, result_numbers, res))
+    goto err;
+  if (str1.length == str2.length &&
+      memcmp(str1.str, str2.str, str1.length) ==0)
+    rc= TRUE;
+
+err:
+  ok(rc, "%s", "update_many");
+  /* cleanup */
+  dynamic_column_column_free(&str1);
+  dynamic_column_column_free(&str2);
+}
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+  uint i;
+  char *big_string= (char *)malloc(1024*1024);
+
+  MY_INIT(argv[0]);
+  plan(59);
+
+  if (!big_string)
+    exit(1);
+  for (i= 0; i < 1024*1024; i++)
+    big_string[i]= ('0' + (i % 10));
+  test_value_single_null();
+  test_value_single_uint(0, "0");
+  test_value_single_uint(0xffffffffffffffff, "0xffffffffffffffff");
+  test_value_single_uint(0xaaaaaaaaaaaaaaaa, "0xaaaaaaaaaaaaaaaa");
+  test_value_single_uint(0x5555555555555555, "0x5555555555555555");
+  test_value_single_uint(27652, "27652");
+  test_value_single_sint(0, "0");
+  test_value_single_sint(1, "1");
+  test_value_single_sint(-1, "-1");
+  test_value_single_sint((longlong)0x7fffffffffffffff,
+                         "0x7fffffffffffffff");
+  test_value_single_sint((longlong)0xaaaaaaaaaaaaaaaa,
+                         "0xaaaaaaaaaaaaaaaa");
+  test_value_single_sint((longlong)0x5555555555555555,
+                         "0x5555555555555555");
+  test_value_single_sint((longlong)0x8000000000000000,
+                         "0x8000000000000000");
+  test_value_single_double(0.0, "0.0");
+  test_value_single_double(1.0, "1.0");
+  test_value_single_double(-1.0, "-1.0");
+  test_value_single_double(1.0e100, "1.0e100");
+  test_value_single_double(1.0e-100, "1.0e-100");
+  test_value_single_double(9999999999999999999999999999999999999.0,
+                           "9999999999999999999999999999999999999.0");
+  test_value_single_double(-9999999999999999999999999999999999999.0,
+                           "-9999999999999999999999999999999999999.0");
+  test_value_single_decimal("0");
+  test_value_single_decimal("1");
+  test_value_single_decimal("-1");
+  test_value_single_decimal("9999999999999999999999999999999");
+  test_value_single_decimal("-9999999999999999999999999999999");
+  test_value_single_decimal("0.9999999999999999999999999999999");
+  test_value_single_decimal("-0.9999999999999999999999999999999");
+  test_value_single_string("", 0, charset_list[0]);
+  test_value_single_string("", 1, charset_list[0]);
+  test_value_single_string("1234567890", 11, charset_list[0]);
+  test_value_single_string("nulls\0\0\0\0\0", 10, charset_list[0]);
+  sprintf(big_string, "%x", 0x7a);
+  test_value_single_string(big_string, 0x7a, charset_list[0]);
+  sprintf(big_string, "%x", 0x80);
+  test_value_single_string(big_string, 0x80, charset_list[0]);
+  sprintf(big_string, "%x", 0x7ffa);
+  test_value_single_string(big_string, 0x7ffa, charset_list[0]);
+  sprintf(big_string, "%x", 0x8000);
+  test_value_single_string(big_string, 0x8000, charset_list[0]);
+  sprintf(big_string, "%x", 1024*1024);
+  test_value_single_string(big_string, 1024*1024, charset_list[0]);
+  free(big_string);
+  test_value_single_date(0, 0, 0, "zero date");
+  test_value_single_date(9999, 12, 31, "max date");
+  test_value_single_date(2011, 3, 26, "some date");
+  test_value_single_time(0, 0, 0, 0, 0, "zero time");
+  test_value_single_time(1, 23, 59, 59, 999999, "min time");
+  test_value_single_time(0, 23, 59, 59, 999999, "max time");
+  test_value_single_time(0, 21, 36, 20, 28, "some time");
+  test_value_single_datetime(0, 0, 0, 0, 0, 0, 0, 0, "zero datetime");
+  test_value_single_datetime(1, 9999, 12, 31, 23, 59, 59, 999999,
+                             "min datetime");
+  test_value_single_datetime(0, 9999, 12, 31, 23, 59, 59, 999999,
+                             "max datetime");
+  test_value_single_datetime(0, 2011, 3, 26, 21, 53, 12, 3445,
+                             "some datetime");
+  {
+    uint column_numbers[]= {100,1,2,3,4,5,6,7,8};
+    test_value_multi(0, 0, 0.0, "0",
+                     "", 0, charset_list[0],
+                     0, 0, 0,
+                     0, 0, 0, 0, 0,
+                     0, 0, 0, 0, 0, 0, 0, 0,
+                     column_numbers,
+                     "zero data");
+  }
+  {
+    uint column_numbers[]= {10,1,12,37,4,57,6,76,87};
+    test_value_multi(0xffffffffffffffff, 0x7fffffffffffffff,
+                     99999999.999e120, "9999999999999999999999999999999",
+                     big_string, 1024*1024, charset_list[0],
+                     9999, 12, 31,
+                     0, 23, 59, 59, 999999,
+                     0, 9999, 12, 31, 23, 59, 59, 999999,
+                     column_numbers,
+                     "much data");
+  }
+  {
+    uint column_numbers[]= {101,12,122,37,24,572,16,726,77};
+    test_value_multi(37878, -3344,
+                     2873.3874, "92743.238984789898",
+                     "string", 6, charset_list[0],
+                     2011, 3, 26,
+                     1, 23, 23, 20, 333,
+                     0, 2011, 3, 26, 23, 23, 53, 334,
+                     column_numbers,
+                     "zero data");
+  }
+  test_value_multi_same_num();
+  {
+    uint column_numbers[]= {1,2,3,4,5,6,7,2, 3, 4};
+    uint column_values[]=  {1,2,3,4,5,6,7,0,30,40};
+    my_bool null_values[]= {0,0,0,0,0,0,0,1, 0, 0};
+
+    test_update_multi(column_numbers, column_values, null_values, 7, 10);
+  }
+  {
+    uint column_numbers[]= {4,3,2,1, 1,2,3,4};
+    uint column_values[]=  {4,3,2,1, 0,0,0,0};
+    my_bool null_values[]= {0,0,0,0, 1,1,1,1};
+
+    test_update_multi(column_numbers, column_values, null_values, 4, 8);
+  }
+  {
+    uint column_numbers[]= {4,3,2,1, 4,3,2,1};
+    uint column_values[]=  {4,3,2,1, 0,0,0,0};
+    my_bool null_values[]= {0,0,0,0, 1,1,1,1};
+
+    test_update_multi(column_numbers, column_values, null_values, 4, 8);
+  }
+  test_empty_string();
+  {
+    uint column_numbers[]= {1, 2, 3};
+    uint column_values[]=  {1, 2, 3};
+    uint update_numbers[]= {4, 3, 2, 1};
+    uint update_values[]=  {40,30, 0,10};
+    my_bool update_nulls[]={0, 0, 1, 0};
+    uint result_numbers[]= {1, 3, 4};
+    uint result_values[]=  {10,30,40};
+    test_update_many(column_numbers, column_values, 3,
+                     update_numbers, update_values, update_nulls, 4,
+                     result_numbers, result_values, 3);
+  }
+  return 0;
+}

=== modified file 'include/decimal.h'
--- include/decimal.h	2007-05-24 10:24:36 +0000
+++ include/decimal.h	2011-04-29 09:52:28 +0000
@@ -29,17 +29,17 @@
 
 int internal_str2dec(const char *from, decimal_t *to, char **end,
                      my_bool fixed);
-int decimal2string(decimal_t *from, char *to, int *to_len,
+int decimal2string(const decimal_t *from, char *to, int *to_len,
                    int fixed_precision, int fixed_decimals,
                    char filler);
-int decimal2ulonglong(decimal_t *from, ulonglong *to);
-int ulonglong2decimal(ulonglong from, decimal_t *to);
-int decimal2longlong(decimal_t *from, longlong *to);
+int decimal2ulonglong(const decimal_t *from, ulonglong *to);
+int ulonglong2decimal(const ulonglong from, decimal_t *to);
+int decimal2longlong(const decimal_t *from, longlong *to);
 int longlong2decimal(longlong from, decimal_t *to);
-int decimal2double(decimal_t *from, double *to);
+int decimal2double(const decimal_t *from, double *to);
 int double2decimal(double from, decimal_t *to);
 int decimal_actual_fraction(decimal_t *from);
-int decimal2bin(decimal_t *from, uchar *to, int precision, int scale);
+int decimal2bin(const decimal_t *from, uchar *to, int precision, int scale);
 int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale);
 
 int decimal_size(int precision, int scale);
@@ -55,7 +55,7 @@
 int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to,
                 int scale_incr);
 int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to);
-int decimal_round(decimal_t *from, decimal_t *to, int new_scale,
+int decimal_round(const decimal_t *from, decimal_t *to, int new_scale,
                   decimal_round_mode mode);
 int decimal_is_zero(decimal_t *from);
 void max_decimal(int precision, int frac, decimal_t *to);

=== added file 'include/ma_dyncol.h'
--- include/ma_dyncol.h	1970-01-01 00:00:00 +0000
+++ include/ma_dyncol.h	2011-04-29 09:52:28 +0000
@@ -0,0 +1,101 @@
+#ifndef ma_dyncol_h
+#define ma_dyncol_h
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <decimal.h>
+#include <my_decimal_limits.h>
+#include <mysql_time.h>
+
+#define ER_DYNCOL_YES 1
+/* NO and OK is the same used just to show semantics */
+#define ER_DYNCOL_NO 0
+#define ER_DYNCOL_OK 0
+/* Wrong format of the string with encoded columns */
+#define ER_DYNCOL_FORMAT -1
+/* Some limit reached */
+#define ER_DYNCOL_LIMIT -2
+/* Out of resourses */
+#define ER_DYNCOL_RESOURCE -3
+/* Incorrect input data */
+#define ER_DYNCOL_DATA -4
+
+typedef DYNAMIC_STRING DYNAMIC_COLUMN;
+
+enum enum_dynamic_column_type
+{
+  DYN_COL_NULL= 0,
+  DYN_COL_INT,
+  DYN_COL_UINT,
+  DYN_COL_DOUBLE,
+  DYN_COL_STRING,
+  DYN_COL_DECIMAL,
+  DYN_COL_DATETIME,
+  DYN_COL_DATE,
+  DYN_COL_TIME
+};
+
+typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE;
+
+struct st_dynamic_column_value
+{
+  DYNAMIC_COLUMN_TYPE type;
+  union
+  {
+    long long long_value;
+    unsigned long long ulong_value;
+    double double_value;
+    struct {
+      LEX_STRING string_value;
+      CHARSET_INFO *charset;
+    };
+    struct {
+      decimal_digit_t decimal_buffer[DECIMAL_BUFF_LENGTH];
+      decimal_t decimal_value;
+    };
+    MYSQL_TIME time_value;
+  };
+};
+
+typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;
+
+int dynamic_column_create(DYNAMIC_COLUMN *str,
+                          uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value);
+
+int dynamic_column_create_many(DYNAMIC_COLUMN *str,
+                               uint column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values);
+
+int dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value);
+int dynamic_column_update_many(DYNAMIC_COLUMN *str,
+                               uint add_column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values);
+
+int dynamic_column_delete(DYNAMIC_COLUMN *org, uint column_nr);
+
+int dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr);
+
+/* List of not NULL columns */
+int dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint);
+
+/*
+   if the column do not exists it is NULL
+*/
+int dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr,
+                       DYNAMIC_COLUMN_VALUE *store_it_here);
+
+#define dynamic_column_column_free(V) dynstr_free(V)
+
+#define dynamic_column_value_init(V) (V)->type= DYN_COL_NULL
+
+/*
+  Prepare value for using as decimal
+*/
+void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value);
+
+#endif

=== added file 'include/my_decimal_limits.h'
--- include/my_decimal_limits.h	1970-01-01 00:00:00 +0000
+++ include/my_decimal_limits.h	2011-04-29 09:52:28 +0000
@@ -0,0 +1,31 @@
+#ifndef my_decimal_limits_h
+#define my_decimal_limits_h
+
+#define DECIMAL_LONGLONG_DIGITS 22
+#define DECIMAL_LONG_DIGITS 10
+#define DECIMAL_LONG3_DIGITS 8
+
+/** maximum length of buffer in our big digits (uint32). */
+#define DECIMAL_BUFF_LENGTH 9
+
+/* the number of digits that my_decimal can possibly contain */
+#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)
+
+
+/**
+  maximum guaranteed precision of number in decimal digits (number of our
+  digits * number of decimal digits in one our big digit - number of decimal
+  digits in one our big digit decreased by 1 (because we always put decimal
+  point on the border of our big digits))
+*/
+#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
+#define DECIMAL_MAX_SCALE 30
+#define DECIMAL_NOT_SPECIFIED 31
+
+/**
+  maximum length of string representation (number of maximum decimal
+  digits + 1 position for sign + 1 position for decimal point)
+*/
+#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
+
+#endif

=== modified file 'include/my_time.h'
--- include/my_time.h	2008-04-03 17:14:57 +0000
+++ include/my_time.h	2011-04-29 09:52:28 +0000
@@ -72,6 +72,7 @@
                         TIME_MAX_SECOND)
 #define TIME_MAX_VALUE_SECONDS (TIME_MAX_HOUR * 3600L + \
                                 TIME_MAX_MINUTE * 60L + TIME_MAX_SECOND)
+#define TIME_SUBSECOND_RANGE 1000000
 
 my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date,
                    ulong flags, int *was_cut);
@@ -80,6 +81,8 @@
                 uint flags, int *was_cut);
 longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res,
                             uint flags, int *was_cut);
+my_bool double_to_datetime(double nr, MYSQL_TIME *time_res,
+                           uint flags);
 ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *);
 ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *);
 ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *);
@@ -87,7 +90,7 @@
 
 
 my_bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time,
-                    int *warning);
+                    ulong flag,int *warning);
 
 int check_time_range(struct st_mysql_time *, int *warning);
 

=== modified file 'libmysql/libmysql.c'
--- libmysql/libmysql.c	2011-02-28 17:39:30 +0000
+++ libmysql/libmysql.c	2011-04-29 09:52:28 +0000
@@ -3549,7 +3549,7 @@
   case MYSQL_TYPE_TIME:
   {
     MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
-    str_to_time(value, length, tm, &err);
+    str_to_time(value, length, tm, TIME_FUZZY_DATE, &err);
     *param->error= test(err);
     break;
   }

=== modified file 'mysql-test/r/bigint.result'
--- mysql-test/r/bigint.result	2010-02-25 19:13:11 +0000
+++ mysql-test/r/bigint.result	2011-04-29 10:51:42 +0000
@@ -362,12 +362,12 @@
 cast(19999999999999999999 as signed)
 9223372036854775807
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '19999999999999999999' to INT. Value truncated.
 select cast(-19999999999999999999 as signed);
 cast(-19999999999999999999 as signed)
 -9223372036854775808
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-19999999999999999999' to INT. Value truncated.
 select -9223372036854775808;
 Catalog	Database	Table	Table_alias	Column	Column_alias	Type	Length	Max length	Is_null	Flags	Decimals	Charsetnr
 def					-9223372036854775808	8	20	20	N	32897	0	63

=== modified file 'mysql-test/r/cast.result'
--- mysql-test/r/cast.result	2009-05-21 08:06:43 +0000
+++ mysql-test/r/cast.result	2011-04-29 09:52:28 +0000
@@ -1,9 +1,13 @@
 select CAST(1-2 AS UNSIGNED);
 CAST(1-2 AS UNSIGNED)
 18446744073709551615
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
 CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER)
 -1
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select CAST('10 ' as unsigned integer);
 CAST('10 ' as unsigned integer)
 10
@@ -12,9 +16,15 @@
 select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1;
 cast(-5 as unsigned) | 1	cast(-5 as unsigned) & -1
 18446744073709551611	18446744073709551611
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1;
 cast(-5 as unsigned) -1	cast(-5 as unsigned) + 1
 18446744073709551610	18446744073709551612
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select ~5, cast(~5 as signed);
 ~5	cast(~5 as signed)
 18446744073709551610	-6
@@ -29,6 +39,51 @@
 select cast(NULL as signed), cast(1/0 as signed);
 cast(NULL as signed)	cast(1/0 as signed)
 NULL	NULL
+select cast(1 as double(5,2));
+cast(1 as double(5,2))
+1.00
+select cast("5.2222" as double(5,2));
+cast("5.2222" as double(5,2))
+5.22
+select cast(12.444 as double(5,2));
+cast(12.444 as double(5,2))
+12.44
+select cast(cast(12.444 as decimal(10,3)) as double(5,2));
+cast(cast(12.444 as decimal(10,3)) as double(5,2))
+12.44
+select cast(null as double(5,2));
+cast(null as double(5,2))
+NULL
+select cast(12.444 as double);
+cast(12.444 as double)
+12.444
+select cast(cast("20:01:01" as time) as datetime);
+cast(cast("20:01:01" as time) as datetime)
+0000-00-00 20:01:01
+select cast(cast("8:46:06.23434" AS time) as decimal(32,10));
+cast(cast("8:46:06.23434" AS time) as decimal(32,10))
+84606.2343400000
+select cast(cast(20010203101112.121314 as double) as datetime);
+cast(cast(20010203101112.121314 as double) as datetime)
+2001-02-03 10:11:12.125000
+select cast(cast(010203101112.12 as double) as datetime);
+cast(cast(010203101112.12 as double) as datetime)
+2001-02-03 10:11:12.120000
+select cast(cast(20010203101112.121314 as decimal(32,6)) as datetime);
+cast(cast(20010203101112.121314 as decimal(32,6)) as datetime)
+2001-02-03 10:11:12.121314
+select cast(20010203101112.121314 as datetime);
+cast(20010203101112.121314 as datetime)
+2001-02-03 10:11:12.121314
+select cast(110203101112.121314 as datetime);
+cast(110203101112.121314 as datetime)
+2011-02-03 10:11:12.121314
+select cast(cast(010203101112.12 as double) as datetime);
+cast(cast(010203101112.12 as double) as datetime)
+2001-02-03 10:11:12.120000
+select cast(cast("2011-04-05 8:46:06.23434" AS datetime) as time);
+cast(cast("2011-04-05 8:46:06.23434" AS datetime) as time)
+08:46:06.234340
 select cast(NULL as unsigned), cast(1/0 as unsigned);
 cast(NULL as unsigned)	cast(1/0 as unsigned)
 NULL	NULL
@@ -111,6 +166,115 @@
 10
 Warnings:
 Warning	1292	Truncated incorrect DOUBLE value: 'a'
+select cast("a" as double(5,2));
+cast("a" as double(5,2))
+0.00
+Warnings:
+Warning	1292	Truncated incorrect DOUBLE value: 'a'
+select cast(1000 as decimal(5,2));
+cast(1000 as decimal(5,2))
+999.99
+Warnings:
+Error	1264	Out of range value for column 'cast(1000 as decimal(5,2))' at row 1
+select cast(-1000 as decimal(5,2));
+cast(-1000 as decimal(5,2))
+-999.99
+Warnings:
+Error	1264	Out of range value for column 'cast(-1000 as decimal(5,2))' at row 1
+select cast(1000 as double(5,2));
+cast(1000 as double(5,2))
+999.99
+Warnings:
+Warning	1264	Out of range value for column 'cast(1000 as double(5,2))' at row 1
+select cast(-1000 as double(5,2));
+cast(-1000 as double(5,2))
+-999.99
+Warnings:
+Warning	1264	Out of range value for column 'cast(-1000 as double(5,2))' at row 1
+select cast(010203101112.121314 as datetime);
+cast(010203101112.121314 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '10203101112.121314'
+select cast(120010203101112.121314 as datetime);
+cast(120010203101112.121314 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '120010203101112.121314'
+select cast(cast(1.1 as decimal) as datetime);
+cast(cast(1.1 as decimal) as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '1'
+select cast(cast(-1.1 as decimal) as datetime);
+cast(cast(-1.1 as decimal) as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '-1'
+select cast('0' as date);
+cast('0' as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '0'
+select cast('' as date);
+cast('' as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: ''
+select cast('0' as datetime);
+cast('0' as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '0'
+select cast('' as datetime);
+cast('' as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: ''
+select cast('0' as time);
+cast('0' as time)
+00:00:00
+select cast('' as time);
+cast('' as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: ''
+select cast(NULL as DATE);
+cast(NULL as DATE)
+NULL
+select cast(NULL as DATETIME);
+cast(NULL as DATETIME)
+NULL
+select cast(NULL as TIME);
+cast(NULL as TIME)
+NULL
+select cast(NULL as BINARY);
+cast(NULL as BINARY)
+NULL
+select cast(cast(120010203101112.121314 as double) as datetime);
+cast(cast(120010203101112.121314 as double) as datetime)
+NULL
+select cast(cast(1.1 as double) as datetime);
+cast(cast(1.1 as double) as datetime)
+NULL
+select cast(cast(-1.1 as double) as datetime);
+cast(cast(-1.1 as double) as datetime)
+NULL
+explain extended select cast(10 as double(5,2));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(10 as double(5,2)) AS `cast(10 as double(5,2))`
+explain extended select cast(10 as double);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(10 as double) AS `cast(10 as double)`
+explain extended select cast(10 as decimal(5,2));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(10 as decimal(5,2)) AS `cast(10 as decimal(5,2))`
 select cast('18446744073709551616' as unsigned);
 cast('18446744073709551616' as unsigned)
 18446744073709551615
@@ -146,6 +310,18 @@
 0
 Warnings:
 Warning	1292	Truncated incorrect INTEGER value: ''
+select cast(1 as double(5,6));
+ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '').
+select cast(1 as decimal(5,6));
+ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '').
+select cast(1 as double(66,6));
+ERROR 42000: Too big precision 66 specified for column '1'. Maximum is 65.
+select cast(1 as decimal(66,6));
+ERROR 42000: Too big precision 66 specified for column '1'. Maximum is 65.
+select cast(1 as decimal(64,63));
+ERROR 42000: Too big scale 63 specified for column '1'. Maximum is 30.
+select cast(1 as double(64,63));
+ERROR 42000: Too big scale 63 specified for column '1'. Maximum is 30.
 set names binary;
 select cast(_latin1'test' as char character set latin2);
 cast(_latin1'test' as char character set latin2)
@@ -255,12 +431,6 @@
 select cast("1:2:3" as TIME) = "1:02:03";
 cast("1:2:3" as TIME) = "1:02:03"
 0
-select cast(NULL as DATE);
-cast(NULL as DATE)
-NULL
-select cast(NULL as BINARY);
-cast(NULL as BINARY)
-NULL
 CREATE TABLE t1 (a enum ('aac','aab','aaa') not null);
 INSERT INTO t1 VALUES ('aaa'),('aab'),('aac');
 SELECT a, CAST(a AS CHAR) FROM t1 ORDER BY CAST(a AS UNSIGNED) ;
@@ -337,6 +507,21 @@
 select cast(1.0e+300 as signed int);
 cast(1.0e+300 as signed int)
 9223372036854775807
+create table t1  select cast(1 as unsigned), cast(1 as signed), cast(1 as double(5,2)), cast(1 as decimal(5,3)), cast("A" as binary), cast("A" as char(100)), cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME), cast("1:2:3" as TIME);
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `cast(1 as unsigned)` int(1) unsigned NOT NULL DEFAULT '0',
+  `cast(1 as signed)` int(1) NOT NULL DEFAULT '0',
+  `cast(1 as double(5,2))` double(5,2) DEFAULT NULL,
+  `cast(1 as decimal(5,3))` decimal(5,3) NOT NULL DEFAULT '0.000',
+  `cast("A" as binary)` varbinary(1) NOT NULL DEFAULT '',
+  `cast("A" as char(100))` varbinary(100) NOT NULL DEFAULT '',
+  `cast("2001-1-1" as DATE)` date DEFAULT NULL,
+  `cast("2001-1-1" as DATETIME)` datetime DEFAULT NULL,
+  `cast("1:2:3" as TIME)` time DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
 CREATE TABLE t1 (f1 double);
 INSERT INTO t1 SET f1 = -1.0e+30 ;
 INSERT INTO t1 SET f1 = +1.0e+30 ;

=== added file 'mysql-test/r/dyncol.result'
--- mysql-test/r/dyncol.result	1970-01-01 00:00:00 +0000
+++ mysql-test/r/dyncol.result	2011-04-29 11:07:51 +0000
@@ -0,0 +1,1012 @@
+#
+# column create
+#
+select hex(COLUMN_CREATE(1, NULL AS char character set utf8));
+hex(COLUMN_CREATE(1, NULL AS char character set utf8))
+000000
+select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8));
+hex(COLUMN_CREATE(1, "afaf" AS char character set utf8))
+0001000100030861666166
+select hex(COLUMN_CREATE(1, 1212 AS char character set utf8));
+hex(COLUMN_CREATE(1, 1212 AS char character set utf8))
+0001000100033F31323132
+select hex(COLUMN_CREATE(1, 12.12 AS char character set utf8));
+hex(COLUMN_CREATE(1, 12.12 AS char character set utf8))
+0001000100033F31322E3132
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS char character set utf8));
+hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS char character set utf8))
+0001000100033F3939393939393939393939393939393939393939393939393939393939
+select hex(COLUMN_CREATE(1, NULL AS unsigned int));
+hex(COLUMN_CREATE(1, NULL AS unsigned int))
+000000
+select hex(COLUMN_CREATE(1, 1212 AS unsigned int));
+hex(COLUMN_CREATE(1, 1212 AS unsigned int))
+000100010001BC04
+select hex(COLUMN_CREATE(1, 7 AS unsigned int));
+hex(COLUMN_CREATE(1, 7 AS unsigned int))
+00010001000107
+select hex(COLUMN_CREATE(1, 8 AS unsigned int));
+hex(COLUMN_CREATE(1, 8 AS unsigned int))
+00010001000108
+select hex(COLUMN_CREATE(1, 127 AS unsigned int));
+hex(COLUMN_CREATE(1, 127 AS unsigned int))
+0001000100017F
+select hex(COLUMN_CREATE(1, 128 AS unsigned int));
+hex(COLUMN_CREATE(1, 128 AS unsigned int))
+00010001000180
+select hex(COLUMN_CREATE(1, 12.12 AS unsigned int));
+hex(COLUMN_CREATE(1, 12.12 AS unsigned int))
+0001000100010C
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS unsigned int));
+hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS unsigned int))
+000100010001FFFFFFFFFFFFFF7F
+Warnings:
+Error	1655	Got overflow when converting '99999999999999999999999999999' to INT. Value truncated.
+select hex(COLUMN_CREATE(1, NULL AS int));
+hex(COLUMN_CREATE(1, NULL AS int))
+000000
+select hex(COLUMN_CREATE(1, 1212 AS int));
+hex(COLUMN_CREATE(1, 1212 AS int))
+0001000100007809
+select hex(COLUMN_CREATE(1, 7 AS int));
+hex(COLUMN_CREATE(1, 7 AS int))
+0001000100000E
+select hex(COLUMN_CREATE(1, 8 AS int));
+hex(COLUMN_CREATE(1, 8 AS int))
+00010001000010
+select hex(COLUMN_CREATE(1, 127 AS int));
+hex(COLUMN_CREATE(1, 127 AS int))
+000100010000FE
+select hex(COLUMN_CREATE(1, 128 AS int));
+hex(COLUMN_CREATE(1, 128 AS int))
+0001000100000001
+select hex(COLUMN_CREATE(1, 12.12 AS int));
+hex(COLUMN_CREATE(1, 12.12 AS int))
+00010001000018
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS int));
+hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS int))
+000100010000FEFFFFFFFFFFFFFF
+Warnings:
+Error	1655	Got overflow when converting '99999999999999999999999999999' to INT. Value truncated.
+select hex(COLUMN_CREATE(1, NULL AS double));
+hex(COLUMN_CREATE(1, NULL AS double))
+000000
+select hex(COLUMN_CREATE(1, 1212 AS double));
+hex(COLUMN_CREATE(1, 1212 AS double))
+0001000100020000000000F09240
+select hex(COLUMN_CREATE(1, 12.12 AS double));
+hex(COLUMN_CREATE(1, 12.12 AS double))
+0001000100023D0AD7A3703D2840
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS double));
+hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS double))
+00010001000221D7E6FAE031F445
+select hex(COLUMN_CREATE(1, NULL AS decimal));
+hex(COLUMN_CREATE(1, NULL AS decimal))
+000000
+select hex(COLUMN_CREATE(1, 1212 AS decimal));
+hex(COLUMN_CREATE(1, 1212 AS decimal))
+0001000100040900800004BC
+select hex(COLUMN_CREATE(1, 7 AS decimal));
+hex(COLUMN_CREATE(1, 7 AS decimal))
+000100010004090080000007
+select hex(COLUMN_CREATE(1, 8 AS decimal));
+hex(COLUMN_CREATE(1, 8 AS decimal))
+000100010004090080000008
+select hex(COLUMN_CREATE(1, 127 AS decimal));
+hex(COLUMN_CREATE(1, 127 AS decimal))
+00010001000409008000007F
+select hex(COLUMN_CREATE(1, 128 AS decimal));
+hex(COLUMN_CREATE(1, 128 AS decimal))
+000100010004090080000080
+select hex(COLUMN_CREATE(1, 12.12 AS decimal));
+hex(COLUMN_CREATE(1, 12.12 AS decimal))
+00010001000402028C0C
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS decimal));
+hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS decimal))
+0001000100041D00E33B9AC9FF3B9AC9FF3B9AC9FF
+select hex(COLUMN_CREATE(1, NULL AS date));
+hex(COLUMN_CREATE(1, NULL AS date))
+000000
+select hex(COLUMN_CREATE(1, "2011-04-05" AS date));
+hex(COLUMN_CREATE(1, "2011-04-05" AS date))
+00010001000685B60F
+select hex(COLUMN_CREATE(1, NULL AS time));
+hex(COLUMN_CREATE(1, NULL AS time))
+000000
+select hex(COLUMN_CREATE(1, "0:45:49.000001" AS time));
+hex(COLUMN_CREATE(1, "0:45:49.000001" AS time))
+000100010007010010B70000
+select hex(COLUMN_CREATE(1, NULL AS datetime));
+hex(COLUMN_CREATE(1, NULL AS datetime))
+000000
+select hex(COLUMN_CREATE(1, "2011-04-05 0:45:49.000001" AS datetime));
+hex(COLUMN_CREATE(1, "2011-04-05 0:45:49.000001" AS datetime))
+00010001000585B60F010010B70000
+select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
+2, 1212 AS unsigned int,
+3, 1212 AS int,
+4, 12.12 AS double,
+4+1, 12.12 AS decimal,
+6, "2011-04-05" AS date,
+7, "- 0:45:49.000001" AS time,
+8, "2011-04-05 0:45:49.000001" AS datetime));
+hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
+2, 1212 AS unsigned int,
+3, 1212 AS int,
+4, 12.12 AS double,
+4+1, 12.12 AS decimal,
+6, "2011-04-05" AS date,
+7, "- 0:45:49.000001" AS time,
+8, "2011-04-05 0:45:49.000001" AS datetime))
+01080001000300020029000300380004004A0005008C000600AE000700C7000800F5000861666166BC0478093D0AD7A3703D284002028C0C85B60F010010B7000485B60F010010B70000
+explain extended
+select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
+2, 1212 AS unsigned int,
+3, 1212 AS int,
+4, 12.12 AS double,
+4+1, 12.12 AS decimal,
+6, "2011-04-05" AS date,
+7, "- 0:45:49.000001" AS time,
+8, "2011-04-05 0:45:49.000001" AS datetime));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select hex(column_create(1,'afaf' AS char charset utf8 ,2,1212 AS unsigned int,3,1212 AS int,4,12.12 AS double,(4 + 1),12.12 AS decimal,6,'2011-04-05' AS date,7,'- 0:45:49.000001' AS time,8,'2011-04-05 0:45:49.000001' AS datetime)) AS `hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
+2, 1212 AS unsigned int,
+3, 1212 AS int,
+4, 12.12 AS double,
+4+1, 12.12 AS decimal,
+6, "2011-04-05" AS date,
+7, "- 0:45:49.000001" AS time,
+8, "2011-04-05 0:45:49.000001" AS datetime))`
+#
+# column get uint
+#
+select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int);
+column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int)
+1212
+explain extended
+select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212 AS unsigned int),1) as unsigned) AS `column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int)`
+explain extended
+select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212 AS unsigned int),1) as unsigned) AS `column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned)`
+select column_get(column_create(1, 1212 AS decimal), 1 as unsigned int);
+column_get(column_create(1, 1212 AS decimal), 1 as unsigned int)
+1212
+select column_get(column_create(1, 1212 AS double), 1 as unsigned int);
+column_get(column_create(1, 1212 AS double), 1 as unsigned int)
+1212
+select column_get(column_create(1, 1212 AS int), 1 as unsigned int);
+column_get(column_create(1, 1212 AS int), 1 as unsigned int)
+1212
+select column_get(column_create(1, "1212" AS char), 1 as unsigned int);
+column_get(column_create(1, "1212" AS char), 1 as unsigned int)
+1212
+select column_get(column_create(1, "2011-04-05" AS date), 1 as unsigned int);
+column_get(column_create(1, "2011-04-05" AS date), 1 as unsigned int)
+20110405
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as unsigned int);
+column_get(column_create(1, "8:46:06.23434" AS time), 1 as unsigned int)
+84606
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as unsigned int);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as unsigned int)
+20110405084606
+select column_get(column_create(1, NULL AS unsigned int), 1 as unsigned int);
+column_get(column_create(1, NULL AS unsigned int), 1 as unsigned int)
+NULL
+# column geint truncation & warnings
+select column_get(column_create(1, -1212 AS int), 1 as unsigned int);
+column_get(column_create(1, -1212 AS int), 1 as unsigned int)
+18446744073709550404
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as unsigned int);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as unsigned int)
+18446744073709551615
+Warnings:
+Error	1655	Got overflow when converting '99999999999999999999999999999' to UNSIGNED INT. Value truncated.
+select column_get(column_create(1, 999.9999999999999999 AS decimal), 1 as unsigned int);
+column_get(column_create(1, 999.9999999999999999 AS decimal), 1 as unsigned int)
+1000
+select column_get(column_create(1, -1 AS decimal), 1 as unsigned int);
+column_get(column_create(1, -1 AS decimal), 1 as unsigned int)
+0
+Warnings:
+Error	1655	Got overflow when converting '-1' to UNSIGNED INT. Value truncated.
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as unsigned int);
+column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as unsigned int)
+18446744073709551615
+Warnings:
+Warning	1655	Got overflow when converting '1e+29' to UNSIGNED INT. Value truncated.
+select column_get(column_create(1, 999.9 AS double), 1 as unsigned int);
+column_get(column_create(1, 999.9 AS double), 1 as unsigned int)
+1000
+select column_get(column_create(1, -1 AS double), 1 as unsigned int);
+column_get(column_create(1, -1 AS double), 1 as unsigned int)
+0
+Warnings:
+Warning	1655	Got overflow when converting '-1' to UNSIGNED INT. Value truncated.
+select column_get(column_create(1, "1212III" AS char), 1 as unsigned int);
+column_get(column_create(1, "1212III" AS char), 1 as unsigned int)
+1212
+Warnings:
+Warning	1657	Encountered illegal value '1212III' when converting to UNSIGNED INT
+#
+# column get int
+#
+select column_get(column_create(1, 1212 AS int), 1 as int);
+column_get(column_create(1, 1212 AS int), 1 as int)
+1212
+explain extended
+select column_get(column_create(1, 1212 AS int), 1 as int);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212 AS int),1) as signed) AS `column_get(column_create(1, 1212 AS int), 1 as int)`
+explain extended
+select column_get(column_create(1, 1212 AS int), 1 as signed int);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212 AS int),1) as signed) AS `column_get(column_create(1, 1212 AS int), 1 as signed int)`
+select column_get(column_create(1, -1212 AS int), 1 as int);
+column_get(column_create(1, -1212 AS int), 1 as int)
+-1212
+select column_get(column_create(1, 1212 AS decimal), 1 as int);
+column_get(column_create(1, 1212 AS decimal), 1 as int)
+1212
+select column_get(column_create(1, 1212 AS double), 1 as int);
+column_get(column_create(1, 1212 AS double), 1 as int)
+1212
+select column_get(column_create(1, 1212 AS unsigned int), 1 as int);
+column_get(column_create(1, 1212 AS unsigned int), 1 as int)
+1212
+select column_get(column_create(1, "1212" AS char), 1 as int);
+column_get(column_create(1, "1212" AS char), 1 as int)
+1212
+select column_get(column_create(1, "-1212" AS char), 1 as int);
+column_get(column_create(1, "-1212" AS char), 1 as int)
+-1212
+select column_get(column_create(1, "2011-04-05" AS date), 1 as int);
+column_get(column_create(1, "2011-04-05" AS date), 1 as int)
+20110405
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as int);
+column_get(column_create(1, "8:46:06.23434" AS time), 1 as int)
+84606
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as int);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as int)
+20110405084606
+select column_get(column_create(1, NULL AS int), 1 as int);
+column_get(column_create(1, NULL AS int), 1 as int)
+NULL
+#column gett truncation & warnings
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as int);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as int)
+-1
+Warnings:
+Warning	1105	Cast to signed converted positive out-of-range integer to it's negative complement
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as int);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as int)
+9223372036854775807
+Warnings:
+Error	1655	Got overflow when converting '99999999999999999999999999999' to INT. Value truncated.
+select column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as int);
+column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as int)
+-9223372036854775808
+Warnings:
+Error	1655	Got overflow when converting '-99999999999999999999999999999' to INT. Value truncated.
+select column_get(column_create(1, 999.9999999999999999 AS decimal), 1 as int);
+column_get(column_create(1, 999.9999999999999999 AS decimal), 1 as int)
+1000
+select column_get(column_create(1, 999.9 AS double), 1 as int);
+column_get(column_create(1, 999.9 AS double), 1 as int)
+1000
+select column_get(column_create(1, -99999999999999999999999999999 AS double), 1 as int);
+column_get(column_create(1, -99999999999999999999999999999 AS double), 1 as int)
+-9223372036854775808
+Warnings:
+Warning	1655	Got overflow when converting '-1e+29' to INT. Value truncated.
+select column_get(column_create(1, "-1212III" AS char), 1 as int);
+column_get(column_create(1, "-1212III" AS char), 1 as int)
+-1212
+Warnings:
+Warning	1657	Encountered illegal value '-1212III' when converting to INT
+select column_get(column_create(1, "1212III" AS char), 1 as int);
+column_get(column_create(1, "1212III" AS char), 1 as int)
+1212
+Warnings:
+Warning	1657	Encountered illegal value '1212III' when converting to INT
+#
+#column get char
+#
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8);
+column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8)
+1212
+explain extended
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,'1212' AS char charset utf8 ),1) as char charset utf8) AS `column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8)`
+select column_get(column_create(1, 1212 AS unsigned int), 1 as char charset utf8);
+column_get(column_create(1, 1212 AS unsigned int), 1 as char charset utf8)
+1212
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as char charset utf8);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as char charset utf8)
+18446744073709551615
+select column_get(column_create(1, 1212 AS int), 1 as char charset utf8);
+column_get(column_create(1, 1212 AS int), 1 as char charset utf8)
+1212
+select column_get(column_create(1, -1212 AS int), 1 as char charset utf8);
+column_get(column_create(1, -1212 AS int), 1 as char charset utf8)
+-1212
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as char charset utf8);
+column_get(column_create(1, 9223372036854775807 AS int), 1 as char charset utf8)
+9223372036854775807
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as char charset utf8);
+column_get(column_create(1, -9223372036854775808 AS int), 1 as char charset utf8)
+-9223372036854775808
+select column_get(column_create(1, 1212.12 AS decimal), 1 as char charset utf8);
+column_get(column_create(1, 1212.12 AS decimal), 1 as char charset utf8)
+1212.12
+select column_get(column_create(1, 1212.12 AS double), 1 as char charset utf8);
+column_get(column_create(1, 1212.12 AS double), 1 as char charset utf8)
+1212.12
+select column_get(column_create(1, "2011-04-05" AS date), 1 as char charset utf8);
+column_get(column_create(1, "2011-04-05" AS date), 1 as char charset utf8)
+2011-04-05
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as char charset utf8);
+column_get(column_create(1, "8:46:06.23434" AS time), 1 as char charset utf8)
+08:46:06.234340
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as char charset utf8);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as char charset utf8)
+2011-04-05 08:46:06.234340
+select column_get(column_create(1, NULL AS char charset utf8), 1 as char charset utf8);
+column_get(column_create(1, NULL AS char charset utf8), 1 as char charset utf8)
+NULL
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary);
+column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary)
+1212
+explain extended
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,'1212' AS char charset utf8 ),1) as char charset binary) AS `column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary)`
+#
+# column get real
+#
+select column_get(column_create(1, 1212.12 AS double), 1 as double);
+column_get(column_create(1, 1212.12 AS double), 1 as double)
+1212.12
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as double);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212.12 AS double),1) as double) AS `column_get(column_create(1, 1212.12 AS double), 1 as double)`
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as double(6,2));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212.12 AS double),1) as double(6,2)) AS `column_get(column_create(1, 1212.12 AS double), 1 as double(6,2))`
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as double);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as double)
+1.84467440737096e+19
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as double);
+column_get(column_create(1, 9223372036854775807 AS int), 1 as double)
+9.22337203685478e+18
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as double);
+column_get(column_create(1, -9223372036854775808 AS int), 1 as double)
+-9.22337203685478e+18
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as double);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as double)
+1e+29
+select column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as double);
+column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as double)
+-1e+29
+select column_get(column_create(1, "2011-04-05" AS date), 1 as double);
+column_get(column_create(1, "2011-04-05" AS date), 1 as double)
+20110405
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as double);
+column_get(column_create(1, "8:46:06.23434" AS time), 1 as double)
+84606.23434
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as double);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as double)
+20110405084606.2
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as double(20,6));
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as double(20,6))
+20110405084606.234375
+select column_get(column_create(1, NULL AS double), 1 as double);
+column_get(column_create(1, NULL AS double), 1 as double)
+NULL
+# column get real truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as double);
+column_get(column_create(1, "1223.5aa" AS char), 1 as double)
+1223.5
+Warnings:
+Warning	1657	Encountered illegal value '1223.5aa' when converting to DOUBLE
+select column_get(column_create(1, "aa" AS char), 1 as double);
+column_get(column_create(1, "aa" AS char), 1 as double)
+0
+Warnings:
+Warning	1657	Encountered illegal value 'aa' when converting to DOUBLE
+select column_get(column_create(1, "1223.5555" AS double), 1 as double(5,2));
+column_get(column_create(1, "1223.5555" AS double), 1 as double(5,2))
+999.99
+Warnings:
+Warning	1264	Out of range value for column 'column_get(column_create(1, "1223.5555" AS double), 1 as double(5,2))' at row 1
+select column_get(column_create(1, "1223.5555" AS double), 1 as double(3,2));
+column_get(column_create(1, "1223.5555" AS double), 1 as double(3,2))
+9.99
+Warnings:
+Warning	1264	Out of range value for column 'column_get(column_create(1, "1223.5555" AS double), 1 as double(3,2))' at row 1
+#
+# column get decimal
+#
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal);
+column_get(column_create(1, 1212.12 AS double), 1 as decimal)
+1212
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2));
+column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2))
+1212.12
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212.12 AS double),1) as decimal(10,0)) AS `column_get(column_create(1, 1212.12 AS double), 1 as decimal)`
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+Warnings:
+Note	1003	select cast(column_get(column_create(1,1212.12 AS double),1) as decimal(6,2)) AS `column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2))`
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal(20,0));
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal(20,0))
+18446744073709551615
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal(32,0));
+column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal(32,0))
+9223372036854775807
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal(32,0));
+column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal(32,0))
+-9223372036854775808
+select column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as decimal(40,10));
+column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as decimal(40,10))
+-99999999999999999999999999999.0000000000
+select column_get(column_create(1, "2011-04-05" AS date), 1 as decimal(32,6));
+column_get(column_create(1, "2011-04-05" AS date), 1 as decimal(32,6))
+20110405.000000
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as decimal(32,6));
+column_get(column_create(1, "8:46:06.23434" AS time), 1 as decimal(32,6))
+84606.234340
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal(32,6));
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal(32,6))
+20110405084606.230000
+select column_get(column_create(1, NULL as decimal), 1 as decimal(32,10));
+column_get(column_create(1, NULL as decimal), 1 as decimal(32,10))
+NULL
+select column_get(column_create(1, "1223.5555" as decimal(10,5)), 1 as decimal(6,2));
+column_get(column_create(1, "1223.5555" as decimal(10,5)), 1 as decimal(6,2))
+1223.56
+# column get decimal truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as decimal(32,10));
+column_get(column_create(1, "1223.5aa" AS char), 1 as decimal(32,10))
+1223.5000000000
+Warnings:
+Warning	1657	Encountered illegal value '1223.5aa' when converting to DECIMAL
+select column_get(column_create(1, "aa" AS char), 1 as decimal(32,10));
+column_get(column_create(1, "aa" AS char), 1 as decimal(32,10))
+0.0000000000
+Warnings:
+Warning	1657	Encountered illegal value 'aa' when converting to DECIMAL
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal)
+9999999999
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal)' at row 1
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal);
+column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal)
+9999999999
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal)' at row 1
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal);
+column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal)
+-9999999999
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal)' at row 1
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as decimal);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as decimal)
+9999999999
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as decimal)' at row 1
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal)
+9999999999
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal)' at row 1
+select column_get(column_create(1, "1223.5555" as double), 1 as decimal(5,2));
+column_get(column_create(1, "1223.5555" as double), 1 as decimal(5,2))
+999.99
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, "1223.5555" as double), 1 as decimal(5,2))' at row 1
+select column_get(column_create(1, "-1223.5555" as double), 1 as decimal(5,2));
+column_get(column_create(1, "-1223.5555" as double), 1 as decimal(5,2))
+-999.99
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, "-1223.5555" as double), 1 as decimal(5,2))' at row 1
+select column_get(column_create(1, "1223.5555" AS double), 1 as decimal(3,2));
+column_get(column_create(1, "1223.5555" AS double), 1 as decimal(3,2))
+9.99
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, "1223.5555" AS double), 1 as decimal(3,2))' at row 1
+select column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2));
+column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2))
+9.99
+Warnings:
+Error	1264	Out of range value for column 'column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2))' at row 1
+#
+# column get datetime
+#
+select column_get(column_create(1, 20010203101112.121314 as double), 1 as datetime);
+column_get(column_create(1, 20010203101112.121314 as double), 1 as datetime)
+2001-02-03 10:11:12.125000
+select column_get(column_create(1, 20010203101112.121314 as decimal), 1 as datetime);
+column_get(column_create(1, 20010203101112.121314 as decimal), 1 as datetime)
+2001-02-03 10:11:12.121314
+select column_get(column_create(1, 20010203101112 as unsigned int), 1 as datetime);
+column_get(column_create(1, 20010203101112 as unsigned int), 1 as datetime)
+2001-02-03 10:11:12
+select column_get(column_create(1, 20010203101112 as int), 1 as datetime);
+column_get(column_create(1, 20010203101112 as int), 1 as datetime)
+2001-02-03 10:11:12
+select column_get(column_create(1, "20010203101112" as char), 1 as datetime);
+column_get(column_create(1, "20010203101112" as char), 1 as datetime)
+2001-02-03 10:11:12
+select column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as datetime);
+column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as datetime)
+2001-02-03 10:11:12
+select column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as datetime);
+column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as datetime)
+2001-02-03 10:11:12.121314
+select column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as datetime);
+column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as datetime)
+2001-02-03 10:11:12.121314
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as datetime);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as datetime)
+2011-04-05 08:46:06.234340
+select column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as datetime)
+2011-00-00 08:46:06.234340
+select column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as datetime)
+2011-00-01 08:46:06.234340
+select column_get(column_create(1, 20010203 as unsigned int), 1 as datetime);
+column_get(column_create(1, 20010203 as unsigned int), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, 20010203 as int), 1 as datetime);
+column_get(column_create(1, 20010203 as int), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, 20010203), 1 as datetime);
+column_get(column_create(1, 20010203), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, 20010203.0), 1 as datetime);
+column_get(column_create(1, 20010203.0), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, 20010203.0 as double), 1 as datetime);
+column_get(column_create(1, 20010203.0 as double), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, "2001-02-03"), 1 as datetime);
+column_get(column_create(1, "2001-02-03"), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, "20010203"), 1 as datetime);
+column_get(column_create(1, "20010203"), 1 as datetime)
+2001-02-03 00:00:00
+select column_get(column_create(1, 0), 1 as datetime);
+column_get(column_create(1, 0), 1 as datetime)
+0000-00-00 00:00:00
+select column_get(column_create(1, "2001021"), 1 as datetime);
+column_get(column_create(1, "2001021"), 1 as datetime)
+2020-01-02 01:00:00
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as datetime);
+column_get(column_create(1, "8:46:06.23434" AS time), 1 as datetime)
+0000-00-00 08:46:06.234340
+set @@sql_mode="allow_invalid_dates";
+select column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as datetime)
+2011-02-30 18:46:06.234340
+select column_get(column_create(1, "0000-00-000" AS CHAR), 1 as datetime);
+column_get(column_create(1, "0000-00-000" AS CHAR), 1 as datetime)
+0000-00-00 00:00:00
+select column_get(column_create(1, "2001-00-02" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2001-00-02" AS CHAR), 1 as datetime)
+2001-00-02 00:00:00
+set @@sql_mode="";
+# column get datetime truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as datetime);
+column_get(column_create(1, "1223.5aa" AS char), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '1223.5aa'
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as datetime);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as datetime)
+NULL
+Warnings:
+Warning	1657	Encountered illegal value '18446744073709551615' when converting to DATE or DATETIME
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as datetime);
+column_get(column_create(1, 9223372036854775807 AS int), 1 as datetime)
+NULL
+Warnings:
+Warning	1657	Encountered illegal value '9223372036854775807' when converting to DATE or DATETIME
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as datetime);
+column_get(column_create(1, -9223372036854775808 AS int), 1 as datetime)
+NULL
+Warnings:
+Warning	1657	Encountered illegal value '-9223372036854775808' when converting to DATE or DATETIME
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as datetime);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '99999999999999999999999999999'
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as datetime);
+column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect datetime value: '9.99999999999999914332e+28    '
+select column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '2011-02-32 8:46:06.23434'
+select column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '2011-13-01 8:46:06.23434'
+select column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as datetime);
+column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '2011-02-30 8:46:06.23434'
+select column_get(column_create(1, "20010231"), 1 as datetime);
+column_get(column_create(1, "20010231"), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '20010231'
+select column_get(column_create(1, "0" AS CHAR), 1 as datetime);
+column_get(column_create(1, "0" AS CHAR), 1 as datetime)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '0'
+#
+# column get date
+#
+select column_get(column_create(1, 20010203101112.121314 as double), 1 as date);
+column_get(column_create(1, 20010203101112.121314 as double), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203101112.121314 as decimal), 1 as date);
+column_get(column_create(1, 20010203101112.121314 as decimal), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203101112 as unsigned int), 1 as date);
+column_get(column_create(1, 20010203101112 as unsigned int), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203101112 as int), 1 as date);
+column_get(column_create(1, 20010203101112 as int), 1 as date)
+2001-02-03
+select column_get(column_create(1, "20010203101112" as char), 1 as date);
+column_get(column_create(1, "20010203101112" as char), 1 as date)
+2001-02-03
+select column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as date);
+column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as date)
+2001-02-03
+select column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as date);
+column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as date)
+2001-02-03
+select column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as date);
+column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as date)
+2001-02-03
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as date);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as date)
+2011-04-05
+select column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as date);
+column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as date)
+2011-00-00
+select column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as date);
+column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as date)
+2011-00-01
+select column_get(column_create(1, 20010203 as unsigned int), 1 as date);
+column_get(column_create(1, 20010203 as unsigned int), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203 as int), 1 as date);
+column_get(column_create(1, 20010203 as int), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203), 1 as date);
+column_get(column_create(1, 20010203), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203.0), 1 as date);
+column_get(column_create(1, 20010203.0), 1 as date)
+2001-02-03
+select column_get(column_create(1, 20010203.0 as double), 1 as date);
+column_get(column_create(1, 20010203.0 as double), 1 as date)
+2001-02-03
+select column_get(column_create(1, "2001-02-03"), 1 as date);
+column_get(column_create(1, "2001-02-03"), 1 as date)
+2001-02-03
+select column_get(column_create(1, "20010203"), 1 as date);
+column_get(column_create(1, "20010203"), 1 as date)
+2001-02-03
+select column_get(column_create(1, 0), 1 as date);
+column_get(column_create(1, 0), 1 as date)
+0000-00-00
+select column_get(column_create(1, "2001021"), 1 as date);
+column_get(column_create(1, "2001021"), 1 as date)
+2020-01-02
+set @@sql_mode="allow_invalid_dates";
+select column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as date);
+column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as date)
+2011-02-30
+select column_get(column_create(1, "0000-00-000" AS CHAR), 1 as date);
+column_get(column_create(1, "0000-00-000" AS CHAR), 1 as date)
+0000-00-00
+select column_get(column_create(1, "2001-00-02" AS CHAR), 1 as date);
+column_get(column_create(1, "2001-00-02" AS CHAR), 1 as date)
+2001-00-02
+set @@sql_mode="";
+# column get date truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as date);
+column_get(column_create(1, "1223.5aa" AS char), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '1223.5aa'
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as date);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as date)
+NULL
+Warnings:
+Warning	1657	Encountered illegal value '18446744073709551615' when converting to DATE or DATETIME
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as date);
+column_get(column_create(1, 9223372036854775807 AS int), 1 as date)
+NULL
+Warnings:
+Warning	1657	Encountered illegal value '9223372036854775807' when converting to DATE or DATETIME
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as date);
+column_get(column_create(1, -9223372036854775808 AS int), 1 as date)
+NULL
+Warnings:
+Warning	1657	Encountered illegal value '-9223372036854775808' when converting to DATE or DATETIME
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as date);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '99999999999999999999999999999'
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as date);
+column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as date)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect datetime value: '9.99999999999999914332e+28    '
+select column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as date);
+column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '2011-02-32 8:46:06.23434'
+select column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as date);
+column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '2011-13-01 8:46:06.23434'
+select column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as date);
+column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '2011-02-30 8:46:06.23434'
+select column_get(column_create(1, "20010231"), 1 as date);
+column_get(column_create(1, "20010231"), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '20010231'
+select column_get(column_create(1, "0" AS CHAR), 1 as date);
+column_get(column_create(1, "0" AS CHAR), 1 as date)
+NULL
+Warnings:
+Warning	1292	Incorrect datetime value: '0'
+#
+# column get time
+#
+select column_get(column_create(1, 20010203101112.121314 as double), 1 as time);
+column_get(column_create(1, 20010203101112.121314 as double), 1 as time)
+10:11:12.100000
+select column_get(column_create(1, 20010203101112.121314 as decimal), 1 as time);
+column_get(column_create(1, 20010203101112.121314 as decimal), 1 as time)
+10:11:12.121314
+select column_get(column_create(1, 20010203101112 as unsigned int), 1 as time);
+column_get(column_create(1, 20010203101112 as unsigned int), 1 as time)
+10:11:12
+select column_get(column_create(1, 20010203101112 as int), 1 as time);
+column_get(column_create(1, 20010203101112 as int), 1 as time)
+10:11:12
+select column_get(column_create(1, "20010203101112" as char), 1 as time);
+column_get(column_create(1, "20010203101112" as char), 1 as time)
+10:11:12
+select column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as time);
+column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as time)
+10:11:12
+select column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as time);
+column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as time)
+10:11:12.121314
+select column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as time);
+column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as time)
+10:11:12.121314
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as time);
+column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as time)
+08:46:06.234340
+select column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as time)
+08:46:06.234340
+select column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as time)
+08:46:06.234340
+select column_get(column_create(1, "830:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "830:46:06.23434" AS CHAR), 1 as time)
+830:46:06.234340
+select column_get(column_create(1, "-830:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "-830:46:06.23434" AS CHAR), 1 as time)
+-830:46:06.234340
+select column_get(column_create(1, "0" AS CHAR), 1 as time);
+column_get(column_create(1, "0" AS CHAR), 1 as time)
+00:00:00
+select column_get(column_create(1, "6" AS CHAR), 1 as time);
+column_get(column_create(1, "6" AS CHAR), 1 as time)
+00:00:06
+select column_get(column_create(1, "1:6" AS CHAR), 1 as time);
+column_get(column_create(1, "1:6" AS CHAR), 1 as time)
+01:06:00
+select column_get(column_create(1, "2:1:6" AS CHAR), 1 as time);
+column_get(column_create(1, "2:1:6" AS CHAR), 1 as time)
+02:01:06
+select column_get(column_create(1, 0), 1 as time);
+column_get(column_create(1, 0), 1 as time)
+00:00:00
+select column_get(column_create(1, "2001021"), 1 as time);
+column_get(column_create(1, "2001021"), 1 as time)
+200:10:21
+set @@sql_mode="allow_invalid_dates";
+select column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as time)
+18:46:06.234340
+set @@sql_mode="";
+# column get date truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as time);
+column_get(column_create(1, "1223.5aa" AS char), 1 as time)
+00:12:23.500000
+Warnings:
+Warning	1292	Truncated incorrect time value: '1223.5aa'
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as time);
+column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '18446744073709551615'
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as time);
+column_get(column_create(1, 9223372036854775807 AS int), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '9223372036854775807'
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as time);
+column_get(column_create(1, -9223372036854775808 AS int), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '-9223372036854775808'
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as time);
+column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '99999999999999999999999999999'
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as time);
+column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '1e+29'
+select column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '2011-02-32 8:46:06.23434'
+select column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '2011-13-01 8:46:06.23434'
+select column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as time);
+column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as time)
+NULL
+Warnings:
+Warning	1292	Truncated incorrect time value: '2011-02-30 8:46:06.23434'
+select column_get(column_create(1, "2001-02-03"), 1 as time);
+column_get(column_create(1, "2001-02-03"), 1 as time)
+00:20:01
+Warnings:
+Warning	1292	Truncated incorrect time value: '2001-02-03'
+select column_get(column_create(1, "20010203"), 1 as time);
+column_get(column_create(1, "20010203"), 1 as time)
+838:59:59
+Warnings:
+Warning	1292	Truncated incorrect time value: '20010203'
+# column add
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer));
+hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer))
+00020001000002001078097809
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer));
+hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer))
+0001000100007809
+select hex(column_add(column_create(1, 1212 as integer), 1, NULL as integer));
+hex(column_add(column_create(1, 1212 as integer), 1, NULL as integer))
+000000
+select hex(column_add(column_create(1, 1212 as integer), 2, NULL as integer));
+hex(column_add(column_create(1, 1212 as integer), 2, NULL as integer))
+0001000100007809
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer));
+hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer))
+000200010000020008167809
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 1 as integer);
+column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 1 as integer)
+11
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 2 as integer);
+column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 2 as integer)
+1212
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer, 2, 11 as integer));
+hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer, 2, 11 as integer))
+000200010000020010780916
+select hex(column_add(column_create(1, NULL as integer), 1, 1212 as integer, 2, 11 as integer));
+hex(column_add(column_create(1, NULL as integer), 1, 1212 as integer, 2, 11 as integer))
+000200010000020010780916
+select hex(column_add(column_create(1, 1212 as integer, 2, 1212 as integer), 1, 11 as integer));
+hex(column_add(column_create(1, 1212 as integer, 2, 1212 as integer), 1, 11 as integer))
+000200010000020008167809
+# column delete
+select hex(column_delete(column_create(1, 1212 as integer, 2, 1212 as integer), 1));
+hex(column_delete(column_create(1, 1212 as integer, 2, 1212 as integer), 1))
+0001000200007809
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2))
+0002000100000300080206
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 3));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 3))
+0002000100000200080204
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 4));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 4))
+000300010000020008030010020406
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 1));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 1))
+00010003000006
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 3));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 3))
+00010001000002
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3))
+000000
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3, 10));
+hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3, 10))
+000000
+# column exists
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 1);
+column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 1)
+1
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4);
+column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4)
+0
+# column list
+select column_list(column_create(1, 1212 as integer, 2, 1212 as integer));
+column_list(column_create(1, 1212 as integer, 2, 1212 as integer))
+1,2
+select column_list(column_create(1, 1212 as integer));
+column_list(column_create(1, 1212 as integer))
+1
+select column_list(column_create(1, NULL as integer));
+column_list(column_create(1, NULL as integer))
+

=== modified file 'mysql-test/r/func_math.result'
--- mysql-test/r/func_math.result	2010-12-24 11:05:04 +0000
+++ mysql-test/r/func_math.result	2011-04-29 10:51:37 +0000
@@ -285,33 +285,55 @@
 select cast(-2 as unsigned), 18446744073709551614, -2;
 cast(-2 as unsigned)	18446744073709551614	-2
 18446744073709551614	18446744073709551614	-2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select abs(cast(-2 as unsigned)), abs(18446744073709551614), abs(-2);
 abs(cast(-2 as unsigned))	abs(18446744073709551614)	abs(-2)
 18446744073709551614	18446744073709551614	2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select ceiling(cast(-2 as unsigned)), ceiling(18446744073709551614), ceiling(-2);
 ceiling(cast(-2 as unsigned))	ceiling(18446744073709551614)	ceiling(-2)
 18446744073709551614	18446744073709551614	-2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select floor(cast(-2 as unsigned)), floor(18446744073709551614), floor(-2);
 floor(cast(-2 as unsigned))	floor(18446744073709551614)	floor(-2)
 18446744073709551614	18446744073709551614	-2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select format(cast(-2 as unsigned), 2), format(18446744073709551614, 2), format(-2, 2);
 format(cast(-2 as unsigned), 2)	format(18446744073709551614, 2)	format(-2, 2)
 18,446,744,073,709,551,614.00	18,446,744,073,709,551,614.00	-2.00
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select sqrt(cast(-2 as unsigned)), sqrt(18446744073709551614), sqrt(-2);
 sqrt(cast(-2 as unsigned))	sqrt(18446744073709551614)	sqrt(-2)
 4294967296	4294967296	NULL
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select round(cast(-2 as unsigned), 1), round(18446744073709551614, 1), round(-2, 1);
 round(cast(-2 as unsigned), 1)	round(18446744073709551614, 1)	round(-2, 1)
 18446744073709551614	18446744073709551614	-2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select round(4, cast(-2 as unsigned)), round(4, 18446744073709551614), round(4, -2);
 round(4, cast(-2 as unsigned))	round(4, 18446744073709551614)	round(4, -2)
 4	4	0
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select truncate(cast(-2 as unsigned), 1), truncate(18446744073709551614, 1), truncate(-2, 1);
 truncate(cast(-2 as unsigned), 1)	truncate(18446744073709551614, 1)	truncate(-2, 1)
 18446744073709551614	18446744073709551614	-2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select truncate(4, cast(-2 as unsigned)), truncate(4, 18446744073709551614), truncate(4, -2);
 truncate(4, cast(-2 as unsigned))	truncate(4, 18446744073709551614)	truncate(4, -2)
 4	4	0
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select round(10000000000000000000, -19), truncate(10000000000000000000, -19);
 round(10000000000000000000, -19)	truncate(10000000000000000000, -19)
 10000000000000000000	10000000000000000000
@@ -363,12 +385,18 @@
 select mod(cast(-2 as unsigned), 3), mod(18446744073709551614, 3), mod(-2, 3);
 mod(cast(-2 as unsigned), 3)	mod(18446744073709551614, 3)	mod(-2, 3)
 2	2	-2
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select mod(5, cast(-2 as unsigned)), mod(5, 18446744073709551614), mod(5, -2);
 mod(5, cast(-2 as unsigned))	mod(5, 18446744073709551614)	mod(5, -2)
 5	5	1
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select pow(cast(-2 as unsigned), 5), pow(18446744073709551614, 5), pow(-2, 5);
 pow(cast(-2 as unsigned), 5)	pow(18446744073709551614, 5)	pow(-2, 5)
 2.13598703592091e+96	2.13598703592091e+96	-32
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 CREATE TABLE t1 (a timestamp, b varchar(20), c bit(1));
 INSERT INTO t1 VALUES('1998-09-23', 'str1', 1), ('2003-03-25', 'str2', 0);
 SELECT a DIV 900 y FROM t1 GROUP BY y;
@@ -488,7 +516,7 @@
 -9999999999999999991 DIV -1
 -9223372036854775808
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-9999999999999999991' to INT. Value truncated.
 SELECT -9223372036854775808 DIV -1;
 -9223372036854775808 DIV -1
 -9223372036854775808

=== modified file 'mysql-test/r/func_str.result'
--- mysql-test/r/func_str.result	2011-03-09 13:47:59 +0000
+++ mysql-test/r/func_str.result	2011-04-29 11:17:50 +0000
@@ -1533,7 +1533,7 @@
 locate('lo','hello',-18446744073709551615)
 0
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select locate('lo','hello',18446744073709551615);
 locate('lo','hello',18446744073709551615)
 0
@@ -1541,22 +1541,22 @@
 locate('lo','hello',-18446744073709551616)
 0
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select locate('lo','hello',18446744073709551616);
 locate('lo','hello',18446744073709551616)
 0
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select locate('lo','hello',-18446744073709551617);
 locate('lo','hello',-18446744073709551617)
 0
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select locate('lo','hello',18446744073709551617);
 locate('lo','hello',18446744073709551617)
 0
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select left('hello', 10);
 left('hello', 10)
 hello
@@ -1588,8 +1588,8 @@
 left('hello', -18446744073709551615)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select left('hello', 18446744073709551615);
 left('hello', 18446744073709551615)
 hello
@@ -1597,26 +1597,26 @@
 left('hello', -18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select left('hello', 18446744073709551616);
 left('hello', 18446744073709551616)
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select left('hello', -18446744073709551617);
 left('hello', -18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select left('hello', 18446744073709551617);
 left('hello', 18446744073709551617)
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select right('hello', 10);
 right('hello', 10)
 hello
@@ -1648,8 +1648,8 @@
 right('hello', -18446744073709551615)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select right('hello', 18446744073709551615);
 right('hello', 18446744073709551615)
 hello
@@ -1657,26 +1657,26 @@
 right('hello', -18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select right('hello', 18446744073709551616);
 right('hello', 18446744073709551616)
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select right('hello', -18446744073709551617);
 right('hello', -18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select right('hello', 18446744073709551617);
 right('hello', 18446744073709551617)
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select substring('hello', 2, -1);
 substring('hello', 2, -1)
 
@@ -1708,8 +1708,8 @@
 substring('hello', -18446744073709551615, 1)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select substring('hello', 18446744073709551615, 1);
 substring('hello', 18446744073709551615, 1)
 
@@ -1717,26 +1717,26 @@
 substring('hello', -18446744073709551616, 1)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select substring('hello', 18446744073709551616, 1);
 substring('hello', 18446744073709551616, 1)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select substring('hello', -18446744073709551617, 1);
 substring('hello', -18446744073709551617, 1)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select substring('hello', 18446744073709551617, 1);
 substring('hello', 18446744073709551617, 1)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select substring('hello', 1, -1);
 substring('hello', 1, -1)
 
@@ -1762,8 +1762,8 @@
 substring('hello', 1, -18446744073709551615)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select substring('hello', 1, 18446744073709551615);
 substring('hello', 1, 18446744073709551615)
 hello
@@ -1771,26 +1771,26 @@
 substring('hello', 1, -18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select substring('hello', 1, 18446744073709551616);
 substring('hello', 1, 18446744073709551616)
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select substring('hello', 1, -18446744073709551617);
 substring('hello', 1, -18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select substring('hello', 1, 18446744073709551617);
 substring('hello', 1, 18446744073709551617)
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select substring('hello', -1, -1);
 substring('hello', -1, -1)
 
@@ -1816,10 +1816,10 @@
 substring('hello', -18446744073709551615, -18446744073709551615)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select substring('hello', 18446744073709551615, 18446744073709551615);
 substring('hello', 18446744073709551615, 18446744073709551615)
 
@@ -1827,34 +1827,34 @@
 substring('hello', -18446744073709551616, -18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select substring('hello', 18446744073709551616, 18446744073709551616);
 substring('hello', 18446744073709551616, 18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select substring('hello', -18446744073709551617, -18446744073709551617);
 substring('hello', -18446744073709551617, -18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select substring('hello', 18446744073709551617, 18446744073709551617);
 substring('hello', 18446744073709551617, 18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select insert('hello', -1, 1, 'hi');
 insert('hello', -1, 1, 'hi')
 hello
@@ -1880,7 +1880,7 @@
 insert('hello', -18446744073709551615, 1, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select insert('hello', 18446744073709551615, 1, 'hi');
 insert('hello', 18446744073709551615, 1, 'hi')
 hello
@@ -1888,22 +1888,22 @@
 insert('hello', -18446744073709551616, 1, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select insert('hello', 18446744073709551616, 1, 'hi');
 insert('hello', 18446744073709551616, 1, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select insert('hello', -18446744073709551617, 1, 'hi');
 insert('hello', -18446744073709551617, 1, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select insert('hello', 18446744073709551617, 1, 'hi');
 insert('hello', 18446744073709551617, 1, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select insert('hello', 1, -1, 'hi');
 insert('hello', 1, -1, 'hi')
 hi
@@ -1929,7 +1929,7 @@
 insert('hello', 1, -18446744073709551615, 'hi')
 hi
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select insert('hello', 1, 18446744073709551615, 'hi');
 insert('hello', 1, 18446744073709551615, 'hi')
 hi
@@ -1937,22 +1937,22 @@
 insert('hello', 1, -18446744073709551616, 'hi')
 hi
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select insert('hello', 1, 18446744073709551616, 'hi');
 insert('hello', 1, 18446744073709551616, 'hi')
 hi
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select insert('hello', 1, -18446744073709551617, 'hi');
 insert('hello', 1, -18446744073709551617, 'hi')
 hi
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select insert('hello', 1, 18446744073709551617, 'hi');
 insert('hello', 1, 18446744073709551617, 'hi')
 hi
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select insert('hello', -1, -1, 'hi');
 insert('hello', -1, -1, 'hi')
 hello
@@ -1978,8 +1978,8 @@
 insert('hello', -18446744073709551615, -18446744073709551615, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select insert('hello', 18446744073709551615, 18446744073709551615, 'hi');
 insert('hello', 18446744073709551615, 18446744073709551615, 'hi')
 hello
@@ -1987,26 +1987,26 @@
 insert('hello', -18446744073709551616, -18446744073709551616, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select insert('hello', 18446744073709551616, 18446744073709551616, 'hi');
 insert('hello', 18446744073709551616, 18446744073709551616, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 select insert('hello', -18446744073709551617, -18446744073709551617, 'hi');
 insert('hello', -18446744073709551617, -18446744073709551617, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select insert('hello', 18446744073709551617, 18446744073709551617, 'hi');
 insert('hello', 18446744073709551617, 18446744073709551617, 'hi')
 hello
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 select repeat('hello', -1);
 repeat('hello', -1)
 
@@ -2038,8 +2038,8 @@
 repeat('hello', -18446744073709551615)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select repeat('hello', 18446744073709551615);
 repeat('hello', 18446744073709551615)
 NULL
@@ -2049,27 +2049,27 @@
 repeat('hello', -18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select repeat('hello', 18446744073709551616);
 repeat('hello', 18446744073709551616)
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 Warning	1301	Result of repeat() was larger than max_allowed_packet (1048576) - truncated
 select repeat('hello', -18446744073709551617);
 repeat('hello', -18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select repeat('hello', 18446744073709551617);
 repeat('hello', 18446744073709551617)
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 Warning	1301	Result of repeat() was larger than max_allowed_packet (1048576) - truncated
 select space(-1);
 space(-1)
@@ -2102,8 +2102,8 @@
 space(-18446744073709551615)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select space(18446744073709551615);
 space(18446744073709551615)
 NULL
@@ -2113,27 +2113,27 @@
 space(-18446744073709551616)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select space(18446744073709551616);
 space(18446744073709551616)
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 Warning	1301	Result of repeat() was larger than max_allowed_packet (1048576) - truncated
 select space(-18446744073709551617);
 space(-18446744073709551617)
 
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select space(18446744073709551617);
 space(18446744073709551617)
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 Warning	1301	Result of repeat() was larger than max_allowed_packet (1048576) - truncated
 select rpad('hello', -1, '1');
 rpad('hello', -1, '1')
@@ -2166,8 +2166,8 @@
 rpad('hello', -18446744073709551615, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select rpad('hello', 18446744073709551615, '1');
 rpad('hello', 18446744073709551615, '1')
 NULL
@@ -2177,27 +2177,27 @@
 rpad('hello', -18446744073709551616, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select rpad('hello', 18446744073709551616, '1');
 rpad('hello', 18446744073709551616, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 Warning	1301	Result of rpad() was larger than max_allowed_packet (1048576) - truncated
 select rpad('hello', -18446744073709551617, '1');
 rpad('hello', -18446744073709551617, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select rpad('hello', 18446744073709551617, '1');
 rpad('hello', 18446744073709551617, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 Warning	1301	Result of rpad() was larger than max_allowed_packet (1048576) - truncated
 select lpad('hello', -1, '1');
 lpad('hello', -1, '1')
@@ -2230,8 +2230,8 @@
 lpad('hello', -18446744073709551615, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551615' to INT. Value truncated.
 select lpad('hello', 18446744073709551615, '1');
 lpad('hello', 18446744073709551615, '1')
 NULL
@@ -2241,27 +2241,27 @@
 lpad('hello', -18446744073709551616, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551616' to INT. Value truncated.
 select lpad('hello', 18446744073709551616, '1');
 lpad('hello', 18446744073709551616, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551616' to INT. Value truncated.
 Warning	1301	Result of lpad() was larger than max_allowed_packet (1048576) - truncated
 select lpad('hello', -18446744073709551617, '1');
 lpad('hello', -18446744073709551617, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '-18446744073709551617' to INT. Value truncated.
 select lpad('hello', 18446744073709551617, '1');
 lpad('hello', 18446744073709551617, '1')
 NULL
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
+Error	1655	Got overflow when converting '18446744073709551617' to INT. Value truncated.
 Warning	1301	Result of lpad() was larger than max_allowed_packet (1048576) - truncated
 SET @orig_sql_mode = @@SQL_MODE;
 SET SQL_MODE=traditional;

=== modified file 'mysql-test/r/func_time.result'
--- mysql-test/r/func_time.result	2011-02-20 16:51:43 +0000
+++ mysql-test/r/func_time.result	2011-04-29 09:52:28 +0000
@@ -1014,6 +1014,7 @@
 MAKETIME(CAST(-1 AS UNSIGNED), 0, 0)
 838:59:59
 Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 Warning	1292	Truncated incorrect time value: '18446744073709551615:00:00'
 SELECT EXTRACT(HOUR FROM '100000:02:03');
 EXTRACT(HOUR FROM '100000:02:03')
@@ -1033,6 +1034,7 @@
 SEC_TO_TIME(CAST(-1 AS UNSIGNED))
 838:59:59
 Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 Warning	1292	Truncated incorrect time value: '18446744073709551615'
 SET NAMES latin1;
 SET character_set_results = NULL;

=== modified file 'mysql-test/r/sp-vars.result'
--- mysql-test/r/sp-vars.result	2007-05-18 12:29:24 +0000
+++ mysql-test/r/sp-vars.result	2011-04-29 09:52:28 +0000
@@ -380,7 +380,7 @@
 SELECT sp_vars_check_ret2();
 ERROR 22003: Out of range value for column 'sp_vars_check_ret2()' at row 1
 SELECT sp_vars_check_ret3();
-ERROR HY000: Incorrect integer value: 'Hello, world' for column 'sp_vars_check_ret3()' at row 1
+ERROR 22007: Incorrect integer value: 'Hello, world' for column 'sp_vars_check_ret3()' at row 1
 SELECT sp_vars_check_ret4();
 sp_vars_check_ret4()
 154.12

=== modified file 'mysql-test/r/strict.result'
--- mysql-test/r/strict.result	2009-06-11 16:21:32 +0000
+++ mysql-test/r/strict.result	2011-04-29 09:52:28 +0000
@@ -260,24 +260,24 @@
 INSERT INTO t1 (col3) VALUES (CAST('2004-10-15 10:15' AS DATETIME));
 INSERT INTO t1 (col1) VALUES(CAST('0000-10-31' AS DATE));
 INSERT INTO t1 (col1) VALUES(CAST('2004-10-0' AS DATE));
-ERROR 22007: Incorrect date value: '2004-10-00' for column 'col1' at row 1
+ERROR 22007: Incorrect datetime value: '2004-10-0'
 INSERT INTO t1 (col1) VALUES(CAST('2004-0-10' AS DATE));
-ERROR 22007: Incorrect date value: '2004-00-10' for column 'col1' at row 1
+ERROR 22007: Incorrect datetime value: '2004-0-10'
 INSERT INTO t1 (col1) VALUES(CAST('0000-00-00' AS DATE));
 ERROR 22007: Incorrect datetime value: '0000-00-00'
 INSERT INTO t1 (col2) VALUES(CAST('0000-10-31 15:30' AS DATETIME));
 INSERT INTO t1 (col2) VALUES(CAST('2004-10-0 15:30' AS DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col2' at row 1
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30'
 INSERT INTO t1 (col2) VALUES(CAST('2004-0-10 15:30' AS DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col2' at row 1
+ERROR 22007: Incorrect datetime value: '2004-0-10 15:30'
 INSERT INTO t1 (col2) VALUES(CAST('0000-00-00' AS DATETIME));
 ERROR 22007: Incorrect datetime value: '0000-00-00'
 INSERT INTO t1 (col3) VALUES(CAST('0000-10-31 15:30' AS DATETIME));
 ERROR 22007: Incorrect datetime value: '0000-10-31 15:30:00' for column 'col3' at row 1
 INSERT INTO t1 (col3) VALUES(CAST('2004-10-0 15:30' AS DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col3' at row 1
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30'
 INSERT INTO t1 (col3) VALUES(CAST('2004-0-10 15:30' AS DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col3' at row 1
+ERROR 22007: Incorrect datetime value: '2004-0-10 15:30'
 INSERT INTO t1 (col3) VALUES(CAST('0000-00-00' AS DATETIME));
 ERROR 22007: Incorrect datetime value: '0000-00-00'
 drop table t1;
@@ -287,24 +287,26 @@
 INSERT INTO t1 (col3) VALUES (CONVERT('2004-10-15 10:15',DATETIME));
 INSERT INTO t1 (col1) VALUES(CONVERT('0000-10-31' , DATE));
 INSERT INTO t1 (col1) VALUES(CONVERT('2004-10-0' , DATE));
-ERROR 22007: Incorrect date value: '2004-10-00' for column 'col1' at row 1
+ERROR 22007: Incorrect datetime value: '2004-10-0'
 INSERT INTO t1 (col1) VALUES(CONVERT('2004-0-10' , DATE));
-ERROR 22007: Incorrect date value: '2004-00-10' for column 'col1' at row 1
+ERROR 22007: Incorrect datetime value: '2004-0-10'
+INSERT INTO t1 (col1) VALUES('2004-0-10');
+ERROR 22007: Incorrect date value: '2004-0-10' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES(CONVERT('0000-00-00',DATE));
 ERROR 22007: Incorrect datetime value: '0000-00-00'
 INSERT INTO t1 (col2) VALUES(CONVERT('0000-10-31 15:30',DATETIME));
 INSERT INTO t1 (col2) VALUES(CONVERT('2004-10-0 15:30',DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col2' at row 1
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30'
 INSERT INTO t1 (col2) VALUES(CONVERT('2004-0-10 15:30',DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col2' at row 1
+ERROR 22007: Incorrect datetime value: '2004-0-10 15:30'
 INSERT INTO t1 (col2) VALUES(CONVERT('0000-00-00',DATETIME));
 ERROR 22007: Incorrect datetime value: '0000-00-00'
 INSERT INTO t1 (col3) VALUES(CONVERT('0000-10-31 15:30',DATETIME));
 ERROR 22007: Incorrect datetime value: '0000-10-31 15:30:00' for column 'col3' at row 1
 INSERT INTO t1 (col3) VALUES(CONVERT('2004-10-0 15:30',DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col3' at row 1
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30'
 INSERT INTO t1 (col3) VALUES(CONVERT('2004-0-10 15:30',DATETIME));
-ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col3' at row 1
+ERROR 22007: Incorrect datetime value: '2004-0-10 15:30'
 INSERT INTO t1 (col3) VALUES(CONVERT('0000-00-00',DATETIME));
 ERROR 22007: Incorrect datetime value: '0000-00-00'
 drop table t1;
@@ -364,9 +366,9 @@
 Error	1365	Division by 0
 Error	1365	Division by 0
 INSERT INTO t1 (col1) VALUES ('');
-ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: '' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('a59b');
-ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: 'a59b' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('1a');
 ERROR 01000: Data truncated for column 'col1' at row 1
 INSERT IGNORE INTO t1 (col1) VALUES ('2a');
@@ -447,9 +449,9 @@
 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
 ERROR 22012: Division by 0
 INSERT INTO t1 (col1) VALUES ('');
-ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: '' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('a59b');
-ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: 'a59b' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('1a');
 ERROR 01000: Data truncated for column 'col1' at row 1
 INSERT IGNORE INTO t1 (col1) VALUES ('2a');
@@ -531,9 +533,9 @@
 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
 ERROR 22012: Division by 0
 INSERT INTO t1 (col1) VALUES ('');
-ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: '' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('a59b');
-ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: 'a59b' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('1a');
 ERROR 01000: Data truncated for column 'col1' at row 1
 INSERT IGNORE INTO t1 (col1) VALUES ('2a');
@@ -615,9 +617,9 @@
 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
 ERROR 22012: Division by 0
 INSERT INTO t1 (col1) VALUES ('');
-ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: '' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('a59b');
-ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: 'a59b' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('1a');
 ERROR 01000: Data truncated for column 'col1' at row 1
 INSERT IGNORE INTO t1 (col1) VALUES ('2a');
@@ -697,9 +699,9 @@
 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
 ERROR 22012: Division by 0
 INSERT INTO t1 (col1) VALUES ('');
-ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: '' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('a59b');
-ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: 'a59b' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('1a');
 ERROR 01000: Data truncated for column 'col1' at row 1
 INSERT IGNORE INTO t1 (col1) VALUES ('2a');
@@ -776,7 +778,7 @@
 INSERT INTO t1 VALUES ('-100E+1');
 ERROR 22003: Out of range value for column 'col1' at row 1
 INSERT INTO t1 VALUES ('-100E');
-ERROR HY000: Incorrect decimal value: '-100E' for column 'col1' at row 1
+ERROR 22007: Incorrect decimal value: '-100E' for column 'col1' at row 1
 UPDATE t1 SET col1 =col1 * 50000 WHERE col1 =11;
 ERROR 22003: Out of range value for column 'col1' at row 6
 UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
@@ -784,11 +786,11 @@
 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
 ERROR 22012: Division by 0
 INSERT INTO t1 (col1) VALUES ('');
-ERROR HY000: Incorrect decimal value: '' for column 'col1' at row 1
+ERROR 22007: Incorrect decimal value: '' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('a59b');
-ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect decimal value: 'a59b' for column 'col1' at row 1
 INSERT INTO t1 (col1) VALUES ('1a');
-ERROR HY000: Incorrect decimal value: '1a' for column 'col1' at row 1
+ERROR 22007: Incorrect decimal value: '1a' for column 'col1' at row 1
 INSERT IGNORE INTO t1 (col1) VALUES ('2a');
 Warnings:
 Note	1265	Data truncated for column 'col1' at row 1
@@ -1361,34 +1363,34 @@
 col7 int, col8 int unsigned,
 col9 bigint, col10 bigint unsigned);
 insert into t1(col1) values('-');
-ERROR HY000: Incorrect integer value: '-' for column 'col1' at row 1
+ERROR 22007: Incorrect integer value: '-' for column 'col1' at row 1
 insert into t1(col2) values('+');
-ERROR HY000: Incorrect integer value: '+' for column 'col2' at row 1
+ERROR 22007: Incorrect integer value: '+' for column 'col2' at row 1
 insert into t1(col3) values('-');
-ERROR HY000: Incorrect integer value: '-' for column 'col3' at row 1
+ERROR 22007: Incorrect integer value: '-' for column 'col3' at row 1
 insert into t1(col4) values('+');
-ERROR HY000: Incorrect integer value: '+' for column 'col4' at row 1
+ERROR 22007: Incorrect integer value: '+' for column 'col4' at row 1
 insert into t1(col5) values('-');
-ERROR HY000: Incorrect integer value: '-' for column 'col5' at row 1
+ERROR 22007: Incorrect integer value: '-' for column 'col5' at row 1
 insert into t1(col6) values('+');
-ERROR HY000: Incorrect integer value: '+' for column 'col6' at row 1
+ERROR 22007: Incorrect integer value: '+' for column 'col6' at row 1
 insert into t1(col7) values('-');
-ERROR HY000: Incorrect integer value: '-' for column 'col7' at row 1
+ERROR 22007: Incorrect integer value: '-' for column 'col7' at row 1
 insert into t1(col8) values('+');
-ERROR HY000: Incorrect integer value: '+' for column 'col8' at row 1
+ERROR 22007: Incorrect integer value: '+' for column 'col8' at row 1
 insert into t1(col9) values('-');
-ERROR HY000: Incorrect integer value: '-' for column 'col9' at row 1
+ERROR 22007: Incorrect integer value: '-' for column 'col9' at row 1
 insert into t1(col10) values('+');
-ERROR HY000: Incorrect integer value: '+' for column 'col10' at row 1
+ERROR 22007: Incorrect integer value: '+' for column 'col10' at row 1
 drop table t1;
 set sql_mode='traditional';
 create table t1(a year);
 insert into t1 values ('-');
-ERROR HY000: Incorrect integer value: '-' for column 'a' at row 1
+ERROR 22007: Incorrect integer value: '-' for column 'a' at row 1
 insert into t1 values ('+');
-ERROR HY000: Incorrect integer value: '+' for column 'a' at row 1
+ERROR 22007: Incorrect integer value: '+' for column 'a' at row 1
 insert into t1 values ('');
-ERROR HY000: Incorrect integer value: '' for column 'a' at row 1
+ERROR 22007: Incorrect integer value: '' for column 'a' at row 1
 insert into t1 values ('2000a');
 ERROR 01000: Data truncated for column 'a' at row 1
 insert into t1 values ('2E3x');

=== modified file 'mysql-test/r/type_newdecimal.result'
--- mysql-test/r/type_newdecimal.result	2009-12-08 09:26:11 +0000
+++ mysql-test/r/type_newdecimal.result	2011-04-29 10:53:06 +0000
@@ -825,7 +825,7 @@
 Error	1365	Division by 0
 Error	1365	Division by 0
 INSERT INTO Sow6_2f VALUES ('a59b');
-ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1
+ERROR 22007: Incorrect decimal value: 'a59b' for column 'col1' at row 1
 drop table Sow6_2f;
 select 10.3330000000000/12.34500000;
 10.3330000000000/12.34500000
@@ -838,12 +838,12 @@
 x
 99999999999999999999999999999999999999999999999999999999999999999
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
 select 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + 1 as x;
 x
 100000000000000000000000000000000000000000000000000000000000000000
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
 select 0.190287977636363637 + 0.040372670 * 0 -  0;
 0.190287977636363637 + 0.040372670 * 0 -  0
 0.190287977636363637
@@ -1380,15 +1380,15 @@
 insert into t1 values(
 89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000);
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
 Warning	1264	Out of range value for column 'c1' at row 1
 insert into t1 values(
 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 *
 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999);
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
 Warning	1264	Out of range value for column 'c1' at row 1
 insert into t1 values(1e100);
 Warnings:
@@ -1432,7 +1432,7 @@
 cast(19999999999999999999 as unsigned)
 18446744073709551615
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '19999999999999999999' to UNSIGNED INT. Value truncated.
 create table t1(a decimal(18));
 insert into t1 values(123456789012345678);
 alter table t1 modify column a decimal(19);
@@ -1674,7 +1674,7 @@
 /* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001
 AS c1;
 Warnings:
-Error	1292	Truncated incorrect DECIMAL value: ''
+Error	1655	Got overflow when converting '' to DECIMAL. Value truncated.
 DESC t1;
 Field	Type	Null	Key	Default	Extra
 c1	decimal(65,0)	NO		0	

=== modified file 'mysql-test/r/warnings.result'
--- mysql-test/r/warnings.result	2010-04-28 12:52:24 +0000
+++ mysql-test/r/warnings.result	2011-04-29 10:50:43 +0000
@@ -324,7 +324,7 @@
 CAST(a AS DECIMAL(13,5))
 0.00000
 Warnings:
-Error	1366	Incorrect decimal value: '' for column '' at row 0
+Error	1657	Encountered illegal value '' when converting to DECIMAL
 Warning	1292	Truncated incorrect DECIMAL value: ''
 create table t1 (a integer unsigned);
 insert into t1 values (1),(-1),(0),(-2);

=== modified file 'mysql-test/suite/optimizer_unfixed_bugs/t/bug43448.test'
--- mysql-test/suite/optimizer_unfixed_bugs/t/bug43448.test	2009-12-15 07:16:46 +0000
+++ mysql-test/suite/optimizer_unfixed_bugs/t/bug43448.test	2011-04-29 09:52:28 +0000
@@ -26,6 +26,7 @@
 
 disable_query_log;
 
+begin;
 let $1 = 100;
 while ($1)
 {
@@ -44,6 +45,7 @@
   }
   dec $1;
 }
+commit;
 
 enable_query_log;
 

=== modified file 'mysql-test/suite/parts/inc/part_supported_sql_funcs_delete.inc'
--- mysql-test/suite/parts/inc/part_supported_sql_funcs_delete.inc	2008-07-01 18:38:15 +0000
+++ mysql-test/suite/parts/inc/part_supported_sql_funcs_delete.inc	2011-04-29 09:52:28 +0000
@@ -16,12 +16,14 @@
 --echo ---  Delete rows and partitions of tables with $sqlfunc
 --echo -------------------------------------------------------------------------
 
+begin;
 eval delete from $t1 where col1=$val2;
 eval delete from $t2 where col1=$val2;
 eval delete from $t3 where col1=$val2;
 eval delete from $t4 where col1=$val2;
 eval delete from $t5 where col1=$val2;
 eval delete from $t6 where col1=$val2;
+commit;
 
 eval select * from $t1 order by col1;
 eval select * from $t2 order by col1;
@@ -29,12 +31,14 @@
 eval select * from $t4 order by colint;
 eval select * from $t5 order by colint;
 
+begin;
 eval insert into $t1 values ($val2);
 eval insert into $t2 values ($val2);
 eval insert into $t3 values ($val2);
 eval insert into $t4 values (60,$val2);
 eval insert into $t5 values (60,$val2);
 eval insert into $t6 values (60,$val2);
+commit;
 
 eval select * from $t1 order by col1;
 eval select * from $t2 order by col1;

=== modified file 'mysql-test/suite/parts/inc/partition_supported_sql_funcs.inc'
--- mysql-test/suite/parts/inc/partition_supported_sql_funcs.inc	2008-08-04 05:04:47 +0000
+++ mysql-test/suite/parts/inc/partition_supported_sql_funcs.inc	2011-04-29 09:52:28 +0000
@@ -113,6 +113,7 @@
 --echo ---  Access tables with $sqlfunc 
 --echo -------------------------------------------------------------------------
 
+begin;
 eval insert into t1 values ($val1);
 eval insert into t1 values ($val2);
 
@@ -123,6 +124,7 @@
 eval insert into t3 values ($val1);
 eval insert into t3 values ($val2);
 eval insert into t3 values ($val3);
+commit;
 
 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
 eval load data infile '$MYSQLTEST_VARDIR/std_data/parts/$infile' into table t4;
@@ -142,12 +144,14 @@
 
 if ($do_long_tests)
 {
+        begin;
 	eval update t1 set col1=$val4 where col1=$val1;
 	eval update t2 set col1=$val4 where col1=$val1;
 	eval update t3 set col1=$val4 where col1=$val1;
 	eval update t4 set col1=$val4 where col1=$val1;
 	eval update t5 set col1=$val4 where col1=$val1;
 	eval update t6 set col1=$val4 where col1=$val1;
+        commit;
 
 	select * from t1 order by col1;
 	select * from t2 order by col1;

=== modified file 'mysql-test/suite/parts/r/part_supported_sql_func_innodb.result'
--- mysql-test/suite/parts/r/part_supported_sql_func_innodb.result	2010-12-22 09:50:36 +0000
+++ mysql-test/suite/parts/r/part_supported_sql_func_innodb.result	2011-04-29 09:52:28 +0000
@@ -47,6 +47,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with abs(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values (5 );
 insert into t1 values (13 );
 insert into t2 values (5 );
@@ -55,6 +56,7 @@
 insert into t3 values (5 );
 insert into t3 values (13 );
 insert into t3 values (17 );
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t6;
@@ -217,12 +219,14 @@
 50	56
 51	34
 55	123
+begin;
 update t1 set col1=15  where col1=5 ;
 update t2 set col1=15  where col1=5 ;
 update t3 set col1=15  where col1=5 ;
 update t4 set col1=15  where col1=5 ;
 update t5 set col1=15  where col1=5 ;
 update t6 set col1=15  where col1=5 ;
+commit;
 select * from t1 order by col1;
 col1
 13
@@ -877,12 +881,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with abs(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1=13 ;
 delete from t2 where col1=13 ;
 delete from t3 where col1=13 ;
 delete from t4 where col1=13 ;
 delete from t5 where col1=13 ;
 delete from t6 where col1=13 ;
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -986,12 +992,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t1 values (13 );
 insert into t2 values (13 );
 insert into t3 values (13 );
 insert into t4 values (60,13 );
 insert into t5 values (60,13 );
 insert into t6 values (60,13 );
+commit;
 select * from t1 order by col1;
 col1
 13
@@ -1274,12 +1282,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with abs(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1=13 ;
 delete from t22 where col1=13 ;
 delete from t33 where col1=13 ;
 delete from t44 where col1=13 ;
 delete from t55 where col1=13 ;
 delete from t66 where col1=13 ;
+commit;
 select * from t11 order by col1;
 col1
 15
@@ -1383,12 +1393,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t11 values (13 );
 insert into t22 values (13 );
 insert into t33 values (13 );
 insert into t44 values (60,13 );
 insert into t55 values (60,13 );
 insert into t66 values (60,13 );
+commit;
 select * from t11 order by col1;
 col1
 13
@@ -1732,6 +1744,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with mod(col1,10) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values (5);
 insert into t1 values (19);
 insert into t2 values (5);
@@ -1740,6 +1753,7 @@
 insert into t3 values (5);
 insert into t3 values (19);
 insert into t3 values (17);
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t6;
@@ -1902,12 +1916,14 @@
 50	56
 51	34
 55	123
+begin;
 update t1 set col1=15  where col1=5;
 update t2 set col1=15  where col1=5;
 update t3 set col1=15  where col1=5;
 update t4 set col1=15  where col1=5;
 update t5 set col1=15  where col1=5;
 update t6 set col1=15  where col1=5;
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -2562,12 +2578,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with mod(col1,10)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1=19;
 delete from t2 where col1=19;
 delete from t3 where col1=19;
 delete from t4 where col1=19;
 delete from t5 where col1=19;
 delete from t6 where col1=19;
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -2673,12 +2691,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t1 values (19);
 insert into t2 values (19);
 insert into t3 values (19);
 insert into t4 values (60,19);
 insert into t5 values (60,19);
 insert into t6 values (60,19);
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -2970,12 +2990,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with mod(col1,10)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1=19;
 delete from t22 where col1=19;
 delete from t33 where col1=19;
 delete from t44 where col1=19;
 delete from t55 where col1=19;
 delete from t66 where col1=19;
+commit;
 select * from t11 order by col1;
 col1
 15
@@ -3081,12 +3103,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t11 values (19);
 insert into t22 values (19);
 insert into t33 values (19);
 insert into t44 values (60,19);
 insert into t55 values (60,19);
 insert into t66 values (60,19);
+commit;
 select * from t11 order by col1;
 col1
 15
@@ -3439,6 +3463,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with day(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-02-03');
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-02-03');
@@ -3447,6 +3472,7 @@
 insert into t3 values ('2006-02-03');
 insert into t3 values ('2006-01-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -3486,12 +3512,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-02-03';
 update t2 set col1='2006-02-05' where col1='2006-02-03';
 update t3 set col1='2006-02-05' where col1='2006-02-03';
 update t4 set col1='2006-02-05' where col1='2006-02-03';
 update t5 set col1='2006-02-05' where col1='2006-02-03';
 update t6 set col1='2006-02-05' where col1='2006-02-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -3695,12 +3723,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with day(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-01-17';
 delete from t2 where col1='2006-01-17';
 delete from t3 where col1='2006-01-17';
 delete from t4 where col1='2006-01-17';
 delete from t5 where col1='2006-01-17';
 delete from t6 where col1='2006-01-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -3722,12 +3752,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-17');
 insert into t3 values ('2006-01-17');
 insert into t4 values (60,'2006-01-17');
 insert into t5 values (60,'2006-01-17');
 insert into t6 values (60,'2006-01-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -3789,12 +3821,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with day(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-01-17';
 delete from t22 where col1='2006-01-17';
 delete from t33 where col1='2006-01-17';
 delete from t44 where col1='2006-01-17';
 delete from t55 where col1='2006-01-17';
 delete from t66 where col1='2006-01-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -3816,12 +3850,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-01-17');
 insert into t22 values ('2006-01-17');
 insert into t33 values ('2006-01-17');
 insert into t44 values (60,'2006-01-17');
 insert into t55 values (60,'2006-01-17');
 insert into t66 values (60,'2006-01-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-01-17
@@ -3944,6 +3980,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with dayofmonth(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-02-03');
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-02-03');
@@ -3952,6 +3989,7 @@
 insert into t3 values ('2006-02-03');
 insert into t3 values ('2006-01-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -3991,12 +4029,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-02-03';
 update t2 set col1='2006-02-05' where col1='2006-02-03';
 update t3 set col1='2006-02-05' where col1='2006-02-03';
 update t4 set col1='2006-02-05' where col1='2006-02-03';
 update t5 set col1='2006-02-05' where col1='2006-02-03';
 update t6 set col1='2006-02-05' where col1='2006-02-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -4200,12 +4240,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofmonth(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-01-17';
 delete from t2 where col1='2006-01-17';
 delete from t3 where col1='2006-01-17';
 delete from t4 where col1='2006-01-17';
 delete from t5 where col1='2006-01-17';
 delete from t6 where col1='2006-01-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4227,12 +4269,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-17');
 insert into t3 values ('2006-01-17');
 insert into t4 values (60,'2006-01-17');
 insert into t5 values (60,'2006-01-17');
 insert into t6 values (60,'2006-01-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -4294,12 +4338,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofmonth(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-01-17';
 delete from t22 where col1='2006-01-17';
 delete from t33 where col1='2006-01-17';
 delete from t44 where col1='2006-01-17';
 delete from t55 where col1='2006-01-17';
 delete from t66 where col1='2006-01-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -4321,12 +4367,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-01-17');
 insert into t22 values ('2006-01-17');
 insert into t33 values ('2006-01-17');
 insert into t44 values (60,'2006-01-17');
 insert into t55 values (60,'2006-01-17');
 insert into t66 values (60,'2006-01-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-01-17
@@ -4449,6 +4497,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with dayofweek(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-01-03');
@@ -4457,6 +4506,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-02-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -4496,12 +4546,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-01-03';
 update t2 set col1='2006-02-05' where col1='2006-01-03';
 update t3 set col1='2006-02-05' where col1='2006-01-03';
 update t4 set col1='2006-02-05' where col1='2006-01-03';
 update t5 set col1='2006-02-05' where col1='2006-01-03';
 update t6 set col1='2006-02-05' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4705,12 +4757,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofweek(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-02-17';
 delete from t2 where col1='2006-02-17';
 delete from t3 where col1='2006-02-17';
 delete from t4 where col1='2006-02-17';
 delete from t5 where col1='2006-02-17';
 delete from t6 where col1='2006-02-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4734,12 +4788,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-02-17');
 insert into t3 values ('2006-02-17');
 insert into t4 values (60,'2006-02-17');
 insert into t5 values (60,'2006-02-17');
 insert into t6 values (60,'2006-02-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4805,12 +4861,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofweek(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-02-17';
 delete from t22 where col1='2006-02-17';
 delete from t33 where col1='2006-02-17';
 delete from t44 where col1='2006-02-17';
 delete from t55 where col1='2006-02-17';
 delete from t66 where col1='2006-02-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -4834,12 +4892,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-02-17');
 insert into t22 values ('2006-02-17');
 insert into t33 values ('2006-02-17');
 insert into t44 values (60,'2006-02-17');
 insert into t55 values (60,'2006-02-17');
 insert into t66 values (60,'2006-02-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -4966,6 +5026,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with dayofyear(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-03');
@@ -4974,6 +5035,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-01-17');
 insert into t3 values ('2006-02-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -5013,12 +5075,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-01-03';
 update t2 set col1='2006-02-05' where col1='2006-01-03';
 update t3 set col1='2006-02-05' where col1='2006-01-03';
 update t4 set col1='2006-02-05' where col1='2006-01-03';
 update t5 set col1='2006-02-05' where col1='2006-01-03';
 update t6 set col1='2006-02-05' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -5222,12 +5286,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofyear(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-01-17';
 delete from t2 where col1='2006-01-17';
 delete from t3 where col1='2006-01-17';
 delete from t4 where col1='2006-01-17';
 delete from t5 where col1='2006-01-17';
 delete from t6 where col1='2006-01-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5249,12 +5315,14 @@
 1	2006-02-03
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-17');
 insert into t3 values ('2006-01-17');
 insert into t4 values (60,'2006-01-17');
 insert into t5 values (60,'2006-01-17');
 insert into t6 values (60,'2006-01-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -5317,12 +5385,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofyear(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-01-17';
 delete from t22 where col1='2006-01-17';
 delete from t33 where col1='2006-01-17';
 delete from t44 where col1='2006-01-17';
 delete from t55 where col1='2006-01-17';
 delete from t66 where col1='2006-01-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -5344,12 +5414,14 @@
 1	2006-02-03
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-01-17');
 insert into t22 values ('2006-01-17');
 insert into t33 values ('2006-01-17');
 insert into t44 values (60,'2006-01-17');
 insert into t55 values (60,'2006-01-17');
 insert into t66 values (60,'2006-01-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-01-17
@@ -5473,6 +5545,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with extract(month from col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-01-03');
@@ -5481,6 +5554,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-02-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -5520,12 +5594,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-01-03';
 update t2 set col1='2006-02-05' where col1='2006-01-03';
 update t3 set col1='2006-02-05' where col1='2006-01-03';
 update t4 set col1='2006-02-05' where col1='2006-01-03';
 update t5 set col1='2006-02-05' where col1='2006-01-03';
 update t6 set col1='2006-02-05' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5729,12 +5805,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with extract(month from col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-02-17';
 delete from t2 where col1='2006-02-17';
 delete from t3 where col1='2006-02-17';
 delete from t4 where col1='2006-02-17';
 delete from t5 where col1='2006-02-17';
 delete from t6 where col1='2006-02-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5758,12 +5836,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-02-17');
 insert into t3 values ('2006-02-17');
 insert into t4 values (60,'2006-02-17');
 insert into t5 values (60,'2006-02-17');
 insert into t6 values (60,'2006-02-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5824,12 +5904,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with extract(month from col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-02-17';
 delete from t22 where col1='2006-02-17';
 delete from t33 where col1='2006-02-17';
 delete from t44 where col1='2006-02-17';
 delete from t55 where col1='2006-02-17';
 delete from t66 where col1='2006-02-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -5853,12 +5935,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-02-17');
 insert into t22 values ('2006-02-17');
 insert into t33 values ('2006-02-17');
 insert into t44 values (60,'2006-02-17');
 insert into t55 values (60,'2006-02-17');
 insert into t66 values (60,'2006-02-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -5980,6 +6064,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with hour(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09');
 insert into t1 values ('14:30');
 insert into t2 values ('09:09');
@@ -5988,6 +6073,7 @@
 insert into t3 values ('09:09');
 insert into t3 values ('14:30');
 insert into t3 values ('21:59');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -6027,12 +6113,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:30' where col1='09:09';
 update t2 set col1='10:30' where col1='09:09';
 update t3 set col1='10:30' where col1='09:09';
 update t4 set col1='10:30' where col1='09:09';
 update t5 set col1='10:30' where col1='09:09';
 update t6 set col1='10:30' where col1='09:09';
+commit;
 select * from t1 order by col1;
 col1
 10:30:00
@@ -6236,12 +6324,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with hour(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30';
 delete from t2 where col1='14:30';
 delete from t3 where col1='14:30';
 delete from t4 where col1='14:30';
 delete from t5 where col1='14:30';
 delete from t6 where col1='14:30';
+commit;
 select * from t1 order by col1;
 col1
 10:30:00
@@ -6265,12 +6355,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30');
 insert into t2 values ('14:30');
 insert into t3 values ('14:30');
 insert into t4 values (60,'14:30');
 insert into t5 values (60,'14:30');
 insert into t6 values (60,'14:30');
+commit;
 select * from t1 order by col1;
 col1
 10:30:00
@@ -6334,12 +6426,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with hour(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30';
 delete from t22 where col1='14:30';
 delete from t33 where col1='14:30';
 delete from t44 where col1='14:30';
 delete from t55 where col1='14:30';
 delete from t66 where col1='14:30';
+commit;
 select * from t11 order by col1;
 col1
 10:30:00
@@ -6363,12 +6457,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30');
 insert into t22 values ('14:30');
 insert into t33 values ('14:30');
 insert into t44 values (60,'14:30');
 insert into t55 values (60,'14:30');
 insert into t66 values (60,'14:30');
+commit;
 select * from t11 order by col1;
 col1
 10:30:00
@@ -6493,6 +6589,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with microsecond(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:15.000002');
 insert into t1 values ('04:30:01.000018');
 insert into t2 values ('09:09:15.000002');
@@ -6501,6 +6598,7 @@
 insert into t3 values ('09:09:15.000002');
 insert into t3 values ('04:30:01.000018');
 insert into t3 values ('00:59:22.000024');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -6540,12 +6638,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t2 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t3 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t4 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t5 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t6 set col1='05:30:34.000037' where col1='09:09:15.000002';
+commit;
 select * from t1 order by col1;
 col1
 04:30:01
@@ -6749,12 +6849,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with microsecond(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='04:30:01.000018';
 delete from t2 where col1='04:30:01.000018';
 delete from t3 where col1='04:30:01.000018';
 delete from t4 where col1='04:30:01.000018';
 delete from t5 where col1='04:30:01.000018';
 delete from t6 where col1='04:30:01.000018';
+commit;
 select * from t1 order by col1;
 col1
 05:30:34
@@ -6776,12 +6878,14 @@
 1	05:30:34
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('04:30:01.000018');
 insert into t2 values ('04:30:01.000018');
 insert into t3 values ('04:30:01.000018');
 insert into t4 values (60,'04:30:01.000018');
 insert into t5 values (60,'04:30:01.000018');
 insert into t6 values (60,'04:30:01.000018');
+commit;
 select * from t1 order by col1;
 col1
 04:30:01
@@ -6840,12 +6944,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with microsecond(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='04:30:01.000018';
 delete from t22 where col1='04:30:01.000018';
 delete from t33 where col1='04:30:01.000018';
 delete from t44 where col1='04:30:01.000018';
 delete from t55 where col1='04:30:01.000018';
 delete from t66 where col1='04:30:01.000018';
+commit;
 select * from t11 order by col1;
 col1
 05:30:34
@@ -6867,12 +6973,14 @@
 1	05:30:34
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('04:30:01.000018');
 insert into t22 values ('04:30:01.000018');
 insert into t33 values ('04:30:01.000018');
 insert into t44 values (60,'04:30:01.000018');
 insert into t55 values (60,'04:30:01.000018');
 insert into t66 values (60,'04:30:01.000018');
+commit;
 select * from t11 order by col1;
 col1
 04:30:01
@@ -6992,6 +7100,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with minute(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:15');
 insert into t1 values ('14:30:45');
 insert into t2 values ('09:09:15');
@@ -7000,6 +7109,7 @@
 insert into t3 values ('09:09:15');
 insert into t3 values ('14:30:45');
 insert into t3 values ('21:59:22');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -7039,12 +7149,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:24:23' where col1='09:09:15';
 update t2 set col1='10:24:23' where col1='09:09:15';
 update t3 set col1='10:24:23' where col1='09:09:15';
 update t4 set col1='10:24:23' where col1='09:09:15';
 update t5 set col1='10:24:23' where col1='09:09:15';
 update t6 set col1='10:24:23' where col1='09:09:15';
+commit;
 select * from t1 order by col1;
 col1
 10:24:23
@@ -7248,12 +7360,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with minute(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30:45';
 delete from t2 where col1='14:30:45';
 delete from t3 where col1='14:30:45';
 delete from t4 where col1='14:30:45';
 delete from t5 where col1='14:30:45';
 delete from t6 where col1='14:30:45';
+commit;
 select * from t1 order by col1;
 col1
 10:24:23
@@ -7277,12 +7391,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30:45');
 insert into t2 values ('14:30:45');
 insert into t3 values ('14:30:45');
 insert into t4 values (60,'14:30:45');
 insert into t5 values (60,'14:30:45');
 insert into t6 values (60,'14:30:45');
+commit;
 select * from t1 order by col1;
 col1
 10:24:23
@@ -7349,12 +7465,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with minute(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30:45';
 delete from t22 where col1='14:30:45';
 delete from t33 where col1='14:30:45';
 delete from t44 where col1='14:30:45';
 delete from t55 where col1='14:30:45';
 delete from t66 where col1='14:30:45';
+commit;
 select * from t11 order by col1;
 col1
 10:24:23
@@ -7378,12 +7496,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30:45');
 insert into t22 values ('14:30:45');
 insert into t33 values ('14:30:45');
 insert into t44 values (60,'14:30:45');
 insert into t55 values (60,'14:30:45');
 insert into t66 values (60,'14:30:45');
+commit;
 select * from t11 order by col1;
 col1
 10:24:23
@@ -7511,6 +7631,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with second(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:09');
 insert into t1 values ('14:30:20');
 insert into t2 values ('09:09:09');
@@ -7519,6 +7640,7 @@
 insert into t3 values ('09:09:09');
 insert into t3 values ('14:30:20');
 insert into t3 values ('21:59:22');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -7558,12 +7680,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:22:33' where col1='09:09:09';
 update t2 set col1='10:22:33' where col1='09:09:09';
 update t3 set col1='10:22:33' where col1='09:09:09';
 update t4 set col1='10:22:33' where col1='09:09:09';
 update t5 set col1='10:22:33' where col1='09:09:09';
 update t6 set col1='10:22:33' where col1='09:09:09';
+commit;
 select * from t1 order by col1;
 col1
 10:22:33
@@ -7767,12 +7891,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with second(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30:20';
 delete from t2 where col1='14:30:20';
 delete from t3 where col1='14:30:20';
 delete from t4 where col1='14:30:20';
 delete from t5 where col1='14:30:20';
 delete from t6 where col1='14:30:20';
+commit;
 select * from t1 order by col1;
 col1
 10:22:33
@@ -7796,12 +7922,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30:20');
 insert into t2 values ('14:30:20');
 insert into t3 values ('14:30:20');
 insert into t4 values (60,'14:30:20');
 insert into t5 values (60,'14:30:20');
 insert into t6 values (60,'14:30:20');
+commit;
 select * from t1 order by col1;
 col1
 10:22:33
@@ -7868,12 +7996,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with second(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30:20';
 delete from t22 where col1='14:30:20';
 delete from t33 where col1='14:30:20';
 delete from t44 where col1='14:30:20';
 delete from t55 where col1='14:30:20';
 delete from t66 where col1='14:30:20';
+commit;
 select * from t11 order by col1;
 col1
 10:22:33
@@ -7897,12 +8027,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30:20');
 insert into t22 values ('14:30:20');
 insert into t33 values ('14:30:20');
 insert into t44 values (60,'14:30:20');
 insert into t55 values (60,'14:30:20');
 insert into t66 values (60,'14:30:20');
+commit;
 select * from t11 order by col1;
 col1
 10:22:33
@@ -8030,6 +8162,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with month(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-01-03');
@@ -8038,6 +8171,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-12-17');
 insert into t3 values ('2006-05-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -8077,12 +8211,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-11-06' where col1='2006-01-03';
 update t2 set col1='2006-11-06' where col1='2006-01-03';
 update t3 set col1='2006-11-06' where col1='2006-01-03';
 update t4 set col1='2006-11-06' where col1='2006-01-03';
 update t5 set col1='2006-11-06' where col1='2006-01-03';
 update t6 set col1='2006-11-06' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-11-06
@@ -8286,12 +8422,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with month(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-12-17';
 delete from t2 where col1='2006-12-17';
 delete from t3 where col1='2006-12-17';
 delete from t4 where col1='2006-12-17';
 delete from t5 where col1='2006-12-17';
 delete from t6 where col1='2006-12-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-11-06
@@ -8315,12 +8453,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-12-17');
 insert into t3 values ('2006-12-17');
 insert into t4 values (60,'2006-12-17');
 insert into t5 values (60,'2006-12-17');
 insert into t6 values (60,'2006-12-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-11-06
@@ -8384,12 +8524,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with month(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-12-17';
 delete from t22 where col1='2006-12-17';
 delete from t33 where col1='2006-12-17';
 delete from t44 where col1='2006-12-17';
 delete from t55 where col1='2006-12-17';
 delete from t66 where col1='2006-12-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-11-06
@@ -8413,12 +8555,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-12-17');
 insert into t22 values ('2006-12-17');
 insert into t33 values ('2006-12-17');
 insert into t44 values (60,'2006-12-17');
 insert into t55 values (60,'2006-12-17');
 insert into t66 values (60,'2006-12-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-11-06
@@ -8543,6 +8687,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with quarter(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-01-03');
@@ -8551,6 +8696,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-12-17');
 insert into t3 values ('2006-09-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -8590,12 +8736,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-07-30' where col1='2006-01-03';
 update t2 set col1='2006-07-30' where col1='2006-01-03';
 update t3 set col1='2006-07-30' where col1='2006-01-03';
 update t4 set col1='2006-07-30' where col1='2006-01-03';
 update t5 set col1='2006-07-30' where col1='2006-01-03';
 update t6 set col1='2006-07-30' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-07-30
@@ -8799,12 +8947,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with quarter(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-12-17';
 delete from t2 where col1='2006-12-17';
 delete from t3 where col1='2006-12-17';
 delete from t4 where col1='2006-12-17';
 delete from t5 where col1='2006-12-17';
 delete from t6 where col1='2006-12-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-07-30
@@ -8828,12 +8978,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-12-17');
 insert into t3 values ('2006-12-17');
 insert into t4 values (60,'2006-12-17');
 insert into t5 values (60,'2006-12-17');
 insert into t6 values (60,'2006-12-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-07-30
@@ -8896,12 +9048,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with quarter(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-12-17';
 delete from t22 where col1='2006-12-17';
 delete from t33 where col1='2006-12-17';
 delete from t44 where col1='2006-12-17';
 delete from t55 where col1='2006-12-17';
 delete from t66 where col1='2006-12-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-07-30
@@ -8925,12 +9079,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-12-17');
 insert into t22 values ('2006-12-17');
 insert into t33 values ('2006-12-17');
 insert into t44 values (60,'2006-12-17');
 insert into t55 values (60,'2006-12-17');
 insert into t66 values (60,'2006-12-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-07-30
@@ -9054,6 +9210,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with time_to_sec(col1)-(time_to_sec(col1)-20) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:15');
 insert into t1 values ('14:30:45');
 insert into t2 values ('09:09:15');
@@ -9062,6 +9219,7 @@
 insert into t3 values ('09:09:15');
 insert into t3 values ('14:30:45');
 insert into t3 values ('21:59:22');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -9101,12 +9259,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:33:11' where col1='09:09:15';
 update t2 set col1='10:33:11' where col1='09:09:15';
 update t3 set col1='10:33:11' where col1='09:09:15';
 update t4 set col1='10:33:11' where col1='09:09:15';
 update t5 set col1='10:33:11' where col1='09:09:15';
 update t6 set col1='10:33:11' where col1='09:09:15';
+commit;
 select * from t1 order by col1;
 col1
 10:33:11
@@ -9310,12 +9470,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with time_to_sec(col1)-(time_to_sec(col1)-20)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30:45';
 delete from t2 where col1='14:30:45';
 delete from t3 where col1='14:30:45';
 delete from t4 where col1='14:30:45';
 delete from t5 where col1='14:30:45';
 delete from t6 where col1='14:30:45';
+commit;
 select * from t1 order by col1;
 col1
 10:33:11
@@ -9339,12 +9501,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30:45');
 insert into t2 values ('14:30:45');
 insert into t3 values ('14:30:45');
 insert into t4 values (60,'14:30:45');
 insert into t5 values (60,'14:30:45');
 insert into t6 values (60,'14:30:45');
+commit;
 select * from t1 order by col1;
 col1
 10:33:11
@@ -9410,12 +9574,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with time_to_sec(col1)-(time_to_sec(col1)-20)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30:45';
 delete from t22 where col1='14:30:45';
 delete from t33 where col1='14:30:45';
 delete from t44 where col1='14:30:45';
 delete from t55 where col1='14:30:45';
 delete from t66 where col1='14:30:45';
+commit;
 select * from t11 order by col1;
 col1
 10:33:11
@@ -9439,12 +9605,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30:45');
 insert into t22 values ('14:30:45');
 insert into t33 values ('14:30:45');
 insert into t44 values (60,'14:30:45');
 insert into t55 values (60,'14:30:45');
 insert into t66 values (60,'14:30:45');
+commit;
 select * from t11 order by col1;
 col1
 10:33:11
@@ -9571,6 +9739,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with weekday(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-12-03');
 insert into t1 values ('2006-11-17');
 insert into t2 values ('2006-12-03');
@@ -9579,6 +9748,7 @@
 insert into t3 values ('2006-12-03');
 insert into t3 values ('2006-11-17');
 insert into t3 values ('2006-05-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -9618,12 +9788,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-06' where col1='2006-12-03';
 update t2 set col1='2006-02-06' where col1='2006-12-03';
 update t3 set col1='2006-02-06' where col1='2006-12-03';
 update t4 set col1='2006-02-06' where col1='2006-12-03';
 update t5 set col1='2006-02-06' where col1='2006-12-03';
 update t6 set col1='2006-02-06' where col1='2006-12-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-06
@@ -9827,12 +9999,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with weekday(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-11-17';
 delete from t2 where col1='2006-11-17';
 delete from t3 where col1='2006-11-17';
 delete from t4 where col1='2006-11-17';
 delete from t5 where col1='2006-11-17';
 delete from t6 where col1='2006-11-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-06
@@ -9856,12 +10030,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-11-17');
 insert into t2 values ('2006-11-17');
 insert into t3 values ('2006-11-17');
 insert into t4 values (60,'2006-11-17');
 insert into t5 values (60,'2006-11-17');
 insert into t6 values (60,'2006-11-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-02-06
@@ -9923,12 +10099,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with weekday(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-11-17';
 delete from t22 where col1='2006-11-17';
 delete from t33 where col1='2006-11-17';
 delete from t44 where col1='2006-11-17';
 delete from t55 where col1='2006-11-17';
 delete from t66 where col1='2006-11-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-06
@@ -9952,12 +10130,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-11-17');
 insert into t22 values ('2006-11-17');
 insert into t33 values ('2006-11-17');
 insert into t44 values (60,'2006-11-17');
 insert into t55 values (60,'2006-11-17');
 insert into t66 values (60,'2006-11-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-02-06
@@ -10080,6 +10260,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with year(col1)-1990 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('1996-01-03');
 insert into t1 values ('2000-02-17');
 insert into t2 values ('1996-01-03');
@@ -10088,6 +10269,7 @@
 insert into t3 values ('1996-01-03');
 insert into t3 values ('2000-02-17');
 insert into t3 values ('2004-05-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -10127,12 +10309,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2002-02-15' where col1='1996-01-03';
 update t2 set col1='2002-02-15' where col1='1996-01-03';
 update t3 set col1='2002-02-15' where col1='1996-01-03';
 update t4 set col1='2002-02-15' where col1='1996-01-03';
 update t5 set col1='2002-02-15' where col1='1996-01-03';
 update t6 set col1='2002-02-15' where col1='1996-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2000-02-17
@@ -10336,12 +10520,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with year(col1)-1990
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2000-02-17';
 delete from t2 where col1='2000-02-17';
 delete from t3 where col1='2000-02-17';
 delete from t4 where col1='2000-02-17';
 delete from t5 where col1='2000-02-17';
 delete from t6 where col1='2000-02-17';
+commit;
 select * from t1 order by col1;
 col1
 2002-02-15
@@ -10365,12 +10551,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2000-02-17');
 insert into t2 values ('2000-02-17');
 insert into t3 values ('2000-02-17');
 insert into t4 values (60,'2000-02-17');
 insert into t5 values (60,'2000-02-17');
 insert into t6 values (60,'2000-02-17');
+commit;
 select * from t1 order by col1;
 col1
 2000-02-17
@@ -10434,12 +10622,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with year(col1)-1990
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2000-02-17';
 delete from t22 where col1='2000-02-17';
 delete from t33 where col1='2000-02-17';
 delete from t44 where col1='2000-02-17';
 delete from t55 where col1='2000-02-17';
 delete from t66 where col1='2000-02-17';
+commit;
 select * from t11 order by col1;
 col1
 2002-02-15
@@ -10463,12 +10653,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2000-02-17');
 insert into t22 values ('2000-02-17');
 insert into t33 values ('2000-02-17');
 insert into t44 values (60,'2000-02-17');
 insert into t55 values (60,'2000-02-17');
 insert into t66 values (60,'2000-02-17');
+commit;
 select * from t11 order by col1;
 col1
 2000-02-17
@@ -10593,6 +10785,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with yearweek(col1)-200600 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-08-17');
 insert into t2 values ('2006-01-03');
@@ -10601,6 +10794,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-08-17');
 insert into t3 values ('2006-03-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -10640,12 +10834,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-11-15' where col1='2006-01-03';
 update t2 set col1='2006-11-15' where col1='2006-01-03';
 update t3 set col1='2006-11-15' where col1='2006-01-03';
 update t4 set col1='2006-11-15' where col1='2006-01-03';
 update t5 set col1='2006-11-15' where col1='2006-01-03';
 update t6 set col1='2006-11-15' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-08-17
@@ -10849,12 +11045,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with yearweek(col1)-200600
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-08-17';
 delete from t2 where col1='2006-08-17';
 delete from t3 where col1='2006-08-17';
 delete from t4 where col1='2006-08-17';
 delete from t5 where col1='2006-08-17';
 delete from t6 where col1='2006-08-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-11-15
@@ -10878,12 +11076,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-08-17');
 insert into t2 values ('2006-08-17');
 insert into t3 values ('2006-08-17');
 insert into t4 values (60,'2006-08-17');
 insert into t5 values (60,'2006-08-17');
 insert into t6 values (60,'2006-08-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-08-17
@@ -10950,12 +11150,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with yearweek(col1)-200600
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-08-17';
 delete from t22 where col1='2006-08-17';
 delete from t33 where col1='2006-08-17';
 delete from t44 where col1='2006-08-17';
 delete from t55 where col1='2006-08-17';
 delete from t66 where col1='2006-08-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-11-15
@@ -10979,12 +11181,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-08-17');
 insert into t22 values ('2006-08-17');
 insert into t33 values ('2006-08-17');
 insert into t44 values (60,'2006-08-17');
 insert into t55 values (60,'2006-08-17');
 insert into t66 values (60,'2006-08-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-08-17

=== modified file 'mysql-test/suite/parts/r/part_supported_sql_func_myisam.result'
--- mysql-test/suite/parts/r/part_supported_sql_func_myisam.result	2010-12-22 09:50:36 +0000
+++ mysql-test/suite/parts/r/part_supported_sql_func_myisam.result	2011-04-29 09:52:28 +0000
@@ -47,6 +47,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with abs(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values (5 );
 insert into t1 values (13 );
 insert into t2 values (5 );
@@ -55,6 +56,7 @@
 insert into t3 values (5 );
 insert into t3 values (13 );
 insert into t3 values (17 );
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t6;
@@ -217,12 +219,14 @@
 50	56
 51	34
 55	123
+begin;
 update t1 set col1=15  where col1=5 ;
 update t2 set col1=15  where col1=5 ;
 update t3 set col1=15  where col1=5 ;
 update t4 set col1=15  where col1=5 ;
 update t5 set col1=15  where col1=5 ;
 update t6 set col1=15  where col1=5 ;
+commit;
 select * from t1 order by col1;
 col1
 13
@@ -877,12 +881,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with abs(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1=13 ;
 delete from t2 where col1=13 ;
 delete from t3 where col1=13 ;
 delete from t4 where col1=13 ;
 delete from t5 where col1=13 ;
 delete from t6 where col1=13 ;
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -986,12 +992,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t1 values (13 );
 insert into t2 values (13 );
 insert into t3 values (13 );
 insert into t4 values (60,13 );
 insert into t5 values (60,13 );
 insert into t6 values (60,13 );
+commit;
 select * from t1 order by col1;
 col1
 13
@@ -1274,12 +1282,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with abs(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1=13 ;
 delete from t22 where col1=13 ;
 delete from t33 where col1=13 ;
 delete from t44 where col1=13 ;
 delete from t55 where col1=13 ;
 delete from t66 where col1=13 ;
+commit;
 select * from t11 order by col1;
 col1
 15
@@ -1383,12 +1393,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t11 values (13 );
 insert into t22 values (13 );
 insert into t33 values (13 );
 insert into t44 values (60,13 );
 insert into t55 values (60,13 );
 insert into t66 values (60,13 );
+commit;
 select * from t11 order by col1;
 col1
 13
@@ -1732,6 +1744,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with mod(col1,10) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values (5);
 insert into t1 values (19);
 insert into t2 values (5);
@@ -1740,6 +1753,7 @@
 insert into t3 values (5);
 insert into t3 values (19);
 insert into t3 values (17);
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_int.inc' into table t6;
@@ -1902,12 +1916,14 @@
 50	56
 51	34
 55	123
+begin;
 update t1 set col1=15  where col1=5;
 update t2 set col1=15  where col1=5;
 update t3 set col1=15  where col1=5;
 update t4 set col1=15  where col1=5;
 update t5 set col1=15  where col1=5;
 update t6 set col1=15  where col1=5;
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -2562,12 +2578,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with mod(col1,10)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1=19;
 delete from t2 where col1=19;
 delete from t3 where col1=19;
 delete from t4 where col1=19;
 delete from t5 where col1=19;
 delete from t6 where col1=19;
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -2673,12 +2691,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t1 values (19);
 insert into t2 values (19);
 insert into t3 values (19);
 insert into t4 values (60,19);
 insert into t5 values (60,19);
 insert into t6 values (60,19);
+commit;
 select * from t1 order by col1;
 col1
 15
@@ -2970,12 +2990,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with mod(col1,10)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1=19;
 delete from t22 where col1=19;
 delete from t33 where col1=19;
 delete from t44 where col1=19;
 delete from t55 where col1=19;
 delete from t66 where col1=19;
+commit;
 select * from t11 order by col1;
 col1
 15
@@ -3081,12 +3103,14 @@
 50	56
 51	34
 55	123
+begin;
 insert into t11 values (19);
 insert into t22 values (19);
 insert into t33 values (19);
 insert into t44 values (60,19);
 insert into t55 values (60,19);
 insert into t66 values (60,19);
+commit;
 select * from t11 order by col1;
 col1
 15
@@ -3439,6 +3463,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with day(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-02-03');
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-02-03');
@@ -3447,6 +3472,7 @@
 insert into t3 values ('2006-02-03');
 insert into t3 values ('2006-01-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -3486,12 +3512,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-02-03';
 update t2 set col1='2006-02-05' where col1='2006-02-03';
 update t3 set col1='2006-02-05' where col1='2006-02-03';
 update t4 set col1='2006-02-05' where col1='2006-02-03';
 update t5 set col1='2006-02-05' where col1='2006-02-03';
 update t6 set col1='2006-02-05' where col1='2006-02-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -3695,12 +3723,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with day(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-01-17';
 delete from t2 where col1='2006-01-17';
 delete from t3 where col1='2006-01-17';
 delete from t4 where col1='2006-01-17';
 delete from t5 where col1='2006-01-17';
 delete from t6 where col1='2006-01-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -3722,12 +3752,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-17');
 insert into t3 values ('2006-01-17');
 insert into t4 values (60,'2006-01-17');
 insert into t5 values (60,'2006-01-17');
 insert into t6 values (60,'2006-01-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -3789,12 +3821,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with day(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-01-17';
 delete from t22 where col1='2006-01-17';
 delete from t33 where col1='2006-01-17';
 delete from t44 where col1='2006-01-17';
 delete from t55 where col1='2006-01-17';
 delete from t66 where col1='2006-01-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -3816,12 +3850,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-01-17');
 insert into t22 values ('2006-01-17');
 insert into t33 values ('2006-01-17');
 insert into t44 values (60,'2006-01-17');
 insert into t55 values (60,'2006-01-17');
 insert into t66 values (60,'2006-01-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-01-17
@@ -3944,6 +3980,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with dayofmonth(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-02-03');
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-02-03');
@@ -3952,6 +3989,7 @@
 insert into t3 values ('2006-02-03');
 insert into t3 values ('2006-01-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -3991,12 +4029,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-02-03';
 update t2 set col1='2006-02-05' where col1='2006-02-03';
 update t3 set col1='2006-02-05' where col1='2006-02-03';
 update t4 set col1='2006-02-05' where col1='2006-02-03';
 update t5 set col1='2006-02-05' where col1='2006-02-03';
 update t6 set col1='2006-02-05' where col1='2006-02-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -4200,12 +4240,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofmonth(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-01-17';
 delete from t2 where col1='2006-01-17';
 delete from t3 where col1='2006-01-17';
 delete from t4 where col1='2006-01-17';
 delete from t5 where col1='2006-01-17';
 delete from t6 where col1='2006-01-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4227,12 +4269,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-17');
 insert into t3 values ('2006-01-17');
 insert into t4 values (60,'2006-01-17');
 insert into t5 values (60,'2006-01-17');
 insert into t6 values (60,'2006-01-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -4294,12 +4338,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofmonth(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-01-17';
 delete from t22 where col1='2006-01-17';
 delete from t33 where col1='2006-01-17';
 delete from t44 where col1='2006-01-17';
 delete from t55 where col1='2006-01-17';
 delete from t66 where col1='2006-01-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -4321,12 +4367,14 @@
 1	2006-02-05
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-01-17');
 insert into t22 values ('2006-01-17');
 insert into t33 values ('2006-01-17');
 insert into t44 values (60,'2006-01-17');
 insert into t55 values (60,'2006-01-17');
 insert into t66 values (60,'2006-01-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-01-17
@@ -4449,6 +4497,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with dayofweek(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-01-03');
@@ -4457,6 +4506,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-02-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -4496,12 +4546,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-01-03';
 update t2 set col1='2006-02-05' where col1='2006-01-03';
 update t3 set col1='2006-02-05' where col1='2006-01-03';
 update t4 set col1='2006-02-05' where col1='2006-01-03';
 update t5 set col1='2006-02-05' where col1='2006-01-03';
 update t6 set col1='2006-02-05' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4705,12 +4757,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofweek(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-02-17';
 delete from t2 where col1='2006-02-17';
 delete from t3 where col1='2006-02-17';
 delete from t4 where col1='2006-02-17';
 delete from t5 where col1='2006-02-17';
 delete from t6 where col1='2006-02-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4734,12 +4788,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-02-17');
 insert into t3 values ('2006-02-17');
 insert into t4 values (60,'2006-02-17');
 insert into t5 values (60,'2006-02-17');
 insert into t6 values (60,'2006-02-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -4805,12 +4861,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofweek(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-02-17';
 delete from t22 where col1='2006-02-17';
 delete from t33 where col1='2006-02-17';
 delete from t44 where col1='2006-02-17';
 delete from t55 where col1='2006-02-17';
 delete from t66 where col1='2006-02-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -4834,12 +4892,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-02-17');
 insert into t22 values ('2006-02-17');
 insert into t33 values ('2006-02-17');
 insert into t44 values (60,'2006-02-17');
 insert into t55 values (60,'2006-02-17');
 insert into t66 values (60,'2006-02-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -4966,6 +5026,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with dayofyear(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-03');
@@ -4974,6 +5035,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-01-17');
 insert into t3 values ('2006-02-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -5013,12 +5075,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-01-03';
 update t2 set col1='2006-02-05' where col1='2006-01-03';
 update t3 set col1='2006-02-05' where col1='2006-01-03';
 update t4 set col1='2006-02-05' where col1='2006-01-03';
 update t5 set col1='2006-02-05' where col1='2006-01-03';
 update t6 set col1='2006-02-05' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -5222,12 +5286,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofyear(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-01-17';
 delete from t2 where col1='2006-01-17';
 delete from t3 where col1='2006-01-17';
 delete from t4 where col1='2006-01-17';
 delete from t5 where col1='2006-01-17';
 delete from t6 where col1='2006-01-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5249,12 +5315,14 @@
 1	2006-02-03
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-01-17');
 insert into t2 values ('2006-01-17');
 insert into t3 values ('2006-01-17');
 insert into t4 values (60,'2006-01-17');
 insert into t5 values (60,'2006-01-17');
 insert into t6 values (60,'2006-01-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-01-17
@@ -5317,12 +5385,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with dayofyear(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-01-17';
 delete from t22 where col1='2006-01-17';
 delete from t33 where col1='2006-01-17';
 delete from t44 where col1='2006-01-17';
 delete from t55 where col1='2006-01-17';
 delete from t66 where col1='2006-01-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -5344,12 +5414,14 @@
 1	2006-02-03
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-01-17');
 insert into t22 values ('2006-01-17');
 insert into t33 values ('2006-01-17');
 insert into t44 values (60,'2006-01-17');
 insert into t55 values (60,'2006-01-17');
 insert into t66 values (60,'2006-01-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-01-17
@@ -5473,6 +5545,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with extract(month from col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-01-03');
@@ -5481,6 +5554,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-02-17');
 insert into t3 values ('2006-01-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -5520,12 +5594,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-05' where col1='2006-01-03';
 update t2 set col1='2006-02-05' where col1='2006-01-03';
 update t3 set col1='2006-02-05' where col1='2006-01-03';
 update t4 set col1='2006-02-05' where col1='2006-01-03';
 update t5 set col1='2006-02-05' where col1='2006-01-03';
 update t6 set col1='2006-02-05' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5729,12 +5805,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with extract(month from col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-02-17';
 delete from t2 where col1='2006-02-17';
 delete from t3 where col1='2006-02-17';
 delete from t4 where col1='2006-02-17';
 delete from t5 where col1='2006-02-17';
 delete from t6 where col1='2006-02-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5758,12 +5836,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-02-17');
 insert into t2 values ('2006-02-17');
 insert into t3 values ('2006-02-17');
 insert into t4 values (60,'2006-02-17');
 insert into t5 values (60,'2006-02-17');
 insert into t6 values (60,'2006-02-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-02-05
@@ -5824,12 +5904,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with extract(month from col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-02-17';
 delete from t22 where col1='2006-02-17';
 delete from t33 where col1='2006-02-17';
 delete from t44 where col1='2006-02-17';
 delete from t55 where col1='2006-02-17';
 delete from t66 where col1='2006-02-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -5853,12 +5935,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-02-17');
 insert into t22 values ('2006-02-17');
 insert into t33 values ('2006-02-17');
 insert into t44 values (60,'2006-02-17');
 insert into t55 values (60,'2006-02-17');
 insert into t66 values (60,'2006-02-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-02-05
@@ -5980,6 +6064,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with hour(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09');
 insert into t1 values ('14:30');
 insert into t2 values ('09:09');
@@ -5988,6 +6073,7 @@
 insert into t3 values ('09:09');
 insert into t3 values ('14:30');
 insert into t3 values ('21:59');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -6027,12 +6113,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:30' where col1='09:09';
 update t2 set col1='10:30' where col1='09:09';
 update t3 set col1='10:30' where col1='09:09';
 update t4 set col1='10:30' where col1='09:09';
 update t5 set col1='10:30' where col1='09:09';
 update t6 set col1='10:30' where col1='09:09';
+commit;
 select * from t1 order by col1;
 col1
 10:30:00
@@ -6236,12 +6324,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with hour(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30';
 delete from t2 where col1='14:30';
 delete from t3 where col1='14:30';
 delete from t4 where col1='14:30';
 delete from t5 where col1='14:30';
 delete from t6 where col1='14:30';
+commit;
 select * from t1 order by col1;
 col1
 10:30:00
@@ -6265,12 +6355,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30');
 insert into t2 values ('14:30');
 insert into t3 values ('14:30');
 insert into t4 values (60,'14:30');
 insert into t5 values (60,'14:30');
 insert into t6 values (60,'14:30');
+commit;
 select * from t1 order by col1;
 col1
 10:30:00
@@ -6334,12 +6426,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with hour(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30';
 delete from t22 where col1='14:30';
 delete from t33 where col1='14:30';
 delete from t44 where col1='14:30';
 delete from t55 where col1='14:30';
 delete from t66 where col1='14:30';
+commit;
 select * from t11 order by col1;
 col1
 10:30:00
@@ -6363,12 +6457,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30');
 insert into t22 values ('14:30');
 insert into t33 values ('14:30');
 insert into t44 values (60,'14:30');
 insert into t55 values (60,'14:30');
 insert into t66 values (60,'14:30');
+commit;
 select * from t11 order by col1;
 col1
 10:30:00
@@ -6493,6 +6589,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with microsecond(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:15.000002');
 insert into t1 values ('04:30:01.000018');
 insert into t2 values ('09:09:15.000002');
@@ -6501,6 +6598,7 @@
 insert into t3 values ('09:09:15.000002');
 insert into t3 values ('04:30:01.000018');
 insert into t3 values ('00:59:22.000024');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -6540,12 +6638,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t2 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t3 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t4 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t5 set col1='05:30:34.000037' where col1='09:09:15.000002';
 update t6 set col1='05:30:34.000037' where col1='09:09:15.000002';
+commit;
 select * from t1 order by col1;
 col1
 04:30:01
@@ -6749,12 +6849,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with microsecond(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='04:30:01.000018';
 delete from t2 where col1='04:30:01.000018';
 delete from t3 where col1='04:30:01.000018';
 delete from t4 where col1='04:30:01.000018';
 delete from t5 where col1='04:30:01.000018';
 delete from t6 where col1='04:30:01.000018';
+commit;
 select * from t1 order by col1;
 col1
 05:30:34
@@ -6776,12 +6878,14 @@
 1	05:30:34
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('04:30:01.000018');
 insert into t2 values ('04:30:01.000018');
 insert into t3 values ('04:30:01.000018');
 insert into t4 values (60,'04:30:01.000018');
 insert into t5 values (60,'04:30:01.000018');
 insert into t6 values (60,'04:30:01.000018');
+commit;
 select * from t1 order by col1;
 col1
 04:30:01
@@ -6840,12 +6944,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with microsecond(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='04:30:01.000018';
 delete from t22 where col1='04:30:01.000018';
 delete from t33 where col1='04:30:01.000018';
 delete from t44 where col1='04:30:01.000018';
 delete from t55 where col1='04:30:01.000018';
 delete from t66 where col1='04:30:01.000018';
+commit;
 select * from t11 order by col1;
 col1
 05:30:34
@@ -6867,12 +6973,14 @@
 1	05:30:34
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('04:30:01.000018');
 insert into t22 values ('04:30:01.000018');
 insert into t33 values ('04:30:01.000018');
 insert into t44 values (60,'04:30:01.000018');
 insert into t55 values (60,'04:30:01.000018');
 insert into t66 values (60,'04:30:01.000018');
+commit;
 select * from t11 order by col1;
 col1
 04:30:01
@@ -6992,6 +7100,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with minute(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:15');
 insert into t1 values ('14:30:45');
 insert into t2 values ('09:09:15');
@@ -7000,6 +7109,7 @@
 insert into t3 values ('09:09:15');
 insert into t3 values ('14:30:45');
 insert into t3 values ('21:59:22');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -7039,12 +7149,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:24:23' where col1='09:09:15';
 update t2 set col1='10:24:23' where col1='09:09:15';
 update t3 set col1='10:24:23' where col1='09:09:15';
 update t4 set col1='10:24:23' where col1='09:09:15';
 update t5 set col1='10:24:23' where col1='09:09:15';
 update t6 set col1='10:24:23' where col1='09:09:15';
+commit;
 select * from t1 order by col1;
 col1
 10:24:23
@@ -7248,12 +7360,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with minute(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30:45';
 delete from t2 where col1='14:30:45';
 delete from t3 where col1='14:30:45';
 delete from t4 where col1='14:30:45';
 delete from t5 where col1='14:30:45';
 delete from t6 where col1='14:30:45';
+commit;
 select * from t1 order by col1;
 col1
 10:24:23
@@ -7277,12 +7391,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30:45');
 insert into t2 values ('14:30:45');
 insert into t3 values ('14:30:45');
 insert into t4 values (60,'14:30:45');
 insert into t5 values (60,'14:30:45');
 insert into t6 values (60,'14:30:45');
+commit;
 select * from t1 order by col1;
 col1
 10:24:23
@@ -7349,12 +7465,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with minute(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30:45';
 delete from t22 where col1='14:30:45';
 delete from t33 where col1='14:30:45';
 delete from t44 where col1='14:30:45';
 delete from t55 where col1='14:30:45';
 delete from t66 where col1='14:30:45';
+commit;
 select * from t11 order by col1;
 col1
 10:24:23
@@ -7378,12 +7496,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30:45');
 insert into t22 values ('14:30:45');
 insert into t33 values ('14:30:45');
 insert into t44 values (60,'14:30:45');
 insert into t55 values (60,'14:30:45');
 insert into t66 values (60,'14:30:45');
+commit;
 select * from t11 order by col1;
 col1
 10:24:23
@@ -7511,6 +7631,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with second(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:09');
 insert into t1 values ('14:30:20');
 insert into t2 values ('09:09:09');
@@ -7519,6 +7640,7 @@
 insert into t3 values ('09:09:09');
 insert into t3 values ('14:30:20');
 insert into t3 values ('21:59:22');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -7558,12 +7680,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:22:33' where col1='09:09:09';
 update t2 set col1='10:22:33' where col1='09:09:09';
 update t3 set col1='10:22:33' where col1='09:09:09';
 update t4 set col1='10:22:33' where col1='09:09:09';
 update t5 set col1='10:22:33' where col1='09:09:09';
 update t6 set col1='10:22:33' where col1='09:09:09';
+commit;
 select * from t1 order by col1;
 col1
 10:22:33
@@ -7767,12 +7891,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with second(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30:20';
 delete from t2 where col1='14:30:20';
 delete from t3 where col1='14:30:20';
 delete from t4 where col1='14:30:20';
 delete from t5 where col1='14:30:20';
 delete from t6 where col1='14:30:20';
+commit;
 select * from t1 order by col1;
 col1
 10:22:33
@@ -7796,12 +7922,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30:20');
 insert into t2 values ('14:30:20');
 insert into t3 values ('14:30:20');
 insert into t4 values (60,'14:30:20');
 insert into t5 values (60,'14:30:20');
 insert into t6 values (60,'14:30:20');
+commit;
 select * from t1 order by col1;
 col1
 10:22:33
@@ -7868,12 +7996,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with second(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30:20';
 delete from t22 where col1='14:30:20';
 delete from t33 where col1='14:30:20';
 delete from t44 where col1='14:30:20';
 delete from t55 where col1='14:30:20';
 delete from t66 where col1='14:30:20';
+commit;
 select * from t11 order by col1;
 col1
 10:22:33
@@ -7897,12 +8027,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30:20');
 insert into t22 values ('14:30:20');
 insert into t33 values ('14:30:20');
 insert into t44 values (60,'14:30:20');
 insert into t55 values (60,'14:30:20');
 insert into t66 values (60,'14:30:20');
+commit;
 select * from t11 order by col1;
 col1
 10:22:33
@@ -8030,6 +8162,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with month(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-01-03');
@@ -8038,6 +8171,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-12-17');
 insert into t3 values ('2006-05-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -8077,12 +8211,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-11-06' where col1='2006-01-03';
 update t2 set col1='2006-11-06' where col1='2006-01-03';
 update t3 set col1='2006-11-06' where col1='2006-01-03';
 update t4 set col1='2006-11-06' where col1='2006-01-03';
 update t5 set col1='2006-11-06' where col1='2006-01-03';
 update t6 set col1='2006-11-06' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-11-06
@@ -8286,12 +8422,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with month(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-12-17';
 delete from t2 where col1='2006-12-17';
 delete from t3 where col1='2006-12-17';
 delete from t4 where col1='2006-12-17';
 delete from t5 where col1='2006-12-17';
 delete from t6 where col1='2006-12-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-11-06
@@ -8315,12 +8453,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-12-17');
 insert into t3 values ('2006-12-17');
 insert into t4 values (60,'2006-12-17');
 insert into t5 values (60,'2006-12-17');
 insert into t6 values (60,'2006-12-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-11-06
@@ -8384,12 +8524,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with month(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-12-17';
 delete from t22 where col1='2006-12-17';
 delete from t33 where col1='2006-12-17';
 delete from t44 where col1='2006-12-17';
 delete from t55 where col1='2006-12-17';
 delete from t66 where col1='2006-12-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-11-06
@@ -8413,12 +8555,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-12-17');
 insert into t22 values ('2006-12-17');
 insert into t33 values ('2006-12-17');
 insert into t44 values (60,'2006-12-17');
 insert into t55 values (60,'2006-12-17');
 insert into t66 values (60,'2006-12-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-11-06
@@ -8543,6 +8687,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with quarter(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-01-03');
@@ -8551,6 +8696,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-12-17');
 insert into t3 values ('2006-09-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -8590,12 +8736,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-07-30' where col1='2006-01-03';
 update t2 set col1='2006-07-30' where col1='2006-01-03';
 update t3 set col1='2006-07-30' where col1='2006-01-03';
 update t4 set col1='2006-07-30' where col1='2006-01-03';
 update t5 set col1='2006-07-30' where col1='2006-01-03';
 update t6 set col1='2006-07-30' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-07-30
@@ -8799,12 +8947,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with quarter(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-12-17';
 delete from t2 where col1='2006-12-17';
 delete from t3 where col1='2006-12-17';
 delete from t4 where col1='2006-12-17';
 delete from t5 where col1='2006-12-17';
 delete from t6 where col1='2006-12-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-07-30
@@ -8828,12 +8978,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-12-17');
 insert into t2 values ('2006-12-17');
 insert into t3 values ('2006-12-17');
 insert into t4 values (60,'2006-12-17');
 insert into t5 values (60,'2006-12-17');
 insert into t6 values (60,'2006-12-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-07-30
@@ -8896,12 +9048,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with quarter(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-12-17';
 delete from t22 where col1='2006-12-17';
 delete from t33 where col1='2006-12-17';
 delete from t44 where col1='2006-12-17';
 delete from t55 where col1='2006-12-17';
 delete from t66 where col1='2006-12-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-07-30
@@ -8925,12 +9079,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-12-17');
 insert into t22 values ('2006-12-17');
 insert into t33 values ('2006-12-17');
 insert into t44 values (60,'2006-12-17');
 insert into t55 values (60,'2006-12-17');
 insert into t66 values (60,'2006-12-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-07-30
@@ -9054,6 +9210,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with time_to_sec(col1)-(time_to_sec(col1)-20) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('09:09:15');
 insert into t1 values ('14:30:45');
 insert into t2 values ('09:09:15');
@@ -9062,6 +9219,7 @@
 insert into t3 values ('09:09:15');
 insert into t3 values ('14:30:45');
 insert into t3 values ('21:59:22');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_time.inc' into table t6;
@@ -9101,12 +9259,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 update t1 set col1='10:33:11' where col1='09:09:15';
 update t2 set col1='10:33:11' where col1='09:09:15';
 update t3 set col1='10:33:11' where col1='09:09:15';
 update t4 set col1='10:33:11' where col1='09:09:15';
 update t5 set col1='10:33:11' where col1='09:09:15';
 update t6 set col1='10:33:11' where col1='09:09:15';
+commit;
 select * from t1 order by col1;
 col1
 10:33:11
@@ -9310,12 +9470,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with time_to_sec(col1)-(time_to_sec(col1)-20)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='14:30:45';
 delete from t2 where col1='14:30:45';
 delete from t3 where col1='14:30:45';
 delete from t4 where col1='14:30:45';
 delete from t5 where col1='14:30:45';
 delete from t6 where col1='14:30:45';
+commit;
 select * from t1 order by col1;
 col1
 10:33:11
@@ -9339,12 +9501,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t1 values ('14:30:45');
 insert into t2 values ('14:30:45');
 insert into t3 values ('14:30:45');
 insert into t4 values (60,'14:30:45');
 insert into t5 values (60,'14:30:45');
 insert into t6 values (60,'14:30:45');
+commit;
 select * from t1 order by col1;
 col1
 10:33:11
@@ -9410,12 +9574,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with time_to_sec(col1)-(time_to_sec(col1)-20)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='14:30:45';
 delete from t22 where col1='14:30:45';
 delete from t33 where col1='14:30:45';
 delete from t44 where col1='14:30:45';
 delete from t55 where col1='14:30:45';
 delete from t66 where col1='14:30:45';
+commit;
 select * from t11 order by col1;
 col1
 10:33:11
@@ -9439,12 +9605,14 @@
 2	04:30:01
 3	00:59:22
 4	05:30:34
+begin;
 insert into t11 values ('14:30:45');
 insert into t22 values ('14:30:45');
 insert into t33 values ('14:30:45');
 insert into t44 values (60,'14:30:45');
 insert into t55 values (60,'14:30:45');
 insert into t66 values (60,'14:30:45');
+commit;
 select * from t11 order by col1;
 col1
 10:33:11
@@ -9571,6 +9739,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with weekday(col1) 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-12-03');
 insert into t1 values ('2006-11-17');
 insert into t2 values ('2006-12-03');
@@ -9579,6 +9748,7 @@
 insert into t3 values ('2006-12-03');
 insert into t3 values ('2006-11-17');
 insert into t3 values ('2006-05-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -9618,12 +9788,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-02-06' where col1='2006-12-03';
 update t2 set col1='2006-02-06' where col1='2006-12-03';
 update t3 set col1='2006-02-06' where col1='2006-12-03';
 update t4 set col1='2006-02-06' where col1='2006-12-03';
 update t5 set col1='2006-02-06' where col1='2006-12-03';
 update t6 set col1='2006-02-06' where col1='2006-12-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-06
@@ -9827,12 +9999,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with weekday(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-11-17';
 delete from t2 where col1='2006-11-17';
 delete from t3 where col1='2006-11-17';
 delete from t4 where col1='2006-11-17';
 delete from t5 where col1='2006-11-17';
 delete from t6 where col1='2006-11-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-02-06
@@ -9856,12 +10030,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-11-17');
 insert into t2 values ('2006-11-17');
 insert into t3 values ('2006-11-17');
 insert into t4 values (60,'2006-11-17');
 insert into t5 values (60,'2006-11-17');
 insert into t6 values (60,'2006-11-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-02-06
@@ -9923,12 +10099,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with weekday(col1)
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-11-17';
 delete from t22 where col1='2006-11-17';
 delete from t33 where col1='2006-11-17';
 delete from t44 where col1='2006-11-17';
 delete from t55 where col1='2006-11-17';
 delete from t66 where col1='2006-11-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-02-06
@@ -9952,12 +10130,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-11-17');
 insert into t22 values ('2006-11-17');
 insert into t33 values ('2006-11-17');
 insert into t44 values (60,'2006-11-17');
 insert into t55 values (60,'2006-11-17');
 insert into t66 values (60,'2006-11-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-02-06
@@ -10080,6 +10260,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with year(col1)-1990 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('1996-01-03');
 insert into t1 values ('2000-02-17');
 insert into t2 values ('1996-01-03');
@@ -10088,6 +10269,7 @@
 insert into t3 values ('1996-01-03');
 insert into t3 values ('2000-02-17');
 insert into t3 values ('2004-05-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -10127,12 +10309,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2002-02-15' where col1='1996-01-03';
 update t2 set col1='2002-02-15' where col1='1996-01-03';
 update t3 set col1='2002-02-15' where col1='1996-01-03';
 update t4 set col1='2002-02-15' where col1='1996-01-03';
 update t5 set col1='2002-02-15' where col1='1996-01-03';
 update t6 set col1='2002-02-15' where col1='1996-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2000-02-17
@@ -10336,12 +10520,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with year(col1)-1990
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2000-02-17';
 delete from t2 where col1='2000-02-17';
 delete from t3 where col1='2000-02-17';
 delete from t4 where col1='2000-02-17';
 delete from t5 where col1='2000-02-17';
 delete from t6 where col1='2000-02-17';
+commit;
 select * from t1 order by col1;
 col1
 2002-02-15
@@ -10365,12 +10551,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2000-02-17');
 insert into t2 values ('2000-02-17');
 insert into t3 values ('2000-02-17');
 insert into t4 values (60,'2000-02-17');
 insert into t5 values (60,'2000-02-17');
 insert into t6 values (60,'2000-02-17');
+commit;
 select * from t1 order by col1;
 col1
 2000-02-17
@@ -10434,12 +10622,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with year(col1)-1990
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2000-02-17';
 delete from t22 where col1='2000-02-17';
 delete from t33 where col1='2000-02-17';
 delete from t44 where col1='2000-02-17';
 delete from t55 where col1='2000-02-17';
 delete from t66 where col1='2000-02-17';
+commit;
 select * from t11 order by col1;
 col1
 2002-02-15
@@ -10463,12 +10653,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2000-02-17');
 insert into t22 values ('2000-02-17');
 insert into t33 values ('2000-02-17');
 insert into t44 values (60,'2000-02-17');
 insert into t55 values (60,'2000-02-17');
 insert into t66 values (60,'2000-02-17');
+commit;
 select * from t11 order by col1;
 col1
 2000-02-17
@@ -10593,6 +10785,7 @@
 -------------------------------------------------------------------------
 ---  Access tables with yearweek(col1)-200600 
 -------------------------------------------------------------------------
+begin;
 insert into t1 values ('2006-01-03');
 insert into t1 values ('2006-08-17');
 insert into t2 values ('2006-01-03');
@@ -10601,6 +10794,7 @@
 insert into t3 values ('2006-01-03');
 insert into t3 values ('2006-08-17');
 insert into t3 values ('2006-03-25');
+commit;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t4;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t5;
 load data infile 'MYSQLTEST_VARDIR/std_data/parts/part_supported_sql_funcs_int_date.inc' into table t6;
@@ -10640,12 +10834,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 update t1 set col1='2006-11-15' where col1='2006-01-03';
 update t2 set col1='2006-11-15' where col1='2006-01-03';
 update t3 set col1='2006-11-15' where col1='2006-01-03';
 update t4 set col1='2006-11-15' where col1='2006-01-03';
 update t5 set col1='2006-11-15' where col1='2006-01-03';
 update t6 set col1='2006-11-15' where col1='2006-01-03';
+commit;
 select * from t1 order by col1;
 col1
 2006-08-17
@@ -10849,12 +11045,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with yearweek(col1)-200600
 -------------------------------------------------------------------------
+begin;
 delete from t1 where col1='2006-08-17';
 delete from t2 where col1='2006-08-17';
 delete from t3 where col1='2006-08-17';
 delete from t4 where col1='2006-08-17';
 delete from t5 where col1='2006-08-17';
 delete from t6 where col1='2006-08-17';
+commit;
 select * from t1 order by col1;
 col1
 2006-11-15
@@ -10878,12 +11076,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t1 values ('2006-08-17');
 insert into t2 values ('2006-08-17');
 insert into t3 values ('2006-08-17');
 insert into t4 values (60,'2006-08-17');
 insert into t5 values (60,'2006-08-17');
 insert into t6 values (60,'2006-08-17');
+commit;
 select * from t1 order by col1;
 col1
 2006-08-17
@@ -10950,12 +11150,14 @@
 -------------------------------------------------------------------------
 ---  Delete rows and partitions of tables with yearweek(col1)-200600
 -------------------------------------------------------------------------
+begin;
 delete from t11 where col1='2006-08-17';
 delete from t22 where col1='2006-08-17';
 delete from t33 where col1='2006-08-17';
 delete from t44 where col1='2006-08-17';
 delete from t55 where col1='2006-08-17';
 delete from t66 where col1='2006-08-17';
+commit;
 select * from t11 order by col1;
 col1
 2006-11-15
@@ -10979,12 +11181,14 @@
 2	2006-01-17
 3	2006-01-25
 4	2006-02-05
+begin;
 insert into t11 values ('2006-08-17');
 insert into t22 values ('2006-08-17');
 insert into t33 values ('2006-08-17');
 insert into t44 values (60,'2006-08-17');
 insert into t55 values (60,'2006-08-17');
 insert into t66 values (60,'2006-08-17');
+commit;
 select * from t11 order by col1;
 col1
 2006-08-17

=== modified file 'mysql-test/suite/parts/r/rpl_partition.result'
--- mysql-test/suite/parts/r/rpl_partition.result	2010-12-19 17:07:28 +0000
+++ mysql-test/suite/parts/r/rpl_partition.result	2011-04-29 09:52:28 +0000
@@ -96,13 +96,19 @@
 SET del_count = del_count - 2;
 END WHILE;
 END|
+begin;
 CALL p1();
+commit;
 SELECT count(*) as "Master regular" FROM t1;
 Master regular	500
+begin;
 CALL p2();
+commit;
 SELECT count(*) as "Master bykey" FROM t2;
 Master bykey	500
+begin;
 CALL p3();
+commit;
 SELECT count(*) as "Master byrange" FROM t3;
 Master byrange	500
 show create table t3;

=== modified file 'mysql-test/suite/parts/t/part_supported_sql_func_innodb.test'
--- mysql-test/suite/parts/t/part_supported_sql_func_innodb.test	2011-02-20 16:51:43 +0000
+++ mysql-test/suite/parts/t/part_supported_sql_func_innodb.test	2011-04-29 09:52:28 +0000
@@ -26,13 +26,11 @@
 let $do_long_tests= 1;
 
 #
+# This test takes long time, so only run it with the --big mtr-flag.
 --source include/big_test.inc
 # The server must support partitioning.
 --source include/have_partition.inc
 
-# This test takes long time, so only run it with the --big mtr-flag.
---source include/big_test.inc
-
 #------------------------------------------------------------------------------#
 # Engine specific settings and requirements
 

=== modified file 'mysql-test/suite/parts/t/rpl_partition.test'
--- mysql-test/suite/parts/t/rpl_partition.test	2011-02-20 16:51:43 +0000
+++ mysql-test/suite/parts/t/rpl_partition.test	2011-04-29 09:52:28 +0000
@@ -127,11 +127,17 @@
 
 ############ Test Section ###################
 
+begin;
 CALL p1();
+commit;
 SELECT count(*) as "Master regular" FROM t1;
+begin;
 CALL p2();
+commit;
 SELECT count(*) as "Master bykey" FROM t2;
+begin;
 CALL p3();
+commit;
 SELECT count(*) as "Master byrange" FROM t3;
 
 --sync_slave_with_master

=== modified file 'mysql-test/suite/rpl/r/rpl_innodb_bug28430.result'
--- mysql-test/suite/rpl/r/rpl_innodb_bug28430.result	2010-12-19 17:07:28 +0000
+++ mysql-test/suite/rpl/r/rpl_innodb_bug28430.result	2011-04-29 09:52:28 +0000
@@ -90,13 +90,19 @@
 SET del_count = del_count - 2;
 END WHILE;
 END|
+begin;
 CALL test.proc_norm();
+commit;
 SELECT count(*) as "Master regular" FROM test.regular_tbl;
 Master regular	500
+begin;
 CALL test.proc_bykey();
+commit;
 SELECT count(*) as "Master bykey" FROM test.bykey_tbl;
 Master bykey	500
+begin;
 CALL test.proc_byrange();
+commit;
 SELECT count(*) as "Master byrange" FROM test.byrange_tbl;
 Master byrange	500
 show create table test.byrange_tbl;

=== modified file 'mysql-test/suite/rpl/t/rpl_innodb_bug28430.test'
--- mysql-test/suite/rpl/t/rpl_innodb_bug28430.test	2011-02-20 16:51:43 +0000
+++ mysql-test/suite/rpl/t/rpl_innodb_bug28430.test	2011-04-29 09:52:28 +0000
@@ -127,11 +127,17 @@
 
 ############ Test Section ###################
 
+begin;
 CALL test.proc_norm();
+commit;
 SELECT count(*) as "Master regular" FROM test.regular_tbl;
+begin;
 CALL test.proc_bykey();
+commit;
 SELECT count(*) as "Master bykey" FROM test.bykey_tbl;
+begin;
 CALL test.proc_byrange();
+commit;
 SELECT count(*) as "Master byrange" FROM test.byrange_tbl;
 
 --sync_slave_with_master

=== modified file 'mysql-test/suite/vcol/r/vcol_supported_sql_funcs_innodb.result'
--- mysql-test/suite/vcol/r/vcol_supported_sql_funcs_innodb.result	2010-10-30 17:54:38 +0000
+++ mysql-test/suite/vcol/r/vcol_supported_sql_funcs_innodb.result	2011-04-29 09:52:28 +0000
@@ -2686,10 +2686,15 @@
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
 insert into t1 values (1,default);
 insert into t1 values (-1,default);
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select * from t1;
 a	b
 1	1
 -1	18446744073709551615
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 drop table t1;
 set sql_warnings = 0;
 # Convert()
@@ -2703,10 +2708,15 @@
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
 insert into t1 values (1,default);
 insert into t1 values (-1,default);
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select * from t1;
 a	b
 1	1
 -1	18446744073709551615
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 drop table t1;
 set sql_warnings = 0;
 #

=== modified file 'mysql-test/suite/vcol/r/vcol_supported_sql_funcs_myisam.result'
--- mysql-test/suite/vcol/r/vcol_supported_sql_funcs_myisam.result	2010-10-30 17:54:38 +0000
+++ mysql-test/suite/vcol/r/vcol_supported_sql_funcs_myisam.result	2011-04-29 09:52:28 +0000
@@ -2686,10 +2686,15 @@
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 insert into t1 values (1,default);
 insert into t1 values (-1,default);
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select * from t1;
 a	b
 1	1
 -1	18446744073709551615
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 drop table t1;
 set sql_warnings = 0;
 # Convert()
@@ -2703,10 +2708,15 @@
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 insert into t1 values (1,default);
 insert into t1 values (-1,default);
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 select * from t1;
 a	b
 1	1
 -1	18446744073709551615
+Warnings:
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
+Warning	1105	Cast to unsigned converted negative integer to it's positive complement
 drop table t1;
 set sql_warnings = 0;
 #

=== modified file 'mysql-test/t/cast.test'
--- mysql-test/t/cast.test	2009-05-21 08:06:43 +0000
+++ mysql-test/t/cast.test	2011-04-29 09:52:28 +0000
@@ -11,6 +11,21 @@
 explain extended select ~5, cast(~5 as signed);
 select cast(5 as unsigned) -6.0;
 select cast(NULL as signed), cast(1/0 as signed);
+select cast(1 as double(5,2));
+select cast("5.2222" as double(5,2));
+select cast(12.444 as double(5,2));
+select cast(cast(12.444 as decimal(10,3)) as double(5,2));
+select cast(null as double(5,2));
+select cast(12.444 as double);
+select cast(cast("20:01:01" as time) as datetime);
+select cast(cast("8:46:06.23434" AS time) as decimal(32,10));
+select cast(cast(20010203101112.121314 as double) as datetime);
+select cast(cast(010203101112.12 as double) as datetime);
+select cast(cast(20010203101112.121314 as decimal(32,6)) as datetime);
+select cast(20010203101112.121314 as datetime);
+select cast(110203101112.121314 as datetime);
+select cast(cast(010203101112.12 as double) as datetime);
+select cast(cast("2011-04-05 8:46:06.23434" AS datetime) as time);
 #
 # Bug #28250: Run-Time Check Failure #3 - The variable 'value' is being used 
 # without being def
@@ -42,6 +57,44 @@
 select 10+'a';
 select 10.0+cast('a' as decimal);
 select 10E+0+'a';
+select cast("a" as double(5,2));
+select cast(1000 as decimal(5,2));
+select cast(-1000 as decimal(5,2));
+select cast(1000 as double(5,2));
+select cast(-1000 as double(5,2));
+select cast(010203101112.121314 as datetime);
+select cast(120010203101112.121314 as datetime);
+select cast(cast(1.1 as decimal) as datetime);
+select cast(cast(-1.1 as decimal) as datetime);
+select cast('0' as date);
+select cast('' as date);
+select cast('0' as datetime);
+select cast('' as datetime);
+select cast('0' as time);
+select cast('' as time);
+select cast(NULL as DATE);
+select cast(NULL as DATETIME);
+select cast(NULL as TIME);
+select cast(NULL as BINARY);
+
+#
+# We have to disable warnings for these as the printed double value is
+# not portable
+#
+--disable_warnings
+select cast(cast(120010203101112.121314 as double) as datetime);
+select cast(cast(1.1 as double) as datetime);
+select cast(cast(-1.1 as double) as datetime);
+--enable_warnings
+
+
+#
+# Some EXPLAIN EXTENDED to ensure the print functions are correct
+#
+
+explain extended select cast(10 as double(5,2));
+explain extended select cast(10 as double);
+explain extended select cast(10 as decimal(5,2));
 
 # out-of-range cases
 select cast('18446744073709551616' as unsigned);
@@ -52,6 +105,20 @@
 select cast('1a' as signed);
 select cast('' as signed);
 
+--error ER_M_BIGGER_THAN_D
+select cast(1 as double(5,6));
+--error ER_M_BIGGER_THAN_D
+select cast(1 as decimal(5,6));
+--error ER_TOO_BIG_PRECISION
+select cast(1 as double(66,6));
+--error ER_TOO_BIG_PRECISION
+select cast(1 as decimal(66,6));
+--error ER_TOO_BIG_SCALE
+select cast(1 as decimal(64,63));
+--error ER_TOO_BIG_SCALE
+select cast(1 as double(64,63));
+
+
 #
 # Character set conversion
 #
@@ -124,8 +191,6 @@
 select cast("2001-1-1" as date) = "2001-01-01";
 select cast("2001-1-1" as datetime) = "2001-01-01 00:00:00";
 select cast("1:2:3" as TIME) = "1:02:03";
-select cast(NULL as DATE);
-select cast(NULL as BINARY);
 
 #
 # Bug #5228 ORDER BY CAST(enumcol) sorts incorrectly under certain conditions
@@ -172,6 +237,14 @@
 select cast(1.0e+300 as signed int);
 
 #
+# Test that we create the correct types with create ... select cast()
+#
+
+create table t1  select cast(1 as unsigned), cast(1 as signed), cast(1 as double(5,2)), cast(1 as decimal(5,3)), cast("A" as binary), cast("A" as char(100)), cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME), cast("1:2:3" as TIME);
+show create table t1;
+drop table t1;
+
+#
 # Bugs: #15098: CAST(column double TO signed int), wrong result
 #
 CREATE TABLE t1 (f1 double);

=== added file 'mysql-test/t/dyncol.test'
--- mysql-test/t/dyncol.test	1970-01-01 00:00:00 +0000
+++ mysql-test/t/dyncol.test	2011-04-29 11:02:53 +0000
@@ -0,0 +1,361 @@
+#
+# Dynamic column function test
+#
+
+--echo #
+--echo # column create
+--echo #
+select hex(COLUMN_CREATE(1, NULL AS char character set utf8));
+select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8));
+select hex(COLUMN_CREATE(1, 1212 AS char character set utf8));
+select hex(COLUMN_CREATE(1, 12.12 AS char character set utf8));
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS char character set utf8));
+select hex(COLUMN_CREATE(1, NULL AS unsigned int));
+select hex(COLUMN_CREATE(1, 1212 AS unsigned int));
+select hex(COLUMN_CREATE(1, 7 AS unsigned int));
+select hex(COLUMN_CREATE(1, 8 AS unsigned int));
+select hex(COLUMN_CREATE(1, 127 AS unsigned int));
+select hex(COLUMN_CREATE(1, 128 AS unsigned int));
+select hex(COLUMN_CREATE(1, 12.12 AS unsigned int));
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS unsigned int));
+select hex(COLUMN_CREATE(1, NULL AS int));
+select hex(COLUMN_CREATE(1, 1212 AS int));
+select hex(COLUMN_CREATE(1, 7 AS int));
+select hex(COLUMN_CREATE(1, 8 AS int));
+select hex(COLUMN_CREATE(1, 127 AS int));
+select hex(COLUMN_CREATE(1, 128 AS int));
+select hex(COLUMN_CREATE(1, 12.12 AS int));
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS int));
+select hex(COLUMN_CREATE(1, NULL AS double));
+select hex(COLUMN_CREATE(1, 1212 AS double));
+select hex(COLUMN_CREATE(1, 12.12 AS double));
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS double));
+select hex(COLUMN_CREATE(1, NULL AS decimal));
+select hex(COLUMN_CREATE(1, 1212 AS decimal));
+select hex(COLUMN_CREATE(1, 7 AS decimal));
+select hex(COLUMN_CREATE(1, 8 AS decimal));
+select hex(COLUMN_CREATE(1, 127 AS decimal));
+select hex(COLUMN_CREATE(1, 128 AS decimal));
+select hex(COLUMN_CREATE(1, 12.12 AS decimal));
+select hex(COLUMN_CREATE(1, 99999999999999999999999999999 AS decimal));
+select hex(COLUMN_CREATE(1, NULL AS date));
+select hex(COLUMN_CREATE(1, "2011-04-05" AS date)); 
+select hex(COLUMN_CREATE(1, NULL AS time));
+select hex(COLUMN_CREATE(1, "0:45:49.000001" AS time)); 
+select hex(COLUMN_CREATE(1, NULL AS datetime));
+select hex(COLUMN_CREATE(1, "2011-04-05 0:45:49.000001" AS datetime)); 
+select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
+			 2, 1212 AS unsigned int,
+			 3, 1212 AS int,
+			 4, 12.12 AS double,
+			 4+1, 12.12 AS decimal,
+			 6, "2011-04-05" AS date,
+			 7, "- 0:45:49.000001" AS time,
+			 8, "2011-04-05 0:45:49.000001" AS datetime));
+explain extended
+select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
+			 2, 1212 AS unsigned int,
+			 3, 1212 AS int,
+			 4, 12.12 AS double,
+			 4+1, 12.12 AS decimal,
+			 6, "2011-04-05" AS date,
+			 7, "- 0:45:49.000001" AS time,
+			 8, "2011-04-05 0:45:49.000001" AS datetime));
+
+
+--echo #
+--echo # column get uint
+--echo #
+select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int);
+explain extended
+select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned int);
+explain extended
+select column_get(column_create(1, 1212 AS unsigned int), 1 as unsigned);
+select column_get(column_create(1, 1212 AS decimal), 1 as unsigned int);
+select column_get(column_create(1, 1212 AS double), 1 as unsigned int);
+select column_get(column_create(1, 1212 AS int), 1 as unsigned int);
+select column_get(column_create(1, "1212" AS char), 1 as unsigned int);
+select column_get(column_create(1, "2011-04-05" AS date), 1 as unsigned int);
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as unsigned int);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as unsigned int);
+select column_get(column_create(1, NULL AS unsigned int), 1 as unsigned int);
+--echo # column geint truncation & warnings
+select column_get(column_create(1, -1212 AS int), 1 as unsigned int);
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as unsigned int);
+select column_get(column_create(1, 999.9999999999999999 AS decimal), 1 as unsigned int);
+select column_get(column_create(1, -1 AS decimal), 1 as unsigned int);
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as unsigned int);
+select column_get(column_create(1, 999.9 AS double), 1 as unsigned int);
+select column_get(column_create(1, -1 AS double), 1 as unsigned int);
+select column_get(column_create(1, "1212III" AS char), 1 as unsigned int);
+
+--echo #
+--echo # column get int
+--echo #
+select column_get(column_create(1, 1212 AS int), 1 as int);
+explain extended
+select column_get(column_create(1, 1212 AS int), 1 as int);
+explain extended
+select column_get(column_create(1, 1212 AS int), 1 as signed int);
+select column_get(column_create(1, -1212 AS int), 1 as int);
+select column_get(column_create(1, 1212 AS decimal), 1 as int);
+select column_get(column_create(1, 1212 AS double), 1 as int);
+select column_get(column_create(1, 1212 AS unsigned int), 1 as int);
+select column_get(column_create(1, "1212" AS char), 1 as int);
+select column_get(column_create(1, "-1212" AS char), 1 as int);
+select column_get(column_create(1, "2011-04-05" AS date), 1 as int);
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as int);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as int);
+select column_get(column_create(1, NULL AS int), 1 as int);
+--echo #column gett truncation & warnings
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as int);
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as int);
+select column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as int);
+select column_get(column_create(1, 999.9999999999999999 AS decimal), 1 as int);
+select column_get(column_create(1, 999.9 AS double), 1 as int);
+select column_get(column_create(1, -99999999999999999999999999999 AS double), 1 as int);
+select column_get(column_create(1, "-1212III" AS char), 1 as int);
+select column_get(column_create(1, "1212III" AS char), 1 as int);
+
+--echo #
+--echo #column get char
+--echo #
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8);
+explain extended
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset utf8);
+select column_get(column_create(1, 1212 AS unsigned int), 1 as char charset utf8);
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as char charset utf8);
+select column_get(column_create(1, 1212 AS int), 1 as char charset utf8);
+select column_get(column_create(1, -1212 AS int), 1 as char charset utf8);
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as char charset utf8);
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as char charset utf8);
+select column_get(column_create(1, 1212.12 AS decimal), 1 as char charset utf8);
+select column_get(column_create(1, 1212.12 AS double), 1 as char charset utf8);
+select column_get(column_create(1, "2011-04-05" AS date), 1 as char charset utf8);
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as char charset utf8);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as char charset utf8);
+select column_get(column_create(1, NULL AS char charset utf8), 1 as char charset utf8);
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary);
+explain extended
+select column_get(column_create(1, "1212" AS char charset utf8), 1 as char charset binary);
+
+--echo #
+--echo # column get real
+--echo #
+select column_get(column_create(1, 1212.12 AS double), 1 as double);
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as double);
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as double(6,2));
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as double);
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as double);
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as double); 
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal), 1 as double);
+select column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as double);
+select column_get(column_create(1, "2011-04-05" AS date), 1 as double);
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as double);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as double);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as double(20,6));
+select column_get(column_create(1, NULL AS double), 1 as double);
+
+-- echo # column get real truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as double);
+select column_get(column_create(1, "aa" AS char), 1 as double);
+select column_get(column_create(1, "1223.5555" AS double), 1 as double(5,2));
+select column_get(column_create(1, "1223.5555" AS double), 1 as double(3,2));
+
+--echo #
+--echo # column get decimal
+--echo #
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal);
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2));
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal);
+explain extended
+select column_get(column_create(1, 1212.12 AS double), 1 as decimal(6,2));
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal(20,0));
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal(32,0));
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal(32,0)); 
+select column_get(column_create(1, -99999999999999999999999999999 AS decimal), 1 as decimal(40,10));
+select column_get(column_create(1, "2011-04-05" AS date), 1 as decimal(32,6));
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as decimal(32,6));
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal(32,6));
+select column_get(column_create(1, NULL as decimal), 1 as decimal(32,10));
+select column_get(column_create(1, "1223.5555" as decimal(10,5)), 1 as decimal(6,2));
+
+-- echo # column get decimal truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as decimal(32,10));
+select column_get(column_create(1, "aa" AS char), 1 as decimal(32,10));
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as decimal);
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as decimal);
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as decimal); 
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as decimal);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as decimal);
+select column_get(column_create(1, "1223.5555" as double), 1 as decimal(5,2));
+select column_get(column_create(1, "-1223.5555" as double), 1 as decimal(5,2));
+select column_get(column_create(1, "1223.5555" AS double), 1 as decimal(3,2));
+select column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2));
+
+--echo #
+--echo # column get datetime
+--echo #
+select column_get(column_create(1, 20010203101112.121314 as double), 1 as datetime);
+select column_get(column_create(1, 20010203101112.121314 as decimal), 1 as datetime);
+select column_get(column_create(1, 20010203101112 as unsigned int), 1 as datetime);
+select column_get(column_create(1, 20010203101112 as int), 1 as datetime);
+select column_get(column_create(1, "20010203101112" as char), 1 as datetime);
+select column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as datetime);
+select column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as datetime);
+select column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as datetime);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as datetime);
+select column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as datetime);
+select column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as datetime);
+
+select column_get(column_create(1, 20010203 as unsigned int), 1 as datetime);
+select column_get(column_create(1, 20010203 as int), 1 as datetime);
+select column_get(column_create(1, 20010203), 1 as datetime);
+select column_get(column_create(1, 20010203.0), 1 as datetime);
+select column_get(column_create(1, 20010203.0 as double), 1 as datetime);
+select column_get(column_create(1, "2001-02-03"), 1 as datetime);
+select column_get(column_create(1, "20010203"), 1 as datetime);
+select column_get(column_create(1, 0), 1 as datetime);
+select column_get(column_create(1, "2001021"), 1 as datetime);
+
+select column_get(column_create(1, "8:46:06.23434" AS time), 1 as datetime);
+
+set @@sql_mode="allow_invalid_dates";
+select column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as datetime);
+select column_get(column_create(1, "0000-00-000" AS CHAR), 1 as datetime);
+select column_get(column_create(1, "2001-00-02" AS CHAR), 1 as datetime);
+set @@sql_mode="";
+
+-- echo # column get datetime truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as datetime);
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as datetime);
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as datetime);
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as datetime); 
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as datetime);
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as datetime);
+select column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as datetime);
+select column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as datetime);
+select column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as datetime);
+select column_get(column_create(1, "20010231"), 1 as datetime);
+select column_get(column_create(1, "0" AS CHAR), 1 as datetime);
+
+
+--echo #
+--echo # column get date
+--echo #
+select column_get(column_create(1, 20010203101112.121314 as double), 1 as date);
+select column_get(column_create(1, 20010203101112.121314 as decimal), 1 as date);
+select column_get(column_create(1, 20010203101112 as unsigned int), 1 as date);
+select column_get(column_create(1, 20010203101112 as int), 1 as date);
+select column_get(column_create(1, "20010203101112" as char), 1 as date);
+select column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as date);
+select column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as date);
+select column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as date);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as date);
+select column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as date);
+select column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as date);
+
+select column_get(column_create(1, 20010203 as unsigned int), 1 as date);
+select column_get(column_create(1, 20010203 as int), 1 as date);
+select column_get(column_create(1, 20010203), 1 as date);
+select column_get(column_create(1, 20010203.0), 1 as date);
+select column_get(column_create(1, 20010203.0 as double), 1 as date);
+select column_get(column_create(1, "2001-02-03"), 1 as date);
+select column_get(column_create(1, "20010203"), 1 as date);
+select column_get(column_create(1, 0), 1 as date);
+select column_get(column_create(1, "2001021"), 1 as date);
+
+set @@sql_mode="allow_invalid_dates";
+select column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as date);
+select column_get(column_create(1, "0000-00-000" AS CHAR), 1 as date);
+select column_get(column_create(1, "2001-00-02" AS CHAR), 1 as date);
+set @@sql_mode="";
+
+-- echo # column get date truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as date);
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as date);
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as date);
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as date); 
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as date);
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as date);
+select column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as date);
+select column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as date);
+select column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as date);
+select column_get(column_create(1, "20010231"), 1 as date);
+select column_get(column_create(1, "0" AS CHAR), 1 as date);
+
+--echo #
+--echo # column get time
+--echo #
+select column_get(column_create(1, 20010203101112.121314 as double), 1 as time);
+select column_get(column_create(1, 20010203101112.121314 as decimal), 1 as time);
+select column_get(column_create(1, 20010203101112 as unsigned int), 1 as time);
+select column_get(column_create(1, 20010203101112 as int), 1 as time);
+select column_get(column_create(1, "20010203101112" as char), 1 as time);
+select column_get(column_create(1, "2001-02-03 10:11:12" as char), 1 as time);
+select column_get(column_create(1, "2001-02-03 10:11:12.121314" as char), 1 as time);
+select column_get(column_create(1, "2001-02-03 10:11:12.121314"), 1 as time);
+select column_get(column_create(1, "2011-04-05 8:46:06.23434" AS datetime), 1 as time);
+select column_get(column_create(1, "2011-00-00 8:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "2011-00-01 8:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "830:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "-830:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "0" AS CHAR), 1 as time);
+select column_get(column_create(1, "6" AS CHAR), 1 as time);
+select column_get(column_create(1, "1:6" AS CHAR), 1 as time);
+select column_get(column_create(1, "2:1:6" AS CHAR), 1 as time);
+
+select column_get(column_create(1, 0), 1 as time);
+select column_get(column_create(1, "2001021"), 1 as time);
+
+set @@sql_mode="allow_invalid_dates";
+select column_get(column_create(1, "2011-02-30 18:46:06.23434" AS CHAR), 1 as time);
+set @@sql_mode="";
+
+-- echo # column get date truncation & warnings
+select column_get(column_create(1, "1223.5aa" AS char), 1 as time);
+select column_get(column_create(1, 18446744073709551615 AS unsigned int), 1 as time);
+select column_get(column_create(1, 9223372036854775807 AS int), 1 as time);
+select column_get(column_create(1, -9223372036854775808 AS int), 1 as time); 
+select column_get(column_create(1, 99999999999999999999999999999 AS decimal(32,10)), 1 as time);
+select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as time);
+select column_get(column_create(1, "2011-02-32 8:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "2011-13-01 8:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "2011-02-30 8:46:06.23434" AS CHAR), 1 as time);
+select column_get(column_create(1, "2001-02-03"), 1 as time);
+select column_get(column_create(1, "20010203"), 1 as time);
+
+
+-- echo # column add
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer));
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer));
+select hex(column_add(column_create(1, 1212 as integer), 1, NULL as integer));
+select hex(column_add(column_create(1, 1212 as integer), 2, NULL as integer));
+select hex(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer));
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 1 as integer);
+select column_get(column_add(column_create(1, 1212 as integer), 2, 1212 as integer, 1, 11 as integer), 2 as integer);
+select hex(column_add(column_create(1, 1212 as integer), 1, 1212 as integer, 2, 11 as integer));
+select hex(column_add(column_create(1, NULL as integer), 1, 1212 as integer, 2, 11 as integer));
+select hex(column_add(column_create(1, 1212 as integer, 2, 1212 as integer), 1, 11 as integer));
+
+-- echo # column delete
+select hex(column_delete(column_create(1, 1212 as integer, 2, 1212 as integer), 1));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 3));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 4));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 1));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 2, 3));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3));
+select hex(column_delete(column_create(1, 1 as integer, 2, 2 as integer, 3, 3 as integer), 1, 2, 3, 10));
+
+-- echo # column exists
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 1);
+select column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4);
+
+-- echo # column list
+select column_list(column_create(1, 1212 as integer, 2, 1212 as integer));
+select column_list(column_create(1, 1212 as integer));
+select column_list(column_create(1, NULL as integer));

=== modified file 'mysql-test/t/strict.test'
--- mysql-test/t/strict.test	2009-06-11 16:21:32 +0000
+++ mysql-test/t/strict.test	2011-04-29 09:52:28 +0000
@@ -367,6 +367,8 @@
 INSERT INTO t1 (col1) VALUES(CONVERT('2004-10-0' , DATE));
 --error 1292
 INSERT INTO t1 (col1) VALUES(CONVERT('2004-0-10' , DATE));
+--error 1292
+INSERT INTO t1 (col1) VALUES('2004-0-10');
 
 # deactivated because of Bug#8294
 # Bug#8294 Traditional: Misleading error message for invalid CAST to DATE

=== modified file 'mysys/Makefile.am'
--- mysys/Makefile.am	2011-02-28 17:39:30 +0000
+++ mysys/Makefile.am	2011-04-29 09:52:28 +0000
@@ -27,7 +27,7 @@
 			mf_path.c mf_loadpath.c my_file.c \
 			my_open.c my_create.c my_dup.c my_seek.c my_read.c \
 			my_pread.c my_write.c my_getpagesize.c \
-			my_crc32.c \
+			my_crc32.c ma_dyncol.c \
 			mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
 			mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
 			my_malloc.c my_realloc.c my_once.c mulalloc.c \

=== added file 'mysys/ma_dyncol.c'
--- mysys/ma_dyncol.c	1970-01-01 00:00:00 +0000
+++ mysys/ma_dyncol.c	2011-04-29 09:52:28 +0000
@@ -0,0 +1,1831 @@
+#include <ma_dyncol.h>
+
+/*
+  Flag byte bits
+
+  2 bits which determinate size of offset in the header -1
+*/
+/* mask to get above bits */
+#define DYNCOL_FLG_OFFSET  3
+/* All known flags mask */
+#define DYNCOL_FLG_KNOWN  3
+
+/* dynamic column size reserve */
+#define DYNCOL_SYZERESERVE 80
+
+/* length of fixed string header 1 byte - flags, 2 bytes - columns counter */
+#define FIXED_HEADER_SIZE 3
+
+#define COLUMN_NUMBER_SIZE 2
+
+
+static int dynamic_column_time_add(DYNAMIC_COLUMN *str,
+                                   MYSQL_TIME *value);
+static int dynamic_column_date_add(DYNAMIC_COLUMN *str,
+                                   MYSQL_TIME *value);
+static int
+dynamic_column_time_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data, size_t length);
+static int
+dynamic_column_date_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data, size_t length);
+
+/**
+  Initialize dynamic column string with (make it empty but correct format)
+
+  @param str             The string to initialize
+  @param size            Amount of preallocated memory for the string
+
+  @retval FALSE OK
+  @retval TRUE  error
+*/
+
+my_bool dynamic_column_init_str(DYNAMIC_COLUMN *str, size_t size)
+{
+  if (!size)
+    size= DYNCOL_SYZERESERVE;
+  /*
+    Make string with no fields (empty header)
+    - First \0 is flags
+    - other four \0 is 0 fileds counter
+  */
+  if (init_dynamic_string(str, NULL,
+                              size + FIXED_HEADER_SIZE, DYNCOL_SYZERESERVE))
+    return TRUE;
+  bzero(str->str, FIXED_HEADER_SIZE);
+  str->length= FIXED_HEADER_SIZE;
+  return FALSE;
+}
+
+
+/**
+  Calculate how many bytes needed to store val as variable length integer
+  where fist bit indicate continuation of the sequence.
+
+  @param val             The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+static size_t dynamic_column_var_uint_bytes(ulonglong val)
+{
+  size_t len= 0;
+  do
+  {
+    len++;
+    val>>= 7;
+  } while (val);
+  return len;
+}
+
+
+/**
+  Add variable value int to the string.
+
+  @param str             The string where to put the value
+  @param val             The value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_var_uint_add(DYNAMIC_COLUMN *str, ulonglong val)
+{
+  if (dynstr_realloc(str, 10)) // max what we can use
+    return ER_DYNCOL_RESOURCE;
+
+  do
+  {
+    ulonglong rest= val >> 7;
+    str->str[str->length++]= ((val & 0x7f) | (rest ? 0x80 : 0x00));
+    val= rest;
+  } while (val);
+  return ER_DYNCOL_OK;
+}
+
+/**
+  Reads variable length unsigned int value from the string
+
+  @param data            The string which should be read
+  @param len             Where to put length of the string read in bytes
+
+  @return value of the unsigned integer read from the string
+*/
+
+ulonglong dynamic_column_var_uint_get(uchar *data, size_t *len)
+{
+  ulonglong val= 0;
+  *len= 0;
+  for(;;)
+  {
+    val+= (((ulonglong)(data[len[0]] & 0x7f)) << (len[0]*7));
+    if (!(data[len[0]] & 0x80))
+      break;
+    len[0]++;
+  }
+  len[0]++;
+  return val;
+}
+
+/**
+  Calculate how many bytes needed to store val as unsigned.
+
+  @param val             The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_uint_bytes(ulonglong val)
+{
+  size_t len= 0;
+  do
+  {
+    len++;
+    val>>= 8;
+  } while (val);
+  return len;
+}
+
+
+/**
+  Append the string with given unsigned int value.
+
+  @param str             The string where to put the value
+  @param val             The value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_uint_add(DYNAMIC_COLUMN *str, ulonglong val)
+{
+  if (dynstr_realloc(str, 8)) // max what we can use
+    return ER_DYNCOL_RESOURCE;
+  do
+  {
+    str->str[str->length++]= val & 0xff;
+    val>>= 8;
+  } while (val);
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read unsigned int value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_uint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data,
+                             size_t length)
+{
+  ulonglong value= 0;
+  size_t i;
+  for (i= 0; i < length; i++)
+  {
+    value+= ((ulonglong)data[i]) << (i*8);
+  }
+  store_it_here->ulong_value= value;
+  return ER_DYNCOL_OK;
+}
+
+/**
+  Calculate how many bytes needed to store val as signed in following encoding:
+    0 -> 0
+   -1 -> 1
+    1 -> 2
+   -2 -> 3
+    2 -> 4
+   ...
+
+  @param val             The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_sint_bytes(longlong val)
+{
+  return dynamic_column_uint_bytes((val << 1) ^
+                                   (val < 0 ? ULL(0xffffffffffffffff) : 0));
+}
+
+
+/**
+  Append the string with given signed int value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_sint_add(DYNAMIC_COLUMN *str, longlong val)
+{
+  return dynamic_column_uint_add(str,
+                                 (val << 1) ^
+                                 (val < 0 ? ULL(0xffffffffffffffff) : 0));
+}
+
+
+/**
+  Read signed int value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_sint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data,
+                             size_t length)
+{
+  ulonglong val;
+  dynamic_column_uint_read(store_it_here, data, length);
+  val= store_it_here->ulong_value;
+  if (val & 1)
+    val= (val >> 1) ^ ULL(0xffffffffffffffff);
+  else
+    val>>= 1;
+  store_it_here->long_value= (longlong)(val);
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Calculate how many bytes needed to store the value.
+
+  @param value          The value for which we are calculating length
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_value_len(DYNAMIC_COLUMN_VALUE *value)
+{
+  switch (value->type) {
+  case DYN_COL_NULL:
+    return 0;
+  case DYN_COL_INT:
+    return dynamic_column_sint_bytes(value->long_value);
+  case DYN_COL_UINT:
+    return dynamic_column_uint_bytes(value->ulong_value);
+  case DYN_COL_DOUBLE:
+    return 8;
+  case DYN_COL_STRING:
+    return (dynamic_column_var_uint_bytes(value->charset->number) +
+            value->string_value.length);
+  case DYN_COL_DECIMAL:
+    return (dynamic_column_var_uint_bytes(value->decimal_value.intg) +
+            dynamic_column_var_uint_bytes(value->decimal_value.frac) +
+            decimal_bin_size(value->decimal_value.intg +
+                             value->decimal_value.frac,
+                             value->decimal_value.frac));
+  case DYN_COL_DATETIME:
+    /* date+time in bits: 14 + 4 + 5 + 10 + 6 + 6 + 20 + 1 66bits ~= 9 bytes */
+    return 9;
+  case DYN_COL_DATE:
+    /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
+    return 3;
+  case DYN_COL_TIME:
+    /* time in bits: 10 + 6 + 6 + 20 + 1 = 43bits ~= 6bytes*/
+    return 6;
+  default:
+    DBUG_ASSERT(0);
+    return 0;
+  }
+}
+
+
+/**
+  Append the string with given double value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_double_add(DYNAMIC_COLUMN *str, double val)
+{
+   if (dynstr_realloc(str, 8))
+     return ER_DYNCOL_RESOURCE;
+   float8store(str->str + str->length, val);
+   str->length+= 8;
+   return ER_DYNCOL_OK;
+}
+
+/**
+  Read double value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_double_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                               uchar *data,
+                               size_t length)
+{
+  if (length != 8)
+    return ER_DYNCOL_FORMAT;
+  float8get(store_it_here->double_value, data);
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Append the string with given string value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_string_add(DYNAMIC_COLUMN *str, LEX_STRING *string,
+                              CHARSET_INFO *charset)
+{
+  int rc;
+  if ((rc= dynamic_column_var_uint_add(str, charset->number)))
+    return rc;
+  if (dynstr_append_mem(str, string->str, string->length))
+    return ER_DYNCOL_RESOURCE;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read string value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_string_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                               uchar *data,
+                               size_t length)
+{
+  size_t len;
+  store_it_here->charset= get_charset(dynamic_column_var_uint_get(data, &len),
+                                      MYF(0));
+  if (store_it_here->charset == NULL || len > length)
+    return ER_DYNCOL_FORMAT;
+  data+= len;
+  store_it_here->string_value.length= (length-= len);
+  store_it_here->string_value.str= (char*)data;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Append the string with given decimal value.
+
+  @param str             the string where to put the value
+  @param val             the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_decimal_add(DYNAMIC_COLUMN *str,
+                               decimal_t *value)
+{
+  int rc;
+  uint bin_size= decimal_bin_size(value->intg + value->frac, value->frac);
+  if ((rc= dynamic_column_var_uint_add(str, value->intg)) ||
+      (rc= dynamic_column_var_uint_add(str, value->frac)))
+    return rc;
+  if (dynstr_realloc(str, bin_size))
+    return ER_DYNCOL_RESOURCE;
+  decimal2bin(value, (uchar *)str->str + str->length, value->intg + value->frac,
+              value->frac);
+  str->length+= bin_size;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Prepare the value to be used as decimal.
+
+  @param value           The value structure which sould be setup.
+*/
+
+void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
+{
+  value->decimal_value.buf= value->decimal_buffer;
+  value->decimal_value.len= DECIMAL_BUFF_LENGTH;
+  // just to be safe
+  value->type= DYN_COL_DECIMAL;
+  decimal_make_zero(&value->decimal_value);
+}
+
+
+/**
+  Read decimal value of given length from the string
+
+  @param store_it_here   The structure to store the value
+  @param data            The string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_decimal_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                uchar *data,
+                                size_t length __attribute__((unused)))
+{
+  size_t len;
+  uint intg, frac;
+
+  dynamic_column_prepare_decimal(store_it_here);
+  intg= dynamic_column_var_uint_get(data, &len);
+  data+= len;
+  frac= dynamic_column_var_uint_get(data, &len);
+  data+= len;
+  if (bin2decimal(data, &store_it_here->decimal_value, intg + frac, frac) !=
+      E_DEC_OK)
+    return ER_DYNCOL_FORMAT;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Append the string with given datetime value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_time_add(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+  int rc;
+  /*
+    0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
+     12345678901234123412345     1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456><123456><123456><123456>
+  */
+  if ((rc= dynamic_column_date_add(str, value)) ||
+      (rc= dynamic_column_time_add(str, value)))
+    return rc;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read datetime value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                  uchar *data,
+                                  size_t length)
+{
+  uint rc= ER_DYNCOL_FORMAT;
+  /*
+    0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
+     12345678901234123412345     1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456><123456><123456><123456>
+  */
+  if (length != 9)
+    goto err;
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+  if ((rc= dynamic_column_date_read_int(store_it_here, data, 3)) ||
+      (rc= dynamic_column_time_read_int(store_it_here, data + 3, 6)))
+    goto err;
+  return ER_DYNCOL_OK;
+
+err:
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+  return rc;
+}
+
+
+/**
+  Append the string with given time value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_time_add(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+  uchar *buf= ((uchar *)str->str) + str->length;
+  if (dynstr_realloc(str, 6))
+    return ER_DYNCOL_RESOURCE;
+  if (value->time_type == MYSQL_TIMESTAMP_NONE ||
+      value->time_type == MYSQL_TIMESTAMP_ERROR ||
+      value->time_type == MYSQL_TIMESTAMP_DATE)
+    value->neg= value->second_part= value->hour=
+      value->minute= value->second= 0;
+  DBUG_ASSERT(value->hour <= 838);
+  DBUG_ASSERT(value->minute <= 59);
+  DBUG_ASSERT(value->second <= 59);
+  DBUG_ASSERT(value->second_part <= 999999);
+  /*
+    00000!<-hours--><min-><sec-><---microseconds--->
+         1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456>
+  */
+  buf[0]= (value->second_part & 0xff);
+  buf[1]= ((value->second_part & 0xff00) >> 8);
+  buf[2]= (((value->second & 0xf) << 4) |
+           ((value->second_part & 0xf0000) >> 16));
+  buf[3]= ((value->minute << 2) | ((value->second & 0x30) >> 4));
+  buf[4]= (value->hour & 0xff);
+  buf[5]= ((value->neg ? 0x4 : 0) | (value->hour >> 8));
+  str->length+= 6;
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Read time value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                             uchar *data,
+                             size_t length)
+{
+  store_it_here->time_value.year= store_it_here->time_value.month=
+    store_it_here->time_value.day= 0;
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_TIME;
+  return dynamic_column_time_read_int(store_it_here, data, length);
+}
+
+/**
+  Internal function for reading time part from the string.
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_time_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                 uchar *data,
+                                 size_t length)
+{
+  if (length != 6)
+    goto err;
+  /*
+    00000!<-hours--><min-><sec-><---microseconds--->
+         1123456789012345612345612345678901234567890
+    <123456><123456><123456><123456><123456><123456>
+  */
+  store_it_here->time_value.second_part= (data[0] |
+                                          (data[1] << 8) |
+                                          ((data[2] & 0xf) << 16));
+  store_it_here->time_value.second= ((data[2] >> 4) |
+                                     ((data[3] & 0x3) << 4));
+  store_it_here->time_value.minute= (data[3] >> 2);
+  store_it_here->time_value.hour= (((((uint)data[5]) & 0x3 ) << 8) | data[4]);
+  store_it_here->time_value.neg= ((data[5] & 0x4) ? 1 : 0);
+  if (store_it_here->time_value.second > 59 ||
+      store_it_here->time_value.minute > 59 ||
+      store_it_here->time_value.hour > 838 ||
+      store_it_here->time_value.second_part > 999999)
+    goto err;
+  return ER_DYNCOL_OK;
+
+err:
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+  return ER_DYNCOL_FORMAT;
+}
+
+
+/**
+  Append the string with given date value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_add(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
+{
+  uchar *buf= ((uchar *)str->str) + str->length;
+  if (dynstr_realloc(str, 3))
+    return ER_DYNCOL_RESOURCE;
+  if (value->time_type == MYSQL_TIMESTAMP_NONE ||
+      value->time_type == MYSQL_TIMESTAMP_ERROR ||
+      value->time_type == MYSQL_TIMESTAMP_TIME)
+    value->year= value->month= value->day = 0;
+  DBUG_ASSERT(value->year <= 9999);
+  DBUG_ASSERT(value->month <= 12);
+  DBUG_ASSERT(value->day <= 31);
+  /*
+    0<----year----><mn><day>
+    012345678901234123412345
+    <123456><123456><123456>
+  */
+  buf[0]= (value->day |
+           ((value->month & 0x7) << 5));
+  buf[1]= ((value->month >> 3) | ((value->year & 0x7F) << 1));
+  buf[2]= (value->year >> 7);
+  str->length+= 3;
+  return ER_DYNCOL_OK;
+}
+
+
+
+/**
+  Read date value of given length from the packed string
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+my_bool dynamic_column_date_read(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                 uchar *data,
+                                 size_t length)
+{
+  store_it_here->time_value.neg= store_it_here->time_value.second_part=
+    store_it_here->time_value.hour= store_it_here->time_value.minute=
+    store_it_here->time_value.second= 0;
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_DATE;
+  return dynamic_column_date_read_int(store_it_here, data, length);
+}
+
+/**
+  Internal function for reading date part from the string.
+
+  @param store_it_here   The structure to store the value
+  @param data            The packed string which should be read
+  @param length          The length (in bytes) of the value in nthe string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_date_read_int(DYNAMIC_COLUMN_VALUE *store_it_here,
+                                 uchar *data,
+                                 size_t length)
+{
+  if (length != 3)
+    goto err;
+  /*
+    0<----year----><mn><day>
+     12345678901234123412345
+    <123456><123456><123456>
+  */
+  store_it_here->time_value.day= (data[0] & 0x1f);
+  store_it_here->time_value.month= (((data[1] & 0x1) << 3) |
+                                    (data[0] >> 5));
+  store_it_here->time_value.year= ((((uint)data[2]) << 7) |
+                                    (data[1] >> 1));
+  if (store_it_here->time_value.day > 31 ||
+      store_it_here->time_value.month > 12 ||
+      store_it_here->time_value.year > 9999)
+    goto err;
+  return ER_DYNCOL_OK;
+
+err:
+  store_it_here->time_value.time_type= MYSQL_TIMESTAMP_ERROR;
+  return ER_DYNCOL_FORMAT;
+}
+
+
+/**
+  Append the string with given value.
+
+  @param str             the string where to put the value
+  @param value           the value to put in the string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int data_add(DYNAMIC_COLUMN *str, DYNAMIC_COLUMN_VALUE *value)
+{
+  switch (value->type) {
+  case DYN_COL_INT:
+    return dynamic_column_sint_add(str, value->long_value);
+  case DYN_COL_UINT:
+    return dynamic_column_uint_add(str, value->ulong_value);
+  case DYN_COL_DOUBLE:
+    return dynamic_column_double_add(str, value->double_value);
+  case DYN_COL_STRING:
+    return dynamic_column_string_add(str, &value->string_value,
+                                     value->charset);
+  case DYN_COL_DECIMAL:
+    return dynamic_column_decimal_add(str, &value->decimal_value);
+  case DYN_COL_DATETIME:
+    /* date+time in bits: 14 + 4 + 5 + 5 + 6 + 6 40bits = 5 bytes */
+    return dynamic_column_date_time_add(str, &value->time_value);
+  case DYN_COL_DATE:
+    /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
+    return dynamic_column_date_add(str, &value->time_value);
+  case DYN_COL_TIME:
+    /* time in bits: 5 + 6 + 6 = 17bits ~= 3bytes*/
+    return dynamic_column_time_add(str, &value->time_value);
+  default:
+    DBUG_ASSERT(0);
+    return ER_DYNCOL_DATA;
+  }
+}
+
+
+/**
+  Calculate length of offset field for given data length
+
+  @param data_length     Length of the data segment
+
+  @return number of bytes
+*/
+
+size_t dynamic_column_offset_bytes(size_t data_length)
+{
+  if (data_length < 0x1f)  // all 1 value is reserved
+    return 1;
+  if (data_length < 0x1fff)  // all 1 value is reserved
+    return 2;
+  if (data_length < 0x1fffff)  // all 1 value is reserved
+    return 3;
+  if (data_length < 0x1fffffff)  // all 1 value is reserved
+    return 4;
+  return 5;
+}
+
+/**
+  Store offset and type information in the given place
+
+  @param place           Beginning of the index entry
+  @param offset_size     Size of offset field in bytes
+  @param type            Type to be written
+  @param offset          Offset to be written
+*/
+
+void type_and_offset_store(uchar *place, size_t offset_size,
+                          DYNAMIC_COLUMN_TYPE type,
+                          size_t offset)
+{
+  ulong val = (((ulong) offset) << 3) | (type - 1);;
+  place+= COLUMN_NUMBER_SIZE;
+  DBUG_ASSERT(type != DYN_COL_NULL);
+  DBUG_ASSERT(((type - 1) & (~7)) == 0); // fit in 3 bits
+  switch (offset_size) {
+  case 1:
+    DBUG_ASSERT(offset < 0x1f); // all 1 value is reserved
+    place[0]= (uchar)val;
+    break;
+  case 2:
+    DBUG_ASSERT(offset < 0x1fff); // all 1 value is reserved
+    int2store(place, val);
+    break;
+  case 3:
+    DBUG_ASSERT(offset < 0x1fffff); // all 1 value is reserved
+    int3store(place, val);
+    break;
+  case 4:
+    DBUG_ASSERT(offset < 0x1fffffff); // all 1 value is reserved
+    int4store(place, val);
+    break;
+  default:
+    DBUG_ASSERT(0); // impossible
+  }
+}
+
+
+/**
+  Read offset and type information from index entry
+
+  @param type            Where to put type info
+  @param offset          Where to put offset info
+  @param place           Beginning of the index entry
+  @param offset_size     Size of offset field in bytes
+*/
+
+void type_and_offset_read(DYNAMIC_COLUMN_TYPE *type,
+                          size_t *offset,
+                          uchar *place, size_t offset_size)
+{
+  ulong val;
+  place+= COLUMN_NUMBER_SIZE; // skip column number
+  switch (offset_size) {
+  case 1:
+    val= (ulong)place[0];
+    break;
+  case 2:
+    val= uint2korr(place);
+    break;
+  case 3:
+    val= uint3korr(place);
+    break;
+  case 4:
+    val= uint4korr(place);
+    break;
+  default:
+    DBUG_ASSERT(0); // impossible
+  }
+  *type= (val & 0x7) + 1;
+  *offset= val >> 3;
+}
+
+/**
+  Comparator function for references on column numbers for qsort
+*/
+
+int column_sort(const void *a, const void *b)
+{
+  return **((uint **)a) - **((uint **)b);
+}
+
+/**
+  Write information to the fixed header
+
+  @param str             String where to write the header
+  @param offset_size     Size of offset field in bytes
+  @param column_count    Number of columns
+*/
+
+static void set_fixed_header(DYNAMIC_COLUMN *str,
+                             uint offset_size,
+                             uint column_count)
+{
+  DBUG_ASSERT(column_count <= 0xffff);
+  DBUG_ASSERT(offset_size <= 4);
+  str->str[0]= ((str->str[0] & ~DYNCOL_FLG_OFFSET) |
+                (offset_size - 1)); // size of offset
+  int2store(str->str + 1, column_count); // columns number
+  DBUG_ASSERT((str->str[0] & (~DYNCOL_FLG_KNOWN)) == 0);
+}
+
+
+/*
+  Read offset size (O) and column count (C) from string (S)
+*/
+
+#define read_fixed_header(S,O,C) do {         \
+  (O)= ((S)->str[0] & DYNCOL_FLG_OFFSET) + 1; \
+  (C)= uint2korr((S)->str + 1);               \
+}while(0);
+
+
+/*
+  Calculete entry size (E) and header size (H) by offset size (O) and column
+  count (C).
+*/
+
+#define calc_param(E,H,O,C) do { \
+  (E)= (O) + COLUMN_NUMBER_SIZE; \
+  (H)= (E) * (C);                \
+}while(0);
+
+
+/**
+  Adds columns into the empty string
+
+  @param str             String where to write the data
+  @param header_size     Size of the header without fixed part
+  @param offset_size     Size of offset field in bytes
+  @param column_count    Number of columns in the arrays
+  @parem non_null_count  Number of non-null columns in the arrays
+  @param data_size       Size of the data segment
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+  @param new_str         True if we need allocate new string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_new_column_add(DYNAMIC_COLUMN *str,
+                           size_t header_size,
+                           size_t offset_size,
+                           uint column_count,
+                           uint non_null_count,
+                           size_t data_size,
+                           uint *column_numbers,
+                           DYNAMIC_COLUMN_VALUE *values,
+                           my_bool new_str)
+{
+  uchar *header_end;
+  uint **columns_order;
+  uint i;
+  uint entry_size= COLUMN_NUMBER_SIZE + offset_size;
+  int err= ER_DYNCOL_RESOURCE;
+  if (!(columns_order= malloc(sizeof(uint*)*column_count)))
+    return ER_DYNCOL_RESOURCE;
+  if (new_str)
+  {
+    if (dynamic_column_init_str(str,
+                                data_size + header_size + DYNCOL_SYZERESERVE))
+      goto err;
+  }
+  else
+  {
+    str->length= 0;
+    bzero(str->str, FIXED_HEADER_SIZE);
+    str->length= FIXED_HEADER_SIZE;
+    if (dynstr_realloc(str, data_size + header_size + DYNCOL_SYZERESERVE))
+      goto err;
+  }
+
+  /* sort columns for the header */
+  for (i= 0; i < column_count; i++)
+    columns_order[i]= column_numbers + i;
+  qsort(columns_order, (size_t)column_count, sizeof(uint*), &column_sort);
+  /* check numbers */
+  for (i= 0; i < column_count - 1; i++)
+  {
+    if (columns_order[i][0] == columns_order[i + 1][0])
+    {
+      err= ER_DYNCOL_DATA;
+      goto err;
+    }
+  }
+
+  DBUG_ASSERT(str->length == FIXED_HEADER_SIZE);
+  set_fixed_header(str, offset_size, non_null_count);
+  DBUG_ASSERT(str->max_length > str->length + header_size);
+  str->length+= header_size; // reserve place for header
+  header_end= (uchar *)str->str + FIXED_HEADER_SIZE;
+  for (i= 0; i < column_count; i++)
+  {
+    uint ord= columns_order[i] - column_numbers;
+    if (values[ord].type != DYN_COL_NULL)
+    {
+      int2store(header_end, column_numbers[ord]);
+      type_and_offset_store(header_end, offset_size,
+                            values[ord].type,
+                            str->length - header_size - FIXED_HEADER_SIZE);
+      if ((err= data_add(str, values + ord)))
+        goto err;
+      header_end+= entry_size;
+    }
+  }
+  err= ER_DYNCOL_OK;
+err:
+  free(columns_order);
+  return err;
+}
+
+/**
+  Create packed string which contains given columns (internal)
+
+  @param str             String where to write the data
+  @param column_count    Number of columns in the arrays
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+  @param new_str         True if we need allocate new string
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_create_many_int(DYNAMIC_COLUMN *str,
+                                   uint column_count,
+                                   uint *column_numbers,
+                                   DYNAMIC_COLUMN_VALUE *values,
+                                   my_bool new_str)
+{
+  size_t data_size= 0;
+  size_t header_size, offset_size;
+  uint i;
+  int not_null_column_count= column_count;
+  if (new_str)
+    bzero(str, sizeof(DYNAMIC_COLUMN)); // to make dynstr_free() working;
+  for (i= 0; i < column_count; i++)
+  {
+    data_size+= dynamic_column_value_len(values + i);
+    if (values[i].type == DYN_COL_NULL)
+      not_null_column_count--;
+  }
+
+  if ((offset_size= dynamic_column_offset_bytes(data_size)) >= 5)
+    return ER_DYNCOL_LIMIT;
+
+  /* header entry is column number + offset&type */
+  header_size= not_null_column_count * (offset_size + 2);
+
+  return dynamic_new_column_add(str,
+                                header_size, offset_size,
+                                column_count,
+                                not_null_column_count,
+                                data_size,
+                                column_numbers, values,
+                                new_str);
+}
+
+
+/**
+  Create packed string which contains given columns
+
+  @param str             String where to write the data
+  @param column_count    Number of columns in the arrays
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_create_many(DYNAMIC_COLUMN *str,
+                               uint column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values)
+{
+  return dynamic_column_create_many_int(str, column_count,
+                                        column_numbers, values,
+                                        TRUE);
+}
+
+
+/**
+  Create packed string which contains given column
+
+  @param str             String where to write the data
+  @param column_number   Column number
+  @param value           The columns value
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value)
+{
+  return dynamic_column_create_many(str, 1, &column_nr, value);
+}
+
+
+/**
+  Calculate length of data between given two header entries
+
+  @param entry           Pointer to the first entry
+  @param entry_next      Pointer to the last entry
+  @param header_end      Pointer to the header end
+  @param offset_size     Size of offset field in bytes
+  @param last_offset     Size of the data segment
+
+  @return number of bytes
+*/
+
+size_t get_length_interval (uchar *entry, uchar *entry_next,
+                            uchar *header_end, size_t offset_size,
+                            size_t last_offset)
+{
+  size_t offset, offset_next;
+  DYNAMIC_COLUMN_TYPE type, type_next;
+  DBUG_ASSERT(entry < entry_next);
+  type_and_offset_read(&type, &offset, entry, offset_size);
+  if (entry_next >= header_end)
+    return last_offset - offset;
+  type_and_offset_read(&type_next, &offset_next, entry_next, offset_size);
+  return offset_next - offset;
+}
+
+/*
+  Calculate length of data of one column
+
+
+  @param entry           Pointer to the first entry
+  @param header_end      Pointer to the header end
+  @param offset_size     Size of offset field in bytes
+  @param last_offset     Size of the data segment
+
+  @return number of bytes
+*/
+
+size_t get_length(uchar *entry, uchar *header_end,
+                  size_t offset_size,
+                  size_t last_offset)
+{
+  return get_length_interval(entry,
+                             entry + offset_size + COLUMN_NUMBER_SIZE,
+                             header_end, offset_size, last_offset);
+}
+
+
+/**
+  Comparator function for references to header entries for qsort
+*/
+
+int header_compar(const void *a, const void *b)
+{
+  uint va= uint2korr((uchar*)a), vb= uint2korr((uchar*)b);
+  return (va > vb ? 1 : (va < vb ? -1 : 0));
+}
+
+
+/**
+  Find column and fill information about it
+
+  @param type            Returns type of the column
+  @param data            Returns a pointer to the data
+  @param length          Returns length of the data
+  @param offset_size     Size of offset field in bytes
+  @param column_count    Number of column in the packed string
+  @param data_end        Pointer to the data end
+  @param num             Number of the column we want to fetch
+  @param entry_pos       NULL or place where to put reference to the entry
+*/
+
+void find_column(DYNAMIC_COLUMN_TYPE *type, uchar **data, size_t *length,
+                 uchar *header, size_t offset_size, uint column_count,
+                 uchar *data_end, uint num, uchar **entry_pos)
+{
+  uchar *entry;
+  size_t offset;
+  size_t header_size, entry_size;
+  uchar key[2+4];
+  if (!entry_pos)
+    entry_pos= &entry;
+
+  calc_param(entry_size, header_size, offset_size, column_count);
+  int2store(key, num);
+  entry= bsearch(key, header, (size_t)column_count, entry_size,
+                 &header_compar);
+  if (!entry)
+  {
+    *type= DYN_COL_NULL;
+    *entry_pos= NULL;
+    return;
+  }
+  type_and_offset_read(type, &offset, entry, offset_size);
+  *data= header + header_size + offset;
+  DBUG_ASSERT(*data < data_end);
+  *length= get_length(entry, header + header_size, offset_size,
+                      data_end - (header + header_size));
+  *entry_pos= entry;
+  return;
+}
+
+
+/**
+  Make simple check of the packed string format
+
+  @param str             The string to check
+
+  @retval FALSE OK
+  @retval TRUE  error
+*/
+
+static my_bool dynamic_column_str_check(DYNAMIC_COLUMN *str)
+{
+  if (str == NULL)
+    return TRUE;
+  if (str->length == 0)
+    return FALSE;
+  return ((str->length < FIXED_HEADER_SIZE) ||
+          (str->str[0] & (~DYNCOL_FLG_KNOWN)));
+}
+
+/**
+  Get dynamic column value
+
+  @param str             The packed string to extract the column
+  @param column_nr       Number of column to fetch
+  @param store_it_here   Where to store the extracted value
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_get(DYNAMIC_COLUMN *str, uint column_nr,
+                       DYNAMIC_COLUMN_VALUE *store_it_here)
+{
+  uchar *data;
+  size_t offset_size, length;
+  uint column_count;
+  int rc= ER_DYNCOL_FORMAT;
+
+  if (dynamic_column_str_check(str))
+    goto err;
+
+  if (str->length == 0)
+    goto null;
+
+  read_fixed_header(str, offset_size, column_count);
+  if (column_count == 0)
+    goto null;
+
+  find_column(&store_it_here->type, &data, &length,
+              (uchar*)str->str + FIXED_HEADER_SIZE,
+              offset_size, column_count, (uchar*)str->str + str->length,
+              column_nr, NULL);
+
+  switch (store_it_here->type)
+  {
+  case DYN_COL_INT:
+    rc= dynamic_column_sint_read(store_it_here, data, length);
+    break;
+  case DYN_COL_UINT:
+    rc= dynamic_column_uint_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DOUBLE:
+    rc= dynamic_column_double_read(store_it_here, data, length);
+    break;
+  case DYN_COL_STRING:
+    rc= dynamic_column_string_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DECIMAL:
+    rc= dynamic_column_decimal_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DATETIME:
+    rc= dynamic_column_date_time_read(store_it_here, data, length);
+    break;
+  case DYN_COL_DATE:
+    rc= dynamic_column_date_read(store_it_here, data, length);
+    break;
+  case DYN_COL_TIME:
+    rc= dynamic_column_time_read(store_it_here, data, length);
+    break;
+  case DYN_COL_NULL:
+    rc= ER_DYNCOL_OK;
+    break;
+  default:
+    goto err;
+  }
+  return rc;
+
+null:
+    rc= ER_DYNCOL_OK;
+err:
+    store_it_here->type= DYN_COL_NULL;
+    return rc;
+}
+
+/**
+  Delete column with given number from the packed string
+
+  @param str             The packed string to delete the column
+  @param column_nr       Number of column to delete
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_delete(DYNAMIC_COLUMN *str, uint column_nr)
+{
+  uchar *data, *header_entry, *read, *write;
+  size_t offset_size, new_offset_size, length, entry_size, new_entry_size,
+         header_size, new_header_size, data_size, new_data_size,
+         deleted_entry_offset;
+  uint column_count, i;
+  DYNAMIC_COLUMN_TYPE type;
+
+  if (dynamic_column_str_check(str))
+    return ER_DYNCOL_FORMAT;
+
+  if (str->length == 0)
+    return ER_DYNCOL_OK;  // no columns
+
+  read_fixed_header(str, offset_size, column_count);
+
+  if (column_count == 0)
+     return ER_DYNCOL_OK;  // no columns
+
+  find_column(&type, &data, &length, (uchar*)str->str + FIXED_HEADER_SIZE,
+              offset_size, column_count, (uchar*)str->str + str->length,
+              column_nr, &header_entry);
+
+  if (type == DYN_COL_NULL)
+    return ER_DYNCOL_OK;  // no such column
+
+  if (column_count == 1)
+  {
+    /* delete the only column */
+    str->length= FIXED_HEADER_SIZE;
+    bzero(str->str, FIXED_HEADER_SIZE);
+    return ER_DYNCOL_OK;
+  }
+
+  calc_param(entry_size, header_size, offset_size, column_count);
+  entry_size= 2 + offset_size;
+  header_size= entry_size * column_count;
+  data_size= str->length - FIXED_HEADER_SIZE - header_size;
+
+  new_data_size= data_size - length;
+  if ((new_offset_size= dynamic_column_offset_bytes(new_data_size)) >= 5)
+    return ER_DYNCOL_LIMIT;
+  DBUG_ASSERT(new_offset_size <= offset_size);
+  calc_param(new_entry_size, new_header_size,
+             new_offset_size, column_count - 1);
+
+  deleted_entry_offset= (data - (uchar*)str->str) -
+    header_size - FIXED_HEADER_SIZE;
+
+
+  /* rewrite header*/
+  set_fixed_header(str, new_offset_size, column_count - 1);
+  for (i= 0, write= read= (uchar *)str->str + FIXED_HEADER_SIZE;
+       i < column_count;
+       i++, read+= entry_size, write+= new_entry_size)
+  {
+    size_t offs;
+    uint nm;
+    DYNAMIC_COLUMN_TYPE tp;
+    if (read == header_entry)
+    {
+#ifndef DBUG_OFF
+      nm= uint2korr(read);
+      type_and_offset_read(&tp, &offs, read,
+                           offset_size);
+      DBUG_ASSERT(nm == column_nr);
+      DBUG_ASSERT(offs == deleted_entry_offset);
+#endif
+      write-= new_entry_size; // do not move writer
+      continue; // skip removed field
+    }
+
+    nm= uint2korr(read),
+    type_and_offset_read(&tp, &offs, read,
+                         offset_size);
+
+    if (offs > deleted_entry_offset)
+      offs-= length; // data stored after removed data
+
+    int2store(write, nm);
+    type_and_offset_store(write, new_offset_size, tp, offs);
+  }
+
+  /* move data */
+  {
+    size_t first_chunk_len= (data - (uchar *)str->str) -
+      FIXED_HEADER_SIZE - header_size;
+    size_t second_chunk_len= new_data_size - first_chunk_len;
+    if (first_chunk_len)
+      memmove(str->str + FIXED_HEADER_SIZE + new_header_size,
+              str->str + FIXED_HEADER_SIZE + header_size,
+              first_chunk_len);
+    if (second_chunk_len)
+      memmove(str->str +
+              FIXED_HEADER_SIZE + new_header_size + first_chunk_len,
+              str->str +
+              FIXED_HEADER_SIZE + header_size + first_chunk_len + length,
+              second_chunk_len);
+  }
+
+  /* fix str length */
+  DBUG_ASSERT(str->length >=
+              FIXED_HEADER_SIZE + new_header_size + new_data_size);
+  str->length= FIXED_HEADER_SIZE + new_header_size + new_data_size;
+
+  return FALSE;
+}
+
+
+/**
+  Check existence of the column in the packed string
+
+  @param str             The packed string to check the column
+  @param column_nr       Number of column to check
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_exists(DYNAMIC_COLUMN *str, uint column_nr)
+{
+  uchar *data;
+  size_t offset_size, length;
+  uint column_count;
+  DYNAMIC_COLUMN_TYPE type;
+
+  if (dynamic_column_str_check(str))
+    return ER_DYNCOL_FORMAT;
+
+  if (str->length == 0)
+    return ER_DYNCOL_NO; // no columns
+
+  read_fixed_header(str, offset_size, column_count);
+
+  if (column_count == 0)
+     return ER_DYNCOL_NO;  // no columns
+
+  find_column(&type, &data, &length, (uchar*)str->str + FIXED_HEADER_SIZE,
+              offset_size, column_count, (uchar*)str->str + str->length,
+              column_nr, NULL);
+
+  return (type != DYN_COL_NULL ? ER_DYNCOL_YES : ER_DYNCOL_NO);
+}
+
+/**
+  List not-null columns in the packed string
+
+  @param str             The packed string
+  @param array_of_uint   Where to put reference on created array
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_list(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_uint)
+{
+  uchar *read;
+  size_t offset_size, entry_size;
+  uint column_count, i;
+
+  if (dynamic_column_str_check(str))
+    return ER_DYNCOL_FORMAT;
+
+  if (str->length == 0)
+  {
+    if (init_dynamic_array(array_of_uint, sizeof(uint),
+                           0, 10 CALLER_INFO))
+      return ER_DYNCOL_RESOURCE;
+    return ER_DYNCOL_OK; // no columns
+  }
+
+
+  read_fixed_header(str, offset_size, column_count);
+  entry_size= COLUMN_NUMBER_SIZE + offset_size;
+
+  if (init_dynamic_array(array_of_uint, sizeof(uint),
+                         column_count, 10 CALLER_INFO))
+    return ER_DYNCOL_RESOURCE;
+
+  for (i= 0, read= (uchar *)str->str + FIXED_HEADER_SIZE;
+       i < column_count;
+       i++, read+= entry_size)
+  {
+    uint nm= uint2korr(read);
+    if (insert_dynamic(array_of_uint, (uchar *)&nm))
+    {
+      delete_dynamic(array_of_uint);
+      return ER_DYNCOL_RESOURCE;
+    }
+  }
+  return ER_DYNCOL_OK;
+}
+
+
+/**
+  Find the place of the column in the header or place where it should be put
+
+  @param num             Number of the column
+  @param header          Pointer to the header
+  @param entry_size      Size of a header entry
+  @param column_count    Number of columns in the packed string
+  @param entry           Return pointer to the entry or next entry
+
+  @retval TRUE found
+  @retval FALSE pointer set to the next row
+*/
+
+my_bool find_place(uint num,
+                   uchar *header, size_t entry_size, uint column_count,
+                   uchar **entry)
+{
+  uint mid, start, end, val;
+  int flag;
+
+  start= 0;
+  end= column_count -1;
+  mid= 1;
+  while (start != end)
+  {
+   uint val;
+   mid= (start + end) / 2;
+   val= uint2korr(header + mid * entry_size);
+   if ((flag= CMP_NUM(num, val)) <= 0)
+     end= mid;
+   else
+     start= mid + 1;
+  }
+  if (start != mid)
+  {
+    val= uint2korr(header + start * entry_size);
+    flag= CMP_NUM(num, val);
+  }
+  *entry= header + start * entry_size;
+  if (flag > 0)
+    *entry+= entry_size;        /* Point at next bigger key */
+  return flag == 0;
+}
+
+/*
+  Description of plan of adding/removing/updating a packed string
+*/
+
+typedef enum {PLAN_REPLACE, PLAN_ADD, PLAN_DELETE, PLAN_NOP} PLAN_ACT;
+
+struct st_plan {
+  DYNAMIC_COLUMN_VALUE *val;
+  uint *num;
+  uchar *place;
+  size_t length;
+  int hdelta, ddelta;
+  PLAN_ACT act;
+};
+typedef struct st_plan PLAN;
+
+
+int plan_sort(const void *a, const void *b)
+{
+  return ((PLAN *)a)->num[0] - ((PLAN *)b)->num[0];
+}
+
+#define DELTA_CHECK(S, D, C)        \
+  if ((S) == 0)                     \
+    (S)= (D);                       \
+  else if (((S) > 0 && (D) < 0) ||  \
+            ((S) < 0 && (D) > 0))   \
+  {                                 \
+    (C)= TRUE;                      \
+    break;                          \
+  }                                 \
+
+/**
+  Update the packed string with the given columns
+
+  @param str             String where to write the data
+  @param add_column_count Number of columns in the arrays
+  @param column_numbers  Array of columns numbers
+  @param values          Array of columns values
+
+  @return ER_DYNCOL_* return code
+*/
+
+int dynamic_column_update_many(DYNAMIC_COLUMN *str,
+                               uint add_column_count,
+                               uint *column_numbers,
+                               DYNAMIC_COLUMN_VALUE *values)
+{
+  PLAN *plan;
+  uchar *header_end;
+  long data_delta= 0;
+  uint i, j, k;
+  uint new_column_count, column_count,
+       not_null= add_column_count;
+  int rc;
+  int header_delta= 0;
+  int header_delta_sign, data_delta_sign;
+  size_t offset_size, entry_size, header_size, data_size;
+  size_t new_offset_size, new_entry_size, new_header_size, new_data_size;
+  size_t max_offset;
+  my_bool copy;
+
+
+  if (add_column_count == 0)
+    return ER_DYNCOL_OK;
+
+  if (!(plan= malloc(sizeof(PLAN) * (add_column_count + 1))))
+    return ER_DYNCOL_RESOURCE;
+
+  for (i= 0; i < add_column_count; i++)
+  {
+    plan[i].val= values + i;
+    plan[i].num= column_numbers + i;
+    if (values[i].type == DYN_COL_NULL)
+      not_null--;
+  }
+  qsort(plan, (size_t)add_column_count, sizeof(PLAN), &plan_sort);
+
+  if (str->length == 0)
+  {
+    /* There is no columns so we just add them */
+    if (not_null == 0)
+    {
+      if (str->str)
+      {
+        if (dynstr_realloc(str, FIXED_HEADER_SIZE + DYNCOL_SYZERESERVE))
+          return ER_DYNCOL_RESOURCE;
+        bzero(str->str, FIXED_HEADER_SIZE);
+        str->length= FIXED_HEADER_SIZE;
+      }
+      else
+      {
+        if (dynamic_column_init_str(str,
+                                    FIXED_HEADER_SIZE + DYNCOL_SYZERESERVE))
+          return ER_DYNCOL_RESOURCE;
+      }
+      return  ER_DYNCOL_OK;
+    }
+    return dynamic_column_create_many_int(str, add_column_count,
+                                          column_numbers, values,
+                                          str->str == NULL);
+  }
+
+  read_fixed_header(str, offset_size, column_count);
+  new_column_count= column_count;
+
+  if (column_count == 0)
+  {
+    /* There is no columns so we just add them */
+    if (not_null == 0)
+      return  ER_DYNCOL_OK;
+    return dynamic_column_create_many_int(str, add_column_count,
+                                          column_numbers, values,
+                                          FALSE);
+  }
+
+  calc_param(entry_size, header_size, offset_size, column_count);
+  max_offset= str->length - (FIXED_HEADER_SIZE + header_size);
+  header_end= (uchar *)str->str + FIXED_HEADER_SIZE + header_size;
+
+  /* check numbers */
+  for (i= 0; i < add_column_count; i++)
+  {
+    uchar *entry;
+    if (i < add_column_count - 1 && plan[i].num[0] == plan[i + 1].num[0])
+    {
+      rc= ER_DYNCOL_DATA;
+      goto err;
+    }
+
+    if (find_place(plan[i].num[0],
+                   (uchar *)str->str + FIXED_HEADER_SIZE,
+                   entry_size, column_count, &entry))
+    {
+      if (plan[i].val->type == DYN_COL_NULL)
+      {
+        size_t entry_data_size;
+        new_column_count--;
+        /* replace the value */
+        plan[i].act= PLAN_DELETE;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta--;
+        /* get data delta in bytes */
+        entry_data_size= get_length(entry, header_end,
+                                    offset_size, max_offset);
+        plan[i].length= 0;
+        plan[i].ddelta= data_delta;
+        data_delta-= entry_data_size;
+      }
+      else
+      {
+        size_t entry_data_size;
+        /* replace the value */
+        plan[i].act= PLAN_REPLACE;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta;
+        /* get data delta in bytes */
+        entry_data_size= get_length(entry, header_end,
+                                    offset_size, max_offset);
+        plan[i].length= dynamic_column_value_len(plan[i].val);
+        plan[i].ddelta= data_delta;
+        data_delta+= plan[i].length - entry_data_size;
+      }
+    }
+    else
+    {
+      if (plan[i].val->type == DYN_COL_NULL)
+      {
+        plan[i].act= PLAN_NOP;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta;
+        /* get data delta in bytes */
+        plan[i].length= 0;
+        plan[i].ddelta= data_delta;
+      }
+      else
+      {
+        new_column_count++;
+        /* replace the value */
+        plan[i].act= PLAN_ADD;
+        /* get header delta in entries */
+        plan[i].hdelta= header_delta++;
+        /* get data delta in bytes */
+        plan[i].length= dynamic_column_value_len(plan[i].val);
+        plan[i].ddelta= data_delta;
+        data_delta+= plan[i].length;
+      }
+    }
+    plan[i].place= entry;
+  }
+  plan[add_column_count].hdelta= header_delta;
+  plan[add_column_count].ddelta= data_delta;
+  /*
+    check if it is only "incising" or only "decreasing" plan for (header
+    and data separately).
+  */
+  data_size= str->length - header_size - FIXED_HEADER_SIZE;
+  new_data_size= data_size + data_delta;
+  if ((new_offset_size= dynamic_column_offset_bytes(new_data_size)) >= 5)
+    return ER_DYNCOL_LIMIT;
+  //if (new_offset_size != offset_size) rewrite_header= TRUE;
+  header_delta_sign= new_offset_size - offset_size;
+  data_delta_sign= 0;
+  copy= FALSE;
+  for (i= 0; i < add_column_count; i++)
+  {
+    DELTA_CHECK(header_delta_sign, plan[i].hdelta, copy);
+    DELTA_CHECK(data_delta_sign, plan[i].ddelta, copy);
+  }
+
+  calc_param(new_entry_size, new_header_size,
+             new_offset_size, new_column_count);
+
+  //if (copy)
+  {
+    DYNAMIC_COLUMN tmp;
+    uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE,
+          *write;
+    if (dynamic_column_init_str(&tmp,
+                                (FIXED_HEADER_SIZE + new_header_size +
+                                 new_data_size + DYNCOL_SYZERESERVE)))
+    {
+      rc= ER_DYNCOL_RESOURCE;
+      goto err;
+    }
+    write= (uchar *)tmp.str + FIXED_HEADER_SIZE;
+    tmp.length= FIXED_HEADER_SIZE + new_header_size;
+    set_fixed_header(&tmp, new_offset_size, new_column_count);
+    data_delta= 0;
+    /* Copy data to the new string */
+    for (i= 0, j= 0; i < add_column_count || j < column_count; i++)
+    {
+      size_t first_offset;
+      uint start= j, end;
+      /* skip NOP */
+      while (i < add_column_count && plan[i].act == PLAN_NOP)
+        i++;
+      /* old data portion */
+      while (j < column_count &&
+             (i >= add_column_count ||
+              header_base + j * entry_size < plan[i].place))
+        j++;
+      end= j;
+      if (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE)
+        j++;
+      for (k= start; k < end; k++)
+      {
+        uchar *read= header_base + k * entry_size;
+        size_t offs;
+        uint nm;
+        DYNAMIC_COLUMN_TYPE tp;
+        nm= uint2korr(read);
+        type_and_offset_read(&tp, &offs, read,
+                             offset_size);
+        if (k == start)
+          first_offset= offs;
+        offs+= plan[i].ddelta;
+        int2store(write, nm);
+        type_and_offset_store(write, new_offset_size, tp, offs);
+        write+= new_entry_size;
+      }
+      if (start < end)
+      {
+        size_t data_size=
+          get_length_interval(header_base + start * entry_size,
+                              header_base + end * entry_size,
+                              header_end, offset_size, max_offset);
+        memcpy(tmp.str + tmp.length, (char *)header_end + first_offset,
+               data_size);
+        tmp.length+= data_size;
+      }
+
+      /* new data adding */
+      if (i < add_column_count)
+      {
+        if(plan[i].act == PLAN_ADD ||
+           plan[i].act == PLAN_REPLACE)
+        {
+          int2store(write, plan[i].num[0]);
+          type_and_offset_store(write, new_offset_size,
+                                plan[i].val[0].type,
+                                tmp.length -
+                                (FIXED_HEADER_SIZE + new_header_size));
+          write+= new_entry_size;
+          data_add(&tmp, plan[i].val);
+        }
+        data_delta= plan[i].ddelta;
+      }
+    }
+    dynamic_column_column_free(str);
+    *str= tmp;
+  }
+
+  rc= ER_DYNCOL_OK;
+err:
+    free(plan);
+    return rc;
+}
+
+
+/**
+  Update the packed string with the given column
+
+  @param str             String where to write the data
+  @param column_number   Array of columns number
+  @param values          Array of columns values
+
+  @return ER_DYNCOL_* return code
+*/
+
+
+int dynamic_column_update(DYNAMIC_COLUMN *str, uint column_nr,
+                          DYNAMIC_COLUMN_VALUE *value)
+{
+  return dynamic_column_update_many(str, 1, &column_nr, value);
+}

=== modified file 'sql-common/my_time.c'
--- sql-common/my_time.c	2011-03-09 13:47:59 +0000
+++ sql-common/my_time.c	2011-04-29 09:52:28 +0000
@@ -482,7 +482,7 @@
 */
 
 my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time,
-                    int *warning)
+                    ulong fuzzydate, int *warning)
 {
   ulong date[5];
   ulonglong value;
@@ -509,7 +509,7 @@
     int was_cut;
     enum enum_mysql_timestamp_type
       res= str_to_datetime(str, length, l_time,
-                           (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut);
+                           fuzzydate | TIME_DATETIME_ONLY, &was_cut);
     if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR)
     {
       if (was_cut)
@@ -1028,11 +1028,15 @@
 int my_time_to_str(const MYSQL_TIME *l_time, char *to)
 {
   uint extra_hours= 0;
-  return my_sprintf(to, (to, "%s%02u:%02u:%02u",
+  return my_sprintf(to, (to,
+                         (l_time->second_part ?
+                          "%s%02u:%02u:%02u.%06ld" :
+                          "%s%02u:%02u:%02u"),
                          (l_time->neg ? "-" : ""),
                          extra_hours+ l_time->hour,
                          l_time->minute,
-                         l_time->second));
+                         l_time->second,
+                         l_time->second_part));
 }
 
 int my_date_to_str(const MYSQL_TIME *l_time, char *to)
@@ -1045,13 +1049,17 @@
 
 int my_datetime_to_str(const MYSQL_TIME *l_time, char *to)
 {
-  return my_sprintf(to, (to, "%04u-%02u-%02u %02u:%02u:%02u",
+  return my_sprintf(to, (to,
+                         (l_time->second_part ? 
+                         "%04u-%02u-%02u %02u:%02u:%02u.%06ld" :
+                          "%04u-%02u-%02u %02u:%02u:%02u"),
                          l_time->year,
                          l_time->month,
                          l_time->day,
                          l_time->hour,
                          l_time->minute,
-                         l_time->second));
+                         l_time->second,
+                         l_time->second_part));
 }
 
 
@@ -1062,6 +1070,9 @@
   SYNOPSIS
     my_TIME_to_string()
 
+  RETURN
+    length of string
+
   NOTE
     The string must have at least MAX_DATE_STRING_REP_LENGTH bytes reserved.
 */
@@ -1118,7 +1129,6 @@
   long part1,part2;
 
   *was_cut= 0;
-  bzero((char*) time_res, sizeof(*time_res));
   time_res->time_type=MYSQL_TIMESTAMP_DATE;
 
   if (nr == LL(0) || nr >= LL(10000101000000))
@@ -1171,6 +1181,8 @@
   time_res->hour=  (int) (part2/10000L);  part2%=10000L;
   time_res->minute=(int) part2 / 100;
   time_res->second=(int) part2 % 100;
+  time_res->second_part=  0;
+  time_res->neg= 0;
 
   if (time_res->year <= 9999 && time_res->month <= 12 &&
       time_res->day <= 31 && time_res->hour <= 23 &&
@@ -1179,15 +1191,58 @@
     return nr;
 
   /* Don't want to have was_cut get set if NO_ZERO_DATE was violated. */
-  if (!nr && (flags & TIME_NO_ZERO_DATE))
-    return LL(-1);
+  if (nr || !(flags & TIME_NO_ZERO_DATE))
+    *was_cut= 1;
+  return LL(-1);
 
  err:
-  *was_cut= 1;
+  {
+    /* reset everything except time_type */
+    enum enum_mysql_timestamp_type save= time_res->time_type;
+    bzero((char*) time_res, sizeof(*time_res));
+    time_res->time_type= save;                     /* Restore range */
+    *was_cut= 1;                                /* Found invalid date */
+  }
   return LL(-1);
 }
 
 
+/*
+  Convert a double to a date/datetime
+
+  Note that for sub seconds, the precision of double is not good enough!
+
+  RESULT:
+    0  ok
+    1  error ;  ltime is zeroed
+*/
+
+my_bool double_to_datetime(double value, MYSQL_TIME *ltime,
+                           uint fuzzydate)
+{
+  double datepart_value;
+  int was_cut;
+
+  if (value < 0 || value >  99991231235959.0)
+  {
+    bzero((char*) ltime, sizeof(*ltime));
+    return 1;
+  }
+
+  datepart_value= floor(value);
+  if (number_to_datetime((longlong) datepart_value, ltime, fuzzydate,
+                         &was_cut) == LL(-1))
+    return 1;
+  if (ltime->time_type == MYSQL_TIMESTAMP_DATETIME ||
+      ltime->time_type == MYSQL_TIMESTAMP_TIME)
+  {
+    /* Add sub seconds to results */
+    ltime->second_part= floor((value - datepart_value)* TIME_SUBSECOND_RANGE);
+  }
+  return 0;
+}  
+
+
 /* Convert time value to integer in YYYYMMDDHHMMSS format */
 
 ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *my_time)

=== modified file 'sql/field.cc'
--- sql/field.cc	2011-03-09 13:47:59 +0000
+++ sql/field.cc	2011-04-29 09:52:28 +0000
@@ -1753,7 +1753,10 @@
   char buff[40];
   String tmp(buff,sizeof(buff),&my_charset_bin),*res;
   if (!(res=val_str(&tmp)) ||
-      str_to_time_with_warn(res->ptr(), res->length(), ltime))
+      str_to_time_with_warn(res->ptr(), res->length(), ltime,
+                            table->in_use->variables.sql_mode &
+                            (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+                             MODE_INVALID_DATES)))
     return 1;
   return 0;
 }
@@ -3866,40 +3869,11 @@
 int Field_longlong::store(double nr)
 {
   ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
-  int error= 0;
+  bool error;
   longlong res;
 
-  nr= rint(nr);
-  if (unsigned_flag)
-  {
-    if (nr < 0)
-    {
-      res=0;
-      error= 1;
-    }
-    else if (nr >= (double) ULONGLONG_MAX)
-    {
-      res= ~(longlong) 0;
-      error= 1;
-    }
-    else
-      res=(longlong) double2ulonglong(nr);
-  }
-  else
-  {
-    if (nr <= (double) LONGLONG_MIN)
-    {
-      res= LONGLONG_MIN;
-      error= (nr < (double) LONGLONG_MIN);
-    }
-    else if (nr >= (double) (ulonglong) LONGLONG_MAX)
-    {
-      res= LONGLONG_MAX;
-      error= (nr > (double) LONGLONG_MAX);
-    }
-    else
-      res=(longlong) nr;
-  }
+  res= double_to_longlong(nr, unsigned_flag, &error);
+
   if (error)
     set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
 
@@ -4144,7 +4118,18 @@
 int Field_float::store(double nr)
 {
   ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
-  int error= truncate(&nr, FLT_MAX);
+  int error= truncate_double(&nr, field_length,
+                             not_fixed ? NOT_FIXED_DEC : dec,
+                             unsigned_flag, FLT_MAX);
+  if (error)
+  {
+    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+    if (error < 0)                                // Wrong double value
+    {
+      error= 1;
+      set_null();
+    }
+  }
   float j= (float)nr;
 
 #ifdef WORDS_BIGENDIAN
@@ -4406,7 +4391,18 @@
 int Field_double::store(double nr)
 {
   ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
-  int error= truncate(&nr, DBL_MAX);
+  int error= truncate_double(&nr, field_length,
+                             not_fixed ? NOT_FIXED_DEC : dec,
+                             unsigned_flag, DBL_MAX);
+  if (error)
+  {
+    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+    if (error < 0)                                // Wrong double value
+    {
+      error= 1;
+      set_null();
+    }
+  }
 
 #ifdef WORDS_BIGENDIAN
   if (table->s->db_low_byte_first)
@@ -4430,28 +4426,31 @@
   If a field has fixed length, truncate the double argument pointed to by 'nr'
   appropriately.
   Also ensure that the argument is within [-max_value; max_value] range.
+
+  return
+    0   ok
+    -1  Illegal double value
+    1   Value was truncated
 */
 
-int Field_real::truncate(double *nr, double max_value)
+int truncate_double(double *nr, uint field_length, uint dec,
+                    bool unsigned_flag, double max_value)
 {
-  int error= 1;
+  int error= 0;
   double res= *nr;
   
   if (isnan(res))
   {
-    res= 0;
-    set_null();
-    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
-    goto end;
+    *nr= 0;
+    return -1;
   }
   else if (unsigned_flag && res < 0)
   {
-    res= 0;
-    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
-    goto end;
+    *nr= 0;
+    return 1;
   }
 
-  if (!not_fixed)
+  if (dec < NOT_FIXED_DEC)
   {
     uint order= field_length - dec;
     uint step= array_elements(log_10) - 1;
@@ -4467,22 +4466,70 @@
   
   if (res < -max_value)
   {
-   res= -max_value;
-   set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+    res= -max_value;
+    error= 1;
   }
   else if (res > max_value)
   {
     res= max_value;
-    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+    error= 1;
   }
-  else
-    error= 0;
 
-end:
   *nr= res;
   return error;
 }
 
+/*
+  Convert double to longlong / ulonglong.
+  If double is outside of range, adjust return value and set error.
+
+  SYNOPSIS
+  double_to_longlong()
+  nr	  	 Number to convert
+  unsigned_flag  1 if result is unsigned
+  error		 Will be set to 1 in case of overflow.
+*/
+
+longlong double_to_longlong(double nr, bool unsigned_flag, bool *error)
+{
+  longlong res;
+
+  *error= 0;
+
+  nr= rint(nr);
+  if (unsigned_flag)
+  {
+    if (nr < 0)
+    {
+      res= 0;
+      *error= 1;
+    }
+    else if (nr >= (double) ULONGLONG_MAX)
+    {
+      res= ~(longlong) 0;
+      *error= 1;
+    }
+    else
+      res= (longlong) double2ulonglong(nr);
+  }
+  else
+  {
+    if (nr <= (double) LONGLONG_MIN)
+    {
+      res= LONGLONG_MIN;
+      *error= (nr < (double) LONGLONG_MIN);
+    }
+    else if (nr >= (double) (ulonglong) LONGLONG_MAX)
+    {
+      res= LONGLONG_MAX;
+      *error= (nr > (double) LONGLONG_MAX);
+    }
+    else
+      res= (longlong) nr;
+  }
+  return res;
+}
+
 
 int Field_real::store_decimal(const my_decimal *dm)
 {
@@ -4511,6 +4558,7 @@
   ASSERT_COLUMN_MARKED_FOR_READ;
   double j;
   longlong res;
+  bool error;
 #ifdef WORDS_BIGENDIAN
   if (table->s->db_low_byte_first)
   {
@@ -4519,20 +4567,9 @@
   else
 #endif
     doubleget(j,ptr);
-  /* Check whether we fit into longlong range */
-  if (j <= (double) LONGLONG_MIN)
-  {
-    res= (longlong) LONGLONG_MIN;
-    goto warn;
-  }
-  if (j >= (double) (ulonglong) LONGLONG_MAX)
-  {
-    res= (longlong) LONGLONG_MAX;
-    goto warn;
-  }
-  return (longlong) rint(j);
 
-warn:
+  res= double_to_longlong(j, 0, &error);
+  if (error)
   {
     char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
     String tmp(buf, sizeof(buf), &my_charset_latin1), *str;
@@ -5147,7 +5184,10 @@
   int error= 0;
   int warning;
 
-  if (str_to_time(from, len, &ltime, &warning))
+  if (str_to_time(from, len, &ltime,
+                  table->in_use->variables.sql_mode &
+                  (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+                   MODE_INVALID_DATES), &warning))
   {
     tmp=0L;
     error= 2;
@@ -5305,6 +5345,7 @@
   ltime.hour= (uint) (tmp/10000);
   ltime.minute= (uint) (tmp/100 % 100);
   ltime.second= (uint) (tmp % 100);
+  ltime.second_part= 0;
   make_time((DATE_TIME_FORMAT*) 0, &ltime, val_buffer);
   return val_buffer;
 }

=== modified file 'sql/field.h'
--- sql/field.h	2011-03-09 13:47:59 +0000
+++ sql/field.h	2011-04-29 09:52:28 +0000
@@ -33,6 +33,9 @@
 
 struct st_cache_field;
 int field_conv(Field *to,Field *from);
+int truncate_double(double *nr, uint field_length, uint dec,
+                    bool unsigned_flag, double max_value);
+longlong double_to_longlong(double nr, bool unsigned_flag, bool *error);
 
 inline uint get_enum_pack_length(int elements)
 {
@@ -808,7 +811,6 @@
     {}
   int store_decimal(const my_decimal *);
   my_decimal *val_decimal(my_decimal *);
-  int truncate(double *nr, double max_length);
   uint32 max_display_length() { return field_length; }
   uint size_of() const { return sizeof(*this); }
   virtual const uchar *unpack(uchar* to, const uchar *from,

=== modified file 'sql/item.cc'
--- sql/item.cc	2011-04-27 04:11:06 +0000
+++ sql/item.cc	2011-04-29 09:52:28 +0000
@@ -985,19 +985,13 @@
 
 bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
 {
-  if (result_type() == STRING_RESULT)
-  {
-    char buff[40];
-    String tmp(buff,sizeof(buff), &my_charset_bin),*res;
-    if (!(res=val_str(&tmp)) ||
-        str_to_datetime_with_warn(res->ptr(), res->length(),
-                                  ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
-      goto err;
-  }
-  else
-  {
+  switch (result_type()) {
+  case INT_RESULT:
+  {
+    int was_cut;
     longlong value= val_int();
-    int was_cut;
+    if (null_value)
+      goto err;
     if (number_to_datetime(value, ltime, fuzzydate, &was_cut) == LL(-1))
     {
       char buff[22], *end;
@@ -1005,8 +999,52 @@
       make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                                    buff, (int) (end-buff), MYSQL_TIMESTAMP_NONE,
                                    NullS);
-      goto err;
-    }
+      null_value= 1;
+      return 1;
+    }
+    break;
+  }
+  case REAL_RESULT:
+  {
+    double value= val_real();
+    if (null_value)
+      goto err;
+    if (double_to_datetime_with_warn(value, ltime, fuzzydate))
+    {
+      null_value= 1;
+      return 1;
+    }
+    break;
+  }
+  case DECIMAL_RESULT:   // This we could do better but string is ok for now
+  {
+    my_decimal value, *res;
+    if (!(res= val_decimal(&value)))
+      goto err;                                 // Null
+    if (decimal_to_datetime_with_warn(res, ltime, fuzzydate))
+    {
+      null_value= 1;
+      return 1;
+    }
+    break;
+  }
+  default:
+  {
+    /*
+      Default go trough string as this is the safest way to ensure that
+      we also get the microseconds.
+    */
+    char buff[40];
+    String tmp(buff,sizeof(buff), &my_charset_bin),*res;
+    if (!(res=val_str(&tmp)) ||
+        str_to_datetime_with_warn(res->ptr(), res->length(),
+                                  ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+    {
+      null_value= 1;
+      goto err;
+    }
+    break;
+  }
   }
   return 0;
 
@@ -1026,7 +1064,11 @@
   char buff[40];
   String tmp(buff,sizeof(buff),&my_charset_bin),*res;
   if (!(res=val_str(&tmp)) ||
-      str_to_time_with_warn(res->ptr(), res->length(), ltime))
+      str_to_time_with_warn(res->ptr(), res->length(), ltime,
+                            TIME_FUZZY_DATE |
+                            (current_thd->variables.sql_mode &
+                             (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+                              MODE_INVALID_DATES))))
   {
     bzero((char*) ltime,sizeof(*ltime));
     return 1;

=== modified file 'sql/item.h'
--- sql/item.h	2011-04-27 04:11:06 +0000
+++ sql/item.h	2011-04-29 09:52:28 +0000
@@ -18,6 +18,10 @@
 #pragma interface			/* gcc class implementation */
 #endif
 
+C_MODE_START
+#include <ma_dyncol.h>
+C_MODE_END
+
 inline
 bool trace_unsupported_func(const char *where, const char *processor_name)
 {
@@ -471,6 +475,17 @@
 };
 
 
+struct st_dyncall_create_def
+{
+  Item  *num, *value;
+  CHARSET_INFO *cs;
+  uint len, frac;
+  DYNAMIC_COLUMN_TYPE type;
+};
+
+typedef struct st_dyncall_create_def DYNCALL_CREATE_DEF;
+
+
 typedef bool (Item::*Item_processor) (uchar *arg);
 /*
   Analyzer function
@@ -804,7 +819,11 @@
   { return val_decimal(val); }
   virtual bool val_bool_result() { return val_bool(); }
   virtual bool is_null_result() { return is_null(); }
-
+  /*
+    Returns 1 if result type and collation for val_str() can change between
+    calls
+  */
+  virtual bool dynamic_result() { return 0; }
   /* 
     Bitmap of tables used by item
     (note: if you need to check dependencies on individual columns, check out

=== modified file 'sql/item_cmpfunc.cc'
--- sql/item_cmpfunc.cc	2011-04-27 04:11:06 +0000
+++ sql/item_cmpfunc.cc	2011-04-29 09:52:28 +0000
@@ -6074,3 +6074,34 @@
   DBUG_ASSERT(0);
   return NULL;
 }
+
+
+longlong Item_func_dyncol_exists::val_int()
+{
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+  DYNAMIC_COLUMN col;
+  String *str;
+  uint num;
+  int rc;
+
+  num= args[1]->val_int();
+  str= args[0]->val_str(&tmp);
+  if (args[0]->null_value || args[1]->null_value)
+    goto null;
+  col.length= str->length();
+  /* We do not change the string, so could do this trick */
+  col.str= (char *)str->ptr();
+  rc= dynamic_column_exists(&col, num);
+  if (rc < 0)
+  {
+    dynamic_column_error_message(rc);
+    goto null;
+  }
+  null_value= FALSE;
+  return rc == ER_DYNCOL_YES;
+
+null:
+  null_value= TRUE;
+  return 0;
+}

=== modified file 'sql/item_cmpfunc.h'
--- sql/item_cmpfunc.h	2011-04-27 04:11:06 +0000
+++ sql/item_cmpfunc.h	2011-04-29 09:52:28 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+/*dyncol_exists Copyright (c) 2000, 2010, Oracle and/or its affiliates.
 
    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
@@ -1869,3 +1869,11 @@
 
 bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, 
                              const char *warn_name, MYSQL_TIME *l_time);
+
+class Item_func_dyncol_exists :public Item_bool_func
+{
+public:
+  Item_func_dyncol_exists(Item *str, Item *num) :Item_bool_func(str, num) {}
+  longlong val_int();
+  const char *func_name() const { return "column_exists"; }
+};

=== modified file 'sql/item_create.cc'
--- sql/item_create.cc	2011-02-20 16:51:43 +0000
+++ sql/item_create.cc	2011-04-29 09:52:28 +0000
@@ -27,6 +27,50 @@
 
 /*
 =============================================================================
+  HELPER FUNCTIONS
+=============================================================================
+*/
+
+/*
+  Get precision and scale for a declaration
+ 
+  return
+    0  ok
+    1  error
+*/
+
+bool get_length_and_scale(ulonglong length, ulonglong decimals,
+                          ulong *out_length, uint *out_decimals,
+                          uint max_precision, uint max_scale,
+                          const char *name)
+{
+  if (length > (ulonglong) max_precision)
+  {
+    my_error(ER_TOO_BIG_PRECISION, MYF(0), (int) length, name,
+             max_precision);
+    return 1;
+  }
+  if (decimals > (ulonglong) max_scale)
+  {
+    my_error(ER_TOO_BIG_SCALE, MYF(0), (int) decimals, name,
+             DECIMAL_MAX_SCALE);
+    return 1;
+  }
+
+  *out_length=  (ulong) length;
+  *out_decimals=  (uint) decimals;
+  my_decimal_trim(out_length, out_decimals);
+  
+  if (*out_length < *out_decimals)
+  {
+    my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
+    return 1;
+  }
+  return 0;
+}
+
+/*
+=============================================================================
   LOCAL DECLARATIONS
 =============================================================================
 */
@@ -5054,6 +5098,17 @@
                  CHARSET_INFO *cs)
 {
   Item *UNINIT_VAR(res);
+  ulonglong length= 0, decimals= 0;
+  int error;
+  
+  /*
+    We don't have to check for error here as sql_yacc.yy has guaranteed
+    that the values are in range of ulonglong
+  */
+  if (c_len)
+    length= (ulonglong) my_strtoll10(c_len, NULL, &error);
+  if (c_dec)
+    decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error);
 
   switch (cast_type) {
   case ITEM_CAST_BINARY:
@@ -5076,72 +5131,45 @@
     break;
   case ITEM_CAST_DECIMAL:
   {
-    ulong len= 0;
-    uint dec= 0;
-
-    if (c_len)
-    {
-      ulong decoded_size;
-      errno= 0;
-      decoded_size= strtoul(c_len, NULL, 10);
-      if (errno != 0)
-      {
-        my_error(ER_TOO_BIG_PRECISION, MYF(0), c_len, a->name,
-                 DECIMAL_MAX_PRECISION);
-        return NULL;
-      }
-      len= decoded_size;
-    }
-
-    if (c_dec)
-    {
-      ulong decoded_size;
-      errno= 0;
-      decoded_size= strtoul(c_dec, NULL, 10);
-      if ((errno != 0) || (decoded_size > UINT_MAX))
-      {
-        my_error(ER_TOO_BIG_SCALE, MYF(0), c_dec, a->name,
-                 DECIMAL_MAX_SCALE);
-        return NULL;
-      }
-      dec= decoded_size;
-    }
-    my_decimal_trim(&len, &dec);
-    if (len < dec)
-    {
-      my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
-      return 0;
-    }
-    if (len > DECIMAL_MAX_PRECISION)
-    {
-      my_error(ER_TOO_BIG_PRECISION, MYF(0), len, a->name,
-               DECIMAL_MAX_PRECISION);
-      return 0;
-    }
-    if (dec > DECIMAL_MAX_SCALE)
-    {
-      my_error(ER_TOO_BIG_SCALE, MYF(0), dec, a->name,
-               DECIMAL_MAX_SCALE);
-      return 0;
-    }
+    ulong len;
+    uint dec;
+    if (get_length_and_scale(length, decimals, &len, &dec,
+                             DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE,
+                             a->name))
+      return NULL;
     res= new (thd->mem_root) Item_decimal_typecast(a, len, dec);
     break;
   }
+  case ITEM_CAST_DOUBLE:
+  {
+    ulong len;
+    uint dec;
+
+    if (!c_len)
+    {
+      length=   DBL_DIG+7;
+      decimals= NOT_FIXED_DEC;
+    }
+    else if (get_length_and_scale(length, decimals, &len, &dec,
+                                  DECIMAL_MAX_PRECISION, NOT_FIXED_DEC-1,
+                                  a->name))
+      return NULL;
+    res= new (thd->mem_root) Item_double_typecast(a, length, decimals);
+    break;
+  }
   case ITEM_CAST_CHAR:
   {
     int len= -1;
     CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection);
     if (c_len)
     {
-      ulong decoded_size;
-      errno= 0;
-      decoded_size= strtoul(c_len, NULL, 10);
-      if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH))
+      if (length > MAX_FIELD_BLOBLENGTH)
       {
-        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH);
+        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char",
+                 MAX_FIELD_BLOBLENGTH);
         return NULL;
       }
-      len= (int) decoded_size;
+      len= (int) length;
     }
     res= new (thd->mem_root) Item_char_typecast(a, len, real_cs);
     break;
@@ -5155,3 +5183,99 @@
   }
   return res;
 }
+
+
+static List<Item> *create_func_dyncol_prepare(THD *thd,
+                                              DYNCALL_CREATE_DEF **dfs,
+                                              List<DYNCALL_CREATE_DEF> &list)
+{
+  List_iterator_fast<DYNCALL_CREATE_DEF> li(list);
+  List<Item> *args= new (thd->mem_root) List<Item>;
+
+  *dfs=
+    (DYNCALL_CREATE_DEF *)alloc_root(thd->mem_root,
+                                     sizeof(DYNCALL_CREATE_DEF) *
+                                     list.elements);
+  DYNCALL_CREATE_DEF *def;
+  uint i= 0;
+
+  if (!args || !dfs)
+    return NULL;
+
+  while ((def= li++))
+  {
+    dfs[0][i++]= *def;
+    args->push_back(def->num);
+    args->push_back(def->value);
+  }
+  return args;
+}
+
+Item *create_func_dyncol_create(THD *thd, List<DYNCALL_CREATE_DEF> &list)
+{
+  List<Item> *args;
+  DYNCALL_CREATE_DEF *dfs;
+  if (!(args= create_func_dyncol_prepare(thd, &dfs, list)))
+    return NULL;
+
+  return new (thd->mem_root) Item_func_dyncol_create(*args, dfs);
+}
+
+
+Item *create_func_dyncol_add(THD *thd, Item *str,
+                             List<DYNCALL_CREATE_DEF> &list)
+{
+  List<Item> *args;
+  DYNCALL_CREATE_DEF *dfs;
+
+  if (!(args= create_func_dyncol_prepare(thd, &dfs, list)))
+    return NULL;
+
+  args->push_back(str);
+
+  return new (thd->mem_root) Item_func_dyncol_add(*args, dfs);
+}
+
+
+
+Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums)
+{
+  DYNCALL_CREATE_DEF *dfs;
+  List<Item> *args= new (thd->mem_root) List<Item>;
+  List_iterator_fast<Item> it(nums);
+  Item *num;
+  uint i;
+
+  dfs=
+    (DYNCALL_CREATE_DEF *)alloc_root(thd->mem_root,
+                                     sizeof(DYNCALL_CREATE_DEF) *
+                                     nums.elements);
+  if (!args || !dfs)
+    return NULL;
+
+  for (i= 0; (num= it++); i++)
+  {
+    dfs[i].num= num;
+    dfs[i].value= new Item_null();
+    dfs[i].type= DYN_COL_INT;
+    args->push_back(dfs[i].num);
+    args->push_back(dfs[i].value);
+  }
+
+  args->push_back(str);
+
+  return new (thd->mem_root) Item_func_dyncol_add(*args, dfs);
+}
+
+
+Item *create_func_dyncol_get(THD *thd,  Item *str, Item *num,
+                             Cast_target cast_type,
+                             const char *c_len, const char *c_dec,
+                             CHARSET_INFO *cs)
+{
+  Item *res;
+
+  if (!(res= new (thd->mem_root) Item_dyncol_get(str, num)))
+    return res;                                 // Return NULL
+  return create_func_cast(thd, res, cast_type, c_len, c_dec, cs);
+}

=== modified file 'sql/item_create.h'
--- sql/item_create.h	2011-02-20 16:51:43 +0000
+++ sql/item_create.h	2011-04-29 09:52:28 +0000
@@ -164,5 +164,15 @@
 create_func_cast(THD *thd, Item *a, Cast_target cast_type,
                  const char *len, const char *dec,
                  CHARSET_INFO *cs);
+
+Item *create_func_dyncol_create(THD *thd, List<DYNCALL_CREATE_DEF> &list);
+Item *create_func_dyncol_add(THD *thd, Item *str,
+                             List<DYNCALL_CREATE_DEF> &list);
+Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums);
+Item *create_func_dyncol_get(THD *thd, Item *num, Item *str,
+                             Cast_target cast_type,
+                             const char *c_len, const char *c_dec,
+                             CHARSET_INFO *cs);
+
 #endif
 

=== modified file 'sql/item_func.cc'
--- sql/item_func.cc	2011-03-24 14:34:06 +0000
+++ sql/item_func.cc	2011-04-29 09:52:28 +0000
@@ -989,9 +989,24 @@
     null_value= args[0]->null_value; 
     return value;
   }
+  else if (args[0]->dynamic_result())
+  {
+    /* We come here when argument has an unknown type */
+    args[0]->unsigned_flag= 0;   // Mark that we want to have a signed value
+    value= args[0]->val_int();
+    null_value= args[0]->null_value; 
+    if (!null_value && args[0]->unsigned_flag && value < 0)
+      goto err;                                 // Warn about overflow
+    return value;
+  }
 
   value= val_int_from_str(&error);
   if (value < 0 && error == 0)
+    goto err;
+  return value;
+
+err:
+  if (value < 0 && error == 0)
   {
     push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
                  "Cast to signed converted positive out-of-range integer to "
@@ -1024,19 +1039,36 @@
       value= 0;
     return value;
   }
+  else if (args[0]->dynamic_result())
+  {
+    /* We come here when argument has an unknown type */
+    args[0]->unsigned_flag= 1;   // Mark that we want to have an unsigned value
+    value= args[0]->val_int();
+    null_value= args[0]->null_value; 
+    if (!null_value && args[0]->unsigned_flag == 0 && value < 0)
+      goto err;                                 // Warn about overflow
+    return value;
+  }
   else if (args[0]->cast_to_int_type() != STRING_RESULT ||
            args[0]->result_as_longlong())
   {
     value= args[0]->val_int();
     null_value= args[0]->null_value; 
+    if (!null_value && args[0]->unsigned_flag == 0 && value < 0)
+      goto err;                                 // Warn about overflow
     return value;
   }
 
   value= val_int_from_str(&error);
   if (error < 0)
-    push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
-                 "Cast to unsigned converted negative integer to it's "
-                 "positive complement");
+    goto err;
+
+  return value;
+
+err:
+  push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+               "Cast to unsigned converted negative integer to it's "
+               "positive complement");
   return value;
 }
 
@@ -1134,6 +1166,51 @@
 }
 
 
+double Item_double_typecast::val_real()
+{
+  int error;
+  double tmp= args[0]->val_real();
+  if ((null_value= args[0]->null_value))
+    return 0.0;
+
+  if ((error= truncate_double(&tmp, max_length, decimals, 0, DBL_MAX)))
+  {
+    push_warning_printf(current_thd,
+                        MYSQL_ERROR::WARN_LEVEL_WARN,
+                        ER_WARN_DATA_OUT_OF_RANGE,
+                        ER(ER_WARN_DATA_OUT_OF_RANGE),
+                        name, 1);
+    if (error < 0)
+    {
+      null_value= 1;                            // Illegal value
+      tmp= 0.0;
+    }
+  }
+  return tmp;
+}
+
+
+void Item_double_typecast::print(String *str, enum_query_type query_type)
+{
+  char len_buf[20*3 + 1];
+  char *end;
+
+  str->append(STRING_WITH_LEN("cast("));
+  args[0]->print(str, query_type);
+  str->append(STRING_WITH_LEN(" as double"));
+  if (decimals != NOT_FIXED_DEC)
+  {
+    str->append('(');
+    end= int10_to_str(max_length, len_buf,10);
+    str->append(len_buf, (uint32) (end - len_buf));
+    str->append(',');
+    end= int10_to_str(decimals, len_buf,10);
+    str->append(len_buf, (uint32) (end - len_buf));
+    str->append(')');
+  }
+  str->append(')');
+}
+
 double Item_func_plus::real_op()
 {
   double value= args[0]->val_real() + args[1]->val_real();

=== modified file 'sql/item_func.h'
--- sql/item_func.h	2011-03-24 14:34:06 +0000
+++ sql/item_func.h	2011-04-29 09:52:28 +0000
@@ -470,12 +470,29 @@
   my_decimal *val_decimal(my_decimal*);
   enum Item_result result_type () const { return DECIMAL_RESULT; }
   enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
-  void fix_length_and_dec() {};
+  void fix_length_and_dec() {}
   const char *func_name() const { return "decimal_typecast"; }
   virtual void print(String *str, enum_query_type query_type);
 };
 
 
+class Item_double_typecast :public Item_real_func
+{
+public:
+  Item_double_typecast(Item *a, int len, int dec) :Item_real_func(a)
+  {
+    decimals= dec;
+    max_length= len;
+  }
+  double val_real();
+  enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+  void fix_length_and_dec() { maybe_null= 1; }
+  const char *func_name() const { return "double_typecast"; }
+  virtual void print(String *str, enum_query_type query_type);
+};
+
+
+
 class Item_func_additive_op :public Item_num_op
 {
 public:
@@ -1713,7 +1730,7 @@
 {
   ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
   ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR,
-  ITEM_CAST_DECIMAL
+  ITEM_CAST_DECIMAL, ITEM_CAST_DOUBLE
 };
 
 
@@ -1877,4 +1894,3 @@
     return trace_unsupported_by_check_vcol_func_processor(func_name());
   }
 };
-

=== modified file 'sql/item_strfunc.cc'
--- sql/item_strfunc.cc	2011-03-24 14:34:06 +0000
+++ sql/item_strfunc.cc	2011-04-29 09:52:28 +0000
@@ -3451,3 +3451,740 @@
 
   return str;
 }
+
+
+Item_func_dyncol_create::Item_func_dyncol_create(List<Item> &args,
+                                                 DYNCALL_CREATE_DEF *dfs)
+  : Item_str_func(args), defs(dfs), vals(0), nums(0)
+{
+  DBUG_ASSERT((args.elements & 0x1) == 0); // even number of arguments
+}
+
+
+bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref)
+{
+  bool res= Item_func::fix_fields(thd, ref); // no need Item_str_func here
+  vals= (DYNAMIC_COLUMN_VALUE *) alloc_root(thd->mem_root,
+                                            sizeof(DYNAMIC_COLUMN_VALUE) *
+                                            (arg_count / 2));
+  nums= (uint *) alloc_root(thd->mem_root,
+                            sizeof(uint) * (arg_count / 2));
+  return res || vals == 0 || nums == 0;
+}
+
+
+void Item_func_dyncol_create::fix_length_and_dec()
+{
+  maybe_null= TRUE;
+  collation.set(&my_charset_bin);
+  decimals= 0;
+}
+
+void Item_func_dyncol_create::prepare_arguments()
+{
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String *res, tmp(buff, sizeof(buff), &my_charset_bin);
+  uint column_count= (arg_count / 2);
+  uint i;
+  my_decimal dtmp, *dres;
+
+  /* get values */
+  for (i= 0; i < column_count; i++)
+  {
+    uint valpos= i * 2 + 1;
+    DYNAMIC_COLUMN_TYPE type= defs[i].type;
+    if (type == DYN_COL_NULL) // auto detect
+    {
+      switch (args[valpos]->field_type()) {
+      case MYSQL_TYPE_DECIMAL:
+      case MYSQL_TYPE_NEWDECIMAL:
+        type= DYN_COL_DECIMAL;
+        break;
+      case MYSQL_TYPE_TINY:
+      case MYSQL_TYPE_SHORT:
+      case MYSQL_TYPE_LONG:
+      case MYSQL_TYPE_LONGLONG:
+      case MYSQL_TYPE_INT24:
+      case MYSQL_TYPE_YEAR:
+      case MYSQL_TYPE_BIT:
+        type= DYN_COL_INT;
+        break;
+      case MYSQL_TYPE_FLOAT:
+      case MYSQL_TYPE_DOUBLE:
+        type= DYN_COL_DOUBLE;
+        break;
+      case MYSQL_TYPE_NULL:
+        type= DYN_COL_NULL;
+        break;
+      case MYSQL_TYPE_TIMESTAMP:
+      case MYSQL_TYPE_DATETIME:
+        type= DYN_COL_DATETIME;
+	break;
+      case MYSQL_TYPE_DATE:
+      case MYSQL_TYPE_NEWDATE:
+        type= DYN_COL_DATE;
+        break;
+      case MYSQL_TYPE_TIME:
+        type= DYN_COL_TIME;
+        break;
+      case MYSQL_TYPE_VARCHAR:
+      case MYSQL_TYPE_ENUM:
+      case MYSQL_TYPE_SET:
+      case MYSQL_TYPE_TINY_BLOB:
+      case MYSQL_TYPE_MEDIUM_BLOB:
+      case MYSQL_TYPE_LONG_BLOB:
+      case MYSQL_TYPE_BLOB:
+      case MYSQL_TYPE_VAR_STRING:
+      case MYSQL_TYPE_STRING:
+      case MYSQL_TYPE_GEOMETRY:
+        type= DYN_COL_STRING;
+        break;
+      default:
+        DBUG_ASSERT(0);
+        type= DYN_COL_STRING;
+      }
+    }
+    nums[i]= args[i * 2]->val_int();
+    vals[i].type= type;
+    switch (type) {
+    case DYN_COL_NULL:
+      break;
+    case DYN_COL_INT:
+      vals[i].long_value= args[valpos]->val_int();
+      break;
+    case DYN_COL_UINT:
+      vals[i].ulong_value= args[valpos]->val_int();
+      break;
+    case DYN_COL_DOUBLE:
+      vals[i].double_value= args[valpos]->val_real();
+      break;
+    case DYN_COL_STRING:
+      res= args[valpos]->val_str(&tmp);
+      if (res)
+      {
+	vals[i].string_value.str= (char *)my_malloc(res->length(), MYF(0));
+	if (vals[i].string_value.str)
+	  memcpy(vals[i].string_value.str, res->ptr(), res->length());
+	vals[i].string_value.length= res->length();
+	vals[i].charset= res->charset();
+      }
+      else
+      {
+        vals[i].string_value.str= NULL;
+        vals[i].string_value.length= 0; // just to be safe
+	DBUG_ASSERT(args[valpos]->null_value);
+      }
+      break;
+    case DYN_COL_DECIMAL:
+      dres= args[valpos]->val_decimal(&dtmp);
+      if (dres)
+      {
+	dynamic_column_prepare_decimal(&vals[i]);
+        DBUG_ASSERT(vals[i].decimal_value.len == dres->len);
+        vals[i].decimal_value.intg= dres->intg;
+        vals[i].decimal_value.frac= dres->frac;
+        vals[i].decimal_value.sign= dres->sign();
+        memcpy(vals[i].decimal_buffer, dres->buf,
+               sizeof(vals[i].decimal_buffer));
+      }
+      else
+      {
+	dynamic_column_prepare_decimal(&vals[i]); // just to be safe
+        DBUG_ASSERT(args[valpos]->null_value);
+      }
+      break;
+    case DYN_COL_DATETIME:
+      args[valpos]->get_date(&vals[i].time_value, TIME_FUZZY_DATE);
+      break;
+    case DYN_COL_DATE:
+      args[valpos]->get_date(&vals[i].time_value, TIME_FUZZY_DATE);
+      break;
+    case DYN_COL_TIME:
+      args[valpos]->get_time(&vals[i].time_value);
+      break;
+    default:
+      DBUG_ASSERT(0);
+      vals[i].type= DYN_COL_NULL;
+    }
+    if (vals[i].type != DYN_COL_NULL && args[valpos]->null_value)
+    {
+      if (vals[i].type == DYN_COL_STRING)
+        my_free(vals[i].string_value.str, MYF(MY_ALLOW_ZERO_PTR));
+      vals[i].type= DYN_COL_NULL;
+    }
+  }
+}
+
+void Item_func_dyncol_create::cleanup_arguments()
+{
+  uint column_count= (arg_count / 2);
+  uint i;
+
+  for (i= 0; i < column_count; i++)
+  {
+    if (vals[i].type == DYN_COL_STRING)
+      my_free(vals[i].string_value.str, MYF(MY_ALLOW_ZERO_PTR));
+  }
+}
+
+String *Item_func_dyncol_create::val_str(String *str)
+{
+  DYNAMIC_COLUMN col;
+  String *res;
+  uint column_count= (arg_count / 2);
+  int rc;
+  DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments
+
+  prepare_arguments();
+
+  if ((rc= dynamic_column_create_many(&col, column_count, nums, vals)))
+  {
+    dynamic_column_error_message(rc);
+    res= NULL;
+    null_value= TRUE;
+  }
+  else
+  {
+    res= str;
+    str->copy(col.str, col.length, &my_charset_bin);
+  }
+
+  /* cleanup */
+  dynamic_column_column_free(&col);
+  cleanup_arguments();
+
+  return res;
+}
+
+void Item_func_dyncol_create::print_arguments(String *str,
+                                              enum_query_type query_type)
+{
+  uint i;
+  uint column_count= (arg_count / 2);
+  for (i= 0; i < column_count; i++)
+  {
+    args[i*2]->print(str, query_type);
+    str->append(',');
+    args[i*2 + 1]->print(str, query_type);
+    switch (defs[i].type) {
+    case DYN_COL_NULL: // automatic type => write nothing
+      break;
+    case DYN_COL_INT:
+      str->append(STRING_WITH_LEN(" AS int"));
+      break;
+    case DYN_COL_UINT:
+      str->append(STRING_WITH_LEN(" AS unsigned int"));
+      break;
+    case DYN_COL_DOUBLE:
+      str->append(STRING_WITH_LEN(" AS double"));
+      break;
+    case DYN_COL_STRING:
+      str->append(STRING_WITH_LEN(" AS char"));
+      if (defs[i].cs)
+      {
+        str->append(STRING_WITH_LEN(" charset "));
+        str->append(defs[i].cs->csname);
+        str->append(' ');
+      }
+      break;
+    case DYN_COL_DECIMAL:
+      str->append(STRING_WITH_LEN(" AS decimal"));
+      break;
+    case DYN_COL_DATETIME:
+      str->append(STRING_WITH_LEN(" AS datetime"));
+      break;
+    case DYN_COL_DATE:
+      str->append(STRING_WITH_LEN(" AS date"));
+      break;
+    case DYN_COL_TIME:
+      str->append(STRING_WITH_LEN(" AS time"));
+      break;
+    }
+    if (i < column_count - 1)
+      str->append(',');
+  }
+}
+
+
+void Item_func_dyncol_create::print(String *str,
+                                    enum_query_type query_type)
+{
+  DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments
+  str->append(STRING_WITH_LEN("column_create("));
+  print_arguments(str, query_type);
+  str->append(')');
+}
+
+
+String *Item_func_dyncol_add::val_str(String *str)
+{
+  DYNAMIC_COLUMN col;
+  String *res;
+  uint column_count=  (arg_count / 2);
+  int rc;
+  DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments
+
+  prepare_arguments();
+
+  res= args[arg_count - 1]->val_str(str);
+  if (args[arg_count - 1]->null_value)
+    goto null;
+  init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE,
+                      STRING_BUFFER_USUAL_SIZE);
+  col.length= res->length();
+  memcpy(col.str, res->ptr(), col.length);
+  if ((rc= dynamic_column_update_many(&col, column_count, nums, vals)))
+  {
+    dynamic_column_error_message(rc);
+    goto null;
+  }
+
+  str->copy(col.str, col.length, &my_charset_bin);
+
+  /* cleanup */
+  dynamic_column_column_free(&col);
+  cleanup_arguments();
+
+  return str;
+
+null:
+  null_value= TRUE;
+  return NULL;
+}
+
+
+void Item_func_dyncol_add::print(String *str,
+                                 enum_query_type query_type)
+{
+  DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments
+  str->append(STRING_WITH_LEN("column_create("));
+  args[arg_count - 1]->print(str, query_type);
+  str->append(',');
+  print_arguments(str, query_type);
+  str->append(')');
+}
+
+bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp)
+{
+  DYNAMIC_COLUMN dyn_str;
+  String *res;
+  longlong num;
+  int rc;
+
+  num= args[1]->val_int();
+  if (args[1]->null_value || num < 0 || num > INT_MAX)
+  {
+    null_value= 1;
+    return 1;
+  }
+
+  res= args[0]->val_str(tmp);
+  if (args[0]->null_value)
+  {
+    null_value= 1;
+    return 1;
+  }
+
+  dyn_str.str=   (char*) res->ptr();
+  dyn_str.length= res->length();
+  if ((rc= dynamic_column_get(&dyn_str, (uint) num, val)))
+  {
+    dynamic_column_error_message(rc);
+    null_value= 1;
+    return 1;
+  }
+
+  null_value= 0;
+  return 0;                                     // ok
+}
+
+
+String *Item_dyncol_get::val_str(String *str_result)
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return NULL;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_INT:
+  case DYN_COL_UINT:
+    str_result->set_int(val.long_value, test(val.type == DYN_COL_UINT),
+                       &my_charset_latin1);
+    break;
+  case DYN_COL_DOUBLE:
+    str_result->set_real(val.double_value, NOT_FIXED_DEC, &my_charset_latin1);
+    break;
+  case DYN_COL_STRING:
+    if ((char*) tmp.ptr() <= val.string_value.str &&
+        (char*) tmp.ptr() + tmp.length() >= val.string_value.str)
+    {
+      /* value is allocated in tmp buffer; We have to make a copy */
+      str_result->copy(val.string_value.str, val.string_value.length,
+                      val.charset);
+    }
+    else
+    {
+      /*
+        It's safe to use the current value because it's either pointing
+        into a field or in a buffer for another item and this buffer
+        is not going to be deleted during expression evulation
+      */
+      str_result->set(val.string_value.str, val.string_value.length,
+                      val.charset);
+    }
+    break;
+  case DYN_COL_DECIMAL:
+  {
+    int res;
+    int length=
+      my_decimal_string_length((const my_decimal*)&val.decimal_value);
+    if (str_result->alloc(length))
+      goto null;
+    if ((res= decimal2string(&val.decimal_value, (char*) str_result->ptr(),
+                             &length, 0, 0, ' ')) != E_DEC_OK)
+    {
+      char buff[40];
+      int len= sizeof(buff);
+      DBUG_ASSERT(length < (int)sizeof(buff[40]));
+      decimal2string(&val.decimal_value, buff, &len, 0, 0, ' ');
+      decimal_operation_results(res, buff, "CHAR");
+    }
+    str_result->set_charset(&my_charset_latin1);
+    str_result->length(length);
+    break;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+  {
+    int length;
+    if (str_result->alloc(MAX_DATE_STRING_REP_LENGTH) ||
+        !(length= my_TIME_to_str(&val.time_value, (char*) str_result->ptr())))
+      goto null;
+    str_result->set_charset(&my_charset_latin1);
+    str_result->length(length);
+    break;
+  }
+  }
+  return str_result;
+
+null:
+  null_value= TRUE;
+  return 0;
+}
+
+
+longlong Item_dyncol_get::val_int()
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return 0;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_UINT:
+    unsigned_flag= 1;            // Make it possible for caller to detect sign
+    return val.long_value;
+  case DYN_COL_INT:
+    unsigned_flag= 0;            // Make it possible for caller to detect sign
+    return val.long_value;
+  case DYN_COL_DOUBLE:
+  {
+    bool error;
+    longlong num;
+
+    num= double_to_longlong(val.double_value, unsigned_flag, &error);
+    if (error)
+    {
+      char buff[30];
+      sprintf(buff, "%lg", val.double_value);
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_DATA_OVERFLOW,
+                          ER(ER_DATA_OVERFLOW),
+                          buff,
+                          unsigned_flag ? "UNSIGNED INT" : "INT");
+    }
+    return num;
+  }
+  case DYN_COL_STRING:
+  {
+    int error;
+    longlong num;
+    char *end= val.string_value.str + val.string_value.length, *org_end= end;
+
+    num= my_strtoll10(val.string_value.str, &end, &error);
+    if (end != org_end || error > 0)
+    {
+      char buff[80];
+      strmake(buff, val.string_value.str, min(sizeof(buff)-1,
+                                              val.string_value.length));
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BAD_DATA,
+                          ER(ER_BAD_DATA),
+                          buff,
+                          unsigned_flag ? "UNSIGNED INT" : "INT");
+    }
+    unsigned_flag= error >= 0;
+    return num;
+  }
+  case DYN_COL_DECIMAL:
+  {
+    longlong num;
+    my_decimal2int(E_DEC_FATAL_ERROR, &val.decimal_value, unsigned_flag,
+                   &num);
+    return num;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+    unsigned_flag= 1;
+    return TIME_to_ulonglong(&val.time_value);
+  }
+
+null:
+  null_value= TRUE;
+  return 0;
+}
+
+
+double Item_dyncol_get::val_real()
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return 0.0;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_UINT:
+    return ulonglong2double(val.ulong_value);
+  case DYN_COL_INT:
+    return (double) val.long_value;
+  case DYN_COL_DOUBLE:
+    return (double) val.double_value;
+  case DYN_COL_STRING:
+  {
+    int error;
+    char *end;
+    double res= my_strntod(val.charset, (char*) val.string_value.str,
+                           val.string_value.length, &end, &error);
+
+    if (end != (char*) val.string_value.str + val.string_value.length ||
+        error)
+    {
+      char buff[80];
+      strmake(buff, val.string_value.str, min(sizeof(buff)-1,
+                                              val.string_value.length));
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BAD_DATA,
+                          ER(ER_BAD_DATA),
+                          buff, "DOUBLE");
+    }
+    return res;
+  }
+  case DYN_COL_DECIMAL:
+  {
+    double res;
+    /* This will always succed */
+    decimal2double(&val.decimal_value, &res);
+    return res;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+    return (ulonglong2double(TIME_to_ulonglong(&val.time_value)) +
+            val.time_value.second_part / (double) TIME_SUBSECOND_RANGE);
+  }
+
+null:
+  null_value= TRUE;
+  return 0.0;
+}
+
+
+my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value)
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+
+  if (get_dyn_value(&val, &tmp))
+    return NULL;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_UINT:
+    int2my_decimal(E_DEC_FATAL_ERROR, val.long_value, TRUE, decimal_value);
+    break;
+  case DYN_COL_INT:
+    int2my_decimal(E_DEC_FATAL_ERROR, val.long_value, FALSE, decimal_value);
+    break;
+  case DYN_COL_DOUBLE:
+    double2my_decimal(E_DEC_FATAL_ERROR, val.double_value, decimal_value);
+    break;
+  case DYN_COL_STRING:
+  {
+    int rc;
+    rc= str2my_decimal(0, val.string_value.str, val.string_value.length,
+                       val.charset, decimal_value);
+    char buff[80];
+    strmake(buff, val.string_value.str, min(sizeof(buff)-1,
+                                            val.string_value.length));
+    if (rc != E_DEC_OK)
+    {
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BAD_DATA,
+                          ER(ER_BAD_DATA),
+                          buff, "DECIMAL");
+    }
+    break;
+  }
+  case DYN_COL_DECIMAL:
+  {
+    int length= STRING_BUFFER_USUAL_SIZE;
+    decimal2string(&val.decimal_value, buff, &length, 0,0, 0);
+    decimal2my_decimal(&val.decimal_value, decimal_value);
+
+    break;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+  {
+    double tmp= (ulonglong2double(TIME_to_ulonglong(&val.time_value)) +
+                 val.time_value.second_part / (double) TIME_SUBSECOND_RANGE);
+    /* This can't overflow as time is always in the range of decimal */
+    double2my_decimal(E_DEC_FATAL_ERROR, tmp, decimal_value);
+    break;
+  }
+  }
+  return decimal_value;
+
+null:
+  null_value= TRUE;
+  return 0;
+}
+
+
+bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
+{
+  DYNAMIC_COLUMN_VALUE val;
+  char buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp(buff, sizeof(buff), &my_charset_bin);
+  bool signed_value= 0;
+
+  if (get_dyn_value(&val, &tmp))
+    return 0;
+
+  switch (val.type) {
+  case DYN_COL_NULL:
+    goto null;
+  case DYN_COL_INT:
+    signed_value= 1;                                  // For error message
+    /* fall_trough */
+  case DYN_COL_UINT:
+  {
+    ulonglong num;
+    int error;
+
+    num= val.ulong_value;
+    number_to_datetime(num, ltime, fuzzy_date, &error);
+    if (error)
+    {
+      char buff[65];
+      int errnum= error == 2 ? ER_DATA_OVERFLOW : ER_BAD_DATA;
+      longlong2str(num, buff, signed_value ? -10 : 10, 1);
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          errnum,
+                          ER(errnum),
+                          buff, "DATE or DATETIME");
+      goto null;
+    }
+    return 0;
+  }
+  case DYN_COL_DOUBLE:
+  {
+    if (double_to_datetime_with_warn(val.double_value, ltime, fuzzy_date))
+      goto null;
+    return 0;
+  }
+  case DYN_COL_DECIMAL:
+    if (decimal_to_datetime_with_warn(&val.decimal_value, ltime, fuzzy_date))
+      goto null;
+    return 0;
+  case DYN_COL_STRING:
+  {
+    if (str_to_datetime_with_warn(val.string_value.str,
+                                  val.string_value.length,
+                                  ltime, fuzzy_date) <= MYSQL_TIMESTAMP_ERROR)
+      goto null;
+    return 0;
+  }
+  case DYN_COL_DATETIME:
+  case DYN_COL_DATE:
+  case DYN_COL_TIME:
+    *ltime= val.time_value;
+    return 0;
+  }
+
+null:
+  null_value= TRUE;
+  return 1;
+}
+
+void Item_dyncol_get::print(String *str, enum_query_type query_type)
+{
+  str->append(STRING_WITH_LEN("column_get("));
+  args[0]->print(str, query_type);
+  str->append(',');
+  args[1]->print(str, query_type);
+  str->append(')');
+}
+
+String *Item_func_dyncol_list::val_str(String *str)
+{
+  DYNAMIC_ARRAY arr;
+  DYNAMIC_COLUMN col;
+  String *res= args[0]->val_str(str);
+  uint i;
+  int rc;
+
+  if (args[0]->null_value)
+    goto null;
+  col.length= res->length();
+  /* We do not change the string, so could do this trick */
+  col.str= (char *)res->ptr();
+  if ((rc= dynamic_column_list(&col, &arr)))
+  {
+    dynamic_column_error_message(rc);
+    delete_dynamic(&arr);
+    goto null;
+  }
+
+  str->length(0);
+  for (i= 0; i < arr.elements; i++)
+  {
+    str->qs_append(*dynamic_element(&arr, i, uint*));
+    if (i < arr.elements - 1)
+      str->append(',');
+  }
+
+  delete_dynamic(&arr);
+  return str;
+null:
+  null_value= TRUE;
+  return NULL;
+}

=== modified file 'sql/item_strfunc.h'
--- sql/item_strfunc.h	2010-06-01 19:52:20 +0000
+++ sql/item_strfunc.h	2011-04-29 09:52:28 +0000
@@ -871,3 +871,71 @@
   }
 };
 
+
+class Item_func_dyncol_create: public Item_str_func
+{
+protected:
+  DYNCALL_CREATE_DEF *defs;
+  DYNAMIC_COLUMN_VALUE *vals;
+  uint *nums;
+  void prepare_arguments();
+  void cleanup_arguments();
+  void print_arguments(String *str, enum_query_type query_type);
+public:
+  Item_func_dyncol_create(List<Item> &args, DYNCALL_CREATE_DEF *dfs);
+  bool fix_fields(THD *thd, Item **ref);
+  void fix_length_and_dec();
+  const char *func_name() const{ return "column_create"; }
+  String *val_str(String *);
+  virtual void print(String *str, enum_query_type query_type);
+};
+
+
+class Item_func_dyncol_add: public Item_func_dyncol_create
+{
+public:
+  Item_func_dyncol_add(List<Item> &args, DYNCALL_CREATE_DEF *dfs)
+    :Item_func_dyncol_create(args, dfs)
+  {}
+  const char *func_name() const{ return "column_add"; }
+  String *val_str(String *);
+  virtual void print(String *str, enum_query_type query_type);
+};
+
+
+/*
+  The following functions is always called from an Item_cast function
+*/
+
+class Item_dyncol_get: public Item_str_func
+{
+public:
+  Item_dyncol_get(Item *str, Item *num)
+    :Item_str_func(str, num)
+  {
+    max_length= MAX_FIELD_BLOBLENGTH;
+  }
+  void fix_length_and_dec()
+  { maybe_null= 1; }
+  /* Mark that collation can change between calls */
+  bool dynamic_result() { return 1; }
+
+  const char *func_name() const { return "column_get"; }
+  String *val_str(String *);
+  longlong val_int();
+  double val_real();
+  my_decimal *val_decimal(my_decimal *);
+  bool get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp);
+  bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+  void print(String *str, enum_query_type query_type);
+};
+
+
+class Item_func_dyncol_list: public Item_str_func
+{
+public:
+  Item_func_dyncol_list(Item *str) :Item_str_func(str) {};
+  void fix_length_and_dec() { maybe_null= 1; max_length= MAX_BLOB_WIDTH; };
+  const char *func_name() const{ return "column_list"; }
+  String *val_str(String *);
+};

=== modified file 'sql/item_timefunc.cc'
--- sql/item_timefunc.cc	2011-02-20 16:51:43 +0000
+++ sql/item_timefunc.cc	2011-04-29 09:52:28 +0000
@@ -1952,7 +1952,10 @@
   {
     String *res;
     if (!(res=args[0]->val_str(str)) ||
-	(str_to_time_with_warn(res->ptr(), res->length(), &l_time)))
+	(str_to_time_with_warn(res->ptr(), res->length(), &l_time,
+                               current_thd->variables.sql_mode &
+                               (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+                                MODE_INVALID_DATES))))
       goto null_date;
 
     l_time.year=l_time.month=l_time.day=0;
@@ -2322,7 +2325,11 @@
     char buf[40];
     String value(buf, sizeof(buf), &my_charset_bin);;
     String *res= args[0]->val_str(&value);
-    if (!res || str_to_time_with_warn(res->ptr(), res->length(), &ltime))
+    if (!res ||
+        str_to_time_with_warn(res->ptr(), res->length(), &ltime,
+                              current_thd->variables.sql_mode &
+                              (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE |
+                               MODE_INVALID_DATES)))
     {
       null_value=1;
       return 0;
@@ -2464,7 +2471,8 @@
     // Convert character set if differ
     uint dummy_errors;
     if (!(res= args[0]->val_str(str)) ||
-        tmp_value.copy(res->ptr(), res->length(), from_cs,
+        tmp_value.copy(res->ptr(), res->length(),
+                       from_cs ? from_cs  : res->charset(),
                        cast_cs, &dummy_errors))
     {
       null_value= 1;
@@ -2542,15 +2550,19 @@
        and thus avoid unnecessary character set conversion.
      - If the argument is not a number, then from_cs is set to
        the argument's charset.
+     - If argument has a dynamic collation (can change from call to call)
+       we set from_cs to 0 as a marker that we have to take the collation
+       from the result string.
 
        Note (TODO): we could use repertoire technique here.
   */
-  from_cs= (args[0]->result_type() == INT_RESULT || 
-            args[0]->result_type() == DECIMAL_RESULT ||
-            args[0]->result_type() == REAL_RESULT) ?
-           (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) :
-           args[0]->collation.collation;
-  charset_conversion= (cast_cs->mbmaxlen > 1) ||
+  from_cs= ((args[0]->result_type() == INT_RESULT || 
+             args[0]->result_type() == DECIMAL_RESULT ||
+             args[0]->result_type() == REAL_RESULT) ?
+            (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) :
+            args[0]->dynamic_result() ? 0 :
+            args[0]->collation.collation);
+  charset_conversion= !from_cs || (cast_cs->mbmaxlen > 1) ||
                       (!my_charset_same(from_cs, cast_cs) &&
                        from_cs != &my_charset_bin &&
                        cast_cs != &my_charset_bin);
@@ -2604,6 +2616,11 @@
   return res;
 }
 
+bool Item_time_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
+{
+  return get_time(ltime);
+}
+
 
 longlong Item_time_typecast::val_int()
 {
@@ -2621,7 +2638,7 @@
   DBUG_ASSERT(fixed == 1);
   MYSQL_TIME ltime;
 
-  if (!get_arg0_time(&ltime) &&
+  if (!get_time(&ltime) &&
       !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
 		     &ltime, str))
     return str;

=== modified file 'sql/item_timefunc.h'
--- sql/item_timefunc.h	2011-02-28 17:39:30 +0000
+++ sql/item_timefunc.h	2011-04-29 09:52:28 +0000
@@ -937,6 +937,7 @@
 public:
   Item_time_typecast(Item *a) :Item_typecast_maybe_null(a) {}
   const char *func_name() const { return "cast_as_time"; }
+  bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
   String *val_str(String *str);
   bool get_time(MYSQL_TIME *ltime);
   const char *cast_type() const { return "time"; }

=== modified file 'sql/lex.h'
--- sql/lex.h	2011-04-28 16:56:10 +0000
+++ sql/lex.h	2011-04-29 09:52:28 +0000
@@ -116,6 +116,12 @@
   { "COLLATION",	SYM(COLLATION_SYM)},
   { "COLUMN",		SYM(COLUMN_SYM)},
   { "COLUMNS",		SYM(COLUMNS)},
+  { "COLUMN_ADD",       SYM(COLUMN_ADD_SYM)},
+  { "COLUMN_CREATE",    SYM(COLUMN_CREATE_SYM)},
+  { "COLUMN_DELETE",    SYM(COLUMN_DELETE_SYM)},
+  { "COLUMN_EXISTS",    SYM(COLUMN_EXISTS_SYM)},
+  { "COLUMN_GET",       SYM(COLUMN_GET_SYM)},
+  { "COLUMN_LIST",      SYM(COLUMN_LIST_SYM)},
   { "COMMENT",		SYM(COMMENT_SYM)},
   { "COMMIT",		SYM(COMMIT_SYM)},
   { "COMMITTED",	SYM(COMMITTED_SYM)},

=== modified file 'sql/my_decimal.cc'
--- sql/my_decimal.cc	2011-02-20 16:51:43 +0000
+++ sql/my_decimal.cc	2011-04-29 09:52:28 +0000
@@ -30,21 +30,20 @@
     result
 */
 
-int decimal_operation_results(int result)
+int decimal_operation_results(int result, const char *value, const char *type)
 {
   switch (result) {
   case E_DEC_OK:
     break;
   case E_DEC_TRUNCATED:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-			WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED),
-			"", (ulong) 0);
+			ER_DATA_TRUNCATED, ER(ER_DATA_TRUNCATED),
+			value, type);
     break;
   case E_DEC_OVERFLOW:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
-                        ER_TRUNCATED_WRONG_VALUE,
-                        ER(ER_TRUNCATED_WRONG_VALUE),
-			"DECIMAL", "");
+                        ER_DATA_OVERFLOW, ER(ER_DATA_OVERFLOW),
+			value, type);
     break;
   case E_DEC_DIV_ZERO:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
@@ -52,9 +51,8 @@
     break;
   case E_DEC_BAD_NUM:
     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
-			ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
-			ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
-			"decimal", "", "", (ulong) 0);
+			ER_BAD_DATA, ER(ER_BAD_DATA),
+			value, type);
     break;
   case E_DEC_OOM:
     my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -283,6 +281,35 @@
   return buff;
 }
 
+
+/*
+  Convert a decimal to an ulong with a descreptive error message
+*/
+
+int my_decimal2int(uint mask, const decimal_t *d, my_bool unsigned_flag,
+		   longlong *l)
+{
+  int res;
+  my_decimal rounded;
+  /* decimal_round can return only E_DEC_TRUNCATED */
+  decimal_round(d, &rounded, 0, HALF_UP);
+  res= (unsigned_flag ?
+        decimal2ulonglong(&rounded, (ulonglong *) l) :
+        decimal2longlong(&rounded, l));
+  if (res & mask)
+  {
+    char buff[DECIMAL_MAX_STR_LENGTH];
+    int length= sizeof(buff);
+    decimal2string(d, buff, &length, 0, 0, 0);
+
+    decimal_operation_results(res, buff,
+                              unsigned_flag ? "UNSIGNED INT" :
+                              "INT");
+  }
+  return res;
+}
+
+
 #endif /*DBUG_OFF*/
 
 

=== modified file 'sql/my_decimal.h'
--- sql/my_decimal.h	2010-11-24 22:57:34 +0000
+++ sql/my_decimal.h	2011-04-29 09:52:28 +0000
@@ -32,32 +32,7 @@
 #include <decimal.h>
 C_MODE_END
 
-#define DECIMAL_LONGLONG_DIGITS 22
-#define DECIMAL_LONG_DIGITS 10
-#define DECIMAL_LONG3_DIGITS 8
-
-/** maximum length of buffer in our big digits (uint32). */
-#define DECIMAL_BUFF_LENGTH 9
-
-/* the number of digits that my_decimal can possibly contain */
-#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)
-
-
-/**
-  maximum guaranteed precision of number in decimal digits (number of our
-  digits * number of decimal digits in one our big digit - number of decimal
-  digits in one our big digit decreased by 1 (because we always put decimal
-  point on the border of our big digits))
-*/
-#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
-#define DECIMAL_MAX_SCALE 30
-#define DECIMAL_NOT_SPECIFIED 31
-
-/**
-  maximum length of string representation (number of maximum decimal
-  digits + 1 position for sign + 1 position for decimal point)
-*/
-#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
+#include <my_decimal_limits.h>
 
 /**
   maximum size of packet length.
@@ -134,9 +109,10 @@
 #endif
 
 #ifndef MYSQL_CLIENT
-int decimal_operation_results(int result);
+int decimal_operation_results(int result, const char *value, const char *type);
 #else
-inline int decimal_operation_results(int result)
+inline int decimal_operation_results(int result, const char *value,
+                                     const char *type)
 {
   return result;
 }
@@ -158,7 +134,7 @@
 inline int check_result(uint mask, int result)
 {
   if (result & mask)
-    decimal_operation_results(result);
+    decimal_operation_results(result, "", "DECIMAL");
   return result;
 }
 
@@ -294,24 +270,14 @@
 		      uint fixed_dec, char filler, String *str);
 #endif
 
-inline
-int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
-		   longlong *l)
-{
-  my_decimal rounded;
-  /* decimal_round can return only E_DEC_TRUNCATED */
-  decimal_round((decimal_t*)d, &rounded, 0, HALF_UP);
-  return check_result(mask, (unsigned_flag ?
-			     decimal2ulonglong(&rounded, (ulonglong *)l) :
-			     decimal2longlong(&rounded, l)));
-}
-
-
-inline
-int my_decimal2double(uint, const my_decimal *d, double *result)
+int my_decimal2int(uint mask, const decimal_t *d, my_bool unsigned_flag,
+		   longlong *l);
+
+inline
+int my_decimal2double(uint, const decimal_t *d, double *result)
 {
   /* No need to call check_result as this will always succeed */
-  return decimal2double((decimal_t*) d, result);
+  return decimal2double(d, result);
 }
 
 
@@ -354,6 +320,18 @@
 			     longlong2decimal(i, d)));
 }
 
+inline
+void decimal2my_decimal(decimal_t *from, my_decimal *to)
+{
+  DBUG_ASSERT(to->len >= from->len);
+  to->intg= from->intg;
+  to->frac= from->frac;
+  to->sign(from->sign);
+  memcpy(to->buf, from->buf, to->len*sizeof(decimal_digit_t));
+}
+
+
+
 
 inline
 void my_decimal_neg(decimal_t *arg)

=== modified file 'sql/mysql_priv.h'
--- sql/mysql_priv.h	2011-04-28 16:56:10 +0000
+++ sql/mysql_priv.h	2011-04-29 09:52:28 +0000
@@ -1412,6 +1412,7 @@
 Field *
 find_field_in_table_sef(TABLE *table, const char *name);
 int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE);
+int dynamic_column_error_message(int rc);
 
 #endif /* MYSQL_SERVER */
 
@@ -2322,16 +2323,22 @@
 void get_date_from_daynr(long daynr,uint *year, uint *month,
 			 uint *day);
 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
-bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time);
+bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time,
+                           ulong fuzzydate);
 timestamp_type str_to_datetime_with_warn(const char *str, uint length,
-                                         MYSQL_TIME *l_time, uint flags);
+                                         MYSQL_TIME *l_time, ulong flags);
 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
 void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
 
-void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+void make_truncated_value_warning(THD *thd,
+                                  MYSQL_ERROR::enum_warning_level level,
                                   const char *str_val,
 				  uint str_length, timestamp_type time_type,
                                   const char *field_name);
+bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
+                                  ulong fuzzy_date);
+bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
+                                   ulong fuzzy_date);
 
 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval);
 bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,

=== modified file 'sql/share/errmsg.txt'
--- sql/share/errmsg.txt	2011-04-28 16:56:10 +0000
+++ sql/share/errmsg.txt	2011-04-29 09:55:41 +0000
@@ -5321,7 +5321,7 @@
 ER_DIVISION_BY_ZERO 22012 
         eng "Division by 0"
         ger "Division durch 0"
-ER_TRUNCATED_WRONG_VALUE_FOR_FIELD  
+ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 22007
         eng "Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %lu"
         ger "Falscher %-.32s-Wert: '%-.128s' für Feld '%.192s' in Zeile %lu"
 ER_ILLEGAL_VALUE_FOR_TYPE 22007 
@@ -6251,4 +6251,15 @@
         eng "Incorrect value '%-.64s' for option '%-.64s'"
 ER_CANT_DO_ONLINE
         eng "Can't execute the given '%s' command as online"
-
+ER_DATA_OVERFLOW 22003
+        eng "Got overflow when converting '%-.128s' to %-.32s. Value truncated."
+ER_DATA_TRUNCATED 22003
+        eng "Truncated value '%-.128s' when converting to %-.32s"
+ER_BAD_DATA 22007
+        eng "Encountered illegal value '%-.128s' when converting to %-.32s"
+ER_DYN_COL_WRONG_FORMAT
+        eng "Encountered illegal format of dynamic column string"
+ER_DYN_COL_IMPLEMENTATION_LIMIT
+        eng "Dynamic column implementation limit reached"
+ER_DYN_COL_DATA 22007
+        eng "Illegal value used as argument of dynamic column function"

=== modified file 'sql/sql_base.cc'
--- sql/sql_base.cc	2011-03-31 15:35:57 +0000
+++ sql/sql_base.cc	2011-04-29 09:52:28 +0000
@@ -9406,6 +9406,39 @@
   thd->restore_backup_open_tables_state(backup);
 }
 
+
+/**
+  Check result of dynamic column function and issue error if it is needed
+
+  @param rc              The result code of dynamic column function
+
+  @return the result code which was get as an argument\
+*/
+
+int dynamic_column_error_message(int rc)
+{
+  switch (rc) {
+  case ER_DYNCOL_YES:
+  case ER_DYNCOL_OK:
+    break; // it is not an error
+  case ER_DYNCOL_FORMAT:
+    my_error(ER_DYN_COL_WRONG_FORMAT, MYF(0));
+    break;
+  case ER_DYNCOL_LIMIT:
+    my_error(ER_DYN_COL_IMPLEMENTATION_LIMIT, MYF(0));
+    break;
+  case ER_DYNCOL_RESOURCE:
+    my_error(ER_OUT_OF_RESOURCES, MYF(0));
+    break;
+  case ER_DYNCOL_DATA:
+    my_error(ER_DYN_COL_DATA, MYF(0));
+    break;
+  default:
+    DBUG_ASSERT(0);
+  }
+  return rc;
+}
+
 /**
   @} (end of group Data_Dictionary)
 */

=== modified file 'sql/sql_yacc.yy'
--- sql/sql_yacc.yy	2011-04-28 16:56:10 +0000
+++ sql/sql_yacc.yy	2011-04-29 09:56:51 +0000
@@ -34,6 +34,7 @@
 #define YYINITDEPTH 100
 #define YYMAXDEPTH 3200                        /* Because of 64K stack */
 #define Lex (YYTHD->lex)
+
 #define Select Lex->current_select
 #include "mysql_priv.h"
 #include "slave.h"
@@ -671,6 +672,8 @@
   sp_head *sphead;
   struct p_elem_val *p_elem_value;
   enum index_hint_type index_hint;
+  DYNCALL_CREATE_DEF *dyncol_def;
+  List<DYNCALL_CREATE_DEF> *dyncol_def_list;
 }
 
 %{
@@ -770,6 +773,12 @@
 %token  COLLATE_SYM                   /* SQL-2003-R */
 %token  COLLATION_SYM                 /* SQL-2003-N */
 %token  COLUMNS
+%token  COLUMN_ADD_SYM
+%token  COLUMN_CREATE_SYM
+%token  COLUMN_DELETE_SYM
+%token  COLUMN_EXISTS_SYM
+%token  COLUMN_GET_SYM
+%token  COLUMN_LIST_SYM
 %token  COLUMN_SYM                    /* SQL-2003-R */
 %token  COMMENT_SYM
 %token  COMMITTED_SYM                 /* SQL-2003-N */
@@ -1338,7 +1347,7 @@
         opt_natural_language_mode opt_query_expansion
         opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
         ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
-        optional_flush_tables_arguments
+        optional_flush_tables_arguments opt_dyncol_type dyncol_type
 
 %type <ulong_num>
         ulong_num real_ulong_num merge_insert_types
@@ -1438,6 +1447,10 @@
 
 %type <boolfunc2creator> comp_op
 
+%type <dyncol_def> dyncall_create_element
+
+%type <dyncol_def_list> dyncall_create_list
+
 %type <NONE>
         query verb_clause create change select do drop insert replace insert2
         insert_values update delete truncate rename
@@ -7506,6 +7519,131 @@
         | ANY_SYM { $$ = 0; }
         ;
 
+opt_dyncol_type:
+          /* empty */ 
+          {
+            LEX *lex= Lex;
+	    $$= DYN_COL_NULL; /* automatic type */
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+	  }
+        | AS dyncol_type { $$= $2; }
+        ;
+
+dyncol_type:
+          INT_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_INT;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | UNSIGNED INT_SYM 
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_UINT;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | DOUBLE_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DOUBLE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | REAL
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DOUBLE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | FLOAT_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DOUBLE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | DECIMAL_SYM float_options
+          {
+            $$= DYN_COL_DECIMAL;
+            Lex->charset= NULL;
+          }
+        | char opt_binary
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_STRING;
+            lex->length= lex->dec= 0;
+          }
+        | nchar
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_STRING;
+            lex->charset= national_charset_info;
+            lex->length= lex->dec= 0;
+          }
+        | DATE_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DATE;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | TIME_SYM
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_TIME;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        | DATETIME
+          {
+            LEX *lex= Lex;
+            $$= DYN_COL_DATETIME;
+            lex->charset= NULL;
+            lex->length= lex->dec= 0;
+          }
+        ;
+
+dyncall_create_element:
+   expr ',' expr opt_dyncol_type
+   {
+     LEX *lex= Lex;
+     $$= (DYNCALL_CREATE_DEF *)
+       alloc_root(YYTHD->mem_root, sizeof(DYNCALL_CREATE_DEF));
+     if ($$ == NULL)
+       MYSQL_YYABORT;
+     $$->num= $1;
+     $$->value= $3;
+     $$->type= (DYNAMIC_COLUMN_TYPE)$4;
+     $$->cs= lex->charset;
+     if (lex->length)
+       $$->len= strtoul(lex->length, NULL, 10);
+     else
+       $$->len= 0;
+     if (lex->dec)
+       $$->frac= strtoul(lex->dec, NULL, 10);
+     else
+       $$->len= 0;
+   }
+
+dyncall_create_list:
+     dyncall_create_element
+       {
+         $$= new (YYTHD->mem_root) List<DYNCALL_CREATE_DEF>;
+         if ($$ == NULL)
+           MYSQL_YYABORT;
+         $$->push_back($1);
+       }
+   | dyncall_create_list ',' dyncall_create_element
+       {
+         $1->push_back($3);
+         $$= $1;
+       }
+   ;
+
 simple_expr:
           simple_ident
         | function_call_keyword
@@ -8040,6 +8178,51 @@
               MYSQL_YYABORT;
             Lex->safe_to_cache_query=0;
           }
+        |
+          COLUMN_ADD_SYM '(' expr ',' dyncall_create_list ')'
+          {
+            $$= create_func_dyncol_add(YYTHD, $3, *$5);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_DELETE_SYM '(' expr ',' expr_list ')'
+          {
+            $$= create_func_dyncol_delete(YYTHD, $3, *$5);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_EXISTS_SYM '(' expr ',' expr ')'
+          {
+            $$= new (YYTHD->mem_root) Item_func_dyncol_exists($3, $5);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_LIST_SYM '(' expr ')'
+          {
+            $$= new (YYTHD->mem_root) Item_func_dyncol_list($3);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_CREATE_SYM '(' dyncall_create_list ')'
+          {
+            $$= create_func_dyncol_create(YYTHD, *$3);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
+        |
+          COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')'
+          {
+            LEX *lex= Lex;
+            $$= create_func_dyncol_get(YYTHD, $3, $5, $7,
+                                        lex->length, lex->dec,
+                                        lex->charset);
+            if ($$ == NULL)
+              MYSQL_YYABORT;
+          }
         ;
 
 /*
@@ -8641,6 +8824,8 @@
           { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
         | NCHAR_SYM opt_field_length
           { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; }
+        | INT_SYM
+          { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
         | SIGNED_SYM
           { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
         | SIGNED_SYM INT_SYM
@@ -8657,7 +8842,10 @@
           { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
         | DECIMAL_SYM float_options
           { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
-        ;
+        | DOUBLE_SYM
+          { Lex->charset= NULL; Lex->length= Lex->dec= 0;}
+          opt_precision
+          { $$=ITEM_CAST_DOUBLE; }
 
 opt_expr_list:
           /* empty */ { $$= NULL; }
@@ -11887,6 +12075,12 @@
         | CHECKSUM_SYM          {}
         | CHECKPOINT_SYM        {}
         | CLOSE_SYM             {}
+        | COLUMN_ADD_SYM        {}
+        | COLUMN_CREATE_SYM     {}
+        | COLUMN_DELETE_SYM     {}
+        | COLUMN_EXISTS_SYM     {}
+        | COLUMN_GET_SYM        {}
+        | COLUMN_LIST_SYM       {}
         | COMMENT_SYM           {}
         | COMMIT_SYM            {}
         | CONTAINS_SYM          {}

=== modified file 'sql/time.cc'
--- sql/time.cc	2010-01-15 15:27:55 +0000
+++ sql/time.cc	2011-04-29 09:52:28 +0000
@@ -223,7 +223,7 @@
 
 timestamp_type
 str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
-                          uint flags)
+                          ulong flags)
 {
   int was_cut;
   THD *thd= current_thd;
@@ -232,15 +232,42 @@
   ts_type= str_to_datetime(str, length, l_time,
                            (flags | (thd->variables.sql_mode &
                                      (MODE_INVALID_DATES |
+                                      MODE_NO_ZERO_IN_DATE |
                                       MODE_NO_ZERO_DATE))),
                            &was_cut);
   if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
-    make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+    make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                                  str, length, ts_type,  NullS);
   return ts_type;
 }
 
 
+bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
+                                  ulong fuzzydate)
+{
+  if (double_to_datetime(value, ltime, fuzzydate))
+  {
+    char buff[40];
+    uint length= my_sprintf(buff, (buff, "%-30.21g", value));
+    make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                                 buff, length, MYSQL_TIMESTAMP_DATETIME,
+                                 NullS);
+    return 1;
+  }
+  return 0;
+}
+
+bool decimal_to_datetime_with_warn(decimal_t *value, MYSQL_TIME *ltime,
+                                  ulong fuzzydate)
+{
+  char buff[40];
+  int length= sizeof(buff);
+
+  decimal2string(value, buff, &length, 0, 0, 0);
+  return (str_to_datetime_with_warn(buff, length, ltime, fuzzydate) <=
+          MYSQL_TIMESTAMP_ERROR);
+}
+
 /*
   Convert a datetime from broken-down MYSQL_TIME representation to corresponding 
   TIMESTAMP value.
@@ -284,10 +311,11 @@
     See str_to_time() for more info.
 */
 bool
-str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time)
+str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
+                      ulong fuzzydate)
 {
   int warning;
-  bool ret_val= str_to_time(str, length, l_time, &warning);
+  bool ret_val= str_to_time(str, length, l_time, fuzzydate, &warning);
   if (ret_val || warning)
     make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                                  str, length, MYSQL_TIMESTAMP_TIME, NullS);
@@ -719,7 +747,8 @@
 }
 
 
-void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+void make_truncated_value_warning(THD *thd,
+                                  MYSQL_ERROR::enum_warning_level level,
                                   const char *str_val,
 				  uint str_length, timestamp_type time_type,
                                   const char *field_name)
@@ -763,6 +792,7 @@
                ER_TRUNCATED_WRONG_VALUE, warn_buff);
 }
 
+
 /* Daynumber from year 0 to 9999-12-31 */
 #define MAX_DAY_NUMBER 3652424L
 

=== modified file 'strings/decimal.c'
--- strings/decimal.c	2011-02-28 17:39:30 +0000
+++ strings/decimal.c	2011-04-29 09:52:28 +0000
@@ -255,7 +255,7 @@
 }
 
 
-static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result)
+static dec1 *remove_leading_zeroes(const decimal_t *from, int *intg_result)
 {
   int intg= from->intg, i;
   dec1 *buf0= from->buf;
@@ -333,7 +333,7 @@
     E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
 */
 
-int decimal2string(decimal_t *from, char *to, int *to_len,
+int decimal2string(const decimal_t *from, char *to, int *to_len,
                    int fixed_precision, int fixed_decimals,
                    char filler)
 {
@@ -949,7 +949,7 @@
     E_DEC_OK
 */
 
-int decimal2double(decimal_t *from, double *to)
+int decimal2double(const decimal_t *from, double *to)
 {
   double result= 0.0;
   int i, exp= 0;
@@ -1041,7 +1041,7 @@
   return ull2dec(from, to);
 }
 
-int decimal2ulonglong(decimal_t *from, ulonglong *to)
+int decimal2ulonglong(const decimal_t *from, ulonglong *to)
 {
   dec1 *buf=from->buf;
   ulonglong x=0;
@@ -1070,7 +1070,7 @@
   return E_DEC_OK;
 }
 
-int decimal2longlong(decimal_t *from, longlong *to)
+int decimal2longlong(const decimal_t *from, longlong *to)
 {
   dec1 *buf=from->buf;
   longlong x=0;
@@ -1189,7 +1189,7 @@
 
                 7E F2 04 37 2D FB 2D
 */
-int decimal2bin(decimal_t *from, uchar *to, int precision, int frac)
+int decimal2bin(const decimal_t *from, uchar *to, int precision, int frac)
 {
   dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1;
   int error=E_DEC_OK, intg=precision-frac,
@@ -1479,7 +1479,7 @@
 */
 
 int
-decimal_round(decimal_t *from, decimal_t *to, int scale,
+decimal_round(const decimal_t *from, decimal_t *to, int scale,
               decimal_round_mode mode)
 {
   int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1,

=== modified file 'unittest/mysys/Makefile.am'
--- unittest/mysys/Makefile.am	2010-11-30 21:11:03 +0000
+++ unittest/mysys/Makefile.am	2011-04-29 09:52:28 +0000
@@ -25,4 +25,4 @@
 
 EXTRA_DIST       = CMakeLists.txt 
 noinst_PROGRAMS  = bitmap-t base64-t my_atomic-t lf-t waiting_threads-t \
-		   my_vsnprintf-t
+		   my_vsnprintf-t ma_dyncol-t

=== added file 'unittest/mysys/ma_dyncol-t.c'
--- unittest/mysys/ma_dyncol-t.c	1970-01-01 00:00:00 +0000
+++ unittest/mysys/ma_dyncol-t.c	2011-04-29 09:52:28 +0000
@@ -0,0 +1,767 @@
+#include <my_global.h>
+#include <ma_dyncol.h>
+#include <tap.h>
+
+
+
+void test_value_single_null()
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_NULL;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_NULL);
+err:
+  ok(rc, "%s", "NULL");
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_uint(ulonglong num, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_UINT;
+  val.ulong_value= num;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_UINT) && (res.ulong_value == num);
+  num= res.ulong_value;
+err:
+  ok(rc, "%s - %llu", name, num);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_sint(longlong num, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_INT;
+  val.long_value= num;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_INT) && (res.long_value == num);
+  num= res.ulong_value;
+err:
+  ok(rc, "%s - %lld", name, num);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_single_double(double num, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_DOUBLE;
+  val.double_value= num;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= (res.type == DYN_COL_DOUBLE) && (res.double_value == num);
+  num= res.ulong_value;
+err:
+  ok(rc, "%s - %lf", name, num);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_decimal(const char *num)
+{
+  char *end= (((char*)num) + strlen(num));
+  char buff[80];
+  int rc= FALSE;
+  int length= 80;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+
+  /* init values */
+  dynamic_column_prepare_decimal(&val); // special procedure for decimal!!!
+  if (string2decimal(num, &val.decimal_value, &end) != E_DEC_OK)
+    goto err;
+  dynamic_column_value_init(&res);
+
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_DECIMAL) &&
+       (decimal_cmp(&res.decimal_value, &val.decimal_value) == 0));
+  decimal2string(&res.decimal_value, buff, &length, 0, 0, ' ');
+err:
+  ok(rc, "%s - %s", num, buff);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+static CHARSET_INFO *charset_list[]=
+{
+#ifdef HAVE_CHARSET_big5
+  &my_charset_big5_chinese_ci,
+  &my_charset_big5_bin,
+#endif
+#ifdef HAVE_CHARSET_euckr
+  &my_charset_euckr_korean_ci,
+  &my_charset_euckr_bin,
+#endif
+#ifdef HAVE_CHARSET_gb2312
+  &my_charset_gb2312_chinese_ci,
+  &my_charset_gb2312_bin,
+#endif
+#ifdef HAVE_CHARSET_gbk
+  &my_charset_gbk_chinese_ci,
+  &my_charset_gbk_bin,
+#endif
+#ifdef HAVE_CHARSET_latin1
+  &my_charset_latin1,
+  &my_charset_latin1_bin,
+#endif
+#ifdef HAVE_CHARSET_sjis
+  &my_charset_sjis_japanese_ci,
+  &my_charset_sjis_bin,
+#endif
+#ifdef HAVE_CHARSET_tis620
+  &my_charset_tis620_thai_ci,
+  &my_charset_tis620_bin,
+#endif
+#ifdef HAVE_CHARSET_ujis
+  &my_charset_ujis_japanese_ci,
+  &my_charset_ujis_bin,
+#endif
+#ifdef HAVE_CHARSET_utf8
+  &my_charset_utf8_general_ci,
+#ifdef HAVE_HAVE_UCA_COLLATIONS
+  &my_charset_utf8_unicode_ci,
+#endif
+  &my_charset_utf8_bin,
+#endif
+};
+
+
+void test_value_single_string(const char *string, size_t len,
+                              CHARSET_INFO *cs)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+
+  /* init values */
+  val.type= DYN_COL_STRING;
+  val.string_value.str= (char*)string;
+  val.string_value.length= len;
+  val.charset= cs;
+  dynamic_column_value_init(&res);
+
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_STRING) &&
+       (res.string_value.length == len) &&
+       (memcmp(res.string_value.str, string, len) == 0) &&
+       (res.charset->number == cs->number));
+err:
+  ok(rc, "'%s' - '%s' %u %u-%s", string,
+     res.string_value.str, (uint)res.string_value.length,
+     (uint)res.charset->number, res.charset->name);
+  /* cleanup */
+  val.string_value.str= NULL; // we did not allocated it
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_date(uint year, uint month, uint day, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_DATE;
+  val.time_value.time_type= MYSQL_TIMESTAMP_DATE;
+  val.time_value.year= year;
+  val.time_value.month= month;
+  val.time_value.day= day;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_DATE) &&
+       (res.time_value.time_type == MYSQL_TIMESTAMP_DATE) &&
+       (res.time_value.year == year) &&
+       (res.time_value.month == month) &&
+       (res.time_value.day == day));
+err:
+  ok(rc, "%s - %04u-%02u-%02u", name, year, month, day);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_value_single_time(uint neg, uint hour, uint minute, uint second,
+                            uint mic, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_TIME;
+  val.time_value.time_type= MYSQL_TIMESTAMP_TIME;
+  val.time_value.neg= neg;
+  val.time_value.hour= hour;
+  val.time_value.minute= minute;
+  val.time_value.second= second;
+  val.time_value.second_part= mic;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_TIME) &&
+       (res.time_value.time_type == MYSQL_TIMESTAMP_TIME) &&
+       (res.time_value.neg == (int)neg) &&
+       (res.time_value.hour == hour) &&
+       (res.time_value.minute == minute) &&
+       (res.time_value.second == second) &&
+       (res.time_value.second_part == mic));
+err:
+  ok(rc, "%s - %c%02u:%02u:%02u.%06u", name, (neg ? '-' : '+'),
+     hour, minute, second, mic);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_single_datetime(uint neg, uint year, uint month, uint day,
+                                uint hour, uint minute, uint second,
+                                uint mic, const char *name)
+{
+  int rc= FALSE;
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val.type= DYN_COL_DATETIME;
+  val.time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+  val.time_value.neg= neg;
+  val.time_value.year= year;
+  val.time_value.month= month;
+  val.time_value.day= day;
+  val.time_value.hour= hour;
+  val.time_value.minute= minute;
+  val.time_value.second= second;
+  val.time_value.second_part= mic;
+  dynamic_column_value_init(&res);
+  /* create column */
+  if (dynamic_column_create(&str, 1, &val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  if (dynamic_column_get(&str, 1, &res))
+    goto err;
+  rc= ((res.type == DYN_COL_DATETIME) &&
+       (res.time_value.time_type == MYSQL_TIMESTAMP_DATETIME) &&
+       (res.time_value.neg == (int)neg) &&
+       (res.time_value.year == year) &&
+       (res.time_value.month == month) &&
+       (res.time_value.day == day) &&
+       (res.time_value.hour == hour) &&
+       (res.time_value.minute == minute) &&
+       (res.time_value.second == second) &&
+       (res.time_value.second_part == mic));
+err:
+  ok(rc, "%s - %c %04u-%02u-%02u %02u:%02u:%02u.%06u", name, (neg ? '-' : '+'),
+     year, month, day, hour, minute, second, mic);
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_multi(ulonglong num0,
+                      longlong num1,
+                      double num2,
+                      const char *num3,
+                      const char *string4, size_t len4, CHARSET_INFO *cs4,
+                      uint year5, uint month5, uint day5,
+                      uint neg6, uint hour6, uint minute6,
+                      uint second6, uint mic6,
+                      uint neg7, uint year7, uint month7, uint day7,
+                      uint hour7, uint minute7, uint second7,
+                      uint mic7,
+                      uint *column_numbers,
+                      const char *name)
+{
+  char *end3= (((char*)num3) + strlen(num3));
+  int rc= FALSE;
+  uint i;
+  DYNAMIC_COLUMN_VALUE val[9], res[9];
+  DYNAMIC_COLUMN str;
+  /* init values */
+  val[0].type= DYN_COL_UINT;
+  val[0].ulong_value= num0;
+  val[1].type= DYN_COL_INT;
+  val[1].long_value= num1;
+  val[2].type= DYN_COL_DOUBLE;
+  val[2].double_value= num2;
+  dynamic_column_prepare_decimal(val + 3); // special procedure for decimal!!!
+  if (string2decimal(num3, &val[3].decimal_value, &end3) != E_DEC_OK)
+    goto err;
+  val[4].type= DYN_COL_STRING;
+  val[4].string_value.str= (char*)string4;
+  val[4].string_value.length= len4;
+  val[4].charset= cs4;
+  val[5].type= DYN_COL_DATE;
+  val[5].time_value.time_type= MYSQL_TIMESTAMP_DATE;
+  val[5].time_value.year= year5;
+  val[5].time_value.month= month5;
+  val[5].time_value.day= day5;
+  val[6].type= DYN_COL_TIME;
+  val[6].time_value.time_type= MYSQL_TIMESTAMP_TIME;
+  val[6].time_value.neg= neg6;
+  val[6].time_value.hour= hour6;
+  val[6].time_value.minute= minute6;
+  val[6].time_value.second= second6;
+  val[6].time_value.second_part= mic6;
+  val[7].type= DYN_COL_DATETIME;
+  val[7].time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
+  val[7].time_value.neg= neg7;
+  val[7].time_value.year= year7;
+  val[7].time_value.month= month7;
+  val[7].time_value.day= day7;
+  val[7].time_value.hour= hour7;
+  val[7].time_value.minute= minute7;
+  val[7].time_value.second= second7;
+  val[7].time_value.second_part= mic7;
+  val[8].type= DYN_COL_NULL;
+  for (i= 0; i < 9; i++)
+    dynamic_column_value_init(res + i);
+  /* create column */
+  if (dynamic_column_create_many(&str, 9, column_numbers, val))
+    goto err;
+  dynstr_append(&str, "\1"); str.length--; //check for overflow
+  /* read column */
+  for (i= 0; i < 9; i++)
+    if (dynamic_column_get(&str, column_numbers[i], res + i))
+      goto err;
+  rc= ((res[0].type == DYN_COL_UINT) &&
+       (res[0].ulong_value == num0) &&
+       (res[1].type == DYN_COL_INT) &&
+       (res[1].long_value == num1) &&
+       (res[2].type == DYN_COL_DOUBLE) &&
+       (res[2].double_value == num2) &&
+       (res[3].type == DYN_COL_DECIMAL) &&
+       (decimal_cmp(&res[3].decimal_value, &val[3].decimal_value) == 0) &&
+       (res[4].type == DYN_COL_STRING) &&
+       (res[4].string_value.length == len4) &&
+       (memcmp(res[4].string_value.str, string4, len4) == 0) &&
+       (res[4].charset->number == cs4->number) &&
+       (res[5].type == DYN_COL_DATE) &&
+       (res[5].time_value.time_type == MYSQL_TIMESTAMP_DATE) &&
+       (res[5].time_value.year == year5) &&
+       (res[5].time_value.month == month5) &&
+       (res[5].time_value.day == day5) &&
+       (res[6].type == DYN_COL_TIME) &&
+       (res[6].time_value.time_type == MYSQL_TIMESTAMP_TIME) &&
+       (res[6].time_value.neg == (int)neg6) &&
+       (res[6].time_value.hour == hour6) &&
+       (res[6].time_value.minute == minute6) &&
+       (res[6].time_value.second == second6) &&
+       (res[6].time_value.second_part == mic6) &&
+       (res[7].type == DYN_COL_DATETIME) &&
+       (res[7].time_value.time_type == MYSQL_TIMESTAMP_DATETIME) &&
+       (res[7].time_value.neg == (int)neg7) &&
+       (res[7].time_value.year == year7) &&
+       (res[7].time_value.month == month7) &&
+       (res[7].time_value.day == day7) &&
+       (res[7].time_value.hour == hour7) &&
+       (res[7].time_value.minute == minute7) &&
+       (res[7].time_value.second == second7) &&
+       (res[7].time_value.second_part == mic7) &&
+       (res[8].type == DYN_COL_NULL));
+err:
+  ok(rc, "%s", name);
+  /* cleanup */
+  val[4].string_value.str= NULL; // we did not allocated it
+  dynamic_column_column_free(&str);
+}
+
+
+void test_value_multi_same_num()
+{
+  int rc= FALSE;
+  uint i;
+  DYNAMIC_COLUMN_VALUE val[5];
+  uint column_numbers[]= {3,4,5,3,6}; // same column numbers
+  DYNAMIC_COLUMN str;
+  /* init values */
+  for (i= 0; i < 5; i++)
+    val[i].type= DYN_COL_NULL;
+  /* create column */
+  if (!dynamic_column_create_many(&str, 5, column_numbers, val))
+    goto err;
+  rc= TRUE;
+err:
+  ok(rc, "%s", "same column numbers check");
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+
+void test_update_multi(uint *column_numbers, uint *column_values,
+                       my_bool *null_values, int only_add, int all)
+{
+  int rc= FALSE;
+  int i, j;
+  DYNAMIC_COLUMN str;
+  DYNAMIC_COLUMN_VALUE val;
+
+  val.type= DYN_COL_UINT;
+  val.ulong_value= column_values[0];
+  if (dynamic_column_create(&str, column_numbers[0], &val))
+    goto err;
+  for (i= 1; i < all; i++)
+  {
+    val.type= (null_values[i] ? DYN_COL_NULL : DYN_COL_UINT);
+    val.ulong_value= column_values[i];
+    if (dynamic_column_update(&str, column_numbers[i], &val))
+      goto err;
+
+    /* check value(s) */
+    for (j= i; j >= (i < only_add ? 0 : i); j--)
+    {
+      if (dynamic_column_get(&str, column_numbers[j], &val))
+        goto err;
+      if (null_values[j])
+      {
+        if (val.type != DYN_COL_NULL ||
+            dynamic_column_exists(&str, column_numbers[j]) == ER_DYNCOL_YES)
+          goto err;
+      }
+      else
+      {
+        if (val.type != DYN_COL_UINT ||
+            val.ulong_value != column_values[j] ||
+            dynamic_column_exists(&str, column_numbers[j]) == ER_DYNCOL_NO)
+          goto err;
+      }
+    }
+    if (i < only_add)
+    {
+      DYNAMIC_ARRAY num;
+      if (dynamic_column_list(&str, &num))
+        goto err;
+      /* cross check arrays */
+      if ((int)num.elements != i + 1)
+      {
+        delete_dynamic(&num);
+        goto err;
+      }
+      for(j= 0; j < i + 1; j++)
+      {
+        int k;
+        for(k= 0;
+            k < i + 1 && column_numbers[j] !=
+            *dynamic_element(&num, k, uint*);
+            k++);
+        if (k >= i + 1)
+        {
+          delete_dynamic(&num);
+          goto err;
+        }
+        for(k= 0;
+            k < i + 1 && column_numbers[k] !=
+            *dynamic_element(&num, j, uint*);
+            k++);
+        if (k >= i + 1)
+        {
+          delete_dynamic(&num);
+          goto err;
+        }
+      }
+      delete_dynamic(&num);
+    }
+  }
+
+  rc= TRUE;
+err:
+  ok(rc, "%s", "add/delete/update");
+  /* cleanup */
+  dynamic_column_column_free(&str);
+}
+
+void test_empty_string()
+{
+  DYNAMIC_COLUMN_VALUE val, res;
+  DYNAMIC_COLUMN str;
+  DYNAMIC_ARRAY array_of_uint;
+  int rc;
+  /* empty string */
+  bzero(&str, sizeof(str));
+
+  rc= dynamic_column_get(&str, 1, &res);
+  ok( (rc == ER_DYNCOL_OK) && (res.type == DYN_COL_NULL), "%s", "empty get");
+
+  rc= dynamic_column_delete(&str, 1);
+  ok( (rc == ER_DYNCOL_OK), "%s", "empty delete");
+
+  rc= dynamic_column_exists(&str, 1);
+  ok( (rc == ER_DYNCOL_NO), "%s", "empty exists");
+
+  rc= dynamic_column_list(&str, &array_of_uint);
+  ok( (rc == ER_DYNCOL_OK) && (array_of_uint.elements == 0),
+      "%s", "empty list");
+
+  val.type= DYN_COL_UINT;
+  val.ulong_value= 1212;
+  rc= dynamic_column_update(&str, 1, &val);
+  if (rc == ER_DYNCOL_OK)
+    rc= dynamic_column_get(&str, 1, &res);
+  ok( (rc == ER_DYNCOL_OK) &&
+      (res.type == DYN_COL_UINT) && (res.ulong_value == val.ulong_value),
+      "%s", "empty update");
+}
+
+
+void test_update_many(uint *column_numbers, uint *column_values,
+                      uint column_count,
+                      uint *update_numbers, uint *update_values,
+                      my_bool *update_nulls, uint update_count,
+                      uint *result_numbers, uint *result_values,
+                      uint result_count)
+{
+  int rc= FALSE;
+  uint i;
+  DYNAMIC_COLUMN str1;
+  DYNAMIC_COLUMN str2;
+  DYNAMIC_COLUMN_VALUE *val, *upd, *res;
+
+  val= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE) *
+                                      column_count);
+  upd= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE) *
+                                      update_count);
+  res= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE) *
+                                      result_count);
+
+
+  for (i= 0; i < column_count; i++)
+  {
+    val[i].type= DYN_COL_UINT;
+    val[i].ulong_value= column_values[i];
+  }
+  for (i= 0; i < update_count; i++)
+  {
+    if (update_nulls[i])
+      upd[i].type= DYN_COL_NULL;
+    else
+    {
+      upd[i].type= DYN_COL_UINT;
+      upd[i].ulong_value= update_values[i];
+    }
+  }
+  for (i= 0; i < result_count; i++)
+  {
+    res[i].type= DYN_COL_UINT;
+    res[i].ulong_value= result_values[i];
+  }
+  if (dynamic_column_create_many(&str1, column_count, column_numbers, val))
+    goto err;
+  if (dynamic_column_update_many(&str1, update_count, update_numbers, upd))
+    goto err;
+  if (dynamic_column_create_many(&str2, result_count, result_numbers, res))
+    goto err;
+  if (str1.length == str2.length &&
+      memcmp(str1.str, str2.str, str1.length) ==0)
+    rc= TRUE;
+
+err:
+  ok(rc, "%s", "update_many");
+  /* cleanup */
+  dynamic_column_column_free(&str1);
+  dynamic_column_column_free(&str2);
+}
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+  uint i;
+  char *big_string= (char *)malloc(1024*1024);
+
+  MY_INIT(argv[0]);
+  plan(59);
+
+  if (!big_string)
+    exit(1);
+  for (i= 0; i < 1024*1024; i++)
+    big_string[i]= ('0' + (i % 10));
+  test_value_single_null();
+  test_value_single_uint(0, "0");
+  test_value_single_uint(0xffffffffffffffff, "0xffffffffffffffff");
+  test_value_single_uint(0xaaaaaaaaaaaaaaaa, "0xaaaaaaaaaaaaaaaa");
+  test_value_single_uint(0x5555555555555555, "0x5555555555555555");
+  test_value_single_uint(27652, "27652");
+  test_value_single_sint(0, "0");
+  test_value_single_sint(1, "1");
+  test_value_single_sint(-1, "-1");
+  test_value_single_sint((longlong)0x7fffffffffffffff,
+                         "0x7fffffffffffffff");
+  test_value_single_sint((longlong)0xaaaaaaaaaaaaaaaa,
+                         "0xaaaaaaaaaaaaaaaa");
+  test_value_single_sint((longlong)0x5555555555555555,
+                         "0x5555555555555555");
+  test_value_single_sint((longlong)0x8000000000000000,
+                         "0x8000000000000000");
+  test_value_single_double(0.0, "0.0");
+  test_value_single_double(1.0, "1.0");
+  test_value_single_double(-1.0, "-1.0");
+  test_value_single_double(1.0e100, "1.0e100");
+  test_value_single_double(1.0e-100, "1.0e-100");
+  test_value_single_double(9999999999999999999999999999999999999.0,
+                           "9999999999999999999999999999999999999.0");
+  test_value_single_double(-9999999999999999999999999999999999999.0,
+                           "-9999999999999999999999999999999999999.0");
+  test_value_single_decimal("0");
+  test_value_single_decimal("1");
+  test_value_single_decimal("-1");
+  test_value_single_decimal("9999999999999999999999999999999");
+  test_value_single_decimal("-9999999999999999999999999999999");
+  test_value_single_decimal("0.9999999999999999999999999999999");
+  test_value_single_decimal("-0.9999999999999999999999999999999");
+  test_value_single_string("", 0, charset_list[0]);
+  test_value_single_string("", 1, charset_list[0]);
+  test_value_single_string("1234567890", 11, charset_list[0]);
+  test_value_single_string("nulls\0\0\0\0\0", 10, charset_list[0]);
+  sprintf(big_string, "%x", 0x7a);
+  test_value_single_string(big_string, 0x7a, charset_list[0]);
+  sprintf(big_string, "%x", 0x80);
+  test_value_single_string(big_string, 0x80, charset_list[0]);
+  sprintf(big_string, "%x", 0x7ffa);
+  test_value_single_string(big_string, 0x7ffa, charset_list[0]);
+  sprintf(big_string, "%x", 0x8000);
+  test_value_single_string(big_string, 0x8000, charset_list[0]);
+  sprintf(big_string, "%x", 1024*1024);
+  test_value_single_string(big_string, 1024*1024, charset_list[0]);
+  free(big_string);
+  test_value_single_date(0, 0, 0, "zero date");
+  test_value_single_date(9999, 12, 31, "max date");
+  test_value_single_date(2011, 3, 26, "some date");
+  test_value_single_time(0, 0, 0, 0, 0, "zero time");
+  test_value_single_time(1, 23, 59, 59, 999999, "min time");
+  test_value_single_time(0, 23, 59, 59, 999999, "max time");
+  test_value_single_time(0, 21, 36, 20, 28, "some time");
+  test_value_single_datetime(0, 0, 0, 0, 0, 0, 0, 0, "zero datetime");
+  test_value_single_datetime(1, 9999, 12, 31, 23, 59, 59, 999999,
+                             "min datetime");
+  test_value_single_datetime(0, 9999, 12, 31, 23, 59, 59, 999999,
+                             "max datetime");
+  test_value_single_datetime(0, 2011, 3, 26, 21, 53, 12, 3445,
+                             "some datetime");
+  {
+    uint column_numbers[]= {100,1,2,3,4,5,6,7,8};
+    test_value_multi(0, 0, 0.0, "0",
+                     "", 0, charset_list[0],
+                     0, 0, 0,
+                     0, 0, 0, 0, 0,
+                     0, 0, 0, 0, 0, 0, 0, 0,
+                     column_numbers,
+                     "zero data");
+  }
+  {
+    uint column_numbers[]= {10,1,12,37,4,57,6,76,87};
+    test_value_multi(0xffffffffffffffff, 0x7fffffffffffffff,
+                     99999999.999e120, "9999999999999999999999999999999",
+                     big_string, 1024*1024, charset_list[0],
+                     9999, 12, 31,
+                     0, 23, 59, 59, 999999,
+                     0, 9999, 12, 31, 23, 59, 59, 999999,
+                     column_numbers,
+                     "much data");
+  }
+  {
+    uint column_numbers[]= {101,12,122,37,24,572,16,726,77};
+    test_value_multi(37878, -3344,
+                     2873.3874, "92743.238984789898",
+                     "string", 6, charset_list[0],
+                     2011, 3, 26,
+                     1, 23, 23, 20, 333,
+                     0, 2011, 3, 26, 23, 23, 53, 334,
+                     column_numbers,
+                     "zero data");
+  }
+  test_value_multi_same_num();
+  {
+    uint column_numbers[]= {1,2,3,4,5,6,7,2, 3, 4};
+    uint column_values[]=  {1,2,3,4,5,6,7,0,30,40};
+    my_bool null_values[]= {0,0,0,0,0,0,0,1, 0, 0};
+
+    test_update_multi(column_numbers, column_values, null_values, 7, 10);
+  }
+  {
+    uint column_numbers[]= {4,3,2,1, 1,2,3,4};
+    uint column_values[]=  {4,3,2,1, 0,0,0,0};
+    my_bool null_values[]= {0,0,0,0, 1,1,1,1};
+
+    test_update_multi(column_numbers, column_values, null_values, 4, 8);
+  }
+  {
+    uint column_numbers[]= {4,3,2,1, 4,3,2,1};
+    uint column_values[]=  {4,3,2,1, 0,0,0,0};
+    my_bool null_values[]= {0,0,0,0, 1,1,1,1};
+
+    test_update_multi(column_numbers, column_values, null_values, 4, 8);
+  }
+  test_empty_string();
+  {
+    uint column_numbers[]= {1, 2, 3};
+    uint column_values[]=  {1, 2, 3};
+    uint update_numbers[]= {4, 3, 2, 1};
+    uint update_values[]=  {40,30, 0,10};
+    my_bool update_nulls[]={0, 0, 1, 0};
+    uint result_numbers[]= {1, 3, 4};
+    uint result_values[]=  {10,30,40};
+    test_update_many(column_numbers, column_values, 3,
+                     update_numbers, update_values, update_nulls, 4,
+                     result_numbers, result_values, 3);
+  }
+  return 0;
+}