1
/*****************************************************************************
3
Copyright (c) 1996, 2009, 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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/******************************************************************//**
20
@file dict/dict0dict.c
21
Data dictionary system
23
Created 1/8/1996 Heikki Tuuri
24
***********************************************************************/
26
#include "dict0dict.h"
29
#include "dict0dict.ic"
32
/** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
33
UNIV_INTERN dict_index_t* dict_ind_redundant;
34
/** dummy index for ROW_FORMAT=COMPACT supremum and infimum records */
35
UNIV_INTERN dict_index_t* dict_ind_compact;
37
#ifndef UNIV_HOTBACKUP
39
#include "data0type.h"
40
#include "mach0data.h"
41
#include "dict0boot.h"
43
#include "dict0crea.h"
49
#include "page0page.h"
50
#include "pars0pars.h"
54
#include "row0merge.h"
55
#include "m_ctype.h" /* my_isspace() */
56
#include "ha_prototypes.h" /* innobase_strcasecmp() */
60
/** the dictionary system */
61
UNIV_INTERN dict_sys_t* dict_sys = NULL;
63
/** @brief the data dictionary rw-latch protecting dict_sys
65
table create, drop, etc. reserve this in X-mode; implicit or
66
backround operations purge, rollback, foreign key checks reserve this
67
in S-mode; we cannot trust that MySQL protects implicit or background
68
operations a table drop since MySQL does not know of them; therefore
69
we need this; NOTE: a transaction which reserves this must keep book
70
on the mode in trx_struct::dict_operation_lock_mode */
71
UNIV_INTERN rw_lock_t dict_operation_lock;
73
#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
74
creating a table or index object */
75
#define DICT_POOL_PER_TABLE_HASH 512 /*!< buffer pool max size per table
76
hash table fixed size in bytes */
77
#define DICT_POOL_PER_VARYING 4 /*!< buffer pool max size per data
78
dictionary varying size in bytes */
80
/** Identifies generated InnoDB foreign key names */
81
static char dict_ibfk[] = "_ibfk_";
83
/*******************************************************************//**
84
Tries to find column names for the index and sets the col field of the
86
@return TRUE if the column names were found */
91
dict_table_t* table, /*!< in: table */
92
dict_index_t* index); /*!< in: index */
93
/*******************************************************************//**
94
Builds the internal dictionary cache representation for a clustered
95
index, containing also system fields not defined by the user.
96
@return own: the internal representation of the clustered index */
99
dict_index_build_internal_clust(
100
/*============================*/
101
const dict_table_t* table, /*!< in: table */
102
dict_index_t* index); /*!< in: user representation of
104
/*******************************************************************//**
105
Builds the internal dictionary cache representation for a non-clustered
106
index, containing also system fields not defined by the user.
107
@return own: the internal representation of the non-clustered index */
110
dict_index_build_internal_non_clust(
111
/*================================*/
112
const dict_table_t* table, /*!< in: table */
113
dict_index_t* index); /*!< in: user representation of
114
a non-clustered index */
115
/**********************************************************************//**
116
Removes a foreign constraint struct from the dictionary cache. */
119
dict_foreign_remove_from_cache(
120
/*===========================*/
121
dict_foreign_t* foreign); /*!< in, own: foreign constraint */
122
/**********************************************************************//**
123
Prints a column data. */
128
const dict_table_t* table, /*!< in: table */
129
const dict_col_t* col); /*!< in: column */
130
/**********************************************************************//**
131
Prints an index data. */
134
dict_index_print_low(
135
/*=================*/
136
dict_index_t* index); /*!< in: index */
137
/**********************************************************************//**
138
Prints a field data. */
141
dict_field_print_low(
142
/*=================*/
143
dict_field_t* field); /*!< in: field */
144
/*********************************************************************//**
145
Frees a foreign key struct. */
150
dict_foreign_t* foreign); /*!< in, own: foreign key struct */
152
/* Stream for storing detailed information about the latest foreign key
153
and unique key errors */
154
UNIV_INTERN FILE* dict_foreign_err_file = NULL;
155
/* mutex protecting the foreign and unique error buffers */
156
UNIV_INTERN mutex_t dict_foreign_err_mutex;
158
/******************************************************************//**
159
Makes all characters in a NUL-terminated UTF-8 string lower case. */
164
char* a) /*!< in/out: string to put in lower case */
166
innobase_casedn_str(a);
169
/********************************************************************//**
170
Checks if the database name in two table names is the same.
171
@return TRUE if same db name */
174
dict_tables_have_same_db(
175
/*=====================*/
176
const char* name1, /*!< in: table name in the form
177
dbname '/' tablename */
178
const char* name2) /*!< in: table name in the form
179
dbname '/' tablename */
181
for (; *name1 == *name2; name1++, name2++) {
185
ut_a(*name1); /* the names must contain '/' */
190
/********************************************************************//**
191
Return the end of table name where we have removed dbname and '/'.
192
@return table name */
197
const char* name) /*!< in: table name in the form
198
dbname '/' tablename */
200
const char* s = strchr(name, '/');
206
/********************************************************************//**
207
Get the database name length in a table name.
208
@return database name length */
211
dict_get_db_name_len(
212
/*=================*/
213
const char* name) /*!< in: table name in the form
214
dbname '/' tablename */
217
s = strchr(name, '/');
222
/********************************************************************//**
223
Reserves the dictionary system mutex for MySQL. */
226
dict_mutex_enter_for_mysql(void)
227
/*============================*/
229
mutex_enter(&(dict_sys->mutex));
232
/********************************************************************//**
233
Releases the dictionary system mutex for MySQL. */
236
dict_mutex_exit_for_mysql(void)
237
/*===========================*/
239
mutex_exit(&(dict_sys->mutex));
242
/********************************************************************//**
243
Decrements the count of open MySQL handles to a table. */
246
dict_table_decrement_handle_count(
247
/*==============================*/
248
dict_table_t* table, /*!< in/out: table */
249
ibool dict_locked) /*!< in: TRUE=data dictionary locked */
252
mutex_enter(&dict_sys->mutex);
255
ut_ad(mutex_own(&dict_sys->mutex));
256
ut_a(table->n_mysql_handles_opened > 0);
258
table->n_mysql_handles_opened--;
261
mutex_exit(&dict_sys->mutex);
264
#endif /* !UNIV_HOTBACKUP */
266
/**********************************************************************//**
267
Returns a column's name.
268
@return column name. NOTE: not guaranteed to stay valid if table is
269
modified in any way (columns added, etc.). */
272
dict_table_get_col_name(
273
/*====================*/
274
const dict_table_t* table, /*!< in: table */
275
ulint col_nr) /*!< in: column number */
281
ut_ad(col_nr < table->n_def);
282
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
284
s = table->col_names;
286
for (i = 0; i < col_nr; i++) {
294
#ifndef UNIV_HOTBACKUP
295
/********************************************************************//**
296
Acquire the autoinc lock. */
299
dict_table_autoinc_lock(
300
/*====================*/
301
dict_table_t* table) /*!< in/out: table */
303
mutex_enter(&table->autoinc_mutex);
306
/********************************************************************//**
307
Unconditionally set the autoinc counter. */
310
dict_table_autoinc_initialize(
311
/*==========================*/
312
dict_table_t* table, /*!< in/out: table */
313
ib_uint64_t value) /*!< in: next value to assign to a row */
315
ut_ad(mutex_own(&table->autoinc_mutex));
317
table->autoinc = value;
320
/********************************************************************//**
321
Reads the next autoinc value (== autoinc counter value), 0 if not yet
323
@return value for a new row, or 0 */
326
dict_table_autoinc_read(
327
/*====================*/
328
const dict_table_t* table) /*!< in: table */
330
ut_ad(mutex_own(&table->autoinc_mutex));
332
return(table->autoinc);
335
/********************************************************************//**
336
Updates the autoinc counter if the value supplied is greater than the
340
dict_table_autoinc_update_if_greater(
341
/*=================================*/
343
dict_table_t* table, /*!< in/out: table */
344
ib_uint64_t value) /*!< in: value which was assigned to a row */
346
ut_ad(mutex_own(&table->autoinc_mutex));
348
if (value > table->autoinc) {
350
table->autoinc = value;
354
/********************************************************************//**
355
Release the autoinc lock. */
358
dict_table_autoinc_unlock(
359
/*======================*/
360
dict_table_t* table) /*!< in/out: table */
362
mutex_exit(&table->autoinc_mutex);
365
/**********************************************************************//**
366
Looks for an index with the given table and index id.
367
NOTE that we do not reserve the dictionary mutex.
368
@return index or NULL if not found from cache */
371
dict_index_get_on_id_low(
372
/*=====================*/
373
dict_table_t* table, /*!< in: table */
374
dulint id) /*!< in: index id */
378
index = dict_table_get_first_index(table);
381
if (0 == ut_dulint_cmp(id, index->id)) {
387
index = dict_table_get_next_index(index);
392
#endif /* !UNIV_HOTBACKUP */
394
/********************************************************************//**
395
Looks for column n in an index.
396
@return position in internal representation of the index;
397
ULINT_UNDEFINED if not contained */
400
dict_index_get_nth_col_pos(
401
/*=======================*/
402
const dict_index_t* index, /*!< in: index */
403
ulint n) /*!< in: column number */
405
const dict_field_t* field;
406
const dict_col_t* col;
411
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
413
col = dict_table_get_nth_col(index->table, n);
415
if (dict_index_is_clust(index)) {
417
return(dict_col_get_clust_pos(col, index));
420
n_fields = dict_index_get_n_fields(index);
422
for (pos = 0; pos < n_fields; pos++) {
423
field = dict_index_get_nth_field(index, pos);
425
if (col == field->col && field->prefix_len == 0) {
431
return(ULINT_UNDEFINED);
434
#ifndef UNIV_HOTBACKUP
435
/********************************************************************//**
436
Returns TRUE if the index contains a column or a prefix of that column.
437
@return TRUE if contains the column or its prefix */
440
dict_index_contains_col_or_prefix(
441
/*==============================*/
442
const dict_index_t* index, /*!< in: index */
443
ulint n) /*!< in: column number */
445
const dict_field_t* field;
446
const dict_col_t* col;
451
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
453
if (dict_index_is_clust(index)) {
458
col = dict_table_get_nth_col(index->table, n);
460
n_fields = dict_index_get_n_fields(index);
462
for (pos = 0; pos < n_fields; pos++) {
463
field = dict_index_get_nth_field(index, pos);
465
if (col == field->col) {
474
/********************************************************************//**
475
Looks for a matching field in an index. The column has to be the same. The
476
column in index must be complete, or must contain a prefix longer than the
477
column in index2. That is, we must be able to construct the prefix in index2
478
from the prefix in index.
479
@return position in internal representation of the index;
480
ULINT_UNDEFINED if not contained */
483
dict_index_get_nth_field_pos(
484
/*=========================*/
485
const dict_index_t* index, /*!< in: index from which to search */
486
const dict_index_t* index2, /*!< in: index */
487
ulint n) /*!< in: field number in index2 */
489
const dict_field_t* field;
490
const dict_field_t* field2;
495
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
497
field2 = dict_index_get_nth_field(index2, n);
499
n_fields = dict_index_get_n_fields(index);
501
for (pos = 0; pos < n_fields; pos++) {
502
field = dict_index_get_nth_field(index, pos);
504
if (field->col == field2->col
505
&& (field->prefix_len == 0
506
|| (field->prefix_len >= field2->prefix_len
507
&& field2->prefix_len != 0))) {
513
return(ULINT_UNDEFINED);
516
/**********************************************************************//**
517
Returns a table object based on table id.
518
@return table, NULL if does not exist */
521
dict_table_get_on_id(
522
/*=================*/
523
dulint table_id, /*!< in: table id */
524
trx_t* trx) /*!< in: transaction handle */
528
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
529
|| trx->dict_operation_lock_mode == RW_X_LATCH) {
530
/* It is a system table which will always exist in the table
531
cache: we avoid acquiring the dictionary mutex, because
532
if we are doing a rollback to handle an error in TABLE
533
CREATE, for example, we already have the mutex! */
535
ut_ad(mutex_own(&(dict_sys->mutex))
536
|| trx->dict_operation_lock_mode == RW_X_LATCH);
538
return(dict_table_get_on_id_low(table_id));
541
mutex_enter(&(dict_sys->mutex));
543
table = dict_table_get_on_id_low(table_id);
545
mutex_exit(&(dict_sys->mutex));
550
/********************************************************************//**
551
Looks for column n position in the clustered index.
552
@return position in internal representation of the clustered index */
555
dict_table_get_nth_col_pos(
556
/*=======================*/
557
const dict_table_t* table, /*!< in: table */
558
ulint n) /*!< in: column number */
560
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
564
/********************************************************************//**
565
Checks if a column is in the ordering columns of the clustered index of a
566
table. Column prefixes are treated like whole columns.
567
@return TRUE if the column, or its prefix, is in the clustered key */
570
dict_table_col_in_clustered_key(
571
/*============================*/
572
const dict_table_t* table, /*!< in: table */
573
ulint n) /*!< in: column number */
575
const dict_index_t* index;
576
const dict_field_t* field;
577
const dict_col_t* col;
583
col = dict_table_get_nth_col(table, n);
585
index = dict_table_get_first_index(table);
587
n_fields = dict_index_get_n_unique(index);
589
for (pos = 0; pos < n_fields; pos++) {
590
field = dict_index_get_nth_field(index, pos);
592
if (col == field->col) {
601
/**********************************************************************//**
602
Inits the data dictionary module. */
608
dict_sys = mem_alloc(sizeof(dict_sys_t));
610
mutex_create(&dict_sys->mutex, SYNC_DICT);
612
dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
613
/ (DICT_POOL_PER_TABLE_HASH
615
dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
616
/ (DICT_POOL_PER_TABLE_HASH
620
UT_LIST_INIT(dict_sys->table_LRU);
622
rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
624
dict_foreign_err_file = os_file_create_tmpfile();
625
ut_a(dict_foreign_err_file);
627
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
630
/**********************************************************************//**
631
Returns a table object and optionally increment its MySQL open handle count.
632
NOTE! This is a high-level function to be used mainly from outside the
633
'dict' directory. Inside this directory dict_table_get_low is usually the
634
appropriate function.
635
@return table, NULL if does not exist */
640
const char* table_name, /*!< in: table name */
641
ibool inc_mysql_count)/*!< in: whether to increment the open
642
handle count on the table */
646
mutex_enter(&(dict_sys->mutex));
648
table = dict_table_get_low(table_name);
650
if (inc_mysql_count && table) {
651
table->n_mysql_handles_opened++;
654
mutex_exit(&(dict_sys->mutex));
657
if (!table->stat_initialized) {
658
/* If table->ibd_file_missing == TRUE, this will
659
print an error message and return without doing
661
dict_update_statistics(table);
667
#endif /* !UNIV_HOTBACKUP */
669
/**********************************************************************//**
670
Adds system columns to a table object. */
673
dict_table_add_system_columns(
674
/*==========================*/
675
dict_table_t* table, /*!< in/out: table */
676
mem_heap_t* heap) /*!< in: temporary heap */
679
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
680
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
681
ut_ad(!table->cached);
683
/* NOTE: the system columns MUST be added in the following order
684
(so that they can be indexed by the numerical value of DATA_ROW_ID,
685
etc.) and as the last columns of the table memory object.
686
The clustered index will not always physically contain all
689
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
690
DATA_ROW_ID | DATA_NOT_NULL,
693
#error "DATA_ROW_ID != 0"
695
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
696
DATA_TRX_ID | DATA_NOT_NULL,
699
#error "DATA_TRX_ID != 1"
701
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
702
DATA_ROLL_PTR | DATA_NOT_NULL,
704
#if DATA_ROLL_PTR != 2
705
#error "DATA_ROLL_PTR != 2"
708
/* This check reminds that if a new system column is added to
709
the program, it should be dealt with here */
710
#if DATA_N_SYS_COLS != 3
711
#error "DATA_N_SYS_COLS != 3"
715
#ifndef UNIV_HOTBACKUP
716
/**********************************************************************//**
717
Adds a table object to the dictionary cache. */
720
dict_table_add_to_cache(
721
/*====================*/
722
dict_table_t* table, /*!< in: table */
723
mem_heap_t* heap) /*!< in: temporary heap */
730
/* The lower limit for what we consider a "big" row */
731
#define BIG_ROW_SIZE 1024
733
ut_ad(mutex_own(&(dict_sys->mutex)));
735
dict_table_add_system_columns(table, heap);
737
table->cached = TRUE;
739
fold = ut_fold_string(table->name);
740
id_fold = ut_fold_dulint(table->id);
743
for (i = 0; i < table->n_def; i++) {
744
ulint col_len = dict_col_get_max_size(
745
dict_table_get_nth_col(table, i));
749
/* If we have a single unbounded field, or several gigantic
750
fields, mark the maximum row size as BIG_ROW_SIZE. */
751
if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
752
row_len = BIG_ROW_SIZE;
758
table->big_rows = row_len >= BIG_ROW_SIZE;
760
/* Look for a table with the same name: error if such exists */
762
dict_table_t* table2;
763
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
764
dict_table_t*, table2, ut_ad(table2->cached),
765
ut_strcmp(table2->name, table->name) == 0);
766
ut_a(table2 == NULL);
769
/* Look for the same table pointer with a different name */
770
HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
771
dict_table_t*, table2, ut_ad(table2->cached),
773
ut_ad(table2 == NULL);
774
#endif /* UNIV_DEBUG */
777
/* Look for a table with the same id: error if such exists */
779
dict_table_t* table2;
780
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
781
dict_table_t*, table2, ut_ad(table2->cached),
782
ut_dulint_cmp(table2->id, table->id) == 0);
783
ut_a(table2 == NULL);
786
/* Look for the same table pointer with a different id */
787
HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
788
dict_table_t*, table2, ut_ad(table2->cached),
790
ut_ad(table2 == NULL);
791
#endif /* UNIV_DEBUG */
794
/* Add table to hash table of tables */
795
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
798
/* Add table to hash table of tables based on table id */
799
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
801
/* Add table to LRU list of tables */
802
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
804
dict_sys->size += mem_heap_get_size(table->heap);
807
/**********************************************************************//**
808
Looks for an index with the given id. NOTE that we do not reserve
809
the dictionary mutex: this function is for emergency purposes like
810
printing info of a corrupt database page!
811
@return index or NULL if not found from cache */
814
dict_index_find_on_id_low(
815
/*======================*/
816
dulint id) /*!< in: index id */
821
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
824
index = dict_table_get_first_index(table);
827
if (0 == ut_dulint_cmp(id, index->id)) {
833
index = dict_table_get_next_index(index);
836
table = UT_LIST_GET_NEXT(table_LRU, table);
842
/**********************************************************************//**
843
Renames a table object.
844
@return TRUE if success */
847
dict_table_rename_in_cache(
848
/*=======================*/
849
dict_table_t* table, /*!< in/out: table */
850
const char* new_name, /*!< in: new name */
851
ibool rename_also_foreigns)/*!< in: in ALTER TABLE we want
852
to preserve the original table name
853
in constraints which reference it */
855
dict_foreign_t* foreign;
859
const char* old_name;
862
ut_ad(mutex_own(&(dict_sys->mutex)));
864
old_size = mem_heap_get_size(table->heap);
865
old_name = table->name;
867
fold = ut_fold_string(new_name);
869
/* Look for a table with the same name: error if such exists */
871
dict_table_t* table2;
872
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
873
dict_table_t*, table2, ut_ad(table2->cached),
874
(ut_strcmp(table2->name, new_name) == 0));
875
if (UNIV_LIKELY_NULL(table2)) {
876
ut_print_timestamp(stderr);
877
fputs(" InnoDB: Error: dictionary cache"
878
" already contains a table ", stderr);
879
ut_print_name(stderr, NULL, TRUE, new_name);
881
"InnoDB: cannot rename table ", stderr);
882
ut_print_name(stderr, NULL, TRUE, old_name);
888
/* If the table is stored in a single-table tablespace, rename the
891
if (table->space != 0) {
892
if (table->dir_path_of_temp_table != NULL) {
893
ut_print_timestamp(stderr);
894
fputs(" InnoDB: Error: trying to rename a"
895
" TEMPORARY TABLE ", stderr);
896
ut_print_name(stderr, NULL, TRUE, old_name);
898
ut_print_filename(stderr,
899
table->dir_path_of_temp_table);
900
fputs(" )\n", stderr);
902
} else if (!fil_rename_tablespace(old_name, table->space,
908
/* Remove table from the hash tables of tables */
909
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
910
ut_fold_string(old_name), table);
911
table->name = mem_heap_strdup(table->heap, new_name);
913
/* Add table to hash table of tables */
914
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
916
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
918
/* Update the table_name field in indexes */
919
index = dict_table_get_first_index(table);
921
while (index != NULL) {
922
index->table_name = table->name;
924
index = dict_table_get_next_index(index);
927
if (!rename_also_foreigns) {
928
/* In ALTER TABLE we think of the rename table operation
929
in the direction table -> temporary table (#sql...)
930
as dropping the table with the old name and creating
931
a new with the new name. Thus we kind of drop the
932
constraints from the dictionary cache here. The foreign key
933
constraints will be inherited to the new table from the
934
system tables through a call of dict_load_foreigns. */
936
/* Remove the foreign constraints from the cache */
937
foreign = UT_LIST_GET_LAST(table->foreign_list);
939
while (foreign != NULL) {
940
dict_foreign_remove_from_cache(foreign);
941
foreign = UT_LIST_GET_LAST(table->foreign_list);
944
/* Reset table field in referencing constraints */
946
foreign = UT_LIST_GET_FIRST(table->referenced_list);
948
while (foreign != NULL) {
949
foreign->referenced_table = NULL;
950
foreign->referenced_index = NULL;
952
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
955
/* Make the list of referencing constraints empty */
957
UT_LIST_INIT(table->referenced_list);
962
/* Update the table name fields in foreign constraints, and update also
963
the constraint id of new format >= 4.0.18 constraints. Note that at
964
this point we have already changed table->name to the new name. */
966
foreign = UT_LIST_GET_FIRST(table->foreign_list);
968
while (foreign != NULL) {
969
if (ut_strlen(foreign->foreign_table_name)
970
< ut_strlen(table->name)) {
971
/* Allocate a longer name buffer;
972
TODO: store buf len to save memory */
974
foreign->foreign_table_name
975
= mem_heap_alloc(foreign->heap,
976
ut_strlen(table->name) + 1);
979
strcpy(foreign->foreign_table_name, table->name);
981
if (strchr(foreign->id, '/')) {
985
/* This is a >= 4.0.18 format id */
987
old_id = mem_strdup(foreign->id);
989
if (ut_strlen(foreign->id) > ut_strlen(old_name)
990
+ ((sizeof dict_ibfk) - 1)
991
&& !memcmp(foreign->id, old_name,
993
&& !memcmp(foreign->id + ut_strlen(old_name),
994
dict_ibfk, (sizeof dict_ibfk) - 1)) {
996
/* This is a generated >= 4.0.18 format id */
998
if (strlen(table->name) > strlen(old_name)) {
999
foreign->id = mem_heap_alloc(
1002
+ strlen(old_id) + 1);
1005
/* Replace the prefix 'databasename/tablename'
1006
with the new names */
1007
strcpy(foreign->id, table->name);
1009
old_id + ut_strlen(old_name));
1011
/* This is a >= 4.0.18 format id where the user
1013
db_len = dict_get_db_name_len(table->name) + 1;
1015
if (dict_get_db_name_len(table->name)
1016
> dict_get_db_name_len(foreign->id)) {
1018
foreign->id = mem_heap_alloc(
1020
db_len + strlen(old_id) + 1);
1023
/* Replace the database prefix in id with the
1024
one from table->name */
1026
ut_memcpy(foreign->id, table->name, db_len);
1028
strcpy(foreign->id + db_len,
1029
dict_remove_db_name(old_id));
1035
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1038
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1040
while (foreign != NULL) {
1041
if (ut_strlen(foreign->referenced_table_name)
1042
< ut_strlen(table->name)) {
1043
/* Allocate a longer name buffer;
1044
TODO: store buf len to save memory */
1046
foreign->referenced_table_name = mem_heap_alloc(
1047
foreign->heap, strlen(table->name) + 1);
1050
strcpy(foreign->referenced_table_name, table->name);
1052
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1058
/**********************************************************************//**
1059
Change the id of a table object in the dictionary cache. This is used in
1060
DISCARD TABLESPACE. */
1063
dict_table_change_id_in_cache(
1064
/*==========================*/
1065
dict_table_t* table, /*!< in/out: table object already in cache */
1066
dulint new_id) /*!< in: new id to set */
1069
ut_ad(mutex_own(&(dict_sys->mutex)));
1070
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1072
/* Remove the table from the hash table of id's */
1074
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1075
ut_fold_dulint(table->id), table);
1078
/* Add the table back to the hash table */
1079
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1080
ut_fold_dulint(table->id), table);
1083
/**********************************************************************//**
1084
Removes a table object from the dictionary cache. */
1087
dict_table_remove_from_cache(
1088
/*=========================*/
1089
dict_table_t* table) /*!< in, own: table */
1091
dict_foreign_t* foreign;
1092
dict_index_t* index;
1096
ut_ad(mutex_own(&(dict_sys->mutex)));
1097
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1100
fputs("Removing table ", stderr);
1101
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1102
fputs(" from dictionary cache\n", stderr);
1105
/* Remove the foreign constraints from the cache */
1106
foreign = UT_LIST_GET_LAST(table->foreign_list);
1108
while (foreign != NULL) {
1109
dict_foreign_remove_from_cache(foreign);
1110
foreign = UT_LIST_GET_LAST(table->foreign_list);
1113
/* Reset table field in referencing constraints */
1115
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1117
while (foreign != NULL) {
1118
foreign->referenced_table = NULL;
1119
foreign->referenced_index = NULL;
1121
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1124
/* Remove the indexes from the cache */
1125
index = UT_LIST_GET_LAST(table->indexes);
1127
while (index != NULL) {
1128
dict_index_remove_from_cache(table, index);
1129
index = UT_LIST_GET_LAST(table->indexes);
1132
/* Remove table from the hash tables of tables */
1133
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1134
ut_fold_string(table->name), table);
1135
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1136
ut_fold_dulint(table->id), table);
1138
/* Remove table from LRU list of tables */
1139
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1141
size = mem_heap_get_size(table->heap);
1143
ut_ad(dict_sys->size >= size);
1145
dict_sys->size -= size;
1147
dict_mem_table_free(table);
1150
/****************************************************************//**
1151
If the given column name is reserved for InnoDB system columns, return
1153
@return TRUE if name is reserved */
1156
dict_col_name_is_reserved(
1157
/*======================*/
1158
const char* name) /*!< in: column name */
1160
/* This check reminds that if a new system column is added to
1161
the program, it should be dealt with here. */
1162
#if DATA_N_SYS_COLS != 3
1163
#error "DATA_N_SYS_COLS != 3"
1166
static const char* reserved_names[] = {
1167
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1172
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1173
if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1182
/****************************************************************//**
1183
If an undo log record for this table might not fit on a single page,
1185
@return TRUE if the undo log record could become too big */
1188
dict_index_too_big_for_undo(
1189
/*========================*/
1190
const dict_table_t* table, /*!< in: table */
1191
const dict_index_t* new_index) /*!< in: index */
1193
/* Make sure that all column prefixes will fit in the undo log record
1194
in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1197
const dict_index_t* clust_index
1198
= dict_table_get_first_index(table);
1200
= TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
1201
+ 2 /* next record pointer */
1203
+ 11 /* trx->undo_no */ + 11 /* table->id */
1204
+ 1 /* rec_get_info_bits() */
1205
+ 11 /* DB_TRX_ID */
1206
+ 11 /* DB_ROLL_PTR */
1207
+ 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
1208
+ 2/* pointer to previous undo log record */;
1210
if (UNIV_UNLIKELY(!clust_index)) {
1211
ut_a(dict_index_is_clust(new_index));
1212
clust_index = new_index;
1215
/* Add the size of the ordering columns in the
1217
for (i = 0; i < clust_index->n_uniq; i++) {
1218
const dict_col_t* col
1219
= dict_index_get_nth_col(clust_index, i);
1221
/* Use the maximum output size of
1222
mach_write_compressed(), although the encoded
1223
length should always fit in 2 bytes. */
1224
undo_page_len += 5 + dict_col_get_max_size(col);
1227
/* Add the old values of the columns to be updated.
1228
First, the amount and the numbers of the columns.
1229
These are written by mach_write_compressed() whose
1230
maximum output length is 5 bytes. However, given that
1231
the quantities are below REC_MAX_N_FIELDS (10 bits),
1232
the maximum length is 2 bytes per item. */
1233
undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
1235
for (i = 0; i < clust_index->n_def; i++) {
1236
const dict_col_t* col
1237
= dict_index_get_nth_col(clust_index, i);
1239
= dict_col_get_max_size(col);
1241
= dict_col_get_fixed_size(col,
1242
dict_table_is_comp(table));
1245
/* Fixed-size columns are stored locally. */
1246
max_size = fixed_size;
1247
} else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
1248
/* Short columns are stored locally. */
1249
} else if (!col->ord_part) {
1250
/* See if col->ord_part would be set
1251
because of new_index. */
1254
for (j = 0; j < new_index->n_uniq; j++) {
1255
if (dict_index_get_nth_col(
1256
new_index, j) == col) {
1262
/* This is not an ordering column in any index.
1263
Thus, it can be stored completely externally. */
1264
max_size = BTR_EXTERN_FIELD_REF_SIZE;
1267
/* This is an ordering column in some index.
1268
A long enough prefix must be written to the
1269
undo log. See trx_undo_page_fetch_ext(). */
1271
if (max_size > REC_MAX_INDEX_COL_LEN) {
1272
max_size = REC_MAX_INDEX_COL_LEN;
1275
max_size += BTR_EXTERN_FIELD_REF_SIZE;
1278
undo_page_len += 5 + max_size;
1281
return(undo_page_len >= UNIV_PAGE_SIZE);
1284
/****************************************************************//**
1285
If a record of this index might not fit on a single B-tree page,
1287
@return TRUE if the index record could become too big */
1290
dict_index_too_big_for_tree(
1291
/*========================*/
1292
const dict_table_t* table, /*!< in: table */
1293
const dict_index_t* new_index) /*!< in: index */
1298
/* maximum possible storage size of a record */
1300
/* maximum allowed size of a record on a leaf page */
1302
/* maximum allowed size of a node pointer record */
1305
comp = dict_table_is_comp(table);
1306
zip_size = dict_table_zip_size(table);
1308
if (zip_size && zip_size < UNIV_PAGE_SIZE) {
1309
/* On a compressed page, two records must fit in the
1310
uncompressed page modification log. On compressed
1311
pages with zip_size == UNIV_PAGE_SIZE, this limit will
1312
never be reached. */
1314
/* The maximum allowed record size is the size of
1315
an empty page, minus a byte for recoding the heap
1316
number in the page modification log. The maximum
1317
allowed node pointer size is half that. */
1318
page_rec_max = page_zip_empty_size(new_index->n_fields,
1320
page_ptr_max = page_rec_max / 2;
1321
/* On a compressed page, there is a two-byte entry in
1322
the dense page directory for every record. But there
1323
is no record header. */
1326
/* The maximum allowed record size is half a B-tree
1327
page. No additional sparse page directory entry will
1328
be generated for the first few user records. */
1329
page_rec_max = page_get_free_space_of_empty(comp) / 2;
1330
page_ptr_max = page_rec_max;
1331
/* Each record has a header. */
1333
? REC_N_NEW_EXTRA_BYTES
1334
: REC_N_OLD_EXTRA_BYTES;
1338
/* Include the "null" flags in the
1339
maximum possible record size. */
1340
rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
1342
/* For each column, include a 2-byte offset and a
1343
"null" flag. The 1-byte format is only used in short
1344
records that do not contain externally stored columns.
1345
Such records could never exceed the page limit, even
1346
when using the 2-byte format. */
1347
rec_max_size += 2 * new_index->n_fields;
1350
/* Compute the maximum possible record size. */
1351
for (i = 0; i < new_index->n_fields; i++) {
1352
const dict_field_t* field
1353
= dict_index_get_nth_field(new_index, i);
1354
const dict_col_t* col
1355
= dict_field_get_col(field);
1356
ulint field_max_size;
1357
ulint field_ext_max_size;
1359
/* In dtuple_convert_big_rec(), variable-length columns
1360
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1361
may be chosen for external storage.
1363
Fixed-length columns, and all columns of secondary
1364
index records are always stored inline. */
1366
/* Determine the maximum length of the index field.
1367
The field_ext_max_size should be computed as the worst
1368
case in rec_get_converted_size_comp() for
1369
REC_STATUS_ORDINARY records. */
1371
field_max_size = dict_col_get_fixed_size(col, comp);
1372
if (field_max_size) {
1373
/* dict_index_add_col() should guarantee this */
1374
ut_ad(!field->prefix_len
1375
|| field->fixed_len == field->prefix_len);
1376
/* Fixed lengths are not encoded
1377
in ROW_FORMAT=COMPACT. */
1378
field_ext_max_size = 0;
1379
goto add_field_size;
1382
field_max_size = dict_col_get_max_size(col);
1383
field_ext_max_size = field_max_size < 256 ? 1 : 2;
1385
if (field->prefix_len) {
1386
if (field->prefix_len < field_max_size) {
1387
field_max_size = field->prefix_len;
1389
} else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
1390
&& dict_index_is_clust(new_index)) {
1392
/* In the worst case, we have a locally stored
1393
column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
1394
The length can be stored in one byte. If the
1395
column were stored externally, the lengths in
1396
the clustered index page would be
1397
BTR_EXTERN_FIELD_REF_SIZE and 2. */
1398
field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
1399
field_ext_max_size = 1;
1403
/* Add the extra size for ROW_FORMAT=COMPACT.
1404
For ROW_FORMAT=REDUNDANT, these bytes were
1405
added to rec_max_size before this loop. */
1406
rec_max_size += field_ext_max_size;
1409
rec_max_size += field_max_size;
1411
/* Check the size limit on leaf pages. */
1412
if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
1417
/* Check the size limit on non-leaf pages. Records
1418
stored in non-leaf B-tree pages consist of the unique
1419
columns of the record (the key columns of the B-tree)
1420
and a node pointer field. When we have processed the
1421
unique columns, rec_max_size equals the size of the
1422
node pointer record minus the node pointer column. */
1423
if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
1424
&& rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
1433
/**********************************************************************//**
1434
Adds an index to the dictionary cache.
1435
@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
1438
dict_index_add_to_cache(
1439
/*====================*/
1440
dict_table_t* table, /*!< in: table on which the index is */
1441
dict_index_t* index, /*!< in, own: index; NOTE! The index memory
1442
object is freed in this function! */
1443
ulint page_no,/*!< in: root page number of the index */
1444
ibool strict) /*!< in: TRUE=refuse to create the index
1445
if records could be too big to fit in
1448
dict_index_t* new_index;
1453
ut_ad(mutex_own(&(dict_sys->mutex)));
1454
ut_ad(index->n_def == index->n_fields);
1455
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1457
ut_ad(mem_heap_validate(index->heap));
1458
ut_a(!dict_index_is_clust(index)
1459
|| UT_LIST_GET_LEN(table->indexes) == 0);
1461
if (!dict_index_find_cols(table, index)) {
1463
return(DB_CORRUPTION);
1466
/* Build the cache internal representation of the index,
1467
containing also the added system fields */
1469
if (dict_index_is_clust(index)) {
1470
new_index = dict_index_build_internal_clust(table, index);
1472
new_index = dict_index_build_internal_non_clust(table, index);
1475
/* Set the n_fields value in new_index to the actual defined
1476
number of fields in the cache internal representation */
1478
new_index->n_fields = new_index->n_def;
1480
if (strict && dict_index_too_big_for_tree(table, new_index)) {
1482
dict_mem_index_free(new_index);
1483
dict_mem_index_free(index);
1484
return(DB_TOO_BIG_RECORD);
1487
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1488
n_ord = new_index->n_fields;
1490
n_ord = new_index->n_uniq;
1493
switch (dict_table_get_format(table)) {
1494
case DICT_TF_FORMAT_51:
1495
/* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
1496
prefixes of externally stored columns locally within
1497
the record. There are no special considerations for
1498
the undo log record size. */
1501
case DICT_TF_FORMAT_ZIP:
1502
/* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
1503
column prefix indexes require that prefixes of
1504
externally stored columns are written to the undo log.
1505
This may make the undo log record bigger than the
1506
record on the B-tree page. The maximum size of an
1507
undo log record is the page size. That must be
1508
checked for below. */
1511
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
1512
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
1516
for (i = 0; i < n_ord; i++) {
1517
const dict_field_t* field
1518
= dict_index_get_nth_field(new_index, i);
1519
const dict_col_t* col
1520
= dict_field_get_col(field);
1522
/* In dtuple_convert_big_rec(), variable-length columns
1523
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1524
may be chosen for external storage. If the column appears
1525
in an ordering column of an index, a longer prefix of
1526
REC_MAX_INDEX_COL_LEN will be copied to the undo log
1527
by trx_undo_page_report_modify() and
1528
trx_undo_page_fetch_ext(). It suffices to check the
1529
capacity of the undo log whenever new_index includes
1530
a column prefix on a column that may be stored externally. */
1532
if (field->prefix_len /* prefix index */
1533
&& !col->ord_part /* not yet ordering column */
1534
&& !dict_col_get_fixed_size(col, TRUE) /* variable-length */
1535
&& dict_col_get_max_size(col)
1536
> BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
1538
if (dict_index_too_big_for_undo(table, new_index)) {
1539
/* An undo log record might not fit in
1540
a single page. Refuse to create this index. */
1550
/* Flag the ordering columns */
1552
for (i = 0; i < n_ord; i++) {
1554
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1557
/* Add the new index as the last index for the table */
1559
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1560
new_index->table = table;
1561
new_index->table_name = table->name;
1563
new_index->search_info = btr_search_info_create(new_index->heap);
1565
new_index->stat_index_size = 1;
1566
new_index->stat_n_leaf_pages = 1;
1568
new_index->page = page_no;
1569
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1571
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1573
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1575
(1 + dict_index_get_n_unique(new_index))
1576
* sizeof(ib_int64_t));
1577
/* Give some sensible values to stat_n_... in case we do
1578
not calculate statistics quickly enough */
1580
for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1582
new_index->stat_n_diff_key_vals[i] = 100;
1586
dict_sys->size += mem_heap_get_size(new_index->heap);
1588
dict_mem_index_free(index);
1593
/**********************************************************************//**
1594
Removes an index from the dictionary cache. */
1597
dict_index_remove_from_cache(
1598
/*=========================*/
1599
dict_table_t* table, /*!< in/out: table */
1600
dict_index_t* index) /*!< in, own: index */
1606
ut_ad(table && index);
1607
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1608
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1609
ut_ad(mutex_own(&(dict_sys->mutex)));
1611
/* We always create search info whether or not adaptive
1612
hash index is enabled or not. */
1613
info = index->search_info;
1616
/* We are not allowed to free the in-memory index struct
1617
dict_index_t until all entries in the adaptive hash index
1618
that point to any of the page belonging to his b-tree index
1619
are dropped. This is so because dropping of these entries
1620
require access to dict_index_t struct. To avoid such scenario
1621
We keep a count of number of such pages in the search_info and
1622
only free the dict_index_t struct when this count drops to
1626
ulint ref_count = btr_search_info_get_ref_count(info);
1627
if (ref_count == 0) {
1631
/* Sleep for 10ms before trying again. */
1632
os_thread_sleep(10000);
1635
if (retries % 500 == 0) {
1636
/* No luck after 5 seconds of wait. */
1637
fprintf(stderr, "InnoDB: Error: Waited for"
1638
" %lu secs for hash index"
1639
" ref_count (%lu) to drop"
1649
/* To avoid a hang here we commit suicide if the
1650
ref_count doesn't drop to zero in 600 seconds. */
1651
if (retries >= 60000) {
1656
rw_lock_free(&index->lock);
1658
/* Remove the index from the list of indexes of the table */
1659
UT_LIST_REMOVE(indexes, table->indexes, index);
1661
size = mem_heap_get_size(index->heap);
1663
ut_ad(dict_sys->size >= size);
1665
dict_sys->size -= size;
1667
dict_mem_index_free(index);
1670
/*******************************************************************//**
1671
Tries to find column names for the index and sets the col field of the
1673
@return TRUE if the column names were found */
1676
dict_index_find_cols(
1677
/*=================*/
1678
dict_table_t* table, /*!< in: table */
1679
dict_index_t* index) /*!< in: index */
1683
ut_ad(table && index);
1684
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1685
ut_ad(mutex_own(&(dict_sys->mutex)));
1687
for (i = 0; i < index->n_fields; i++) {
1689
dict_field_t* field = dict_index_get_nth_field(index, i);
1691
for (j = 0; j < table->n_cols; j++) {
1692
if (!strcmp(dict_table_get_col_name(table, j),
1694
field->col = dict_table_get_nth_col(table, j);
1701
/* It is an error not to find a matching column. */
1702
fputs("InnoDB: Error: no matching column for ", stderr);
1703
ut_print_name(stderr, NULL, FALSE, field->name);
1704
fputs(" in ", stderr);
1705
dict_index_name_print(stderr, NULL, index);
1706
fputs("!\n", stderr);
1707
#endif /* UNIV_DEBUG */
1716
#endif /* !UNIV_HOTBACKUP */
1718
/*******************************************************************//**
1719
Adds a column to index. */
1724
dict_index_t* index, /*!< in/out: index */
1725
const dict_table_t* table, /*!< in: table */
1726
dict_col_t* col, /*!< in: column */
1727
ulint prefix_len) /*!< in: column prefix length */
1729
dict_field_t* field;
1730
const char* col_name;
1732
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1734
dict_mem_index_add_field(index, col_name, prefix_len);
1736
field = dict_index_get_nth_field(index, index->n_def - 1);
1739
field->fixed_len = (unsigned int) dict_col_get_fixed_size(
1740
col, dict_table_is_comp(table));
1742
if (prefix_len && field->fixed_len > prefix_len) {
1743
field->fixed_len = (unsigned int) prefix_len;
1746
/* Long fixed-length fields that need external storage are treated as
1747
variable-length fields, so that the extern flag can be embedded in
1750
if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1751
field->fixed_len = 0;
1753
#if DICT_MAX_INDEX_COL_LEN != 768
1754
/* The comparison limit above must be constant. If it were
1755
changed, the disk format of some fixed-length columns would
1756
change, which would be a disaster. */
1757
# error "DICT_MAX_INDEX_COL_LEN != 768"
1760
if (!(col->prtype & DATA_NOT_NULL)) {
1761
index->n_nullable++;
1765
#ifndef UNIV_HOTBACKUP
1766
/*******************************************************************//**
1767
Copies fields contained in index2 to index1. */
1772
dict_index_t* index1, /*!< in: index to copy to */
1773
dict_index_t* index2, /*!< in: index to copy from */
1774
const dict_table_t* table, /*!< in: table */
1775
ulint start, /*!< in: first position to copy */
1776
ulint end) /*!< in: last position to copy */
1778
dict_field_t* field;
1781
/* Copy fields contained in index2 */
1783
for (i = start; i < end; i++) {
1785
field = dict_index_get_nth_field(index2, i);
1786
dict_index_add_col(index1, table, field->col,
1791
/*******************************************************************//**
1792
Copies types of fields contained in index to tuple. */
1795
dict_index_copy_types(
1796
/*==================*/
1797
dtuple_t* tuple, /*!< in/out: data tuple */
1798
const dict_index_t* index, /*!< in: index */
1799
ulint n_fields) /*!< in: number of
1800
field types to copy */
1804
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1805
dtuple_set_types_binary(tuple, n_fields);
1810
for (i = 0; i < n_fields; i++) {
1811
const dict_field_t* ifield;
1812
dtype_t* dfield_type;
1814
ifield = dict_index_get_nth_field(index, i);
1815
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1816
dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1820
/*******************************************************************//**
1821
Copies types of columns contained in table to tuple and sets all
1822
fields of the tuple to the SQL NULL value. This function should
1823
be called right after dtuple_create(). */
1826
dict_table_copy_types(
1827
/*==================*/
1828
dtuple_t* tuple, /*!< in/out: data tuple */
1829
const dict_table_t* table) /*!< in: table */
1833
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1835
dfield_t* dfield = dtuple_get_nth_field(tuple, i);
1836
dtype_t* dtype = dfield_get_type(dfield);
1838
dfield_set_null(dfield);
1839
dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
1843
/*******************************************************************//**
1844
Builds the internal dictionary cache representation for a clustered
1845
index, containing also system fields not defined by the user.
1846
@return own: the internal representation of the clustered index */
1849
dict_index_build_internal_clust(
1850
/*============================*/
1851
const dict_table_t* table, /*!< in: table */
1852
dict_index_t* index) /*!< in: user representation of
1853
a clustered index */
1855
dict_index_t* new_index;
1856
dict_field_t* field;
1862
ut_ad(table && index);
1863
ut_ad(dict_index_is_clust(index));
1864
ut_ad(mutex_own(&(dict_sys->mutex)));
1865
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1867
/* Create a new index object with certainly enough fields */
1868
new_index = dict_mem_index_create(table->name,
1869
index->name, table->space,
1871
index->n_fields + table->n_cols);
1873
/* Copy other relevant data from the old index struct to the new
1874
struct: it inherits the values */
1876
new_index->n_user_defined_cols = index->n_fields;
1878
new_index->id = index->id;
1880
/* Copy the fields of index */
1881
dict_index_copy(new_index, index, table, 0, index->n_fields);
1883
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1884
/* No fixed number of fields determines an entry uniquely */
1886
new_index->n_uniq = REC_MAX_N_FIELDS;
1888
} else if (dict_index_is_unique(index)) {
1889
/* Only the fields defined so far are needed to identify
1890
the index entry uniquely */
1892
new_index->n_uniq = new_index->n_def;
1894
/* Also the row id is needed to identify the entry */
1895
new_index->n_uniq = 1 + new_index->n_def;
1898
new_index->trx_id_offset = 0;
1900
if (!dict_index_is_ibuf(index)) {
1901
/* Add system columns, trx id first */
1903
trx_id_pos = new_index->n_def;
1905
#if DATA_ROW_ID != 0
1906
# error "DATA_ROW_ID != 0"
1908
#if DATA_TRX_ID != 1
1909
# error "DATA_TRX_ID != 1"
1911
#if DATA_ROLL_PTR != 2
1912
# error "DATA_ROLL_PTR != 2"
1915
if (!dict_index_is_unique(index)) {
1916
dict_index_add_col(new_index, table,
1917
dict_table_get_sys_col(
1918
table, DATA_ROW_ID),
1923
dict_index_add_col(new_index, table,
1924
dict_table_get_sys_col(table, DATA_TRX_ID),
1927
dict_index_add_col(new_index, table,
1928
dict_table_get_sys_col(table,
1932
for (i = 0; i < trx_id_pos; i++) {
1934
fixed_size = dict_col_get_fixed_size(
1935
dict_index_get_nth_col(new_index, i),
1936
dict_table_is_comp(table));
1938
if (fixed_size == 0) {
1939
new_index->trx_id_offset = 0;
1944
if (dict_index_get_nth_field(new_index, i)->prefix_len
1946
new_index->trx_id_offset = 0;
1951
new_index->trx_id_offset += (unsigned int) fixed_size;
1956
/* Remember the table columns already contained in new_index */
1957
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
1959
/* Mark the table columns already contained in new_index */
1960
for (i = 0; i < new_index->n_def; i++) {
1962
field = dict_index_get_nth_field(new_index, i);
1964
/* If there is only a prefix of the column in the index
1965
field, do not mark the column as contained in the index */
1967
if (field->prefix_len == 0) {
1969
indexed[field->col->ind] = TRUE;
1973
/* Add to new_index non-system columns of table not yet included
1975
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1977
dict_col_t* col = dict_table_get_nth_col(table, i);
1978
ut_ad(col->mtype != DATA_SYS);
1980
if (!indexed[col->ind]) {
1981
dict_index_add_col(new_index, table, col, 0);
1987
ut_ad(dict_index_is_ibuf(index)
1988
|| (UT_LIST_GET_LEN(table->indexes) == 0));
1990
new_index->cached = TRUE;
1995
/*******************************************************************//**
1996
Builds the internal dictionary cache representation for a non-clustered
1997
index, containing also system fields not defined by the user.
1998
@return own: the internal representation of the non-clustered index */
2001
dict_index_build_internal_non_clust(
2002
/*================================*/
2003
const dict_table_t* table, /*!< in: table */
2004
dict_index_t* index) /*!< in: user representation of
2005
a non-clustered index */
2007
dict_field_t* field;
2008
dict_index_t* new_index;
2009
dict_index_t* clust_index;
2013
ut_ad(table && index);
2014
ut_ad(!dict_index_is_clust(index));
2015
ut_ad(mutex_own(&(dict_sys->mutex)));
2016
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2018
/* The clustered index should be the first in the list of indexes */
2019
clust_index = UT_LIST_GET_FIRST(table->indexes);
2022
ut_ad(dict_index_is_clust(clust_index));
2023
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
2025
/* Create a new index */
2026
new_index = dict_mem_index_create(
2027
table->name, index->name, index->space, index->type,
2028
index->n_fields + 1 + clust_index->n_uniq);
2030
/* Copy other relevant data from the old index
2031
struct to the new struct: it inherits the values */
2033
new_index->n_user_defined_cols = index->n_fields;
2035
new_index->id = index->id;
2037
/* Copy fields from index to new_index */
2038
dict_index_copy(new_index, index, table, 0, index->n_fields);
2040
/* Remember the table columns already contained in new_index */
2041
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2043
/* Mark the table columns already contained in new_index */
2044
for (i = 0; i < new_index->n_def; i++) {
2046
field = dict_index_get_nth_field(new_index, i);
2048
/* If there is only a prefix of the column in the index
2049
field, do not mark the column as contained in the index */
2051
if (field->prefix_len == 0) {
2053
indexed[field->col->ind] = TRUE;
2057
/* Add to new_index the columns necessary to determine the clustered
2058
index entry uniquely */
2060
for (i = 0; i < clust_index->n_uniq; i++) {
2062
field = dict_index_get_nth_field(clust_index, i);
2064
if (!indexed[field->col->ind]) {
2065
dict_index_add_col(new_index, table, field->col,
2072
if (dict_index_is_unique(index)) {
2073
new_index->n_uniq = index->n_fields;
2075
new_index->n_uniq = new_index->n_def;
2078
/* Set the n_fields value in new_index to the actual defined
2081
new_index->n_fields = new_index->n_def;
2083
new_index->cached = TRUE;
2088
/*====================== FOREIGN KEY PROCESSING ========================*/
2090
/*********************************************************************//**
2091
Checks if a table is referenced by foreign keys.
2092
@return TRUE if table is referenced by a foreign key */
2095
dict_table_is_referenced_by_foreign_key(
2096
/*====================================*/
2097
const dict_table_t* table) /*!< in: InnoDB table */
2099
return(UT_LIST_GET_LEN(table->referenced_list) > 0);
2102
/*********************************************************************//**
2103
Check if the index is referenced by a foreign key, if TRUE return foreign
2105
@return pointer to foreign key struct if index is defined for foreign
2106
key, otherwise NULL */
2109
dict_table_get_referenced_constraint(
2110
/*=================================*/
2111
dict_table_t* table, /*!< in: InnoDB table */
2112
dict_index_t* index) /*!< in: InnoDB index */
2114
dict_foreign_t* foreign;
2116
ut_ad(index != NULL);
2117
ut_ad(table != NULL);
2119
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
2121
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
2123
if (foreign->referenced_index == index) {
2132
/*********************************************************************//**
2133
Checks if a index is defined for a foreign key constraint. Index is a part
2134
of a foreign key constraint if the index is referenced by foreign key
2135
or index is a foreign key index.
2136
@return pointer to foreign key struct if index is defined for foreign
2137
key, otherwise NULL */
2140
dict_table_get_foreign_constraint(
2141
/*==============================*/
2142
dict_table_t* table, /*!< in: InnoDB table */
2143
dict_index_t* index) /*!< in: InnoDB index */
2145
dict_foreign_t* foreign;
2147
ut_ad(index != NULL);
2148
ut_ad(table != NULL);
2150
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
2152
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
2154
if (foreign->foreign_index == index
2155
|| foreign->referenced_index == index) {
2164
/*********************************************************************//**
2165
Frees a foreign key struct. */
2170
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
2172
mem_heap_free(foreign->heap);
2175
/**********************************************************************//**
2176
Removes a foreign constraint struct from the dictionary cache. */
2179
dict_foreign_remove_from_cache(
2180
/*===========================*/
2181
dict_foreign_t* foreign) /*!< in, own: foreign constraint */
2183
ut_ad(mutex_own(&(dict_sys->mutex)));
2186
if (foreign->referenced_table) {
2187
UT_LIST_REMOVE(referenced_list,
2188
foreign->referenced_table->referenced_list,
2192
if (foreign->foreign_table) {
2193
UT_LIST_REMOVE(foreign_list,
2194
foreign->foreign_table->foreign_list,
2198
dict_foreign_free(foreign);
2201
/**********************************************************************//**
2202
Looks for the foreign constraint from the foreign and referenced lists
2204
@return foreign constraint */
2209
dict_table_t* table, /*!< in: table object */
2210
const char* id) /*!< in: foreign constraint id */
2212
dict_foreign_t* foreign;
2214
ut_ad(mutex_own(&(dict_sys->mutex)));
2216
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2219
if (ut_strcmp(id, foreign->id) == 0) {
2224
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2227
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2230
if (ut_strcmp(id, foreign->id) == 0) {
2235
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2241
/*********************************************************************//**
2242
Tries to find an index whose first fields are the columns in the array,
2243
in the same order and is not marked for deletion and is not the same
2245
@return matching index, NULL if not found */
2248
dict_foreign_find_index(
2249
/*====================*/
2250
dict_table_t* table, /*!< in: table */
2251
const char** columns,/*!< in: array of column names */
2252
ulint n_cols, /*!< in: number of columns */
2253
dict_index_t* types_idx, /*!< in: NULL or an index to whose types the
2254
column types must match */
2255
ibool check_charsets,
2256
/*!< in: whether to check charsets.
2257
only has an effect if types_idx != NULL */
2259
/*!< in: nonzero if none of the columns must
2260
be declared NOT NULL */
2262
dict_index_t* index;
2264
index = dict_table_get_first_index(table);
2266
while (index != NULL) {
2267
/* Ignore matches that refer to the same instance
2268
or the index is to be dropped */
2269
if (index->to_be_dropped || types_idx == index) {
2273
} else if (dict_index_get_n_fields(index) >= n_cols) {
2276
for (i = 0; i < n_cols; i++) {
2277
dict_field_t* field;
2278
const char* col_name;
2280
field = dict_index_get_nth_field(index, i);
2282
col_name = dict_table_get_col_name(
2283
table, dict_col_get_no(field->col));
2285
if (field->prefix_len != 0) {
2286
/* We do not accept column prefix
2292
if (0 != innobase_strcasecmp(columns[i],
2298
&& (field->col->prtype & DATA_NOT_NULL)) {
2303
if (types_idx && !cmp_cols_are_equal(
2304
dict_index_get_nth_col(index, i),
2305
dict_index_get_nth_col(types_idx,
2314
/* We found a matching index */
2321
index = dict_table_get_next_index(index);
2327
/**********************************************************************//**
2328
Find an index that is equivalent to the one passed in and is not marked
2330
@return index equivalent to foreign->foreign_index, or NULL */
2333
dict_foreign_find_equiv_index(
2334
/*==========================*/
2335
dict_foreign_t* foreign)/*!< in: foreign key */
2337
ut_a(foreign != NULL);
2339
/* Try to find an index which contains the columns as the
2340
first fields and in the right order, and the types are the
2341
same as in foreign->foreign_index */
2343
return(dict_foreign_find_index(
2344
foreign->foreign_table,
2345
foreign->foreign_col_names, foreign->n_fields,
2346
foreign->foreign_index, TRUE, /* check types */
2347
FALSE/* allow columns to be NULL */));
2350
/**********************************************************************//**
2351
Returns an index object by matching on the name and column names and
2352
if more than one index matches return the index with the max id
2353
@return matching index, NULL if not found */
2356
dict_table_get_index_by_max_id(
2357
/*===========================*/
2358
dict_table_t* table, /*!< in: table */
2359
const char* name, /*!< in: the index name to find */
2360
const char** columns,/*!< in: array of column names */
2361
ulint n_cols) /*!< in: number of columns */
2363
dict_index_t* index;
2364
dict_index_t* found;
2367
index = dict_table_get_first_index(table);
2369
while (index != NULL) {
2370
if (ut_strcmp(index->name, name) == 0
2371
&& dict_index_get_n_ordering_defined_by_user(index)
2376
for (i = 0; i < n_cols; i++) {
2377
dict_field_t* field;
2378
const char* col_name;
2380
field = dict_index_get_nth_field(index, i);
2382
col_name = dict_table_get_col_name(
2383
table, dict_col_get_no(field->col));
2385
if (0 != innobase_strcasecmp(
2386
columns[i], col_name)) {
2393
/* We found a matching index, select
2394
the index with the higher id*/
2397
|| ut_dulint_cmp(index->id, found->id) > 0) {
2404
index = dict_table_get_next_index(index);
2410
/**********************************************************************//**
2411
Report an error in a foreign key definition. */
2414
dict_foreign_error_report_low(
2415
/*==========================*/
2416
FILE* file, /*!< in: output stream */
2417
const char* name) /*!< in: table name */
2420
ut_print_timestamp(file);
2421
fprintf(file, " Error in foreign key constraint of table %s:\n",
2425
/**********************************************************************//**
2426
Report an error in a foreign key definition. */
2429
dict_foreign_error_report(
2430
/*======================*/
2431
FILE* file, /*!< in: output stream */
2432
dict_foreign_t* fk, /*!< in: foreign key constraint */
2433
const char* msg) /*!< in: the error message */
2435
mutex_enter(&dict_foreign_err_mutex);
2436
dict_foreign_error_report_low(file, fk->foreign_table_name);
2438
fputs(" Constraint:\n", file);
2439
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2441
if (fk->foreign_index) {
2442
fputs("The index in the foreign key in table is ", file);
2443
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2445
"See " REFMAN "innodb-foreign-key-constraints.html\n"
2446
"for correct foreign key definition.\n",
2449
mutex_exit(&dict_foreign_err_mutex);
2452
/**********************************************************************//**
2453
Adds a foreign key constraint object to the dictionary cache. May free
2454
the object if there already is an object with the same identifier in.
2455
At least one of the foreign table and the referenced table must already
2456
be in the dictionary cache!
2457
@return DB_SUCCESS or error code */
2460
dict_foreign_add_to_cache(
2461
/*======================*/
2462
dict_foreign_t* foreign, /*!< in, own: foreign key constraint */
2463
ibool check_charsets) /*!< in: TRUE=check charset
2466
dict_table_t* for_table;
2467
dict_table_t* ref_table;
2468
dict_foreign_t* for_in_cache = NULL;
2469
dict_index_t* index;
2470
ibool added_to_referenced_list= FALSE;
2471
FILE* ef = dict_foreign_err_file;
2473
ut_ad(mutex_own(&(dict_sys->mutex)));
2475
for_table = dict_table_check_if_in_cache_low(
2476
foreign->foreign_table_name);
2478
ref_table = dict_table_check_if_in_cache_low(
2479
foreign->referenced_table_name);
2480
ut_a(for_table || ref_table);
2483
for_in_cache = dict_foreign_find(for_table, foreign->id);
2486
if (!for_in_cache && ref_table) {
2487
for_in_cache = dict_foreign_find(ref_table, foreign->id);
2491
/* Free the foreign object */
2492
mem_heap_free(foreign->heap);
2494
for_in_cache = foreign;
2497
if (for_in_cache->referenced_table == NULL && ref_table) {
2498
index = dict_foreign_find_index(
2500
for_in_cache->referenced_col_names,
2501
for_in_cache->n_fields, for_in_cache->foreign_index,
2502
check_charsets, FALSE);
2504
if (index == NULL) {
2505
dict_foreign_error_report(
2507
"there is no index in referenced table"
2508
" which would contain\n"
2509
"the columns as the first columns,"
2510
" or the data types in the\n"
2511
"referenced table do not match"
2512
" the ones in table.");
2514
if (for_in_cache == foreign) {
2515
mem_heap_free(foreign->heap);
2518
return(DB_CANNOT_ADD_CONSTRAINT);
2521
for_in_cache->referenced_table = ref_table;
2522
for_in_cache->referenced_index = index;
2523
UT_LIST_ADD_LAST(referenced_list,
2524
ref_table->referenced_list,
2526
added_to_referenced_list = TRUE;
2529
if (for_in_cache->foreign_table == NULL && for_table) {
2530
index = dict_foreign_find_index(
2532
for_in_cache->foreign_col_names,
2533
for_in_cache->n_fields,
2534
for_in_cache->referenced_index, check_charsets,
2536
& (DICT_FOREIGN_ON_DELETE_SET_NULL
2537
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
2539
if (index == NULL) {
2540
dict_foreign_error_report(
2542
"there is no index in the table"
2543
" which would contain\n"
2544
"the columns as the first columns,"
2545
" or the data types in the\n"
2546
"table do not match"
2547
" the ones in the referenced table\n"
2548
"or one of the ON ... SET NULL columns"
2549
" is declared NOT NULL.");
2551
if (for_in_cache == foreign) {
2552
if (added_to_referenced_list) {
2555
ref_table->referenced_list,
2559
mem_heap_free(foreign->heap);
2562
return(DB_CANNOT_ADD_CONSTRAINT);
2565
for_in_cache->foreign_table = for_table;
2566
for_in_cache->foreign_index = index;
2567
UT_LIST_ADD_LAST(foreign_list,
2568
for_table->foreign_list,
2575
/*********************************************************************//**
2576
Scans from pointer onwards. Stops if is at the start of a copy of
2577
'string' where characters are compared without case sensitivity, and
2578
only outside `` or "" quotes. Stops also at NUL.
2579
@return scanned up to this */
2584
const char* ptr, /*!< in: scan from */
2585
const char* string) /*!< in: look for this */
2589
for (; *ptr; ptr++) {
2590
if (*ptr == quote) {
2591
/* Closing quote character: do not look for
2592
starting quote or the keyword. */
2595
/* Within quotes: do nothing. */
2596
} else if (*ptr == '`' || *ptr == '"') {
2597
/* Starting quote: remember the quote character. */
2600
/* Outside quotes: look for the keyword. */
2602
for (i = 0; string[i]; i++) {
2603
if (toupper((int)(unsigned char)(ptr[i]))
2604
!= toupper((int)(unsigned char)
2618
/*********************************************************************//**
2619
Accepts a specified string. Comparisons are case-insensitive.
2620
@return if string was accepted, the pointer is moved after that, else
2626
struct charset_info_st* cs,/*!< in: the character set of ptr */
2627
const char* ptr, /*!< in: scan from this */
2628
const char* string, /*!< in: accept only this string as the next
2629
non-whitespace string */
2630
ibool* success)/*!< out: TRUE if accepted */
2632
const char* old_ptr = ptr;
2633
const char* old_ptr2;
2637
while (my_isspace(cs, *ptr)) {
2643
ptr = dict_scan_to(ptr, string);
2645
if (*ptr == '\0' || old_ptr2 != ptr) {
2651
return(ptr + ut_strlen(string));
2654
/*********************************************************************//**
2655
Scans an id. For the lexical definition of an 'id', see the code below.
2656
Strips backquotes or double quotes from around the id.
2657
@return scanned to */
2662
struct charset_info_st* cs,/*!< in: the character set of ptr */
2663
const char* ptr, /*!< in: scanned to */
2664
mem_heap_t* heap, /*!< in: heap where to allocate the id
2665
(NULL=id will not be allocated, but it
2666
will point to string near ptr) */
2667
const char** id, /*!< out,own: the id; NULL if no id was
2669
ibool table_id,/*!< in: TRUE=convert the allocated id
2670
as a table name; FALSE=convert to UTF-8 */
2671
ibool accept_also_dot)
2672
/*!< in: TRUE if also a dot can appear in a
2673
non-quoted id; in a quoted id it can appear
2684
while (my_isspace(cs, *ptr)) {
2693
if (*ptr == '`' || *ptr == '"') {
2705
if (*ptr == quote) {
2707
if (*ptr != quote) {
2715
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2716
&& (accept_also_dot || *ptr != '.')
2717
&& *ptr != ',' && *ptr != '\0') {
2725
if (UNIV_UNLIKELY(!heap)) {
2726
/* no heap given: id will point to source string */
2733
str = d = mem_heap_alloc(heap, len + 1);
2735
if ((*d++ = *s++) == quote) {
2742
ut_ad(s + 1 == ptr);
2744
str = mem_heap_strdupl(heap, s, len);
2749
/* Convert the identifier from connection character set
2752
*id = dst = mem_heap_alloc(heap, len);
2754
innobase_convert_from_id(cs, dst, str, len);
2755
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2756
sizeof srv_mysql50_table_name_prefix)) {
2757
/* This is a pre-5.1 table name
2758
containing chars other than [A-Za-z0-9].
2759
Discard the prefix and use raw UTF-8 encoding. */
2760
str += sizeof srv_mysql50_table_name_prefix;
2761
len -= sizeof srv_mysql50_table_name_prefix;
2764
/* Encode using filename-safe characters. */
2766
*id = dst = mem_heap_alloc(heap, len);
2768
innobase_convert_from_table_id(cs, dst, str, len);
2774
/*********************************************************************//**
2775
Tries to scan a column name.
2776
@return scanned to */
2781
struct charset_info_st* cs, /*!< in: the character set of ptr */
2782
const char* ptr, /*!< in: scanned to */
2783
ibool* success,/*!< out: TRUE if success */
2784
dict_table_t* table, /*!< in: table in which the column is */
2785
const dict_col_t** column, /*!< out: pointer to column if success */
2786
mem_heap_t* heap, /*!< in: heap where to allocate */
2787
const char** name) /*!< out,own: the column name;
2788
NULL if no name was scannable */
2794
ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2796
if (*name == NULL) {
2798
return(ptr); /* Syntax error */
2801
if (table == NULL) {
2805
for (i = 0; i < dict_table_get_n_cols(table); i++) {
2807
const char* col_name = dict_table_get_col_name(
2810
if (0 == innobase_strcasecmp(col_name, *name)) {
2814
*column = dict_table_get_nth_col(table, i);
2815
strcpy((char*) *name, col_name);
2825
/*********************************************************************//**
2826
Scans a table name from an SQL string.
2827
@return scanned to */
2830
dict_scan_table_name(
2831
/*=================*/
2832
struct charset_info_st* cs,/*!< in: the character set of ptr */
2833
const char* ptr, /*!< in: scanned to */
2834
dict_table_t** table, /*!< out: table object or NULL */
2835
const char* name, /*!< in: foreign key table name */
2836
ibool* success,/*!< out: TRUE if ok name found */
2837
mem_heap_t* heap, /*!< in: heap where to allocate the id */
2838
const char** ref_name)/*!< out,own: the table name;
2839
NULL if no name was scannable */
2841
const char* database_name = NULL;
2842
ulint database_name_len = 0;
2843
const char* table_name = NULL;
2844
ulint table_name_len;
2845
const char* scan_name;
2851
ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2853
if (scan_name == NULL) {
2855
return(ptr); /* Syntax error */
2859
/* We scanned the database name; scan also the table name */
2863
database_name = scan_name;
2864
database_name_len = strlen(database_name);
2866
ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2868
if (table_name == NULL) {
2870
return(ptr); /* Syntax error */
2873
/* To be able to read table dumps made with InnoDB-4.0.17 or
2874
earlier, we must allow the dot separator between the database
2875
name and the table name also to appear within a quoted
2876
identifier! InnoDB used to print a constraint as:
2877
... REFERENCES `databasename.tablename` ...
2878
starting from 4.0.18 it is
2879
... REFERENCES `databasename`.`tablename` ... */
2882
for (s = scan_name; *s; s++) {
2884
database_name = scan_name;
2885
database_name_len = s - scan_name;
2887
break;/* to do: multiple dots? */
2891
table_name = scan_name;
2894
if (database_name == NULL) {
2895
/* Use the database name of the foreign key table */
2897
database_name = name;
2898
database_name_len = dict_get_db_name_len(name);
2901
table_name_len = strlen(table_name);
2903
/* Copy database_name, '/', table_name, '\0' */
2904
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2905
memcpy(ref, database_name, database_name_len);
2906
ref[database_name_len] = '/';
2907
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2909
if (srv_lower_case_table_names) {
2910
#endif /* !__WIN__ */
2911
/* The table name is always put to lower case on Windows. */
2912
innobase_casedn_str(ref);
2915
#endif /* !__WIN__ */
2919
*table = dict_table_get_low(ref);
2924
/*********************************************************************//**
2925
Skips one id. The id is allowed to contain also '.'.
2926
@return scanned to */
2931
struct charset_info_st* cs,/*!< in: the character set of ptr */
2932
const char* ptr, /*!< in: scanned to */
2933
ibool* success)/*!< out: TRUE if success, FALSE if just spaces
2934
left in string or a syntax error */
2940
ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2949
/*********************************************************************//**
2950
Removes MySQL comments from an SQL string. A comment is either
2951
(a) '#' to the end of the line,
2952
(b) '--[space]' to the end of the line, or
2953
(c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
2955
@return own: SQL string stripped from comments; the caller must free
2956
this with mem_free()! */
2959
dict_strip_comments(
2960
/*================*/
2961
const char* sql_string) /*!< in: SQL string */
2966
/* unclosed quote character (0 if none) */
2969
str = mem_alloc(strlen(sql_string) + 1);
2976
if (*sptr == '\0') {
2979
ut_a(ptr <= str + strlen(sql_string));
2984
if (*sptr == quote) {
2985
/* Closing quote character: do not look for
2986
starting quote or comments. */
2989
/* Within quotes: do not look for
2990
starting quotes or comments. */
2991
} else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
2992
/* Starting quote: remember the quote character. */
2994
} else if (*sptr == '#'
2995
|| (sptr[0] == '-' && sptr[1] == '-'
2996
&& sptr[2] == ' ')) {
2998
/* In Unix a newline is 0x0A while in Windows
2999
it is 0x0D followed by 0x0A */
3001
if (*sptr == (char)0x0A
3002
|| *sptr == (char)0x0D
3010
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3012
if (*sptr == '*' && *(sptr + 1) == '/') {
3019
if (*sptr == '\0') {
3035
/*********************************************************************//**
3036
Finds the highest [number] for foreign key constraints of the table. Looks
3037
only at the >= 4.0.18-format id's, which are of the form
3038
databasename/tablename_ibfk_[number].
3039
@return highest number, 0 if table has no new format foreign key constraints */
3042
dict_table_get_highest_foreign_id(
3043
/*==============================*/
3044
dict_table_t* table) /*!< in: table in the dictionary memory cache */
3046
dict_foreign_t* foreign;
3048
ulint biggest_id = 0;
3054
len = ut_strlen(table->name);
3055
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3058
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
3059
&& 0 == ut_memcmp(foreign->id, table->name, len)
3060
&& 0 == ut_memcmp(foreign->id + len,
3061
dict_ibfk, (sizeof dict_ibfk) - 1)
3062
&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
3063
/* It is of the >= 4.0.18 format */
3065
id = strtoul(foreign->id + len
3066
+ ((sizeof dict_ibfk) - 1),
3068
if (*endp == '\0') {
3069
ut_a(id != biggest_id);
3071
if (id > biggest_id) {
3077
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3083
/*********************************************************************//**
3084
Reports a simple foreign key create clause syntax error. */
3087
dict_foreign_report_syntax_err(
3088
/*===========================*/
3089
const char* name, /*!< in: table name */
3090
const char* start_of_latest_foreign,
3091
/*!< in: start of the foreign key clause
3092
in the SQL string */
3093
const char* ptr) /*!< in: place of the syntax error */
3095
FILE* ef = dict_foreign_err_file;
3097
mutex_enter(&dict_foreign_err_mutex);
3098
dict_foreign_error_report_low(ef, name);
3099
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
3100
start_of_latest_foreign, ptr);
3101
mutex_exit(&dict_foreign_err_mutex);
3104
/*********************************************************************//**
3105
Scans a table create SQL string and adds to the data dictionary the foreign
3106
key constraints declared in the string. This function should be called after
3107
the indexes for a table have been created. Each foreign key constraint must
3108
be accompanied with indexes in both participating tables. The indexes are
3109
allowed to contain more fields than mentioned in the constraint.
3110
@return error code or DB_SUCCESS */
3113
dict_create_foreign_constraints_low(
3114
/*================================*/
3115
trx_t* trx, /*!< in: transaction */
3116
mem_heap_t* heap, /*!< in: memory heap */
3117
struct charset_info_st* cs,/*!< in: the character set of sql_string */
3118
const char* sql_string,
3119
/*!< in: CREATE TABLE or ALTER TABLE statement
3120
where foreign keys are declared like:
3121
FOREIGN KEY (a, b) REFERENCES table2(c, d),
3122
table2 can be written also with the database
3123
name before it: test.table2; the default
3124
database is the database of parameter name */
3125
const char* name, /*!< in: table full name in the normalized form
3126
database_name/table_name */
3128
/*!< in: if TRUE, fail with error code
3129
DB_CANNOT_ADD_CONSTRAINT if any foreign
3132
dict_table_t* table;
3133
dict_table_t* referenced_table;
3134
dict_table_t* table_to_alter;
3135
ulint highest_id_so_far = 0;
3136
dict_index_t* index;
3137
dict_foreign_t* foreign;
3138
const char* ptr = sql_string;
3139
const char* start_of_latest_foreign = sql_string;
3140
FILE* ef = dict_foreign_err_file;
3141
const char* constraint_name;
3151
const dict_col_t*columns[500];
3152
const char* column_names[500];
3153
const char* referenced_table_name;
3155
ut_ad(mutex_own(&(dict_sys->mutex)));
3157
table = dict_table_get_low(name);
3159
if (table == NULL) {
3160
mutex_enter(&dict_foreign_err_mutex);
3161
dict_foreign_error_report_low(ef, name);
3163
"Cannot find the table in the internal"
3164
" data dictionary of InnoDB.\n"
3165
"Create table statement:\n%s\n", sql_string);
3166
mutex_exit(&dict_foreign_err_mutex);
3171
/* First check if we are actually doing an ALTER TABLE, and in that
3172
case look for the table being altered */
3174
ptr = dict_accept(cs, ptr, "ALTER", &success);
3181
ptr = dict_accept(cs, ptr, "TABLE", &success);
3188
/* We are doing an ALTER TABLE: scan the table name we are altering */
3190
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
3191
&success, heap, &referenced_table_name);
3194
"InnoDB: Error: could not find"
3195
" the table being ALTERED in:\n%s\n",
3201
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
3202
format databasename/tablename_ibfk_[number], where [number] is local
3203
to the table; look for the highest [number] for table_to_alter, so
3204
that we can assign to new constraints higher numbers. */
3206
/* If we are altering a temporary table, the table name after ALTER
3207
TABLE does not correspond to the internal table name, and
3208
table_to_alter is NULL. TODO: should we fix this somehow? */
3210
if (table_to_alter == NULL) {
3211
highest_id_so_far = 0;
3213
highest_id_so_far = dict_table_get_highest_foreign_id(
3217
/* Scan for foreign key declarations in a loop */
3219
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
3221
ptr1 = dict_scan_to(ptr, "CONSTRAINT");
3222
ptr2 = dict_scan_to(ptr, "FOREIGN");
3224
constraint_name = NULL;
3227
/* The user may have specified a constraint name. Pick it so
3228
that we can store 'databasename/constraintname' as the id of
3229
of the constraint to system tables. */
3232
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
3236
if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
3240
while (my_isspace(cs, *ptr)) {
3244
/* read constraint name unless got "CONSTRAINT FOREIGN" */
3246
ptr = dict_scan_id(cs, ptr, heap,
3247
&constraint_name, FALSE, FALSE);
3254
/* The proper way to reject foreign keys for temporary
3255
tables would be to split the lexing and syntactical
3256
analysis of foreign key clauses from the actual adding
3257
of them, so that ha_innodb.cc could first parse the SQL
3258
command, determine if there are any foreign keys, and
3259
if so, immediately reject the command if the table is a
3260
temporary one. For now, this kludge will work. */
3261
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
3263
return(DB_CANNOT_ADD_CONSTRAINT);
3266
/**********************************************************/
3267
/* The following call adds the foreign key constraints
3268
to the data dictionary system tables on disk */
3270
error = dict_create_add_foreigns_to_dictionary(
3271
highest_id_so_far, table, trx);
3275
start_of_latest_foreign = ptr;
3277
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3283
if (!my_isspace(cs, *ptr)) {
3287
ptr = dict_accept(cs, ptr, "KEY", &success);
3293
ptr = dict_accept(cs, ptr, "(", &success);
3296
/* MySQL allows also an index id before the '('; we
3298
ptr = dict_skip_word(cs, ptr, &success);
3301
dict_foreign_report_syntax_err(
3302
name, start_of_latest_foreign, ptr);
3304
return(DB_CANNOT_ADD_CONSTRAINT);
3307
ptr = dict_accept(cs, ptr, "(", &success);
3310
/* We do not flag a syntax error here because in an
3311
ALTER TABLE we may also have DROP FOREIGN KEY abc */
3319
/* Scan the columns in the first list */
3321
ut_a(i < (sizeof column_names) / sizeof *column_names);
3322
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
3323
heap, column_names + i);
3325
mutex_enter(&dict_foreign_err_mutex);
3326
dict_foreign_error_report_low(ef, name);
3327
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
3328
start_of_latest_foreign, ptr);
3329
mutex_exit(&dict_foreign_err_mutex);
3331
return(DB_CANNOT_ADD_CONSTRAINT);
3336
ptr = dict_accept(cs, ptr, ",", &success);
3342
ptr = dict_accept(cs, ptr, ")", &success);
3345
dict_foreign_report_syntax_err(
3346
name, start_of_latest_foreign, ptr);
3347
return(DB_CANNOT_ADD_CONSTRAINT);
3350
/* Try to find an index which contains the columns
3351
as the first fields and in the right order */
3353
index = dict_foreign_find_index(table, column_names, i,
3357
mutex_enter(&dict_foreign_err_mutex);
3358
dict_foreign_error_report_low(ef, name);
3359
fputs("There is no index in table ", ef);
3360
ut_print_name(ef, NULL, TRUE, name);
3361
fprintf(ef, " where the columns appear\n"
3362
"as the first columns. Constraint:\n%s\n"
3363
"See " REFMAN "innodb-foreign-key-constraints.html\n"
3364
"for correct foreign key definition.\n",
3365
start_of_latest_foreign);
3366
mutex_exit(&dict_foreign_err_mutex);
3368
return(DB_CANNOT_ADD_CONSTRAINT);
3370
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3372
if (!success || !my_isspace(cs, *ptr)) {
3373
dict_foreign_report_syntax_err(
3374
name, start_of_latest_foreign, ptr);
3375
return(DB_CANNOT_ADD_CONSTRAINT);
3378
/* Let us create a constraint struct */
3380
foreign = dict_mem_foreign_create();
3382
if (constraint_name) {
3385
/* Catenate 'databasename/' to the constraint name specified
3386
by the user: we conceive the constraint as belonging to the
3387
same MySQL 'database' as the table itself. We store the name
3390
db_len = dict_get_db_name_len(table->name);
3392
foreign->id = mem_heap_alloc(
3393
foreign->heap, db_len + strlen(constraint_name) + 2);
3395
ut_memcpy(foreign->id, table->name, db_len);
3396
foreign->id[db_len] = '/';
3397
strcpy(foreign->id + db_len + 1, constraint_name);
3400
foreign->foreign_table = table;
3401
foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
3403
foreign->foreign_index = index;
3404
foreign->n_fields = (unsigned int) i;
3405
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3407
for (i = 0; i < foreign->n_fields; i++) {
3408
foreign->foreign_col_names[i] = mem_heap_strdup(
3410
dict_table_get_col_name(table,
3411
dict_col_get_no(columns[i])));
3414
ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3415
&success, heap, &referenced_table_name);
3417
/* Note that referenced_table can be NULL if the user has suppressed
3418
checking of foreign key constraints! */
3420
if (!success || (!referenced_table && trx->check_foreigns)) {
3421
dict_foreign_free(foreign);
3423
mutex_enter(&dict_foreign_err_mutex);
3424
dict_foreign_error_report_low(ef, name);
3425
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3427
start_of_latest_foreign, ptr);
3428
mutex_exit(&dict_foreign_err_mutex);
3430
return(DB_CANNOT_ADD_CONSTRAINT);
3433
ptr = dict_accept(cs, ptr, "(", &success);
3436
dict_foreign_free(foreign);
3437
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3439
return(DB_CANNOT_ADD_CONSTRAINT);
3442
/* Scan the columns in the second list */
3446
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3447
heap, column_names + i);
3451
dict_foreign_free(foreign);
3453
mutex_enter(&dict_foreign_err_mutex);
3454
dict_foreign_error_report_low(ef, name);
3455
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3457
start_of_latest_foreign, ptr);
3458
mutex_exit(&dict_foreign_err_mutex);
3460
return(DB_CANNOT_ADD_CONSTRAINT);
3463
ptr = dict_accept(cs, ptr, ",", &success);
3469
ptr = dict_accept(cs, ptr, ")", &success);
3471
if (!success || foreign->n_fields != i) {
3472
dict_foreign_free(foreign);
3474
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3476
return(DB_CANNOT_ADD_CONSTRAINT);
3483
/* Loop here as long as we can find ON ... conditions */
3485
ptr = dict_accept(cs, ptr, "ON", &success);
3489
goto try_find_index;
3492
ptr = dict_accept(cs, ptr, "DELETE", &success);
3495
ptr = dict_accept(cs, ptr, "UPDATE", &success);
3498
dict_foreign_free(foreign);
3500
dict_foreign_report_syntax_err(
3501
name, start_of_latest_foreign, ptr);
3502
return(DB_CANNOT_ADD_CONSTRAINT);
3505
is_on_delete = FALSE;
3508
is_on_delete = TRUE;
3512
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3515
goto scan_on_conditions;
3518
ptr = dict_accept(cs, ptr, "CASCADE", &success);
3522
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3524
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3527
goto scan_on_conditions;
3530
ptr = dict_accept(cs, ptr, "NO", &success);
3533
ptr = dict_accept(cs, ptr, "ACTION", &success);
3536
dict_foreign_free(foreign);
3537
dict_foreign_report_syntax_err(
3538
name, start_of_latest_foreign, ptr);
3540
return(DB_CANNOT_ADD_CONSTRAINT);
3544
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3546
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3549
goto scan_on_conditions;
3552
ptr = dict_accept(cs, ptr, "SET", &success);
3555
dict_foreign_free(foreign);
3556
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3558
return(DB_CANNOT_ADD_CONSTRAINT);
3561
ptr = dict_accept(cs, ptr, "NULL", &success);
3564
dict_foreign_free(foreign);
3565
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3567
return(DB_CANNOT_ADD_CONSTRAINT);
3570
for (j = 0; j < foreign->n_fields; j++) {
3571
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3574
/* It is not sensible to define SET NULL
3575
if the column is not allowed to be NULL! */
3577
dict_foreign_free(foreign);
3579
mutex_enter(&dict_foreign_err_mutex);
3580
dict_foreign_error_report_low(ef, name);
3582
"You have defined a SET NULL condition"
3583
" though some of the\n"
3584
"columns are defined as NOT NULL.\n",
3585
start_of_latest_foreign);
3586
mutex_exit(&dict_foreign_err_mutex);
3588
return(DB_CANNOT_ADD_CONSTRAINT);
3593
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3595
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3598
goto scan_on_conditions;
3601
if (n_on_deletes > 1 || n_on_updates > 1) {
3602
/* It is an error to define more than 1 action */
3604
dict_foreign_free(foreign);
3606
mutex_enter(&dict_foreign_err_mutex);
3607
dict_foreign_error_report_low(ef, name);
3609
"You have twice an ON DELETE clause"
3610
" or twice an ON UPDATE clause.\n",
3611
start_of_latest_foreign);
3612
mutex_exit(&dict_foreign_err_mutex);
3614
return(DB_CANNOT_ADD_CONSTRAINT);
3617
/* Try to find an index which contains the columns as the first fields
3618
and in the right order, and the types are the same as in
3619
foreign->foreign_index */
3621
if (referenced_table) {
3622
index = dict_foreign_find_index(referenced_table,
3624
foreign->foreign_index,
3627
dict_foreign_free(foreign);
3628
mutex_enter(&dict_foreign_err_mutex);
3629
dict_foreign_error_report_low(ef, name);
3631
"Cannot find an index in the"
3632
" referenced table where the\n"
3633
"referenced columns appear as the"
3634
" first columns, or column types\n"
3635
"in the table and the referenced table"
3636
" do not match for constraint.\n"
3637
"Note that the internal storage type of"
3638
" ENUM and SET changed in\n"
3639
"tables created with >= InnoDB-4.1.12,"
3640
" and such columns in old tables\n"
3641
"cannot be referenced by such columns"
3644
"innodb-foreign-key-constraints.html\n"
3645
"for correct foreign key definition.\n",
3646
start_of_latest_foreign);
3647
mutex_exit(&dict_foreign_err_mutex);
3649
return(DB_CANNOT_ADD_CONSTRAINT);
3652
ut_a(trx->check_foreigns == FALSE);
3656
foreign->referenced_index = index;
3657
foreign->referenced_table = referenced_table;
3659
foreign->referenced_table_name
3660
= mem_heap_strdup(foreign->heap, referenced_table_name);
3662
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3664
for (i = 0; i < foreign->n_fields; i++) {
3665
foreign->referenced_col_names[i]
3666
= mem_heap_strdup(foreign->heap, column_names[i]);
3669
/* We found an ok constraint definition: add to the lists */
3671
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3673
if (referenced_table) {
3674
UT_LIST_ADD_LAST(referenced_list,
3675
referenced_table->referenced_list,
3682
/*********************************************************************//**
3683
Scans a table create SQL string and adds to the data dictionary the foreign
3684
key constraints declared in the string. This function should be called after
3685
the indexes for a table have been created. Each foreign key constraint must
3686
be accompanied with indexes in both participating tables. The indexes are
3687
allowed to contain more fields than mentioned in the constraint.
3688
@return error code or DB_SUCCESS */
3691
dict_create_foreign_constraints(
3692
/*============================*/
3693
trx_t* trx, /*!< in: transaction */
3694
const char* sql_string, /*!< in: table create statement where
3695
foreign keys are declared like:
3696
FOREIGN KEY (a, b) REFERENCES
3697
table2(c, d), table2 can be written
3698
also with the database
3699
name before it: test.table2; the
3700
default database id the database of
3702
const char* name, /*!< in: table full name in the
3704
database_name/table_name */
3705
ibool reject_fks) /*!< in: if TRUE, fail with error
3706
code DB_CANNOT_ADD_CONSTRAINT if
3707
any foreign keys are found. */
3714
ut_a(trx->mysql_thd);
3716
str = dict_strip_comments(sql_string);
3717
heap = mem_heap_create(10000);
3719
err = dict_create_foreign_constraints_low(
3720
trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3723
mem_heap_free(heap);
3729
/**********************************************************************//**
3730
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
3731
@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
3732
constraint id does not match */
3735
dict_foreign_parse_drop_constraints(
3736
/*================================*/
3737
mem_heap_t* heap, /*!< in: heap from which we can
3739
trx_t* trx, /*!< in: transaction */
3740
dict_table_t* table, /*!< in: table */
3741
ulint* n, /*!< out: number of constraints
3743
const char*** constraints_to_drop) /*!< out: id's of the
3744
constraints to drop */
3746
dict_foreign_t* foreign;
3751
FILE* ef = dict_foreign_err_file;
3752
struct charset_info_st* cs;
3755
ut_a(trx->mysql_thd);
3757
cs = innobase_get_charset(trx->mysql_thd);
3761
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3763
str = dict_strip_comments(*(trx->mysql_query_str));
3766
ut_ad(mutex_own(&(dict_sys->mutex)));
3768
ptr = dict_scan_to(ptr, "DROP");
3776
ptr = dict_accept(cs, ptr, "DROP", &success);
3778
if (!my_isspace(cs, *ptr)) {
3783
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3785
if (!success || !my_isspace(cs, *ptr)) {
3790
ptr = dict_accept(cs, ptr, "KEY", &success);
3797
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3805
(*constraints_to_drop)[*n] = id;
3808
/* Look for the given constraint id */
3810
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3812
while (foreign != NULL) {
3813
if (0 == strcmp(foreign->id, id)
3814
|| (strchr(foreign->id, '/')
3816
dict_remove_db_name(foreign->id)))) {
3821
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3824
if (foreign == NULL) {
3825
mutex_enter(&dict_foreign_err_mutex);
3827
ut_print_timestamp(ef);
3828
fputs(" Error in dropping of a foreign key constraint"
3830
ut_print_name(ef, NULL, TRUE, table->name);
3832
"in SQL command\n", ef);
3834
fputs("\nCannot find a constraint with the given id ", ef);
3835
ut_print_name(ef, NULL, FALSE, id);
3837
mutex_exit(&dict_foreign_err_mutex);
3841
return(DB_CANNOT_DROP_CONSTRAINT);
3847
mutex_enter(&dict_foreign_err_mutex);
3849
ut_print_timestamp(ef);
3850
fputs(" Syntax error in dropping of a"
3851
" foreign key constraint of table ", ef);
3852
ut_print_name(ef, NULL, TRUE, table->name);
3854
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
3855
mutex_exit(&dict_foreign_err_mutex);
3859
return(DB_CANNOT_DROP_CONSTRAINT);
3862
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3864
/**********************************************************************//**
3865
Returns an index object if it is found in the dictionary cache.
3866
Assumes that dict_sys->mutex is already being held.
3867
@return index, NULL if not found */
3870
dict_index_get_if_in_cache_low(
3871
/*===========================*/
3872
dulint index_id) /*!< in: index id */
3874
ut_ad(mutex_own(&(dict_sys->mutex)));
3876
return(dict_index_find_on_id_low(index_id));
3879
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
3880
/**********************************************************************//**
3881
Returns an index object if it is found in the dictionary cache.
3882
@return index, NULL if not found */
3885
dict_index_get_if_in_cache(
3886
/*=======================*/
3887
dulint index_id) /*!< in: index id */
3889
dict_index_t* index;
3891
if (dict_sys == NULL) {
3895
mutex_enter(&(dict_sys->mutex));
3897
index = dict_index_get_if_in_cache_low(index_id);
3899
mutex_exit(&(dict_sys->mutex));
3903
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
3906
/**********************************************************************//**
3907
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3908
no comparison can occur with the page number field in a node pointer.
3909
@return TRUE if ok */
3912
dict_index_check_search_tuple(
3913
/*==========================*/
3914
const dict_index_t* index, /*!< in: index tree */
3915
const dtuple_t* tuple) /*!< in: tuple used in a search */
3918
ut_a(dtuple_get_n_fields_cmp(tuple)
3919
<= dict_index_get_n_unique_in_tree(index));
3922
#endif /* UNIV_DEBUG */
3924
/**********************************************************************//**
3925
Builds a node pointer out of a physical record and a page number.
3926
@return own: node pointer */
3929
dict_index_build_node_ptr(
3930
/*======================*/
3931
const dict_index_t* index, /*!< in: index */
3932
const rec_t* rec, /*!< in: record for which to build node
3934
ulint page_no,/*!< in: page number to put in node
3936
mem_heap_t* heap, /*!< in: memory heap where pointer
3938
ulint level) /*!< in: level of rec in tree:
3939
0 means leaf level */
3946
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3947
/* In a universal index tree, we take the whole record as
3948
the node pointer if the record is on the leaf level,
3949
on non-leaf levels we remove the last field, which
3950
contains the page number of the child page */
3952
ut_a(!dict_table_is_comp(index->table));
3953
n_unique = rec_get_n_fields_old(rec);
3960
n_unique = dict_index_get_n_unique_in_tree(index);
3963
tuple = dtuple_create(heap, n_unique + 1);
3965
/* When searching in the tree for the node pointer, we must not do
3966
comparison on the last field, the page number field, as on upper
3967
levels in the tree there may be identical node pointers with a
3968
different page number; therefore, we set the n_fields_cmp to one
3971
dtuple_set_n_fields_cmp(tuple, n_unique);
3973
dict_index_copy_types(tuple, index, n_unique);
3975
buf = mem_heap_alloc(heap, 4);
3977
mach_write_to_4(buf, page_no);
3979
field = dtuple_get_nth_field(tuple, n_unique);
3980
dfield_set_data(field, buf, 4);
3982
dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3984
rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3985
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3986
| REC_STATUS_NODE_PTR);
3988
ut_ad(dtuple_check_typed(tuple));
3993
/**********************************************************************//**
3994
Copies an initial segment of a physical record, long enough to specify an
3995
index entry uniquely.
3996
@return pointer to the prefix record */
3999
dict_index_copy_rec_order_prefix(
4000
/*=============================*/
4001
const dict_index_t* index, /*!< in: index */
4002
const rec_t* rec, /*!< in: record for which to
4004
ulint* n_fields,/*!< out: number of fields copied */
4005
byte** buf, /*!< in/out: memory buffer for the
4006
copied prefix, or NULL */
4007
ulint* buf_size)/*!< in/out: buffer size */
4011
UNIV_PREFETCH_R(rec);
4013
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
4014
ut_a(!dict_table_is_comp(index->table));
4015
n = rec_get_n_fields_old(rec);
4017
n = dict_index_get_n_unique_in_tree(index);
4021
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
4024
/**********************************************************************//**
4025
Builds a typed data tuple out of a physical record.
4026
@return own: data tuple */
4029
dict_index_build_data_tuple(
4030
/*========================*/
4031
dict_index_t* index, /*!< in: index tree */
4032
rec_t* rec, /*!< in: record for which to build data tuple */
4033
ulint n_fields,/*!< in: number of data fields */
4034
mem_heap_t* heap) /*!< in: memory heap where tuple created */
4038
ut_ad(dict_table_is_comp(index->table)
4039
|| n_fields <= rec_get_n_fields_old(rec));
4041
tuple = dtuple_create(heap, n_fields);
4043
dict_index_copy_types(tuple, index, n_fields);
4045
rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
4047
ut_ad(dtuple_check_typed(tuple));
4052
/*********************************************************************//**
4053
Calculates the minimum record length in an index. */
4056
dict_index_calc_min_rec_len(
4057
/*========================*/
4058
const dict_index_t* index) /*!< in: index */
4062
ulint comp = dict_table_is_comp(index->table);
4066
sum = REC_N_NEW_EXTRA_BYTES;
4067
for (i = 0; i < dict_index_get_n_fields(index); i++) {
4068
const dict_col_t* col
4069
= dict_index_get_nth_col(index, i);
4070
ulint size = dict_col_get_fixed_size(col, comp);
4074
sum += size < 128 ? 1 : 2;
4076
if (!(col->prtype & DATA_NOT_NULL)) {
4081
/* round the NULL flags up to full bytes */
4082
sum += UT_BITS_IN_BYTES(nullable);
4087
for (i = 0; i < dict_index_get_n_fields(index); i++) {
4088
sum += dict_col_get_fixed_size(
4089
dict_index_get_nth_col(index, i), comp);
4093
sum += 2 * dict_index_get_n_fields(index);
4095
sum += dict_index_get_n_fields(index);
4098
sum += REC_N_OLD_EXTRA_BYTES;
4103
/*********************************************************************//**
4104
Calculates new estimates for table and index statistics. The statistics
4105
are used in query optimization. */
4108
dict_update_statistics_low(
4109
/*=======================*/
4110
dict_table_t* table, /*!< in/out: table */
4111
ibool has_dict_mutex __attribute__((unused)))
4112
/*!< in: TRUE if the caller has the
4115
dict_index_t* index;
4117
ulint sum_of_index_sizes = 0;
4119
if (table->ibd_file_missing) {
4120
ut_print_timestamp(stderr);
4122
" InnoDB: cannot calculate statistics for table %s\n"
4123
"InnoDB: because the .ibd file is missing. For help,"
4124
" please refer to\n"
4125
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
4131
/* If we have set a high innodb_force_recovery level, do not calculate
4132
statistics, as a badly corrupted index can cause a crash in it. */
4134
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
4139
/* Find out the sizes of the indexes and how many different values
4140
for the key they approximately have */
4142
index = dict_table_get_first_index(table);
4144
if (index == NULL) {
4145
/* Table definition is corrupt */
4151
size = btr_get_size(index, BTR_TOTAL_SIZE);
4153
index->stat_index_size = size;
4155
sum_of_index_sizes += size;
4157
size = btr_get_size(index, BTR_N_LEAF_PAGES);
4160
/* The root node of the tree is a leaf */
4164
index->stat_n_leaf_pages = size;
4166
btr_estimate_number_of_different_key_vals(index);
4168
index = dict_table_get_next_index(index);
4171
index = dict_table_get_first_index(table);
4173
table->stat_n_rows = index->stat_n_diff_key_vals[
4174
dict_index_get_n_unique(index)];
4176
table->stat_clustered_index_size = index->stat_index_size;
4178
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
4179
- index->stat_index_size;
4181
table->stat_initialized = TRUE;
4183
table->stat_modified_counter = 0;
4186
/*********************************************************************//**
4187
Calculates new estimates for table and index statistics. The statistics
4188
are used in query optimization. */
4191
dict_update_statistics(
4192
/*===================*/
4193
dict_table_t* table) /*!< in/out: table */
4195
dict_update_statistics_low(table, FALSE);
4198
/**********************************************************************//**
4199
Prints info of a foreign key constraint. */
4202
dict_foreign_print_low(
4203
/*===================*/
4204
dict_foreign_t* foreign) /*!< in: foreign key constraint */
4208
ut_ad(mutex_own(&(dict_sys->mutex)));
4210
fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
4211
foreign->id, foreign->foreign_table_name);
4213
for (i = 0; i < foreign->n_fields; i++) {
4214
fprintf(stderr, " %s", foreign->foreign_col_names[i]);
4217
fprintf(stderr, " )\n"
4219
foreign->referenced_table_name);
4221
for (i = 0; i < foreign->n_fields; i++) {
4222
fprintf(stderr, " %s", foreign->referenced_col_names[i]);
4225
fputs(" )\n", stderr);
4228
/**********************************************************************//**
4229
Prints a table data. */
4234
dict_table_t* table) /*!< in: table */
4236
mutex_enter(&(dict_sys->mutex));
4237
dict_table_print_low(table);
4238
mutex_exit(&(dict_sys->mutex));
4241
/**********************************************************************//**
4242
Prints a table data when we know the table name. */
4245
dict_table_print_by_name(
4246
/*=====================*/
4247
const char* name) /*!< in: table name */
4249
dict_table_t* table;
4251
mutex_enter(&(dict_sys->mutex));
4253
table = dict_table_get_low(name);
4257
dict_table_print_low(table);
4258
mutex_exit(&(dict_sys->mutex));
4261
/**********************************************************************//**
4262
Prints a table data. */
4265
dict_table_print_low(
4266
/*=================*/
4267
dict_table_t* table) /*!< in: table */
4269
dict_index_t* index;
4270
dict_foreign_t* foreign;
4273
ut_ad(mutex_own(&(dict_sys->mutex)));
4275
dict_update_statistics_low(table, TRUE);
4278
"--------------------------------------\n"
4279
"TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
4280
" indexes %lu, appr.rows %lu\n"
4283
(ulong) ut_dulint_get_high(table->id),
4284
(ulong) ut_dulint_get_low(table->id),
4285
(ulong) table->flags,
4286
(ulong) table->n_cols,
4287
(ulong) UT_LIST_GET_LEN(table->indexes),
4288
(ulong) table->stat_n_rows);
4290
for (i = 0; i < (ulint) table->n_cols; i++) {
4291
dict_col_print_low(table, dict_table_get_nth_col(table, i));
4292
fputs("; ", stderr);
4297
index = UT_LIST_GET_FIRST(table->indexes);
4299
while (index != NULL) {
4300
dict_index_print_low(index);
4301
index = UT_LIST_GET_NEXT(indexes, index);
4304
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4306
while (foreign != NULL) {
4307
dict_foreign_print_low(foreign);
4308
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4311
foreign = UT_LIST_GET_FIRST(table->referenced_list);
4313
while (foreign != NULL) {
4314
dict_foreign_print_low(foreign);
4315
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
4319
/**********************************************************************//**
4320
Prints a column data. */
4325
const dict_table_t* table, /*!< in: table */
4326
const dict_col_t* col) /*!< in: column */
4330
ut_ad(mutex_own(&(dict_sys->mutex)));
4332
dict_col_copy_type(col, &type);
4333
fprintf(stderr, "%s: ", dict_table_get_col_name(table,
4334
dict_col_get_no(col)));
4339
/**********************************************************************//**
4340
Prints an index data. */
4343
dict_index_print_low(
4344
/*=================*/
4345
dict_index_t* index) /*!< in: index */
4349
const char* type_string;
4351
ut_ad(mutex_own(&(dict_sys->mutex)));
4353
if (index->n_user_defined_cols > 0) {
4354
n_vals = index->stat_n_diff_key_vals[
4355
index->n_user_defined_cols];
4357
n_vals = index->stat_n_diff_key_vals[1];
4360
if (dict_index_is_clust(index)) {
4361
type_string = "clustered index";
4362
} else if (dict_index_is_unique(index)) {
4363
type_string = "unique index";
4365
type_string = "secondary index";
4369
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
4370
" uniq %lu, type %lu\n"
4371
" root page %lu, appr.key vals %lu,"
4372
" leaf pages %lu, size pages %lu\n"
4375
(ulong) ut_dulint_get_high(index->id),
4376
(ulong) ut_dulint_get_low(index->id),
4377
(ulong) index->n_user_defined_cols,
4378
(ulong) index->n_fields,
4379
(ulong) index->n_uniq,
4380
(ulong) index->type,
4381
(ulong) index->page,
4383
(ulong) index->stat_n_leaf_pages,
4384
(ulong) index->stat_index_size);
4386
for (i = 0; i < index->n_fields; i++) {
4387
dict_field_print_low(dict_index_get_nth_field(index, i));
4392
#ifdef UNIV_BTR_PRINT
4393
btr_print_size(index);
4395
btr_print_index(index, 7);
4396
#endif /* UNIV_BTR_PRINT */
4399
/**********************************************************************//**
4400
Prints a field data. */
4403
dict_field_print_low(
4404
/*=================*/
4405
dict_field_t* field) /*!< in: field */
4407
ut_ad(mutex_own(&(dict_sys->mutex)));
4409
fprintf(stderr, " %s", field->name);
4411
if (field->prefix_len != 0) {
4412
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4416
/**********************************************************************//**
4417
Outputs info on a foreign key of a table in a format suitable for
4421
dict_print_info_on_foreign_key_in_create_format(
4422
/*============================================*/
4423
FILE* file, /*!< in: file where to print */
4424
trx_t* trx, /*!< in: transaction */
4425
dict_foreign_t* foreign, /*!< in: foreign key constraint */
4426
ibool add_newline) /*!< in: whether to add a newline */
4428
const char* stripped_id;
4431
if (strchr(foreign->id, '/')) {
4432
/* Strip the preceding database name from the constraint id */
4433
stripped_id = foreign->id + 1
4434
+ dict_get_db_name_len(foreign->id);
4436
stripped_id = foreign->id;
4442
/* SHOW CREATE TABLE wants constraints each printed nicely
4443
on its own line, while error messages want no newlines
4448
fputs(" CONSTRAINT ", file);
4449
ut_print_name(file, trx, FALSE, stripped_id);
4450
fputs(" FOREIGN KEY (", file);
4453
ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4454
if (++i < foreign->n_fields) {
4461
fputs(") REFERENCES ", file);
4463
if (dict_tables_have_same_db(foreign->foreign_table_name,
4464
foreign->referenced_table_name)) {
4465
/* Do not print the database name of the referenced table */
4466
ut_print_name(file, trx, TRUE,
4467
dict_remove_db_name(
4468
foreign->referenced_table_name));
4470
ut_print_name(file, trx, TRUE,
4471
foreign->referenced_table_name);
4478
ut_print_name(file, trx, FALSE,
4479
foreign->referenced_col_names[i]);
4480
if (++i < foreign->n_fields) {
4489
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4490
fputs(" ON DELETE CASCADE", file);
4493
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4494
fputs(" ON DELETE SET NULL", file);
4497
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4498
fputs(" ON DELETE NO ACTION", file);
4501
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4502
fputs(" ON UPDATE CASCADE", file);
4505
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4506
fputs(" ON UPDATE SET NULL", file);
4509
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4510
fputs(" ON UPDATE NO ACTION", file);
4514
/**********************************************************************//**
4515
Outputs info on foreign keys of a table. */
4518
dict_print_info_on_foreign_keys(
4519
/*============================*/
4520
ibool create_table_format, /*!< in: if TRUE then print in
4521
a format suitable to be inserted into
4522
a CREATE TABLE, otherwise in the format
4523
of SHOW TABLE STATUS */
4524
FILE* file, /*!< in: file where to print */
4525
trx_t* trx, /*!< in: transaction */
4526
dict_table_t* table) /*!< in: table */
4528
dict_foreign_t* foreign;
4530
mutex_enter(&(dict_sys->mutex));
4532
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4534
if (foreign == NULL) {
4535
mutex_exit(&(dict_sys->mutex));
4540
while (foreign != NULL) {
4541
if (create_table_format) {
4542
dict_print_info_on_foreign_key_in_create_format(
4543
file, trx, foreign, TRUE);
4548
for (i = 0; i < foreign->n_fields; i++) {
4553
ut_print_name(file, trx, FALSE,
4554
foreign->foreign_col_names[i]);
4557
fputs(") REFER ", file);
4558
ut_print_name(file, trx, TRUE,
4559
foreign->referenced_table_name);
4562
for (i = 0; i < foreign->n_fields; i++) {
4568
foreign->referenced_col_names[i]);
4573
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4574
fputs(" ON DELETE CASCADE", file);
4577
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4578
fputs(" ON DELETE SET NULL", file);
4581
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4582
fputs(" ON DELETE NO ACTION", file);
4585
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4586
fputs(" ON UPDATE CASCADE", file);
4589
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4590
fputs(" ON UPDATE SET NULL", file);
4593
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4594
fputs(" ON UPDATE NO ACTION", file);
4598
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4601
mutex_exit(&(dict_sys->mutex));
4604
/********************************************************************//**
4605
Displays the names of the index and the table. */
4608
dict_index_name_print(
4609
/*==================*/
4610
FILE* file, /*!< in: output stream */
4611
trx_t* trx, /*!< in: transaction */
4612
const dict_index_t* index) /*!< in: index to print */
4614
fputs("index ", file);
4615
ut_print_name(file, trx, FALSE, index->name);
4616
fputs(" of table ", file);
4617
ut_print_name(file, trx, TRUE, index->table_name);
4619
#endif /* !UNIV_HOTBACKUP */
4621
/**********************************************************************//**
4622
Inits dict_ind_redundant and dict_ind_compact. */
4628
dict_table_t* table;
4630
/* create dummy table and index for REDUNDANT infimum and supremum */
4631
table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
4632
dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
4633
DATA_ENGLISH | DATA_NOT_NULL, 8);
4635
dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
4636
DICT_HDR_SPACE, 0, 1);
4637
dict_index_add_col(dict_ind_redundant, table,
4638
dict_table_get_nth_col(table, 0), 0);
4639
dict_ind_redundant->table = table;
4640
/* create dummy table and index for COMPACT infimum and supremum */
4641
table = dict_mem_table_create("SYS_DUMMY2",
4642
DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
4643
dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
4644
DATA_ENGLISH | DATA_NOT_NULL, 8);
4645
dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
4646
DICT_HDR_SPACE, 0, 1);
4647
dict_index_add_col(dict_ind_compact, table,
4648
dict_table_get_nth_col(table, 0), 0);
4649
dict_ind_compact->table = table;
4651
/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
4652
dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
4655
/**********************************************************************//**
4656
Frees dict_ind_redundant and dict_ind_compact. */
4662
dict_table_t* table;
4664
table = dict_ind_compact->table;
4665
dict_mem_index_free(dict_ind_compact);
4666
dict_ind_compact = NULL;
4667
dict_mem_table_free(table);
4669
table = dict_ind_redundant->table;
4670
dict_mem_index_free(dict_ind_redundant);
4671
dict_ind_redundant = NULL;
4672
dict_mem_table_free(table);
4675
#ifndef UNIV_HOTBACKUP
4676
/**********************************************************************//**
4678
@return index, NULL if does not exist */
4681
dict_table_get_index_on_name(
4682
/*=========================*/
4683
dict_table_t* table, /*!< in: table */
4684
const char* name) /*!< in: name of the index to find */
4686
dict_index_t* index;
4688
index = dict_table_get_first_index(table);
4690
while (index != NULL) {
4691
if (ut_strcmp(index->name, name) == 0) {
4696
index = dict_table_get_next_index(index);
4703
/**********************************************************************//**
4704
Replace the index passed in with another equivalent index in the tables
4705
foreign key list. */
4708
dict_table_replace_index_in_foreign_list(
4709
/*=====================================*/
4710
dict_table_t* table, /*!< in/out: table */
4711
dict_index_t* index) /*!< in: index to be replaced */
4713
dict_foreign_t* foreign;
4715
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
4717
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
4719
if (foreign->foreign_index == index) {
4720
dict_index_t* new_index
4721
= dict_foreign_find_equiv_index(foreign);
4724
foreign->foreign_index = new_index;
4729
/**********************************************************************//**
4730
In case there is more than one index with the same name return the index
4732
@return index, NULL if does not exist */
4735
dict_table_get_index_on_name_and_min_id(
4736
/*=====================================*/
4737
dict_table_t* table, /*!< in: table */
4738
const char* name) /*!< in: name of the index to find */
4740
dict_index_t* index;
4741
dict_index_t* min_index; /* Index with matching name and min(id) */
4744
index = dict_table_get_first_index(table);
4746
while (index != NULL) {
4747
if (ut_strcmp(index->name, name) == 0) {
4749
|| ut_dulint_cmp(index->id, min_index->id) < 0) {
4755
index = dict_table_get_next_index(index);
4763
/**********************************************************************//**
4764
Check for duplicate index entries in a table [using the index name] */
4767
dict_table_check_for_dup_indexes(
4768
/*=============================*/
4769
const dict_table_t* table) /*!< in: Check for dup indexes
4772
/* Check for duplicates, ignoring indexes that are marked
4775
const dict_index_t* index1;
4776
const dict_index_t* index2;
4778
/* The primary index _must_ exist */
4779
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
4781
index1 = UT_LIST_GET_FIRST(table->indexes);
4782
index2 = UT_LIST_GET_NEXT(indexes, index1);
4784
while (index1 && index2) {
4788
if (!index2->to_be_dropped) {
4789
ut_ad(ut_strcmp(index1->name, index2->name));
4792
index2 = UT_LIST_GET_NEXT(indexes, index2);
4795
index1 = UT_LIST_GET_NEXT(indexes, index1);
4796
index2 = UT_LIST_GET_NEXT(indexes, index1);
4799
#endif /* UNIV_DEBUG */
4801
/**************************************************************************
4802
Closes the data dictionary module. */
4810
/* Free the hash elements. We don't remove them from the table
4811
because we are going to destroy the table anyway. */
4812
for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
4813
dict_table_t* table;
4815
table = HASH_GET_FIRST(dict_sys->table_hash, i);
4818
dict_table_t* prev_table = table;
4820
table = HASH_GET_NEXT(name_hash, prev_table);
4822
ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
4824
/* Acquire only because it's a pre-condition. */
4825
mutex_enter(&dict_sys->mutex);
4827
dict_table_remove_from_cache(prev_table);
4829
mutex_exit(&dict_sys->mutex);
4833
hash_table_free(dict_sys->table_hash);
4835
/* The elements are the same instance as in dict_sys->table_hash,
4836
therefore we don't delete the individual elements. */
4837
hash_table_free(dict_sys->table_id_hash);
4841
mutex_free(&dict_sys->mutex);
4843
rw_lock_free(&dict_operation_lock);
4844
memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
4846
mutex_free(&dict_foreign_err_mutex);
4851
#endif /* !UNIV_HOTBACKUP */