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

ChangeSet
  1.2005 05/12/28 14:38:05 patg@stripped +11 -0
  Merge pgalbraith@stripped:/home/bk/mysql-5.1-new
  into  govinda.site:/home/patg/mysql-build/mysql-5.1-wl2682

  sql/share/errmsg.txt
    1.63 05/12/28 14:36:57 patg@stripped +6 -6
    WL# 2683 New error message, trying to merge latest 5.1 into our private tree

  sql/handler.h
    1.174 05/12/28 14:36:57 patg@stripped +4 -4
    WL# 2682, merging latest 5.1 into our private tree

  sql/table.h
    1.120 05/12/28 14:32:25 patg@stripped +0 -0
    Auto merged

  sql/sql_yacc.yy
    1.436 05/12/28 14:32:25 patg@stripped +0 -0
    Auto merged

  sql/sql_parse.cc
    1.503 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

  sql/sql_lex.h
    1.212 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

  sql/sql_lex.cc
    1.171 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

  sql/sql_base.cc
    1.289 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

  sql/ha_partition.h
    1.9 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

  sql/ha_partition.cc
    1.18 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

  include/my_sys.h
    1.182 05/12/28 14:32:24 patg@stripped +0 -0
    Auto merged

# 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:	patg
# Host:	govinda.site
# Root:	/home/patg/mysql-build/mysql-5.1-wl2682/RESYNC

--- 1.181/include/my_sys.h	2005-12-13 12:21:11 -08:00
+++ 1.182/include/my_sys.h	2005-12-28 14:32:24 -08:00
@@ -820,6 +820,9 @@
 #ifndef MAP_NOSYNC
 #define MAP_NOSYNC      0
 #endif
+#ifndef MAP_NORESERVE   
+#define MAP_NORESERVE 0         /* For irix and AIX */
+#endif
 
 #ifdef HAVE_MMAP64
 #define my_mmap(a,b,c,d,e,f)    mmap64(a,b,c,d,e,f)
@@ -838,6 +841,7 @@
 /* not a complete set of mmap() flags, but only those that nesessary */
 #define PROT_READ        1
 #define PROT_WRITE       2
+#define MAP_NORESERVE    0
 #define MAP_SHARED       0x0001
 #define MAP_NORESERVE    0x0002
 #define MAP_NOSYNC       0x0800

--- 1.173/sql/handler.h	2005-12-27 11:21:21 -08:00
+++ 1.174/sql/handler.h	2005-12-28 14:36:57 -08:00
@@ -74,6 +74,13 @@
 */
 #define HA_CAN_INSERT_DELAYED  (1 << 14)
 #define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15)
+/*
+  If HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS is set, it means that the engine can
+  do this: the position of an arbitrary record can be retrieved using
+  position() when the table has a primary key, effectively allowing random
+  access on the table based on a given record.
+*/ 
+#define HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS (1 << 16) 
 #define HA_NOT_DELETE_WITH_CACHE (1 << 18)
 #define HA_NO_PREFIX_CHAR_KEYS (1 << 20)
 #define HA_CAN_FULLTEXT        (1 << 21)
@@ -178,7 +185,7 @@
 /* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */
 #define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT 1
 
-enum db_type
+enum legacy_db_type
 {
   DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1,
   DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM,
@@ -191,7 +198,7 @@
   DB_TYPE_BLACKHOLE_DB,
   DB_TYPE_PARTITION_DB,
   DB_TYPE_BINLOG,
-  DB_TYPE_DEFAULT // Must be last
+  DB_TYPE_DEFAULT=127 // Must be last
 };
 
 enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
@@ -315,8 +322,9 @@
 typedef struct st_table_share TABLE_SHARE;
 struct st_foreign_key_info;
 typedef struct st_foreign_key_info FOREIGN_KEY_INFO;
-typedef bool (stat_print_fn)(THD *thd, const char *type, const char *file,
-                             const char *status);
+typedef bool (stat_print_fn)(THD *thd, const char *type, uint type_len,
+                             const char *file, uint file_len,
+                             const char *status, uint status_len);
 enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
 
 /*
@@ -333,6 +341,13 @@
 typedef struct
 {
   /*
+    handlerton structure version
+   */
+  const int interface_version;
+#define MYSQL_HANDLERTON_INTERFACE_VERSION 0x0000
+
+
+  /*
     storage engine name as it should be printed to a user
   */
   const char *name;
@@ -351,7 +366,7 @@
     Historical number used for frm file to determine the correct storage engine.
     This is going away and new engines will just use "name" for this.
   */
-  enum db_type db_type;
+  enum legacy_db_type db_type;
   /* 
     Method that initizlizes a storage engine
   */
@@ -416,19 +431,17 @@
    handler *(*create)(TABLE_SHARE *table);
    void (*drop_database)(char* path);
    int (*panic)(enum ha_panic_function flag);
-   int (*release_temporary_latches)(THD *thd);
-   int (*update_statistics)();
    int (*start_consistent_snapshot)(THD *thd);
    bool (*flush_logs)();
    bool (*show_status)(THD *thd, stat_print_fn *print, enum ha_stat_type stat);
-   int (*repl_report_sent_binlog)(THD *thd, char *log_file_name,
-                                  my_off_t end_offset);
    uint32 flags;                                /* global handler flags */
 } handlerton;
 
+extern const handlerton default_hton;
+
 struct show_table_alias_st {
   const char *alias;
-  const char *type;
+  enum legacy_db_type type;
 };
 
 /* Possible flags of a handlerton */
@@ -496,7 +509,7 @@
   char* part_comment;
   char* data_file_name;
   char* index_file_name;
-  enum db_type engine_type;
+  handlerton *engine_type;
   enum partition_state part_state;
   uint16 nodegroup_id;
   int index;
@@ -505,7 +518,7 @@
   : part_max_rows(0), part_min_rows(0), partition_name(NULL),
     tablespace_name(NULL), range_value(0), part_comment(NULL),
     data_file_name(NULL), index_file_name(NULL),
-    engine_type(DB_TYPE_UNKNOWN),part_state(PART_NORMAL),
+    engine_type(NULL),part_state(PART_NORMAL),
     nodegroup_id(UNDEF_NODEGROUP)
   {
     subpartitions.empty();
@@ -537,21 +550,54 @@
 
   List<char> part_field_list;
   List<char> subpart_field_list;
-
   char *selected_partition;
   HASH partition_names;
+
+  /*
+    If there is no subpartitioning, use only this func to get partition ids.
+    If there is subpartitioning, use the this func to get partition id when
+    you have both partition and subpartition fields.
+  */
   get_part_id_func get_partition_id;
+
+  /* Get partition id when we don't have subpartition fields */
   get_part_id_func get_part_partition_id;
-  get_subpart_id_func get_subpartition_id;
 
+  /* 
+    Get subpartition id when we have don't have partition fields by we do
+    have subpartition ids.
+    Mikael said that for given constant tuple 
+    {subpart_field1, ..., subpart_fieldN} the subpartition id will be the
+    same in all subpartitions
+  */
+  get_subpart_id_func get_subpartition_id;
+  
+  /* NULL-terminated list of fields used in partitioned expression */
   Field **part_field_array;
+  /* NULL-terminated list of fields used in subpartitioned expression */
   Field **subpart_field_array;
+
+  /* 
+    Array of all fields used in partition and subpartition expression,
+    without duplicates, NULL-terminated.
+  */
   Field **full_part_field_array;
 
   Item *part_expr;
   Item *subpart_expr;
 
   Item *item_free_list;
+  
+  /* 
+    A bitmap of partitions used by the current query. 
+    Usage pattern:
+    * It is guaranteed that all partitions are set to be unused on query start.
+    * Before index/rnd_init(), partition pruning code sets the bits for used
+      partitions.
+    * The handler->extra(HA_EXTRA_RESET) call at query end sets all partitions
+      to be unused.
+  */
+  MY_BITMAP used_partitions;
 
   union {
     longlong *range_int_array;
@@ -574,7 +620,7 @@
   key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF;
   key_map some_fields_in_PF;
 
-  enum db_type default_engine_type;
+  handlerton *default_engine_type;
   Item_result part_result_type;
   partition_type part_type;
   partition_type subpart_type;
@@ -615,7 +661,7 @@
     part_info_string(NULL),
     part_func_string(NULL), subpart_func_string(NULL),
     curr_part_elem(NULL), current_partition(NULL),
-    default_engine_type(DB_TYPE_UNKNOWN),
+    default_engine_type(NULL),
     part_result_type(INT_RESULT),
     part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION),
     part_info_len(0), part_func_len(0), subpart_func_len(0),
@@ -690,7 +736,7 @@
   ulong raid_chunksize;
   ulong used_fields;
   SQL_LIST merge_list;
-  enum db_type db_type;
+  handlerton *db_type;
   enum row_type row_type;
   uint null_bits;                       /* NULL bits at start of record */
   uint options;				/* OR of HA_CREATE_ options */
@@ -724,6 +770,9 @@
 bool is_partition_in_list(char *part_name, List<char> list_part_names);
 bool is_partitions_in_table(partition_info *new_part_info,
                             partition_info *old_part_info);
+bool check_reorganise_list(partition_info *new_part_info,
+                           partition_info *old_part_info,
+                           List<char> list_part_names);
 bool set_up_defaults_for_partitioning(partition_info *part_info,
                                       handler *file,
                                       ulonglong max_rows,
@@ -734,7 +783,7 @@
                          uint32 *old_part_id, uint32 *new_part_id);
 int get_part_for_delete(const byte *buf, const byte *rec0,
                         partition_info *part_info, uint32 *part_id);
-bool check_partition_info(partition_info *part_info,enum db_type eng_type,
+bool check_partition_info(partition_info *part_info,handlerton *eng_type,
                           handler *file, ulonglong max_rows);
 bool fix_partition_func(THD *thd, const char *name, TABLE *table);
 char *generate_partition_syntax(partition_info *part_info,
@@ -750,7 +799,14 @@
                                part_id_range *part_spec);
 bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
                             uint part_info_len, TABLE *table,
-                            enum db_type default_db_type);
+                            handlerton *default_db_type);
+void make_used_partitions_str(partition_info *part_info, String *parts_str);
+uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
+                                       bool left_endpoint,
+                                       bool include_endpoint);
+uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
+                                           bool left_endpoint,
+                                           bool include_endpoint);
 #endif
 
 
@@ -1052,11 +1108,9 @@
   uint get_index(void) const { return active_index; }
   virtual int open(const char *name, int mode, uint test_if_locked)=0;
   virtual int close(void)=0;
-  virtual int write_row(byte * buf) { return  HA_ERR_WRONG_COMMAND; }
-  virtual int update_row(const byte * old_data, byte * new_data)
-   { return  HA_ERR_WRONG_COMMAND; }
-  virtual int delete_row(const byte * buf)
-   { return  HA_ERR_WRONG_COMMAND; }
+  virtual int ha_write_row(byte * buf);
+  virtual int ha_update_row(const byte * old_data, byte * new_data);
+  virtual int ha_delete_row(const byte * buf);
   /*
     SYNOPSIS
       start_bulk_update()
@@ -1187,6 +1241,26 @@
   virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
   { return extra(operation); }
   virtual int external_lock(THD *thd, int lock_type) { return 0; }
+  /*
+    In an UPDATE or DELETE, if the row under the cursor was locked by another
+    transaction, and the engine used an optimistic read of the last
+    committed row value under the cursor, then the engine returns 1 from this
+    function. MySQL must NOT try to update this optimistic value. If the
+    optimistic value does not match the WHERE condition, MySQL can decide to
+    skip over this row. Currently only works for InnoDB. This can be used to
+    avoid unnecessary lock waits.
+
+    If this method returns nonzero, it will also signal the storage
+    engine that the next read will be a locking re-read of the row.
+  */
+  virtual bool was_semi_consistent_read() { return 0; }
+  /*
+    Tell the engine whether it should avoid unnecessary lock waits.
+    If yes, in an UPDATE or DELETE, if the row under the cursor was locked
+    by another transaction, the engine may try an optimistic read of
+    the last committed row value under the cursor.
+  */
+  virtual void try_semi_consistent_read(bool) {}
   virtual void unlock_row() {}
   virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;}
   /*
@@ -1403,6 +1477,31 @@
  virtual bool check_if_incompatible_data(HA_CREATE_INFO *create_info,
 					 uint table_changes)
  { return COMPATIBLE_DATA_NO; }
+
+private:
+
+  /*
+    Row-level primitives for storage engines. 
+    These should be overridden by the storage engine class. To call
+    these methods, use the corresponding 'ha_*' method above.
+  */
+  friend int ndb_add_binlog_index(THD *, void *);
+
+  virtual int write_row(byte *buf __attribute__((unused))) 
+  { 
+    return HA_ERR_WRONG_COMMAND; 
+  }
+
+  virtual int update_row(const byte *old_data __attribute__((unused)),
+                         byte *new_data __attribute__((unused)))
+  { 
+    return HA_ERR_WRONG_COMMAND; 
+  }
+
+  virtual int delete_row(const byte *buf __attribute__((unused)))
+  { 
+    return HA_ERR_WRONG_COMMAND; 
+  }
 };
 
 	/* Some extern variables used with handlers */
@@ -1420,32 +1519,56 @@
 #define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
 
 /* lookups */
-enum db_type ha_resolve_by_name(const char *name, uint namelen);
-const char *ha_get_storage_engine(enum db_type db_type);
+handlerton *ha_resolve_by_name(THD *thd, LEX_STRING *name);
+handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type);
+const char *ha_get_storage_engine(enum legacy_db_type db_type);
 handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
-                         enum db_type db_type);
-enum db_type ha_checktype(THD *thd, enum db_type database_type,
+                         handlerton *db_type);
+handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
                           bool no_substitute, bool report_error);
-bool ha_check_storage_engine_flag(enum db_type db_type, uint32 flag);
+
+
+inline enum legacy_db_type ha_legacy_type(const handlerton *db_type)
+{
+  return (db_type == NULL) ? DB_TYPE_UNKNOWN : db_type->db_type;
+}
+
+inline const char *ha_resolve_storage_engine_name(const handlerton *db_type)
+{
+  return db_type == NULL ? "UNKNOWN" : db_type->name;
+}
+
+inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag)
+{
+  return db_type == NULL ? FALSE : test(db_type->flags & flag);
+}
+
+inline bool ha_storage_engine_is_enabled(const handlerton *db_type)
+{
+  return (db_type && db_type->create) ? 
+         (db_type->state == SHOW_OPTION_YES) : FALSE;
+}
 
 /* basic stuff */
 int ha_init(void);
+int ha_register_builtin_plugins();
+int ha_initialize_handlerton(handlerton *hton);
+
 TYPELIB *ha_known_exts(void);
 int ha_panic(enum ha_panic_function flag);
 int ha_update_statistics();
 void ha_close_connection(THD* thd);
-my_bool ha_storage_engine_is_enabled(enum db_type database_type);
-bool ha_flush_logs(enum db_type db_type=DB_TYPE_DEFAULT);
+bool ha_flush_logs(handlerton *db_type);
 void ha_drop_database(char* path);
 int ha_create_table(THD *thd, const char *path,
                     const char *db, const char *table_name,
                     HA_CREATE_INFO *create_info,
 		    bool update_create_info);
-int ha_delete_table(THD *thd, enum db_type db_type, const char *path,
+int ha_delete_table(THD *thd, handlerton *db_type, const char *path,
                     const char *db, const char *alias, bool generate_warning);
 
 /* statistics and info */
-bool ha_show_status(THD *thd, enum db_type db_type, enum ha_stat_type stat);
+bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
 
 /* discovery */
 int ha_create_table_from_engine(THD* thd, const char *db, const char *name);

--- 1.288/sql/sql_base.cc	2005-12-13 14:02:13 -08:00
+++ 1.289/sql/sql_base.cc	2005-12-28 14:32:24 -08:00
@@ -1030,6 +1030,19 @@
     /* Fallthrough */
   }
 
+  /*
+    For RBR: before calling close_thread_tables(), storage engines
+    should autocommit. Hence if there is a a pending event, it belongs
+    to a non-transactional engine, which writes directly to the table,
+    and should therefore be flushed before unlocking and closing the
+    tables.  The test above for locked tables will not be triggered
+    since RBR locks and unlocks tables on a per-event basis.
+
+    TODO (WL#3023): Change the semantics so that RBR does not lock and
+    unlock tables on a per-event basis.
+  */
+  thd->binlog_flush_pending_rows_event(true);
+
   if (thd->lock)
   {
     mysql_unlock_tables(thd, thd->lock);
@@ -1172,7 +1185,8 @@
     next=table->next;
     close_temporary(table, 1, 1);
   }
-  if (query && found_user_tables && mysql_bin_log.is_open())
+  if (query && found_user_tables && mysql_bin_log.is_open() &&
+      !binlog_row_based) // CREATE TEMP TABLE not binlogged if row-based
   {
     /* The -1 is to remove last ',' */
     thd->clear_error();
@@ -1233,6 +1247,7 @@
 
   SYNOPSIS
     unique_table()
+    thd                   thread handle
     table                 table which should be checked
     table_list            list of tables
 
@@ -1258,7 +1273,7 @@
     0 if table is unique
 */
 
-TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
+TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
 {
   TABLE_LIST *res;
   const char *d_name, *t_name;
@@ -1293,9 +1308,10 @@
   DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
   for (;;)
   {
-    if (!(res= find_table_in_global_list(table_list, d_name, t_name)) ||
-        (!res->table || res->table != table->table) &&
-        (res->select_lex && !res->select_lex->exclude_from_table_unique_test))
+    if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
+         (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
+        ((!res->table || res->table != table->table) &&
+         res->select_lex && !res->select_lex->exclude_from_table_unique_test))
       break;
     /*
       If we found entry of this table or or table of SELECT which already
@@ -1434,7 +1450,7 @@
 
 void close_temporary(TABLE *table, bool free_share, bool delete_table)
 {
-  db_type table_type= table->s->db_type;
+  handlerton *table_type= table->s->db_type;
   DBUG_ENTER("close_temporary");
 
   free_io_cache(table);
@@ -1803,7 +1819,7 @@
     */
     {
       char path[FN_REFLEN];
-      db_type not_used;
+      enum legacy_db_type not_used;
       strxnmov(path, FN_REFLEN-1, mysql_data_home, "/", table_list->db, "/",
                table_list->table_name, reg_ext, NullS);
       (void) unpack_filename(path, path);
@@ -2039,6 +2055,8 @@
   tmp.keys_in_use_for_query= tmp.s->keys_in_use;
   tmp.used_keys= 	tmp.s->keys_for_keyread;
 
+  tmp.s->table_map_id=  table->s->table_map_id;
+
   /* Get state */
   tmp.in_use=    	thd;
   tmp.reginfo.lock_type=table->reginfo.lock_type;
@@ -2344,6 +2362,48 @@
 
 
 /*
+  Function to assign a new table map id to a table.
+
+  PARAMETERS
+
+    table - Pointer to table structure
+
+  PRE-CONDITION(S)
+
+    table is non-NULL
+    The LOCK_open mutex is locked
+
+  POST-CONDITION(S)
+
+    table->s->table_map_id is given a value that with a high certainty
+    is not used by any other table.
+
+    table->s->table_map_id is not ULONG_MAX.
+ */
+static void assign_new_table_id(TABLE *table)
+{
+  static ulong last_table_id= ULONG_MAX;
+
+  DBUG_ENTER("assign_new_table_id(TABLE*)");
+
+  /* Preconditions */
+  DBUG_ASSERT(table != NULL);
+  safe_mutex_assert_owner(&LOCK_open);
+
+  ulong tid= ++last_table_id;                   /* get next id */
+  /* There is one reserved number that cannot be used. */
+  if (unlikely(tid == ULONG_MAX))
+    tid= ++last_table_id;
+  table->s->table_map_id= tid;
+  DBUG_PRINT("info", ("table_id=%lu", tid));
+
+  /* Post conditions */
+  DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
+
+  DBUG_VOID_RETURN;
+}
+
+/*
   Load a table definition from file and open unireg table
 
   SYNOPSIS
@@ -2491,7 +2551,21 @@
        goto err;
      break;
    }
-  
+
+  /*
+    We assign a new table id under the protection of the LOCK_open
+    mutex.  We assign a new table id here instead of inside openfrm()
+    since that function can be used without acquiring any lock (e.g.,
+    inside ha_create_table()).  Insted of creatint a new mutex and
+    using it for the sole purpose of serializing accesses to a static
+    variable, we assign the table id here.
+
+    CAVEAT. This means that the table cannot be used for
+    binlogging/replication purposes, unless open_table() has been called
+    directly or indirectly.
+   */
+  assign_new_table_id(entry);
+
   if (Table_triggers_list::check_n_load(thd, share->db.str,
                                         share->table_name.str, entry, 0))
   {
@@ -2512,10 +2586,11 @@
       uint query_buf_size= 20 + share->db.length + share->table_name.length +1;
       if ((query= (char*) my_malloc(query_buf_size,MYF(MY_WME))))
       {
+        /* this DELETE FROM is needed even with row-based binlogging */
         end = strxmov(strmov(query, "DELETE FROM `"),
                       share->db.str,"`.`",share->table_name.str,"`", NullS);
-        Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE);
-        mysql_bin_log.write(&qinfo);
+        thd->binlog_query(THD::STMT_QUERY_TYPE,
+                          query, (ulong)(end-query), FALSE, FALSE);
         my_free(query, MYF(0));
       }
       else
@@ -3309,7 +3384,7 @@
 }
 
 
-bool rm_temporary_table(enum db_type base, char *path)
+bool rm_temporary_table(handlerton *base, char *path)
 {
   bool error=0;
   handler *file;
@@ -4943,11 +5018,13 @@
 {
   reg2 Item *item;
   ulong save_set_query_id= thd->set_query_id;
+  nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
   List_iterator<Item> it(fields);
   DBUG_ENTER("setup_fields");
 
   thd->set_query_id=set_query_id;
-  thd->allow_sum_func= allow_sum_func;
+  if (allow_sum_func)
+    thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
   thd->where= THD::DEFAULT_WHERE;
 
   /*
@@ -4970,6 +5047,7 @@
     if (!item->fixed && item->fix_fields(thd, it.ref()) ||
 	(item= *(it.ref()))->check_cols(1))
     {
+      thd->lex->allow_sum_func= save_allow_sum_func;
       thd->set_query_id= save_set_query_id;
       DBUG_RETURN(TRUE); /* purecov: inspected */
     }
@@ -4980,6 +5058,7 @@
       item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
     thd->used_tables|= item->used_tables();
   }
+  thd->lex->allow_sum_func= save_allow_sum_func;
   thd->set_query_id= save_set_query_id;
   DBUG_RETURN(test(thd->net.report_error));
 }

--- 1.170/sql/sql_lex.cc	2005-12-13 12:14:49 -08:00
+++ 1.171/sql/sql_lex.cc	2005-12-28 14:32:24 -08:00
@@ -184,6 +184,9 @@
   lex->sroutines_list.empty();
   lex->sroutines_list_own_last= lex->sroutines_list.next;
   lex->sroutines_list_own_elements= 0;
+  lex->nest_level=0 ;
+  lex->allow_sum_func= 0;
+  lex->in_sum_func= NULL;
   DBUG_VOID_RETURN;
 }
 
@@ -1147,6 +1150,7 @@
   first_cond_optimization= 1;
   parsing_place= NO_MATTER;
   exclude_from_table_unique_test= no_wrap_view_item= FALSE;
+  nest_level= 0;
   link_next= 0;
 }
 
@@ -1166,6 +1170,7 @@
   interval_list.empty();
   use_index.empty();
   ftfunc_list_alloc.empty();
+  inner_sum_func_list= 0;
   ftfunc_list= &ftfunc_list_alloc;
   linkage= UNSPECIFIED_TYPE;
   order_list.elements= 0;

--- 1.211/sql/sql_lex.h	2005-12-13 12:14:51 -08:00
+++ 1.212/sql/sql_lex.h	2005-12-28 14:32:24 -08:00
@@ -93,7 +93,8 @@
   SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
   SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
   SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN,
-  SQLCOM_SHOW_AUTHORS,
+  SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
+  SQLCOM_SHOW_PLUGINS,
   /* This should be the last !!! */
 
   SQLCOM_END
@@ -102,6 +103,11 @@
 // describe/explain types
 #define DESCRIBE_NORMAL		1
 #define DESCRIBE_EXTENDED	2
+/*
+  This is not #ifdef'ed because we want "EXPLAIN PARTITIONS ..." to produce
+  additional "partitions" column even if partitioning is not compiled in.
+*/
+#define DESCRIBE_PARTITIONS	4
 
 enum enum_sp_suid_behaviour
 {
@@ -531,6 +537,8 @@
   ulong table_join_options;
   uint in_sum_expr;
   uint select_number; /* number of select (used for EXPLAIN) */
+  int nest_level;     /* nesting level of select */
+  Item_sum *inner_sum_func_list; /* list of sum func in nested selects */ 
   uint with_wild; /* item list contain '*' */
   bool  braces;   	/* SELECT ... UNION (SELECT ... ) <- this braces */
   /* TRUE when having fix field called in processing of this SELECT */
@@ -794,12 +802,23 @@
 
   SQL_LIST	      proc_list, auxilliary_table_list, save_list;
   create_field	      *last_field;
+  Item_sum *in_sum_func;
   udf_func udf;
   HA_CHECK_OPT   check_opt;			// check/repair options
   HA_CREATE_INFO create_info;
   LEX_MASTER_INFO mi;				// used by CHANGE MASTER
   USER_RESOURCES mqh;
   ulong type;
+  /*
+    This variable is used in post-parse stage to declare that sum-functions,
+    or functions which have sense only if GROUP BY is present, are allowed.
+    For example in a query
+    SELECT ... FROM ...WHERE MIN(i) == 1 GROUP BY ... HAVING MIN(i) > 2
+    MIN(i) in the WHERE clause is not allowed in the opposite to MIN(i)
+    in the HAVING clause. Due to possible nesting of select construct
+    the variable can contain 0 or 1 for each nest level.
+  */
+  nesting_map allow_sum_func;
   enum_sql_command sql_command, orig_sql_command;
   thr_lock_type lock_option;
   enum SSL_type ssl_type;			/* defined in violite.h */
@@ -818,6 +837,7 @@
   uint grant, grant_tot_col, which_columns;
   uint fk_delete_opt, fk_update_opt, fk_match_option;
   uint slave_thd_opt, start_transaction_opt;
+  int nest_level;
   /*
     In LEX representing update which were transformed to multi-update
     stores total number of tables. For LEX representing multi-delete

--- 1.502/sql/sql_parse.cc	2005-12-28 08:47:55 -08:00
+++ 1.503/sql/sql_parse.cc	2005-12-28 14:32:24 -08:00
@@ -5893,7 +5893,7 @@
 					     thr_lock_type lock_type,
 					     List<String> *use_index_arg,
 					     List<String> *ignore_index_arg,
-                                             LEX_STRING *option)
+                         LEX_STRING *option)
 {
   register TABLE_LIST *ptr;
   TABLE_LIST *previous_table_ref; /* The table preceding the current one. */

--- 1.435/sql/sql_yacc.yy	2005-12-26 01:39:52 -08:00
+++ 1.436/sql/sql_yacc.yy	2005-12-28 14:32:25 -08:00
@@ -702,7 +702,7 @@
         sp_opt_label BIN_NUM label_ident
 
 %type <lex_str_ptr>
-	opt_table_alias opt_fulltext_parser
+	opt_table_alias opt_fulltext_parser opt_use_partition
 
 %type <table>
 	table_ident table_ident_nodb references xid
@@ -5951,6 +5951,13 @@
 	| CROSS JOIN_SYM	{}
 	;
 
+opt_use_partition:
+	/* empty */	{ $$=0; }
+	| PARTITION_SYM '(' ident ')' 
+		{ $$= &$3; }
+	| SUBPARTITION_SYM '(' ident ')' 
+		{ $$= &$3; };
+		
 /* Warning - may return NULL in case of incomplete SELECT */
 table_factor:
 	{
@@ -5958,11 +5965,27 @@
 	  sel->use_index_ptr=sel->ignore_index_ptr=0;
 	  sel->table_join_options= 0;
 	}
-        table_ident opt_table_alias opt_key_definition
+        table_ident opt_use_partition opt_table_alias opt_key_definition
 	{
 	  LEX *lex= Lex;
+
+	  /* 
+	    If we are given a partition name, then we new up a dummy partition info object
+	    on the lex and store the selected partition name on the selected_partition field
+	    of that partition_info object.  We'll check this in ha_partition
+	  */
+      if($3)
+      {
+		lex->part_info= new partition_info();
+		if (!lex->part_info)
+		{
+			my_error(ER_OUTOFMEMORY, MYF(0), sizeof(partition_info));
+			YYABORT;
+		}
+		lex->part_info->selected_partition= $3->str;
+      }
 	  SELECT_LEX *sel= lex->current_select;
-	  if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
+	  if (!($$= sel->add_table_to_list(lex->thd, $2, $4,
 					   sel->get_table_join_options(),
 					   lex->lock_option,
 					   sel->get_use_index(),

--- 1.119/sql/table.h	2005-12-09 09:48:43 -08:00
+++ 1.120/sql/table.h	2005-12-28 14:32:25 -08:00
@@ -153,7 +153,7 @@
   ulong   timestamp_offset;		/* Set to offset+1 of record */
   ulong   reclength;			/* Recordlength */
 
-  enum db_type db_type;			/* table_type for handler */
+  handlerton *db_type;			/* table_type for handler */
   enum row_type row_type;		/* How rows are stored */
   enum tmp_table_type tmp_table;
 
@@ -189,7 +189,8 @@
   bool is_view;
   bool name_lock, replace_with_name_lock;
   bool waiting_on_cond;                 /* Protection against free */
-
+  ulong table_map_id;                   /* for row-based replication */
+  ulonglong table_map_version;
   /*
     TRUE if this is a system table like 'mysql.proc', which we want to be
     able to open and lock even when we already have some tables open and
@@ -200,7 +201,7 @@
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   const uchar *partition_info;
   uint  partition_info_len;
-  enum db_type default_part_db_type;
+  handlerton *default_part_db_type;
 #endif
 } TABLE_SHARE;
 
@@ -220,6 +221,8 @@
   Field **field;			/* Pointer to fields */
 
   byte *record[2];			/* Pointer to records */
+  byte *write_row_record;		/* Used as optimisation in
+					   THD::write_row */
   byte *insert_values;                  /* used by INSERT ... UPDATE */
   key_map quick_keys, used_keys, keys_in_use_for_query;
   KEY  *key_info;			/* data of keys in database */
@@ -297,6 +300,7 @@
   FILESORT_INFO sort;
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   partition_info *part_info;            /* Partition related information */
+  bool no_partitions_used; /* If true, all partitions have been pruned away */
 #endif
 
   bool fill_item_list(List<Item> *item_list) const;
@@ -314,6 +318,9 @@
   List<LEX_STRING> referenced_fields;
 } FOREIGN_KEY_INFO;
 
+/*
+  Make sure that the order of schema_tables and enum_schema_tables are the same.
+*/
 
 enum enum_schema_tables
 {
@@ -322,8 +329,10 @@
   SCH_COLLATION_CHARACTER_SET_APPLICABILITY,
   SCH_COLUMNS,
   SCH_COLUMN_PRIVILEGES,
+  SCH_ENGINES,
   SCH_KEY_COLUMN_USAGE,
   SCH_OPEN_TABLES,
+  SCH_PLUGINS,
   SCH_PROCEDURES,
   SCH_SCHEMATA,
   SCH_SCHEMA_PRIVILEGES,
@@ -639,7 +648,7 @@
   bool          where_processed;
   /* FRMTYPE_ERROR if any type is acceptable */
   enum frm_type_enum required_type;
-  enum db_type  db_type;		/* table_type for handler */
+  handlerton	*db_type;		/* table_type for handler */
   char		timestamp_buffer[20];	/* buffer for timestamp (19+1) */
   /*
     This TABLE_LIST object is just placeholder for prelocking, it will be

--- 1.62/sql/share/errmsg.txt	2005-12-11 20:48:22 -08:00
+++ 1.63/sql/share/errmsg.txt	2005-12-28 14:36:57 -08:00
@@ -5372,7 +5372,7 @@
 	eng "WSAStartup Failed"
 	ger "WSAStartup fehlgeschlagen"
 ER_DIFF_GROUPS_PROC  
-	eng "Can't handle procedures with differents groups yet"
+	eng "Can't handle procedures with different groups yet"
 	ger "Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten"
 ER_NO_GROUP_FOR_PROC  
 	eng "Select must have a group with this procedure"
@@ -5725,6 +5725,8 @@
 	eng "Plugin '%-.64s' is not loaded"
 ER_WRONG_VALUE
 	eng "Incorrect %-.32s value: '%-.128s'"
+ER_NO_PARTITION_FOR_GIVEN_VALUE
+	eng "Table has no partition for value %ld"
 ER_NO_SUCH_PARTITION 
 	cze "partion '%-.64s.%s' neexistuje"
 	dan "partition '%-.64s' eksisterer ikke"
@@ -5748,3 +5750,9 @@
 	spa "Particion '%-.64s' no existe"
 	swe "Det finns ingen partition som heter '%-.64s'"
+ER_BINLOG_ROW_LOGGING_FAILED
+	eng "Writing one row to the row-based binary log failed"
+ER_BINLOG_ROW_WRONG_TABLE_DEF
+	eng "Table definition on master and slave does not match"
+ER_BINLOG_ROW_RBR_TO_SBR
+	eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events"

--- 1.17/sql/ha_partition.cc	2005-12-26 03:53:40 -08:00
+++ 1.18/sql/ha_partition.cc	2005-12-28 14:32:24 -08:00
@@ -62,6 +62,45 @@
 static PARTITION_SHARE *get_share(const char *table_name, TABLE * table);
 #endif
 
+//static byte *partition_names_get_key(PARTITION_NAME *partition_name, uint *length,
+//			       my_bool not_used __attribute__ ((unused)))
+//{
+//  *length= partition_name->partition_name_length;
+//  return (byte *) partition_name->partition_name;
+//}
+
+static byte *partition_names_get_key(partition_element *partition_element, uint *length,
+			       my_bool not_used __attribute__ ((unused)))
+{
+  *length= strlen(partition_element->partition_name);
+  return (byte *) partition_element->partition_name;
+}
+
+int ha_partition::get_partition_index(const char* partition_name)
+{
+  partition_element *el= (partition_element*)hash_search(
+	                                 &(m_part_info->partition_names), 
+	                                 (byte*)partition_name, 
+									 strlen(partition_name));
+  if (el == NULL)
+    return -1;
+  return el->index;
+}
+
+
+bool is_partition_in_table(PARTITION_SHARE *share, char *name)
+{
+  PARTITION_NAME *partition_name;
+  DBUG_ENTER("is_partition_in_table");
+  partition_name= (PARTITION_NAME*)hash_search(&share->partition_names,
+                                               (byte*) name,
+                                               strlen(name));
+  if (partition_name && partition_name->partition_name)
+    DBUG_RETURN(1);
+
+  DBUG_RETURN(0);
+}
+
 /****************************************************************************
                 MODULE create/delete handler object
 ****************************************************************************/
@@ -852,6 +891,76 @@
   DBUG_RETURN(TRUE);
 }
 
+/*
+ * populate_partition_name_hash
+ * This function will iterate over the list of partition elements and insert them
+ * into a hash based on partition name.  This hash sits on the partition info object
+ * but is used by the handler for determining if a partition specified in a query
+ * actually exists.
+ * RETURNS:  1 on error, 0 if successful
+*/
+int ha_partition::populate_partition_name_hash()
+{
+  List_iterator_fast <partition_element> part_it(m_part_info->partitions);
+
+  (void) hash_init(&(m_part_info->partition_names), system_charset_info, 32, 0, 0,
+                   (hash_get_key) partition_names_get_key, 0, 0);
+
+  int index= 0;
+  partition_element *el;
+  while ((el= part_it++) != NULL)
+  {
+	  el->index= index++;
+    if (my_hash_insert(&(m_part_info->partition_names), (byte*)el))
+	  return 1;
+    if (!is_sub_partitioned(m_part_info)) continue;
+    List_iterator_fast <partition_element> sub_part_it(el->subpartitions);
+	partition_element *subel;
+	while ((subel= sub_part_it++) != NULL)
+	{
+	  subel->index= index++;
+      if (my_hash_insert(&(m_part_info->partition_names), (byte*)subel))
+	    return 1;
+	}
+  }
+  return 0;
+
+/*  for (i= 0; i < m_part_info->no_parts; i++)
+  {
+    PARTITION_NAME *partition_name = (PARTITION_NAME*)my_malloc(sizeof(PARTITION_NAME), MYF(MY_WME));
+    partition_element *part_elem= part_it++;
+    partition_name->partition_name= part_elem->partition_name;
+    partition_name->partition_name_length= strlen(part_elem->partition_name);
+    partition_name->partition_number=part_num_counter++;
+    partition_name->is_sub_partition= FALSE;
+    if (my_hash_insert(&share->partition_names, (byte *)partition_name))
+      goto err_handler;
+    if (is_sub_partitioned(m_part_info))
+    {
+        List_iterator<partition_element> sub_it(part_elem->subpartitions);
+        for (j= 0; j < m_part_info->no_subparts; j++)
+        {
+          partition_element *sub_elem= sub_it++;
+          if (!strcmp(sub_elem->partition_name, part_elem->partition_name))
+          {
+            PARTITION_NAME *sub_partition_name =
+              (PARTITION_NAME*)my_malloc(sizeof(PARTITION_NAME), MYF(MY_WME));
+            sub_partition_name->partition_name= sub_elem->partition_name;
+            sub_partition_name->partition_name_length= strlen(sub_elem->partition_name);
+            sub_partition_name->partition_number=part_num_counter++;
+            sub_partition_name->is_sub_partition= TRUE;
+          }
+          else
+          {
+            continue;
+          }
+        }
+    }
+    DBUG_PRINT("info", ("partition name %s", part_elem->partition_name));
+  }*/
+}
+
+
 /****************************************************************************
                 MODULE open/close object
 ****************************************************************************/
@@ -867,11 +976,11 @@
 
 int ha_partition::open(const char *name, int mode, uint test_if_locked)
 {
-  int error;
   char name_buff[FN_REFLEN];
   char *name_buffer_ptr= m_name_buffer_ptr;
+  int error;
+  uint alloc_len,i, j, part_num_counter= 0;
   handler **file;
-  uint alloc_len;
   DBUG_ENTER("ha_partition::open");
 
   ref_length= 0;
@@ -907,6 +1016,14 @@
       m_start_key.key= (const byte*)ptr;
     }
   }
+
+  /* Initialze the bitmap we use to determine what partitions are used */
+  bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE);
+
+  /* Here we stick all of our partition element objects in a hash by name */
+  if (populate_partition_name_hash())
+    goto err_handler;
+
   file= m_file;
   do
   {
@@ -918,6 +1035,7 @@
     name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
     set_if_bigger(ref_length, ((*file)->ref_length));
   } while (*(++file));
+
   /*
     Add 2 bytes for partition id in position ref length.
     ref_length=max_in_all_partitions(ref_length) + PARTITION_BYTES_IN_POS
@@ -935,6 +1053,9 @@
   if ((error= init_queue(&queue, m_tot_parts, (uint) PARTITION_BYTES_IN_POS,
                          0, key_rec_cmp, (void*)this)))
     goto err_handler;
+
+
+
   /*
     Some handlers update statistics as part of the open call. This will in
     some cases corrupt the statistics of the partition handler and thus
@@ -964,12 +1085,22 @@
 int ha_partition::close(void)
 {
   handler **file;
+  List_iterator_fast <partition_element> part_it(m_part_info->partitions);
   DBUG_ENTER("ha_partition::close");
 
   delete_queue(&queue);
+  bitmap_free(&(m_part_info->used_partitions));
   file= m_file;
   do
   {
+    //PARTITION_NAME *partition_name;
+    partition_element *part_elem= part_it++;
+    //partition_name= (PARTITION_NAME*)hash_search(&share->partition_names,
+      //                                            (byte*) part_elem->partition_name,
+        //                                          strlen(part_elem->partition_name));
+    VOID(hash_delete(&(m_part_info->partition_names), (byte*)part_it++));
+//    DBUG_PRINT("info", ("partition_name->partition_name %s", partition_name->partition_name));
+  //  my_free((gptr) partition_name, MYF(0));
     (*file)->close();
   } while (*(++file));
   DBUG_RETURN(0);
@@ -1008,22 +1139,70 @@
 {
   uint error;
   handler **file;
+  bool is_in_list;
+//  List_iterator_fast <partition_element> part_it(m_part_info->partitions);
   DBUG_ENTER("ha_partition::external_lock");
-  file= m_file;
-  do
+  
+  /* 
+    if thd->lex->part_info is non-null, then we were given a 
+    specific partition to target
+  */
+  bitmap_set_all(&(m_part_info->used_partitions));  // TODO:  remove this once the pruning patch goes in
+  if (thd->lex->part_info)
+  {
+    bitmap_clear_all(&(m_part_info->used_partitions));
+    uint index= get_partition_index(thd->lex->part_info->selected_partition);
+//    uint retval=0;
+  //  retval= is_partition_in_table(share, thd->lex->part_info->selected_partition); 
+    if (index >= 0)
+    {
+      DBUG_PRINT("info", ("selected partition %s is in table",
+                          thd->lex->part_info->selected_partition));
+      bitmap_set_bit(&(m_part_info->used_partitions), index);
+	}
+    else
+    {
+      my_error(ER_NO_SUCH_PARTITION, MYF(0),
+               thd->lex->part_info->selected_partition);
+    }
+  }
+
+  DBUG_PRINT("info", ("is_in_list %d", is_in_list));
+  //file= m_file;
+
+  int i= 0;
+  for (i= 0; i < m_part_info->no_parts; i++)
+  {
+    if (_bitmap_is_set(&(m_part_info->used_partitions), i))
+	  if (error= m_file[i]->external_lock(thd, lock_type))
+	  {
+        DBUG_PRINT("info", ("(file)->s->table_name.str", (*file)->table_share->table_name.str));
+        if (lock_type != F_UNLCK)
+	      goto err_handler;
+	  }
+  }
+
+/*  do
   {
     if ((error= (*file)->external_lock(thd, lock_type)))
     {
+      DBUG_PRINT("info", ("(file)->s->table_name.str", (*file)->table_share->table_name.str));
       if (lock_type != F_UNLCK)
 	goto err_handler;
     }
-  } while (*(++file));
+  } while (*(++file));*/
   m_lock_type= lock_type;                       // For the future (2009?)
   DBUG_RETURN(0);
 
 err_handler:
-  while (file-- != m_file)
-    (*file)->external_lock(thd, F_UNLCK);
+  while (i >= 0)
+  {
+    if (_bitmap_is_set(&(m_part_info->used_partitions), i))
+	  m_file[i--]->external_lock(thd, F_UNLCK);
+  }
+
+  //while (file-- != m_file)
+    //(*file)->external_lock(thd, F_UNLCK);
   DBUG_RETURN(error);
 }
 
@@ -1377,7 +1556,7 @@
   DBUG_ENTER("ha_partition::rnd_init");
 
   include_partition_fields_in_used_fields();
-  if (scan)
+  if (scan && 0)
   {
     /*
       rnd_end() is needed for partitioning to reset internal data if scan
@@ -1405,18 +1584,33 @@
       m_scan_value= 2;                          // No scan active
     DBUG_RETURN(error);
   }
-  file= m_file;
-  do
+
+  int i= 0;
+  for (i= 0; i < m_part_info->no_parts; i++)
   {
-    if ((error= (*file)->ha_rnd_init(0)))
-      goto err;
-  } while (*(++file));
+    if (_bitmap_is_set(&(m_part_info->used_partitions), i))
+	  if (error= m_file[i]->ha_rnd_init(scan))
+	    goto err;
+  }
+
+
+//  file= m_file;
+//  do
+//  {
+//    if ((error= (*file)->ha_rnd_init(0)))
+//      goto err;
+//  } while (*(++file));
   m_scan_value= 0;
   DBUG_RETURN(0);
 
 err:
-  while (file--)
-    (*file)->ha_rnd_end();
+  while (i >= 0)
+  {
+    if (_bitmap_is_set(&(m_part_info->used_partitions), i))
+	  m_file[i--]->ha_rnd_end();
+  }
+//  while (file--)
+  //  (*file)->ha_rnd_end();
   DBUG_RETURN(error);
 }
 
@@ -3271,6 +3465,11 @@
     hash_delete(&partition_open_tables, (byte *) share);
     thr_lock_delete(&share->lock);
     pthread_mutex_destroy(&share->mutex);
+    /*
+      this doesn't seem to free share->partition_names,
+      need to know how to make sure this happens
+    */
+    my_free((gptr) &share->partition_names, MYF(0));
     my_free((gptr) share, MYF(0));
   }
   pthread_mutex_unlock(&partition_mutex);

--- 1.8/sql/ha_partition.h	2005-12-27 11:21:20 -08:00
+++ 1.9/sql/ha_partition.h	2005-12-28 14:32:24 -08:00
@@ -55,7 +55,7 @@
   /* Data for the partition handler */
   char *m_file_buffer;                  // Buffer with names
   char *m_name_buffer_ptr;		// Pointer to first partition name
-  uchar *m_engine_array;                // Array of types of the handlers
+  handlerton **m_engine_array;          // Array of types of the handlers
   handler **m_file;                     // Array of references to handler inst.
   partition_info *m_part_info;          // local reference to partition
   byte *m_start_key_ref;                // Reference of start key in current
Thread
bk commit into 5.1 tree (patg:1.2005)"Patrick Galbraith"28 Dec