~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/statement/alter_table.cc

  • Committer: Brian Aker
  • Date: 2010-11-06 05:47:12 UTC
  • mto: This revision was merged to the branch mainline in revision 1909.
  • Revision ID: brian@tangent.org-20101106054712-jwxd8e0s0s3nm7qn
Merge in encapsulations in filesort.

Show diffs side-by-side

added added

removed removed

Lines of Context:
107
107
  assert(select_lex->db);
108
108
 
109
109
  /* Chicken/Egg... we need to search for the table, to know if the table exists, so we can build a full identifier from it */
110
 
  message::table::shared_ptr original_table_message;
 
110
  message::Table original_table_message;
111
111
  {
112
112
    TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
113
113
    if (plugin::StorageEngine::getTableDefinition(*session, identifier, original_table_message) != EEXIST)
114
114
    {
115
 
      std::string path;
116
 
      identifier.getSQLPath(path);
117
 
      my_error(ER_BAD_TABLE_ERROR, MYF(0), path.c_str());
 
115
      my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
118
116
      return true;
119
117
    }
120
118
 
121
119
    if (not  create_info.db_type)
122
120
    {
123
121
      create_info.db_type= 
124
 
        plugin::StorageEngine::findByName(*session, original_table_message->engine().name());
 
122
        plugin::StorageEngine::findByName(*session, original_table_message.engine().name());
125
123
 
126
124
      if (not create_info.db_type)
127
125
      {
128
 
        std::string path;
129
 
        identifier.getSQLPath(path);
130
 
        my_error(ER_BAD_TABLE_ERROR, MYF(0), path.c_str());
 
126
        my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
131
127
        return true;
132
128
      }
133
129
    }
134
130
  }
135
131
 
136
132
  if (not validateCreateTableOption())
 
133
  {
137
134
    return true;
 
135
  }
138
136
 
139
137
  /* ALTER TABLE ends previous transaction */
140
138
  if (not session->endActiveTransaction())
 
139
  {
141
140
    return true;
 
141
  }
142
142
 
143
 
  if (not (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
 
143
  if (not (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
 
144
  {
144
145
    return true;
 
146
  }
145
147
 
146
148
  bool res;
147
 
  if (original_table_message->type() == message::Table::STANDARD )
 
149
  if (original_table_message.type() == message::Table::STANDARD )
148
150
  {
149
151
    TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
150
152
    TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
154
156
                     identifier,
155
157
                     new_identifier,
156
158
                     &create_info,
157
 
                     *original_table_message,
 
159
                     original_table_message,
158
160
                     create_table_message,
159
161
                     first_table,
160
162
                     &alter_info,
177
179
                       identifier,
178
180
                       new_identifier,
179
181
                       &create_info,
180
 
                       *original_table_message,
 
182
                       original_table_message,
181
183
                       create_table_message,
182
184
                       first_table,
183
185
                       &alter_info,
191
193
     Release the protection against the global read lock and wake
192
194
     everyone, who might want to set a global read lock.
193
195
   */
194
 
  session->startWaitingGlobalReadLock();
195
 
 
 
196
  start_waiting_global_read_lock(session);
196
197
  return res;
197
198
}
198
199
 
347
348
        if (def->sql_type == DRIZZLE_TYPE_BLOB)
348
349
        {
349
350
          my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
350
 
          return true;
 
351
                goto err;
351
352
        }
352
353
        if ((def->def= alter->def))
353
354
        {
355
356
          def->flags&= ~NO_DEFAULT_VALUE_FLAG;
356
357
        }
357
358
        else
358
 
        {
359
359
          def->flags|= NO_DEFAULT_VALUE_FLAG;
360
 
        }
361
360
        alter_it.remove();
362
361
      }
363
362
    }
368
367
    if (def->change && ! def->field)
369
368
    {
370
369
      my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
371
 
      return true;
 
370
      goto err;
372
371
    }
373
372
    /*
374
 
      If we have been given a field which has no default value, and is not null then we need to bail.
 
373
      Check that the DATE/DATETIME not null field we are going to add is
 
374
      either has a default value or the '0000-00-00' is allowed by the
 
375
      set sql mode.
 
376
      If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
 
377
      flag to allow ALTER Table only if the table to be altered is empty.
375
378
    */
376
 
    if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
 
379
    if ((def->sql_type == DRIZZLE_TYPE_DATE ||
 
380
         def->sql_type == DRIZZLE_TYPE_DATETIME) &&
 
381
        ! alter_info->datetime_field &&
 
382
        ! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)))
377
383
    {
 
384
      alter_info->datetime_field= def;
378
385
      alter_info->error_if_not_empty= true;
379
386
    }
380
387
    if (! def->after)
381
 
    {
382
388
      new_create_list.push_back(def);
383
 
    }
384
389
    else if (def->after == first_keyword)
385
 
    {
386
390
      new_create_list.push_front(def);
387
 
    }
388
391
    else
389
392
    {
390
393
      CreateField *find;
397
400
      if (! find)
398
401
      {
399
402
        my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
400
 
        return true;
 
403
        goto err;
401
404
      }
402
405
      find_it.after(def); /* Put element after this */
403
406
      /*
412
415
      */
413
416
      if (alter_info->build_method == HA_BUILD_ONLINE)
414
417
      {
415
 
        my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->getQueryString()->c_str());
416
 
        return true;
 
418
        my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query.c_str());
 
419
        goto err;
417
420
      }
418
421
      alter_info->build_method= HA_BUILD_OFFLINE;
419
422
    }
424
427
             MYF(0),
425
428
             alter_info->alter_list.head()->name,
426
429
             table->getMutableShare()->getTableName());
427
 
    return true;
 
430
    goto err;
428
431
  }
429
432
  if (! new_create_list.elements)
430
433
  {
431
434
    my_message(ER_CANT_REMOVE_ALL_FIELDS,
432
435
               ER(ER_CANT_REMOVE_ALL_FIELDS),
433
436
               MYF(0));
434
 
    return true;
 
437
    goto err;
435
438
  }
436
439
 
437
440
  /*
568
571
      if (key->type == Key::FOREIGN_KEY)
569
572
      {
570
573
        if (((Foreign_key *)key)->validate(new_create_list))
571
 
        {
572
 
          return true;
573
 
        }
 
574
          goto err;
574
575
 
575
576
        Foreign_key *fkey= (Foreign_key*)key;
576
577
        add_foreign_key_to_table_message(&table_message,
591
592
        my_error(ER_WRONG_NAME_FOR_INDEX,
592
593
                 MYF(0),
593
594
                 key->name.str);
594
 
        return true;
 
595
        goto err;
595
596
      }
596
597
    }
597
598
  }
618
619
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
619
620
             MYF(0),
620
621
             alter_info->drop_list.head()->name);
621
 
    return true;
 
622
    goto err;
622
623
  }
623
624
  if (alter_info->alter_list.elements)
624
625
  {
625
626
    my_error(ER_CANT_DROP_FIELD_OR_KEY,
626
627
             MYF(0),
627
628
             alter_info->alter_list.head()->name);
628
 
    return true;
 
629
    goto err;
629
630
  }
630
631
 
631
632
  if (not table_message.options().has_comment()
644
645
  rc= false;
645
646
  alter_info->create_list.swap(new_create_list);
646
647
  alter_info->key_list.swap(new_key_list);
 
648
err:
647
649
 
648
650
  size_t num_engine_options= table_message.engine().options_size();
649
651
  size_t original_num_engine_options= original_proto.engine().options_size();
670
672
 
671
673
  drizzled::message::update(table_message);
672
674
 
673
 
  return false;
 
675
  return rc;
674
676
}
675
677
 
676
678
/* table_list should contain just one table */
712
714
 
713
715
  /* The ALTER Table is always in its own transaction */
714
716
  error= transaction_services.autocommitOrRollback(session, false);
715
 
  if (not session->endActiveTransaction())
 
717
  if (! session->endActiveTransaction())
716
718
    error=1;
717
 
 
718
719
  if (error)
719
720
    goto err;
720
 
 
721
 
  write_bin_log(session, *session->getQueryString());
 
721
  write_bin_log(session, session->query.c_str());
722
722
 
723
723
err:
724
724
  (void) transaction_services.autocommitOrRollback(session, error);
791
791
 
792
792
      if (session.find_temporary_table(new_table_identifier))
793
793
      {
794
 
        std::string path;
795
 
        new_table_identifier.getSQLPath(path);
796
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
794
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
797
795
        return false;
798
796
      }
799
797
    }
806
804
 
807
805
      if (not name_lock)
808
806
      {
809
 
        std::string path;
810
 
        new_table_identifier.getSQLPath(path);
811
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
807
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
812
808
        return false;
813
809
      }
814
810
 
815
811
      if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
816
812
      {
817
 
        std::string path;
818
 
        new_table_identifier.getSQLPath(path);
819
 
 
820
813
        /* Table will be closed by Session::executeCommand() */
821
 
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
814
        my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
822
815
 
823
 
        table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
 
816
        LOCK_open.lock(); /* ALTER TABLe */
824
817
        session.unlink_open_table(name_lock);
825
 
        table::Cache::singleton().mutex().unlock();
 
818
        LOCK_open.unlock();
826
819
 
827
820
        return false;
828
821
      }
893
886
  ha_rows copied= 0;
894
887
  ha_rows deleted= 0;
895
888
 
896
 
  if (not original_table_identifier.isValid())
897
 
    return true;
898
 
 
899
 
  if (not new_table_identifier.isValid())
900
 
    return true;
901
 
 
902
889
  session->set_proc_info("init");
903
890
 
904
891
  table->use_all_columns();
934
921
  if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
935
922
      new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
936
923
  {
937
 
    std::string path;
938
 
    new_table_identifier.getSQLPath(path);
939
 
    my_error(ER_ILLEGAL_HA, MYF(0), path.c_str());
 
924
    my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
940
925
 
941
926
    return true;
942
927
  }
970
955
          while the fact that the table is still open gives us protection
971
956
          from concurrent DDL statements.
972
957
        */
973
 
        table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
 
958
        LOCK_open.lock(); /* DDL wait for/blocker */
974
959
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
975
 
        table::Cache::singleton().mutex().unlock();
 
960
        LOCK_open.unlock();
976
961
        error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
977
962
        /* COND_refresh will be signaled in close_thread_tables() */
978
963
        break;
979
964
      case DISABLE:
980
 
        table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
 
965
        LOCK_open.lock(); /* DDL wait for/blocker */
981
966
        wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
982
 
        table::Cache::singleton().mutex().unlock();
 
967
        LOCK_open.unlock();
983
968
        error=table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
984
969
        /* COND_refresh will be signaled in close_thread_tables() */
985
970
        break;
997
982
                            table->getAlias());
998
983
      }
999
984
 
1000
 
      table::Cache::singleton().mutex().lock(); /* Lock to remove all instances of table from table cache before ALTER */
 
985
      LOCK_open.lock(); /* Lock to remove all instances of table from table cache before ALTER */
1001
986
      /*
1002
987
        Unlike to the above case close_cached_table() below will remove ALL
1003
988
        instances of Table from table cache (it will also remove table lock
1004
989
        held by this thread). So to make actual table renaming and writing
1005
990
        to binlog atomic we have to put them into the same critical section
1006
 
        protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
 
991
        protected by LOCK_open mutex. This also removes gap for races between
1007
992
        access() and mysql_rename_table() calls.
1008
993
      */
1009
994
 
1025
1010
        */
1026
1011
        if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1027
1012
        {
1028
 
          std::string path;
1029
 
          new_table_identifier.getSQLPath(path);
1030
 
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
 
1013
          my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
1031
1014
          error= -1;
1032
1015
        }
1033
1016
        else
1049
1032
 
1050
1033
      if (error == 0)
1051
1034
      {
1052
 
        TransactionServices &transaction_services= TransactionServices::singleton();
1053
 
        transaction_services.allocateNewTransactionId();
1054
 
        write_bin_log(session, *session->getQueryString());
 
1035
        write_bin_log(session, session->query.c_str());
1055
1036
        session->my_ok();
1056
1037
      }
1057
1038
      else if (error > 0)
1060
1041
        error= -1;
1061
1042
      }
1062
1043
 
1063
 
      table::Cache::singleton().mutex().unlock();
 
1044
      LOCK_open.unlock();
1064
1045
      table_list->table= NULL;
1065
1046
 
1066
1047
      return error;
1105
1086
 
1106
1087
  if (not new_table)
1107
1088
  {
1108
 
    plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
 
1089
    quick_rm_table(*session, new_table_as_temporary);
1109
1090
    return true;
1110
1091
  }
1111
1092
 
1149
1130
    */
1150
1131
    if (alter_info->error_if_not_empty && session->row_count)
1151
1132
    {
1152
 
      my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
 
1133
      const char *f_val= 0;
 
1134
      enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
 
1135
 
 
1136
      switch (alter_info->datetime_field->sql_type)
 
1137
      {
 
1138
      case DRIZZLE_TYPE_DATE:
 
1139
        f_val= "0000-00-00";
 
1140
        t_type= DRIZZLE_TIMESTAMP_DATE;
 
1141
        break;
 
1142
      case DRIZZLE_TYPE_DATETIME:
 
1143
        f_val= "0000-00-00 00:00:00";
 
1144
        t_type= DRIZZLE_TIMESTAMP_DATETIME;
 
1145
        break;
 
1146
      default:
 
1147
        /* Shouldn't get here. */
 
1148
        assert(0);
 
1149
      }
 
1150
      bool save_abort_on_warning= session->abort_on_warning;
 
1151
      session->abort_on_warning= true;
 
1152
      make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
1153
                                   f_val, internal::strlength(f_val), t_type,
 
1154
                                   alter_info->datetime_field->field_name);
 
1155
      session->abort_on_warning= save_abort_on_warning;
1153
1156
    }
1154
1157
 
1155
1158
    if (original_table_identifier.isTmp())
1161
1164
      }
1162
1165
      else
1163
1166
      {
1164
 
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
 
1167
        quick_rm_table(*session, new_table_as_temporary);
1165
1168
      }
1166
1169
 
1167
1170
      return true;
1183
1186
        delete new_table;
1184
1187
      }
1185
1188
 
1186
 
      table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
 
1189
      LOCK_open.lock(); /* ALTER TABLE */
1187
1190
 
1188
 
      plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1189
 
      table::Cache::singleton().mutex().unlock();
 
1191
      quick_rm_table(*session, new_table_as_temporary);
 
1192
      LOCK_open.unlock();
1190
1193
 
1191
1194
      return true;
1192
1195
    }
1197
1200
    /* Close lock if this is a transactional table */
1198
1201
    if (session->lock)
1199
1202
    {
1200
 
      session->unlockTables(session->lock);
 
1203
      mysql_unlock_tables(session, session->lock);
1201
1204
      session->lock= 0;
1202
1205
    }
1203
1206
 
1233
1236
      delete new_table;
1234
1237
    }
1235
1238
 
1236
 
    table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
 
1239
    LOCK_open.lock(); /* ALTER TABLE */
1237
1240
 
1238
1241
    /*
1239
1242
      Data is copied. Now we:
1278
1281
    if (mysql_rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1279
1282
    {
1280
1283
      error= 1;
1281
 
      plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
 
1284
      quick_rm_table(*session, new_table_as_temporary);
1282
1285
    }
1283
1286
    else
1284
1287
    {
1287
1290
        /* Try to get everything back. */
1288
1291
        error= 1;
1289
1292
 
1290
 
        plugin::StorageEngine::dropTable(*session, new_table_identifier);
 
1293
        quick_rm_table(*session, new_table_identifier);
1291
1294
 
1292
 
        plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
 
1295
        quick_rm_table(*session, new_table_as_temporary);
1293
1296
 
1294
1297
        mysql_rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1295
1298
      }
1296
1299
      else
1297
1300
      {
1298
 
        plugin::StorageEngine::dropTable(*session, original_table_to_drop);
 
1301
        quick_rm_table(*session, original_table_to_drop);
1299
1302
      }
1300
1303
    }
1301
1304
 
1307
1310
        from list of open tables list and table cache.
1308
1311
      */
1309
1312
      session->unlink_open_table(table);
1310
 
      table::Cache::singleton().mutex().unlock();
 
1313
      LOCK_open.unlock();
1311
1314
 
1312
1315
      return true;
1313
1316
    }
1314
1317
 
1315
 
    table::Cache::singleton().mutex().unlock();
 
1318
    LOCK_open.unlock();
1316
1319
 
1317
1320
    session->set_proc_info("end");
1318
1321
 
1319
 
    write_bin_log(session, *session->getQueryString());
 
1322
    write_bin_log(session, session->query.c_str());
1320
1323
    table_list->table= NULL;
1321
1324
  }
1322
1325
 
1395
1398
 
1396
1399
    if (name_lock)
1397
1400
    {
1398
 
      table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
 
1401
      LOCK_open.lock(); /* ALTER TABLe */
1399
1402
      session->unlink_open_table(name_lock);
1400
 
      table::Cache::singleton().mutex().unlock();
 
1403
      LOCK_open.unlock();
1401
1404
    }
1402
1405
  }
1403
1406
 
1440
1443
  /* 
1441
1444
   * LP Bug #552420 
1442
1445
   *
1443
 
   * Since open_temporary_table() doesn't invoke lockTables(), we
 
1446
   * Since open_temporary_table() doesn't invoke mysql_lock_tables(), we
1444
1447
   * don't get the usual automatic call to StorageEngine::startStatement(), so
1445
1448
   * we manually call it here...
1446
1449
   */
1525
1528
  to->restoreRecordAsDefault();        // Create empty record
1526
1529
  while (!(error=info.read_record(&info)))
1527
1530
  {
1528
 
    if (session->getKilled())
 
1531
    if (session->killed)
1529
1532
    {
1530
1533
      session->send_kill_message();
1531
1534
      error= 1;
1546
1549
        to->next_number_field->reset();
1547
1550
    }
1548
1551
 
1549
 
    for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
 
1552
    for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1550
1553
    {
1551
 
      if (not copy->to_field->hasDefault() and copy->from_null_ptr and  *copy->from_null_ptr & copy->from_bit)
1552
 
      {
1553
 
        copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1554
 
                                    ER_WARN_DATA_TRUNCATED, 1);
1555
 
        copy->to_field->reset();
1556
 
        error= 1;
1557
 
        break;
1558
 
      }
1559
 
 
1560
1554
      copy_ptr->do_copy(copy_ptr);
1561
1555
    }
1562
 
 
1563
 
    if (error)
1564
 
    {
1565
 
      break;
1566
 
    }
1567
 
 
1568
1556
    prev_insert_id= to->cursor->next_insert_id;
1569
1557
    error= to->cursor->insertRecord(to->record[0]);
1570
1558
    to->auto_increment_field_not_null= false;
1571
1559
 
1572
1560
    if (error)
1573
1561
    { 
1574
 
      if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
1562
      if (!ignore ||
 
1563
          to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1575
1564
      { 
1576
1565
        to->print_error(error, MYF(0));
1577
1566
        break;