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,16 @@
       goto err;			/* purecov: inspected */
     }
 
+    if (!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/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,9 @@
 #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"
+
 /* 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,18 @@
         if (i > 0 && tab[-1].next_select == sub_select_cache)
           extra.append(STRING_WITH_LEN("; Using join buffer"));
         
+        /* 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/sql_base.cc
===================================================================
--- sql/sql_base.cc	(revision 4123)
+++ sql/sql_base.cc	(working copy)
@@ -8283,14 +8283,18 @@
       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 &&
+          !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 +8664,10 @@
   }
   while ((field = *ptr++) && ! thd->is_error())
   {
+    if (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,11 @@
 
   for (ptr=table->field ; (field= *ptr); ptr++)
   {
+    if (field && !my_strcasecmp(system_charset_info, field->field_name, IMPLICIT_PK_NAME))
+    {
+      continue;
+    }
+
     uint flags = field->flags;
 
     if (ptr != table->field)
@@ -1345,6 +1350,12 @@
   {
     KEY_PART_INFO *key_part= key_info->key_part;
     bool found_primary=0;
+
+    if (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,26 @@
                            handler *file, KEY **key_info_buffer,
                            uint *key_count, int select_field_count)
 {
+  /*
+   * 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 +5323,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 +5539,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 +5678,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 +5743,16 @@
   if (table->s->tmp_table)
     create_info->options|=HA_LEX_CREATE_TMP_TABLE;
 
+  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 +6635,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 +7602,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)
@@ -212,7 +212,8 @@
                table_list->view_db.str, table_list->view_name.str);
       return -1;
     }
-    if (values.elements != table->s->fields)
+    if ((values.elements != table->s->fields) &&
+        (values.elements != table->s->fields - table->s->invisible_fields))
     {
       my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
       return -1;
