diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index e2463761e67..b8ae5967475 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -14,6 +14,55 @@
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+/* 
+  ha_example is a stubbed storage engine. It does nothing at this point. It 
+  will let you create/open/delete tables but that is all. You can enable it 
+  in your buld by doing the following during your build process:
+  ./configure --with-example-storage-engine
+  
+  Once this is done mysql will let you create tables with:
+  CREATE TABLE A (...) ENGINE=EXAMPLE;
+
+  The example is setup to use table locks. It implements an example "SHARE"
+  that is inserted into a hash by table name. You can use this to store 
+  information of state that any example handler object will be able to see
+  if it is using the same table.
+
+  Please read the object definition in ha_example.h before reading the rest 
+  if this file.
+
+  To get an idea of what occurs here is an example select that would do a 
+  scan of an entire table:
+  ha_example::store_lock
+  ha_example::external_lock
+  ha_example::info
+  ha_example::rnd_init
+  ha_example::extra
+  ENUM HA_EXTRA_CACHE   Cash record in HA_rrnd()
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::rnd_next
+  ha_example::extra
+  ENUM HA_EXTRA_NO_CACHE   End cacheing of records (def)
+  ha_example::external_lock    
+  ha_example::extra
+  ENUM HA_EXTRA_RESET   Reset database to after open
+
+  In the above example has 9 row called before rnd_next signalled that it was 
+  at the end of its data. In the above example the table was already opened 
+  (or you would have seen a call to ha_example::open(). Calls to 
+  ha_example::extra() are hints as to what will be occuring to the request.
+
+  Happy coding!
+    -Brian
+*/
+
 #ifdef __GNUC__
 #pragma implementation        // gcc: Class implementation
 #endif
@@ -24,10 +73,14 @@
 #include "ha_example.h"
 
 /* Variables for example share methods */
-pthread_mutex_t example_mutex;
-static HASH example_open_tables;
-static int example_init= 0;
+static HASH example_open_tables; // Hash used to track open tables
+pthread_mutex_t example_mutex;   // This is the mutex we use to init the hash
+static int example_init= 0;      // Variable for checking the init state of hash
 
+
+/*
+  Function we use in the creation of our hash to get key.
+*/
 static byte* example_get_key(EXAMPLE_SHARE *share,uint *length,
                              my_bool not_used __attribute__((unused)))
 {
@@ -37,7 +90,9 @@ static byte* example_get_key(EXAMPLE_SHARE *share,uint *length,
 
 
 /*
-  Example of simple lock controls.
+  Example of simple lock controls. The "share" it creates is structure we will
+  pass to each example handler. Do you have to have one of these? Well, you have
+  pieces that are used for locking, and they are needed to function. 
 */
 static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table)
 {
@@ -45,6 +100,12 @@ static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table)
   uint length;
   char *tmp_name;
 
+  /*
+    So why does this exist? There is no way currently to init a storage engine.
+    Innodb and BDB both have modifications to the server to allow them to
+    do this. Since you will not want to do this, this is probably the next
+    best method.
+  */
   if (!example_init)
   {
     /* Hijack a mutex for init'ing the storage engine */
@@ -101,7 +162,8 @@ error:
 
 
 /* 
-  Free lock controls.
+  Free lock controls. We call this whenever we close a table. If the table had
+  the last reference to the share then we free memory associated with it.
 */
 static int free_share(EXAMPLE_SHARE *share)
 {
@@ -119,10 +181,24 @@ static int free_share(EXAMPLE_SHARE *share)
 }
 
 
+/*
+  If frm_error() is called then we will use this to to find out what file extentions 
+  exist for the storage engine. This is also used by the default rename_table and
+  delete_table method in handler.cc.
+*/
 const char **ha_example::bas_ext() const
 { static const char *ext[]= { NullS }; return ext; }
 
 
+/* 
+  Used for opening tables. The name will be the name of the file.
+  A table is opened when it needs to be opened. For instance
+  when a request comes in for a select on the table (tables are not 
+  open and closed for each request, they are cached).
+
+  Called from handler.cc by handler::ha_open(). The server opens all tables by
+  calling ha_open() which then calls the handler specific open().
+*/
 int ha_example::open(const char *name, int mode, uint test_if_locked)
 {
   DBUG_ENTER("ha_example::open");
@@ -134,18 +210,66 @@ int ha_example::open(const char *name, int mode, uint test_if_locked)
   DBUG_RETURN(0);
 }
 
+
+/*
+  Closes a table. We call the free_share() function to free any resources 
+  that we have allocated in the "shared" structure.
+
+  Called from sql_base.cc, sql_select.cc, and table.cc.
+  In sql_select.cc it is only used to close up temporary tables or during
+  the process where a temporary table is converted over to being a 
+  myisam table.
+  For sql_base.cc look at close_data_tables().
+*/
 int ha_example::close(void)
 {
   DBUG_ENTER("ha_example::close");
   DBUG_RETURN(free_share(share));
 }
 
+
+/*
+  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 
+  information to extract the data from the native byte array type.
+  Example of this would be:
+  for (Field **field=table->field ; *field ; field++)
+  {
+    ...
+  }
+
+  See ha_tina.cc for an example of extracting all of the data as strings. 
+  ha_berekly.cc has an example of how to store it intact by "packing" it
+  for ha_berkeley's own native storage type.
+
+  See the note for update_row() on auto_increments and timestamps. This
+  case also applied to write_row().
+
+  Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, 
+  sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
+*/
 int ha_example::write_row(byte * buf)
 {
   DBUG_ENTER("ha_example::write_row");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  Yes, update_row() does what you expect, it updates a row. old_data will have
+  the previous row record in it, while new_data will have the newest data in
+  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.
+  Currently new_data will not have an updated auto_increament record, or
+  and updated timestamp field. You can do these for example by doing these:
+  if (table->timestamp_on_update_now)
+    update_timestamp(new_row+table->timestamp_on_update_now-1);
+  if (table->next_number_field && record == table->record[0])
+    update_auto_increment();
+
+  Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
+*/
 int ha_example::update_row(const byte * old_data, byte * new_data)
 {
 
@@ -153,12 +277,32 @@ int ha_example::update_row(const byte * old_data, byte * new_data)
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  This will delete a row. buf will contain a copy of the row to be deleted.
+  The server will call this right after the current row has been called (from
+  either a previous rnd_nexT() or index call).
+  If you keep a pointer to the last row or can access a primary key it will 
+  make doing the deletion quite a bit easier. 
+  Keep in mind that the server does no guarentee consecutive deletions. ORDER BY
+  clauses can be used.
+
+  Called in sql_acl.cc and sql_udf.cc to manage internal table information.
+  Called in sql_delete.cc, sql_insert.cc, and sql_select.cc. In sql_select it is
+  used for removing duplicates while in insert it is used for REPLACE calls.
+*/
 int ha_example::delete_row(const byte * buf)
 {
   DBUG_ENTER("ha_example::delete_row");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  Positions an index cursor to the index specified in the handle. Fetches the
+  row if available. If the key value is null, begin at the first key of the
+  index.
+*/
 int ha_example::index_read(byte * buf, const byte * key,
                            uint key_len __attribute__((unused)),
                            enum ha_rkey_function find_flag
@@ -168,6 +312,11 @@ int ha_example::index_read(byte * buf, const byte * key,
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  Positions an index cursor to the index specified in key. Fetches the
+  row if any.  This is only used to read whole keys.
+*/
 int ha_example::index_read_idx(byte * buf, uint index, const byte * key,
                                uint key_len __attribute__((unused)),
                                enum ha_rkey_function find_flag
@@ -178,66 +327,187 @@ int ha_example::index_read_idx(byte * buf, uint index, const byte * key,
 }
 
 
+/*
+  Used to read forward through the index.
+*/
 int ha_example::index_next(byte * buf)
 {
   DBUG_ENTER("ha_example::index_next");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  Used to read backwards through the index.
+*/
 int ha_example::index_prev(byte * buf)
 {
   DBUG_ENTER("ha_example::index_prev");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  index_first() asks for the first key in the index.
+
+  Called from opt_range.cc, opt_sum.cc, sql_handler.cc, 
+  and sql_select.cc.
+*/
 int ha_example::index_first(byte * buf)
 {
   DBUG_ENTER("ha_example::index_first");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  index_last() asks for the last key in the index.
+
+  Called from opt_range.cc, opt_sum.cc, sql_handler.cc, 
+  and sql_select.cc.
+*/
 int ha_example::index_last(byte * buf)
 {
   DBUG_ENTER("ha_example::index_last");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/* 
+  rnd_init() is called when the system wants the storage engine to do a table
+  scan. 
+  See the example in the introduction at the top of this file to see when 
+  rnd_init() is called.
+
+  Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+  and sql_update.cc.
+*/
 int ha_example::rnd_init(bool scan)
 {
   DBUG_ENTER("ha_example::rnd_init");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/* 
+  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.
+  The Field structure for the table is the key to getting data into buf
+  in a manner that will allow the server to understand it.
+
+  Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+  and sql_update.cc.
+*/
 int ha_example::rnd_next(byte *buf)
 {
   DBUG_ENTER("ha_example::rnd_next");
   DBUG_RETURN(HA_ERR_END_OF_FILE);
 }
 
+
+/*
+  position() is called after each call to rnd_next() if the data needs
+  to be ordered. You can do something like the following to store
+  the position:
+  ha_store_ptr(ref, ref_length, current_position);
+
+  The server uses ref to store data. ref_length in the above case is
+  the size needed to store current_position. ref is just a byte array
+  that the server will maintain. If you are using offsets to mark rows, then
+  current_position should be the offset. If it is a primary key like in
+  BDB, then it needs to be a primary key. 
+  
+  Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
+*/
 void ha_example::position(const byte *record)
 {
   DBUG_ENTER("ha_example::position");
   DBUG_VOID_RETURN;
 }
 
+
+/*
+  This is like rnd_next, but you are given a position to use
+  to determine the row. The position will be of the type that you stored in
+  ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key
+  or position you saved when position() was called.
+  Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc.
+*/
 int ha_example::rnd_pos(byte * buf, byte *pos)
 {
   DBUG_ENTER("ha_example::rnd_pos");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/*
+  ::info() is used to return information to the optimizer.
+  Currently this table handler doesn't implement most of the fields
+  really needed. SHOW also makes use of this data
+  Another note, you will probably want to have the following in your
+  code:
+  if (records < 2)
+    records = 2;
+  The reason is that the server will optimize for cases of only a single
+  record. If in a table scan you don't know the number of records 
+  it will probably be better to set records to two so you can return
+  as many records as you need. 
+  Along with records a few more variables you may wish to set are:
+    records
+    deleted
+    data_file_length
+    index_file_length
+    delete_length
+    check_time
+  Take a look at the public variables in handler.h for more information.
+
+  Called in:
+    filesort.cc
+    ha_heap.cc
+    item_sum.cc
+    opt_sum.cc
+    sql_delete.cc
+    sql_delete.cc
+    sql_derived.cc
+    sql_select.cc
+    sql_select.cc
+    sql_select.cc
+    sql_select.cc
+    sql_select.cc
+    sql_show.cc
+    sql_show.cc
+    sql_show.cc
+    sql_show.cc
+    sql_table.cc
+    sql_union.cc
+    sql_update.cc
+
+*/
 void ha_example::info(uint flag)
 {
   DBUG_ENTER("ha_example::info");
   DBUG_VOID_RETURN;
 }
 
+
+/*
+  extra() is called whenever the server wishes to send a hint to
+  the storage engine. The myisam engine implements the most hints.
+  ha_innodb.cc has the most exhaustive list of these hints.
+*/
 int ha_example::extra(enum ha_extra_function operation)
 {
   DBUG_ENTER("ha_example::extra");
   DBUG_RETURN(0);
 }
 
+
+/*
+  Deprecated and likely to be removed in the future. Storage engines normally
+  just make a call like:
+  ha_example::extra(HA_EXTRA_RESET);
+  to handle it.
+*/
 int ha_example::reset(void)
 {
   DBUG_ENTER("ha_example::reset");
@@ -245,18 +515,71 @@ int ha_example::reset(void)
 }
 
 
+/*
+  Used to delete all rows in a table. Both for cases of truncate and
+  for cases where the optimizer realizes that all rows will be
+  removed as a result of a SQL statement. 
+
+  Called from item_sum.cc by Item_func_group_concat::clear(), 
+  Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
+  Called from sql_delete.cc by mysql_delete().
+  Called from sql_select.cc by JOIN::reinit().
+  Called from sql_union.cc by st_select_lex_unit::exec().
+*/
 int ha_example::delete_all_rows()
 {
   DBUG_ENTER("ha_example::delete_all_rows");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+
+/* 
+  First you should go read the section "locking functions for mysql" in 
+  lock.cc to understand this.
+  This create a lock on the table. If you are implementing a storage engine
+  that can handle transacations look at ha_berkely.cc to see how you will
+  want to goo about doing this. Otherwise you should consider calling flock()
+  here.
+
+  Called from lock.cc by lock_external() and unlock_external(). Also called
+  from sql_table.cc by copy_data_between_tables().
+*/
 int ha_example::external_lock(THD *thd, int lock_type)
 {
   DBUG_ENTER("ha_example::external_lock");
   DBUG_RETURN(0);
 }
 
+
+/*
+  The idea with handler::store_lock() is the following:
+
+  The statement decided which locks we should need for the table
+  for updates/deletes/inserts we get WRITE locks, for SELECT... we get
+  read locks.
+
+  Before adding the lock into the table lock handler (see thr_lock.c)
+  mysqld calls store lock with the requested locks.  Store lock can now
+  modify a write lock to a read lock (or some other lock), ignore the
+  lock (if we don't want to use MySQL table locks at all) or add locks
+  for many tables (like we do when we are using a MERGE handler).
+
+  Berkeley DB for example  changes all WRITE locks to TL_WRITE_ALLOW_WRITE 
+  (which signals that we are doing WRITES, but we are still allowing other
+  reader's and writer's.
+
+  When releasing locks, store_lock() are also called. In this case one
+  usually doesn't have to do anything.
+
+  In some exceptional cases MySQL may send a request for a TL_IGNORE;
+  This means that we are requesting the same lock as last time and this
+  should also be ignored. (This may happen when someone does a flush
+  table when we have opened a part of the tables, in which case mysqld
+  closes and reopens the tables and tries to get the same locks at last
+  time).  In the future we will probably try to remove this.
+
+  Called from lock.cc by get_lock_data().
+*/
 THR_LOCK_DATA **ha_example::store_lock(THD *thd,
                                        THR_LOCK_DATA **to,
                                        enum thr_lock_type lock_type)
@@ -267,6 +590,16 @@ THR_LOCK_DATA **ha_example::store_lock(THD *thd,
   return to;
 }
 
+/*
+  Used to delete a table. By the time delete_table() has been called all 
+  opened references to this table will have been closed (and your globally
+  shared references released. The variable name will just be the name of 
+  the table. You will need to remove any files you have created at this point.
+
+  Called from handler.cc by delete_table and  ha_create_table(). Only used
+  during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
+  the storage engine.
+*/
 int ha_example::delete_table(const char *name)
 {
   DBUG_ENTER("ha_example::delete_table");
@@ -274,12 +607,24 @@ int ha_example::delete_table(const char *name)
   DBUG_RETURN(0);
 }
 
+/*
+  Renames a table from one name to another from alter table call.
+
+  Called from sql_table.cc by mysql_rename_table().
+*/
 int ha_example::rename_table(const char * from, const char * to)
 {
   DBUG_ENTER("ha_example::rename_table ");
   DBUG_RETURN(HA_ERR_NOT_IMPLEMENTED);
 }
 
+/* 
+  Given a starting key, and an ending key estimate the number of rows that
+  will exist between the two. end_key may be empty which in case determine
+  if start_key matches any rows.
+
+  Called from opt_range.cc by check_quick_keys().
+*/
 ha_rows ha_example::records_in_range(int inx,
                                      const byte *start_key,uint start_key_len,
                                      enum ha_rkey_function start_search_flag,
@@ -287,11 +632,22 @@ ha_rows ha_example::records_in_range(int inx,
                                      enum ha_rkey_function end_search_flag)
 {
   DBUG_ENTER("ha_example::records_in_range ");
-  DBUG_RETURN(records); // HA_ERR_NOT_IMPLEMENTED 
+  DBUG_RETURN(records);
 }
 
 
-int ha_example::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info)
+/*
+  create() is called to create a database. The variable name will have the name
+  of the table. When create() is called you do not need to worry about opening
+  the table. Also, the FRM file will have already been created so adjusting 
+  create_info will not do you any good. You can overwrite the frm file at this
+  point if you wish to change the table definition, but there are no methods 
+  currently provided for doing that.
+
+  Called from handle.cc by ha_create_table().
+*/
+int ha_example::create(const char *name, TABLE *table_arg, 
+                       HA_CREATE_INFO *create_info)
 {
   DBUG_ENTER("ha_example::create");
   /* This is not implemented but we want someone to be able that it works. */
diff --git a/sql/examples/ha_example.h b/sql/examples/ha_example.h
index 466632a1795..ffc4f5b941c 100644
--- a/sql/examples/ha_example.h
+++ b/sql/examples/ha_example.h
@@ -14,6 +14,17 @@
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+/* 
+  Please read ha_exmple.cc before reading this file.
+  Please keep in mind that the example storage engine implements all methods
+  that are required to be implemented. handler.h has a full list of methods
+  that you can implement.
+*/
+
+/*
+  EXAMPLE_SHARE is a structure that will be shared amoung all open handlers
+  The example implements the minimum of what you will probably need.
+*/
 typedef struct st_example_share {
   char *table_name;
   uint table_name_length,use_count;
@@ -21,6 +32,9 @@ typedef struct st_example_share {
   THR_LOCK lock;
 } EXAMPLE_SHARE;
 
+/*
+  Class definition for the storage engine
+*/
 class ha_example: public handler
 {
   THR_LOCK_DATA lock;      /* MySQL lock */
@@ -33,17 +47,34 @@ public:
   ~ha_example() 
   {
   }
-  const char *table_type() const { return "EXAMPLE"; }
+  /* The name that will be used for display purposes */
+  const char *table_type() const { return "EXAMPLE"; } 
+  /* The name of the index type that will be used for display */
   const char *index_type(uint inx) { return "NONE"; }
   const char **bas_ext() const;
+  /* 
+    This is a list of flags that says what the storage engine 
+    implements. The current table flags are documented in
+    table_flags.
+  */
   ulong table_flags() const
   {
     return 0;
   }
+  /* 
+    This is a list of flags that says how the storage engine 
+    implements indexes. The current index flags are documented in
+    handler.h. If you do not implement indexes, just return zero 
+    here.
+  */
   ulong index_flags(uint inx) const
   {
     return 0;
   }
+  /* 
+    unireg.cc will call the following to make sure that the storage engine can
+    handle the data it is about to send.
+  */
   uint max_record_length() const { return HA_MAX_REC_LENGTH; }
   uint max_keys()          const { return 0; }
   uint max_key_parts()     const { return 0; }
@@ -52,10 +83,15 @@ public:
     Called in test_quick_select to determine if indexes should be used.
   */
   virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
-  /* The next method will never be called */
+  /* 
+    The next method will never be called if you do not implement indexes.
+  */
   virtual double read_time(ha_rows rows) { return (double) rows /  20.0+1; }
   virtual bool fast_key_read() { return 1;}
 
+  /* 
+    Everything below are methods that we implment in ha_example.cc.
+  */
   int open(const char *name, int mode, uint test_if_locked);
   int close(void);
   int write_row(byte * buf);