1
/**********************************************************************
6
Created 1/8/1996 Heikki Tuuri
7
***********************************************************************/
12
#include "dict0dict.ic"
16
#include "data0type.h"
17
#include "mach0data.h"
18
#include "dict0boot.h"
20
#include "dict0crea.h"
25
#include "pars0pars.h"
29
#include "row0merge.h"
30
#ifndef UNIV_HOTBACKUP
31
# if defined(BUILD_DRIZZLE)
32
# include <mystrings/m_ctype.h>
34
# include "m_ctype.h" /* my_isspace() */
36
# include "ha_prototypes.h" /* innobase_strcasecmp() */
37
#endif /* !UNIV_HOTBACKUP */
41
/* the dictionary system */
42
UNIV_INTERN dict_sys_t* dict_sys = NULL;
44
/* table create, drop, etc. reserve this in X-mode; implicit or
45
backround operations purge, rollback, foreign key checks reserve this
46
in S-mode; we cannot trust that MySQL protects implicit or background
47
operations a table drop since MySQL does not know of them; therefore
48
we need this; NOTE: a transaction which reserves this must keep book
49
on the mode in trx->dict_operation_lock_mode */
50
UNIV_INTERN rw_lock_t dict_operation_lock;
52
#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
53
hash table fixed size in bytes */
55
/* Identifies generated InnoDB foreign key names */
56
static char dict_ibfk[] = "_ibfk_";
58
#ifndef UNIV_HOTBACKUP
59
/**********************************************************************
60
Converts an identifier to a table name.
62
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
63
this function, you MUST change also the prototype here! */
66
innobase_convert_from_table_id(
67
/*===========================*/
68
char* to, /* out: converted identifier */
69
const char* from, /* in: identifier to convert */
70
ulint len); /* in: length of 'to', in bytes;
71
should be at least 5 * strlen(to) + 1 */
72
/**********************************************************************
73
Converts an identifier to UTF-8.
75
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
76
this function, you MUST change also the prototype here! */
79
innobase_convert_from_id(
80
/*=====================*/
81
char* to, /* out: converted identifier */
82
const char* from, /* in: identifier to convert */
83
ulint len); /* in: length of 'to', in bytes;
84
should be at least 3 * strlen(to) + 1 */
85
/**********************************************************************
86
Makes all characters in a NUL-terminated UTF-8 string lower case.
88
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
89
this function, you MUST change also the prototype here! */
94
char* a); /* in/out: string to put in lower case */
96
/**************************************************************************
97
Determines the connection character set.
99
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
100
this function, you MUST change also the prototype here! */
101
struct charset_info_st*
102
innobase_get_charset(
103
/*=================*/
104
/* out: connection character set */
105
void* mysql_thd); /* in: MySQL thread handle */
106
#endif /* !UNIV_HOTBACKUP */
108
/***********************************************************************
109
Tries to find column names for the index and sets the col field of the
113
dict_index_find_cols(
114
/*=================*/
115
dict_table_t* table, /* in: table */
116
dict_index_t* index); /* in: index */
117
/***********************************************************************
118
Builds the internal dictionary cache representation for a clustered
119
index, containing also system fields not defined by the user. */
122
dict_index_build_internal_clust(
123
/*============================*/
124
/* out, own: the internal
125
representation of the clustered
127
const dict_table_t* table, /* in: table */
128
dict_index_t* index); /* in: user representation of
130
/***********************************************************************
131
Builds the internal dictionary cache representation for a non-clustered
132
index, containing also system fields not defined by the user. */
135
dict_index_build_internal_non_clust(
136
/*================================*/
137
/* out, own: the internal
138
representation of the non-clustered
140
const dict_table_t* table, /* in: table */
141
dict_index_t* index); /* in: user representation of
142
a non-clustered index */
143
/**************************************************************************
144
Removes a foreign constraint struct from the dictionary cache. */
147
dict_foreign_remove_from_cache(
148
/*===========================*/
149
dict_foreign_t* foreign); /* in, own: foreign constraint */
150
/**************************************************************************
151
Prints a column data. */
156
const dict_table_t* table, /* in: table */
157
const dict_col_t* col); /* in: column */
158
/**************************************************************************
159
Prints an index data. */
162
dict_index_print_low(
163
/*=================*/
164
dict_index_t* index); /* in: index */
165
/**************************************************************************
166
Prints a field data. */
169
dict_field_print_low(
170
/*=================*/
171
dict_field_t* field); /* in: field */
172
/*************************************************************************
173
Frees a foreign key struct. */
178
dict_foreign_t* foreign); /* in, own: foreign key struct */
180
/* Stream for storing detailed information about the latest foreign key
181
and unique key errors */
182
UNIV_INTERN FILE* dict_foreign_err_file = NULL;
183
/* mutex protecting the foreign and unique error buffers */
184
UNIV_INTERN mutex_t dict_foreign_err_mutex;
186
#ifndef UNIV_HOTBACKUP
187
/**********************************************************************
188
Makes all characters in a NUL-terminated UTF-8 string lower case. */
193
char* a) /* in/out: string to put in lower case */
195
innobase_casedn_str(a);
197
#endif /* !UNIV_HOTBACKUP */
199
/************************************************************************
200
Checks if the database name in two table names is the same. */
203
dict_tables_have_same_db(
204
/*=====================*/
205
/* out: TRUE if same db name */
206
const char* name1, /* in: table name in the form
207
dbname '/' tablename */
208
const char* name2) /* in: table name in the form
209
dbname '/' tablename */
211
for (; *name1 == *name2; name1++, name2++) {
215
ut_a(*name1); /* the names must contain '/' */
220
/************************************************************************
221
Return the end of table name where we have removed dbname and '/'. */
226
/* out: table name */
227
const char* name) /* in: table name in the form
228
dbname '/' tablename */
230
const char* s = strchr(name, '/');
236
/************************************************************************
237
Get the database name length in a table name. */
240
dict_get_db_name_len(
241
/*=================*/
242
/* out: database name length */
243
const char* name) /* in: table name in the form
244
dbname '/' tablename */
247
s = strchr(name, '/');
252
/************************************************************************
253
Reserves the dictionary system mutex for MySQL. */
256
dict_mutex_enter_for_mysql(void)
257
/*============================*/
259
mutex_enter(&(dict_sys->mutex));
262
/************************************************************************
263
Releases the dictionary system mutex for MySQL. */
266
dict_mutex_exit_for_mysql(void)
267
/*===========================*/
269
mutex_exit(&(dict_sys->mutex));
272
/************************************************************************
273
Decrements the count of open MySQL handles to a table. */
276
dict_table_decrement_handle_count(
277
/*==============================*/
278
dict_table_t* table, /* in/out: table */
279
ibool dict_locked) /* in: TRUE=data dictionary locked */
282
mutex_enter(&dict_sys->mutex);
285
ut_ad(mutex_own(&dict_sys->mutex));
286
ut_a(table->n_mysql_handles_opened > 0);
288
table->n_mysql_handles_opened--;
291
mutex_exit(&dict_sys->mutex);
295
/**************************************************************************
296
Returns a column's name. */
299
dict_table_get_col_name(
300
/*====================*/
301
/* out: column name. NOTE: not
302
guaranteed to stay valid if table is
303
modified in any way (columns added,
305
const dict_table_t* table, /* in: table */
306
ulint col_nr) /* in: column number */
312
ut_ad(col_nr < table->n_def);
313
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
315
s = table->col_names;
317
for (i = 0; i < col_nr; i++) {
326
/************************************************************************
327
Acquire the autoinc lock.*/
330
dict_table_autoinc_lock(
331
/*====================*/
332
dict_table_t* table) /* in/out: table */
334
mutex_enter(&table->autoinc_mutex);
337
/************************************************************************
338
Initializes the autoinc counter. It is not an error to initialize an already
339
initialized counter. */
342
dict_table_autoinc_initialize(
343
/*==========================*/
344
dict_table_t* table, /* in/out: table */
345
ib_uint64_t value) /* in: next value to assign to a row */
347
ut_ad(mutex_own(&table->autoinc_mutex));
349
table->autoinc_inited = TRUE;
350
table->autoinc = value;
353
/************************************************************************
354
Reads the next autoinc value (== autoinc counter value), 0 if not yet
358
dict_table_autoinc_read(
359
/*====================*/
360
/* out: value for a new row, or 0 */
361
const dict_table_t* table) /* in: table */
365
ut_ad(mutex_own(&table->autoinc_mutex));
367
if (!table->autoinc_inited) {
371
value = table->autoinc;
377
/************************************************************************
378
Updates the autoinc counter if the value supplied is greater than the
379
current value. If not inited, does nothing. */
382
dict_table_autoinc_update(
383
/*======================*/
385
dict_table_t* table, /* in/out: table */
386
ib_uint64_t value) /* in: value which was assigned to a row */
388
if (table->autoinc_inited && value > table->autoinc) {
390
table->autoinc = value;
394
/************************************************************************
395
Release the autoinc lock.*/
398
dict_table_autoinc_unlock(
399
/*======================*/
400
dict_table_t* table) /* in/out: table */
402
mutex_exit(&table->autoinc_mutex);
405
/**************************************************************************
406
Looks for an index with the given table and index id.
407
NOTE that we do not reserve the dictionary mutex. */
410
dict_index_get_on_id_low(
411
/*=====================*/
412
/* out: index or NULL if not found
414
dict_table_t* table, /* in: table */
415
dulint id) /* in: index id */
419
index = dict_table_get_first_index(table);
422
if (0 == ut_dulint_cmp(id, index->id)) {
428
index = dict_table_get_next_index(index);
434
/************************************************************************
435
Looks for column n in an index. */
438
dict_index_get_nth_col_pos(
439
/*=======================*/
440
/* out: position in internal
441
representation of the index;
442
if not contained, returns
444
const dict_index_t* index, /* in: index */
445
ulint n) /* in: column number */
447
const dict_field_t* field;
448
const dict_col_t* col;
453
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
455
col = dict_table_get_nth_col(index->table, n);
457
if (dict_index_is_clust(index)) {
459
return(dict_col_get_clust_pos(col, index));
462
n_fields = dict_index_get_n_fields(index);
464
for (pos = 0; pos < n_fields; pos++) {
465
field = dict_index_get_nth_field(index, pos);
467
if (col == field->col && field->prefix_len == 0) {
473
return(ULINT_UNDEFINED);
476
/************************************************************************
477
Returns TRUE if the index contains a column or a prefix of that column. */
480
dict_index_contains_col_or_prefix(
481
/*==============================*/
482
/* out: TRUE if contains the column
484
const dict_index_t* index, /* in: index */
485
ulint n) /* in: column number */
487
const dict_field_t* field;
488
const dict_col_t* col;
493
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
495
if (dict_index_is_clust(index)) {
500
col = dict_table_get_nth_col(index->table, n);
502
n_fields = dict_index_get_n_fields(index);
504
for (pos = 0; pos < n_fields; pos++) {
505
field = dict_index_get_nth_field(index, pos);
507
if (col == field->col) {
516
/************************************************************************
517
Looks for a matching field in an index. The column has to be the same. The
518
column in index must be complete, or must contain a prefix longer than the
519
column in index2. That is, we must be able to construct the prefix in index2
520
from the prefix in index. */
523
dict_index_get_nth_field_pos(
524
/*=========================*/
525
/* out: position in internal
526
representation of the index;
527
if not contained, returns
529
const dict_index_t* index, /* in: index from which to search */
530
const dict_index_t* index2, /* in: index */
531
ulint n) /* in: field number in index2 */
533
const dict_field_t* field;
534
const dict_field_t* field2;
539
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
541
field2 = dict_index_get_nth_field(index2, n);
543
n_fields = dict_index_get_n_fields(index);
545
for (pos = 0; pos < n_fields; pos++) {
546
field = dict_index_get_nth_field(index, pos);
548
if (field->col == field2->col
549
&& (field->prefix_len == 0
550
|| (field->prefix_len >= field2->prefix_len
551
&& field2->prefix_len != 0))) {
557
return(ULINT_UNDEFINED);
560
/**************************************************************************
561
Returns a table object based on table id. */
564
dict_table_get_on_id(
565
/*=================*/
566
/* out: table, NULL if does not exist */
567
dulint table_id, /* in: table id */
568
trx_t* trx) /* in: transaction handle */
572
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
573
|| trx->dict_operation_lock_mode == RW_X_LATCH) {
574
/* It is a system table which will always exist in the table
575
cache: we avoid acquiring the dictionary mutex, because
576
if we are doing a rollback to handle an error in TABLE
577
CREATE, for example, we already have the mutex! */
579
ut_ad(mutex_own(&(dict_sys->mutex))
580
|| trx->dict_operation_lock_mode == RW_X_LATCH);
582
return(dict_table_get_on_id_low(table_id));
585
mutex_enter(&(dict_sys->mutex));
587
table = dict_table_get_on_id_low(table_id);
589
mutex_exit(&(dict_sys->mutex));
594
/************************************************************************
595
Looks for column n position in the clustered index. */
598
dict_table_get_nth_col_pos(
599
/*=======================*/
600
/* out: position in internal
602
the clustered index */
603
const dict_table_t* table, /* in: table */
604
ulint n) /* in: column number */
606
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
610
/************************************************************************
611
Checks if a column is in the ordering columns of the clustered index of a
612
table. Column prefixes are treated like whole columns. */
615
dict_table_col_in_clustered_key(
616
/*============================*/
617
/* out: TRUE if the column, or its
618
prefix, is in the clustered key */
619
const dict_table_t* table, /* in: table */
620
ulint n) /* in: column number */
622
const dict_index_t* index;
623
const dict_field_t* field;
624
const dict_col_t* col;
630
col = dict_table_get_nth_col(table, n);
632
index = dict_table_get_first_index(table);
634
n_fields = dict_index_get_n_unique(index);
636
for (pos = 0; pos < n_fields; pos++) {
637
field = dict_index_get_nth_field(index, pos);
639
if (col == field->col) {
648
/**************************************************************************
649
Inits the data dictionary module. */
655
dict_sys = mem_alloc(sizeof(dict_sys_t));
657
mutex_create(&dict_sys->mutex, SYNC_DICT);
659
dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
660
/ (DICT_POOL_PER_TABLE_HASH
662
dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
663
/ (DICT_POOL_PER_TABLE_HASH
667
UT_LIST_INIT(dict_sys->table_LRU);
669
rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
671
dict_foreign_err_file = os_file_create_tmpfile();
672
ut_a(dict_foreign_err_file);
674
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
677
/**************************************************************************
678
Returns a table object and optionally increment its MySQL open handle count.
679
NOTE! This is a high-level function to be used mainly from outside the
680
'dict' directory. Inside this directory dict_table_get_low is usually the
681
appropriate function. */
686
/* out: table, NULL if
688
const char* table_name, /* in: table name */
689
ibool inc_mysql_count)
690
/* in: whether to increment the open
691
handle count on the table */
695
mutex_enter(&(dict_sys->mutex));
697
table = dict_table_get_low(table_name);
699
if (inc_mysql_count && table) {
700
table->n_mysql_handles_opened++;
703
mutex_exit(&(dict_sys->mutex));
706
if (!table->stat_initialized) {
707
/* If table->ibd_file_missing == TRUE, this will
708
print an error message and return without doing
710
dict_update_statistics(table);
717
/**************************************************************************
718
Adds system columns to a table object. */
721
dict_table_add_system_columns(
722
/*==========================*/
723
dict_table_t* table, /* in/out: table */
724
mem_heap_t* heap) /* in: temporary heap */
727
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
728
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
729
ut_ad(!table->cached);
731
/* NOTE: the system columns MUST be added in the following order
732
(so that they can be indexed by the numerical value of DATA_ROW_ID,
733
etc.) and as the last columns of the table memory object.
734
The clustered index will not always physically contain all
737
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
738
DATA_ROW_ID | DATA_NOT_NULL,
741
#error "DATA_ROW_ID != 0"
743
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
744
DATA_TRX_ID | DATA_NOT_NULL,
747
#error "DATA_TRX_ID != 1"
749
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
750
DATA_ROLL_PTR | DATA_NOT_NULL,
752
#if DATA_ROLL_PTR != 2
753
#error "DATA_ROLL_PTR != 2"
756
/* This check reminds that if a new system column is added to
757
the program, it should be dealt with here */
758
#if DATA_N_SYS_COLS != 3
759
#error "DATA_N_SYS_COLS != 3"
763
/**************************************************************************
764
Adds a table object to the dictionary cache. */
767
dict_table_add_to_cache(
768
/*====================*/
769
dict_table_t* table, /* in: table */
770
mem_heap_t* heap) /* in: temporary heap */
777
/* The lower limit for what we consider a "big" row */
778
#define BIG_ROW_SIZE 1024
780
ut_ad(mutex_own(&(dict_sys->mutex)));
782
dict_table_add_system_columns(table, heap);
784
table->cached = TRUE;
786
fold = ut_fold_string(table->name);
787
id_fold = ut_fold_dulint(table->id);
790
for (i = 0; i < table->n_def; i++) {
791
ulint col_len = dict_col_get_max_size(
792
dict_table_get_nth_col(table, i));
796
/* If we have a single unbounded field, or several gigantic
797
fields, mark the maximum row size as BIG_ROW_SIZE. */
798
if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
799
row_len = BIG_ROW_SIZE;
805
table->big_rows = row_len >= BIG_ROW_SIZE;
807
/* Look for a table with the same name: error if such exists */
809
dict_table_t* table2;
810
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
811
dict_table_t*, table2,
812
(ut_strcmp(table2->name, table->name) == 0));
813
ut_a(table2 == NULL);
816
/* Look for a table with the same id: error if such exists */
818
dict_table_t* table2;
819
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
820
dict_table_t*, table2,
821
(ut_dulint_cmp(table2->id, table->id) == 0));
822
ut_a(table2 == NULL);
825
/* Add table to hash table of tables */
826
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
829
/* Add table to hash table of tables based on table id */
830
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
832
/* Add table to LRU list of tables */
833
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
835
dict_sys->size += mem_heap_get_size(table->heap);
838
/**************************************************************************
839
Looks for an index with the given id. NOTE that we do not reserve
840
the dictionary mutex: this function is for emergency purposes like
841
printing info of a corrupt database page! */
844
dict_index_find_on_id_low(
845
/*======================*/
846
/* out: index or NULL if not found from cache */
847
dulint id) /* in: index id */
852
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
855
index = dict_table_get_first_index(table);
858
if (0 == ut_dulint_cmp(id, index->id)) {
864
index = dict_table_get_next_index(index);
867
table = UT_LIST_GET_NEXT(table_LRU, table);
873
/**************************************************************************
874
Renames a table object. */
877
dict_table_rename_in_cache(
878
/*=======================*/
879
/* out: TRUE if success */
880
dict_table_t* table, /* in/out: table */
881
const char* new_name, /* in: new name */
882
ibool rename_also_foreigns)/* in: in ALTER TABLE we want
883
to preserve the original table name
884
in constraints which reference it */
886
dict_foreign_t* foreign;
890
const char* old_name;
893
ut_ad(mutex_own(&(dict_sys->mutex)));
895
old_size = mem_heap_get_size(table->heap);
896
old_name = table->name;
898
fold = ut_fold_string(new_name);
900
/* Look for a table with the same name: error if such exists */
902
dict_table_t* table2;
903
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
904
dict_table_t*, table2,
905
(ut_strcmp(table2->name, new_name) == 0));
906
if (UNIV_LIKELY_NULL(table2)) {
907
ut_print_timestamp(stderr);
908
fputs(" InnoDB: Error: dictionary cache"
909
" already contains a table ", stderr);
910
ut_print_name(stderr, NULL, TRUE, new_name);
912
"InnoDB: cannot rename table ", stderr);
913
ut_print_name(stderr, NULL, TRUE, old_name);
919
/* If the table is stored in a single-table tablespace, rename the
922
if (table->space != 0) {
923
if (table->dir_path_of_temp_table != NULL) {
924
ut_print_timestamp(stderr);
925
fputs(" InnoDB: Error: trying to rename a"
926
" TEMPORARY TABLE ", stderr);
927
ut_print_name(stderr, NULL, TRUE, old_name);
929
ut_print_filename(stderr,
930
table->dir_path_of_temp_table);
931
fputs(" )\n", stderr);
933
} else if (!fil_rename_tablespace(old_name, table->space,
939
/* Remove table from the hash tables of tables */
940
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
941
ut_fold_string(old_name), table);
942
table->name = mem_heap_strdup(table->heap, new_name);
944
/* Add table to hash table of tables */
945
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
947
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
949
/* Update the table_name field in indexes */
950
index = dict_table_get_first_index(table);
952
while (index != NULL) {
953
index->table_name = table->name;
955
index = dict_table_get_next_index(index);
958
if (!rename_also_foreigns) {
959
/* In ALTER TABLE we think of the rename table operation
960
in the direction table -> temporary table (#sql...)
961
as dropping the table with the old name and creating
962
a new with the new name. Thus we kind of drop the
963
constraints from the dictionary cache here. The foreign key
964
constraints will be inherited to the new table from the
965
system tables through a call of dict_load_foreigns. */
967
/* Remove the foreign constraints from the cache */
968
foreign = UT_LIST_GET_LAST(table->foreign_list);
970
while (foreign != NULL) {
971
dict_foreign_remove_from_cache(foreign);
972
foreign = UT_LIST_GET_LAST(table->foreign_list);
975
/* Reset table field in referencing constraints */
977
foreign = UT_LIST_GET_FIRST(table->referenced_list);
979
while (foreign != NULL) {
980
foreign->referenced_table = NULL;
981
foreign->referenced_index = NULL;
983
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
986
/* Make the list of referencing constraints empty */
988
UT_LIST_INIT(table->referenced_list);
993
/* Update the table name fields in foreign constraints, and update also
994
the constraint id of new format >= 4.0.18 constraints. Note that at
995
this point we have already changed table->name to the new name. */
997
foreign = UT_LIST_GET_FIRST(table->foreign_list);
999
while (foreign != NULL) {
1000
if (ut_strlen(foreign->foreign_table_name)
1001
< ut_strlen(table->name)) {
1002
/* Allocate a longer name buffer;
1003
TODO: store buf len to save memory */
1005
foreign->foreign_table_name
1006
= mem_heap_alloc(foreign->heap,
1007
ut_strlen(table->name) + 1);
1010
strcpy(foreign->foreign_table_name, table->name);
1012
if (strchr(foreign->id, '/')) {
1016
/* This is a >= 4.0.18 format id */
1018
old_id = mem_strdup(foreign->id);
1020
if (ut_strlen(foreign->id) > ut_strlen(old_name)
1021
+ ((sizeof dict_ibfk) - 1)
1022
&& !memcmp(foreign->id, old_name,
1023
ut_strlen(old_name))
1024
&& !memcmp(foreign->id + ut_strlen(old_name),
1025
dict_ibfk, (sizeof dict_ibfk) - 1)) {
1027
/* This is a generated >= 4.0.18 format id */
1029
if (strlen(table->name) > strlen(old_name)) {
1030
foreign->id = mem_heap_alloc(
1033
+ strlen(old_id) + 1);
1036
/* Replace the prefix 'databasename/tablename'
1037
with the new names */
1038
strcpy(foreign->id, table->name);
1040
old_id + ut_strlen(old_name));
1042
/* This is a >= 4.0.18 format id where the user
1044
db_len = dict_get_db_name_len(table->name) + 1;
1046
if (dict_get_db_name_len(table->name)
1047
> dict_get_db_name_len(foreign->id)) {
1049
foreign->id = mem_heap_alloc(
1051
db_len + strlen(old_id) + 1);
1054
/* Replace the database prefix in id with the
1055
one from table->name */
1057
ut_memcpy(foreign->id, table->name, db_len);
1059
strcpy(foreign->id + db_len,
1060
dict_remove_db_name(old_id));
1066
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1069
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1071
while (foreign != NULL) {
1072
if (ut_strlen(foreign->referenced_table_name)
1073
< ut_strlen(table->name)) {
1074
/* Allocate a longer name buffer;
1075
TODO: store buf len to save memory */
1077
foreign->referenced_table_name = mem_heap_alloc(
1078
foreign->heap, strlen(table->name) + 1);
1081
strcpy(foreign->referenced_table_name, table->name);
1083
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1089
/**************************************************************************
1090
Change the id of a table object in the dictionary cache. This is used in
1091
DISCARD TABLESPACE. */
1094
dict_table_change_id_in_cache(
1095
/*==========================*/
1096
dict_table_t* table, /* in/out: table object already in cache */
1097
dulint new_id) /* in: new id to set */
1100
ut_ad(mutex_own(&(dict_sys->mutex)));
1101
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1103
/* Remove the table from the hash table of id's */
1105
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1106
ut_fold_dulint(table->id), table);
1109
/* Add the table back to the hash table */
1110
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1111
ut_fold_dulint(table->id), table);
1114
/**************************************************************************
1115
Removes a table object from the dictionary cache. */
1118
dict_table_remove_from_cache(
1119
/*=========================*/
1120
dict_table_t* table) /* in, own: table */
1122
dict_foreign_t* foreign;
1123
dict_index_t* index;
1127
ut_ad(mutex_own(&(dict_sys->mutex)));
1128
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1131
fputs("Removing table ", stderr);
1132
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1133
fputs(" from dictionary cache\n", stderr);
1136
/* Remove the foreign constraints from the cache */
1137
foreign = UT_LIST_GET_LAST(table->foreign_list);
1139
while (foreign != NULL) {
1140
dict_foreign_remove_from_cache(foreign);
1141
foreign = UT_LIST_GET_LAST(table->foreign_list);
1144
/* Reset table field in referencing constraints */
1146
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1148
while (foreign != NULL) {
1149
foreign->referenced_table = NULL;
1150
foreign->referenced_index = NULL;
1152
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1155
/* Remove the indexes from the cache */
1156
index = UT_LIST_GET_LAST(table->indexes);
1158
while (index != NULL) {
1159
dict_index_remove_from_cache(table, index);
1160
index = UT_LIST_GET_LAST(table->indexes);
1163
/* Remove table from the hash tables of tables */
1164
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1165
ut_fold_string(table->name), table);
1166
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1167
ut_fold_dulint(table->id), table);
1169
/* Remove table from LRU list of tables */
1170
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1172
size = mem_heap_get_size(table->heap);
1174
ut_ad(dict_sys->size >= size);
1176
dict_sys->size -= size;
1178
dict_mem_table_free(table);
1181
/********************************************************************
1182
If the given column name is reserved for InnoDB system columns, return
1186
dict_col_name_is_reserved(
1187
/*======================*/
1188
/* out: TRUE if name is reserved */
1189
const char* name) /* in: column name */
1191
/* This check reminds that if a new system column is added to
1192
the program, it should be dealt with here. */
1193
#if DATA_N_SYS_COLS != 3
1194
#error "DATA_N_SYS_COLS != 3"
1197
static const char* reserved_names[] = {
1198
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1203
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1204
if (strcmp(name, reserved_names[i]) == 0) {
1213
/********************************************************************
1214
If an undo log record for this table might not fit on a single page,
1218
dict_index_too_big_for_undo(
1219
/*========================*/
1220
/* out: TRUE if the undo log
1221
record could become too big */
1222
const dict_table_t* table, /* in: table */
1223
const dict_index_t* new_index) /* in: index */
1225
/* Make sure that all column prefixes will fit in the undo log record
1226
in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1229
const dict_index_t* clust_index
1230
= dict_table_get_first_index(table);
1232
= TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
1233
+ 2 /* next record pointer */
1235
+ 11 /* trx->undo_no */ - 11 /* table->id */
1236
+ 1 /* rec_get_info_bits() */
1237
+ 11 /* DB_TRX_ID */
1238
+ 11 /* DB_ROLL_PTR */
1239
+ 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
1240
+ 2/* pointer to previous undo log record */;
1242
if (UNIV_UNLIKELY(!clust_index)) {
1243
ut_a(dict_index_is_clust(new_index));
1244
clust_index = new_index;
1247
/* Add the size of the ordering columns in the
1249
for (i = 0; i < clust_index->n_uniq; i++) {
1250
const dict_col_t* col
1251
= dict_index_get_nth_col(clust_index, i);
1253
/* Use the maximum output size of
1254
mach_write_compressed(), although the encoded
1255
length should always fit in 2 bytes. */
1256
undo_page_len += 5 + dict_col_get_max_size(col);
1259
/* Add the old values of the columns to be updated.
1260
First, the amount and the numbers of the columns.
1261
These are written by mach_write_compressed() whose
1262
maximum output length is 5 bytes. However, given that
1263
the quantities are below REC_MAX_N_FIELDS (10 bits),
1264
the maximum length is 2 bytes per item. */
1265
undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
1267
for (i = 0; i < clust_index->n_def; i++) {
1268
const dict_col_t* col
1269
= dict_index_get_nth_col(clust_index, i);
1271
= dict_col_get_max_size(col);
1273
= dict_col_get_fixed_size(col);
1276
/* Fixed-size columns are stored locally. */
1277
max_size = fixed_size;
1278
} else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
1279
/* Short columns are stored locally. */
1280
} else if (!col->ord_part) {
1281
/* See if col->ord_part would be set
1282
because of new_index. */
1285
for (j = 0; j < new_index->n_uniq; j++) {
1286
if (dict_index_get_nth_col(
1287
new_index, j) == col) {
1293
/* This is not an ordering column in any index.
1294
Thus, it can be stored completely externally. */
1295
max_size = BTR_EXTERN_FIELD_REF_SIZE;
1298
/* This is an ordering column in some index.
1299
A long enough prefix must be written to the
1300
undo log. See trx_undo_page_fetch_ext(). */
1302
if (max_size > REC_MAX_INDEX_COL_LEN) {
1303
max_size = REC_MAX_INDEX_COL_LEN;
1306
max_size += BTR_EXTERN_FIELD_REF_SIZE;
1309
undo_page_len += 5 + max_size;
1312
return(undo_page_len >= UNIV_PAGE_SIZE);
1315
/**************************************************************************
1316
Adds an index to the dictionary cache. */
1319
dict_index_add_to_cache(
1320
/*====================*/
1321
/* out: DB_SUCCESS or DB_TOO_BIG_RECORD */
1322
dict_table_t* table, /* in: table on which the index is */
1323
dict_index_t* index, /* in, own: index; NOTE! The index memory
1324
object is freed in this function! */
1325
ulint page_no)/* in: root page number of the index */
1327
dict_index_t* new_index;
1332
ut_ad(mutex_own(&(dict_sys->mutex)));
1333
ut_ad(index->n_def == index->n_fields);
1334
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1336
ut_ad(mem_heap_validate(index->heap));
1337
ut_a(!dict_index_is_clust(index)
1338
|| UT_LIST_GET_LEN(table->indexes) == 0);
1340
dict_index_find_cols(table, index);
1342
/* Build the cache internal representation of the index,
1343
containing also the added system fields */
1345
if (dict_index_is_clust(index)) {
1346
new_index = dict_index_build_internal_clust(table, index);
1348
new_index = dict_index_build_internal_non_clust(table, index);
1351
/* Set the n_fields value in new_index to the actual defined
1352
number of fields in the cache internal representation */
1354
new_index->n_fields = new_index->n_def;
1356
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1357
n_ord = new_index->n_fields;
1359
n_ord = new_index->n_uniq;
1362
for (i = 0; i < n_ord; i++) {
1363
const dict_field_t* field
1364
= dict_index_get_nth_field(new_index, i);
1365
const dict_col_t* col
1366
= dict_field_get_col(field);
1368
/* In dtuple_convert_big_rec(), variable-length columns
1369
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1370
may be chosen for external storage. If the column appears
1371
in an ordering column of an index, a longer prefix of
1372
REC_MAX_INDEX_COL_LEN will be copied to the undo log
1373
by trx_undo_page_report_modify() and
1374
trx_undo_page_fetch_ext(). It suffices to check the
1375
capacity of the undo log whenever new_index includes
1376
a column prefix on a column that may be stored externally. */
1378
if (field->prefix_len /* prefix index */
1379
&& !col->ord_part /* not yet ordering column */
1380
&& !dict_col_get_fixed_size(col) /* variable-length */
1381
&& dict_col_get_max_size(col)
1382
> BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
1384
if (dict_index_too_big_for_undo(table, new_index)) {
1385
/* An undo log record might not fit in
1386
a single page. Refuse to create this index. */
1387
dict_mem_index_free(new_index);
1388
dict_mem_index_free(index);
1389
return(DB_TOO_BIG_RECORD);
1396
/* Flag the ordering columns */
1398
for (i = 0; i < n_ord; i++) {
1400
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1403
/* Add the new index as the last index for the table */
1405
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1406
new_index->table = table;
1407
new_index->table_name = table->name;
1409
new_index->search_info = btr_search_info_create(new_index->heap);
1411
new_index->stat_index_size = 1;
1412
new_index->stat_n_leaf_pages = 1;
1414
new_index->page = page_no;
1415
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1417
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1419
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1421
(1 + dict_index_get_n_unique(new_index))
1422
* sizeof(ib_int64_t));
1423
/* Give some sensible values to stat_n_... in case we do
1424
not calculate statistics quickly enough */
1426
for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1428
new_index->stat_n_diff_key_vals[i] = 100;
1432
dict_sys->size += mem_heap_get_size(new_index->heap);
1434
dict_mem_index_free(index);
1439
/**************************************************************************
1440
Removes an index from the dictionary cache. */
1443
dict_index_remove_from_cache(
1444
/*=========================*/
1445
dict_table_t* table, /* in/out: table */
1446
dict_index_t* index) /* in, own: index */
1450
ut_ad(table && index);
1451
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1452
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1453
ut_ad(mutex_own(&(dict_sys->mutex)));
1455
rw_lock_free(&index->lock);
1457
/* Remove the index from the list of indexes of the table */
1458
UT_LIST_REMOVE(indexes, table->indexes, index);
1460
size = mem_heap_get_size(index->heap);
1462
ut_ad(dict_sys->size >= size);
1464
dict_sys->size -= size;
1466
dict_mem_index_free(index);
1469
/***********************************************************************
1470
Tries to find column names for the index and sets the col field of the
1474
dict_index_find_cols(
1475
/*=================*/
1476
dict_table_t* table, /* in: table */
1477
dict_index_t* index) /* in: index */
1481
ut_ad(table && index);
1482
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1483
ut_ad(mutex_own(&(dict_sys->mutex)));
1485
for (i = 0; i < index->n_fields; i++) {
1487
dict_field_t* field = dict_index_get_nth_field(index, i);
1489
for (j = 0; j < table->n_cols; j++) {
1490
if (!strcmp(dict_table_get_col_name(table, j),
1492
field->col = dict_table_get_nth_col(table, j);
1498
/* It is an error not to find a matching column. */
1506
/***********************************************************************
1507
Adds a column to index. */
1512
dict_index_t* index, /* in/out: index */
1513
const dict_table_t* table, /* in: table */
1514
dict_col_t* col, /* in: column */
1515
ulint prefix_len) /* in: column prefix length */
1517
dict_field_t* field;
1518
const char* col_name;
1520
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1522
dict_mem_index_add_field(index, col_name, prefix_len);
1524
field = dict_index_get_nth_field(index, index->n_def - 1);
1527
field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1529
if (prefix_len && field->fixed_len > prefix_len) {
1530
field->fixed_len = (unsigned int) prefix_len;
1533
/* Long fixed-length fields that need external storage are treated as
1534
variable-length fields, so that the extern flag can be embedded in
1537
if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1538
field->fixed_len = 0;
1540
#if DICT_MAX_INDEX_COL_LEN != 768
1541
/* The comparison limit above must be constant. If it were
1542
changed, the disk format of some fixed-length columns would
1543
change, which would be a disaster. */
1544
# error "DICT_MAX_INDEX_COL_LEN != 768"
1547
if (!(col->prtype & DATA_NOT_NULL)) {
1548
index->n_nullable++;
1552
/***********************************************************************
1553
Copies fields contained in index2 to index1. */
1558
dict_index_t* index1, /* in: index to copy to */
1559
dict_index_t* index2, /* in: index to copy from */
1560
const dict_table_t* table, /* in: table */
1561
ulint start, /* in: first position to copy */
1562
ulint end) /* in: last position to copy */
1564
dict_field_t* field;
1567
/* Copy fields contained in index2 */
1569
for (i = start; i < end; i++) {
1571
field = dict_index_get_nth_field(index2, i);
1572
dict_index_add_col(index1, table, field->col,
1577
/***********************************************************************
1578
Copies types of fields contained in index to tuple. */
1581
dict_index_copy_types(
1582
/*==================*/
1583
dtuple_t* tuple, /* in/out: data tuple */
1584
const dict_index_t* index, /* in: index */
1585
ulint n_fields) /* in: number of
1586
field types to copy */
1590
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1591
dtuple_set_types_binary(tuple, n_fields);
1596
for (i = 0; i < n_fields; i++) {
1597
const dict_field_t* ifield;
1598
dtype_t* dfield_type;
1600
ifield = dict_index_get_nth_field(index, i);
1601
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1602
dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1606
/***********************************************************************
1607
Copies types of columns contained in table to tuple and sets all
1608
fields of the tuple to the SQL NULL value. This function should
1609
be called right after dtuple_create(). */
1612
dict_table_copy_types(
1613
/*==================*/
1614
dtuple_t* tuple, /* in/out: data tuple */
1615
const dict_table_t* table) /* in: table */
1619
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1621
dfield_t* dfield = dtuple_get_nth_field(tuple, i);
1622
dtype_t* dtype = dfield_get_type(dfield);
1624
dfield_set_null(dfield);
1625
dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
1629
/***********************************************************************
1630
Builds the internal dictionary cache representation for a clustered
1631
index, containing also system fields not defined by the user. */
1634
dict_index_build_internal_clust(
1635
/*============================*/
1636
/* out, own: the internal
1637
representation of the clustered
1639
const dict_table_t* table, /* in: table */
1640
dict_index_t* index) /* in: user representation of
1641
a clustered index */
1643
dict_index_t* new_index;
1644
dict_field_t* field;
1650
ut_ad(table && index);
1651
ut_ad(dict_index_is_clust(index));
1652
ut_ad(mutex_own(&(dict_sys->mutex)));
1653
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1655
/* Create a new index object with certainly enough fields */
1656
new_index = dict_mem_index_create(table->name,
1657
index->name, table->space,
1659
index->n_fields + table->n_cols);
1661
/* Copy other relevant data from the old index struct to the new
1662
struct: it inherits the values */
1664
new_index->n_user_defined_cols = index->n_fields;
1666
new_index->id = index->id;
1668
/* Copy the fields of index */
1669
dict_index_copy(new_index, index, table, 0, index->n_fields);
1671
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1672
/* No fixed number of fields determines an entry uniquely */
1674
new_index->n_uniq = REC_MAX_N_FIELDS;
1676
} else if (dict_index_is_unique(index)) {
1677
/* Only the fields defined so far are needed to identify
1678
the index entry uniquely */
1680
new_index->n_uniq = new_index->n_def;
1682
/* Also the row id is needed to identify the entry */
1683
new_index->n_uniq = 1 + new_index->n_def;
1686
new_index->trx_id_offset = 0;
1688
if (!dict_index_is_ibuf(index)) {
1689
/* Add system columns, trx id first */
1691
trx_id_pos = new_index->n_def;
1693
#if DATA_ROW_ID != 0
1694
# error "DATA_ROW_ID != 0"
1696
#if DATA_TRX_ID != 1
1697
# error "DATA_TRX_ID != 1"
1699
#if DATA_ROLL_PTR != 2
1700
# error "DATA_ROLL_PTR != 2"
1703
if (!dict_index_is_unique(index)) {
1704
dict_index_add_col(new_index, table,
1705
dict_table_get_sys_col(
1706
table, DATA_ROW_ID),
1711
dict_index_add_col(new_index, table,
1712
dict_table_get_sys_col(table, DATA_TRX_ID),
1715
dict_index_add_col(new_index, table,
1716
dict_table_get_sys_col(table,
1720
for (i = 0; i < trx_id_pos; i++) {
1722
fixed_size = dict_col_get_fixed_size(
1723
dict_index_get_nth_col(new_index, i));
1725
if (fixed_size == 0) {
1726
new_index->trx_id_offset = 0;
1731
if (dict_index_get_nth_field(new_index, i)->prefix_len
1733
new_index->trx_id_offset = 0;
1738
new_index->trx_id_offset += (unsigned int) fixed_size;
1743
/* Remember the table columns already contained in new_index */
1744
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
1746
/* Mark the table columns already contained in new_index */
1747
for (i = 0; i < new_index->n_def; i++) {
1749
field = dict_index_get_nth_field(new_index, i);
1751
/* If there is only a prefix of the column in the index
1752
field, do not mark the column as contained in the index */
1754
if (field->prefix_len == 0) {
1756
indexed[field->col->ind] = TRUE;
1760
/* Add to new_index non-system columns of table not yet included
1762
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1764
dict_col_t* col = dict_table_get_nth_col(table, i);
1765
ut_ad(col->mtype != DATA_SYS);
1767
if (!indexed[col->ind]) {
1768
dict_index_add_col(new_index, table, col, 0);
1774
ut_ad(dict_index_is_ibuf(index)
1775
|| (UT_LIST_GET_LEN(table->indexes) == 0));
1777
new_index->cached = TRUE;
1782
/***********************************************************************
1783
Builds the internal dictionary cache representation for a non-clustered
1784
index, containing also system fields not defined by the user. */
1787
dict_index_build_internal_non_clust(
1788
/*================================*/
1789
/* out, own: the internal
1790
representation of the non-clustered
1792
const dict_table_t* table, /* in: table */
1793
dict_index_t* index) /* in: user representation of
1794
a non-clustered index */
1796
dict_field_t* field;
1797
dict_index_t* new_index;
1798
dict_index_t* clust_index;
1802
ut_ad(table && index);
1803
ut_ad(!dict_index_is_clust(index));
1804
ut_ad(mutex_own(&(dict_sys->mutex)));
1805
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1807
/* The clustered index should be the first in the list of indexes */
1808
clust_index = UT_LIST_GET_FIRST(table->indexes);
1811
ut_ad(dict_index_is_clust(clust_index));
1812
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
1814
/* Create a new index */
1815
new_index = dict_mem_index_create(
1816
table->name, index->name, index->space, index->type,
1817
index->n_fields + 1 + clust_index->n_uniq);
1819
/* Copy other relevant data from the old index
1820
struct to the new struct: it inherits the values */
1822
new_index->n_user_defined_cols = index->n_fields;
1824
new_index->id = index->id;
1826
/* Copy fields from index to new_index */
1827
dict_index_copy(new_index, index, table, 0, index->n_fields);
1829
/* Remember the table columns already contained in new_index */
1830
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
1832
/* Mark the table columns already contained in new_index */
1833
for (i = 0; i < new_index->n_def; i++) {
1835
field = dict_index_get_nth_field(new_index, i);
1837
/* If there is only a prefix of the column in the index
1838
field, do not mark the column as contained in the index */
1840
if (field->prefix_len == 0) {
1842
indexed[field->col->ind] = TRUE;
1846
/* Add to new_index the columns necessary to determine the clustered
1847
index entry uniquely */
1849
for (i = 0; i < clust_index->n_uniq; i++) {
1851
field = dict_index_get_nth_field(clust_index, i);
1853
if (!indexed[field->col->ind]) {
1854
dict_index_add_col(new_index, table, field->col,
1861
if (dict_index_is_unique(index)) {
1862
new_index->n_uniq = index->n_fields;
1864
new_index->n_uniq = new_index->n_def;
1867
/* Set the n_fields value in new_index to the actual defined
1870
new_index->n_fields = new_index->n_def;
1872
new_index->cached = TRUE;
1877
/*====================== FOREIGN KEY PROCESSING ========================*/
1879
/*************************************************************************
1880
Checks if a table is referenced by foreign keys. */
1883
dict_table_is_referenced_by_foreign_key(
1884
/*====================================*/
1885
/* out: TRUE if table is referenced
1887
const dict_table_t* table) /* in: InnoDB table */
1889
return(UT_LIST_GET_LEN(table->referenced_list) > 0);
1892
/*************************************************************************
1893
Check if the index is referenced by a foreign key, if TRUE return foreign
1897
dict_table_get_referenced_constraint(
1898
/*=================================*/
1899
/* out: pointer to foreign key struct if index
1900
is defined for foreign key, otherwise NULL */
1901
dict_table_t* table, /* in: InnoDB table */
1902
dict_index_t* index) /* in: InnoDB index */
1904
dict_foreign_t* foreign = NULL;
1906
ut_ad(index && table);
1908
/* If the referenced list is empty, nothing to do */
1910
if (UT_LIST_GET_LEN(table->referenced_list) == 0) {
1915
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1918
if (foreign->referenced_index == index
1919
|| foreign->referenced_index == index) {
1924
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1930
/*************************************************************************
1931
Checks if a index is defined for a foreign key constraint. Index is a part
1932
of a foreign key constraint if the index is referenced by foreign key
1933
or index is a foreign key index. */
1936
dict_table_get_foreign_constraint(
1937
/*==============================*/
1938
/* out: pointer to foreign key struct if index
1939
is defined for foreign key, otherwise NULL */
1940
dict_table_t* table, /* in: InnoDB table */
1941
dict_index_t* index) /* in: InnoDB index */
1943
dict_foreign_t* foreign = NULL;
1945
ut_ad(index && table);
1947
/* If list empty then nothgin to do */
1949
if (UT_LIST_GET_LEN(table->foreign_list) == 0) {
1954
/* Check whether this index is defined for a foreign key */
1956
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1959
if (foreign->foreign_index == index
1960
|| foreign->referenced_index == index) {
1965
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1971
/*************************************************************************
1972
Frees a foreign key struct. */
1977
dict_foreign_t* foreign) /* in, own: foreign key struct */
1979
mem_heap_free(foreign->heap);
1982
/**************************************************************************
1983
Removes a foreign constraint struct from the dictionary cache. */
1986
dict_foreign_remove_from_cache(
1987
/*===========================*/
1988
dict_foreign_t* foreign) /* in, own: foreign constraint */
1990
ut_ad(mutex_own(&(dict_sys->mutex)));
1993
if (foreign->referenced_table) {
1994
UT_LIST_REMOVE(referenced_list,
1995
foreign->referenced_table->referenced_list,
1999
if (foreign->foreign_table) {
2000
UT_LIST_REMOVE(foreign_list,
2001
foreign->foreign_table->foreign_list,
2005
dict_foreign_free(foreign);
2008
#ifndef UNIV_HOTBACKUP
2009
/**************************************************************************
2010
Looks for the foreign constraint from the foreign and referenced lists
2016
/* out: foreign constraint */
2017
dict_table_t* table, /* in: table object */
2018
const char* id) /* in: foreign constraint id */
2020
dict_foreign_t* foreign;
2022
ut_ad(mutex_own(&(dict_sys->mutex)));
2024
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2027
if (ut_strcmp(id, foreign->id) == 0) {
2032
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2035
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2038
if (ut_strcmp(id, foreign->id) == 0) {
2043
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2049
/*************************************************************************
2050
Tries to find an index whose first fields are the columns in the array,
2051
in the same order and is not marked for deletion and is not the same
2055
dict_foreign_find_index(
2056
/*====================*/
2057
/* out: matching index, NULL if not found */
2058
dict_table_t* table, /* in: table */
2059
const char** columns,/* in: array of column names */
2060
ulint n_cols, /* in: number of columns */
2061
dict_index_t* types_idx, /* in: NULL or an index to whose types the
2062
column types must match */
2063
ibool check_charsets,
2064
/* in: whether to check charsets.
2065
only has an effect if types_idx != NULL */
2067
/* in: nonzero if none of the columns must
2068
be declared NOT NULL */
2070
dict_index_t* index;
2072
index = dict_table_get_first_index(table);
2074
while (index != NULL) {
2075
/* Ignore matches that refer to the same instance
2076
or the index is to be dropped */
2077
if (index->to_be_dropped || types_idx == index) {
2081
} else if (dict_index_get_n_fields(index) >= n_cols) {
2084
for (i = 0; i < n_cols; i++) {
2085
dict_field_t* field;
2086
const char* col_name;
2088
field = dict_index_get_nth_field(index, i);
2090
col_name = dict_table_get_col_name(
2091
table, dict_col_get_no(field->col));
2093
if (field->prefix_len != 0) {
2094
/* We do not accept column prefix
2100
if (0 != innobase_strcasecmp(columns[i],
2106
&& (field->col->prtype & DATA_NOT_NULL)) {
2111
if (types_idx && !cmp_cols_are_equal(
2112
dict_index_get_nth_col(index, i),
2113
dict_index_get_nth_col(types_idx,
2122
/* We found a matching index */
2129
index = dict_table_get_next_index(index);
2135
/**************************************************************************
2136
Returns an index object by matching on the name and column names and
2137
if more than one index matches return the index with the max id */
2140
dict_table_get_index_by_max_id(
2141
/*===========================*/
2142
/* out: matching index, NULL if not found */
2143
dict_table_t* table, /* in: table */
2144
const char* name, /* in: the index name to find */
2145
const char** columns,/* in: array of column names */
2146
ulint n_cols) /* in: number of columns */
2148
dict_index_t* index;
2149
dict_index_t* found;
2152
index = dict_table_get_first_index(table);
2154
while (index != NULL) {
2155
if (ut_strcmp(index->name, name) == 0
2156
&& dict_index_get_n_ordering_defined_by_user(index)
2161
for (i = 0; i < n_cols; i++) {
2162
dict_field_t* field;
2163
const char* col_name;
2165
field = dict_index_get_nth_field(index, i);
2167
col_name = dict_table_get_col_name(
2168
table, dict_col_get_no(field->col));
2170
if (0 != innobase_strcasecmp(
2171
columns[i], col_name)) {
2178
/* We found a matching index, select
2179
the index with the higher id*/
2182
|| ut_dulint_cmp(index->id, found->id) > 0) {
2189
index = dict_table_get_next_index(index);
2195
/**************************************************************************
2196
Report an error in a foreign key definition. */
2199
dict_foreign_error_report_low(
2200
/*==========================*/
2201
FILE* file, /* in: output stream */
2202
const char* name) /* in: table name */
2205
ut_print_timestamp(file);
2206
fprintf(file, " Error in foreign key constraint of table %s:\n",
2210
/**************************************************************************
2211
Report an error in a foreign key definition. */
2214
dict_foreign_error_report(
2215
/*======================*/
2216
FILE* file, /* in: output stream */
2217
dict_foreign_t* fk, /* in: foreign key constraint */
2218
const char* msg) /* in: the error message */
2220
mutex_enter(&dict_foreign_err_mutex);
2221
dict_foreign_error_report_low(file, fk->foreign_table_name);
2223
fputs(" Constraint:\n", file);
2224
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2226
if (fk->foreign_index) {
2227
fputs("The index in the foreign key in table is ", file);
2228
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2230
"See http://dev.mysql.com/doc/refman/5.1/en/"
2231
"innodb-foreign-key-constraints.html\n"
2232
"for correct foreign key definition.\n",
2235
mutex_exit(&dict_foreign_err_mutex);
2238
/**************************************************************************
2239
Adds a foreign key constraint object to the dictionary cache. May free
2240
the object if there already is an object with the same identifier in.
2241
At least one of the foreign table and the referenced table must already
2242
be in the dictionary cache! */
2245
dict_foreign_add_to_cache(
2246
/*======================*/
2247
/* out: DB_SUCCESS or error code */
2248
dict_foreign_t* foreign, /* in, own: foreign key constraint */
2249
ibool check_charsets) /* in: TRUE=check charset
2252
dict_table_t* for_table;
2253
dict_table_t* ref_table;
2254
dict_foreign_t* for_in_cache = NULL;
2255
dict_index_t* index;
2256
ibool added_to_referenced_list= FALSE;
2257
FILE* ef = dict_foreign_err_file;
2259
ut_ad(mutex_own(&(dict_sys->mutex)));
2261
for_table = dict_table_check_if_in_cache_low(
2262
foreign->foreign_table_name);
2264
ref_table = dict_table_check_if_in_cache_low(
2265
foreign->referenced_table_name);
2266
ut_a(for_table || ref_table);
2269
for_in_cache = dict_foreign_find(for_table, foreign->id);
2272
if (!for_in_cache && ref_table) {
2273
for_in_cache = dict_foreign_find(ref_table, foreign->id);
2277
/* Free the foreign object */
2278
mem_heap_free(foreign->heap);
2280
for_in_cache = foreign;
2283
if (for_in_cache->referenced_table == NULL && ref_table) {
2284
index = dict_foreign_find_index(
2286
for_in_cache->referenced_col_names,
2287
for_in_cache->n_fields, for_in_cache->foreign_index,
2288
check_charsets, FALSE);
2290
if (index == NULL) {
2291
dict_foreign_error_report(
2293
"there is no index in referenced table"
2294
" which would contain\n"
2295
"the columns as the first columns,"
2296
" or the data types in the\n"
2297
"referenced table do not match"
2298
" the ones in table.");
2300
if (for_in_cache == foreign) {
2301
mem_heap_free(foreign->heap);
2304
return(DB_CANNOT_ADD_CONSTRAINT);
2307
for_in_cache->referenced_table = ref_table;
2308
for_in_cache->referenced_index = index;
2309
UT_LIST_ADD_LAST(referenced_list,
2310
ref_table->referenced_list,
2312
added_to_referenced_list = TRUE;
2315
if (for_in_cache->foreign_table == NULL && for_table) {
2316
index = dict_foreign_find_index(
2318
for_in_cache->foreign_col_names,
2319
for_in_cache->n_fields,
2320
for_in_cache->referenced_index, check_charsets,
2322
& (DICT_FOREIGN_ON_DELETE_SET_NULL
2323
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
2325
if (index == NULL) {
2326
dict_foreign_error_report(
2328
"there is no index in the table"
2329
" which would contain\n"
2330
"the columns as the first columns,"
2331
" or the data types in the\n"
2332
"table do not match"
2333
" the ones in the referenced table\n"
2334
"or one of the ON ... SET NULL columns"
2335
" is declared NOT NULL.");
2337
if (for_in_cache == foreign) {
2338
if (added_to_referenced_list) {
2341
ref_table->referenced_list,
2345
mem_heap_free(foreign->heap);
2348
return(DB_CANNOT_ADD_CONSTRAINT);
2351
for_in_cache->foreign_table = for_table;
2352
for_in_cache->foreign_index = index;
2353
UT_LIST_ADD_LAST(foreign_list,
2354
for_table->foreign_list,
2361
/*************************************************************************
2362
Scans from pointer onwards. Stops if is at the start of a copy of
2363
'string' where characters are compared without case sensitivity, and
2364
only outside `` or "" quotes. Stops also at '\0'. */
2369
/* out: scanned up to this */
2370
const char* ptr, /* in: scan from */
2371
const char* string) /* in: look for this */
2375
for (; *ptr; ptr++) {
2376
if (*ptr == quote) {
2377
/* Closing quote character: do not look for
2378
starting quote or the keyword. */
2381
/* Within quotes: do nothing. */
2382
} else if (*ptr == '`' || *ptr == '"') {
2383
/* Starting quote: remember the quote character. */
2386
/* Outside quotes: look for the keyword. */
2388
for (i = 0; string[i]; i++) {
2389
if (toupper((int)(unsigned char)(ptr[i]))
2390
!= toupper((int)(unsigned char)
2404
/*************************************************************************
2405
Accepts a specified string. Comparisons are case-insensitive. */
2410
/* out: if string was accepted, the pointer
2411
is moved after that, else ptr is returned */
2412
struct charset_info_st* cs,/* in: the character set of ptr */
2413
const char* ptr, /* in: scan from this */
2414
const char* string, /* in: accept only this string as the next
2415
non-whitespace string */
2416
ibool* success)/* out: TRUE if accepted */
2418
const char* old_ptr = ptr;
2419
const char* old_ptr2;
2423
while (my_isspace(cs, *ptr)) {
2429
ptr = dict_scan_to(ptr, string);
2431
if (*ptr == '\0' || old_ptr2 != ptr) {
2437
return(ptr + ut_strlen(string));
2440
/*************************************************************************
2441
Scans an id. For the lexical definition of an 'id', see the code below.
2442
Strips backquotes or double quotes from around the id. */
2447
/* out: scanned to */
2448
struct charset_info_st* cs,/* in: the character set of ptr */
2449
const char* ptr, /* in: scanned to */
2450
mem_heap_t* heap, /* in: heap where to allocate the id
2451
(NULL=id will not be allocated, but it
2452
will point to string near ptr) */
2453
const char** id, /* out,own: the id; NULL if no id was
2455
ibool table_id,/* in: TRUE=convert the allocated id
2456
as a table name; FALSE=convert to UTF-8 */
2457
ibool accept_also_dot)
2458
/* in: TRUE if also a dot can appear in a
2459
non-quoted id; in a quoted id it can appear
2470
while (my_isspace(cs, *ptr)) {
2479
if (*ptr == '`' || *ptr == '"') {
2491
if (*ptr == quote) {
2493
if (*ptr != quote) {
2501
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2502
&& (accept_also_dot || *ptr != '.')
2503
&& *ptr != ',' && *ptr != '\0') {
2511
if (UNIV_UNLIKELY(!heap)) {
2512
/* no heap given: id will point to source string */
2519
str = d = mem_heap_alloc(heap, len + 1);
2521
if ((*d++ = *s++) == quote) {
2528
ut_ad(s + 1 == ptr);
2530
str = mem_heap_strdupl(heap, s, len);
2535
/* Convert the identifier from connection character set
2538
*id = dst = mem_heap_alloc(heap, len);
2540
innobase_convert_from_id(dst, str, len);
2541
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2542
sizeof srv_mysql50_table_name_prefix)) {
2543
/* This is a pre-5.1 table name
2544
containing chars other than [A-Za-z0-9].
2545
Discard the prefix and use raw UTF-8 encoding. */
2546
str += sizeof srv_mysql50_table_name_prefix;
2547
len -= sizeof srv_mysql50_table_name_prefix;
2550
/* Encode using filename-safe characters. */
2552
*id = dst = mem_heap_alloc(heap, len);
2554
innobase_convert_from_table_id(dst, str, len);
2560
/*************************************************************************
2561
Tries to scan a column name. */
2566
/* out: scanned to */
2567
struct charset_info_st* cs, /* in: the character set of ptr */
2568
const char* ptr, /* in: scanned to */
2569
ibool* success,/* out: TRUE if success */
2570
dict_table_t* table, /* in: table in which the column is */
2571
const dict_col_t** column, /* out: pointer to column if success */
2572
mem_heap_t* heap, /* in: heap where to allocate */
2573
const char** name) /* out,own: the column name;
2574
NULL if no name was scannable */
2580
ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2582
if (*name == NULL) {
2584
return(ptr); /* Syntax error */
2587
if (table == NULL) {
2591
for (i = 0; i < dict_table_get_n_cols(table); i++) {
2593
const char* col_name = dict_table_get_col_name(
2596
if (0 == innobase_strcasecmp(col_name, *name)) {
2600
*column = dict_table_get_nth_col(table, i);
2601
strcpy((char*) *name, col_name);
2611
/*************************************************************************
2612
Scans a table name from an SQL string. */
2615
dict_scan_table_name(
2616
/*=================*/
2617
/* out: scanned to */
2618
struct charset_info_st* cs,/* in: the character set of ptr */
2619
const char* ptr, /* in: scanned to */
2620
dict_table_t** table, /* out: table object or NULL */
2621
const char* name, /* in: foreign key table name */
2622
ibool* success,/* out: TRUE if ok name found */
2623
mem_heap_t* heap, /* in: heap where to allocate the id */
2624
const char** ref_name)/* out,own: the table name;
2625
NULL if no name was scannable */
2627
const char* database_name = NULL;
2628
ulint database_name_len = 0;
2629
const char* table_name = NULL;
2630
ulint table_name_len;
2631
const char* scan_name;
2637
ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2639
if (scan_name == NULL) {
2641
return(ptr); /* Syntax error */
2645
/* We scanned the database name; scan also the table name */
2649
database_name = scan_name;
2650
database_name_len = strlen(database_name);
2652
ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2654
if (table_name == NULL) {
2656
return(ptr); /* Syntax error */
2659
/* To be able to read table dumps made with InnoDB-4.0.17 or
2660
earlier, we must allow the dot separator between the database
2661
name and the table name also to appear within a quoted
2662
identifier! InnoDB used to print a constraint as:
2663
... REFERENCES `databasename.tablename` ...
2664
starting from 4.0.18 it is
2665
... REFERENCES `databasename`.`tablename` ... */
2668
for (s = scan_name; *s; s++) {
2670
database_name = scan_name;
2671
database_name_len = s - scan_name;
2673
break;/* to do: multiple dots? */
2677
table_name = scan_name;
2680
if (database_name == NULL) {
2681
/* Use the database name of the foreign key table */
2683
database_name = name;
2684
database_name_len = dict_get_db_name_len(name);
2687
table_name_len = strlen(table_name);
2689
/* Copy database_name, '/', table_name, '\0' */
2690
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2691
memcpy(ref, database_name, database_name_len);
2692
ref[database_name_len] = '/';
2693
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2695
if (srv_lower_case_table_names) {
2696
#endif /* !__WIN__ */
2697
/* The table name is always put to lower case on Windows. */
2698
innobase_casedn_str(ref);
2701
#endif /* !__WIN__ */
2705
*table = dict_table_get_low(ref);
2710
/*************************************************************************
2711
Skips one id. The id is allowed to contain also '.'. */
2716
/* out: scanned to */
2717
struct charset_info_st* cs,/* in: the character set of ptr */
2718
const char* ptr, /* in: scanned to */
2719
ibool* success)/* out: TRUE if success, FALSE if just spaces
2720
left in string or a syntax error */
2726
ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2735
/*************************************************************************
2736
Removes MySQL comments from an SQL string. A comment is either
2737
(a) '#' to the end of the line,
2738
(b) '--<space>' to the end of the line, or
2739
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
2740
C comment syntax). */
2743
dict_strip_comments(
2744
/*================*/
2745
/* out, own: SQL string stripped from
2746
comments; the caller must free this
2748
const char* sql_string) /* in: SQL string */
2753
/* unclosed quote character (0 if none) */
2756
str = mem_alloc(strlen(sql_string) + 1);
2763
if (*sptr == '\0') {
2766
ut_a(ptr <= str + strlen(sql_string));
2771
if (*sptr == quote) {
2772
/* Closing quote character: do not look for
2773
starting quote or comments. */
2776
/* Within quotes: do not look for
2777
starting quotes or comments. */
2778
} else if (*sptr == '"' || *sptr == '`') {
2779
/* Starting quote: remember the quote character. */
2781
} else if (*sptr == '#'
2782
|| (sptr[0] == '-' && sptr[1] == '-'
2783
&& sptr[2] == ' ')) {
2785
/* In Unix a newline is 0x0A while in Windows
2786
it is 0x0D followed by 0x0A */
2788
if (*sptr == (char)0x0A
2789
|| *sptr == (char)0x0D
2797
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
2799
if (*sptr == '*' && *(sptr + 1) == '/') {
2806
if (*sptr == '\0') {
2822
/*************************************************************************
2823
Finds the highest <number> for foreign key constraints of the table. Looks
2824
only at the >= 4.0.18-format id's, which are of the form
2825
databasename/tablename_ibfk_<number>. */
2828
dict_table_get_highest_foreign_id(
2829
/*==============================*/
2830
/* out: highest number, 0 if table has no new
2831
format foreign key constraints */
2832
dict_table_t* table) /* in: table in the dictionary memory cache */
2834
dict_foreign_t* foreign;
2836
ulint biggest_id = 0;
2842
len = ut_strlen(table->name);
2843
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2846
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
2847
&& 0 == ut_memcmp(foreign->id, table->name, len)
2848
&& 0 == ut_memcmp(foreign->id + len,
2849
dict_ibfk, (sizeof dict_ibfk) - 1)
2850
&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
2851
/* It is of the >= 4.0.18 format */
2853
id = strtoul(foreign->id + len
2854
+ ((sizeof dict_ibfk) - 1),
2856
if (*endp == '\0') {
2857
ut_a(id != biggest_id);
2859
if (id > biggest_id) {
2865
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2871
/*************************************************************************
2872
Reports a simple foreign key create clause syntax error. */
2875
dict_foreign_report_syntax_err(
2876
/*===========================*/
2877
const char* name, /* in: table name */
2878
const char* start_of_latest_foreign,
2879
/* in: start of the foreign key clause
2880
in the SQL string */
2881
const char* ptr) /* in: place of the syntax error */
2883
FILE* ef = dict_foreign_err_file;
2885
mutex_enter(&dict_foreign_err_mutex);
2886
dict_foreign_error_report_low(ef, name);
2887
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
2888
start_of_latest_foreign, ptr);
2889
mutex_exit(&dict_foreign_err_mutex);
2892
/*************************************************************************
2893
Scans a table create SQL string and adds to the data dictionary the foreign
2894
key constraints declared in the string. This function should be called after
2895
the indexes for a table have been created. Each foreign key constraint must
2896
be accompanied with indexes in both participating tables. The indexes are
2897
allowed to contain more fields than mentioned in the constraint. */
2900
dict_create_foreign_constraints_low(
2901
/*================================*/
2902
/* out: error code or DB_SUCCESS */
2903
trx_t* trx, /* in: transaction */
2904
mem_heap_t* heap, /* in: memory heap */
2905
struct charset_info_st* cs,/* in: the character set of sql_string */
2906
const char* sql_string,
2907
/* in: CREATE TABLE or ALTER TABLE statement
2908
where foreign keys are declared like:
2909
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2910
table2 can be written also with the database
2911
name before it: test.table2; the default
2912
database is the database of parameter name */
2913
const char* name, /* in: table full name in the normalized form
2914
database_name/table_name */
2916
/* in: if TRUE, fail with error code
2917
DB_CANNOT_ADD_CONSTRAINT if any foreign
2920
dict_table_t* table;
2921
dict_table_t* referenced_table;
2922
dict_table_t* table_to_alter;
2923
ulint highest_id_so_far = 0;
2924
dict_index_t* index;
2925
dict_foreign_t* foreign;
2926
const char* ptr = sql_string;
2927
const char* start_of_latest_foreign = sql_string;
2928
FILE* ef = dict_foreign_err_file;
2929
const char* constraint_name;
2939
const dict_col_t*columns[500];
2940
const char* column_names[500];
2941
const char* referenced_table_name;
2943
ut_ad(mutex_own(&(dict_sys->mutex)));
2945
table = dict_table_get_low(name);
2947
if (table == NULL) {
2948
mutex_enter(&dict_foreign_err_mutex);
2949
dict_foreign_error_report_low(ef, name);
2951
"Cannot find the table in the internal"
2952
" data dictionary of InnoDB.\n"
2953
"Create table statement:\n%s\n", sql_string);
2954
mutex_exit(&dict_foreign_err_mutex);
2959
/* First check if we are actually doing an ALTER TABLE, and in that
2960
case look for the table being altered */
2962
ptr = dict_accept(cs, ptr, "ALTER", &success);
2969
ptr = dict_accept(cs, ptr, "TABLE", &success);
2976
/* We are doing an ALTER TABLE: scan the table name we are altering */
2978
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
2979
&success, heap, &referenced_table_name);
2982
"InnoDB: Error: could not find"
2983
" the table being ALTERED in:\n%s\n",
2989
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
2990
format databasename/tablename_ibfk_<number>, where <number> is local
2991
to the table; look for the highest <number> for table_to_alter, so
2992
that we can assign to new constraints higher numbers. */
2994
/* If we are altering a temporary table, the table name after ALTER
2995
TABLE does not correspond to the internal table name, and
2996
table_to_alter is NULL. TODO: should we fix this somehow? */
2998
if (table_to_alter == NULL) {
2999
highest_id_so_far = 0;
3001
highest_id_so_far = dict_table_get_highest_foreign_id(
3005
/* Scan for foreign key declarations in a loop */
3007
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
3009
ptr1 = dict_scan_to(ptr, "CONSTRAINT");
3010
ptr2 = dict_scan_to(ptr, "FOREIGN");
3012
constraint_name = NULL;
3015
/* The user may have specified a constraint name. Pick it so
3016
that we can store 'databasename/constraintname' as the id of
3017
of the constraint to system tables. */
3020
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
3024
if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
3028
while (my_isspace(cs, *ptr)) {
3032
/* read constraint name unless got "CONSTRAINT FOREIGN" */
3034
ptr = dict_scan_id(cs, ptr, heap,
3035
&constraint_name, FALSE, FALSE);
3042
/* The proper way to reject foreign keys for temporary
3043
tables would be to split the lexing and syntactical
3044
analysis of foreign key clauses from the actual adding
3045
of them, so that ha_innodb.cc could first parse the SQL
3046
command, determine if there are any foreign keys, and
3047
if so, immediately reject the command if the table is a
3048
temporary one. For now, this kludge will work. */
3049
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
3051
return(DB_CANNOT_ADD_CONSTRAINT);
3054
/**********************************************************/
3055
/* The following call adds the foreign key constraints
3056
to the data dictionary system tables on disk */
3058
error = dict_create_add_foreigns_to_dictionary(
3059
highest_id_so_far, table, trx);
3063
start_of_latest_foreign = ptr;
3065
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3071
if (!my_isspace(cs, *ptr)) {
3075
ptr = dict_accept(cs, ptr, "KEY", &success);
3081
ptr = dict_accept(cs, ptr, "(", &success);
3084
/* MySQL allows also an index id before the '('; we
3086
ptr = dict_skip_word(cs, ptr, &success);
3089
dict_foreign_report_syntax_err(
3090
name, start_of_latest_foreign, ptr);
3092
return(DB_CANNOT_ADD_CONSTRAINT);
3095
ptr = dict_accept(cs, ptr, "(", &success);
3098
/* We do not flag a syntax error here because in an
3099
ALTER TABLE we may also have DROP FOREIGN KEY abc */
3107
/* Scan the columns in the first list */
3109
ut_a(i < (sizeof column_names) / sizeof *column_names);
3110
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
3111
heap, column_names + i);
3113
mutex_enter(&dict_foreign_err_mutex);
3114
dict_foreign_error_report_low(ef, name);
3115
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
3116
start_of_latest_foreign, ptr);
3117
mutex_exit(&dict_foreign_err_mutex);
3119
return(DB_CANNOT_ADD_CONSTRAINT);
3124
ptr = dict_accept(cs, ptr, ",", &success);
3130
ptr = dict_accept(cs, ptr, ")", &success);
3133
dict_foreign_report_syntax_err(
3134
name, start_of_latest_foreign, ptr);
3135
return(DB_CANNOT_ADD_CONSTRAINT);
3138
/* Try to find an index which contains the columns
3139
as the first fields and in the right order */
3141
index = dict_foreign_find_index(table, column_names, i,
3145
mutex_enter(&dict_foreign_err_mutex);
3146
dict_foreign_error_report_low(ef, name);
3147
fputs("There is no index in table ", ef);
3148
ut_print_name(ef, NULL, TRUE, name);
3149
fprintf(ef, " where the columns appear\n"
3150
"as the first columns. Constraint:\n%s\n"
3151
"See http://dev.mysql.com/doc/refman/5.1/en/"
3152
"innodb-foreign-key-constraints.html\n"
3153
"for correct foreign key definition.\n",
3154
start_of_latest_foreign);
3155
mutex_exit(&dict_foreign_err_mutex);
3157
return(DB_CANNOT_ADD_CONSTRAINT);
3159
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3161
if (!success || !my_isspace(cs, *ptr)) {
3162
dict_foreign_report_syntax_err(
3163
name, start_of_latest_foreign, ptr);
3164
return(DB_CANNOT_ADD_CONSTRAINT);
3167
/* Let us create a constraint struct */
3169
foreign = dict_mem_foreign_create();
3171
if (constraint_name) {
3174
/* Catenate 'databasename/' to the constraint name specified
3175
by the user: we conceive the constraint as belonging to the
3176
same MySQL 'database' as the table itself. We store the name
3179
db_len = dict_get_db_name_len(table->name);
3181
foreign->id = mem_heap_alloc(
3182
foreign->heap, db_len + strlen(constraint_name) + 2);
3184
ut_memcpy(foreign->id, table->name, db_len);
3185
foreign->id[db_len] = '/';
3186
strcpy(foreign->id + db_len + 1, constraint_name);
3189
foreign->foreign_table = table;
3190
foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
3192
foreign->foreign_index = index;
3193
foreign->n_fields = (unsigned int) i;
3194
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3196
for (i = 0; i < foreign->n_fields; i++) {
3197
foreign->foreign_col_names[i] = mem_heap_strdup(
3199
dict_table_get_col_name(table,
3200
dict_col_get_no(columns[i])));
3203
ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3204
&success, heap, &referenced_table_name);
3206
/* Note that referenced_table can be NULL if the user has suppressed
3207
checking of foreign key constraints! */
3209
if (!success || (!referenced_table && trx->check_foreigns)) {
3210
dict_foreign_free(foreign);
3212
mutex_enter(&dict_foreign_err_mutex);
3213
dict_foreign_error_report_low(ef, name);
3214
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3216
start_of_latest_foreign, ptr);
3217
mutex_exit(&dict_foreign_err_mutex);
3219
return(DB_CANNOT_ADD_CONSTRAINT);
3222
ptr = dict_accept(cs, ptr, "(", &success);
3225
dict_foreign_free(foreign);
3226
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3228
return(DB_CANNOT_ADD_CONSTRAINT);
3231
/* Scan the columns in the second list */
3235
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3236
heap, column_names + i);
3240
dict_foreign_free(foreign);
3242
mutex_enter(&dict_foreign_err_mutex);
3243
dict_foreign_error_report_low(ef, name);
3244
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3246
start_of_latest_foreign, ptr);
3247
mutex_exit(&dict_foreign_err_mutex);
3249
return(DB_CANNOT_ADD_CONSTRAINT);
3252
ptr = dict_accept(cs, ptr, ",", &success);
3258
ptr = dict_accept(cs, ptr, ")", &success);
3260
if (!success || foreign->n_fields != i) {
3261
dict_foreign_free(foreign);
3263
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3265
return(DB_CANNOT_ADD_CONSTRAINT);
3272
/* Loop here as long as we can find ON ... conditions */
3274
ptr = dict_accept(cs, ptr, "ON", &success);
3278
goto try_find_index;
3281
ptr = dict_accept(cs, ptr, "DELETE", &success);
3284
ptr = dict_accept(cs, ptr, "UPDATE", &success);
3287
dict_foreign_free(foreign);
3289
dict_foreign_report_syntax_err(
3290
name, start_of_latest_foreign, ptr);
3291
return(DB_CANNOT_ADD_CONSTRAINT);
3294
is_on_delete = FALSE;
3297
is_on_delete = TRUE;
3301
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3304
goto scan_on_conditions;
3307
ptr = dict_accept(cs, ptr, "CASCADE", &success);
3311
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3313
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3316
goto scan_on_conditions;
3319
ptr = dict_accept(cs, ptr, "NO", &success);
3322
ptr = dict_accept(cs, ptr, "ACTION", &success);
3325
dict_foreign_free(foreign);
3326
dict_foreign_report_syntax_err(
3327
name, start_of_latest_foreign, ptr);
3329
return(DB_CANNOT_ADD_CONSTRAINT);
3333
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3335
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3338
goto scan_on_conditions;
3341
ptr = dict_accept(cs, ptr, "SET", &success);
3344
dict_foreign_free(foreign);
3345
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3347
return(DB_CANNOT_ADD_CONSTRAINT);
3350
ptr = dict_accept(cs, ptr, "NULL", &success);
3353
dict_foreign_free(foreign);
3354
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3356
return(DB_CANNOT_ADD_CONSTRAINT);
3359
for (j = 0; j < foreign->n_fields; j++) {
3360
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3363
/* It is not sensible to define SET NULL
3364
if the column is not allowed to be NULL! */
3366
dict_foreign_free(foreign);
3368
mutex_enter(&dict_foreign_err_mutex);
3369
dict_foreign_error_report_low(ef, name);
3371
"You have defined a SET NULL condition"
3372
" though some of the\n"
3373
"columns are defined as NOT NULL.\n",
3374
start_of_latest_foreign);
3375
mutex_exit(&dict_foreign_err_mutex);
3377
return(DB_CANNOT_ADD_CONSTRAINT);
3382
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3384
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3387
goto scan_on_conditions;
3390
if (n_on_deletes > 1 || n_on_updates > 1) {
3391
/* It is an error to define more than 1 action */
3393
dict_foreign_free(foreign);
3395
mutex_enter(&dict_foreign_err_mutex);
3396
dict_foreign_error_report_low(ef, name);
3398
"You have twice an ON DELETE clause"
3399
" or twice an ON UPDATE clause.\n",
3400
start_of_latest_foreign);
3401
mutex_exit(&dict_foreign_err_mutex);
3403
return(DB_CANNOT_ADD_CONSTRAINT);
3406
/* Try to find an index which contains the columns as the first fields
3407
and in the right order, and the types are the same as in
3408
foreign->foreign_index */
3410
if (referenced_table) {
3411
index = dict_foreign_find_index(referenced_table,
3413
foreign->foreign_index,
3416
dict_foreign_free(foreign);
3417
mutex_enter(&dict_foreign_err_mutex);
3418
dict_foreign_error_report_low(ef, name);
3420
"Cannot find an index in the"
3421
" referenced table where the\n"
3422
"referenced columns appear as the"
3423
" first columns, or column types\n"
3424
"in the table and the referenced table"
3425
" do not match for constraint.\n"
3426
"Note that the internal storage type of"
3427
" ENUM and SET changed in\n"
3428
"tables created with >= InnoDB-4.1.12,"
3429
" and such columns in old tables\n"
3430
"cannot be referenced by such columns"
3432
"See http://dev.mysql.com/doc/refman/5.1/en/"
3433
"innodb-foreign-key-constraints.html\n"
3434
"for correct foreign key definition.\n",
3435
start_of_latest_foreign);
3436
mutex_exit(&dict_foreign_err_mutex);
3438
return(DB_CANNOT_ADD_CONSTRAINT);
3441
ut_a(trx->check_foreigns == FALSE);
3445
foreign->referenced_index = index;
3446
foreign->referenced_table = referenced_table;
3448
foreign->referenced_table_name
3449
= mem_heap_strdup(foreign->heap, referenced_table_name);
3451
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3453
for (i = 0; i < foreign->n_fields; i++) {
3454
foreign->referenced_col_names[i]
3455
= mem_heap_strdup(foreign->heap, column_names[i]);
3458
/* We found an ok constraint definition: add to the lists */
3460
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3462
if (referenced_table) {
3463
UT_LIST_ADD_LAST(referenced_list,
3464
referenced_table->referenced_list,
3471
/**************************************************************************
3472
Determines whether a string starts with the specified keyword. */
3475
dict_str_starts_with_keyword(
3476
/*=========================*/
3477
/* out: TRUE if str starts
3479
void* mysql_thd, /* in: MySQL thread handle */
3480
const char* str, /* in: string to scan for keyword */
3481
const char* keyword) /* in: keyword to look for */
3483
struct charset_info_st* cs = innobase_get_charset(mysql_thd);
3486
dict_accept(cs, str, keyword, &success);
3490
/*************************************************************************
3491
Scans a table create SQL string and adds to the data dictionary the foreign
3492
key constraints declared in the string. This function should be called after
3493
the indexes for a table have been created. Each foreign key constraint must
3494
be accompanied with indexes in both participating tables. The indexes are
3495
allowed to contain more fields than mentioned in the constraint. */
3498
dict_create_foreign_constraints(
3499
/*============================*/
3500
/* out: error code or DB_SUCCESS */
3501
trx_t* trx, /* in: transaction */
3502
const char* sql_string, /* in: table create statement where
3503
foreign keys are declared like:
3504
FOREIGN KEY (a, b) REFERENCES
3505
table2(c, d), table2 can be written
3506
also with the database
3507
name before it: test.table2; the
3508
default database id the database of
3510
const char* name, /* in: table full name in the
3512
database_name/table_name */
3513
ibool reject_fks) /* in: if TRUE, fail with error
3514
code DB_CANNOT_ADD_CONSTRAINT if
3515
any foreign keys are found. */
3522
ut_a(trx->mysql_thd);
3524
str = dict_strip_comments(sql_string);
3525
heap = mem_heap_create(10000);
3527
err = dict_create_foreign_constraints_low(
3528
trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3531
mem_heap_free(heap);
3537
/**************************************************************************
3538
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3541
dict_foreign_parse_drop_constraints(
3542
/*================================*/
3543
/* out: DB_SUCCESS or
3544
DB_CANNOT_DROP_CONSTRAINT if
3545
syntax error or the constraint
3546
id does not match */
3547
mem_heap_t* heap, /* in: heap from which we can
3549
trx_t* trx, /* in: transaction */
3550
dict_table_t* table, /* in: table */
3551
ulint* n, /* out: number of constraints
3553
const char*** constraints_to_drop) /* out: id's of the
3554
constraints to drop */
3556
dict_foreign_t* foreign;
3561
FILE* ef = dict_foreign_err_file;
3562
struct charset_info_st* cs;
3565
ut_a(trx->mysql_thd);
3567
cs = innobase_get_charset(trx->mysql_thd);
3571
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3573
str = dict_strip_comments(*(trx->mysql_query_str));
3576
ut_ad(mutex_own(&(dict_sys->mutex)));
3578
ptr = dict_scan_to(ptr, "DROP");
3586
ptr = dict_accept(cs, ptr, "DROP", &success);
3588
if (!my_isspace(cs, *ptr)) {
3593
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3595
if (!success || !my_isspace(cs, *ptr)) {
3600
ptr = dict_accept(cs, ptr, "KEY", &success);
3607
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3615
(*constraints_to_drop)[*n] = id;
3618
/* Look for the given constraint id */
3620
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3622
while (foreign != NULL) {
3623
if (0 == strcmp(foreign->id, id)
3624
|| (strchr(foreign->id, '/')
3626
dict_remove_db_name(foreign->id)))) {
3631
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3634
if (foreign == NULL) {
3635
mutex_enter(&dict_foreign_err_mutex);
3637
ut_print_timestamp(ef);
3638
fputs(" Error in dropping of a foreign key constraint"
3640
ut_print_name(ef, NULL, TRUE, table->name);
3642
"in SQL command\n", ef);
3644
fputs("\nCannot find a constraint with the given id ", ef);
3645
ut_print_name(ef, NULL, FALSE, id);
3647
mutex_exit(&dict_foreign_err_mutex);
3651
return(DB_CANNOT_DROP_CONSTRAINT);
3657
mutex_enter(&dict_foreign_err_mutex);
3659
ut_print_timestamp(ef);
3660
fputs(" Syntax error in dropping of a"
3661
" foreign key constraint of table ", ef);
3662
ut_print_name(ef, NULL, TRUE, table->name);
3664
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
3665
mutex_exit(&dict_foreign_err_mutex);
3669
return(DB_CANNOT_DROP_CONSTRAINT);
3671
#endif /* UNIV_HOTBACKUP */
3673
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3675
/**************************************************************************
3676
Returns an index object if it is found in the dictionary cache.
3677
Assumes that dict_sys->mutex is already being held. */
3680
dict_index_get_if_in_cache_low(
3681
/*===========================*/
3682
/* out: index, NULL if not found */
3683
dulint index_id) /* in: index id */
3685
ut_ad(mutex_own(&(dict_sys->mutex)));
3687
return(dict_index_find_on_id_low(index_id));
3690
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
3691
/**************************************************************************
3692
Returns an index object if it is found in the dictionary cache. */
3695
dict_index_get_if_in_cache(
3696
/*=======================*/
3697
/* out: index, NULL if not found */
3698
dulint index_id) /* in: index id */
3700
dict_index_t* index;
3702
if (dict_sys == NULL) {
3706
mutex_enter(&(dict_sys->mutex));
3708
index = dict_index_get_if_in_cache_low(index_id);
3710
mutex_exit(&(dict_sys->mutex));
3714
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
3717
/**************************************************************************
3718
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3719
no comparison can occur with the page number field in a node pointer. */
3722
dict_index_check_search_tuple(
3723
/*==========================*/
3724
/* out: TRUE if ok */
3725
const dict_index_t* index, /* in: index tree */
3726
const dtuple_t* tuple) /* in: tuple used in a search */
3729
ut_a(dtuple_get_n_fields_cmp(tuple)
3730
<= dict_index_get_n_unique_in_tree(index));
3733
#endif /* UNIV_DEBUG */
3735
/**************************************************************************
3736
Builds a node pointer out of a physical record and a page number. */
3739
dict_index_build_node_ptr(
3740
/*======================*/
3741
/* out, own: node pointer */
3742
const dict_index_t* index, /* in: index */
3743
const rec_t* rec, /* in: record for which to build node
3745
ulint page_no,/* in: page number to put in node
3747
mem_heap_t* heap, /* in: memory heap where pointer
3749
ulint level) /* in: level of rec in tree:
3750
0 means leaf level */
3757
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3758
/* In a universal index tree, we take the whole record as
3759
the node pointer if the record is on the leaf level,
3760
on non-leaf levels we remove the last field, which
3761
contains the page number of the child page */
3763
ut_a(!dict_table_is_comp(index->table));
3764
n_unique = rec_get_n_fields_old(rec);
3771
n_unique = dict_index_get_n_unique_in_tree(index);
3774
tuple = dtuple_create(heap, n_unique + 1);
3776
/* When searching in the tree for the node pointer, we must not do
3777
comparison on the last field, the page number field, as on upper
3778
levels in the tree there may be identical node pointers with a
3779
different page number; therefore, we set the n_fields_cmp to one
3782
dtuple_set_n_fields_cmp(tuple, n_unique);
3784
dict_index_copy_types(tuple, index, n_unique);
3786
buf = mem_heap_alloc(heap, 4);
3788
mach_write_to_4(buf, page_no);
3790
field = dtuple_get_nth_field(tuple, n_unique);
3791
dfield_set_data(field, buf, 4);
3793
dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3795
rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3796
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3797
| REC_STATUS_NODE_PTR);
3799
ut_ad(dtuple_check_typed(tuple));
3804
/**************************************************************************
3805
Copies an initial segment of a physical record, long enough to specify an
3806
index entry uniquely. */
3809
dict_index_copy_rec_order_prefix(
3810
/*=============================*/
3811
/* out: pointer to the prefix record */
3812
const dict_index_t* index, /* in: index */
3813
const rec_t* rec, /* in: record for which to
3815
ulint* n_fields,/* out: number of fields copied */
3816
byte** buf, /* in/out: memory buffer for the
3817
copied prefix, or NULL */
3818
ulint* buf_size)/* in/out: buffer size */
3822
UNIV_PREFETCH_R(rec);
3824
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3825
ut_a(!dict_table_is_comp(index->table));
3826
n = rec_get_n_fields_old(rec);
3828
n = dict_index_get_n_unique_in_tree(index);
3832
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
3835
/**************************************************************************
3836
Builds a typed data tuple out of a physical record. */
3839
dict_index_build_data_tuple(
3840
/*========================*/
3841
/* out, own: data tuple */
3842
dict_index_t* index, /* in: index tree */
3843
rec_t* rec, /* in: record for which to build data tuple */
3844
ulint n_fields,/* in: number of data fields */
3845
mem_heap_t* heap) /* in: memory heap where tuple created */
3849
ut_ad(dict_table_is_comp(index->table)
3850
|| n_fields <= rec_get_n_fields_old(rec));
3852
tuple = dtuple_create(heap, n_fields);
3854
dict_index_copy_types(tuple, index, n_fields);
3856
rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
3858
ut_ad(dtuple_check_typed(tuple));
3863
/*************************************************************************
3864
Calculates the minimum record length in an index. */
3867
dict_index_calc_min_rec_len(
3868
/*========================*/
3869
const dict_index_t* index) /* in: index */
3874
if (dict_table_is_comp(index->table)) {
3876
sum = REC_N_NEW_EXTRA_BYTES;
3877
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3878
const dict_col_t* col
3879
= dict_index_get_nth_col(index, i);
3880
ulint size = dict_col_get_fixed_size(col);
3884
sum += size < 128 ? 1 : 2;
3886
if (!(col->prtype & DATA_NOT_NULL)) {
3891
/* round the NULL flags up to full bytes */
3892
sum += UT_BITS_IN_BYTES(nullable);
3897
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3898
sum += dict_col_get_fixed_size(
3899
dict_index_get_nth_col(index, i));
3903
sum += 2 * dict_index_get_n_fields(index);
3905
sum += dict_index_get_n_fields(index);
3908
sum += REC_N_OLD_EXTRA_BYTES;
3913
/*************************************************************************
3914
Calculates new estimates for table and index statistics. The statistics
3915
are used in query optimization. */
3918
dict_update_statistics_low(
3919
/*=======================*/
3920
dict_table_t* table, /* in/out: table */
3921
ibool has_dict_mutex __attribute__((unused)))
3922
/* in: TRUE if the caller has the
3925
dict_index_t* index;
3927
ulint sum_of_index_sizes = 0;
3929
if (table->ibd_file_missing) {
3930
ut_print_timestamp(stderr);
3932
" InnoDB: cannot calculate statistics for table %s\n"
3933
"InnoDB: because the .ibd file is missing. For help,"
3934
" please refer to\n"
3935
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3936
"innodb-troubleshooting.html\n",
3942
/* If we have set a high innodb_force_recovery level, do not calculate
3943
statistics, as a badly corrupted index can cause a crash in it. */
3945
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3950
/* Find out the sizes of the indexes and how many different values
3951
for the key they approximately have */
3953
index = dict_table_get_first_index(table);
3955
if (index == NULL) {
3956
/* Table definition is corrupt */
3962
size = btr_get_size(index, BTR_TOTAL_SIZE);
3964
index->stat_index_size = size;
3966
sum_of_index_sizes += size;
3968
size = btr_get_size(index, BTR_N_LEAF_PAGES);
3971
/* The root node of the tree is a leaf */
3975
index->stat_n_leaf_pages = size;
3977
btr_estimate_number_of_different_key_vals(index);
3979
index = dict_table_get_next_index(index);
3982
index = dict_table_get_first_index(table);
3984
table->stat_n_rows = index->stat_n_diff_key_vals[
3985
dict_index_get_n_unique(index)];
3987
table->stat_clustered_index_size = index->stat_index_size;
3989
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
3990
- index->stat_index_size;
3992
table->stat_initialized = TRUE;
3994
table->stat_modified_counter = 0;
3997
/*************************************************************************
3998
Calculates new estimates for table and index statistics. The statistics
3999
are used in query optimization. */
4002
dict_update_statistics(
4003
/*===================*/
4004
dict_table_t* table) /* in/out: table */
4006
dict_update_statistics_low(table, FALSE);
4009
/**************************************************************************
4010
Prints info of a foreign key constraint. */
4013
dict_foreign_print_low(
4014
/*===================*/
4015
dict_foreign_t* foreign) /* in: foreign key constraint */
4019
ut_ad(mutex_own(&(dict_sys->mutex)));
4021
fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
4022
foreign->id, foreign->foreign_table_name);
4024
for (i = 0; i < foreign->n_fields; i++) {
4025
fprintf(stderr, " %s", foreign->foreign_col_names[i]);
4028
fprintf(stderr, " )\n"
4030
foreign->referenced_table_name);
4032
for (i = 0; i < foreign->n_fields; i++) {
4033
fprintf(stderr, " %s", foreign->referenced_col_names[i]);
4036
fputs(" )\n", stderr);
4039
/**************************************************************************
4040
Prints a table data. */
4045
dict_table_t* table) /* in: table */
4047
mutex_enter(&(dict_sys->mutex));
4048
dict_table_print_low(table);
4049
mutex_exit(&(dict_sys->mutex));
4052
/**************************************************************************
4053
Prints a table data when we know the table name. */
4056
dict_table_print_by_name(
4057
/*=====================*/
4060
dict_table_t* table;
4062
mutex_enter(&(dict_sys->mutex));
4064
table = dict_table_get_low(name);
4068
dict_table_print_low(table);
4069
mutex_exit(&(dict_sys->mutex));
4072
/**************************************************************************
4073
Prints a table data. */
4076
dict_table_print_low(
4077
/*=================*/
4078
dict_table_t* table) /* in: table */
4080
dict_index_t* index;
4081
dict_foreign_t* foreign;
4084
ut_ad(mutex_own(&(dict_sys->mutex)));
4086
dict_update_statistics_low(table, TRUE);
4089
"--------------------------------------\n"
4090
"TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
4091
" indexes %lu, appr.rows %lu\n"
4094
(ulong) ut_dulint_get_high(table->id),
4095
(ulong) ut_dulint_get_low(table->id),
4096
(ulong) table->flags,
4097
(ulong) table->n_cols,
4098
(ulong) UT_LIST_GET_LEN(table->indexes),
4099
(ulong) table->stat_n_rows);
4101
for (i = 0; i + 1 < (ulint) table->n_cols; i++) {
4102
dict_col_print_low(table, dict_table_get_nth_col(table, i));
4103
fputs("; ", stderr);
4108
index = UT_LIST_GET_FIRST(table->indexes);
4110
while (index != NULL) {
4111
dict_index_print_low(index);
4112
index = UT_LIST_GET_NEXT(indexes, index);
4115
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4117
while (foreign != NULL) {
4118
dict_foreign_print_low(foreign);
4119
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4122
foreign = UT_LIST_GET_FIRST(table->referenced_list);
4124
while (foreign != NULL) {
4125
dict_foreign_print_low(foreign);
4126
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
4130
/**************************************************************************
4131
Prints a column data. */
4136
const dict_table_t* table, /* in: table */
4137
const dict_col_t* col) /* in: column */
4141
ut_ad(mutex_own(&(dict_sys->mutex)));
4143
dict_col_copy_type(col, &type);
4144
fprintf(stderr, "%s: ", dict_table_get_col_name(table,
4145
dict_col_get_no(col)));
4150
/**************************************************************************
4151
Prints an index data. */
4154
dict_index_print_low(
4155
/*=================*/
4156
dict_index_t* index) /* in: index */
4160
const char* type_string;
4162
ut_ad(mutex_own(&(dict_sys->mutex)));
4164
if (index->n_user_defined_cols > 0) {
4165
n_vals = index->stat_n_diff_key_vals[
4166
index->n_user_defined_cols];
4168
n_vals = index->stat_n_diff_key_vals[1];
4171
if (dict_index_is_clust(index)) {
4172
type_string = "clustered index";
4173
} else if (dict_index_is_unique(index)) {
4174
type_string = "unique index";
4176
type_string = "secondary index";
4180
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
4181
" uniq %lu, type %lu\n"
4182
" root page %lu, appr.key vals %lu,"
4183
" leaf pages %lu, size pages %lu\n"
4186
(ulong) ut_dulint_get_high(index->id),
4187
(ulong) ut_dulint_get_low(index->id),
4188
(ulong) index->n_user_defined_cols,
4189
(ulong) index->n_fields,
4190
(ulong) index->n_uniq,
4191
(ulong) index->type,
4192
(ulong) index->page,
4194
(ulong) index->stat_n_leaf_pages,
4195
(ulong) index->stat_index_size);
4197
for (i = 0; i < index->n_fields; i++) {
4198
dict_field_print_low(dict_index_get_nth_field(index, i));
4203
#ifdef UNIV_BTR_PRINT
4204
btr_print_size(index);
4206
btr_print_index(index, 7);
4207
#endif /* UNIV_BTR_PRINT */
4210
/**************************************************************************
4211
Prints a field data. */
4214
dict_field_print_low(
4215
/*=================*/
4216
dict_field_t* field) /* in: field */
4218
ut_ad(mutex_own(&(dict_sys->mutex)));
4220
fprintf(stderr, " %s", field->name);
4222
if (field->prefix_len != 0) {
4223
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4227
/**************************************************************************
4228
Outputs info on a foreign key of a table in a format suitable for
4232
dict_print_info_on_foreign_key_in_create_format(
4233
/*============================================*/
4234
FILE* file, /* in: file where to print */
4235
trx_t* trx, /* in: transaction */
4236
dict_foreign_t* foreign, /* in: foreign key constraint */
4237
ibool add_newline) /* in: whether to add a newline */
4239
const char* stripped_id;
4242
if (strchr(foreign->id, '/')) {
4243
/* Strip the preceding database name from the constraint id */
4244
stripped_id = foreign->id + 1
4245
+ dict_get_db_name_len(foreign->id);
4247
stripped_id = foreign->id;
4253
/* SHOW CREATE TABLE wants constraints each printed nicely
4254
on its own line, while error messages want no newlines
4259
fputs(" CONSTRAINT ", file);
4260
ut_print_name(file, trx, FALSE, stripped_id);
4261
fputs(" FOREIGN KEY (", file);
4264
ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4265
if (++i < foreign->n_fields) {
4272
fputs(") REFERENCES ", file);
4274
if (dict_tables_have_same_db(foreign->foreign_table_name,
4275
foreign->referenced_table_name)) {
4276
/* Do not print the database name of the referenced table */
4277
ut_print_name(file, trx, TRUE,
4278
dict_remove_db_name(
4279
foreign->referenced_table_name));
4281
ut_print_name(file, trx, TRUE,
4282
foreign->referenced_table_name);
4289
ut_print_name(file, trx, FALSE,
4290
foreign->referenced_col_names[i]);
4291
if (++i < foreign->n_fields) {
4300
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4301
fputs(" ON DELETE CASCADE", file);
4304
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4305
fputs(" ON DELETE SET NULL", file);
4308
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4309
fputs(" ON DELETE NO ACTION", file);
4312
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4313
fputs(" ON UPDATE CASCADE", file);
4316
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4317
fputs(" ON UPDATE SET NULL", file);
4320
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4321
fputs(" ON UPDATE NO ACTION", file);
4325
/**************************************************************************
4326
Outputs info on foreign keys of a table. */
4329
dict_print_info_on_foreign_keys(
4330
/*============================*/
4331
ibool create_table_format, /* in: if TRUE then print in
4332
a format suitable to be inserted into
4333
a CREATE TABLE, otherwise in the format
4334
of SHOW TABLE STATUS */
4335
FILE* file, /* in: file where to print */
4336
trx_t* trx, /* in: transaction */
4337
dict_table_t* table) /* in: table */
4339
dict_foreign_t* foreign;
4341
mutex_enter(&(dict_sys->mutex));
4343
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4345
if (foreign == NULL) {
4346
mutex_exit(&(dict_sys->mutex));
4351
while (foreign != NULL) {
4352
if (create_table_format) {
4353
dict_print_info_on_foreign_key_in_create_format(
4354
file, trx, foreign, TRUE);
4359
for (i = 0; i < foreign->n_fields; i++) {
4364
ut_print_name(file, trx, FALSE,
4365
foreign->foreign_col_names[i]);
4368
fputs(") REFER ", file);
4369
ut_print_name(file, trx, TRUE,
4370
foreign->referenced_table_name);
4373
for (i = 0; i < foreign->n_fields; i++) {
4379
foreign->referenced_col_names[i]);
4384
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4385
fputs(" ON DELETE CASCADE", file);
4388
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4389
fputs(" ON DELETE SET NULL", file);
4392
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4393
fputs(" ON DELETE NO ACTION", file);
4396
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4397
fputs(" ON UPDATE CASCADE", file);
4400
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4401
fputs(" ON UPDATE SET NULL", file);
4404
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4405
fputs(" ON UPDATE NO ACTION", file);
4409
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4412
mutex_exit(&(dict_sys->mutex));
4415
/************************************************************************
4416
Displays the names of the index and the table. */
4419
dict_index_name_print(
4420
/*==================*/
4421
FILE* file, /* in: output stream */
4422
trx_t* trx, /* in: transaction */
4423
const dict_index_t* index) /* in: index to print */
4425
fputs("index ", file);
4426
ut_print_name(file, trx, FALSE, index->name);
4427
fputs(" of table ", file);
4428
ut_print_name(file, trx, TRUE, index->table_name);
4431
/**************************************************************************
4432
Get index by name */
4435
dict_table_get_index_on_name(
4436
/*=========================*/
4437
/* out: index, NULL if does not exist */
4438
dict_table_t* table, /* in: table */
4439
const char* name) /* in: name of the index to find */
4441
dict_index_t* index;
4443
index = dict_table_get_first_index(table);
4445
while (index != NULL) {
4446
if (ut_strcmp(index->name, name) == 0) {
4451
index = dict_table_get_next_index(index);
4458
/**************************************************************************
4459
Find and index that is equivalent to the one passed in. */
4462
dict_table_find_equivalent_index(
4463
/*=============================*/
4464
dict_table_t* table, /* in/out: table */
4465
dict_index_t* index) /* in: index to match */
4468
const char** column_names;
4469
dict_index_t* equiv_index;
4471
if (UT_LIST_GET_LEN(table->foreign_list) == 0) {
4476
column_names = mem_alloc(index->n_fields * sizeof *column_names);
4478
/* Convert the column names to the format & type accepted by the find
4480
for (i = 0; i < index->n_fields; i++) {
4481
column_names[i] = index->fields[i].name;
4484
equiv_index = dict_foreign_find_index(
4485
table, column_names, index->n_fields,
4486
index, TRUE, FALSE);
4488
mem_free((void*) column_names);
4490
return(equiv_index);
4493
/**************************************************************************
4494
Replace the index passed in with another equivalent index in the tables
4495
foreign key list. */
4498
dict_table_replace_index_in_foreign_list(
4499
/*=====================================*/
4500
dict_table_t* table, /* in/out: table */
4501
dict_index_t* index) /* in: index to be replaced */
4503
dict_index_t* new_index;
4505
new_index = dict_table_find_equivalent_index(table, index);
4507
/* If match found */
4509
dict_foreign_t* foreign;
4511
ut_a(new_index != index);
4513
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4515
/* If the list is not empty then this should hold */
4518
/* Iterate over the foreign index list and replace the index
4519
passed in with the new index */
4522
if (foreign->foreign_index == index) {
4523
foreign->foreign_index = new_index;
4526
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4531
/**************************************************************************
4532
In case there is more than one index with the same name return the index
4533
with the min(id). */
4536
dict_table_get_index_on_name_and_min_id(
4537
/*=====================================*/
4538
/* out: index, NULL if does not exist */
4539
dict_table_t* table, /* in: table */
4540
const char* name) /* in: name of the index to find */
4542
dict_index_t* index;
4543
dict_index_t* min_index; /* Index with matching name and min(id) */
4546
index = dict_table_get_first_index(table);
4548
while (index != NULL) {
4549
if (ut_strcmp(index->name, name) == 0) {
4551
|| ut_dulint_cmp(index->id, min_index->id) < 0) {
4557
index = dict_table_get_next_index(index);
4565
/**************************************************************************
4566
Check for duplicate index entries in a table [using the index name] */
4569
dict_table_check_for_dup_indexes(
4570
/*=============================*/
4571
const dict_table_t* table) /* in: Check for dup indexes
4574
/* Check for duplicates, ignoring indexes that are marked
4577
const dict_index_t* index1;
4578
const dict_index_t* index2;
4580
/* The primary index _must_ exist */
4581
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
4583
index1 = UT_LIST_GET_FIRST(table->indexes);
4584
index2 = UT_LIST_GET_NEXT(indexes, index1);
4586
while (index1 && index2) {
4590
if (!index2->to_be_dropped) {
4591
ut_ad(ut_strcmp(index1->name, index2->name));
4594
index2 = UT_LIST_GET_NEXT(indexes, index2);
4597
index1 = UT_LIST_GET_NEXT(indexes, index1);
4598
index2 = UT_LIST_GET_NEXT(indexes, index1);
4601
#endif /* UNIV_DEBUG */