~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

  • Committer: Brian Aker
  • Date: 2009-05-06 06:59:53 UTC
  • mfrom: (1003.1.20 merge)
  • Revision ID: brian@gaz-20090506065953-4mrfmaty42e0ixpq
Merge handler cleanup (and ALTER TABLE cleanup) We go from 1 and 2 half
thought out systems... to just 1.

This should all be changed when we finish the StorageEngine rewrite

Show diffs side-by-side

added added

removed removed

Lines of Context:
3167
3167
}
3168
3168
 
3169
3169
 
3170
 
/**
3171
 
   @param       session                Thread
3172
 
   @param       table              The original table.
3173
 
   @param       alter_info         Alter options, fields and keys for the new
3174
 
                                   table.
3175
 
   @param       create_info        Create options for the new table.
3176
 
   @param       order_num          Number of order list elements.
3177
 
   @param[out]  ha_alter_flags  Flags that indicate what will be changed
3178
 
   @param[out]  ha_alter_info      Data structures needed for on-line alter
3179
 
   @param[out]  table_changes      Information about particular change
3180
 
 
3181
 
   First argument 'table' contains information of the original
3182
 
   table, which includes all corresponding parts that the new
3183
 
   table has in arguments create_list, key_list and create_info.
3184
 
 
3185
 
   By comparing the changes between the original and new table
3186
 
   we can determine how much it has changed after ALTER Table
3187
 
   and whether we need to make a copy of the table, or just change
3188
 
   the .frm file.
3189
 
 
3190
 
   Mark any changes detected in the ha_alter_flags.
3191
 
 
3192
 
   If there are no data changes, but index changes, 'index_drop_buffer'
3193
 
   and/or 'index_add_buffer' are populated with offsets into
3194
 
   table->key_info or key_info_buffer respectively for the indexes
3195
 
   that need to be dropped and/or (re-)created.
3196
 
 
3197
 
   @retval true  error
3198
 
   @retval false success
3199
 
*/
3200
 
 
3201
 
static
3202
 
bool
3203
 
compare_tables(Session *session,
3204
 
               Table *table,
3205
 
               Alter_info *alter_info,
3206
 
               HA_CREATE_INFO *create_info,
3207
 
               uint32_t order_num,
3208
 
               HA_ALTER_FLAGS *alter_flags,
3209
 
               HA_ALTER_INFO *ha_alter_info,
3210
 
               uint32_t *table_changes)
3211
 
{
3212
 
  Field **f_ptr, *field;
3213
 
  uint32_t table_changes_local= 0;
3214
 
  List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
3215
 
  Create_field *new_field;
3216
 
  KEY_PART_INFO *key_part;
3217
 
  KEY_PART_INFO *end;
3218
 
 
3219
 
  {
3220
 
    /*
3221
 
      Create a copy of alter_info.
3222
 
      To compare the new and old table definitions, we need to "prepare"
3223
 
      the new definition - transform it from parser output to a format
3224
 
      that describes the final table layout (all column defaults are
3225
 
      initialized, duplicate columns are removed). This is done by
3226
 
      mysql_prepare_create_table.  Unfortunately,
3227
 
      mysql_prepare_create_table performs its transformations
3228
 
      "in-place", that is, modifies the argument.  Since we would
3229
 
      like to keep compare_tables() idempotent (not altering any
3230
 
      of the arguments) we create a copy of alter_info here and
3231
 
      pass it to mysql_prepare_create_table, then use the result
3232
 
      to evaluate possibility of fast ALTER Table, and then
3233
 
      destroy the copy.
3234
 
    */
3235
 
    Alter_info tmp_alter_info(*alter_info, session->mem_root);
3236
 
    session= table->in_use;
3237
 
    uint32_t db_options= 0; /* not used */
3238
 
    /* Create the prepared information. */
3239
 
    if (mysql_prepare_create_table(session, create_info,
3240
 
                                   &tmp_alter_info,
3241
 
                                   (table->s->tmp_table != NO_TMP_TABLE),
3242
 
                                   &db_options,
3243
 
                                   table->file,
3244
 
                                   &ha_alter_info->key_info_buffer,
3245
 
                                   &ha_alter_info->key_count,
3246
 
                                   /* select_field_count */ 0))
3247
 
      return(true);
3248
 
    /* Allocate result buffers. */
3249
 
    if (! (ha_alter_info->index_drop_buffer=
3250
 
           (uint*) session->alloc(sizeof(uint32_t) * table->s->keys)) ||
3251
 
        ! (ha_alter_info->index_add_buffer=
3252
 
           (uint*) session->alloc(sizeof(uint32_t) *
3253
 
                              tmp_alter_info.key_list.elements)))
3254
 
      return(true);
3255
 
  }
3256
 
  /*
3257
 
    First we setup ha_alter_flags based on what was detected
3258
 
    by parser
3259
 
  */
3260
 
  setup_ha_alter_flags(alter_info, alter_flags);
3261
 
 
3262
 
 
3263
 
  /*
3264
 
    Some very basic checks. If number of fields changes, or the
3265
 
    handler, we need to run full ALTER Table. In the future
3266
 
    new fields can be added and old dropped without copy, but
3267
 
    not yet.
3268
 
 
3269
 
    Test also that engine was not given during ALTER Table, or
3270
 
    we are force to run regular alter table (copy).
3271
 
    E.g. ALTER Table tbl_name ENGINE=MyISAM.
3272
 
 
3273
 
    For the following ones we also want to run regular alter table:
3274
 
    ALTER Table tbl_name order_st BY ..
3275
 
    ALTER Table tbl_name CONVERT TO CHARACTER SET ..
3276
 
 
3277
 
    At the moment we can't handle altering temporary tables without a copy.
3278
 
    We also test if OPTIMIZE Table was given and was mapped to alter table.
3279
 
    In that case we always do full copy.
3280
 
 
3281
 
    There was a bug prior to mysql-4.0.25. Number of null fields was
3282
 
    calculated incorrectly. As a result frm and data files gets out of
3283
 
    sync after fast alter table. There is no way to determine by which
3284
 
    mysql version (in 4.0 and 4.1 branches) table was created, thus we
3285
 
    disable fast alter table for all tables created by mysql versions
3286
 
    prior to 5.0 branch.
3287
 
    See BUG#6236.
3288
 
  */
3289
 
  if (table->s->fields != alter_info->create_list.elements ||
3290
 
      table->s->db_type() != create_info->db_type ||
3291
 
      table->s->tmp_table ||
3292
 
      create_info->used_fields & HA_CREATE_USED_ENGINE ||
3293
 
      create_info->used_fields & HA_CREATE_USED_CHARSET ||
3294
 
      create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
3295
 
      create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
3296
 
      (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
3297
 
      order_num ||
3298
 
      !table->s->mysql_version)
3299
 
  {
3300
 
    *table_changes= IS_EQUAL_NO;
3301
 
    /*
3302
 
      Check what has changed and set alter_flags
3303
 
    */
3304
 
    if (table->s->fields < alter_info->create_list.elements)
3305
 
      alter_flags->set(HA_ADD_COLUMN);
3306
 
    else if (table->s->fields > alter_info->create_list.elements)
3307
 
      alter_flags->set(HA_DROP_COLUMN);
3308
 
    if (create_info->db_type != table->s->db_type() ||
3309
 
        create_info->used_fields & HA_CREATE_USED_ENGINE)
3310
 
      alter_flags->set(HA_ALTER_STORAGE_ENGINE);
3311
 
    if (create_info->used_fields & HA_CREATE_USED_CHARSET)
3312
 
      alter_flags->set(HA_CHANGE_CHARACTER_SET);
3313
 
    if (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)
3314
 
      alter_flags->set(HA_SET_DEFAULT_CHARACTER_SET);
3315
 
    if (alter_info->flags & ALTER_RECREATE)
3316
 
      alter_flags->set(HA_RECREATE);
3317
 
    /* TODO check for ADD/DROP FOREIGN KEY */
3318
 
    if (alter_info->flags & ALTER_FOREIGN_KEY)
3319
 
      alter_flags->set(HA_ALTER_FOREIGN_KEY);
3320
 
  }
3321
 
  /*
3322
 
    Go through fields and check if the original ones are compatible
3323
 
    with new table.
3324
 
  */
3325
 
  for (f_ptr= table->field, new_field= new_field_it++;
3326
 
       (new_field && (field= *f_ptr));
3327
 
       f_ptr++, new_field= new_field_it++)
3328
 
  {
3329
 
    /* Make sure we have at least the default charset in use. */
3330
 
    if (!new_field->charset)
3331
 
      new_field->charset= create_info->default_table_charset;
3332
 
 
3333
 
    /* Don't pack rows in old tables if the user has requested this. */
3334
 
    if (create_info->row_type == ROW_TYPE_DYNAMIC ||
3335
 
        (new_field->flags & BLOB_FLAG) ||
3336
 
        (new_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
3337
 
      create_info->table_options|= HA_OPTION_PACK_RECORD;
3338
 
 
3339
 
    /* Check how fields have been modified */
3340
 
    if (alter_info->flags & ALTER_CHANGE_COLUMN)
3341
 
    {
3342
 
      /* Evaluate changes bitmap and send to check_if_incompatible_data() */
3343
 
      if (!(table_changes_local= field->is_equal(new_field)))
3344
 
        alter_flags->set(HA_ALTER_COLUMN_TYPE);
3345
 
 
3346
 
      /* Check if field was renamed */
3347
 
      field->flags&= ~FIELD_IS_RENAMED;
3348
 
      if (my_strcasecmp(system_charset_info,
3349
 
                        field->field_name,
3350
 
                        new_field->field_name))
3351
 
      {
3352
 
        field->flags|= FIELD_IS_RENAMED;
3353
 
        alter_flags->set(HA_ALTER_COLUMN_NAME);
3354
 
      }
3355
 
 
3356
 
      *table_changes&= table_changes_local;
3357
 
      if (table_changes_local == IS_EQUAL_PACK_LENGTH)
3358
 
        alter_flags->set(HA_ALTER_COLUMN_TYPE);
3359
 
 
3360
 
      /* Check that NULL behavior is same for old and new fields */
3361
 
      if ((new_field->flags & NOT_NULL_FLAG) !=
3362
 
          (uint32_t) (field->flags & NOT_NULL_FLAG))
3363
 
      {
3364
 
        *table_changes= IS_EQUAL_NO;
3365
 
        alter_flags->set(HA_ALTER_COLUMN_NULLABLE);
3366
 
      }
3367
 
    }
3368
 
 
3369
 
    /* Clear indexed marker */
3370
 
    field->flags&= ~FIELD_IN_ADD_INDEX;
3371
 
  }
3372
 
 
3373
 
  /*
3374
 
    Go through keys and check if the original ones are compatible
3375
 
    with new table.
3376
 
  */
3377
 
  KEY *table_key;
3378
 
  KEY *table_key_end= table->key_info + table->s->keys;
3379
 
  KEY *new_key;
3380
 
  KEY *new_key_end=
3381
 
       ha_alter_info->key_info_buffer + ha_alter_info->key_count;
3382
 
 
3383
 
  /*
3384
 
    Step through all keys of the old table and search matching new keys.
3385
 
  */
3386
 
  ha_alter_info->index_drop_count= 0;
3387
 
  ha_alter_info->index_add_count= 0;
3388
 
  for (table_key= table->key_info; table_key < table_key_end; table_key++)
3389
 
  {
3390
 
    KEY_PART_INFO *table_part;
3391
 
    KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
3392
 
    KEY_PART_INFO *new_part;
3393
 
 
3394
 
    /* Search a new key with the same name. */
3395
 
    for (new_key= ha_alter_info->key_info_buffer;
3396
 
         new_key < new_key_end;
3397
 
         new_key++)
3398
 
    {
3399
 
      if (! strcmp(table_key->name, new_key->name))
3400
 
        break;
3401
 
    }
3402
 
    if (new_key >= new_key_end)
3403
 
    {
3404
 
      /* Key not found. Add the offset of the key to the drop buffer. */
3405
 
      ha_alter_info->index_drop_buffer
3406
 
           [ha_alter_info->index_drop_count++]=
3407
 
           table_key - table->key_info;
3408
 
      if (table_key->flags & HA_NOSAME)
3409
 
      {
3410
 
        /* Unique key. Check for "PRIMARY". */
3411
 
        if (is_primary_key(table_key))
3412
 
          alter_flags->set(HA_DROP_PK_INDEX);
3413
 
        else
3414
 
          alter_flags->set(HA_DROP_UNIQUE_INDEX);
3415
 
      }
3416
 
      else
3417
 
        alter_flags->set(HA_DROP_INDEX);
3418
 
      *table_changes= IS_EQUAL_NO;
3419
 
      continue;
3420
 
    }
3421
 
 
3422
 
    /* Check that the key types are compatible between old and new tables. */
3423
 
    if ((table_key->algorithm != new_key->algorithm) ||
3424
 
        ((table_key->flags & HA_KEYFLAG_MASK) !=
3425
 
         (new_key->flags & HA_KEYFLAG_MASK)) ||
3426
 
        (table_key->key_parts != new_key->key_parts))
3427
 
    {
3428
 
      if (table_key->flags & HA_NOSAME)
3429
 
      {
3430
 
        // Unique key. Check for "PRIMARY".
3431
 
        if (is_primary_key(table_key))
3432
 
          alter_flags->set(HA_ALTER_PK_INDEX);
3433
 
        else
3434
 
          alter_flags->set(HA_ALTER_UNIQUE_INDEX);
3435
 
      }
3436
 
      else
3437
 
        alter_flags->set(HA_ALTER_INDEX);
3438
 
      goto index_changed;
3439
 
    }
3440
 
 
3441
 
    /*
3442
 
      Check that the key parts remain compatible between the old and
3443
 
      new tables.
3444
 
    */
3445
 
    for (table_part= table_key->key_part, new_part= new_key->key_part;
3446
 
         table_part < table_part_end;
3447
 
         table_part++, new_part++)
3448
 
    {
3449
 
      /*
3450
 
        Key definition has changed if we are using a different field or
3451
 
        if the used key part length is different. We know that the fields
3452
 
        did not change. Comparing field numbers is sufficient.
3453
 
      */
3454
 
      if ((table_part->length != new_part->length) ||
3455
 
          (table_part->fieldnr - 1 != new_part->fieldnr))
3456
 
      {
3457
 
        if (table_key->flags & HA_NOSAME)
3458
 
        {
3459
 
          /* Unique key. Check for "PRIMARY" */
3460
 
          if (is_primary_key(table_key))
3461
 
            alter_flags->set(HA_ALTER_PK_INDEX);
3462
 
          else
3463
 
            alter_flags->set(HA_ALTER_UNIQUE_INDEX);
3464
 
        }
3465
 
        else
3466
 
          alter_flags->set(HA_ALTER_INDEX);
3467
 
        goto index_changed;
3468
 
      }
3469
 
    }
3470
 
    continue;
3471
 
 
3472
 
  index_changed:
3473
 
    /* Key modified. Add the offset of the key to both buffers. */
3474
 
    ha_alter_info->index_drop_buffer
3475
 
         [ha_alter_info->index_drop_count++]=
3476
 
         table_key - table->key_info;
3477
 
    ha_alter_info->index_add_buffer
3478
 
         [ha_alter_info->index_add_count++]=
3479
 
         new_key - ha_alter_info->key_info_buffer;
3480
 
    key_part= new_key->key_part;
3481
 
    end= key_part + new_key->key_parts;
3482
 
    for(; key_part != end; key_part++)
3483
 
    {
3484
 
      /* Mark field to be part of new key */
3485
 
      if ((field= table->field[key_part->fieldnr]))
3486
 
        field->flags|= FIELD_IN_ADD_INDEX;
3487
 
    }
3488
 
    *table_changes= IS_EQUAL_NO;
3489
 
  }
3490
 
  /*end of for (; table_key < table_key_end;) */
3491
 
 
3492
 
  /*
3493
 
    Step through all keys of the new table and find matching old keys.
3494
 
  */
3495
 
  for (new_key= ha_alter_info->key_info_buffer;
3496
 
       new_key < new_key_end;
3497
 
       new_key++)
3498
 
  {
3499
 
    /* Search an old key with the same name. */
3500
 
    for (table_key= table->key_info; table_key < table_key_end; table_key++)
3501
 
    {
3502
 
      if (! strcmp(table_key->name, new_key->name))
3503
 
        break;
3504
 
    }
3505
 
    if (table_key >= table_key_end)
3506
 
    {
3507
 
      /* Key not found. Add the offset of the key to the add buffer. */
3508
 
      ha_alter_info->index_add_buffer
3509
 
           [ha_alter_info->index_add_count++]=
3510
 
           new_key - ha_alter_info->key_info_buffer;
3511
 
      key_part= new_key->key_part;
3512
 
      end= key_part + new_key->key_parts;
3513
 
      for(; key_part != end; key_part++)
3514
 
      {
3515
 
        /* Mark field to be part of new key */
3516
 
        if ((field= table->field[key_part->fieldnr]))
3517
 
          field->flags|= FIELD_IN_ADD_INDEX;
3518
 
      }
3519
 
      if (new_key->flags & HA_NOSAME)
3520
 
      {
3521
 
        /* Unique key. Check for "PRIMARY" */
3522
 
        if (is_primary_key(new_key))
3523
 
          alter_flags->set(HA_ADD_PK_INDEX);
3524
 
        else
3525
 
        alter_flags->set(HA_ADD_UNIQUE_INDEX);
3526
 
      }
3527
 
      else
3528
 
        alter_flags->set(HA_ADD_INDEX);
3529
 
      *table_changes= IS_EQUAL_NO;
3530
 
    }
3531
 
  }
3532
 
 
3533
 
  return(false);
3534
 
}
3535
 
 
3536
 
 
3537
3170
/*
3538
3171
  Manages enabling/disabling of indexes for ALTER Table
3539
3172
 
3647
3280
  return(error);
3648
3281
}
3649
3282
 
3650
 
/*
3651
 
  Create a temporary table that reflects what an alter table operation
3652
 
  will accomplish.
3653
 
 
3654
 
  SYNOPSIS
3655
 
    create_altered_table()
3656
 
      session              Thread handle
3657
 
      table            The original table
3658
 
      create_info      Information from the parsing phase about new
3659
 
                       table properties.
3660
 
      alter_info       Lists of fields, keys to be changed, added
3661
 
                       or dropped.
3662
 
      db_change        Specifies if the table is moved to another database
3663
 
  RETURN
3664
 
    A temporary table with all changes
3665
 
    NULL if error
3666
 
  NOTES
3667
 
    The temporary table is created without storing it in any storage engine
3668
 
    and is opened only to get the table struct and frm file reference.
3669
 
*/
3670
 
Table *create_altered_table(Session *session,
3671
 
                            Table *table,
3672
 
                            char *new_db,
3673
 
                            HA_CREATE_INFO *create_info,
3674
 
                            Alter_info *alter_info,
3675
 
                            bool db_change)
3676
 
{
3677
 
  int error;
3678
 
  HA_CREATE_INFO altered_create_info(*create_info);
3679
 
  Table *altered_table;
3680
 
  char tmp_name[80];
3681
 
  char path[FN_REFLEN];
3682
 
 
3683
 
  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64,
3684
 
           TMP_FILE_PREFIX, (unsigned long)current_pid, session->thread_id);
3685
 
  /* Safety fix for InnoDB */
3686
 
  if (lower_case_table_names)
3687
 
    my_casedn_str(files_charset_info, tmp_name);
3688
 
  altered_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
3689
 
 
3690
 
  if ((error= create_temporary_table(session, table, new_db, tmp_name,
3691
 
                                     &altered_create_info,
3692
 
                                     alter_info, db_change)))
3693
 
  {
3694
 
    return(NULL);
3695
 
  };
3696
 
 
3697
 
  build_table_filename(path, sizeof(path), new_db, tmp_name, "",
3698
 
                       FN_IS_TMP);
3699
 
  altered_table= open_temporary_table(session, path, new_db, tmp_name, 1,
3700
 
                                      OTM_ALTER);
3701
 
  return(altered_table);
3702
 
}
3703
 
 
3704
 
 
3705
 
/*
3706
 
  Perform a fast or on-line alter table
3707
 
 
3708
 
  SYNOPSIS
3709
 
    mysql_fast_or_online_alter_table()
3710
 
      session              Thread handle
3711
 
      table            The original table
3712
 
      altered_table    A temporary table showing how we will change table
3713
 
      create_info      Information from the parsing phase about new
3714
 
                       table properties.
3715
 
      alter_info       Storage place for data used during different phases
3716
 
      ha_alter_flags   Bitmask that shows what will be changed
3717
 
      keys_onoff       Specifies if keys are to be enabled/disabled
3718
 
  RETURN
3719
 
     0  OK
3720
 
    >0  An error occured during the on-line alter table operation
3721
 
    -1  Error when re-opening table
3722
 
  NOTES
3723
 
    If mysql_alter_table does not need to copy the table, it is
3724
 
    either a fast alter table where the storage engine does not
3725
 
    need to know about the change, only the frm will change,
3726
 
    or the storage engine supports performing the alter table
3727
 
    operation directly, on-line without mysql having to copy
3728
 
    the table.
3729
 
*/
3730
 
int mysql_fast_or_online_alter_table(Session *session,
3731
 
                                     Table *table,
3732
 
                                     Table *altered_table,
3733
 
                                     HA_CREATE_INFO *create_info,
3734
 
                                     HA_ALTER_INFO *alter_info,
3735
 
                                     HA_ALTER_FLAGS *ha_alter_flags,
3736
 
                                     enum enum_enable_or_disable keys_onoff)
3737
 
{
3738
 
  int error= 0;
3739
 
  bool online= (table->file->ha_table_flags() & HA_ONLINE_ALTER)?true:false;
3740
 
  Table *t_table;
3741
 
 
3742
 
  if (online)
3743
 
  {
3744
 
   /*
3745
 
      Tell the handler to prepare for the online alter
3746
 
    */
3747
 
    if ((error= table->file->alter_table_phase1(session,
3748
 
                                                altered_table,
3749
 
                                                create_info,
3750
 
                                                alter_info,
3751
 
                                                ha_alter_flags)))
3752
 
    {
3753
 
      goto err;
3754
 
    }
3755
 
 
3756
 
    /*
3757
 
       Tell the storage engine to perform the online alter table
3758
 
       TODO:
3759
 
       if check_if_supported_alter() returned HA_ALTER_SUPPORTED_WAIT_LOCK
3760
 
       we need to wrap the next call with a DDL lock.
3761
 
     */
3762
 
    if ((error= table->file->alter_table_phase2(session,
3763
 
                                                altered_table,
3764
 
                                                create_info,
3765
 
                                                alter_info,
3766
 
                                                ha_alter_flags)))
3767
 
    {
3768
 
      goto err;
3769
 
    }
3770
 
  }
3771
 
  /*
3772
 
    The final .frm file is already created as a temporary file
3773
 
    and will be renamed to the original table name.
3774
 
  */
3775
 
  pthread_mutex_lock(&LOCK_open);
3776
 
  wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3777
 
  alter_table_manage_keys(table, table->file->indexes_are_disabled(),
3778
 
                          keys_onoff);
3779
 
  close_data_files_and_morph_locks(session,
3780
 
                                   table->pos_in_table_list->db,
3781
 
                                   table->pos_in_table_list->table_name);
3782
 
  if (mysql_rename_table(NULL,
3783
 
                         altered_table->s->db.str,
3784
 
                         altered_table->s->table_name.str,
3785
 
                         table->s->db.str,
3786
 
                         table->s->table_name.str, FN_FROM_IS_TMP))
3787
 
  {
3788
 
    error= 1;
3789
 
    pthread_mutex_unlock(&LOCK_open);
3790
 
    goto err;
3791
 
  }
3792
 
  broadcast_refresh();
3793
 
  pthread_mutex_unlock(&LOCK_open);
3794
 
 
3795
 
  /*
3796
 
    The ALTER Table is always in its own transaction.
3797
 
    Commit must not be called while LOCK_open is locked. It could call
3798
 
    wait_if_global_read_lock(), which could create a deadlock if called
3799
 
    with LOCK_open.
3800
 
  */
3801
 
  error= ha_autocommit_or_rollback(session, 0);
3802
 
 
3803
 
  if (ha_commit(session))
3804
 
    error=1;
3805
 
  if (error)
3806
 
    goto err;
3807
 
  if (online)
3808
 
  {
3809
 
    pthread_mutex_lock(&LOCK_open);
3810
 
    if (reopen_table(table))
3811
 
    {
3812
 
      error= -1;
3813
 
      goto err;
3814
 
    }
3815
 
    pthread_mutex_unlock(&LOCK_open);
3816
 
    t_table= table;
3817
 
 
3818
 
   /*
3819
 
      Tell the handler that the changed frm is on disk and table
3820
 
      has been re-opened
3821
 
   */
3822
 
    if ((error= t_table->file->alter_table_phase3(session, t_table)))
3823
 
    {
3824
 
      goto err;
3825
 
    }
3826
 
 
3827
 
    /*
3828
 
      We are going to reopen table down on the road, so we have to restore
3829
 
      state of the Table object which we used for obtaining of handler
3830
 
      object to make it suitable for reopening.
3831
 
    */
3832
 
    assert(t_table == table);
3833
 
    table->open_placeholder= 1;
3834
 
    pthread_mutex_lock(&LOCK_open);
3835
 
    close_handle_and_leave_table_as_lock(table);
3836
 
    pthread_mutex_unlock(&LOCK_open);
3837
 
  }
3838
 
 
3839
 
 err:
3840
 
  if (error)
3841
 
    return(error);
3842
 
  return 0;
3843
 
}
3844
 
 
3845
3283
 
3846
3284
/**
3847
3285
  Prepare column and key definitions for CREATE TABLE in ALTER Table.
4571
4009
 
4572
4010
  set_table_default_charset(session, create_info, db);
4573
4011
 
4574
 
  if (session->variables.old_alter_table
4575
 
      || (table->s->db_type() != create_info->db_type)
4576
 
     )
4577
 
  {
4578
 
    if (alter_info->build_method == HA_BUILD_ONLINE)
4579
 
    {
4580
 
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4581
 
      goto err;
4582
 
    }
4583
 
    alter_info->build_method= HA_BUILD_OFFLINE;
4584
 
  }
4585
 
 
4586
 
  if (alter_info->build_method != HA_BUILD_OFFLINE)
4587
 
  {
4588
 
    Table *altered_table= 0;
4589
 
    HA_ALTER_INFO ha_alter_info;
4590
 
    HA_ALTER_FLAGS ha_alter_flags;
4591
 
    uint32_t table_changes= IS_EQUAL_YES;
4592
 
    bool need_copy_table= true;
4593
 
    /* Check how much the tables differ. */
4594
 
    if (compare_tables(session, table, alter_info,
4595
 
                       create_info, order_num,
4596
 
                       &ha_alter_flags,
4597
 
                       &ha_alter_info,
4598
 
                       &table_changes))
4599
 
    {
4600
 
      return(true);
4601
 
    }
4602
 
 
4603
 
    /*
4604
 
      Check if storage engine supports altering the table
4605
 
      on-line.
4606
 
    */
4607
 
 
4608
 
 
4609
 
    /*
4610
 
      If table is not renamed, changed database and
4611
 
      some change was detected then check if engine
4612
 
      can do the change on-line
4613
 
    */
4614
 
    if (new_name == table_name && new_db == db &&
4615
 
        ha_alter_flags.any())
4616
 
    {
4617
 
      Alter_info tmp_alter_info(*alter_info, session->mem_root);
4618
 
 
4619
 
      /*
4620
 
        If no table rename,
4621
 
        check if table can be altered on-line
4622
 
      */
4623
 
      if (!(altered_table= create_altered_table(session,
4624
 
                                                table,
4625
 
                                                new_db,
4626
 
                                                create_info,
4627
 
                                                &tmp_alter_info,
4628
 
                                                !strcmp(db, new_db))))
4629
 
        goto err;
4630
 
 
4631
 
      switch (table->file->check_if_supported_alter(altered_table,
4632
 
                                                    create_info,
4633
 
                                                    &ha_alter_flags,
4634
 
                                                    table_changes)) {
4635
 
      case HA_ALTER_SUPPORTED_WAIT_LOCK:
4636
 
      case HA_ALTER_SUPPORTED_NO_LOCK:
4637
 
        /*
4638
 
          @todo: Currently we always acquire an exclusive name
4639
 
          lock on the table metadata when performing fast or online
4640
 
          ALTER Table. In future we may consider this unnecessary,
4641
 
          and narrow the scope of the exclusive name lock to only
4642
 
          cover manipulation with .frms. Storage engine API
4643
 
          call check_if_supported_alter has provision for this
4644
 
          already now.
4645
 
        */
4646
 
        need_copy_table= false;
4647
 
        break;
4648
 
      case HA_ALTER_NOT_SUPPORTED:
4649
 
        if (alter_info->build_method == HA_BUILD_ONLINE)
4650
 
        {
4651
 
          my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4652
 
          close_temporary_table(session, altered_table, 1, 1);
4653
 
          goto err;
4654
 
        }
4655
 
        need_copy_table= true;
4656
 
        break;
4657
 
      case HA_ALTER_ERROR:
4658
 
      default:
4659
 
        close_temporary_table(session, altered_table, 1, 1);
4660
 
        goto err;
4661
 
      }
4662
 
 
4663
 
    }
4664
 
    /* TODO need to check if changes can be handled as fast ALTER Table */
4665
 
    if (!altered_table)
4666
 
      need_copy_table= true;
4667
 
 
4668
 
    if (!need_copy_table)
4669
 
    {
4670
 
      error= mysql_fast_or_online_alter_table(session,
4671
 
                                              table,
4672
 
                                              altered_table,
4673
 
                                              create_info,
4674
 
                                              &ha_alter_info,
4675
 
                                              &ha_alter_flags,
4676
 
                                              alter_info->keys_onoff);
4677
 
      if (session->lock)
4678
 
      {
4679
 
        mysql_unlock_tables(session, session->lock);
4680
 
        session->lock=0;
4681
 
      }
4682
 
      close_temporary_table(session, altered_table, 1, 1);
4683
 
 
4684
 
      if (error)
4685
 
      {
4686
 
        switch (error) {
4687
 
        case(-1):
4688
 
          goto err_with_placeholders;
4689
 
        default:
4690
 
          goto err;
4691
 
        }
4692
 
      }
4693
 
      else
4694
 
      {
4695
 
        pthread_mutex_lock(&LOCK_open);
4696
 
        goto end_online;
4697
 
      }
4698
 
    }
4699
 
 
4700
 
    if (altered_table)
4701
 
      close_temporary_table(session, altered_table, 1, 1);
4702
 
  }
 
4012
  alter_info->build_method= HA_BUILD_OFFLINE;
4703
4013
 
4704
4014
  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX,
4705
4015
           (unsigned long)current_pid, session->thread_id);
4874
4184
 
4875
4185
  quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
4876
4186
 
4877
 
end_online:
4878
4187
  if (session->locked_tables && new_name == table_name && new_db == db)
4879
4188
  {
4880
4189
    session->in_lock_tables= 1;