~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_table.cc

Merge fix for Bug 394272.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3456
3456
    true   Error
3457
3457
*/
3458
3458
 
3459
 
bool mysql_alter_table(Session *session, char *new_db, char *new_name,
 
3459
bool mysql_alter_table(Session *session, 
 
3460
                       char *new_db, 
 
3461
                       char *new_name,
3460
3462
                       HA_CREATE_INFO *create_info,
3461
3463
                       TableList *table_list,
3462
3464
                       Alter_info *alter_info,
3463
 
                       uint32_t order_num, order_st *order, bool ignore)
 
3465
                       uint32_t order_num, 
 
3466
                       order_st *order, 
 
3467
                       bool ignore)
3464
3468
{
3465
 
  Table *table, *new_table=0, *name_lock= 0;;
 
3469
  Table *table;
 
3470
  Table *new_table= NULL;
 
3471
  Table *name_lock= NULL;
3466
3472
  string new_name_str;
3467
3473
  int error= 0;
3468
 
  char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
3469
 
  char new_alias_buff[FN_REFLEN], *table_name, *db;
 
3474
  char tmp_name[80];
 
3475
  char old_name[32];
 
3476
  char new_name_buff[FN_REFLEN];
 
3477
  char new_alias_buff[FN_REFLEN];
 
3478
  char *table_name;
 
3479
  char *db;
3470
3480
  const char *new_alias;
3471
3481
  char path[FN_REFLEN];
3472
 
  ha_rows copied= 0,deleted= 0;
3473
 
  StorageEngine *old_db_type, *new_db_type, *save_old_db_type;
 
3482
  ha_rows copied= 0;
 
3483
  ha_rows deleted= 0;
 
3484
  StorageEngine *old_db_type;
 
3485
  StorageEngine *new_db_type;
 
3486
  StorageEngine *save_old_db_type;
3474
3487
  bitset<32> tmp;
3475
3488
 
3476
3489
  new_name_buff[0]= '\0';
3481
3494
    return true;
3482
3495
  }
3483
3496
 
 
3497
  session->set_proc_info("init");
 
3498
 
3484
3499
  /*
3485
3500
    Assign variables table_name, new_name, db, new_db, path
3486
3501
    to simplify further comparisons: we want to see if it's a RENAME
3487
3502
    later just by comparing the pointers, avoiding the need for strcmp.
3488
3503
  */
3489
 
  session->set_proc_info("init");
3490
3504
  table_name= table_list->table_name;
3491
 
  db=table_list->db;
3492
 
  if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
 
3505
  db= table_list->db;
 
3506
  if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
3493
3507
    new_db= db;
 
3508
 
 
3509
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
 
3510
  {
 
3511
    /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
 
3512
    return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
 
3513
  }
 
3514
 
3494
3515
  build_table_filename(path, sizeof(path), db, table_name, false);
3495
3516
 
3496
 
  /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
3497
 
  if (alter_info->tablespace_op != NO_TABLESPACE_OP)
3498
 
    /* Conditionally writes to binlog. */
3499
 
    return(mysql_discard_or_import_tablespace(session,table_list,
3500
 
                                              alter_info->tablespace_op));
3501
3517
  ostringstream oss;
3502
3518
  oss << drizzle_data_home << "/" << db << "/" << table_name;
3503
3519
 
3504
3520
  (void) unpack_filename(new_name_buff, oss.str().c_str());
 
3521
 
3505
3522
  /*
3506
3523
    If this is just a rename of a view, short cut to the
3507
3524
    following scenario: 1) lock LOCK_open 2) do a RENAME
3518
3535
 
3519
3536
  if (!(table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
3520
3537
    return true;
 
3538
  
3521
3539
  table->use_all_columns();
3522
3540
 
3523
3541
  /* Check that we are not trying to rename to an existing table */
3528
3546
    new_alias= new_alias_buff;
3529
3547
 
3530
3548
    my_casedn_str(files_charset_info, new_name_buff);
3531
 
    new_alias= new_name;                        // Create lower case table name
 
3549
    new_alias= new_name; // Create lower case table name
3532
3550
    my_casedn_str(files_charset_info, new_name);
3533
3551
 
3534
3552
    if (new_db == db &&
3535
 
        !my_strcasecmp(table_alias_charset, new_name_buff, table_name))
 
3553
        ! my_strcasecmp(table_alias_charset, new_name_buff, table_name))
3536
3554
    {
3537
3555
      /*
3538
 
        Source and destination table names are equal: make later check
3539
 
        easier.
 
3556
        Source and destination table names are equal: make later check
 
3557
        easier.
3540
3558
      */
3541
3559
      new_alias= new_name= table_name;
3542
3560
    }
3544
3562
    {
3545
3563
      if (table->s->tmp_table != NO_TMP_TABLE)
3546
3564
      {
3547
 
        if (session->find_temporary_table(new_db, new_name_buff))
3548
 
        {
3549
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
3550
 
          return true;
3551
 
        }
 
3565
        if (session->find_temporary_table(new_db, new_name_buff))
 
3566
        {
 
3567
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
 
3568
          return true;
 
3569
        }
3552
3570
      }
3553
3571
      else
3554
3572
      {
3555
3573
        if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
3556
3574
          return true;
3557
3575
 
3558
 
        if (!name_lock)
 
3576
        if (! name_lock)
3559
3577
        {
3560
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
3561
 
          return true;
 
3578
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
 
3579
          return true;
3562
3580
        }
3563
3581
 
3564
 
        build_table_filename(new_name_buff, sizeof(new_name_buff),
3565
 
                             new_db, new_name_buff, false);
 
3582
        build_table_filename(new_name_buff, sizeof(new_name_buff), new_db, new_name_buff, false);
 
3583
 
3566
3584
        if (StorageEngine::getTableProto(new_name_buff, NULL) == EEXIST)
3567
 
        {
3568
 
          /* Table will be closed by Session::executeCommand() */
3569
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
3570
 
          goto err;
3571
 
        }
 
3585
        {
 
3586
          /* Table will be closed by Session::executeCommand() */
 
3587
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
 
3588
          goto err;
 
3589
        }
3572
3590
      }
3573
3591
    }
3574
3592
  }
3579
3597
  }
3580
3598
 
3581
3599
  old_db_type= table->s->db_type();
3582
 
  if (!create_info->db_type)
 
3600
  if (! create_info->db_type)
3583
3601
  {
3584
3602
    create_info->db_type= old_db_type;
3585
3603
  }
3586
3604
 
3587
 
  if(table->s->tmp_table != NO_TMP_TABLE)
 
3605
  if (table->s->tmp_table != NO_TMP_TABLE)
3588
3606
    create_info->options|= HA_LEX_CREATE_TMP_TABLE;
3589
3607
 
3590
3608
  if (check_engine(session, new_name, create_info))
3591
3609
    goto err;
 
3610
 
3592
3611
  new_db_type= create_info->db_type;
3593
3612
 
3594
3613
  if (new_db_type != old_db_type &&
3610
3629
  }
3611
3630
 
3612
3631
  session->set_proc_info("setup");
 
3632
  
3613
3633
  /*
3614
3634
   * test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
3615
3635
   */
3620
3640
  if (! (tmp.any()) &&
3621
3641
      ! table->s->tmp_table) // no need to touch frm
3622
3642
  {
3623
 
    switch (alter_info->keys_onoff) {
 
3643
    switch (alter_info->keys_onoff)
 
3644
    {
3624
3645
    case LEAVE_AS_IS:
3625
3646
      break;
3626
3647
    case ENABLE:
3651
3672
      error= 0;
3652
3673
      break;
3653
3674
    }
 
3675
 
3654
3676
    if (error == HA_ERR_WRONG_COMMAND)
3655
3677
    {
3656
3678
      error= 0;
3669
3691
      access() and mysql_rename_table() calls.
3670
3692
    */
3671
3693
 
3672
 
    if (!error && (new_name != table_name || new_db != db))
 
3694
    if (error == 0 && 
 
3695
        (new_name != table_name || new_db != db))
3673
3696
    {
3674
3697
      session->set_proc_info("rename");
3675
3698
      /*
3692
3715
      }
3693
3716
      else
3694
3717
      {
3695
 
        *fn_ext(new_name)=0;
 
3718
        *fn_ext(new_name)= 0;
3696
3719
        if (mysql_rename_table(old_db_type, db, table_name, new_db, new_alias, 0))
3697
3720
          error= -1;
3698
 
        else if (0)
3699
 
        {
3700
 
          mysql_rename_table(old_db_type, new_db, new_alias, db,
3701
 
                             table_name, 0);
3702
 
          error= -1;
3703
 
        }
3704
3721
      }
3705
3722
    }
3706
3723
 
3712
3729
                          table->alias);
3713
3730
    }
3714
3731
 
3715
 
    if (!error)
 
3732
    if (error == 0)
3716
3733
    {
3717
3734
      write_bin_log(session, true, session->query, session->query_length);
3718
3735
      session->my_ok();
3719
 
  }
 
3736
    }
3720
3737
    else if (error > 0)
3721
 
  {
 
3738
    {
3722
3739
      table->file->print_error(error, MYF(0));
3723
3740
      error= -1;
3724
3741
    }
 
3742
 
3725
3743
    if (name_lock)
3726
3744
      session->unlink_open_table(name_lock);
 
3745
 
3727
3746
    pthread_mutex_unlock(&LOCK_open);
3728
 
    table_list->table= NULL;                    // For query cache
3729
 
    return(error);
 
3747
    table_list->table= NULL;
 
3748
    return error;
3730
3749
  }
3731
3750
 
3732
3751
  /* We have to do full alter table. */
3733
3752
 
3734
 
    /*
 
3753
  /*
3735
3754
    If the old table had partitions and we are doing ALTER Table ...
3736
3755
    engine= <new_engine>, the new table must preserve the original
3737
3756
    partitioning. That means that the new engine is still the
3745
3764
  new_db_type= create_info->db_type;
3746
3765
 
3747
3766
  if (mysql_prepare_alter_table(session, table, create_info, alter_info))
3748
 
      goto err;
 
3767
    goto err;
3749
3768
 
3750
3769
  set_table_default_charset(create_info, db);
3751
3770
 
3752
3771
  alter_info->build_method= HA_BUILD_OFFLINE;
3753
3772
 
3754
 
  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX,
3755
 
           (unsigned long)current_pid, session->thread_id);
 
3773
  snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
3774
  
3756
3775
  /* Safety fix for innodb */
3757
3776
  my_casedn_str(files_charset_info, tmp_name);
3758
3777
 
3759
 
 
3760
3778
  /* Create a temporary table with the new format */
3761
 
  if ((error= create_temporary_table(session, table, new_db, tmp_name,
3762
 
                                     create_info, alter_info,
3763
 
                                     !strcmp(db, new_db))))
3764
 
  {
 
3779
  error= create_temporary_table(session, table, new_db, tmp_name, create_info, alter_info, ! strcmp(db, new_db));
 
3780
 
 
3781
  if (error != 0)
3765
3782
    goto err;
3766
 
  }
3767
3783
 
3768
3784
  /* Open the table so we need to copy the data to it. */
3769
3785
  if (table->s->tmp_table)
3790
3806
 
3791
3807
  /* Copy the data if necessary. */
3792
3808
  session->count_cuted_fields= CHECK_FIELD_WARN;        // calc cuted fields
3793
 
  session->cuted_fields=0L;
 
3809
  session->cuted_fields= 0L;
3794
3810
  session->set_proc_info("copy to tmp table");
3795
3811
  copied= deleted= 0;
3796
3812
 
3798
3814
 
3799
3815
  /* We don't want update TIMESTAMP fields during ALTER Table. */
3800
3816
  new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
3801
 
  new_table->next_number_field=new_table->found_next_number_field;
3802
 
  error= copy_data_between_tables(table, new_table,
3803
 
                                  alter_info->create_list, ignore,
3804
 
                                  order_num, order, &copied, &deleted,
 
3817
  new_table->next_number_field= new_table->found_next_number_field;
 
3818
  error= copy_data_between_tables(table, 
 
3819
                                  new_table,
 
3820
                                  alter_info->create_list, 
 
3821
                                  ignore,
 
3822
                                  order_num, 
 
3823
                                  order, 
 
3824
                                  &copied, 
 
3825
                                  &deleted,
3805
3826
                                  alter_info->keys_onoff,
3806
3827
                                  alter_info->error_if_not_empty);
3807
3828
 
3808
 
  /* We must not ignore bad input! */;
 
3829
  /* We must not ignore bad input! */
3809
3830
  session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
3810
3831
 
3811
3832
  if (table->s->tmp_table != NO_TMP_TABLE)
3813
3834
    /* We changed a temporary table */
3814
3835
    if (error)
3815
3836
      goto err1;
 
3837
 
3816
3838
    /* Close lock if this is a transactional table */
3817
3839
    if (session->lock)
3818
3840
    {
3819
3841
      mysql_unlock_tables(session, session->lock);
3820
 
      session->lock=0;
 
3842
      session->lock= 0;
3821
3843
    }
 
3844
 
3822
3845
    /* Remove link to old table and rename the new one */
3823
3846
    session->close_temporary_table(table, true, true);
 
3847
 
3824
3848
    /* Should pass the 'new_name' as we store table name in the cache */
3825
3849
    if (new_table->rename_temporary_table(new_db, new_name))
3826
3850
      goto err1;
 
3851
    
3827
3852
    goto end_temporary;
3828
3853
  }
3829
3854
 
3836
3861
    new_table->intern_close_table();
3837
3862
    free(new_table);
3838
3863
  }
 
3864
 
3839
3865
  pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
 
3866
  
3840
3867
  if (error)
3841
3868
  {
3842
3869
    quick_rm_table(new_db_type, new_db, tmp_name, true);
3861
3888
  */
3862
3889
 
3863
3890
  session->set_proc_info("rename result table");
3864
 
  snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX,
3865
 
           (unsigned long)current_pid, session->thread_id);
 
3891
 
 
3892
  snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
 
3893
 
3866
3894
  my_casedn_str(files_charset_info, old_name);
3867
3895
 
3868
3896
  wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
3869
3897
  session->close_data_files_and_morph_locks(db, table_name);
3870
3898
 
3871
 
  error=0;
 
3899
  error= 0;
3872
3900
  save_old_db_type= old_db_type;
3873
3901
 
3874
3902
  /*
3884
3912
    table is renamed and the SE is also changed, then an intermediate table
3885
3913
    is created and the additional call will not take place.
3886
3914
  */
3887
 
  if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
3888
 
                         FN_TO_IS_TMP))
3889
 
  {
3890
 
    error=1;
3891
 
    quick_rm_table(new_db_type, new_db, tmp_name, true);
3892
 
  }
3893
 
  else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
3894
 
                              new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && 0))
3895
 
  {
3896
 
    /* Try to get everything back. */
 
3915
  if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
 
3916
  {
3897
3917
    error= 1;
3898
 
    quick_rm_table(new_db_type, new_db, new_alias, false);
3899
3918
    quick_rm_table(new_db_type, new_db, tmp_name, true);
3900
 
    mysql_rename_table(old_db_type, db, old_name, db, table_name,
3901
 
                       FN_FROM_IS_TMP);
 
3919
  }
 
3920
  else
 
3921
  {
 
3922
    if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
 
3923
    {
 
3924
      /* Try to get everything back. */
 
3925
      error= 1;
 
3926
      quick_rm_table(new_db_type, new_db, new_alias, false);
 
3927
      quick_rm_table(new_db_type, new_db, tmp_name, true);
 
3928
      mysql_rename_table(old_db_type, db, old_name, db, table_name, FN_FROM_IS_TMP);
 
3929
    }
3902
3930
  }
3903
3931
 
3904
3932
  if (error)
3932
3960
      free(t_table);
3933
3961
    }
3934
3962
    else
3935
 
      errmsg_printf(ERRMSG_LVL_WARN,
3936
 
                    _("Could not open table %s.%s after rename\n"),
3937
 
                    new_db,table_name);
 
3963
      errmsg_printf(ERRMSG_LVL_WARN, _("Could not open table %s.%s after rename\n"), new_db, table_name);
 
3964
 
3938
3965
    ha_flush_logs(old_db_type);
3939
3966
  }
3940
 
  table_list->table=0;                          // For query cache
 
3967
  table_list->table= NULL;
3941
3968
 
3942
3969
end_temporary:
3943
3970
  /*
4019
4046
  if (name_lock)
4020
4047
    session->unlink_open_table(name_lock);
4021
4048
  pthread_mutex_unlock(&LOCK_open);
4022
 
  return(true);
 
4049
  return true;
4023
4050
}
4024
4051
/* mysql_alter_table */
4025
4052