@@ -2751,6 +2751,16 @@ int mysql_add_invisible_field(THD *thd, List<Create_field> * field_list,
27512751 return 0 ;
27522752}
27532753
2754+ static bool is_auto_pk_field (Field *field)
2755+ {
2756+ return field && field->invisible == INVISIBLE_FULL &&
2757+ (field->flags & (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
2758+ UNIQUE_KEY_FLAG)) ==
2759+ (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
2760+ UNIQUE_KEY_FLAG) &&
2761+ field->type_handler () == &type_handler_ulonglong;
2762+ }
2763+
27542764#define INTERNAL_FIELD_NAME_LENGTH 30
27552765
27562766static Lex_ident_column make_internal_field_name (THD *thd, const char *prefix,
@@ -2784,18 +2794,50 @@ static Create_field *add_internal_field(THD *thd, Type_handler *type_handler,
27842794 return cf;
27852795}
27862796
2787- Key *
2788- mysql_add_invisible_index (THD *thd, List< Key> *key_list ,
2789- LEX_CSTRING* field_name, enum Key::Keytype type )
2797+ Key *mysql_add_invisible_index (THD *thd, List<Key> *key_list,
2798+ LEX_CSTRING *field_name, enum Key::Keytype type ,
2799+ bool generated_arg= false )
27902800{
2791- Key *key= new (thd->mem_root ) Key (type, &null_clex_str, HA_KEY_ALG_UNDEF,
2792- false , DDL_options (DDL_options::OPT_NONE));
2801+ Key *key= new (thd->mem_root )
2802+ Key (type, &null_clex_str, HA_KEY_ALG_UNDEF, generated_arg,
2803+ DDL_options (DDL_options::OPT_NONE));
27932804 key->columns .push_back (new (thd->mem_root ) Key_part_spec (field_name, 0 , true ),
27942805 thd->mem_root );
27952806 key_list->push_back (key, thd->mem_root );
27962807 return key;
27972808}
27982809
2810+ static int add_generated_invisible_pk (THD *thd, List<Create_field> *field_list,
2811+ Alter_info *alter_info)
2812+ {
2813+ class Column_derived_attributes dat (&my_charset_bin);
2814+ Create_field *fld= new (thd->mem_root ) Create_field ();
2815+
2816+ Lex_ident_column automatic_pk_name;
2817+ if ((automatic_pk_name= make_unique_invisible_field_name (
2818+ thd, " _inv_PK" _Lex_ident_column, &alter_info->create_list ))
2819+ .str )
2820+ fld->field_name = automatic_pk_name;
2821+ else
2822+ return 1 ;
2823+
2824+ fld->set_handler (&type_handler_ulonglong);
2825+ fld->prepare_stage1 (thd, thd->mem_root , COLUMN_DEFINITION_TABLE_FIELD, &dat);
2826+ fld->invisible = INVISIBLE_FULL;
2827+ fld->flags |=
2828+ AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG | UNIQUE_KEY_FLAG;
2829+
2830+ if (fld->check (thd))
2831+ return 1 ;
2832+
2833+ field_list->push_front (fld, thd->mem_root );
2834+
2835+ Key *key= mysql_add_invisible_index (thd, &(alter_info->key_list ),
2836+ &(fld->field_name ), Key::PRIMARY, true );
2837+ key->invisible = true ;
2838+
2839+ return 0 ;
2840+ }
27992841
28002842bool Type_handler_string::Key_part_spec_init_ft (Key_part_spec *part,
28012843 const Column_definition &def)
@@ -3300,6 +3342,29 @@ mysql_prepare_create_table_finalize(THD *thd, HA_CREATE_INFO *create_info,
33003342 DBUG_RETURN (TRUE );
33013343 }
33023344
3345+ /*
3346+ Check if primary_key exists. If a primary key does not exist, and
3347+ the generate_invisible_primary_key option is set, and the handler
3348+ supports auto increment, add an INVISIBLE_FULL primary key (MDEV-21181)
3349+ */
3350+ if (!create_info->sequence &&
3351+ thd->variables .generate_invisible_primary_key &&
3352+ !(file->ha_table_flags () & HA_NO_AUTO_INCREMENT))
3353+ {
3354+ List_iterator<Key> auto_pk_key_iterator (alter_info->key_list );
3355+ bool has_primary_key= 0 ;
3356+ Key *auto_pk_key;
3357+ while (!has_primary_key && (auto_pk_key= auto_pk_key_iterator++))
3358+ {
3359+ if (auto_pk_key->type == Key::PRIMARY)
3360+ has_primary_key= 1 ;
3361+ }
3362+
3363+ if (!has_primary_key)
3364+ if (add_generated_invisible_pk (thd, &alter_info->create_list ,
3365+ alter_info))
3366+ DBUG_RETURN (TRUE );
3367+ }
33033368
33043369 for (field_no=0 ; (sql_field=it++) ; field_no++)
33053370 {
@@ -8710,14 +8775,59 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
87108775
87118776 table->file ->get_foreign_key_list (thd, &fk_list);
87128777
8778+ /*
8779+ If there is an existing primary key that is defined on a single field
8780+ and the field is an autogenerated pk field, check if the user added a
8781+ primary key of their own.
8782+ */
8783+ bool should_replace_generated_pk= false ;
8784+ Field *generated_pk_field= nullptr ;
8785+ if (table->s ->primary_key != MAX_KEY)
8786+ {
8787+ KEY *primary_key_info= table->key_info + table->s ->primary_key ;
8788+ if (primary_key_info->user_defined_key_parts == 1 &&
8789+ is_auto_pk_field (
8790+ table->field [primary_key_info->key_part [0 ].fieldnr - 1 ]))
8791+ {
8792+ generated_pk_field=
8793+ table->field [primary_key_info->key_part [0 ].fieldnr - 1 ];
8794+
8795+ List_iterator<Key> add_key_it (alter_info->key_list );
8796+ for (Key *key; (key= add_key_it++);)
8797+ {
8798+ if (key->type == Key::PRIMARY && !key->generated )
8799+ {
8800+ should_replace_generated_pk= true ;
8801+ break ;
8802+ }
8803+ }
8804+ }
8805+ }
8806+
87138807 /*
87148808 First collect all fields from table which isn't in drop_list
87158809 */
87168810 bitmap_clear_all (&table->tmp_set );
87178811 for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
87188812 {
87198813 if (field->invisible == INVISIBLE_FULL)
8814+ {
8815+ /*
8816+ If the user added a pk of their own, and this was a generated pk field,
8817+ we drop the generated pk field. Other wise, we want to carry it over to
8818+ the new table.
8819+ */
8820+ if (should_replace_generated_pk && generated_pk_field == field)
8821+ {
87208822 continue ;
8823+ }
8824+ if (generated_pk_field == field)
8825+ {
8826+ def= new (root) Create_field (thd, field, field);
8827+ new_create_list.push_back (def, root);
8828+ }
8829+ continue ;
8830+ }
87218831 Alter_drop *drop;
87228832 if (field->type () == MYSQL_TYPE_VARCHAR)
87238833 create_info->varchar = TRUE ;
@@ -9118,7 +9228,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
91189228 for (uint i= 0 ; i < table->s ->total_keys ; i++, key_info++)
91199229 {
91209230 bool long_hash_key= false ;
9121- if (key_info->flags & HA_INVISIBLE_KEY)
9231+ /*
9232+ If this is the generated PK and the user is not adding their own PK,
9233+ keep it
9234+ */
9235+ if ((key_info->flags & HA_INVISIBLE_KEY) &&
9236+ !(generated_pk_field != nullptr && i == table->s ->primary_key &&
9237+ !should_replace_generated_pk))
91229238 continue ;
91239239 Lex_ident_column key_name (key_info->name );
91249240 const bool primary_key= table->s ->primary_key == i;
0 commit comments