18
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
#include <drizzled/show.h>
28
#include <drizzled/lock.h>
29
#include <drizzled/session.h>
30
#include <drizzled/statement/alter_table.h>
31
#include <drizzled/global_charset_info.h>
34
#include <drizzled/gettext.h>
35
#include <drizzled/data_home.h>
36
#include <drizzled/sql_table.h>
37
#include <drizzled/table_proto.h>
38
#include <drizzled/optimizer/range.h>
39
#include <drizzled/time_functions.h>
40
#include <drizzled/records.h>
41
#include <drizzled/pthread_globals.h>
42
#include <drizzled/internal/my_sys.h>
43
#include <drizzled/internal/iocache.h>
44
#include <drizzled/plugin/storage_engine.h>
45
#include <drizzled/copy_field.h>
47
#include <drizzled/transaction_services.h>
49
#include <drizzled/filesort.h>
51
#include <drizzled/message.h>
27
#include "drizzled/show.h"
28
#include "drizzled/lock.h"
29
#include "drizzled/session.h"
30
#include "drizzled/statement/alter_table.h"
31
#include "drizzled/global_charset_info.h"
34
#include "drizzled/gettext.h"
35
#include "drizzled/data_home.h"
36
#include "drizzled/sql_table.h"
37
#include "drizzled/table_proto.h"
38
#include "drizzled/optimizer/range.h"
39
#include "drizzled/time_functions.h"
40
#include "drizzled/records.h"
41
#include "drizzled/pthread_globals.h"
42
#include "drizzled/internal/my_sys.h"
43
#include "drizzled/internal/iocache.h"
45
#include "drizzled/transaction_services.h"
47
#include "drizzled/filesort.h"
49
#include "drizzled/message.h"
53
51
using namespace std;
245
240
@retval false success
247
242
static bool prepare_alter_table(Session *session,
249
HA_CREATE_INFO *create_info,
250
const message::Table &original_proto,
251
message::Table &table_message,
252
AlterInfo *alter_info)
244
HA_CREATE_INFO *create_info,
245
const message::Table &original_proto,
246
message::Table &table_message,
247
AlterInfo *alter_info)
254
249
/* New column definitions are added here */
255
250
List<CreateField> new_create_list;
256
251
/* New key definitions are added here */
257
252
List<Key> new_key_list;
258
List<AlterDrop>::iterator drop_it(alter_info->drop_list.begin());
259
List<CreateField>::iterator def_it(alter_info->create_list.begin());
260
List<AlterColumn>::iterator alter_it(alter_info->alter_list.begin());
261
List<Key>::iterator key_it(alter_info->key_list.begin());
262
List<CreateField>::iterator find_it(new_create_list.begin());
263
List<CreateField>::iterator field_it(new_create_list.begin());
253
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
254
List_iterator<CreateField> def_it(alter_info->create_list);
255
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
256
List_iterator<Key> key_it(alter_info->key_list);
257
List_iterator<CreateField> find_it(new_create_list);
258
List_iterator<CreateField> field_it(new_create_list);
264
259
List<Key_part_spec> key_parts;
265
260
uint32_t used_fields= create_info->used_fields;
266
261
KeyInfo *key_info= table->key_info;
996
985
while the fact that the table is still open gives us protection
997
986
from concurrent DDL statements.
1000
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
1001
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
988
table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
989
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
990
table::Cache::singleton().mutex().unlock();
1003
991
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1005
992
/* COND_refresh will be signaled in close_thread_tables() */
1010
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
1011
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1013
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
995
table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
996
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
997
table::Cache::singleton().mutex().unlock();
998
error=table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1015
999
/* COND_refresh will be signaled in close_thread_tables() */
1019
1007
if (error == HA_ERR_WRONG_COMMAND)
1022
1010
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1023
1011
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1024
1012
table->getAlias());
1027
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* Lock to remove all instances of table from table cache before ALTER */
1015
table::Cache::singleton().mutex().lock(); /* Lock to remove all instances of table from table cache before ALTER */
1029
1017
Unlike to the above case close_cached_table() below will remove ALL
1030
1018
instances of Table from table cache (it will also remove table lock
1261
1248
delete new_table;
1265
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* ALTER TABLE */
1267
Data is copied. Now we:
1268
1) Wait until all other threads close old version of table.
1269
2) Close instances of table open by this thread and replace them
1270
with exclusive name-locks.
1271
3) Rename the old table to a temp name, rename the new one to the
1273
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1274
we reopen new version of table.
1275
5) Write statement to the binary log.
1276
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1277
remove name-locks from list of open tables and table cache.
1278
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1279
call to remove name-locks from table cache and list of open table.
1282
session->set_proc_info("rename result table");
1284
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1286
my_casedn_str(files_charset_info, old_name);
1288
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1289
session->close_data_files_and_morph_locks(original_table_identifier);
1294
This leads to the storage engine (SE) not being notified for renames in
1295
rename_table(), because we just juggle with the FRM and nothing
1296
more. If we have an intermediate table, then we notify the SE that
1297
it should become the actual table. Later, we will recycle the old table.
1298
However, in case of ALTER Table RENAME there might be no intermediate
1299
table. This is when the old and new tables are compatible, according to
1300
compare_table(). Then, we need one additional call to
1302
identifier::Table original_table_to_drop(original_table_identifier.getSchemaName(),
1303
old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1304
message::Table::TEMPORARY);
1306
drizzled::error_t rename_error= EE_OK;
1307
if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1251
table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
1254
Data is copied. Now we:
1255
1) Wait until all other threads close old version of table.
1256
2) Close instances of table open by this thread and replace them
1257
with exclusive name-locks.
1258
3) Rename the old table to a temp name, rename the new one to the
1260
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1261
we reopen new version of table.
1262
5) Write statement to the binary log.
1263
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1264
remove name-locks from list of open tables and table cache.
1265
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1266
call to remove name-locks from table cache and list of open table.
1269
session->set_proc_info("rename result table");
1271
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1273
my_casedn_str(files_charset_info, old_name);
1275
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1276
session->close_data_files_and_morph_locks(original_table_identifier);
1281
This leads to the storage engine (SE) not being notified for renames in
1282
rename_table(), because we just juggle with the FRM and nothing
1283
more. If we have an intermediate table, then we notify the SE that
1284
it should become the actual table. Later, we will recycle the old table.
1285
However, in case of ALTER Table RENAME there might be no intermediate
1286
table. This is when the old and new tables are compatible, according to
1287
compare_table(). Then, we need one additional call to
1289
TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1290
old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1291
message::Table::TEMPORARY);
1293
if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1296
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1300
if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1309
error= ER_ERROR_ON_RENAME;
1302
/* Try to get everything back. */
1305
plugin::StorageEngine::dropTable(*session, new_table_identifier);
1310
1307
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1309
rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1314
if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1316
/* Try to get everything back. */
1317
rename_error= ER_ERROR_ON_RENAME;
1319
plugin::StorageEngine::dropTable(*session, new_table_identifier);
1321
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1323
rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1327
plugin::StorageEngine::dropTable(*session, original_table_to_drop);
1334
An error happened while we were holding exclusive name-lock on table
1335
being altered. To be safe under LOCK TABLES we should remove placeholders
1336
from list of open tables list and table cache.
1338
session->unlink_open_table(table);
1313
plugin::StorageEngine::dropTable(*session, original_table_to_drop);
1320
An error happened while we were holding exclusive name-lock on table
1321
being altered. To be safe under LOCK TABLES we should remove placeholders
1322
from list of open tables list and table cache.
1324
session->unlink_open_table(table);
1325
table::Cache::singleton().mutex().unlock();
1330
table::Cache::singleton().mutex().unlock();
1344
1332
session->set_proc_info("end");
1506
1495
found_count=delete_count=0;
1512
if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1499
if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1501
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1502
snprintf(warn_buff, sizeof(warn_buff),
1503
_("order_st BY ignored because there is a user-defined clustered "
1504
"index in the table '%-.192s'"),
1505
from->getMutableShare()->getTableName());
1506
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1511
FileSort filesort(*session);
1512
from->sort.io_cache= new internal::IO_CACHE;
1514
memset(&tables, 0, sizeof(tables));
1516
tables.setTableName(const_cast<char *>(from->getMutableShare()->getTableName()));
1517
tables.alias= const_cast<char *>(tables.getTableName());
1518
tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1521
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1522
setup_order(session, session->lex->select_lex.ref_pointer_array,
1523
&tables, fields, all_fields, order) ||
1524
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1525
(from->sort.found_records= filesort.run(from, sortorder, length,
1526
(optimizer::SqlSelect *) 0, HA_POS_ERROR,
1527
1, examined_rows)) == HA_POS_ERROR)
1514
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1515
snprintf(warn_buff, sizeof(warn_buff),
1516
_("order_st BY ignored because there is a user-defined clustered "
1517
"index in the table '%-.192s'"),
1518
from->getMutableShare()->getTableName());
1519
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1534
/* Tell handler that we have values for all columns in the to table */
1535
to->use_all_columns();
1536
error= info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1539
to->print_error(errno, MYF(0));
1544
to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1546
session->row_count= 0;
1547
to->restoreRecordAsDefault(); // Create empty record
1548
while (!(error=info.read_record(&info)))
1550
if (session->getKilled())
1552
session->send_kill_message();
1556
session->row_count++;
1557
/* Return error if source table isn't empty. */
1558
if (error_if_not_empty)
1563
if (to->next_number_field)
1565
if (auto_increment_field_copied)
1566
to->auto_increment_field_not_null= true;
1568
to->next_number_field->reset();
1571
for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
1573
if (not copy->to_field->hasDefault() and copy->from_null_ptr and *copy->from_null_ptr & copy->from_bit)
1524
FileSort filesort(*session);
1525
from->sort.io_cache= new internal::IO_CACHE;
1528
tables.setTableName(from->getMutableShare()->getTableName());
1529
tables.alias= tables.getTableName();
1530
tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1575
copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1576
ER_WARN_DATA_TRUNCATED, 1);
1577
copy->to_field->reset();
1533
if (session->getLex()->select_lex.setup_ref_array(session, order_num) ||
1534
setup_order(session, session->getLex()->select_lex.ref_pointer_array,
1535
&tables, fields, all_fields, order) ||
1536
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1537
(from->sort.found_records= filesort.run(from, sortorder, length,
1538
(optimizer::SqlSelect *) 0, HA_POS_ERROR,
1539
1, examined_rows)) == HA_POS_ERROR)
1582
copy_ptr->do_copy(copy_ptr);
1546
/* Tell handler that we have values for all columns in the to table */
1547
to->use_all_columns();
1549
error= info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1552
to->print_error(errno, MYF(0));
1559
to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1562
session->row_count= 0;
1563
to->restoreRecordAsDefault(); // Create empty record
1564
while (not (error=info.read_record(&info)))
1566
if (session->getKilled())
1568
session->send_kill_message();
1572
session->row_count++;
1573
/* Return error if source table isn't empty. */
1574
if (error_if_not_empty)
1579
if (to->next_number_field)
1581
if (auto_increment_field_copied)
1582
to->auto_increment_field_not_null= true;
1584
to->next_number_field->reset();
1587
for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
1589
if (not copy->to_field->hasDefault() and copy->from_null_ptr and *copy->from_null_ptr & copy->from_bit)
1591
copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1592
ER_WARN_DATA_TRUNCATED, 1);
1593
copy->to_field->reset();
1598
copy_ptr->do_copy(copy_ptr);
1606
prev_insert_id= to->cursor->next_insert_id;
1607
error= to->cursor->insertRecord(to->record[0]);
1608
to->auto_increment_field_not_null= false;
1590
prev_insert_id= to->cursor->next_insert_id;
1591
error= to->cursor->insertRecord(to->record[0]);
1592
to->auto_increment_field_not_null= false;
1596
if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1612
if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1614
to->print_error(error, MYF(0));
1617
to->cursor->restore_auto_increment(prev_insert_id);
1598
to->print_error(error, MYF(0));
1601
to->cursor->restore_auto_increment(prev_insert_id);
1626
info.end_read_record();
1627
from->free_io_cache();
1628
delete [] copy; // This is never 0
1630
if (to->cursor->ha_end_bulk_insert() && error <= 0)
1632
to->print_error(errno, MYF(0));
1635
to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1638
Ensure that the new table is saved properly to disk so that we
1641
if (transaction_services.autocommitOrRollback(*session, false))
1644
if (not session->endActiveTransaction())
1649
session->setAbortOnWarning(false);
1610
info.end_read_record();
1611
from->free_io_cache();
1612
delete [] copy; // This is never 0
1614
if (to->cursor->ha_end_bulk_insert() && error <= 0)
1616
to->print_error(errno, MYF(0));
1619
to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1622
Ensure that the new table is saved properly to disk so that we
1625
if (transaction_services.autocommitOrRollback(session, false))
1627
if (! session->endActiveTransaction())
1631
session->abort_on_warning= 0;
1650
1632
from->free_io_cache();
1651
1633
*copied= found_count;
1652
1634
*deleted=delete_count;
1653
1635
to->cursor->ha_release_auto_increment();
1655
if (to->cursor->ha_external_lock(session, F_UNLCK))
1636
if (to->cursor->ha_external_lock(session,F_UNLCK))
1660
1639
return(error > 0 ? -1 : 0);
1663
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
1643
create_temporary_table(Session *session,
1644
TableIdentifier &identifier,
1645
HA_CREATE_INFO *create_info,
1646
message::Table &create_proto,
1647
AlterInfo *alter_info)
1652
Create a table with a temporary name.
1653
We don't log the statement, it will be logged later.
1655
create_proto.set_name(identifier.getTableName());
1657
create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1659
error= create_table(session,
1661
create_info, create_proto, alter_info, true, 0, false);
1666
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
1665
1668
Table *new_table;