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

ChangeSet@stripped, 2006-12-01 23:01:33+01:00, istruewing@stripped +5 -0
  Merge chilla.local:/home/mydev/mysql-5.0-axmrg
  into  chilla.local:/home/mydev/mysql-5.1-axmrg
  MERGE: 1.1810.1698.179

  configure.in@stripped, 2006-12-01 23:01:28+01:00, istruewing@stripped +0 -0
    Auto merged
    MERGE: 1.245.1.166

  mysql-test/r/federated.result@stripped, 2006-12-01 23:01:28+01:00, istruewing@stripped +0 -0
    Auto merged
    MERGE: 1.25.1.15

  mysql-test/t/federated.test@stripped, 2006-12-01 23:01:28+01:00, istruewing@stripped +0 -0
    Auto merged
    MERGE: 1.19.1.16

  storage/federated/ha_federated.cc@stripped, 2006-12-01 23:01:28+01:00, istruewing@stripped +0 -0
    Auto merged
    MERGE: 1.24.17.2

  storage/federated/ha_federated.cc@stripped, 2006-12-01 23:01:27+01:00, istruewing@stripped +0 -0
    Merge rename: sql/ha_federated.cc -> storage/federated/ha_federated.cc

  storage/myisam/mi_dynrec.c@stripped, 2006-12-01 23:01:28+01:00, istruewing@stripped +0 -0
    Auto merged
    MERGE: 1.37.11.2

  storage/myisam/mi_dynrec.c@stripped, 2006-12-01 23:01:27+01:00, istruewing@stripped +0 -0
    Merge rename: myisam/mi_dynrec.c -> storage/myisam/mi_dynrec.c

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	istruewing
# Host:	chilla.local
# Root:	/home/mydev/mysql-5.1-axmrg/RESYNC

--- 1.37.11.1/myisam/mi_dynrec.c	2006-12-01 23:01:40 +01:00
+++ 1.52/storage/myisam/mi_dynrec.c	2006-12-01 23:01:40 +01:00
@@ -50,6 +50,180 @@ static int _mi_cmp_buffer(File file, con
 
 	/* Interface function from MI_INFO */
 
+#ifdef HAVE_MMAP
+
+/*
+  Create mmaped area for MyISAM handler
+
+  SYNOPSIS
+    mi_dynmap_file()
+    info		MyISAM handler
+
+  RETURN
+    0  ok
+    1  error.
+*/
+
+my_bool mi_dynmap_file(MI_INFO *info, my_off_t size)
+{
+  DBUG_ENTER("mi_dynmap_file");
+  if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
+  {
+    DBUG_PRINT("warning", ("File is too large for mmap"));
+    DBUG_RETURN(1);
+  }
+  info->s->file_map= (byte*)
+                  my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
+                          info->s->mode==O_RDONLY ? PROT_READ :
+                          PROT_READ | PROT_WRITE,
+                          MAP_SHARED | MAP_NORESERVE,
+                          info->dfile, 0L);
+  if (info->s->file_map == (byte*) MAP_FAILED)
+  {
+    info->s->file_map= NULL;
+    DBUG_RETURN(1);
+  }
+#if defined(HAVE_MADVISE)
+  madvise(info->s->file_map, size, MADV_RANDOM);
+#endif
+  info->s->mmaped_length= size;
+  DBUG_RETURN(0);
+}
+
+
+/*
+  Resize mmaped area for MyISAM handler
+
+  SYNOPSIS
+    mi_remap_file()
+    info		MyISAM handler
+
+  RETURN
+*/
+
+void mi_remap_file(MI_INFO *info, my_off_t size)
+{
+  if (info->s->file_map)
+  {
+    VOID(my_munmap(info->s->file_map,
+                   (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
+    mi_dynmap_file(info, size);
+  }
+}
+#endif
+
+
+/*
+  Read bytes from MySAM handler, using mmap or pread
+
+  SYNOPSIS
+    mi_mmap_pread()
+    info		MyISAM handler
+    Buffer              Input buffer
+    Count               Count of bytes for read
+    offset              Start position
+    MyFlags             
+
+  RETURN
+    0  ok
+*/
+
+uint mi_mmap_pread(MI_INFO *info, byte *Buffer,
+                    uint Count, my_off_t offset, myf MyFlags)
+{
+  DBUG_PRINT("info", ("mi_read with mmap %d\n", info->dfile));
+  if (info->s->concurrent_insert)
+    rw_rdlock(&info->s->mmap_lock);
+
+  /*
+    The following test may fail in the following cases:
+    - We failed to remap a memory area (fragmented memory?)
+    - This thread has done some writes, but not yet extended the
+    memory mapped area.
+  */
+
+  if (info->s->mmaped_length >= offset + Count)
+  {
+    memcpy(Buffer, info->s->file_map + offset, Count);
+    if (info->s->concurrent_insert)
+      rw_unlock(&info->s->mmap_lock);
+    return 0;
+  }
+  else
+  {
+    if (info->s->concurrent_insert)
+      rw_unlock(&info->s->mmap_lock);
+    return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
+  }
+}
+
+
+        /* wrapper for my_pread in case if mmap isn't used */
+
+uint mi_nommap_pread(MI_INFO *info, byte *Buffer,
+                      uint Count, my_off_t offset, myf MyFlags)
+{
+  return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
+}
+
+
+/*
+  Write bytes to MySAM handler, using mmap or pwrite
+
+  SYNOPSIS
+    mi_mmap_pwrite()
+    info		MyISAM handler
+    Buffer              Output buffer
+    Count               Count of bytes for write
+    offset              Start position
+    MyFlags             
+
+  RETURN
+    0  ok
+    !=0  error.  In this case return error from pwrite
+*/
+
+uint mi_mmap_pwrite(MI_INFO *info, byte *Buffer,
+                     uint Count, my_off_t offset, myf MyFlags)
+{
+  DBUG_PRINT("info", ("mi_write with mmap %d\n", info->dfile));
+  if (info->s->concurrent_insert)
+    rw_rdlock(&info->s->mmap_lock);
+
+  /*
+    The following test may fail in the following cases:
+    - We failed to remap a memory area (fragmented memory?)
+    - This thread has done some writes, but not yet extended the
+    memory mapped area.
+  */
+
+  if (info->s->mmaped_length >= offset + Count)
+  {
+    memcpy(info->s->file_map + offset, Buffer, Count); 
+    if (info->s->concurrent_insert)
+      rw_unlock(&info->s->mmap_lock);
+    return 0;
+  }
+  else
+  {
+    info->s->nonmmaped_inserts++;
+    if (info->s->concurrent_insert)
+      rw_unlock(&info->s->mmap_lock);
+    return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
+  }
+
+}
+
+
+        /* wrapper for my_pwrite in case if mmap isn't used */
+
+uint mi_nommap_pwrite(MI_INFO *info, byte *Buffer,
+                      uint Count, my_off_t offset, myf MyFlags)
+{
+  return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
+}
+
+
 int _mi_write_dynamic_record(MI_INFO *info, const byte *record)
 {
   ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
@@ -243,7 +417,7 @@ static bool unlink_deleted_block(MI_INFO
 	  & BLOCK_DELETED))
       DBUG_RETURN(1);				/* Something is wrong */
     mi_sizestore(tmp.header+4,block_info->next_filepos);
-    if (my_pwrite(info->dfile,(char*) tmp.header+4,8,
+    if (info->s->file_write(info,(char*) tmp.header+4,8,
 		  block_info->prev_filepos+4, MYF(MY_NABP)))
       DBUG_RETURN(1);
     /* Unlink block from next block */
@@ -253,7 +427,7 @@ static bool unlink_deleted_block(MI_INFO
 	    & BLOCK_DELETED))
 	DBUG_RETURN(1);				/* Something is wrong */
       mi_sizestore(tmp.header+12,block_info->prev_filepos);
-      if (my_pwrite(info->dfile,(char*) tmp.header+12,8,
+      if (info->s->file_write(info,(char*) tmp.header+12,8,
 		    block_info->next_filepos+12,
 		    MYF(MY_NABP)))
 	DBUG_RETURN(1);
@@ -304,7 +478,7 @@ static int update_backward_delete_link(M
     {
       char buff[8];
       mi_sizestore(buff,filepos);
-      if (my_pwrite(info->dfile,buff, 8, delete_block+12, MYF(MY_NABP)))
+      if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
 	DBUG_RETURN(1);				/* Error on write */
     }
     else
@@ -362,7 +536,7 @@ static int delete_dynamic_record(MI_INFO
       bfill(block_info.header+12,8,255);
     else
       mi_sizestore(block_info.header+12,block_info.next_filepos);
-    if (my_pwrite(info->dfile,(byte*) block_info.header,20,filepos,
+    if (info->s->file_write(info,(byte*) block_info.header,20,filepos,
 		  MYF(MY_NABP)))
       DBUG_RETURN(1);
     info->s->state.dellink = filepos;
@@ -545,7 +719,7 @@ int _mi_write_part_record(MI_INFO *info,
   else
   {
     info->rec_cache.seek_not_done=1;
-    if (my_pwrite(info->dfile,(byte*) *record-head_length,length+extra_length+
+    if (info->s->file_write(info,(byte*) *record-head_length,length+extra_length+
 		  del_length,filepos,info->s->write_flag))
       goto err;
   }
@@ -655,7 +829,7 @@ static int update_dynamic_record(MI_INFO
 	      mi_int3store(del_block.header+1, rest_length);
 	      mi_sizestore(del_block.header+4,info->s->state.dellink);
 	      bfill(del_block.header+12,8,255);
-	      if (my_pwrite(info->dfile,(byte*) del_block.header,20, next_pos,
+	      if (info->s->file_write(info,(byte*) del_block.header,20, next_pos,
 			    MYF(MY_NABP)))
 		DBUG_RETURN(1);
 	      info->s->state.dellink= next_pos;
@@ -1237,7 +1411,13 @@ int _mi_read_dynamic_record(MI_INFO *inf
             info->rec_cache.pos_in_file < filepos + block_info.data_len &&
             flush_io_cache(&info->rec_cache))
           goto err;
-        if (my_read(file, (byte*) to, block_info.data_len, MYF(MY_NABP)))
+        /*
+          What a pity that this method is not called 'file_pread' and that
+          there is no equivalent without seeking. We are at the right
+          position already. :(
+        */
+        if (info->s->file_read(info, (byte*) to, block_info.data_len,
+                               filepos, MYF(MY_NABP)))
           goto panic;
         left_length-=block_info.data_len;
         to+=block_info.data_len;

--- 1.43/mysql-test/r/federated.result	2006-12-01 23:01:40 +01:00
+++ 1.44/mysql-test/r/federated.result	2006-12-01 23:01:40 +01:00
@@ -1815,6 +1815,34 @@ engine = federated
 connection='mysql://root@stripped:SLAVE_PORT/federated/test';
 drop table federated.test1, federated.test2;
 drop table federated.test;
+set names utf8;
+create table federated.t1 (a varchar(64)) DEFAULT CHARSET=utf8;
+insert into federated.t1 values (0x6DC3A56E6164);
+select hex(a) from federated.t1;
+hex(a)
+6DC3A56E6164
+create table federated.t1 (a varchar(64))
+ENGINE=FEDERATED 
+connection='mysql://root@stripped:SLAVE_PORT/federated/t1'
+DEFAULT CHARSET=utf8;
+set names utf8;
+select hex(a) from federated.t1;
+hex(a)
+6DC3A56E6164
+insert into federated.t1 values (0xC3A4C3B6C3BCC39F);
+insert into federated.t1 values (0xD18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E);
+select hex(a) from federated.t1;
+hex(a)
+6DC3A56E6164
+C3A4C3B6C3BCC39F
+D18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E
+select hex(a) from federated.t1;
+hex(a)
+6DC3A56E6164
+C3A4C3B6C3BCC39F
+D18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E
+drop table federated.t1;
+drop table federated.t1;
 DROP TABLE IF EXISTS federated.t1;
 DROP DATABASE IF EXISTS federated;
 DROP TABLE IF EXISTS federated.t1;

--- 1.35/mysql-test/t/federated.test	2006-12-01 23:01:40 +01:00
+++ 1.36/mysql-test/t/federated.test	2006-12-01 23:01:40 +01:00
@@ -1598,4 +1598,36 @@ drop table federated.test1, federated.te
 connection slave;
 drop table federated.test;
 
+#
+# BUG# 17044 Federated Storage Engine not UTF8 clean
+#
+connection slave;
+set names utf8;
+create table federated.t1 (a varchar(64)) DEFAULT CHARSET=utf8;
+
+insert into federated.t1 values (0x6DC3A56E6164);
+select hex(a) from federated.t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval create table federated.t1 (a varchar(64))
+ENGINE=FEDERATED 
+connection='mysql://root@stripped:$SLAVE_MYPORT/federated/t1'
+DEFAULT CHARSET=utf8;
+set names utf8;
+select hex(a) from federated.t1;
+insert into federated.t1 values (0xC3A4C3B6C3BCC39F);
+insert into federated.t1 values (0xD18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E);
+select hex(a) from federated.t1;
+
+connection slave;
+select hex(a) from federated.t1;
+
+connection master;
+drop table federated.t1;
+
+connection slave;
+drop table federated.t1;
+
+
 source include/federated_cleanup.inc;

--- 1.24.17.1/sql/ha_federated.cc	2006-12-01 23:01:40 +01:00
+++ 1.91/storage/federated/ha_federated.cc	2006-12-01 23:01:40 +01:00
@@ -333,51 +333,50 @@
 */
 
 
+#define MYSQL_SERVER 1
 #include "mysql_priv.h"
+#include <mysql/plugin.h>
+
 #ifdef USE_PRAGMA_IMPLEMENTATION
 #pragma implementation                          // gcc: Class implementation
 #endif
 
-#ifdef HAVE_FEDERATED_DB
 #include "ha_federated.h"
 
 #include "m_string.h"
+
+#include <mysql/plugin.h>
+
 /* Variables for federated share methods */
-static HASH federated_open_tables;              // Hash used to track open
-                                                // tables
-pthread_mutex_t federated_mutex;                // This is the mutex we use to
-                                                // init the hash
-static int federated_init= FALSE;               // Variable for checking the
-                                                // init state of hash
+static HASH federated_open_tables;              // To track open tables
+pthread_mutex_t federated_mutex;                // To init the hash
+
+/* Variables used when chopping off trailing characters */
+static const uint sizeof_trailing_comma= sizeof(", ") - 1;
+static const uint sizeof_trailing_closeparen= sizeof(") ") - 1;
+static const uint sizeof_trailing_and= sizeof(" AND ") - 1;
+static const uint sizeof_trailing_where= sizeof(" WHERE ") - 1;
+
+/* Static declaration for handerton */
+static handler *federated_create_handler(handlerton *hton,
+                                         TABLE_SHARE *table,
+                                         MEM_ROOT *mem_root);
+static int federated_commit(handlerton *hton, THD *thd, bool all);
+static int federated_rollback(handlerton *hton, THD *thd, bool all);
+static int federated_db_init(void);
+
 
 /* Federated storage engine handlerton */
 
-handlerton federated_hton= {
-  "FEDERATED",
-  SHOW_OPTION_YES,
-  "Federated MySQL storage engine", 
-  DB_TYPE_FEDERATED_DB,
-  federated_db_init,
-  0,       /* slot */
-  0,       /* savepoint size. */
-  NULL,    /* close_connection */
-  NULL,    /* savepoint */
-  NULL,    /* rollback to savepoint */
-  NULL,    /* release savepoint */
-  NULL,    /* commit */
-  NULL,    /* rollback */
-  NULL,    /* prepare */
-  NULL,    /* recover */
-  NULL,    /* commit_by_xid */
-  NULL,    /* rollback_by_xid */
-  NULL,    /* create_cursor_read_view */
-  NULL,    /* set_cursor_read_view */
-  NULL,    /* close_cursor_read_view */
-  HTON_ALTER_NOT_SUPPORTED
-};
+static handler *federated_create_handler(handlerton *hton, 
+                                         TABLE_SHARE *table,
+                                         MEM_ROOT *mem_root)
+{
+  return new (mem_root) ha_federated(hton, table);
+}
 
 
-/* Function we use in the creation of our hash to get key.  */
+/* Function we use in the creation of our hash to get key */
 
 static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
                                my_bool not_used __attribute__ ((unused)))
@@ -398,23 +397,27 @@ static byte *federated_get_key(FEDERATED
     TRUE        Error
 */
 
-bool federated_db_init()
+int federated_db_init(void *p)
 {
   DBUG_ENTER("federated_db_init");
+  handlerton *federated_hton= (handlerton *)p;
+  federated_hton->state= SHOW_OPTION_YES;
+  federated_hton->db_type= DB_TYPE_FEDERATED_DB;
+  federated_hton->commit= federated_commit;
+  federated_hton->rollback= federated_rollback;
+  federated_hton->create= federated_create_handler;
+  federated_hton->flags= HTON_ALTER_NOT_SUPPORTED;
+
   if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST))
     goto error;
-  if (hash_init(&federated_open_tables, &my_charset_bin, 32, 0, 0,
+  if (!hash_init(&federated_open_tables, &my_charset_bin, 32, 0, 0,
                     (hash_get_key) federated_get_key, 0, 0))
   {
-    VOID(pthread_mutex_destroy(&federated_mutex));
-  }
-  else
-  {
-    federated_init= TRUE;
     DBUG_RETURN(FALSE);
   }
+
+  VOID(pthread_mutex_destroy(&federated_mutex));
 error:
-  have_federated_db= SHOW_OPTION_DISABLED;	// If we couldn't use handler
   DBUG_RETURN(TRUE);
 }
 
@@ -424,23 +427,20 @@ error:
 
   SYNOPSIS
     federated_db_end()
-    void
 
   RETURN
     FALSE       OK
 */
 
-bool federated_db_end()
+int federated_done(void *p)
 {
-  if (federated_init)
-  {
-    hash_free(&federated_open_tables);
-    VOID(pthread_mutex_destroy(&federated_mutex));
-  }
-  federated_init= 0;
-  return FALSE;
+  hash_free(&federated_open_tables);
+  VOID(pthread_mutex_destroy(&federated_mutex));
+
+  return 0;
 }
 
+
 /*
  Check (in create) whether the tables exists, and that it can be connected to
 
@@ -515,19 +515,14 @@ static int check_foreign_data_source(FED
 
       the query will be: SELECT * FROM `tablename` WHERE 1=0
     */
-    query.append(FEDERATED_SELECT);
-    query.append(FEDERATED_STAR);
-    query.append(FEDERATED_FROM);
-    query.append(FEDERATED_BTICK);
+    query.append(STRING_WITH_LEN("SELECT * FROM `"));
     escaped_table_name_length=
       escape_string_for_mysql(&my_charset_bin, (char*)escaped_table_name,
                             sizeof(escaped_table_name),
                             share->table_name,
                             share->table_name_length);
     query.append(escaped_table_name, escaped_table_name_length);
-    query.append(FEDERATED_BTICK);
-    query.append(FEDERATED_WHERE);
-    query.append(FEDERATED_FALSE);
+    query.append(STRING_WITH_LEN("` WHERE 1=0"));
 
     if (mysql_real_query(mysql, query.ptr(), query.length()))
     {
@@ -574,12 +569,12 @@ static int parse_url_error(FEDERATED_SHA
 
   SYNOPSIS
     parse_url()
-      share               pointer to FEDERATED share
-      table               pointer to current TABLE class
-      table_create_flag   determines what error to throw
+    share               pointer to FEDERATED share
+    table               pointer to current TABLE class
+    table_create_flag   determines what error to throw
 
   DESCRIPTION
-    populates the share with information about the connection
+    Populates the share with information about the connection
     to the foreign database that will serve as the data source.
     This string must be specified (currently) in the "comment" field,
     listed in the CREATE TABLE statement.
@@ -598,7 +593,7 @@ static int parse_url_error(FEDERATED_SHA
   ***IMPORTANT***
   Currently, only "mysql://" is supported.
 
-    'password' and 'port' are both optional.
+  'password' and 'port' are both optional.
 
   RETURN VALUE
     0           success
@@ -616,12 +611,12 @@ static int parse_url(FEDERATED_SHARE *sh
 
   share->port= 0;
   share->socket= 0;
-  DBUG_PRINT("info", ("Length %d \n", table->s->connect_string.length));
-  DBUG_PRINT("info", ("String %.*s \n", table->s->connect_string.length, 
+  DBUG_PRINT("info", ("Length: %d", table->s->connect_string.length));
+  DBUG_PRINT("info", ("String: '%.*s'", table->s->connect_string.length, 
                       table->s->connect_string.str));
-  share->scheme= my_strdup_with_length(table->s->connect_string.str,
-                                       table->s->connect_string.length,
-                                       MYF(0));
+  share->scheme= my_strndup(table->s->connect_string.str,
+                            table->s->connect_string.length,
+                            MYF(0));
 
   share->connect_string_length= table->s->connect_string.length;
   DBUG_PRINT("info",("parse_url alloced share->scheme 0x%lx", (long) share->scheme));
@@ -706,8 +701,8 @@ static int parse_url(FEDERATED_SHARE *sh
   }
 
   DBUG_PRINT("info",
-             ("scheme %s username %s password %s \
-              hostname %s port %d database %s tablename %s\n",
+             ("scheme: %s  username: %s  password: %s \
+               hostname: %s  port: %d  database: %s  tablename: %s",
               share->scheme, share->username, share->password,
               share->hostname, share->port, share->database,
               share->table_name));
@@ -723,10 +718,13 @@ error:
 ** FEDERATED tables
 *****************************************************************************/
 
-ha_federated::ha_federated(TABLE *table_arg)
-  :handler(&federated_hton, table_arg),
+ha_federated::ha_federated(handlerton *hton,
+                           TABLE_SHARE *table_arg)
+  :handler(hton, table_arg),
   mysql(0), stored_result(0)
-{}
+{
+  trx_next= 0;
+}
 
 
 /*
@@ -747,7 +745,7 @@ ha_federated::ha_federated(TABLE *table_
 
   RETURN VALUE
     0   After fields have had field values stored from record
- */
+*/
 
 uint ha_federated::convert_row_to_internal_format(byte *record,
                                                   MYSQL_ROW row,
@@ -755,39 +753,42 @@ uint ha_federated::convert_row_to_intern
 {
   ulong *lengths;
   Field **field;
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
   DBUG_ENTER("ha_federated::convert_row_to_internal_format");
 
   lengths= mysql_fetch_lengths(result);
 
-  for (field= table->field; *field; field++)
+  for (field= table->field; *field; field++, row++, lengths++)
   {
     /*
       index variable to move us through the row at the
       same iterative step as the field
     */
-    int x= field - table->field;
     my_ptrdiff_t old_ptr;
     old_ptr= (my_ptrdiff_t) (record - table->record[0]);
-    (*field)->move_field(old_ptr);
-    if (!row[x])
+    (*field)->move_field_offset(old_ptr);
+    if (!*row)
       (*field)->set_null();
     else
     {
-      (*field)->set_notnull();
-      (*field)->store(row[x], lengths[x], &my_charset_bin);
+      if (bitmap_is_set(table->read_set, (*field)->field_index))
+      {
+        (*field)->set_notnull();
+        (*field)->store(*row, *lengths, &my_charset_bin);
+      }
     }
-    (*field)->move_field(-old_ptr);
+    (*field)->move_field_offset(-old_ptr);
   }
-
+  dbug_tmp_restore_column_map(table->write_set, old_map);
   DBUG_RETURN(0);
 }
 
 static bool emit_key_part_name(String *to, KEY_PART_INFO *part)
 {
   DBUG_ENTER("emit_key_part_name");
-  if (to->append(FEDERATED_BTICK) ||
+  if (to->append(STRING_WITH_LEN("`")) ||
       to->append(part->field->field_name) ||
-      to->append(FEDERATED_BTICK))
+      to->append(STRING_WITH_LEN("`")))
     DBUG_RETURN(1);                           // Out of memory
   DBUG_RETURN(0);
 }
@@ -799,7 +800,7 @@ static bool emit_key_part_element(String
   Field *field= part->field;
   DBUG_ENTER("emit_key_part_element");
 
-  if (needs_quotes && to->append(FEDERATED_SQUOTE))
+  if (needs_quotes && to->append(STRING_WITH_LEN("'")))
     DBUG_RETURN(1);
 
   if (part->type == HA_KEYTYPE_BIT)
@@ -846,10 +847,10 @@ static bool emit_key_part_element(String
       DBUG_RETURN(1);
   }
 
-  if (is_like && to->append(FEDERATED_PERCENT))
+  if (is_like && to->append(STRING_WITH_LEN("%")))
     DBUG_RETURN(1);
 
-  if (needs_quotes && to->append(FEDERATED_SQUOTE))
+  if (needs_quotes && to->append(STRING_WITH_LEN("'")))
     DBUG_RETURN(1);
 
   DBUG_RETURN(0);
@@ -1097,22 +1098,25 @@ bool ha_federated::create_where_from_key
                                          KEY *key_info,
                                          const key_range *start_key,
                                          const key_range *end_key,
-                                         bool records_in_range)
+                                         bool records_in_range,
+                                         bool eq_range)
 {
-  bool both_not_null= 
+  bool both_not_null=
     (start_key != NULL && end_key != NULL) ? TRUE : FALSE;
   const byte *ptr;
   uint remainder, length;
   char tmpbuff[FEDERATED_QUERY_BUFFER_SIZE];
   String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info);
   const key_range *ranges[2]= { start_key, end_key };
+  my_bitmap_map *old_map;
   DBUG_ENTER("ha_federated::create_where_from_key");
 
   tmp.length(0); 
   if (start_key == NULL && end_key == NULL)
     DBUG_RETURN(1);
 
-  for (int i= 0; i <= 1; i++)
+  old_map= dbug_tmp_use_all_columns(table, table->write_set);
+  for (uint i= 0; i <= 1; i++)
   {
     bool needs_quotes;
     KEY_PART_INFO *key_part;
@@ -1122,9 +1126,9 @@ bool ha_federated::create_where_from_key
     if (both_not_null)
     {
       if (i > 0)
-        tmp.append(FEDERATED_CONJUNCTION);
+        tmp.append(STRING_WITH_LEN(") AND ("));
       else
-        tmp.append(FEDERATED_OPENPAREN);
+        tmp.append(STRING_WITH_LEN(" ("));
     }
 
     for (key_part= key_info->key_part,
@@ -1137,7 +1141,7 @@ bool ha_federated::create_where_from_key
       Field *field= key_part->field;
       uint store_length= key_part->store_length;
       uint part_length= min(store_length, length);
-      needs_quotes= 1;
+      needs_quotes= field->str_needs_quotes();
       DBUG_DUMP("key, start of loop", (char *) ptr, length);
 
       if (key_part->null_bit)
@@ -1145,17 +1149,17 @@ bool ha_federated::create_where_from_key
         if (*ptr++)
         {
           if (emit_key_part_name(&tmp, key_part) ||
-              tmp.append(FEDERATED_ISNULL))
-            DBUG_RETURN(1);
+              tmp.append(STRING_WITH_LEN(" IS NULL ")))
+            goto err;
           continue;
         }
       }
 
-      if (tmp.append(FEDERATED_OPENPAREN))
-        DBUG_RETURN(1);
+      if (tmp.append(STRING_WITH_LEN(" (")))
+        goto err;
 
-      switch(ranges[i]->flag) {
-      case(HA_READ_KEY_EXACT):
+      switch (ranges[i]->flag) {
+      case HA_READ_KEY_EXACT:
         DBUG_PRINT("info", ("federated HA_READ_KEY_EXACT %d", i));
         if (store_length >= length ||
             !needs_quotes ||
@@ -1163,118 +1167,129 @@ bool ha_federated::create_where_from_key
             field->result_type() != STRING_RESULT)
         {
           if (emit_key_part_name(&tmp, key_part))
-            DBUG_RETURN(1);
+            goto err;
 
           if (records_in_range)
           {
-            if (tmp.append(FEDERATED_GE))
-              DBUG_RETURN(1);
+            if (tmp.append(STRING_WITH_LEN(" >= ")))
+              goto err;
           }
           else
           {
-            if (tmp.append(FEDERATED_EQ))
-              DBUG_RETURN(1);
+            if (tmp.append(STRING_WITH_LEN(" = ")))
+              goto err;
           }
 
           if (emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
                                     part_length))
-            DBUG_RETURN(1);
+            goto err;
         }
         else
-          /* LIKE */
         {
+          /* LIKE */
           if (emit_key_part_name(&tmp, key_part) ||
-              tmp.append(FEDERATED_LIKE) ||
+              tmp.append(STRING_WITH_LEN(" LIKE ")) ||
               emit_key_part_element(&tmp, key_part, needs_quotes, 1, ptr,
                                     part_length))
-            DBUG_RETURN(1);
+            goto err;
         }
         break;
-      case(HA_READ_AFTER_KEY):
+      case HA_READ_AFTER_KEY:
+        if (eq_range)
+        {
+          if (tmp.append("1=1"))                // Dummy
+            goto err;
+          break;
+        }
         DBUG_PRINT("info", ("federated HA_READ_AFTER_KEY %d", i));
         if (store_length >= length) /* end key */
         {
           if (emit_key_part_name(&tmp, key_part))
-            DBUG_RETURN(1);
+            goto err;
 
           if (i > 0) /* end key */
           {
-            if (tmp.append(FEDERATED_LE))
-              DBUG_RETURN(1);
+            if (tmp.append(STRING_WITH_LEN(" <= ")))
+              goto err;
           }
           else /* start key */
           {
-            if (tmp.append(FEDERATED_GT))
-              DBUG_RETURN(1);
+            if (tmp.append(STRING_WITH_LEN(" > ")))
+              goto err;
           }
 
           if (emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
                                     part_length))
           {
-            DBUG_RETURN(1);
+            goto err;
           }
           break;
         }
-      case(HA_READ_KEY_OR_NEXT):
+      case HA_READ_KEY_OR_NEXT:
         DBUG_PRINT("info", ("federated HA_READ_KEY_OR_NEXT %d", i));
         if (emit_key_part_name(&tmp, key_part) ||
-            tmp.append(FEDERATED_GE) ||
+            tmp.append(STRING_WITH_LEN(" >= ")) ||
             emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
               part_length))
-          DBUG_RETURN(1);
+          goto err;
         break;
-      case(HA_READ_BEFORE_KEY):
+      case HA_READ_BEFORE_KEY:
         DBUG_PRINT("info", ("federated HA_READ_BEFORE_KEY %d", i));
         if (store_length >= length)
         {
           if (emit_key_part_name(&tmp, key_part) ||
-              tmp.append(FEDERATED_LT) ||
+              tmp.append(STRING_WITH_LEN(" < ")) ||
               emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
                                     part_length))
-            DBUG_RETURN(1);
+            goto err;
           break;
         }
-      case(HA_READ_KEY_OR_PREV):
+      case HA_READ_KEY_OR_PREV:
         DBUG_PRINT("info", ("federated HA_READ_KEY_OR_PREV %d", i));
         if (emit_key_part_name(&tmp, key_part) ||
-            tmp.append(FEDERATED_LE) ||
+            tmp.append(STRING_WITH_LEN(" <= ")) ||
             emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr,
                                   part_length))
-          DBUG_RETURN(1);
+          goto err;
         break;
       default:
         DBUG_PRINT("info",("cannot handle flag %d", ranges[i]->flag));
-        DBUG_RETURN(1);
+        goto err;
       }
-      if (tmp.append(FEDERATED_CLOSEPAREN))
-        DBUG_RETURN(1);
+      if (tmp.append(STRING_WITH_LEN(") ")))
+        goto err;
 
-next_loop:
       if (store_length >= length)
         break;
       DBUG_PRINT("info", ("remainder %d", remainder));
       DBUG_ASSERT(remainder > 1);
       length-= store_length;
       ptr+= store_length;
-      if (tmp.append(FEDERATED_AND))
-        DBUG_RETURN(1);
+      if (tmp.append(STRING_WITH_LEN(" AND ")))
+        goto err;
 
       DBUG_PRINT("info",
                  ("create_where_from_key WHERE clause: %s",
                   tmp.c_ptr_quick()));
     }
   }
+  dbug_tmp_restore_column_map(table->write_set, old_map);
+
   if (both_not_null)
-    if (tmp.append(FEDERATED_CLOSEPAREN))
+    if (tmp.append(STRING_WITH_LEN(") ")))
       DBUG_RETURN(1);
 
-  if (to->append(FEDERATED_WHERE))
+  if (to->append(STRING_WITH_LEN(" WHERE ")))
     DBUG_RETURN(1);
 
   if (to->append(tmp))
     DBUG_RETURN(1);
 
   DBUG_RETURN(0);
+
+err:
+  dbug_tmp_restore_column_map(table->write_set, old_map);
+  DBUG_RETURN(1);
 }
 
 /*
@@ -1293,7 +1308,7 @@ static FEDERATED_SHARE *get_share(const 
   /*
     In order to use this string, we must first zero it's length,
     or it will contain garbage
-   */
+  */
   query.length(0);
 
   pthread_mutex_lock(&federated_mutex);
@@ -1308,17 +1323,17 @@ static FEDERATED_SHARE *get_share(const 
                                                connect_string_length)))
   {
     query.set_charset(system_charset_info);
-    query.append(FEDERATED_SELECT);
+    query.append(STRING_WITH_LEN("SELECT "));
     for (field= table->field; *field; field++)
     {
-      query.append(FEDERATED_BTICK);
+      query.append(STRING_WITH_LEN("`"));
       query.append((*field)->field_name);
-      query.append(FEDERATED_BTICK);
-      query.append(FEDERATED_COMMA);
+      query.append(STRING_WITH_LEN("`, "));
     }
-    query.length(query.length()- strlen(FEDERATED_COMMA));
-    query.append(FEDERATED_FROM);
-    query.append(FEDERATED_BTICK);
+    /* chops off trailing comma */
+    query.length(query.length() - sizeof_trailing_comma);
+
+    query.append(STRING_WITH_LEN(" FROM `"));
 
     if (!(share= (FEDERATED_SHARE *)
           my_multi_malloc(MYF(MY_WME),
@@ -1333,7 +1348,7 @@ static FEDERATED_SHARE *get_share(const 
     share->table_name_length= strlen(share->table_name);
     /* TODO: share->table_name to LEX_STRING object */
     query.append(share->table_name, share->table_name_length);
-    query.append(FEDERATED_BTICK);
+    query.append(STRING_WITH_LEN("`"));
     share->select_query= select_query;
     strmov(share->select_query, query.ptr());
     share->use_count= 0;
@@ -1522,7 +1537,7 @@ int ha_federated::close(void)
       0    otherwise
 */
 
-inline uint field_in_record_is_null(TABLE *table,
+static inline uint field_in_record_is_null(TABLE *table,
                                     Field *field,
                                     char *record)
 {
@@ -1540,6 +1555,7 @@ inline uint field_in_record_is_null(TABL
   DBUG_RETURN(0);
 }
 
+
 /*
   write_row() inserts a row. No extra() hint is given currently if a bulk load
   is happeneding. buf() is a byte array of data. You can use the field
@@ -1556,6 +1572,62 @@ inline uint field_in_record_is_null(TABL
 
 int ha_federated::write_row(byte *buf)
 {
+  /*
+    I need a bool again, in 5.0, I used table->s->fields to accomplish this.
+    This worked as a flag that says there are fields with values or not.
+    In 5.1, this value doesn't work the same, and I end up with the code
+    truncating open parenthesis:
+
+    the statement "INSERT INTO t1 VALUES ()" ends up being first built
+    in two strings
+      "INSERT INTO t1 ("
+      and
+      " VALUES ("
+
+    If there are fields with values, they get appended, with commas, and 
+    the last loop, a trailing comma is there
+
+    "INSERT INTO t1 ( col1, col2, colN, "
+
+    " VALUES ( 'val1', 'val2', 'valN', "
+
+    Then, if there are fields, it should decrement the string by ", " length.
+
+    "INSERT INTO t1 ( col1, col2, colN"
+    " VALUES ( 'val1', 'val2', 'valN'"
+
+    Then it adds a close paren to both - if there are fields
+
+    "INSERT INTO t1 ( col1, col2, colN)"
+    " VALUES ( 'val1', 'val2', 'valN')"
+
+    Then appends both together
+    "INSERT INTO t1 ( col1, col2, colN) VALUES ( 'val1', 'val2', 'valN')"
+
+    So... the problem, is if you have the original statement:
+
+    "INSERT INTO t1 VALUES ()"
+
+    Which is legitimate, but if the code thinks there are fields
+
+    "INSERT INTO t1 ("
+    " VALUES ( "
+
+    If the field flag is set, but there are no commas, reduces the 
+    string by strlen(", ")
+
+    "INSERT INTO t1 "
+    " VALUES "
+
+    Then adds the close parenthesis
+
+    "INSERT INTO t1  )"
+    " VALUES  )"
+
+    So, I have to use a bool as before, set in the loop where fields and commas
+    are appended to the string
+  */
+  my_bool commas_added= FALSE;
   char insert_buffer[FEDERATED_QUERY_BUFFER_SIZE];
   char values_buffer[FEDERATED_QUERY_BUFFER_SIZE];
   char insert_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
@@ -1569,11 +1641,12 @@ int ha_federated::write_row(byte *buf)
   String insert_field_value_string(insert_field_value_buffer,
                                    sizeof(insert_field_value_buffer),
                                    &my_charset_bin);
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+  DBUG_ENTER("ha_federated::write_row");
+
   values_string.length(0);
   insert_string.length(0);
   insert_field_value_string.length(0);
-  DBUG_ENTER("ha_federated::write_row");
-
   statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
   if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
     table->timestamp_field->set_time();
@@ -1581,68 +1654,72 @@ int ha_federated::write_row(byte *buf)
   /*
     start both our field and field values strings
   */
-  insert_string.append(FEDERATED_INSERT);
-  insert_string.append(FEDERATED_BTICK);
+  insert_string.append(STRING_WITH_LEN("INSERT INTO `"));
   insert_string.append(share->table_name, share->table_name_length);
-  insert_string.append(FEDERATED_BTICK);
-  insert_string.append(FEDERATED_OPENPAREN);
+  insert_string.append('`');
+  insert_string.append(STRING_WITH_LEN(" ("));
 
-  values_string.append(FEDERATED_VALUES);
-  values_string.append(FEDERATED_OPENPAREN);
+  values_string.append(STRING_WITH_LEN(" VALUES "));
+  values_string.append(STRING_WITH_LEN(" ("));
 
   /*
     loop through the field pointer array, add any fields to both the values
-    list and the fields list that match the current query id
+    list and the fields list that is part of the write set
   */
   for (field= table->field; *field; field++)
   {
-    if ((*field)->is_null())
-      insert_field_value_string.append(FEDERATED_NULL);
-    else
+    if (bitmap_is_set(table->write_set, (*field)->field_index))
     {
-      (*field)->val_str(&insert_field_value_string);
-      values_string.append('\'');
-      insert_field_value_string.print(&values_string);
-      values_string.append('\'');
-
-      insert_field_value_string.length(0);
-    }
-    /* append the field name */
-    insert_string.append((*field)->field_name);
+      commas_added= TRUE;
+      if ((*field)->is_null())
+        values_string.append(STRING_WITH_LEN(" NULL "));
+      else
+      {
+        bool needs_quote= (*field)->str_needs_quotes();
+        (*field)->val_str(&insert_field_value_string);
+        if (needs_quote)
+          values_string.append('\'');
+        insert_field_value_string.print(&values_string);
+        if (needs_quote)
+          values_string.append('\'');
 
-    /* append the value */
-    values_string.append(insert_field_value_string);
-    insert_field_value_string.length(0);
+        insert_field_value_string.length(0);
+      }
+      /* append the field name */
+      insert_string.append((*field)->field_name);
 
-    /* append commas between both fields and fieldnames */
-    /*
-      unfortunately, we can't use the logic
-      if *(fields + 1) to make the following
-      appends conditional because we may not append
-      if the next field doesn't match the condition:
-      (((*field)->query_id && (*field)->query_id == current_query_id)
-    */
-    insert_string.append(FEDERATED_COMMA);
-    values_string.append(FEDERATED_COMMA);
+      /* append commas between both fields and fieldnames */
+      /*
+        unfortunately, we can't use the logic if *(fields + 1) to
+        make the following appends conditional as we don't know if the
+        next field is in the write set
+      */
+      insert_string.append(STRING_WITH_LEN(", "));
+      values_string.append(STRING_WITH_LEN(", "));
+    }
   }
+  dbug_tmp_restore_column_map(table->read_set, old_map);
 
   /*
-    remove trailing comma
-  */
-  insert_string.length(insert_string.length() - strlen(FEDERATED_COMMA));
-  /*
     if there were no fields, we don't want to add a closing paren
     AND, we don't want to chop off the last char '('
     insert will be "INSERT INTO t1 VALUES ();"
   */
-  if (table->s->fields)
+  if (commas_added)
   {
+    insert_string.length(insert_string.length() - sizeof_trailing_comma);
     /* chops off leading commas */
-    values_string.length(values_string.length() - strlen(FEDERATED_COMMA));
-    insert_string.append(FEDERATED_CLOSEPAREN);
+    values_string.length(values_string.length() - sizeof_trailing_comma);
+    insert_string.append(STRING_WITH_LEN(") "));
+  }
+  else
+  {
+    /* chops off trailing ) */
+    insert_string.length(insert_string.length() - sizeof_trailing_closeparen);
   }
+
   /* we always want to append this, even if there aren't any fields */
-  values_string.append(FEDERATED_CLOSEPAREN);
+  values_string.append(STRING_WITH_LEN(") "));
 
   /* add the values */
   insert_string.append(values_string);
@@ -1667,15 +1744,16 @@ int ha_federated::write_row(byte *buf)
   This method ensures that last_insert_id() works properly. What it simply does
   is calls last_insert_id() on the foreign database immediately after insert
   (if the table has an auto_increment field) and sets the insert id via
-  thd->insert_id(ID) (as well as storing thd->prev_insert_id)
+  thd->insert_id(ID)).
 */
 void ha_federated::update_auto_increment(void)
 {
   THD *thd= current_thd;
   DBUG_ENTER("ha_federated::update_auto_increment");
 
-  thd->insert_id(mysql->last_used_con->insert_id);
-  DBUG_PRINT("info",("last_insert_id: %ld", (long) auto_increment_value));
+  thd->first_successful_insert_id_in_cur_stmt= 
+    mysql->last_used_con->insert_id;
+  DBUG_PRINT("info",("last_insert_id: %ld", (long) stats.auto_increment_value));
 
   DBUG_VOID_RETURN;
 }
@@ -1689,10 +1767,9 @@ int ha_federated::optimize(THD* thd, HA_
   query.length(0);
 
   query.set_charset(system_charset_info);
-  query.append(FEDERATED_OPTIMIZE);
-  query.append(FEDERATED_BTICK);
+  query.append(STRING_WITH_LEN("OPTIMIZE TABLE `"));
   query.append(share->table_name, share->table_name_length);
-  query.append(FEDERATED_BTICK);
+  query.append(STRING_WITH_LEN("`"));
 
   if (mysql_real_query(mysql, query.ptr(), query.length()))
   {
@@ -1712,16 +1789,15 @@ int ha_federated::repair(THD* thd, HA_CH
   query.length(0);
 
   query.set_charset(system_charset_info);
-  query.append(FEDERATED_REPAIR);
-  query.append(FEDERATED_BTICK);
+  query.append(STRING_WITH_LEN("REPAIR TABLE `"));
   query.append(share->table_name, share->table_name_length);
-  query.append(FEDERATED_BTICK);
+  query.append(STRING_WITH_LEN("`"));
   if (check_opt->flags & T_QUICK)
-    query.append(FEDERATED_QUICK);
+    query.append(STRING_WITH_LEN(" QUICK"));
   if (check_opt->flags & T_EXTEND)
-    query.append(FEDERATED_EXTENDED);
+    query.append(STRING_WITH_LEN(" EXTENDED"));
   if (check_opt->sql_flags & TT_USEFRM)
-    query.append(FEDERATED_USE_FRM);
+    query.append(STRING_WITH_LEN(" USE_FRM"));
 
   if (mysql_real_query(mysql, query.ptr(), query.length()))
   {
@@ -1738,7 +1814,7 @@ int ha_federated::repair(THD* thd, HA_CH
   it.
 
   Keep in mind that the server can do updates based on ordering if an ORDER BY
-  clause was used. Consecutive ordering is not guarenteed.
+  clause was used. Consecutive ordering is not guaranteed.
   Currently new_data will not have an updated auto_increament record, or
   and updated timestamp field. You can do these for federated by doing these:
   if (table->timestamp_on_update_now)
@@ -1763,8 +1839,9 @@ int ha_federated::update_row(const byte 
     this? Because we only are updating one record, and LIMIT enforces
     this.
   */
-  bool has_a_primary_key= (table->s->primary_key == 0 ? TRUE : FALSE);
-  /* 
+  bool has_a_primary_key= test(table->s->primary_key != MAX_KEY);
+  
+  /*
     buffers for following strings
   */
   char field_value_buffer[STRING_BUFFER_USUAL_SIZE];
@@ -1782,79 +1859,94 @@ int ha_federated::update_row(const byte 
   String where_string(where_buffer,
                       sizeof(where_buffer),
                       &my_charset_bin);
+  byte *record= table->record[0];
   DBUG_ENTER("ha_federated::update_row");
-  /* 
+  /*
     set string lengths to 0 to avoid misc chars in string
   */
   field_value.length(0);
   update_string.length(0);
   where_string.length(0);
 
-  update_string.append(FEDERATED_UPDATE);
-  update_string.append(FEDERATED_BTICK);
+  update_string.append(STRING_WITH_LEN("UPDATE `"));
   update_string.append(share->table_name);
-  update_string.append(FEDERATED_BTICK);
-  update_string.append(FEDERATED_SET);
+  update_string.append(STRING_WITH_LEN("` SET "));
 
-/*
-  In this loop, we want to match column names to values being inserted
-  (while building INSERT statement).
+  /*
+    In this loop, we want to match column names to values being inserted
+    (while building INSERT statement).
 
-  Iterate through table->field (new data) and share->old_field (old_data)
-  using the same index to create an SQL UPDATE statement. New data is
-  used to create SET field=value and old data is used to create WHERE
-  field=oldvalue
- */
+    Iterate through table->field (new data) and share->old_field (old_data)
+    using the same index to create an SQL UPDATE statement. New data is
+    used to create SET field=value and old data is used to create WHERE
+    field=oldvalue
+  */
 
   for (Field **field= table->field; *field; field++)
   {
-    where_string.append((*field)->field_name);
-    update_string.append((*field)->field_name);
-    update_string.append(FEDERATED_EQ);
-
-    if ((*field)->is_null())
-      update_string.append(FEDERATED_NULL);
-    else
+    if (bitmap_is_set(table->write_set, (*field)->field_index))
     {
-      /* otherwise = */
-      (*field)->val_str(&field_value);
-      update_string.append('\'');
-      field_value.print(&update_string);
-      update_string.append('\'');
-      field_value.length(0);
-    }
+      update_string.append((*field)->field_name);
+      update_string.append(STRING_WITH_LEN(" = "));
 
-    if (field_in_record_is_null(table, *field, (char*) old_data))
-      where_string.append(FEDERATED_ISNULL);
-    else
-    {
-      where_string.append(FEDERATED_EQ);
-      (*field)->val_str(&field_value,
-                        (char*) (old_data + (*field)->offset()));
-      where_string.append('\'');
-      field_value.print(&where_string);
-      where_string.append('\'');
-      field_value.length(0);
+      if ((*field)->is_null())
+        update_string.append(STRING_WITH_LEN(" NULL "));
+      else
+      {
+        /* otherwise = */
+        my_bitmap_map *old_map= tmp_use_all_columns(table, table->read_set);
+        bool needs_quote= (*field)->str_needs_quotes();
+	(*field)->val_str(&field_value);
+        if (needs_quote)
+          update_string.append('\'');
+        field_value.print(&update_string);
+        if (needs_quote)
+          update_string.append('\'');
+        field_value.length(0);
+        tmp_restore_column_map(table->read_set, old_map);
+      }
+      update_string.append(STRING_WITH_LEN(", "));
     }
 
-    /*
-      Only append conjunctions if we have another field in which
-      to iterate
-    */
-    if (*(field + 1))
+    if (bitmap_is_set(table->read_set, (*field)->field_index))
     {
-      update_string.append(FEDERATED_COMMA);
-      where_string.append(FEDERATED_AND);
+      where_string.append((*field)->field_name);
+      if (field_in_record_is_null(table, *field, (char*) old_data))
+        where_string.append(STRING_WITH_LEN(" IS NULL "));
+      else
+      {
+        bool needs_quote= (*field)->str_needs_quotes();
+        where_string.append(STRING_WITH_LEN(" = "));
+        (*field)->val_str(&field_value,
+                          (char*) (old_data + (*field)->offset(record)));
+        if (needs_quote)
+          where_string.append('\'');
+        field_value.print(&where_string);
+        if (needs_quote)
+          where_string.append('\'');
+        field_value.length(0);
+      }
+      where_string.append(STRING_WITH_LEN(" AND "));
     }
   }
-  update_string.append(FEDERATED_WHERE);
-  update_string.append(where_string);
+
+  /* Remove last ', '. This works as there must be at least on updated field */
+  update_string.length(update_string.length() - sizeof_trailing_comma);
+
+  if (where_string.length())
+  {
+    /* chop off trailing AND */
+    where_string.length(where_string.length() - sizeof_trailing_and);
+    update_string.append(STRING_WITH_LEN(" WHERE "));
+    update_string.append(where_string);
+  }
+
   /*
     If this table has not a primary key, then we could possibly
     update multiple rows. We want to make sure to only update one!
   */
   if (!has_a_primary_key)
-    update_string.append(FEDERATED_LIMIT1);
+    update_string.append(STRING_WITH_LEN(" LIMIT 1"));
 
   if (mysql_real_query(mysql, update_string.ptr(), update_string.length()))
   {
@@ -1882,54 +1974,60 @@ int ha_federated::delete_row(const byte 
 {
   char delete_buffer[FEDERATED_QUERY_BUFFER_SIZE];
   char data_buffer[FEDERATED_QUERY_BUFFER_SIZE];
-
   String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin);
   String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin);
+  uint found= 0;
   DBUG_ENTER("ha_federated::delete_row");
 
   delete_string.length(0);
-  delete_string.append(FEDERATED_DELETE);
-  delete_string.append(FEDERATED_FROM);
-  delete_string.append(FEDERATED_BTICK);
+  delete_string.append(STRING_WITH_LEN("DELETE FROM `"));
   delete_string.append(share->table_name);
-  delete_string.append(FEDERATED_BTICK);
-  delete_string.append(FEDERATED_WHERE);
+  delete_string.append(STRING_WITH_LEN("` WHERE "));
 
   for (Field **field= table->field; *field; field++)
   {
     Field *cur_field= *field;
-    data_string.length(0);
-    delete_string.append(cur_field->field_name);
-
-    if (cur_field->is_null())
+    found++;
+    if (bitmap_is_set(table->read_set, cur_field->field_index))
     {
-      delete_string.append(FEDERATED_ISNULL);
-    }
-    else
-    {
-      delete_string.append(FEDERATED_EQ);
-      cur_field->val_str(&data_string);
-      delete_string.append('\'');
-      data_string.print(&delete_string);
-      delete_string.append('\'');
+      data_string.length(0);
+      delete_string.append(cur_field->field_name);
+      if (cur_field->is_null())
+      {
+        delete_string.append(STRING_WITH_LEN(" IS NULL "));
+      }
+      else
+      {
+        bool needs_quote= cur_field->str_needs_quotes();
+        delete_string.append(STRING_WITH_LEN(" = "));
+        cur_field->val_str(&data_string);
+        if (needs_quote)
+          delete_string.append('\'');
+        data_string.print(&delete_string);
+        if (needs_quote)
+          delete_string.append('\'');
+      }
+      delete_string.append(STRING_WITH_LEN(" AND "));
     }
-
-    delete_string.append(FEDERATED_AND);
   }
-  delete_string.length(delete_string.length()-5); // Remove trailing AND
 
-  delete_string.append(FEDERATED_LIMIT1);
+  // Remove trailing AND
+  delete_string.length(delete_string.length() - sizeof_trailing_and);
+  if (!found)
+    delete_string.length(delete_string.length() - sizeof_trailing_where);
+
+  delete_string.append(STRING_WITH_LEN(" LIMIT 1"));
   DBUG_PRINT("info",
              ("Delete sql: %s", delete_string.c_ptr_quick()));
   if (mysql_real_query(mysql, delete_string.ptr(), delete_string.length()))
   {
     DBUG_RETURN(stash_remote_error());
   }
-  deleted+= mysql->affected_rows;
-  records-= mysql->affected_rows;
+  stats.deleted+= (ha_rows) mysql->affected_rows;
+  stats.records-= (ha_rows) mysql->affected_rows;
   DBUG_PRINT("info",
              ("rows deleted %ld  rows deleted for all time %ld",
-              (long) mysql->affected_rows, (long) deleted));
+              (long) mysql->affected_rows, (long) stats.deleted));
 
   DBUG_RETURN(0);
 }
@@ -2027,7 +2125,7 @@ int ha_federated::index_read_idx_with_re
   create_where_from_key(&index_string,
                         &table->key_info[index],
                         &range,
-                        NULL, 0);
+                        NULL, 0, 0);
   sql_query.append(index_string);
 
   if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length()))
@@ -2059,10 +2157,10 @@ error:
 
 /* Initialized at each key walk (called multiple times unlike rnd_init()) */
 
-int ha_federated::index_init(uint keynr)
+int ha_federated::index_init(uint keynr, bool sorted)
 {
   DBUG_ENTER("ha_federated::index_init");
-  DBUG_PRINT("info", ("table: '%s'  key: %u", table->s->table_name, keynr));
+  DBUG_PRINT("info", ("table: '%s'  key: %u", table->s->table_name.str, keynr));
   active_index= keynr;
   DBUG_RETURN(0);
 }
@@ -2089,7 +2187,7 @@ int ha_federated::read_range_first(const
   sql_query.append(share->select_query);
   create_where_from_key(&sql_query,
                         &table->key_info[active_index],
-                        start_key, end_key, 0);
+                        start_key, end_key, 0, eq_range);
 
   if (stored_result)
   {
@@ -2231,6 +2329,7 @@ int ha_federated::index_end(void)
   DBUG_RETURN(0);
 }
 
+
 /*
   This is called for each row of the table scan. When you run out of records
   you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
@@ -2281,7 +2380,6 @@ int ha_federated::rnd_next(byte *buf)
 int ha_federated::read_next(byte *buf, MYSQL_RES *result)
 {
   int retval;
-  my_ulonglong num_rows;
   MYSQL_ROW row;
   DBUG_ENTER("ha_federated::read_next");
 
@@ -2413,15 +2511,13 @@ int ha_federated::info(uint flag)
   if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST))
   {
     status_query_string.length(0);
-    status_query_string.append(FEDERATED_INFO);
-    status_query_string.append(FEDERATED_SQUOTE);
-
+    status_query_string.append(STRING_WITH_LEN("SHOW TABLE STATUS LIKE '"));
     escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_name,
                             sizeof(escaped_table_name),
                             share->table_name,
                             share->table_name_length);
     status_query_string.append(escaped_table_name);
-    status_query_string.append(FEDERATED_SQUOTE);
+    status_query_string.append(STRING_WITH_LEN("'"));
 
     if (mysql_real_query(mysql, status_query_string.ptr(),
                          status_query_string.length()))
@@ -2441,7 +2537,7 @@ int ha_federated::info(uint flag)
 
     if (flag & HA_STATUS_VARIABLE | HA_STATUS_CONST)
     {
-      /* 
+      /*
         deleted is set in ha_federated::info
       */
       /*
@@ -2453,22 +2549,27 @@ int ha_federated::info(uint flag)
         delete_length = ?
       */
       if (row[4] != NULL)
-        records= (ha_rows) my_strtoll10(row[4], (char**) 0, &error);
+        stats.records=   (ha_rows) my_strtoll10(row[4], (char**) 0,
+                                                       &error);
+      if (row[5] != NULL)
+        stats.mean_rec_length= (ha_rows) my_strtoll10(row[5], (char**) 0, &error);
 
-      mean_rec_length= table->s->reclength;
-      data_file_length= records * mean_rec_length;
+      stats.data_file_length= stats.records * stats.mean_rec_length;
 
       if (row[12] != NULL)
-        update_time= (ha_rows) my_strtoll10(row[12], (char**) 0, &error);
+        stats.update_time=     (ha_rows) my_strtoll10(row[12], (char**) 0,
+                                                      &error);
       if (row[13] != NULL)
-        check_time= (ha_rows) my_strtoll10(row[13], (char**) 0, &error);
+        stats.check_time=      (ha_rows) my_strtoll10(row[13], (char**) 0,
+                                                      &error);
     }
-
     /*
       size of IO operations (This is based on a good guess, no high science
       involved)
     */
-    block_size= 4096;
+    if (flag & HA_STATUS_CONST)
+      stats.block_size= 4096;
+
   }
 
   if (result)
@@ -2508,10 +2609,9 @@ int ha_federated::delete_all_rows()
   query.length(0);
 
   query.set_charset(system_charset_info);
-  query.append(FEDERATED_TRUNCATE);
-  query.append(FEDERATED_BTICK);
+  query.append(STRING_WITH_LEN("TRUNCATE `"));
   query.append(share->table_name);
-  query.append(FEDERATED_BTICK);
+  query.append(STRING_WITH_LEN("`"));
 
   /*
     TRUNCATE won't return anything in mysql_affected_rows
@@ -2520,8 +2620,8 @@ int ha_federated::delete_all_rows()
   {
     DBUG_RETURN(stash_remote_error());
   }
-  deleted+= records;
-  records= 0;
+  stats.deleted+= stats.records;
+  stats.records= 0;
   DBUG_RETURN(0);
 }
 
@@ -2641,4 +2741,171 @@ bool ha_federated::get_error_message(int
   DBUG_RETURN(FALSE);
 }
 
-#endif /* HAVE_FEDERATED_DB */
+int ha_federated::external_lock(THD *thd, int lock_type)
+{
+  int error= 0;
+  ha_federated *trx= (ha_federated *)thd->ha_data[ht->slot];
+  DBUG_ENTER("ha_federated::external_lock");
+
+  if (lock_type != F_UNLCK)
+  {
+    DBUG_PRINT("info",("federated not lock F_UNLCK"));
+    if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) 
+    {
+      DBUG_PRINT("info",("federated autocommit"));
+      /* 
+        This means we are doing an autocommit
+      */
+      error= connection_autocommit(TRUE);
+      if (error)
+      {
+        DBUG_PRINT("info", ("error setting autocommit TRUE: %d", error));
+        DBUG_RETURN(error);
+      }
+      trans_register_ha(thd, FALSE, ht);
+    }
+    else 
+    { 
+      DBUG_PRINT("info",("not autocommit"));
+      if (!trx)
+      {
+        /* 
+          This is where a transaction gets its start
+        */
+        error= connection_autocommit(FALSE);
+        if (error)
+        { 
+          DBUG_PRINT("info", ("error setting autocommit FALSE: %d", error));
+          DBUG_RETURN(error);
+        }
+        thd->ha_data[ht->slot]= this;
+        trans_register_ha(thd, TRUE, ht);
+        /*
+          Send a lock table to the remote end.
+          We do not support this at the moment
+        */
+        if (thd->options & (OPTION_TABLE_LOCK))
+        {
+          DBUG_PRINT("info", ("We do not support lock table yet"));
+        }
+      }
+      else
+      {
+        ha_federated *ptr;
+        for (ptr= trx; ptr; ptr= ptr->trx_next)
+          if (ptr == this)
+            break;
+          else if (!ptr->trx_next)
+            ptr->trx_next= this;
+      }
+    }
+  }
+  DBUG_RETURN(0);
+}
+
+
+static int federated_commit(handlerton *hton, THD *thd, bool all)
+{
+  int return_val= 0;
+  ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot];
+  DBUG_ENTER("federated_commit");
+
+  if (all)
+  {
+    int error= 0;
+    ha_federated *ptr, *old= NULL;
+    for (ptr= trx; ptr; old= ptr, ptr= ptr->trx_next)
+    {
+      if (old)
+        old->trx_next= NULL;
+      error= ptr->connection_commit();
+      if (error && !return_val);
+        return_val= error;
+    }
+    thd->ha_data[hton->slot]= NULL;
+  }
+
+  DBUG_PRINT("info", ("error val: %d", return_val));
+  DBUG_RETURN(return_val);
+}
+
+
+static int federated_rollback(handlerton *hton, THD *thd, bool all)
+{
+  int return_val= 0;
+  ha_federated *trx= (ha_federated *)thd->ha_data[hton->slot];
+  DBUG_ENTER("federated_rollback");
+
+  if (all)
+  {
+    int error= 0;
+    ha_federated *ptr, *old= NULL;
+    for (ptr= trx; ptr; old= ptr, ptr= ptr->trx_next)
+    {
+      if (old)
+        old->trx_next= NULL;
+      error= ptr->connection_rollback();
+      if (error && !return_val)
+        return_val= error;
+    }
+    thd->ha_data[hton->slot]= NULL;
+  }
+
+  DBUG_PRINT("info", ("error val: %d", return_val));
+  DBUG_RETURN(return_val);
+}
+
+int ha_federated::connection_commit()
+{
+  DBUG_ENTER("ha_federated::connection_commit");
+  DBUG_RETURN(execute_simple_query("COMMIT", 6));
+}
+
+
+int ha_federated::connection_rollback()
+{
+  DBUG_ENTER("ha_federated::connection_rollback");
+  DBUG_RETURN(execute_simple_query("ROLLBACK", 8));
+}
+
+
+int ha_federated::connection_autocommit(bool state)
+{
+  const char *text;
+  DBUG_ENTER("ha_federated::connection_autocommit");
+  text= (state == TRUE) ? "SET AUTOCOMMIT=1" : "SET AUTOCOMMIT=0";
+  DBUG_RETURN(execute_simple_query(text, 16));
+}
+
+
+int ha_federated::execute_simple_query(const char *query, int len)
+{
+  DBUG_ENTER("ha_federated::execute_simple_query");
+
+  if (mysql_real_query(mysql, query, len))
+  {
+    DBUG_RETURN(stash_remote_error());
+  }
+  DBUG_RETURN(0);
+}
+
+struct st_mysql_storage_engine federated_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+mysql_declare_plugin(federated)
+{
+  MYSQL_STORAGE_ENGINE_PLUGIN,
+  &federated_storage_engine,
+  "FEDERATED",
+  "Patrick Galbraith and Brian Aker, MySQL AB",
+  "Federated MySQL storage engine",
+  PLUGIN_LICENSE_GPL,
+  federated_db_init, /* Plugin Init */
+  federated_done, /* Plugin Deinit */
+  0x0100 /* 1.0 */,
+  NULL,                       /* status variables                */
+  NULL,                       /* system variables                */
+  NULL                        /* config options                  */
+}
+mysql_declare_plugin_end;
+
Thread
bk commit into 5.1 tree (istruewing:1.2371)ingo1 Dec