Index: sql/table.cc
===================================================================
--- sql/table.cc	(revision 4123)
+++ sql/table.cc	(working copy)
@@ -1195,6 +1195,7 @@
   }
 #endif
 
+  share->invisible_fields= 0;
   share->fields= uint2korr(forminfo+258);
   pos= uint2korr(forminfo+260);   /* Length of all screens */
   n_length= uint2korr(forminfo+268);
@@ -1450,6 +1451,17 @@
       goto err;			/* purecov: inspected */
     }
 
+    if (opt_implicit_primary_key && 
+        !my_strcasecmp(system_charset_info, share->fieldnames.type_names[i], IMPLICIT_PK_NAME))
+    {
+      share->invisible_fields= 1;
+      reg_field->is_invisible= 1;
+    }
+    else
+    {
+      reg_field->is_invisible= 0;
+    }
+
     reg_field->field_index= i;
     reg_field->comment=comment;
     if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
Index: sql/field.h
===================================================================
--- sql/field.h	(revision 4123)
+++ sql/field.h	(working copy)
@@ -125,6 +125,7 @@
   };
   enum imagetype { itRAW, itMBR};
 
+  bool    is_invisible; // 1: this field should be hidden for user
   utype		unireg_check;
   uint32	field_length;		// Length of field
   uint32	flags;
Index: sql/mysqld.cc
===================================================================
--- sql/mysqld.cc	(revision 4123)
+++ sql/mysqld.cc	(working copy)
@@ -405,6 +405,7 @@
  */
 bool volatile grant_option;
 
+my_bool opt_implicit_primary_key = 0;
 my_bool opt_skip_slave_start = 0; ///< If set, slave is not autostarted
 my_bool opt_reckless_slave = 0;
 my_bool opt_enable_named_pipe= 0;
Index: sql/table.h
===================================================================
--- sql/table.h	(revision 4123)
+++ sql/table.h	(working copy)
@@ -627,6 +627,7 @@
   uint db_options_in_use;		/* Options in use */
   uint db_record_offset;		/* if HA_REC_IN_SEQ */
   uint rowid_field_offset;		/* Field_nr +1 to rowid field */
+  uint invisible_fields; /* number of invisible fields, like implicit primary key */
   /* Primary key index number, used in TABLE::key_info[] */
   uint primary_key;                     
   uint next_number_index;               /* autoincrement key number */
Index: sql/mysqld.h
===================================================================
--- sql/mysqld.h	(revision 4123)
+++ sql/mysqld.h	(working copy)
@@ -63,6 +63,11 @@
 #define TEST_SIGINT		1024	/**< Allow sigint on threads */
 #define TEST_SYNCHRONIZATION    2048    /**< get server to do sleep in
                                            some places */
+/* Implict Primary Key name */
+#define IMPLICIT_PK_NAME "__row_id"
+extern my_bool opt_implicit_primary_key;
+
+
 /* Function prototypes */
 void kill_mysql(void);
 void close_connection(THD *thd, uint sql_errno= 0);
Index: sql/sql_select.cc
===================================================================
--- sql/sql_select.cc	(revision 4123)
+++ sql/sql_select.cc	(working copy)
@@ -17098,6 +17098,21 @@
         if (i > 0 && tab[-1].next_select == sub_select_cache)
           extra.append(STRING_WITH_LEN("; Using join buffer"));
         
+        if (opt_implicit_primary_key)
+        {
+          /* if primary key is used,check whether is a implicit pk
+           *  Todo: if use implicit pk and found that "Impossible WHERE",
+           *        no information will be output in extra
+           * */
+          if( tab->ref.key_parts                          // is this necessary?
+              && tab->ref.key == table->s->primary_key
+              && (table->s->invisible_fields) // Table has invisibel_fileds (implicit primary key)
+            )
+          {
+            extra.append(STRING_WITH_LEN("; Using implicit primary key"));
+          }
+        }
+
         /* Skip initial "; "*/
         const char *str= extra.ptr();
         uint32 len= extra.length();
Index: sql/handler.h
===================================================================
--- sql/handler.h	(revision 4123)
+++ sql/handler.h	(working copy)
@@ -1059,6 +1059,7 @@
   ulong avg_row_length;
   ulong used_fields;
   ulong key_block_size;
+  uint invisible_fields; /* number of invisible fields, like implicit primary key */
   SQL_I_List<TABLE_LIST> merge_list;
   handlerton *db_type;
   /**
Index: sql/sys_vars.cc
===================================================================
--- sql/sys_vars.cc	(revision 4123)
+++ sql/sys_vars.cc	(working copy)
@@ -3205,6 +3205,12 @@
        log_output_names, DEFAULT(LOG_FILE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
        ON_CHECK(check_not_empty_set), ON_UPDATE(fix_log_output));
 
+static Sys_var_mybool Sys_implicit_primary_key(
+       "implicit_primary_key", "MySQL add the primary key for every tables "
+       "that haven't any unique indexes automaticly",
+       GLOBAL_VAR(opt_implicit_primary_key), CMD_LINE(OPT_ARG),
+       DEFAULT(0));
+
 #ifdef HAVE_REPLICATION
 static Sys_var_mybool Sys_log_slave_updates(
        "log_slave_updates", "Tells the slave to log the updates from "
Index: sql/sql_base.cc
===================================================================
--- sql/sql_base.cc	(revision 4123)
+++ sql/sql_base.cc	(working copy)
@@ -8283,14 +8283,19 @@
       if (item->type() == Item::FIELD_ITEM && tables->cacheable_table)
         ((Item_field *)item)->cached_table= tables;
 
-      if (!found)
+      if (!(item->type() == Item::FIELD_ITEM &&
+          ((Item_field*) item)->field_name &&
+          (opt_implicit_primary_key &&
+          !my_strcasecmp(system_charset_info, ((Item_field*) item)->field_name, IMPLICIT_PK_NAME))))
       {
-        found= TRUE;
-        it->replace(item); /* Replace '*' with the first found item. */
+        if (!found)
+        {
+          found= TRUE;
+          it->replace(item); /* Replace '*' with the first found item. */
+        }
+        else
+          it->after(item);   /* Add 'item' to the SELECT list. */
       }
-      else
-        it->after(item);   /* Add 'item' to the SELECT list. */
-
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
       /*
         Set privilege information for the fields of newly created views.
@@ -8660,6 +8665,11 @@
   }
   while ((field = *ptr++) && ! thd->is_error())
   {
+    if (opt_implicit_primary_key && field && 
+        !my_strcasecmp(system_charset_info, field->field_name, IMPLICIT_PK_NAME))
+    {
+      continue;
+    }
     value=v++;
     table= field->table;
     if (field == table->next_number_field)
Index: sql/sql_show.cc
===================================================================
--- sql/sql_show.cc	(revision 4123)
+++ sql/sql_show.cc	(working copy)
@@ -1265,6 +1265,12 @@
 
   for (ptr=table->field ; (field= *ptr); ptr++)
   {
+    if (opt_implicit_primary_key && field && 
+        !my_strcasecmp(system_charset_info, field->field_name, IMPLICIT_PK_NAME))
+    {
+      continue;
+    }
+
     uint flags = field->flags;
 
     if (ptr != table->field)
@@ -1345,6 +1351,13 @@
   {
     KEY_PART_INFO *key_part= key_info->key_part;
     bool found_primary=0;
+
+    if (opt_implicit_primary_key && key_part->field && 
+        !my_strcasecmp(system_charset_info, key_part->field->field_name, IMPLICIT_PK_NAME))
+    {
+      continue;
+    }
+
     packet->append(STRING_WITH_LEN(",\n  "));
 
     if (i == primary_key && !strcmp(key_info->name, primary_key_name))
Index: sql/sql_table.cc
===================================================================
--- sql/sql_table.cc	(revision 4123)
+++ sql/sql_table.cc	(working copy)
@@ -70,6 +70,12 @@
 
 static bool prepare_blob_field(THD *thd, Create_field *sql_field);
 static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
+static bool add_implicit_primary_key(THD *thd, Alter_info *alter_info,
+                            List<Create_field> *create_list,
+                            List<Key> *key_list);
+static bool drop_implicit_primary_key(HA_CREATE_INFO *create_info,
+                                     List<Create_field> *create_list,
+                                     List<Key> *key_list);
 static int
 mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
                            Alter_info *alter_info,
@@ -2797,6 +2803,30 @@
                            handler *file, KEY **key_info_buffer,
                            uint *key_count, int select_field_count)
 {
+  if (opt_implicit_primary_key)
+  {
+    /*
+     * Adding an implicit primary key. If there is no primary key or unique keys
+     * */
+    List_iterator<Key> key_iterator_ipk(alter_info->key_list);
+    Key *key_ipk;
+    bool has_pk_or_uk= FALSE;
+    key_iterator_ipk.rewind();
+    while ((key_ipk= key_iterator_ipk++))
+    {
+      if (key_ipk->type == Key::PRIMARY ||
+          key_ipk->type == Key::UNIQUE)
+      {
+        has_pk_or_uk= TRUE;
+        break;
+      }
+    }
+    if(!has_pk_or_uk){
+      /* Todo: add some exception info*/
+      add_implicit_primary_key(thd, alter_info, NULL, NULL);
+    }
+  }
+
   const char	*key_name;
   Create_field	*sql_field,*dup_field;
   uint		field,null_fields,blob_columns,max_key_length;
@@ -5297,6 +5327,8 @@
   KEY *key_info=table->key_info;
   bool rc= TRUE;
   bool skip_secondary;
+  uint has_primary_key= 0;
+  uint has_unique_key= 0;
 
   DBUG_ENTER("mysql_prepare_alter_table");
 
@@ -5511,12 +5543,32 @@
   {
     char *key_name= key_info->name;
     Alter_drop *drop;
+
+    /* Collect PK and UK number */
+    if (key_info->flags & HA_NOSAME)
+    {
+      if (!my_strcasecmp(system_charset_info, key_name, primary_key_name))
+        has_primary_key++;
+      else
+        has_unique_key++;
+    }
+
     drop_it.rewind();
     while ((drop=drop_it++))
     {
       if (drop->type == Alter_drop::KEY &&
-	  !my_strcasecmp(system_charset_info,key_name, drop->name))
-	break;
+          !my_strcasecmp(system_charset_info,key_name, drop->name))
+      {
+        /* If droped, reduce the number */
+        if (key_info->flags & HA_NOSAME)
+        {
+          if (!my_strcasecmp(system_charset_info, key_name, primary_key_name))
+            has_primary_key--;
+          else
+            has_unique_key--;
+        }
+        break;
+      }
     }
     if (drop)
     {
@@ -5630,6 +5682,10 @@
     Key *key;
     while ((key=key_it++))			// Add new keys
     {
+      if (key->type == Key::PRIMARY)
+        has_primary_key++;
+      if (key->type == Key::UNIQUE)
+        has_unique_key++;
       if (key->type != Key::FOREIGN_KEY)
       {
         new_key_list.push_back(key);
@@ -5691,6 +5747,19 @@
   if (table->s->tmp_table)
     create_info->options|=HA_LEX_CREATE_TMP_TABLE;
 
+  if (opt_implicit_primary_key)
+  {
+    if (!has_primary_key && !has_unique_key)
+    {
+      add_implicit_primary_key(thd, alter_info, &new_create_list, &new_key_list);
+      create_info->invisible_fields= 1;
+    }
+    if (has_primary_key || has_unique_key)
+    {
+      drop_implicit_primary_key(create_info, &new_create_list, &new_key_list);
+      create_info->invisible_fields= 0;
+    }
+  }
   rc= FALSE;
   alter_info->create_list.swap(new_create_list);
   alter_info->key_list.swap(new_key_list);
@@ -6573,6 +6642,7 @@
       copy data for MERGE tables. Only the children have data.
     */
   }
+  new_table->s->invisible_fields= create_info->invisible_fields;
 
   /* Copy the data if necessary. */
   thd->count_cuted_fields= CHECK_FIELD_WARN;	// calc cuted fields
@@ -7539,3 +7609,96 @@
   }
   return FALSE;
 }
+
+
+static bool add_implicit_primary_key(THD *thd, Alter_info *alter_info,
+                            List<Create_field> *create_list,
+                            List<Key> *key_list)
+{
+  /* Adding PRIMARY KEY field */
+  LEX_STRING field_name= {IMPLICIT_PK_NAME, 4};
+
+  Create_field *new_field= NULL;
+  List<String> *interval_list= NULL;
+  LEX_STRING comment= null_lex_str;
+  uint type_modifier= 0;
+
+  type_modifier|= PRI_KEY_FLAG | AUTO_INCREMENT_FLAG | NOT_NULL_FLAG;
+  if (!(new_field= new Create_field()) ||
+      new_field->init(thd, field_name.str, MYSQL_TYPE_LONGLONG, (char *)NULL, (char *)NULL, 
+                      type_modifier, (Item *)NULL, (Item *)NULL, &comment, (char *)NULL, 
+                      interval_list, &my_charset_bin, 0))
+  {
+    return TRUE;
+  }
+  if (create_list)
+  {
+    create_list->push_back(new_field);
+  }
+  else
+  {
+    alter_info->create_list.push_back(new_field);
+  }
+  alter_info->flags|= ALTER_ADD_COLUMN;
+
+  /* Adding PRIMARY KEY */
+  Key *key;
+  List<Key_part_spec> col_list;
+
+  col_list.push_back(new Key_part_spec(field_name, 0));
+  key= new Key(Key::PRIMARY, null_lex_str, &default_key_create_info, 0, col_list);
+  if (key_list)
+  {
+    key_list->push_back(key);
+  }
+  else
+  {
+    alter_info->key_list.push_back(key);
+  }
+  col_list.empty();
+  alter_info->flags|= ALTER_ADD_INDEX;
+
+  return FALSE;
+}
+
+static bool drop_implicit_primary_key(HA_CREATE_INFO *create_info,
+                                     List<Create_field> *create_list,
+                                     List<Key> *key_list)
+{
+  List_iterator<Key> key_it(*key_list);
+  List_iterator<Create_field> def_it(*create_list);
+
+	/* Reset auto_increment value because it was dropped */
+  create_info->auto_increment_value=0;
+  create_info->used_fields|= HA_CREATE_USED_AUTO;
+
+  /* Droping PRIMARY KEY */
+  Key *key;
+  key_it.rewind();
+  while ((key=key_it++))
+  {
+    if (key->type == Key::PRIMARY && 
+        key->columns.elements == 1)
+    {
+      Key_part_spec *key_part= key->columns.head();
+      if (!my_strcasecmp(system_charset_info, key_part->field_name.str, IMPLICIT_PK_NAME))
+      {
+        key_it.remove();
+        break;
+      }
+    }
+  }
+
+  /* Droping PRIMARY KEY field */
+  Create_field *def;
+  def_it.rewind();
+  while ((def=def_it++))
+  {
+    if (!my_strcasecmp(system_charset_info, def->field_name, IMPLICIT_PK_NAME))
+    {
+      def_it.remove();
+    }
+  }
+
+  return FALSE;
+}
Index: sql/sql_insert.cc
===================================================================
--- sql/sql_insert.cc	(revision 4123)
+++ sql/sql_insert.cc	(working copy)
@@ -204,7 +204,8 @@
     return -1;
   }
 
-  if (fields.elements == 0 && values.elements != 0)
+  if (!opt_implicit_primary_key && 
+      fields.elements == 0 && values.elements != 0)
   {
     if (!table)
     {
@@ -231,13 +232,27 @@
     */
     bitmap_set_all(table->write_set);
   }
-  else
+  else // or implicit primary key
   {						// Part field list
     SELECT_LEX *select_lex= &thd->lex->select_lex;
     Name_resolution_context *context= &select_lex->context;
     Name_resolution_context_state ctx_state;
     int res;
 
+    /* Filling fields from table->fileds */
+    if (opt_implicit_primary_key &&
+        fields.elements == 0 && values.elements != 0)
+    {
+      fields.empty();
+      for (Field **field=table->field ; *field ; field++)
+      {
+        if (my_strcasecmp(system_charset_info, (*field)->field_name, IMPLICIT_PK_NAME))
+        {
+          fields.push_back(new Item_field(context, NullS, NullS, (*field)->field_name));
+        }
+      }
+    }
+
     if (fields.elements != values.elements)
     {
       my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
