1
/*****************************************************************************
3
Copyright (C) 2005, 2010, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
20
@file handler/handler0alter.cc
1
/******************************************************
4
(c) 2005-2008 Innobase Oy
22
5
*******************************************************/
7
#include <drizzled/server_includes.h>
25
8
#include <drizzled/error.h>
26
#include <drizzled/charset_info.h>
9
#include <mystrings/m_ctype.h>
27
10
#include <drizzled/field.h>
28
11
#include <drizzled/table.h>
29
12
#include <drizzled/field/varstring.h>
30
#include <drizzled/internal/my_sys.h>
32
15
#include "log0log.h"
33
16
#include "row0merge.h"
34
17
#include "srv0srv.h"
36
19
#include "trx0roll.h"
37
20
#include "ha_prototypes.h"
38
21
#include "handler0alter.h"
40
24
#include "ha_innodb.h"
41
25
#include "handler0vars.h"
43
/*************************************************************//**
27
/*****************************************************************
44
28
Copies an InnoDB column to a MySQL field. This function is
45
29
adapted from row_sel_field_store_in_mysql_format(). */
48
32
innobase_col_to_mysql(
49
33
/*==================*/
50
const dict_col_t* col, /*!< in: InnoDB column */
51
const unsigned char* data, /*!< in: InnoDB column data */
52
ulint len, /*!< in: length of data, in bytes */
53
Field* field) /*!< in/out: MySQL field */
34
const dict_col_t* col, /* in: InnoDB column */
35
const unsigned char* data, /* in: InnoDB column data */
36
ulint len, /* in: length of data, in bytes */
37
Field* field) /* in/out: MySQL field */
55
39
unsigned char* ptr;
56
40
unsigned char* dest = field->ptr;
103
87
ut_ad(flen >= len);
104
ut_ad(DATA_MBMAXLEN(col->mbminmaxlen)
105
>= DATA_MBMINLEN(col->mbminmaxlen));
106
ut_ad(DATA_MBMAXLEN(col->mbminmaxlen)
107
> DATA_MBMINLEN(col->mbminmaxlen) || flen == len);
88
ut_ad(col->mbmaxlen >= col->mbminlen);
89
ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
108
90
memcpy(dest, data, len);
131
/*************************************************************//**
132
Copies an InnoDB record to table->getInsertRecord(). */
113
/*****************************************************************
114
Copies an InnoDB record to table->record[0]. */
115
extern "C" UNIV_INTERN
135
117
innobase_rec_to_mysql(
136
118
/*==================*/
137
Table* table, /*!< in/out: MySQL table */
138
const rec_t* rec, /*!< in: record */
139
const dict_index_t* index, /*!< in: index */
140
const ulint* offsets) /*!< in: rec_get_offsets(
119
Table* table, /* in/out: MySQL table */
120
const rec_t* rec, /* in: record */
121
const dict_index_t* index, /* in: index */
122
const ulint* offsets) /* in: rec_get_offsets(
141
123
rec, index, ...) */
143
uint n_fields = table->getShare()->sizeFields();
125
uint n_fields = table->s->fields;
146
128
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
148
130
for (i = 0; i < n_fields; i++) {
149
Field* field = table->getField(i);
131
Field* field = table->field[i];
152
134
const unsigned char* ifield;
181
/*************************************************************//**
182
Resets table->getInsertRecord(). */
163
/*****************************************************************
164
Resets table->record[0]. */
165
extern "C" UNIV_INTERN
185
167
innobase_rec_reset(
186
168
/*===============*/
187
Table* table) /*!< in/out: MySQL table */
169
Table* table) /* in/out: MySQL table */
189
uint n_fields = table->getShare()->sizeFields();
171
uint n_fields = table->s->fields;
192
174
for (i = 0; i < n_fields; i++) {
193
table->getField(i)->set_default();
175
table->field[i]->set_default();
197
#if 0 // This is a part of the fast index code.
198
/******************************************************************//**
179
/**********************************************************************
199
180
Removes the filename encoding of a database and table name. */
202
183
innobase_convert_tablename(
203
184
/*=======================*/
204
char* s) /*!< in: identifier; out: decoded identifier */
185
char* s) /* in: identifier; out: decoded identifier */
207
189
char* slash = strchr(s, '/');
211
193
/* Temporarily replace the '/' with NUL. */
213
strncpy(s, s, slash - s + 1);
195
/* Convert the database name. */
196
strconvert(&my_charset_filename, s, system_charset_info,
197
s, slash - s + 1, &errors);
215
199
t = s + strlen(s);
216
200
ut_ad(slash >= t);
220
204
/* Convert the table name. */
221
strncpy(t, slash, slash - t + strlen(slash));
205
strconvert(&my_charset_filename, slash, system_charset_info,
206
t, slash - t + strlen(slash), &errors);
208
strconvert(&my_charset_filename, s,
209
system_charset_info, s, strlen(s), &errors);
226
/*******************************************************************//**
227
This function checks that index keys are sensible.
228
@return 0 or error number */
213
/***********************************************************************
214
This function checks that index keys are sensible. */
231
217
innobase_check_index_keys(
232
218
/*======================*/
233
const KeyInfo* key_info, /*!< in: Indexes to be created */
234
ulint num_of_keys, /*!< in: Number of indexes to
219
/* out: 0 or error number */
220
const KEY* key_info, /* in: Indexes to be created */
221
ulint num_of_keys) /* in: Number of indexes to
236
const dict_table_t* table) /*!< in: Existing indexes */
241
227
ut_ad(num_of_keys);
243
229
for (key_num = 0; key_num < num_of_keys; key_num++) {
244
const KeyInfo& key = key_info[key_num];
230
const KEY& key = key_info[key_num];
246
232
/* Check that the same index name does not appear
247
233
twice in indexes to be created. */
249
235
for (ulint i = 0; i < key_num; i++) {
250
const KeyInfo& key2 = key_info[i];
236
const KEY& key2 = key_info[i];
252
238
if (0 == strcmp(key.name, key2.name)) {
253
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
256
return(ER_WRONG_NAME_FOR_INDEX);
260
/* Check that the same index name does not already exist. */
262
for (const dict_index_t* index
263
= dict_table_get_first_index(table);
264
index; index = dict_table_get_next_index(index)) {
266
if (0 == strcmp(key.name, index->name)) {
267
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
239
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: key name `%s` appears"
240
" twice in CREATE INDEX\n",
270
243
return(ER_WRONG_NAME_FOR_INDEX);
274
247
/* Check that MySQL does not try to create a column
275
248
prefix index field on an inappropriate data type and
276
that the same column does not appear twice in the index. */
249
that the same colum does not appear twice in the index. */
278
251
for (ulint i = 0; i < key.key_parts; i++) {
279
const KeyPartInfo& key_part1
252
const KEY_PART_INFO& key_part1
280
253
= key.key_part[i];
281
254
const Field* field
282
255
= key_part1.field;
307
my_error(ER_WRONG_KEY_COLUMN, MYF(0),
280
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: MySQL is trying to"
281
" create a column prefix"
283
" inappropriate data type."
309
288
return(ER_WRONG_KEY_COLUMN);
312
291
for (ulint j = 0; j < i; j++) {
313
const KeyPartInfo& key_part2
292
const KEY_PART_INFO& key_part2
314
293
= key.key_part[j];
316
295
if (strcmp(key_part1.field->field_name,
321
my_error(ER_WRONG_KEY_COLUMN, MYF(0),
322
key_part1.field->field_name);
300
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: column `%s`"
301
" is not allowed to occur"
302
" twice in index `%s`.\n",
303
key_part1.field->field_name,
323
305
return(ER_WRONG_KEY_COLUMN);
331
/*******************************************************************//**
313
/***********************************************************************
332
314
Create index field definition for key part */
335
317
innobase_create_index_field_def(
336
318
/*============================*/
337
KeyPartInfo* key_part, /*!< in: MySQL key definition */
338
mem_heap_t* heap, /*!< in: memory heap */
339
merge_index_field_t* index_field) /*!< out: index field
319
KEY_PART_INFO* key_part, /* in: MySQL key definition */
320
mem_heap_t* heap, /* in: memory heap */
321
merge_index_field_t* index_field) /* out: index field
340
322
definition for key_part */
371
/*******************************************************************//**
353
/***********************************************************************
372
354
Create index definition for key */
375
357
innobase_create_index_def(
376
358
/*======================*/
377
KeyInfo* key, /*!< in: key definition */
378
bool new_primary, /*!< in: TRUE=generating
359
KEY* key, /* in: key definition */
360
bool new_primary, /* in: TRUE=generating
379
361
a new primary key
381
bool key_primary, /*!< in: TRUE if this key
363
bool key_primary, /* in: TRUE if this key
382
364
is a primary key */
383
merge_index_def_t* index, /*!< out: index definition */
384
mem_heap_t* heap) /*!< in: heap where memory
365
merge_index_def_t* index, /* out: index definition */
366
mem_heap_t* heap) /* in: heap where memory
423
/*******************************************************************//**
405
/***********************************************************************
424
406
Copy index field definition */
427
409
innobase_copy_index_field_def(
428
410
/*==========================*/
429
const dict_field_t* field, /*!< in: definition to copy */
430
merge_index_field_t* index_field) /*!< out: copied definition */
411
const dict_field_t* field, /* in: definition to copy */
412
merge_index_field_t* index_field) /* out: copied definition */
432
414
assert(field != NULL);
433
415
assert(index_field != NULL);
441
/*******************************************************************//**
423
/***********************************************************************
442
424
Copy index definition for the index */
445
427
innobase_copy_index_def(
446
428
/*====================*/
447
const dict_index_t* index, /*!< in: index definition to copy */
448
merge_index_def_t* new_index,/*!< out: Index definition */
449
mem_heap_t* heap) /*!< in: heap where allocated */
429
const dict_index_t* index, /* in: index definition to copy */
430
merge_index_def_t* new_index,/* out: Index definition */
431
mem_heap_t* heap) /* in: heap where allocated */
477
/*******************************************************************//**
459
/***********************************************************************
478
460
Create an index table where indexes are ordered as follows:
480
462
IF a new primary key is defined for the table THEN
493
@return key definitions or NULL */
496
476
merge_index_def_t*
497
477
innobase_create_key_def(
498
478
/*====================*/
499
trx_t* trx, /*!< in: trx */
500
const dict_table_t*table, /*!< in: table definition */
501
mem_heap_t* heap, /*!< in: heap where space for key
479
/* out: key definitions or NULL */
480
trx_t* trx, /* in: trx */
481
const dict_table_t*table, /* in: table definition */
482
mem_heap_t* heap, /* in: heap where space for key
502
483
definitions are allocated */
503
KeyInfo* key_info, /*!< in: Indexes to be created */
504
ulint& n_keys) /*!< in/out: Number of indexes to
484
KEY* key_info, /* in: Indexes to be created */
485
ulint& n_keys) /* in/out: Number of indexes to
520
501
key_info->name, "PRIMARY");
522
503
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
523
columns and if the index does not contain column prefix(es)
524
(only prefix/part of the column is indexed), MySQL will treat the
525
index as a PRIMARY KEY unless the table already has one. */
504
columns, MySQL will treat it as a PRIMARY KEY unless the
505
table already has one. */
527
507
if (!new_primary && (key_info->flags & HA_NOSAME)
528
&& (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG))
529
508
&& row_table_got_default_clust_index(table)) {
530
uint key_part = key_info->key_parts;
509
uint key_part = key_info->key_parts;
532
511
new_primary = TRUE;
534
513
while (key_part--) {
535
if (key_info->key_part[key_part].null_bit == 0) {
514
if (key_info->key_part[key_part].key_type
515
& FIELDFLAG_MAYBE_NULL) {
536
516
new_primary = FALSE;
581
561
return(indexdefs);
584
/*******************************************************************//**
585
Create a temporary tablename using query id, thread id, and id
586
@return temporary tablename */
564
/***********************************************************************
565
Create a temporary tablename using query id, thread id, and id */
589
568
innobase_create_temporary_tablename(
590
569
/*================================*/
591
mem_heap_t* heap, /*!< in: memory heap */
592
char id, /*!< in: identifier [0-9a-zA-Z] */
593
const char* table_name) /*!< in: table name */
570
/* out: temporary tablename */
571
mem_heap_t* heap, /* in: memory heap */
572
char id, /* in: identifier [0-9a-zA-Z] */
573
const char* table_name) /* in: table name */
610
/*******************************************************************//**
612
@return 0 or error number */
589
/***********************************************************************
615
593
ha_innobase::add_index(
616
594
/*===================*/
618
Table* i_table, /*!< in: Table where indexes are created */
619
KeyInfo* key_info, /*!< in: Indexes to be created */
620
uint num_of_keys) /*!< in: Number of indexes to be created */
595
/* out: 0 or error number */
596
Table* i_table, /* in: Table where indexes are created */
597
KEY* key_info, /* in: Indexes to be created */
598
uint num_of_keys) /* in: Number of indexes to be created */
622
dict_index_t** index; /*!< Index to be created */
623
dict_table_t* innodb_table; /*!< InnoDB table in dictionary */
624
dict_table_t* indexed_table; /*!< Table where indexes are created */
625
merge_index_def_t* index_defs; /*!< Index definitions */
626
mem_heap_t* heap; /*!< Heap for index definitions */
627
trx_t* trx; /*!< Transaction */
600
dict_index_t** index; /* Index to be created */
601
dict_table_t* innodb_table; /* InnoDB table in dictionary */
602
dict_table_t* indexed_table; /* Table where indexes are created */
603
merge_index_def_t* index_defs; /* Index definitions */
604
mem_heap_t* heap; /* Heap for index definitions */
605
trx_t* trx; /* Transaction */
628
606
ulint num_of_idx;
629
607
ulint num_created = 0;
630
608
ibool dict_locked = FALSE;
631
609
ulint new_primary;
639
617
return(HA_ERR_WRONG_COMMAND);
642
update_session(session);
644
622
heap = mem_heap_create(1024);
646
624
/* In case MySQL calls this in the middle of a SELECT query, release
647
625
possible adaptive hash latch to avoid deadlocks of threads. */
648
626
trx_search_latch_release_if_reserved(prebuilt->trx);
649
trx_start_if_not_started(prebuilt->trx);
651
628
/* Create a background transaction for the operations on
652
629
the data dictionary tables. */
653
trx = innobase_trx_allocate(user_session);
630
trx = trx_allocate_for_mysql();
654
631
trx_start_if_not_started(trx);
633
trx->mysql_thd = user_session;
634
trx->mysql_query_str = session_query(user_session);
656
636
innodb_table = indexed_table
657
637
= dict_table_get(prebuilt->table->name, FALSE);
659
if (UNIV_UNLIKELY(!innodb_table)) {
660
error = HA_ERR_NO_SUCH_TABLE;
639
/* Check that index keys are sensible */
664
/* Check if the index name is reserved. */
665
if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) {
668
/* Check that index keys are sensible */
669
error = innobase_check_index_keys(key_info, num_of_keys,
641
error = innobase_check_index_keys(key_info, num_of_keys);
673
643
if (UNIV_UNLIKELY(error)) {
675
645
mem_heap_free(heap);
676
trx_general_rollback_for_mysql(trx, NULL);
646
trx_general_rollback_for_mysql(trx, FALSE, NULL);
677
647
trx_free_for_mysql(trx);
678
648
trx_commit_for_mysql(prebuilt->trx);
714
684
row_mysql_lock_data_dictionary(trx);
715
685
dict_locked = TRUE;
717
ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
719
687
/* If a new primary key is defined for the table we need
720
688
to drop the original table and rebuild all indexes. */
775
741
ut_ad(error == DB_SUCCESS);
777
/* We will need to rebuild index translation table. Set
778
valid index entry count in the translation table to zero */
779
share->idx_trans_tbl.index_count = 0;
781
743
/* Commit the data dictionary transaction in order to release
782
the table locks on the system tables. This means that if
783
MySQL crashes while creating a new primary key inside
784
row_merge_build_indexes(), indexed_table will not be dropped
785
by trx_rollback_active(). It will have to be recovered or
786
dropped by the database administrator. */
744
the table locks on the system tables. Unfortunately, this
745
means that if MySQL crashes while creating a new primary key
746
inside row_merge_build_indexes(), indexed_table will not be
747
dropped on crash recovery. Thus, it will become orphaned. */
787
748
trx_commit_for_mysql(trx);
789
750
row_mysql_unlock_data_dictionary(trx);
813
774
index, num_of_idx, i_table);
778
/* TODO: At the moment we can't handle the following statement
779
in our debugging code below:
781
alter table t drop index b, add index (b);
783
The fix will have to parse the SQL and note that the index
784
being added has the same name as the the one being dropped and
785
ignore that in the dup index check.*/
786
//dict_table_check_for_dup_indexes(prebuilt->table);
817
789
/* After an error, remove all those index definitions from the
818
790
dictionary which were defined. */
887
856
prebuilt->trx->error_info = NULL;
888
857
/* fall through */
890
trx->error_state = DB_SUCCESS;
892
859
if (new_primary) {
893
if (indexed_table != innodb_table) {
894
row_merge_drop_table(trx, indexed_table);
860
row_merge_drop_table(trx, indexed_table);
897
862
if (!dict_locked) {
898
863
row_mysql_lock_data_dictionary(trx);
931
/*******************************************************************//**
932
Prepare to drop some indexes of a table.
933
@return 0 or error number */
895
/***********************************************************************
896
Prepare to drop some indexes of a table. */
936
899
ha_innobase::prepare_drop_index(
937
900
/*============================*/
939
Table* i_table, /*!< in: Table where indexes are dropped */
940
uint* key_num, /*!< in: Key nums to be dropped */
941
uint num_of_keys) /*!< in: Number of keys to be dropped */
901
/* out: 0 or error number */
902
Table* i_table, /* in: Table where indexes are dropped */
903
uint* key_num, /* in: Key nums to be dropped */
904
uint num_of_keys) /* in: Number of keys to be dropped */
959
922
/* Test and mark all the indexes to be dropped */
961
924
row_mysql_lock_data_dictionary(trx);
962
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
964
926
/* Check that none of the indexes have previously been flagged
994
956
/* Refuse to drop the clustered index. It would be
995
957
better to automatically generate a clustered index,
996
but drizzled::alter_table() will call this method only
958
but mysql_alter_table() will call this method only
997
959
after ha_innobase::add_index(). */
999
961
if (dict_index_is_clust(index)) {
1005
967
index->to_be_dropped = TRUE;
1008
/* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
970
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
1009
971
for a foreign key constraint because InnoDB requires that both
1010
tables contain indexes for the constraint. Such index can
1011
be dropped only if FOREIGN_KEY_CHECKS is set to 0.
1012
Note that CREATE INDEX id ON table does a CREATE INDEX and
1013
DROP INDEX, and we can ignore here foreign keys because a
1014
new index for the foreign key has already been created.
972
tables contain indexes for the constraint. Note that CREATE
973
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
974
can ignore here foreign keys because a new index for the
975
foreign key has already been created.
1016
977
We check for the foreign key constraints after marking the
1017
978
candidate indexes for deletion, because when we check for an
1126
1087
} while (index);
1129
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1130
1090
row_mysql_unlock_data_dictionary(trx);
1135
/*******************************************************************//**
1136
Drop the indexes that were passed to a successful prepare_drop_index().
1137
@return 0 or error number */
1095
/***********************************************************************
1096
Drop the indexes that were passed to a successful prepare_drop_index(). */
1140
1099
ha_innobase::final_drop_index(
1141
1100
/*==========================*/
1143
Table* ) /*!< in: Table where indexes are dropped */
1101
/* out: 0 or error number */
1102
Table* ) /* in: Table where indexes are dropped */
1145
dict_index_t* index; /*!< Index to be dropped */
1146
trx_t* trx; /*!< Transaction */
1104
dict_index_t* index; /* Index to be dropped */
1105
trx_t* trx; /* Transaction */
1149
1108
if (srv_created_new_raw || srv_force_recovery) {
1150
1109
return(HA_ERR_WRONG_COMMAND);
1153
update_session(session);
1155
1114
trx_search_latch_release_if_reserved(prebuilt->trx);
1156
trx_start_if_not_started(prebuilt->trx);
1158
1116
/* Create a background transaction for the operations on
1159
1117
the data dictionary tables. */
1160
trx = innobase_trx_allocate(user_session);
1118
trx = trx_allocate_for_mysql();
1161
1119
trx_start_if_not_started(trx);
1121
trx->mysql_thd = user_session;
1122
trx->mysql_query_str = session_query(user_session);
1163
1124
/* Flag this transaction as a dictionary operation, so that
1164
1125
the data dictionary will be locked in crash recovery. */
1165
1126
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1171
1132
prebuilt->table->flags, user_session);
1173
1134
row_mysql_lock_data_dictionary(trx);
1174
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1176
1136
if (UNIV_UNLIKELY(err)) {
1208
1168
ut_a(!index->to_be_dropped);
1211
/* We will need to rebuild index translation table. Set
1212
valid index entry count in the translation table to zero */
1213
share->idx_trans_tbl.index_count = 0;
1172
dict_table_check_for_dup_indexes(prebuilt->table);
1216
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1217
1176
trx_commit_for_mysql(trx);
1218
1177
trx_commit_for_mysql(prebuilt->trx);
1219
1178
row_mysql_unlock_data_dictionary(trx);