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
#ifndef UNIV_HOTBACKUP
30
# include "m_ctype.h" /* my_isspace() */
31
#endif /* !UNIV_HOTBACKUP */
35
dict_sys_t* dict_sys = NULL; /* the dictionary system */
37
rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
38
this in X-mode; implicit or backround
39
operations purge, rollback, foreign
40
key checks reserve this in S-mode; we
41
cannot trust that MySQL protects
42
implicit or background operations
43
a table drop since MySQL does not
44
know of them; therefore we need this;
45
NOTE: a transaction which reserves
46
this must keep book on the mode in
47
trx->dict_operation_lock_mode */
49
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
50
creating a table or index object */
51
#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
52
hash table fixed size in bytes */
53
#define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data
54
dictionary varying size in bytes */
56
/* Identifies generated InnoDB foreign key names */
57
static char dict_ibfk[] = "_ibfk_";
59
#ifndef UNIV_HOTBACKUP
60
/**********************************************************************
61
Converts an identifier to a table name.
63
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
64
this function, you MUST change also the prototype here! */
67
innobase_convert_from_table_id(
68
/*===========================*/
69
char* to, /* out: converted identifier */
70
const char* from, /* in: identifier to convert */
71
ulint len); /* in: length of 'to', in bytes;
72
should be at least 5 * strlen(to) + 1 */
73
/**********************************************************************
74
Converts an identifier to UTF-8.
76
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
77
this function, you MUST change also the prototype here! */
80
innobase_convert_from_id(
81
/*=====================*/
82
char* to, /* out: converted identifier */
83
const char* from, /* in: identifier to convert */
84
ulint len); /* in: length of 'to', in bytes;
85
should be at least 3 * strlen(to) + 1 */
86
/**********************************************************************
87
Compares NUL-terminated UTF-8 strings case insensitively.
89
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
90
this function, you MUST change also the prototype here! */
95
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
96
const char* a, /* in: first string to compare */
97
const char* b); /* in: second string to compare */
99
/**********************************************************************
100
Makes all characters in a NUL-terminated UTF-8 string lower case.
102
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
103
this function, you MUST change also the prototype here! */
108
char* a); /* in/out: string to put in lower case */
110
/**************************************************************************
111
Determines the connection character set.
113
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
114
this function, you MUST change also the prototype here! */
115
struct charset_info_st*
116
innobase_get_charset(
117
/*=================*/
118
/* out: connection character set */
119
void* mysql_thd); /* in: MySQL thread handle */
120
#endif /* !UNIV_HOTBACKUP */
122
/**************************************************************************
123
Removes an index from the dictionary cache. */
126
dict_index_remove_from_cache(
127
/*=========================*/
128
dict_table_t* table, /* in: table */
129
dict_index_t* index); /* in, own: index */
130
/***********************************************************************
131
Copies fields contained in index2 to index1. */
136
dict_index_t* index1, /* in: index to copy to */
137
dict_index_t* index2, /* in: index to copy from */
138
dict_table_t* table, /* in: table */
139
ulint start, /* in: first position to copy */
140
ulint end); /* in: last position to copy */
141
/***********************************************************************
142
Tries to find column names for the index and sets the col field of the
146
dict_index_find_cols(
147
/*=================*/
148
dict_table_t* table, /* in: table */
149
dict_index_t* index); /* in: index */
150
/***********************************************************************
151
Builds the internal dictionary cache representation for a clustered
152
index, containing also system fields not defined by the user. */
155
dict_index_build_internal_clust(
156
/*============================*/
157
/* out, own: the internal representation
158
of the clustered index */
159
dict_table_t* table, /* in: table */
160
dict_index_t* index); /* in: user representation of a clustered
162
/***********************************************************************
163
Builds the internal dictionary cache representation for a non-clustered
164
index, containing also system fields not defined by the user. */
167
dict_index_build_internal_non_clust(
168
/*================================*/
169
/* out, own: the internal representation
170
of the non-clustered index */
171
dict_table_t* table, /* in: table */
172
dict_index_t* index); /* in: user representation of a non-clustered
174
/**************************************************************************
175
Removes a foreign constraint struct from the dictionary cache. */
178
dict_foreign_remove_from_cache(
179
/*===========================*/
180
dict_foreign_t* foreign); /* in, own: foreign constraint */
181
/**************************************************************************
182
Prints a column data. */
187
const dict_table_t* table, /* in: table */
188
const dict_col_t* col); /* in: column */
189
/**************************************************************************
190
Prints an index data. */
193
dict_index_print_low(
194
/*=================*/
195
dict_index_t* index); /* in: index */
196
/**************************************************************************
197
Prints a field data. */
200
dict_field_print_low(
201
/*=================*/
202
dict_field_t* field); /* in: field */
203
/*************************************************************************
204
Frees a foreign key struct. */
209
dict_foreign_t* foreign); /* in, own: foreign key struct */
211
/* Stream for storing detailed information about the latest foreign key
212
and unique key errors */
213
FILE* dict_foreign_err_file = NULL;
214
mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign
215
and unique error buffers */
217
#ifndef UNIV_HOTBACKUP
218
/**********************************************************************
219
Makes all characters in a NUL-terminated UTF-8 string lower case. */
224
char* a) /* in/out: string to put in lower case */
226
innobase_casedn_str(a);
228
#endif /* !UNIV_HOTBACKUP */
230
/************************************************************************
231
Checks if the database name in two table names is the same. */
234
dict_tables_have_same_db(
235
/*=====================*/
236
/* out: TRUE if same db name */
237
const char* name1, /* in: table name in the form
238
dbname '/' tablename */
239
const char* name2) /* in: table name in the form
240
dbname '/' tablename */
242
for (; *name1 == *name2; name1++, name2++) {
246
ut_a(*name1); /* the names must contain '/' */
251
/************************************************************************
252
Return the end of table name where we have removed dbname and '/'. */
257
/* out: table name */
258
const char* name) /* in: table name in the form
259
dbname '/' tablename */
261
const char* s = strchr(name, '/');
267
/************************************************************************
268
Get the database name length in a table name. */
271
dict_get_db_name_len(
272
/*=================*/
273
/* out: database name length */
274
const char* name) /* in: table name in the form
275
dbname '/' tablename */
278
s = strchr(name, '/');
283
/************************************************************************
284
Reserves the dictionary system mutex for MySQL. */
287
dict_mutex_enter_for_mysql(void)
288
/*============================*/
290
mutex_enter(&(dict_sys->mutex));
293
/************************************************************************
294
Releases the dictionary system mutex for MySQL. */
297
dict_mutex_exit_for_mysql(void)
298
/*===========================*/
300
mutex_exit(&(dict_sys->mutex));
303
/************************************************************************
304
Decrements the count of open MySQL handles to a table. */
307
dict_table_decrement_handle_count(
308
/*==============================*/
309
dict_table_t* table) /* in: table */
311
mutex_enter(&(dict_sys->mutex));
313
ut_a(table->n_mysql_handles_opened > 0);
315
table->n_mysql_handles_opened--;
317
mutex_exit(&(dict_sys->mutex));
320
/*************************************************************************
321
Gets the column data type. */
324
dict_col_copy_type_noninline(
325
/*=========================*/
326
const dict_col_t* col, /* in: column */
327
dtype_t* type) /* out: data type */
329
dict_col_copy_type(col, type);
332
/************************************************************************
333
Gets the nth column of a table. */
336
dict_table_get_nth_col_noninline(
337
/*=============================*/
338
/* out: pointer to column object */
339
const dict_table_t* table, /* in: table */
340
ulint pos) /* in: position of column */
342
return(dict_table_get_nth_col(table, pos));
345
/************************************************************************
346
Gets the first index on the table (the clustered index). */
349
dict_table_get_first_index_noninline(
350
/*=================================*/
351
/* out: index, NULL if none exists */
352
dict_table_t* table) /* in: table */
354
return(dict_table_get_first_index(table));
357
/************************************************************************
358
Gets the next index on the table. */
361
dict_table_get_next_index_noninline(
362
/*================================*/
363
/* out: index, NULL if none left */
364
dict_index_t* index) /* in: index */
366
return(dict_table_get_next_index(index));
369
/**************************************************************************
370
Returns an index object. */
373
dict_table_get_index_noninline(
374
/*===========================*/
375
/* out: index, NULL if does not exist */
376
dict_table_t* table, /* in: table */
377
const char* name) /* in: index name */
379
return(dict_table_get_index(table, name));
382
/**************************************************************************
383
Returns a column's name. */
386
dict_table_get_col_name(
387
/*====================*/
388
/* out: column name. NOTE: not
389
guaranteed to stay valid if table is
390
modified in any way (columns added,
392
const dict_table_t* table, /* in: table */
393
ulint col_nr) /* in: column number */
399
ut_ad(col_nr < table->n_def);
400
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
402
s = table->col_names;
404
for (i = 0; i < col_nr; i++) {
413
/************************************************************************
414
Acquire the autoinc lock.*/
417
dict_table_autoinc_lock(
418
/*====================*/
421
mutex_enter(&table->autoinc_mutex);
424
/************************************************************************
425
Unconditionally set the autoinc counter. */
428
dict_table_autoinc_initialize(
429
/*==========================*/
430
dict_table_t* table, /* in: table */
431
ib_ulonglong value) /* in: next value to assign to a row */
433
ut_ad(mutex_own(&table->autoinc_mutex));
435
table->autoinc = value;
438
/************************************************************************
439
Reads the next autoinc value (== autoinc counter value), 0 if not yet
443
dict_table_autoinc_read(
444
/*====================*/
445
/* out: value for a new row, or 0 */
446
dict_table_t* table) /* in: table */
448
ut_ad(mutex_own(&table->autoinc_mutex));
450
return(table->autoinc);
453
/************************************************************************
454
Updates the autoinc counter if the value supplied is greater than the
458
dict_table_autoinc_update_if_greater(
459
/*=================================*/
461
dict_table_t* table, /* in: table */
462
ib_ulonglong value) /* in: value which was assigned to a row */
464
ut_ad(mutex_own(&table->autoinc_mutex));
466
if (value > table->autoinc) {
468
table->autoinc = value;
472
/************************************************************************
473
Release the autoinc lock.*/
476
dict_table_autoinc_unlock(
477
/*======================*/
478
dict_table_t* table) /* in: release autoinc lock for this table */
480
mutex_exit(&table->autoinc_mutex);
483
/************************************************************************
484
Looks for column n in an index. */
487
dict_index_get_nth_col_pos(
488
/*=======================*/
489
/* out: position in internal representation
490
of the index; if not contained, returns
492
dict_index_t* index, /* in: index */
493
ulint n) /* in: column number */
495
const dict_field_t* field;
496
const dict_col_t* col;
501
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
503
col = dict_table_get_nth_col(index->table, n);
505
if (index->type & DICT_CLUSTERED) {
507
return(dict_col_get_clust_pos(col, index));
510
n_fields = dict_index_get_n_fields(index);
512
for (pos = 0; pos < n_fields; pos++) {
513
field = dict_index_get_nth_field(index, pos);
515
if (col == field->col && field->prefix_len == 0) {
521
return(ULINT_UNDEFINED);
524
/************************************************************************
525
Returns TRUE if the index contains a column or a prefix of that column. */
528
dict_index_contains_col_or_prefix(
529
/*==============================*/
530
/* out: TRUE if contains the column or its
532
dict_index_t* index, /* in: index */
533
ulint n) /* in: column number */
535
const dict_field_t* field;
536
const dict_col_t* col;
541
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
543
if (index->type & DICT_CLUSTERED) {
548
col = dict_table_get_nth_col(index->table, n);
550
n_fields = dict_index_get_n_fields(index);
552
for (pos = 0; pos < n_fields; pos++) {
553
field = dict_index_get_nth_field(index, pos);
555
if (col == field->col) {
564
/************************************************************************
565
Looks for a matching field in an index. The column has to be the same. The
566
column in index must be complete, or must contain a prefix longer than the
567
column in index2. That is, we must be able to construct the prefix in index2
568
from the prefix in index. */
571
dict_index_get_nth_field_pos(
572
/*=========================*/
573
/* out: position in internal representation
574
of the index; if not contained, returns
576
dict_index_t* index, /* in: index from which to search */
577
dict_index_t* index2, /* in: index */
578
ulint n) /* in: field number in index2 */
581
dict_field_t* field2;
586
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
588
field2 = dict_index_get_nth_field(index2, n);
590
n_fields = dict_index_get_n_fields(index);
592
for (pos = 0; pos < n_fields; pos++) {
593
field = dict_index_get_nth_field(index, pos);
595
if (field->col == field2->col
596
&& (field->prefix_len == 0
597
|| (field->prefix_len >= field2->prefix_len
598
&& field2->prefix_len != 0))) {
604
return(ULINT_UNDEFINED);
607
/**************************************************************************
608
Returns a table object based on table id. */
611
dict_table_get_on_id(
612
/*=================*/
613
/* out: table, NULL if does not exist */
614
dulint table_id, /* in: table id */
615
trx_t* trx) /* in: transaction handle */
619
if (trx->dict_operation_lock_mode == RW_X_LATCH) {
621
/* Note: An X latch implies that the transaction
622
already owns the dictionary mutex. */
624
ut_ad(mutex_own(&dict_sys->mutex));
626
return(dict_table_get_on_id_low(table_id));
629
mutex_enter(&(dict_sys->mutex));
631
table = dict_table_get_on_id_low(table_id);
633
mutex_exit(&(dict_sys->mutex));
638
/************************************************************************
639
Looks for column n position in the clustered index. */
642
dict_table_get_nth_col_pos(
643
/*=======================*/
644
/* out: position in internal representation
645
of the clustered index */
646
dict_table_t* table, /* in: table */
647
ulint n) /* in: column number */
649
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
653
/************************************************************************
654
Check whether the table uses the compact page format. */
657
dict_table_is_comp_noninline(
658
/*=========================*/
659
/* out: TRUE if table uses the
660
compact page format */
661
const dict_table_t* table) /* in: table */
663
return(dict_table_is_comp(table));
666
/************************************************************************
667
Checks if a column is in the ordering columns of the clustered index of a
668
table. Column prefixes are treated like whole columns. */
671
dict_table_col_in_clustered_key(
672
/*============================*/
673
/* out: TRUE if the column, or its prefix, is
674
in the clustered key */
675
dict_table_t* table, /* in: table */
676
ulint n) /* in: column number */
679
const dict_field_t* field;
680
const dict_col_t* col;
686
col = dict_table_get_nth_col(table, n);
688
index = dict_table_get_first_index(table);
690
n_fields = dict_index_get_n_unique(index);
692
for (pos = 0; pos < n_fields; pos++) {
693
field = dict_index_get_nth_field(index, pos);
695
if (col == field->col) {
704
/**************************************************************************
705
Inits the data dictionary module. */
711
dict_sys = mem_alloc(sizeof(dict_sys_t));
713
mutex_create(&dict_sys->mutex, SYNC_DICT);
715
dict_sys->table_hash = hash_create(buf_pool_get_max_size()
716
/ (DICT_POOL_PER_TABLE_HASH
718
dict_sys->table_id_hash = hash_create(buf_pool_get_max_size()
719
/ (DICT_POOL_PER_TABLE_HASH
723
UT_LIST_INIT(dict_sys->table_LRU);
725
rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
727
dict_foreign_err_file = os_file_create_tmpfile();
728
ut_a(dict_foreign_err_file);
730
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
733
/**************************************************************************
734
Returns a table object and optionally increment its MySQL open handle count.
735
NOTE! This is a high-level function to be used mainly from outside the
736
'dict' directory. Inside this directory dict_table_get_low is usually the
737
appropriate function. */
742
/* out: table, NULL if
744
const char* table_name, /* in: table name */
745
ibool inc_mysql_count)
746
/* in: whether to increment the open
747
handle count on the table */
751
mutex_enter(&(dict_sys->mutex));
753
table = dict_table_get_low(table_name);
755
if (inc_mysql_count && table) {
756
table->n_mysql_handles_opened++;
759
mutex_exit(&(dict_sys->mutex));
762
if (!table->stat_initialized) {
763
/* If table->ibd_file_missing == TRUE, this will
764
print an error message and return without doing
766
dict_update_statistics(table);
773
/**************************************************************************
774
Adds system columns to a table object. */
777
dict_table_add_system_columns(
778
/*==========================*/
779
dict_table_t* table, /* in/out: table */
780
mem_heap_t* heap) /* in: temporary heap */
783
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
784
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
785
ut_ad(!table->cached);
787
/* NOTE: the system columns MUST be added in the following order
788
(so that they can be indexed by the numerical value of DATA_ROW_ID,
789
etc.) and as the last columns of the table memory object.
790
The clustered index will not always physically contain all
793
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
794
DATA_ROW_ID | DATA_NOT_NULL,
797
#error "DATA_ROW_ID != 0"
799
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
800
DATA_TRX_ID | DATA_NOT_NULL,
803
#error "DATA_TRX_ID != 1"
805
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
806
DATA_ROLL_PTR | DATA_NOT_NULL,
808
#if DATA_ROLL_PTR != 2
809
#error "DATA_ROLL_PTR != 2"
812
/* This check reminds that if a new system column is added to
813
the program, it should be dealt with here */
814
#if DATA_N_SYS_COLS != 3
815
#error "DATA_N_SYS_COLS != 3"
819
/**************************************************************************
820
Adds a table object to the dictionary cache. */
823
dict_table_add_to_cache(
824
/*====================*/
825
dict_table_t* table, /* in: table */
826
mem_heap_t* heap) /* in: temporary heap */
833
/* The lower limit for what we consider a "big" row */
834
#define BIG_ROW_SIZE 1024
836
ut_ad(mutex_own(&(dict_sys->mutex)));
838
dict_table_add_system_columns(table, heap);
840
table->cached = TRUE;
842
fold = ut_fold_string(table->name);
843
id_fold = ut_fold_dulint(table->id);
846
for (i = 0; i < table->n_def; i++) {
847
ulint col_len = dict_col_get_max_size(
848
dict_table_get_nth_col(table, i));
852
/* If we have a single unbounded field, or several gigantic
853
fields, mark the maximum row size as BIG_ROW_SIZE. */
854
if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
855
row_len = BIG_ROW_SIZE;
861
table->big_rows = row_len >= BIG_ROW_SIZE;
863
/* Look for a table with the same name: error if such exists */
865
dict_table_t* table2;
866
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
867
(ut_strcmp(table2->name, table->name) == 0));
868
ut_a(table2 == NULL);
871
/* Look for a table with the same id: error if such exists */
873
dict_table_t* table2;
874
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2,
875
(ut_dulint_cmp(table2->id, table->id) == 0));
876
ut_a(table2 == NULL);
879
/* Add table to hash table of tables */
880
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
883
/* Add table to hash table of tables based on table id */
884
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
886
/* Add table to LRU list of tables */
887
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
889
dict_sys->size += mem_heap_get_size(table->heap);
892
/**************************************************************************
893
Looks for an index with the given id. NOTE that we do not reserve
894
the dictionary mutex: this function is for emergency purposes like
895
printing info of a corrupt database page! */
898
dict_index_find_on_id_low(
899
/*======================*/
900
/* out: index or NULL if not found from cache */
901
dulint id) /* in: index id */
906
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
909
index = dict_table_get_first_index(table);
912
if (0 == ut_dulint_cmp(id, index->id)) {
918
index = dict_table_get_next_index(index);
921
table = UT_LIST_GET_NEXT(table_LRU, table);
927
/**************************************************************************
928
Renames a table object. */
931
dict_table_rename_in_cache(
932
/*=======================*/
933
/* out: TRUE if success */
934
dict_table_t* table, /* in: table */
935
const char* new_name, /* in: new name */
936
ibool rename_also_foreigns)/* in: in ALTER TABLE we want
937
to preserve the original table name
938
in constraints which reference it */
940
dict_foreign_t* foreign;
948
ut_ad(mutex_own(&(dict_sys->mutex)));
950
old_size = mem_heap_get_size(table->heap);
952
fold = ut_fold_string(new_name);
954
/* Look for a table with the same name: error if such exists */
956
dict_table_t* table2;
957
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
958
(ut_strcmp(table2->name, new_name) == 0));
961
"InnoDB: Error: dictionary cache"
962
" already contains a table of name %s\n",
968
/* If the table is stored in a single-table tablespace, rename the
971
if (table->space != 0) {
972
if (table->dir_path_of_temp_table != NULL) {
974
"InnoDB: Error: trying to rename a table"
975
" %s (%s) created with CREATE\n"
976
"InnoDB: TEMPORARY TABLE\n",
977
table->name, table->dir_path_of_temp_table);
980
success = fil_rename_tablespace(
981
table->name, table->space, new_name);
990
/* Remove table from the hash tables of tables */
991
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
992
ut_fold_string(table->name), table);
993
old_name = mem_heap_strdup(table->heap, table->name);
994
table->name = mem_heap_strdup(table->heap, new_name);
996
/* Add table to hash table of tables */
997
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
999
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
1001
/* Update the table_name field in indexes */
1002
index = dict_table_get_first_index(table);
1004
while (index != NULL) {
1005
index->table_name = table->name;
1007
index = dict_table_get_next_index(index);
1010
if (!rename_also_foreigns) {
1011
/* In ALTER TABLE we think of the rename table operation
1012
in the direction table -> temporary table (#sql...)
1013
as dropping the table with the old name and creating
1014
a new with the new name. Thus we kind of drop the
1015
constraints from the dictionary cache here. The foreign key
1016
constraints will be inherited to the new table from the
1017
system tables through a call of dict_load_foreigns. */
1019
/* Remove the foreign constraints from the cache */
1020
foreign = UT_LIST_GET_LAST(table->foreign_list);
1022
while (foreign != NULL) {
1023
dict_foreign_remove_from_cache(foreign);
1024
foreign = UT_LIST_GET_LAST(table->foreign_list);
1027
/* Reset table field in referencing constraints */
1029
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1031
while (foreign != NULL) {
1032
foreign->referenced_table = NULL;
1033
foreign->referenced_index = NULL;
1035
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1038
/* Make the list of referencing constraints empty */
1040
UT_LIST_INIT(table->referenced_list);
1045
/* Update the table name fields in foreign constraints, and update also
1046
the constraint id of new format >= 4.0.18 constraints. Note that at
1047
this point we have already changed table->name to the new name. */
1049
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1051
while (foreign != NULL) {
1052
if (ut_strlen(foreign->foreign_table_name)
1053
< ut_strlen(table->name)) {
1054
/* Allocate a longer name buffer;
1055
TODO: store buf len to save memory */
1057
foreign->foreign_table_name
1058
= mem_heap_alloc(foreign->heap,
1059
ut_strlen(table->name) + 1);
1062
strcpy(foreign->foreign_table_name, table->name);
1064
if (strchr(foreign->id, '/')) {
1068
/* This is a >= 4.0.18 format id */
1070
old_id = mem_strdup(foreign->id);
1072
if (ut_strlen(foreign->id) > ut_strlen(old_name)
1073
+ ((sizeof dict_ibfk) - 1)
1074
&& !memcmp(foreign->id, old_name,
1075
ut_strlen(old_name))
1076
&& !memcmp(foreign->id + ut_strlen(old_name),
1077
dict_ibfk, (sizeof dict_ibfk) - 1)) {
1079
/* This is a generated >= 4.0.18 format id */
1081
if (strlen(table->name) > strlen(old_name)) {
1082
foreign->id = mem_heap_alloc(
1085
+ strlen(old_id) + 1);
1088
/* Replace the prefix 'databasename/tablename'
1089
with the new names */
1090
strcpy(foreign->id, table->name);
1092
old_id + ut_strlen(old_name));
1094
/* This is a >= 4.0.18 format id where the user
1096
db_len = dict_get_db_name_len(table->name) + 1;
1098
if (dict_get_db_name_len(table->name)
1099
> dict_get_db_name_len(foreign->id)) {
1101
foreign->id = mem_heap_alloc(
1103
db_len + strlen(old_id) + 1);
1106
/* Replace the database prefix in id with the
1107
one from table->name */
1109
ut_memcpy(foreign->id, table->name, db_len);
1111
strcpy(foreign->id + db_len,
1112
dict_remove_db_name(old_id));
1118
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1121
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1123
while (foreign != NULL) {
1124
if (ut_strlen(foreign->referenced_table_name)
1125
< ut_strlen(table->name)) {
1126
/* Allocate a longer name buffer;
1127
TODO: store buf len to save memory */
1129
foreign->referenced_table_name = mem_heap_alloc(
1130
foreign->heap, strlen(table->name) + 1);
1133
strcpy(foreign->referenced_table_name, table->name);
1135
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1141
/**************************************************************************
1142
Change the id of a table object in the dictionary cache. This is used in
1143
DISCARD TABLESPACE. */
1146
dict_table_change_id_in_cache(
1147
/*==========================*/
1148
dict_table_t* table, /* in: table object already in cache */
1149
dulint new_id) /* in: new id to set */
1152
ut_ad(mutex_own(&(dict_sys->mutex)));
1153
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1155
/* Remove the table from the hash table of id's */
1157
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1158
ut_fold_dulint(table->id), table);
1161
/* Add the table back to the hash table */
1162
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1163
ut_fold_dulint(table->id), table);
1166
/**************************************************************************
1167
Removes a table object from the dictionary cache. */
1170
dict_table_remove_from_cache(
1171
/*=========================*/
1172
dict_table_t* table) /* in, own: table */
1174
dict_foreign_t* foreign;
1175
dict_index_t* index;
1179
ut_ad(mutex_own(&(dict_sys->mutex)));
1180
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1183
fputs("Removing table ", stderr);
1184
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1185
fputs(" from dictionary cache\n", stderr);
1188
/* Remove the foreign constraints from the cache */
1189
foreign = UT_LIST_GET_LAST(table->foreign_list);
1191
while (foreign != NULL) {
1192
dict_foreign_remove_from_cache(foreign);
1193
foreign = UT_LIST_GET_LAST(table->foreign_list);
1196
/* Reset table field in referencing constraints */
1198
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1200
while (foreign != NULL) {
1201
foreign->referenced_table = NULL;
1202
foreign->referenced_index = NULL;
1204
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1207
/* Remove the indexes from the cache */
1208
index = UT_LIST_GET_LAST(table->indexes);
1210
while (index != NULL) {
1211
dict_index_remove_from_cache(table, index);
1212
index = UT_LIST_GET_LAST(table->indexes);
1215
/* Remove table from the hash tables of tables */
1216
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1217
ut_fold_string(table->name), table);
1218
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1219
ut_fold_dulint(table->id), table);
1221
/* Remove table from LRU list of tables */
1222
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1224
size = mem_heap_get_size(table->heap);
1226
ut_ad(dict_sys->size >= size);
1228
dict_sys->size -= size;
1230
dict_mem_table_free(table);
1233
/*************************************************************************
1234
Gets the column position in the clustered index. */
1237
dict_col_get_clust_pos_noninline(
1238
/*=============================*/
1239
const dict_col_t* col, /* in: table column */
1240
const dict_index_t* clust_index) /* in: clustered index */
1242
return(dict_col_get_clust_pos(col, clust_index));
1245
/********************************************************************
1246
If the given column name is reserved for InnoDB system columns, return
1250
dict_col_name_is_reserved(
1251
/*======================*/
1252
/* out: TRUE if name is reserved */
1253
const char* name) /* in: column name */
1255
/* This check reminds that if a new system column is added to
1256
the program, it should be dealt with here. */
1257
#if DATA_N_SYS_COLS != 3
1258
#error "DATA_N_SYS_COLS != 3"
1261
static const char* reserved_names[] = {
1262
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1267
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1268
if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1277
/**************************************************************************
1278
Adds an index to the dictionary cache. */
1281
dict_index_add_to_cache(
1282
/*====================*/
1283
dict_table_t* table, /* in: table on which the index is */
1284
dict_index_t* index, /* in, own: index; NOTE! The index memory
1285
object is freed in this function! */
1286
ulint page_no)/* in: root page number of the index */
1288
dict_index_t* new_index;
1293
ut_ad(mutex_own(&(dict_sys->mutex)));
1294
ut_ad(index->n_def == index->n_fields);
1295
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1297
ut_ad(mem_heap_validate(index->heap));
1301
dict_index_t* index2;
1302
index2 = UT_LIST_GET_FIRST(table->indexes);
1304
while (index2 != NULL) {
1305
ut_ad(ut_strcmp(index->name, index2->name) != 0);
1307
index2 = UT_LIST_GET_NEXT(indexes, index2);
1310
#endif /* UNIV_DEBUG */
1312
ut_a(!(index->type & DICT_CLUSTERED)
1313
|| UT_LIST_GET_LEN(table->indexes) == 0);
1315
dict_index_find_cols(table, index);
1317
/* Build the cache internal representation of the index,
1318
containing also the added system fields */
1320
if (index->type & DICT_CLUSTERED) {
1321
new_index = dict_index_build_internal_clust(table, index);
1323
new_index = dict_index_build_internal_non_clust(table, index);
1326
new_index->search_info = btr_search_info_create(new_index->heap);
1328
/* Set the n_fields value in new_index to the actual defined
1329
number of fields in the cache internal representation */
1331
new_index->n_fields = new_index->n_def;
1333
/* Add the new index as the last index for the table */
1335
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1336
new_index->table = table;
1337
new_index->table_name = table->name;
1339
/* Increment the ord_part counts in columns which are ordering */
1341
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1342
n_ord = new_index->n_fields;
1344
n_ord = dict_index_get_n_unique(new_index);
1347
for (i = 0; i < n_ord; i++) {
1349
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1352
new_index->page = (unsigned int) page_no;
1353
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1355
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1357
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1359
(1 + dict_index_get_n_unique(new_index))
1360
* sizeof(ib_longlong));
1362
new_index->stat_n_non_null_key_vals = mem_heap_zalloc(
1364
(1 + dict_index_get_n_unique(new_index))
1365
* sizeof(*new_index->stat_n_non_null_key_vals));
1367
/* Give some sensible values to stat_n_... in case we do
1368
not calculate statistics quickly enough */
1370
for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1372
new_index->stat_n_diff_key_vals[i] = 100;
1376
dict_sys->size += mem_heap_get_size(new_index->heap);
1378
dict_mem_index_free(index);
1381
/**************************************************************************
1382
Removes an index from the dictionary cache. */
1385
dict_index_remove_from_cache(
1386
/*=========================*/
1387
dict_table_t* table, /* in: table */
1388
dict_index_t* index) /* in, own: index */
1394
ut_ad(table && index);
1395
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1396
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1397
ut_ad(mutex_own(&(dict_sys->mutex)));
1399
/* We always create search info whether or not adaptive
1400
hash index is enabled or not. */
1401
info = index->search_info;
1404
/* We are not allowed to free the in-memory index struct
1405
dict_index_t until all entries in the adaptive hash index
1406
that point to any of the page belonging to his b-tree index
1407
are dropped. This is so because dropping of these entries
1408
require access to dict_index_t struct. To avoid such scenario
1409
We keep a count of number of such pages in the search_info and
1410
only free the dict_index_t struct when this count drops to
1414
ulint ref_count = btr_search_info_get_ref_count(info);
1415
if (ref_count == 0) {
1419
/* Sleep for 10ms before trying again. */
1420
os_thread_sleep(10000);
1423
if (retries % 500 == 0) {
1424
/* No luck after 5 seconds of wait. */
1425
fprintf(stderr, "InnoDB: Error: Waited for"
1426
" %lu secs for hash index"
1427
" ref_count (%lu) to drop"
1437
/* To avoid a hang here we commit suicide if the
1438
ref_count doesn't drop to zero in 600 seconds. */
1439
if (retries >= 60000) {
1444
rw_lock_free(&index->lock);
1446
/* Remove the index from the list of indexes of the table */
1447
UT_LIST_REMOVE(indexes, table->indexes, index);
1449
size = mem_heap_get_size(index->heap);
1451
ut_ad(dict_sys->size >= size);
1453
dict_sys->size -= size;
1455
dict_mem_index_free(index);
1458
/***********************************************************************
1459
Tries to find column names for the index and sets the col field of the
1463
dict_index_find_cols(
1464
/*=================*/
1465
dict_table_t* table, /* in: table */
1466
dict_index_t* index) /* in: index */
1470
ut_ad(table && index);
1471
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1472
ut_ad(mutex_own(&(dict_sys->mutex)));
1474
for (i = 0; i < index->n_fields; i++) {
1476
dict_field_t* field = dict_index_get_nth_field(index, i);
1478
for (j = 0; j < table->n_cols; j++) {
1479
if (!strcmp(dict_table_get_col_name(table, j),
1481
field->col = (dict_col_t*)
1482
dict_table_get_nth_col(table, j);
1488
/* It is an error not to find a matching column. */
1496
/***********************************************************************
1497
Adds a column to index. */
1502
dict_index_t* index, /* in: index */
1503
dict_table_t* table, /* in: table */
1504
dict_col_t* col, /* in: column */
1505
ulint prefix_len) /* in: column prefix length */
1507
dict_field_t* field;
1508
const char* col_name;
1510
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1512
dict_mem_index_add_field(index, col_name, prefix_len);
1514
field = dict_index_get_nth_field(index, index->n_def - 1);
1517
field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1519
if (prefix_len && field->fixed_len > prefix_len) {
1520
field->fixed_len = (unsigned int) prefix_len;
1523
/* Long fixed-length fields that need external storage are treated as
1524
variable-length fields, so that the extern flag can be embedded in
1527
if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1528
field->fixed_len = 0;
1530
#if DICT_MAX_INDEX_COL_LEN != 768
1531
/* The comparison limit above must be constant. If it were
1532
changed, the disk format of some fixed-length columns would
1533
change, which would be a disaster. */
1534
# error "DICT_MAX_INDEX_COL_LEN != 768"
1537
if (!(col->prtype & DATA_NOT_NULL)) {
1538
index->n_nullable++;
1542
/***********************************************************************
1543
Copies fields contained in index2 to index1. */
1548
dict_index_t* index1, /* in: index to copy to */
1549
dict_index_t* index2, /* in: index to copy from */
1550
dict_table_t* table, /* in: table */
1551
ulint start, /* in: first position to copy */
1552
ulint end) /* in: last position to copy */
1554
dict_field_t* field;
1557
/* Copy fields contained in index2 */
1559
for (i = start; i < end; i++) {
1561
field = dict_index_get_nth_field(index2, i);
1562
dict_index_add_col(index1, table, field->col,
1567
/***********************************************************************
1568
Copies types of fields contained in index to tuple. */
1571
dict_index_copy_types(
1572
/*==================*/
1573
dtuple_t* tuple, /* in: data tuple */
1574
dict_index_t* index, /* in: index */
1575
ulint n_fields) /* in: number of field types to copy */
1579
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1580
dtuple_set_types_binary(tuple, n_fields);
1585
for (i = 0; i < n_fields; i++) {
1586
dict_field_t* ifield;
1587
dtype_t* dfield_type;
1589
ifield = dict_index_get_nth_field(index, i);
1590
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1591
dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1595
/***********************************************************************
1596
Copies types of columns contained in table to tuple. */
1599
dict_table_copy_types(
1600
/*==================*/
1601
dtuple_t* tuple, /* in: data tuple */
1602
dict_table_t* table) /* in: index */
1604
dtype_t* dfield_type;
1607
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1609
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1610
dict_col_copy_type(dict_table_get_nth_col(table, i),
1615
/***********************************************************************
1616
Builds the internal dictionary cache representation for a clustered
1617
index, containing also system fields not defined by the user. */
1620
dict_index_build_internal_clust(
1621
/*============================*/
1622
/* out, own: the internal representation
1623
of the clustered index */
1624
dict_table_t* table, /* in: table */
1625
dict_index_t* index) /* in: user representation of a clustered
1628
dict_index_t* new_index;
1629
dict_field_t* field;
1635
ut_ad(table && index);
1636
ut_ad(index->type & DICT_CLUSTERED);
1637
ut_ad(mutex_own(&(dict_sys->mutex)));
1638
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1640
/* Create a new index object with certainly enough fields */
1641
new_index = dict_mem_index_create(table->name,
1642
index->name, table->space,
1644
index->n_fields + table->n_cols);
1646
/* Copy other relevant data from the old index struct to the new
1647
struct: it inherits the values */
1649
new_index->n_user_defined_cols = index->n_fields;
1651
new_index->id = index->id;
1653
/* Copy the fields of index */
1654
dict_index_copy(new_index, index, table, 0, index->n_fields);
1656
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1657
/* No fixed number of fields determines an entry uniquely */
1659
new_index->n_uniq = REC_MAX_N_FIELDS;
1661
} else if (index->type & DICT_UNIQUE) {
1662
/* Only the fields defined so far are needed to identify
1663
the index entry uniquely */
1665
new_index->n_uniq = new_index->n_def;
1667
/* Also the row id is needed to identify the entry */
1668
new_index->n_uniq = 1 + new_index->n_def;
1671
new_index->trx_id_offset = 0;
1673
if (!(index->type & DICT_IBUF)) {
1674
/* Add system columns, trx id first */
1676
trx_id_pos = new_index->n_def;
1678
#if DATA_ROW_ID != 0
1679
# error "DATA_ROW_ID != 0"
1681
#if DATA_TRX_ID != 1
1682
# error "DATA_TRX_ID != 1"
1684
#if DATA_ROLL_PTR != 2
1685
# error "DATA_ROLL_PTR != 2"
1688
if (!(index->type & DICT_UNIQUE)) {
1689
dict_index_add_col(new_index, table, (dict_col_t*)
1690
dict_table_get_sys_col(
1691
table, DATA_ROW_ID),
1696
dict_index_add_col(new_index, table, (dict_col_t*)
1697
dict_table_get_sys_col(table, DATA_TRX_ID),
1700
dict_index_add_col(new_index, table, (dict_col_t*)
1701
dict_table_get_sys_col(table,
1705
for (i = 0; i < trx_id_pos; i++) {
1707
fixed_size = dict_col_get_fixed_size(
1708
dict_index_get_nth_col(new_index, i));
1710
if (fixed_size == 0) {
1711
new_index->trx_id_offset = 0;
1716
if (dict_index_get_nth_field(new_index, i)->prefix_len
1718
new_index->trx_id_offset = 0;
1723
new_index->trx_id_offset += (unsigned int) fixed_size;
1728
/* Remember the table columns already contained in new_index */
1729
indexed = mem_alloc(table->n_cols * sizeof *indexed);
1730
memset(indexed, 0, table->n_cols * sizeof *indexed);
1732
/* Mark with 0 the table columns already contained in new_index */
1733
for (i = 0; i < new_index->n_def; i++) {
1735
field = dict_index_get_nth_field(new_index, i);
1737
/* If there is only a prefix of the column in the index
1738
field, do not mark the column as contained in the index */
1740
if (field->prefix_len == 0) {
1742
indexed[field->col->ind] = TRUE;
1746
/* Add to new_index non-system columns of table not yet included
1748
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1750
dict_col_t* col = (dict_col_t*)
1751
dict_table_get_nth_col(table, i);
1752
ut_ad(col->mtype != DATA_SYS);
1754
if (!indexed[col->ind]) {
1755
dict_index_add_col(new_index, table, col, 0);
1761
ut_ad((index->type & DICT_IBUF)
1762
|| (UT_LIST_GET_LEN(table->indexes) == 0));
1764
new_index->cached = TRUE;
1769
/***********************************************************************
1770
Builds the internal dictionary cache representation for a non-clustered
1771
index, containing also system fields not defined by the user. */
1774
dict_index_build_internal_non_clust(
1775
/*================================*/
1776
/* out, own: the internal representation
1777
of the non-clustered index */
1778
dict_table_t* table, /* in: table */
1779
dict_index_t* index) /* in: user representation of a non-clustered
1782
dict_field_t* field;
1783
dict_index_t* new_index;
1784
dict_index_t* clust_index;
1788
ut_ad(table && index);
1789
ut_ad(0 == (index->type & DICT_CLUSTERED));
1790
ut_ad(mutex_own(&(dict_sys->mutex)));
1791
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1793
/* The clustered index should be the first in the list of indexes */
1794
clust_index = UT_LIST_GET_FIRST(table->indexes);
1797
ut_ad(clust_index->type & DICT_CLUSTERED);
1798
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
1800
/* Create a new index */
1801
new_index = dict_mem_index_create(
1802
table->name, index->name, index->space, index->type,
1803
index->n_fields + 1 + clust_index->n_uniq);
1805
/* Copy other relevant data from the old index
1806
struct to the new struct: it inherits the values */
1808
new_index->n_user_defined_cols = index->n_fields;
1810
new_index->id = index->id;
1812
/* Copy fields from index to new_index */
1813
dict_index_copy(new_index, index, table, 0, index->n_fields);
1815
/* Remember the table columns already contained in new_index */
1816
indexed = mem_alloc(table->n_cols * sizeof *indexed);
1817
memset(indexed, 0, table->n_cols * sizeof *indexed);
1819
/* Mark with 0 table columns already contained in new_index */
1820
for (i = 0; i < new_index->n_def; i++) {
1822
field = dict_index_get_nth_field(new_index, i);
1824
/* If there is only a prefix of the column in the index
1825
field, do not mark the column as contained in the index */
1827
if (field->prefix_len == 0) {
1829
indexed[field->col->ind] = TRUE;
1833
/* Add to new_index the columns necessary to determine the clustered
1834
index entry uniquely */
1836
for (i = 0; i < clust_index->n_uniq; i++) {
1838
field = dict_index_get_nth_field(clust_index, i);
1840
if (!indexed[field->col->ind]) {
1841
dict_index_add_col(new_index, table, field->col,
1848
if ((index->type) & DICT_UNIQUE) {
1849
new_index->n_uniq = index->n_fields;
1851
new_index->n_uniq = new_index->n_def;
1854
/* Set the n_fields value in new_index to the actual defined
1857
new_index->n_fields = new_index->n_def;
1859
new_index->cached = TRUE;
1864
/*====================== FOREIGN KEY PROCESSING ========================*/
1866
/*************************************************************************
1867
Checks if a table is referenced by foreign keys. */
1870
dict_table_referenced_by_foreign_key(
1871
/*=================================*/
1872
/* out: TRUE if table is referenced by a
1874
dict_table_t* table) /* in: InnoDB table */
1876
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
1884
/*************************************************************************
1885
Frees a foreign key struct. */
1890
dict_foreign_t* foreign) /* in, own: foreign key struct */
1892
mem_heap_free(foreign->heap);
1895
/**************************************************************************
1896
Removes a foreign constraint struct from the dictionary cache. */
1899
dict_foreign_remove_from_cache(
1900
/*===========================*/
1901
dict_foreign_t* foreign) /* in, own: foreign constraint */
1903
ut_ad(mutex_own(&(dict_sys->mutex)));
1906
if (foreign->referenced_table) {
1907
UT_LIST_REMOVE(referenced_list,
1908
foreign->referenced_table->referenced_list,
1912
if (foreign->foreign_table) {
1913
UT_LIST_REMOVE(foreign_list,
1914
foreign->foreign_table->foreign_list,
1918
dict_foreign_free(foreign);
1921
/**************************************************************************
1922
Looks for the foreign constraint from the foreign and referenced lists
1928
/* out: foreign constraint */
1929
dict_table_t* table, /* in: table object */
1930
const char* id) /* in: foreign constraint id */
1932
dict_foreign_t* foreign;
1934
ut_ad(mutex_own(&(dict_sys->mutex)));
1936
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1939
if (ut_strcmp(id, foreign->id) == 0) {
1944
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1947
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1950
if (ut_strcmp(id, foreign->id) == 0) {
1955
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1961
#ifndef UNIV_HOTBACKUP
1962
/*************************************************************************
1963
Tries to find an index whose first fields are the columns in the array,
1964
in the same order. */
1967
dict_foreign_find_index(
1968
/*====================*/
1969
/* out: matching index, NULL if not found */
1970
dict_table_t* table, /* in: table */
1971
const char** columns,/* in: array of column names */
1972
ulint n_cols, /* in: number of columns */
1973
dict_index_t* types_idx, /* in: NULL or an index to whose types the
1974
column types must match */
1975
ibool check_charsets,
1976
/* in: whether to check charsets.
1977
only has an effect if types_idx != NULL */
1979
/* in: nonzero if none of the columns must
1980
be declared NOT NULL */
1982
dict_index_t* index;
1983
dict_field_t* field;
1984
const char* col_name;
1987
index = dict_table_get_first_index(table);
1989
while (index != NULL) {
1990
if (dict_index_get_n_fields(index) >= n_cols) {
1992
for (i = 0; i < n_cols; i++) {
1993
field = dict_index_get_nth_field(index, i);
1995
col_name = dict_table_get_col_name(
1996
table, dict_col_get_no(field->col));
1998
if (field->prefix_len != 0) {
1999
/* We do not accept column prefix
2005
if (0 != innobase_strcasecmp(columns[i],
2011
&& (field->col->prtype & DATA_NOT_NULL)) {
2016
if (types_idx && !cmp_cols_are_equal(
2017
dict_index_get_nth_col(index, i),
2018
dict_index_get_nth_col(types_idx,
2027
/* We found a matching index */
2033
index = dict_table_get_next_index(index);
2039
/**************************************************************************
2040
Report an error in a foreign key definition. */
2043
dict_foreign_error_report_low(
2044
/*==========================*/
2045
FILE* file, /* in: output stream */
2046
const char* name) /* in: table name */
2049
ut_print_timestamp(file);
2050
fprintf(file, " Error in foreign key constraint of table %s:\n",
2054
/**************************************************************************
2055
Report an error in a foreign key definition. */
2058
dict_foreign_error_report(
2059
/*======================*/
2060
FILE* file, /* in: output stream */
2061
dict_foreign_t* fk, /* in: foreign key constraint */
2062
const char* msg) /* in: the error message */
2064
mutex_enter(&dict_foreign_err_mutex);
2065
dict_foreign_error_report_low(file, fk->foreign_table_name);
2067
fputs(" Constraint:\n", file);
2068
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2070
if (fk->foreign_index) {
2071
fputs("The index in the foreign key in table is ", file);
2072
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2074
"See http://dev.mysql.com/doc/refman/5.1/en/"
2075
"innodb-foreign-key-constraints.html\n"
2076
"for correct foreign key definition.\n",
2079
mutex_exit(&dict_foreign_err_mutex);
2082
/**************************************************************************
2083
Adds a foreign key constraint object to the dictionary cache. May free
2084
the object if there already is an object with the same identifier in.
2085
At least one of the foreign table and the referenced table must already
2086
be in the dictionary cache! */
2089
dict_foreign_add_to_cache(
2090
/*======================*/
2091
/* out: DB_SUCCESS or error code */
2092
dict_foreign_t* foreign, /* in, own: foreign key constraint */
2093
ibool check_charsets) /* in: TRUE=check charset
2096
dict_table_t* for_table;
2097
dict_table_t* ref_table;
2098
dict_foreign_t* for_in_cache = NULL;
2099
dict_index_t* index;
2100
ibool added_to_referenced_list= FALSE;
2101
FILE* ef = dict_foreign_err_file;
2103
ut_ad(mutex_own(&(dict_sys->mutex)));
2105
for_table = dict_table_check_if_in_cache_low(
2106
foreign->foreign_table_name);
2108
ref_table = dict_table_check_if_in_cache_low(
2109
foreign->referenced_table_name);
2110
ut_a(for_table || ref_table);
2113
for_in_cache = dict_foreign_find(for_table, foreign->id);
2116
if (!for_in_cache && ref_table) {
2117
for_in_cache = dict_foreign_find(ref_table, foreign->id);
2121
/* Free the foreign object */
2122
mem_heap_free(foreign->heap);
2124
for_in_cache = foreign;
2127
if (for_in_cache->referenced_table == NULL && ref_table) {
2128
index = dict_foreign_find_index(
2130
(const char**) for_in_cache->referenced_col_names,
2131
for_in_cache->n_fields, for_in_cache->foreign_index,
2132
check_charsets, FALSE);
2134
if (index == NULL) {
2135
dict_foreign_error_report(
2137
"there is no index in referenced table"
2138
" which would contain\n"
2139
"the columns as the first columns,"
2140
" or the data types in the\n"
2141
"referenced table do not match"
2142
" the ones in table.");
2144
if (for_in_cache == foreign) {
2145
mem_heap_free(foreign->heap);
2148
return(DB_FOREIGN_NO_INDEX);
2151
for_in_cache->referenced_table = ref_table;
2152
for_in_cache->referenced_index = index;
2153
UT_LIST_ADD_LAST(referenced_list,
2154
ref_table->referenced_list,
2156
added_to_referenced_list = TRUE;
2159
if (for_in_cache->foreign_table == NULL && for_table) {
2160
index = dict_foreign_find_index(
2162
(const char**) for_in_cache->foreign_col_names,
2163
for_in_cache->n_fields,
2164
for_in_cache->referenced_index, check_charsets,
2166
& (DICT_FOREIGN_ON_DELETE_SET_NULL
2167
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
2169
if (index == NULL) {
2170
dict_foreign_error_report(
2172
"there is no index in the table"
2173
" which would contain\n"
2174
"the columns as the first columns,"
2175
" or the data types in the\n"
2176
"table do not match"
2177
" the ones in the referenced table\n"
2178
"or one of the ON ... SET NULL columns"
2179
" is declared NOT NULL.");
2181
if (for_in_cache == foreign) {
2182
if (added_to_referenced_list) {
2185
ref_table->referenced_list,
2189
mem_heap_free(foreign->heap);
2192
return(DB_REFERENCING_NO_INDEX);
2195
for_in_cache->foreign_table = for_table;
2196
for_in_cache->foreign_index = index;
2197
UT_LIST_ADD_LAST(foreign_list,
2198
for_table->foreign_list,
2205
/*************************************************************************
2206
Scans from pointer onwards. Stops if is at the start of a copy of
2207
'string' where characters are compared without case sensitivity, and
2208
only outside `` or "" quotes. Stops also at '\0'. */
2213
/* out: scanned up to this */
2214
const char* ptr, /* in: scan from */
2215
const char* string) /* in: look for this */
2219
for (; *ptr; ptr++) {
2220
if (*ptr == quote) {
2221
/* Closing quote character: do not look for
2222
starting quote or the keyword. */
2225
/* Within quotes: do nothing. */
2226
} else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
2227
/* Starting quote: remember the quote character. */
2230
/* Outside quotes: look for the keyword. */
2232
for (i = 0; string[i]; i++) {
2233
if (toupper((int)(unsigned char)(ptr[i]))
2234
!= toupper((int)(unsigned char)
2248
/*************************************************************************
2249
Accepts a specified string. Comparisons are case-insensitive. */
2254
/* out: if string was accepted, the pointer
2255
is moved after that, else ptr is returned */
2256
struct charset_info_st* cs,/* in: the character set of ptr */
2257
const char* ptr, /* in: scan from this */
2258
const char* string, /* in: accept only this string as the next
2259
non-whitespace string */
2260
ibool* success)/* out: TRUE if accepted */
2262
const char* old_ptr = ptr;
2263
const char* old_ptr2;
2267
while (my_isspace(cs, *ptr)) {
2273
ptr = dict_scan_to(ptr, string);
2275
if (*ptr == '\0' || old_ptr2 != ptr) {
2281
return(ptr + ut_strlen(string));
2284
/*************************************************************************
2285
Scans an id. For the lexical definition of an 'id', see the code below.
2286
Strips backquotes or double quotes from around the id. */
2291
/* out: scanned to */
2292
struct charset_info_st* cs,/* in: the character set of ptr */
2293
const char* ptr, /* in: scanned to */
2294
mem_heap_t* heap, /* in: heap where to allocate the id
2295
(NULL=id will not be allocated, but it
2296
will point to string near ptr) */
2297
const char** id, /* out,own: the id; NULL if no id was
2299
ibool table_id,/* in: TRUE=convert the allocated id
2300
as a table name; FALSE=convert to UTF-8 */
2301
ibool accept_also_dot)
2302
/* in: TRUE if also a dot can appear in a
2303
non-quoted id; in a quoted id it can appear
2314
while (my_isspace(cs, *ptr)) {
2323
if (*ptr == '`' || *ptr == '"') {
2335
if (*ptr == quote) {
2337
if (*ptr != quote) {
2345
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2346
&& (accept_also_dot || *ptr != '.')
2347
&& *ptr != ',' && *ptr != '\0') {
2355
if (UNIV_UNLIKELY(!heap)) {
2356
/* no heap given: id will point to source string */
2363
str = d = mem_heap_alloc(heap, len + 1);
2365
if ((*d++ = *s++) == quote) {
2372
ut_ad(s + 1 == ptr);
2374
str = mem_heap_strdupl(heap, s, len);
2379
/* Convert the identifier from connection character set
2382
*id = dst = mem_heap_alloc(heap, len);
2384
innobase_convert_from_id(dst, str, len);
2385
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2386
sizeof srv_mysql50_table_name_prefix)) {
2387
/* This is a pre-5.1 table name
2388
containing chars other than [A-Za-z0-9].
2389
Discard the prefix and use raw UTF-8 encoding. */
2390
str += sizeof srv_mysql50_table_name_prefix;
2391
len -= sizeof srv_mysql50_table_name_prefix;
2394
/* Encode using filename-safe characters. */
2396
*id = dst = mem_heap_alloc(heap, len);
2398
innobase_convert_from_table_id(dst, str, len);
2404
/*************************************************************************
2405
Tries to scan a column name. */
2410
/* out: scanned to */
2411
struct charset_info_st* cs, /* in: the character set of ptr */
2412
const char* ptr, /* in: scanned to */
2413
ibool* success,/* out: TRUE if success */
2414
dict_table_t* table, /* in: table in which the column is */
2415
const dict_col_t** column, /* out: pointer to column if success */
2416
mem_heap_t* heap, /* in: heap where to allocate */
2417
const char** name) /* out,own: the column name;
2418
NULL if no name was scannable */
2424
ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2426
if (*name == NULL) {
2428
return(ptr); /* Syntax error */
2431
if (table == NULL) {
2435
for (i = 0; i < dict_table_get_n_cols(table); i++) {
2437
const char* col_name = dict_table_get_col_name(
2440
if (0 == innobase_strcasecmp(col_name, *name)) {
2444
*column = dict_table_get_nth_col(table, i);
2445
strcpy((char*) *name, col_name);
2455
/*************************************************************************
2456
Scans a table name from an SQL string. */
2459
dict_scan_table_name(
2460
/*=================*/
2461
/* out: scanned to */
2462
struct charset_info_st* cs,/* in: the character set of ptr */
2463
const char* ptr, /* in: scanned to */
2464
dict_table_t** table, /* out: table object or NULL */
2465
const char* name, /* in: foreign key table name */
2466
ibool* success,/* out: TRUE if ok name found */
2467
mem_heap_t* heap, /* in: heap where to allocate the id */
2468
const char** ref_name)/* out,own: the table name;
2469
NULL if no name was scannable */
2471
const char* database_name = NULL;
2472
ulint database_name_len = 0;
2473
const char* table_name = NULL;
2474
ulint table_name_len;
2475
const char* scan_name;
2481
ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2483
if (scan_name == NULL) {
2485
return(ptr); /* Syntax error */
2489
/* We scanned the database name; scan also the table name */
2493
database_name = scan_name;
2494
database_name_len = strlen(database_name);
2496
ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2498
if (table_name == NULL) {
2500
return(ptr); /* Syntax error */
2503
/* To be able to read table dumps made with InnoDB-4.0.17 or
2504
earlier, we must allow the dot separator between the database
2505
name and the table name also to appear within a quoted
2506
identifier! InnoDB used to print a constraint as:
2507
... REFERENCES `databasename.tablename` ...
2508
starting from 4.0.18 it is
2509
... REFERENCES `databasename`.`tablename` ... */
2512
for (s = scan_name; *s; s++) {
2514
database_name = scan_name;
2515
database_name_len = s - scan_name;
2517
break;/* to do: multiple dots? */
2521
table_name = scan_name;
2524
if (database_name == NULL) {
2525
/* Use the database name of the foreign key table */
2527
database_name = name;
2528
database_name_len = dict_get_db_name_len(name);
2531
table_name_len = strlen(table_name);
2533
/* Copy database_name, '/', table_name, '\0' */
2534
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2535
memcpy(ref, database_name, database_name_len);
2536
ref[database_name_len] = '/';
2537
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2539
if (srv_lower_case_table_names) {
2540
#endif /* !__WIN__ */
2541
/* The table name is always put to lower case on Windows. */
2542
innobase_casedn_str(ref);
2545
#endif /* !__WIN__ */
2549
*table = dict_table_get_low(ref);
2554
/*************************************************************************
2555
Skips one id. The id is allowed to contain also '.'. */
2560
/* out: scanned to */
2561
struct charset_info_st* cs,/* in: the character set of ptr */
2562
const char* ptr, /* in: scanned to */
2563
ibool* success)/* out: TRUE if success, FALSE if just spaces
2564
left in string or a syntax error */
2570
ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2579
/*************************************************************************
2580
Removes MySQL comments from an SQL string. A comment is either
2581
(a) '#' to the end of the line,
2582
(b) '--<space>' to the end of the line, or
2583
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
2584
C comment syntax). */
2587
dict_strip_comments(
2588
/*================*/
2589
/* out, own: SQL string stripped from
2590
comments; the caller must free this
2592
const char* sql_string, /* in: SQL string */
2593
size_t sql_length) /* in: length of sql_string */
2597
const char* eptr = sql_string + sql_length;
2599
/* unclosed quote character (0 if none) */
2602
str = mem_alloc(sql_length + 1);
2609
if (sptr >= eptr || *sptr == '\0') {
2613
ut_a(ptr <= str + sql_length);
2618
if (*sptr == quote) {
2619
/* Closing quote character: do not look for
2620
starting quote or comments. */
2623
/* Within quotes: do not look for
2624
starting quotes or comments. */
2625
} else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
2626
/* Starting quote: remember the quote character. */
2628
} else if (*sptr == '#'
2629
|| (sptr[0] == '-' && sptr[1] == '-'
2630
&& sptr[2] == ' ')) {
2632
if (++sptr >= eptr) {
2636
/* In Unix a newline is 0x0A while in Windows
2637
it is 0x0D followed by 0x0A */
2646
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
2657
if (sptr[1] == '/') {
2674
/*************************************************************************
2675
Finds the highest <number> for foreign key constraints of the table. Looks
2676
only at the >= 4.0.18-format id's, which are of the form
2677
databasename/tablename_ibfk_<number>. */
2680
dict_table_get_highest_foreign_id(
2681
/*==============================*/
2682
/* out: highest number, 0 if table has no new
2683
format foreign key constraints */
2684
dict_table_t* table) /* in: table in the dictionary memory cache */
2686
dict_foreign_t* foreign;
2688
ulint biggest_id = 0;
2694
len = ut_strlen(table->name);
2695
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2698
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
2699
&& 0 == ut_memcmp(foreign->id, table->name, len)
2700
&& 0 == ut_memcmp(foreign->id + len,
2701
dict_ibfk, (sizeof dict_ibfk) - 1)
2702
&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
2703
/* It is of the >= 4.0.18 format */
2705
id = strtoul(foreign->id + len
2706
+ ((sizeof dict_ibfk) - 1),
2708
if (*endp == '\0') {
2709
ut_a(id != biggest_id);
2711
if (id > biggest_id) {
2717
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2723
/*************************************************************************
2724
Reports a simple foreign key create clause syntax error. */
2727
dict_foreign_report_syntax_err(
2728
/*===========================*/
2729
const char* name, /* in: table name */
2730
const char* start_of_latest_foreign,
2731
/* in: start of the foreign key clause
2732
in the SQL string */
2733
const char* ptr) /* in: place of the syntax error */
2735
FILE* ef = dict_foreign_err_file;
2737
mutex_enter(&dict_foreign_err_mutex);
2738
dict_foreign_error_report_low(ef, name);
2739
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
2740
start_of_latest_foreign, ptr);
2741
mutex_exit(&dict_foreign_err_mutex);
2744
/*************************************************************************
2745
Scans a table create SQL string and adds to the data dictionary the foreign
2746
key constraints declared in the string. This function should be called after
2747
the indexes for a table have been created. Each foreign key constraint must
2748
be accompanied with indexes in both participating tables. The indexes are
2749
allowed to contain more fields than mentioned in the constraint. */
2752
dict_create_foreign_constraints_low(
2753
/*================================*/
2754
/* out: error code or DB_SUCCESS */
2755
trx_t* trx, /* in: transaction */
2756
mem_heap_t* heap, /* in: memory heap */
2757
struct charset_info_st* cs,/* in: the character set of sql_string */
2758
const char* sql_string,
2759
/* in: CREATE TABLE or ALTER TABLE statement
2760
where foreign keys are declared like:
2761
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2762
table2 can be written also with the database
2763
name before it: test.table2; the default
2764
database is the database of parameter name */
2765
const char* name, /* in: table full name in the normalized form
2766
database_name/table_name */
2768
/* in: if TRUE, fail with error code
2769
DB_CANNOT_ADD_CONSTRAINT if any foreign
2772
dict_table_t* table;
2773
dict_table_t* referenced_table;
2774
dict_table_t* table_to_alter;
2775
ulint highest_id_so_far = 0;
2776
dict_index_t* index;
2777
dict_foreign_t* foreign;
2778
const char* ptr = sql_string;
2779
const char* start_of_latest_foreign = sql_string;
2780
FILE* ef = dict_foreign_err_file;
2781
const char* constraint_name;
2791
const dict_col_t*columns[500];
2792
const char* column_names[500];
2793
const char* referenced_table_name;
2795
ut_ad(mutex_own(&(dict_sys->mutex)));
2797
table = dict_table_get_low(name);
2799
if (table == NULL) {
2800
mutex_enter(&dict_foreign_err_mutex);
2801
dict_foreign_error_report_low(ef, name);
2803
"Cannot find the table in the internal"
2804
" data dictionary of InnoDB.\n"
2805
"Create table statement:\n%s\n", sql_string);
2806
mutex_exit(&dict_foreign_err_mutex);
2811
/* First check if we are actually doing an ALTER TABLE, and in that
2812
case look for the table being altered */
2814
ptr = dict_accept(cs, ptr, "ALTER", &success);
2821
ptr = dict_accept(cs, ptr, "TABLE", &success);
2828
/* We are doing an ALTER TABLE: scan the table name we are altering */
2830
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
2831
&success, heap, &referenced_table_name);
2834
"InnoDB: Error: could not find"
2835
" the table being ALTERED in:\n%s\n",
2841
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
2842
format databasename/tablename_ibfk_<number>, where <number> is local
2843
to the table; look for the highest <number> for table_to_alter, so
2844
that we can assign to new constraints higher numbers. */
2846
/* If we are altering a temporary table, the table name after ALTER
2847
TABLE does not correspond to the internal table name, and
2848
table_to_alter is NULL. TODO: should we fix this somehow? */
2850
if (table_to_alter == NULL) {
2851
highest_id_so_far = 0;
2853
highest_id_so_far = dict_table_get_highest_foreign_id(
2857
/* Scan for foreign key declarations in a loop */
2859
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
2861
ptr1 = dict_scan_to(ptr, "CONSTRAINT");
2862
ptr2 = dict_scan_to(ptr, "FOREIGN");
2864
constraint_name = NULL;
2867
/* The user may have specified a constraint name. Pick it so
2868
that we can store 'databasename/constraintname' as the id of
2869
of the constraint to system tables. */
2872
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
2876
if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
2880
while (my_isspace(cs, *ptr)) {
2884
/* read constraint name unless got "CONSTRAINT FOREIGN" */
2886
ptr = dict_scan_id(cs, ptr, heap,
2887
&constraint_name, FALSE, FALSE);
2894
/* The proper way to reject foreign keys for temporary
2895
tables would be to split the lexing and syntactical
2896
analysis of foreign key clauses from the actual adding
2897
of them, so that ha_innodb.cc could first parse the SQL
2898
command, determine if there are any foreign keys, and
2899
if so, immediately reject the command if the table is a
2900
temporary one. For now, this kludge will work. */
2901
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
2903
return(DB_CANNOT_ADD_CONSTRAINT);
2906
/**********************************************************/
2907
/* The following call adds the foreign key constraints
2908
to the data dictionary system tables on disk */
2910
error = dict_create_add_foreigns_to_dictionary(
2911
highest_id_so_far, table, trx);
2915
start_of_latest_foreign = ptr;
2917
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
2923
if (!my_isspace(cs, *ptr)) {
2927
ptr = dict_accept(cs, ptr, "KEY", &success);
2933
ptr = dict_accept(cs, ptr, "(", &success);
2936
/* MySQL allows also an index id before the '('; we
2938
ptr = dict_skip_word(cs, ptr, &success);
2941
dict_foreign_report_syntax_err(
2942
name, start_of_latest_foreign, ptr);
2944
return(DB_CANNOT_ADD_CONSTRAINT);
2947
ptr = dict_accept(cs, ptr, "(", &success);
2950
/* We do not flag a syntax error here because in an
2951
ALTER TABLE we may also have DROP FOREIGN KEY abc */
2959
/* Scan the columns in the first list */
2961
ut_a(i < (sizeof column_names) / sizeof *column_names);
2962
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
2963
heap, column_names + i);
2965
mutex_enter(&dict_foreign_err_mutex);
2966
dict_foreign_error_report_low(ef, name);
2967
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
2968
start_of_latest_foreign, ptr);
2969
mutex_exit(&dict_foreign_err_mutex);
2971
return(DB_CANNOT_ADD_CONSTRAINT);
2976
ptr = dict_accept(cs, ptr, ",", &success);
2982
ptr = dict_accept(cs, ptr, ")", &success);
2985
dict_foreign_report_syntax_err(
2986
name, start_of_latest_foreign, ptr);
2987
return(DB_CANNOT_ADD_CONSTRAINT);
2990
/* Try to find an index which contains the columns
2991
as the first fields and in the right order */
2993
index = dict_foreign_find_index(table, column_names, i,
2997
mutex_enter(&dict_foreign_err_mutex);
2998
dict_foreign_error_report_low(ef, name);
2999
fputs("There is no index in table ", ef);
3000
ut_print_name(ef, NULL, TRUE, name);
3001
fprintf(ef, " where the columns appear\n"
3002
"as the first columns. Constraint:\n%s\n"
3003
"See http://dev.mysql.com/doc/refman/5.1/en/"
3004
"innodb-foreign-key-constraints.html\n"
3005
"for correct foreign key definition.\n",
3006
start_of_latest_foreign);
3007
mutex_exit(&dict_foreign_err_mutex);
3009
return(DB_CANNOT_ADD_CONSTRAINT);
3011
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3013
if (!success || !my_isspace(cs, *ptr)) {
3014
dict_foreign_report_syntax_err(
3015
name, start_of_latest_foreign, ptr);
3016
return(DB_CANNOT_ADD_CONSTRAINT);
3019
/* Let us create a constraint struct */
3021
foreign = dict_mem_foreign_create();
3023
if (constraint_name) {
3026
/* Catenate 'databasename/' to the constraint name specified
3027
by the user: we conceive the constraint as belonging to the
3028
same MySQL 'database' as the table itself. We store the name
3031
db_len = dict_get_db_name_len(table->name);
3033
foreign->id = mem_heap_alloc(
3034
foreign->heap, db_len + strlen(constraint_name) + 2);
3036
ut_memcpy(foreign->id, table->name, db_len);
3037
foreign->id[db_len] = '/';
3038
strcpy(foreign->id + db_len + 1, constraint_name);
3041
foreign->foreign_table = table;
3042
foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
3044
foreign->foreign_index = index;
3045
foreign->n_fields = (unsigned int) i;
3046
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3048
for (i = 0; i < foreign->n_fields; i++) {
3049
foreign->foreign_col_names[i] = mem_heap_strdup(
3051
dict_table_get_col_name(table,
3052
dict_col_get_no(columns[i])));
3055
ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3056
&success, heap, &referenced_table_name);
3058
/* Note that referenced_table can be NULL if the user has suppressed
3059
checking of foreign key constraints! */
3061
if (!success || (!referenced_table && trx->check_foreigns)) {
3062
dict_foreign_free(foreign);
3064
mutex_enter(&dict_foreign_err_mutex);
3065
dict_foreign_error_report_low(ef, name);
3066
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3068
start_of_latest_foreign, ptr);
3069
mutex_exit(&dict_foreign_err_mutex);
3071
return(DB_CANNOT_ADD_CONSTRAINT);
3074
ptr = dict_accept(cs, ptr, "(", &success);
3077
dict_foreign_free(foreign);
3078
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3080
return(DB_CANNOT_ADD_CONSTRAINT);
3083
/* Scan the columns in the second list */
3087
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3088
heap, column_names + i);
3092
dict_foreign_free(foreign);
3094
mutex_enter(&dict_foreign_err_mutex);
3095
dict_foreign_error_report_low(ef, name);
3096
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3098
start_of_latest_foreign, ptr);
3099
mutex_exit(&dict_foreign_err_mutex);
3101
return(DB_CANNOT_ADD_CONSTRAINT);
3104
ptr = dict_accept(cs, ptr, ",", &success);
3110
ptr = dict_accept(cs, ptr, ")", &success);
3112
if (!success || foreign->n_fields != i) {
3113
dict_foreign_free(foreign);
3115
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3117
return(DB_CANNOT_ADD_CONSTRAINT);
3124
/* Loop here as long as we can find ON ... conditions */
3126
ptr = dict_accept(cs, ptr, "ON", &success);
3130
goto try_find_index;
3133
ptr = dict_accept(cs, ptr, "DELETE", &success);
3136
ptr = dict_accept(cs, ptr, "UPDATE", &success);
3139
dict_foreign_free(foreign);
3141
dict_foreign_report_syntax_err(
3142
name, start_of_latest_foreign, ptr);
3143
return(DB_CANNOT_ADD_CONSTRAINT);
3146
is_on_delete = FALSE;
3149
is_on_delete = TRUE;
3153
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3156
goto scan_on_conditions;
3159
ptr = dict_accept(cs, ptr, "CASCADE", &success);
3163
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3165
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3168
goto scan_on_conditions;
3171
ptr = dict_accept(cs, ptr, "NO", &success);
3174
ptr = dict_accept(cs, ptr, "ACTION", &success);
3177
dict_foreign_free(foreign);
3178
dict_foreign_report_syntax_err(
3179
name, start_of_latest_foreign, ptr);
3181
return(DB_CANNOT_ADD_CONSTRAINT);
3185
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3187
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3190
goto scan_on_conditions;
3193
ptr = dict_accept(cs, ptr, "SET", &success);
3196
dict_foreign_free(foreign);
3197
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3199
return(DB_CANNOT_ADD_CONSTRAINT);
3202
ptr = dict_accept(cs, ptr, "NULL", &success);
3205
dict_foreign_free(foreign);
3206
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3208
return(DB_CANNOT_ADD_CONSTRAINT);
3211
for (j = 0; j < foreign->n_fields; j++) {
3212
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3215
/* It is not sensible to define SET NULL
3216
if the column is not allowed to be NULL! */
3218
dict_foreign_free(foreign);
3220
mutex_enter(&dict_foreign_err_mutex);
3221
dict_foreign_error_report_low(ef, name);
3223
"You have defined a SET NULL condition"
3224
" though some of the\n"
3225
"columns are defined as NOT NULL.\n",
3226
start_of_latest_foreign);
3227
mutex_exit(&dict_foreign_err_mutex);
3229
return(DB_CANNOT_ADD_CONSTRAINT);
3234
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3236
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3239
goto scan_on_conditions;
3242
if (n_on_deletes > 1 || n_on_updates > 1) {
3243
/* It is an error to define more than 1 action */
3245
dict_foreign_free(foreign);
3247
mutex_enter(&dict_foreign_err_mutex);
3248
dict_foreign_error_report_low(ef, name);
3250
"You have twice an ON DELETE clause"
3251
" or twice an ON UPDATE clause.\n",
3252
start_of_latest_foreign);
3253
mutex_exit(&dict_foreign_err_mutex);
3255
return(DB_CANNOT_ADD_CONSTRAINT);
3258
/* Try to find an index which contains the columns as the first fields
3259
and in the right order, and the types are the same as in
3260
foreign->foreign_index */
3262
if (referenced_table) {
3263
index = dict_foreign_find_index(referenced_table,
3265
foreign->foreign_index,
3268
dict_foreign_free(foreign);
3269
mutex_enter(&dict_foreign_err_mutex);
3270
dict_foreign_error_report_low(ef, name);
3272
"Cannot find an index in the"
3273
" referenced table where the\n"
3274
"referenced columns appear as the"
3275
" first columns, or column types\n"
3276
"in the table and the referenced table"
3277
" do not match for constraint.\n"
3278
"Note that the internal storage type of"
3279
" ENUM and SET changed in\n"
3280
"tables created with >= InnoDB-4.1.12,"
3281
" and such columns in old tables\n"
3282
"cannot be referenced by such columns"
3284
"See http://dev.mysql.com/doc/refman/5.1/en/"
3285
"innodb-foreign-key-constraints.html\n"
3286
"for correct foreign key definition.\n",
3287
start_of_latest_foreign);
3288
mutex_exit(&dict_foreign_err_mutex);
3290
return(DB_CANNOT_ADD_CONSTRAINT);
3293
ut_a(trx->check_foreigns == FALSE);
3297
foreign->referenced_index = index;
3298
foreign->referenced_table = referenced_table;
3300
foreign->referenced_table_name
3301
= mem_heap_strdup(foreign->heap, referenced_table_name);
3303
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3305
for (i = 0; i < foreign->n_fields; i++) {
3306
foreign->referenced_col_names[i]
3307
= mem_heap_strdup(foreign->heap, column_names[i]);
3310
/* We found an ok constraint definition: add to the lists */
3312
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3314
if (referenced_table) {
3315
UT_LIST_ADD_LAST(referenced_list,
3316
referenced_table->referenced_list,
3323
/**************************************************************************
3324
Determines whether a string starts with the specified keyword. */
3327
dict_str_starts_with_keyword(
3328
/*=========================*/
3329
/* out: TRUE if str starts
3331
void* mysql_thd, /* in: MySQL thread handle */
3332
const char* str, /* in: string to scan for keyword */
3333
const char* keyword) /* in: keyword to look for */
3335
struct charset_info_st* cs = innobase_get_charset(mysql_thd);
3338
dict_accept(cs, str, keyword, &success);
3342
/*************************************************************************
3343
Scans a table create SQL string and adds to the data dictionary the foreign
3344
key constraints declared in the string. This function should be called after
3345
the indexes for a table have been created. Each foreign key constraint must
3346
be accompanied with indexes in both participating tables. The indexes are
3347
allowed to contain more fields than mentioned in the constraint. */
3350
dict_create_foreign_constraints(
3351
/*============================*/
3352
/* out: error code or DB_SUCCESS */
3353
trx_t* trx, /* in: transaction */
3354
const char* sql_string, /* in: table create statement where
3355
foreign keys are declared like:
3356
FOREIGN KEY (a, b) REFERENCES
3357
table2(c, d), table2 can be written
3358
also with the database
3359
name before it: test.table2; the
3360
default database id the database of
3362
size_t sql_length, /* in: length of sql_string */
3363
const char* name, /* in: table full name in the
3365
database_name/table_name */
3366
ibool reject_fks) /* in: if TRUE, fail with error
3367
code DB_CANNOT_ADD_CONSTRAINT if
3368
any foreign keys are found. */
3375
ut_a(trx->mysql_thd);
3377
str = dict_strip_comments(sql_string, sql_length);
3378
heap = mem_heap_create(10000);
3380
err = dict_create_foreign_constraints_low(
3381
trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3384
mem_heap_free(heap);
3390
/**************************************************************************
3391
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3394
dict_foreign_parse_drop_constraints(
3395
/*================================*/
3396
/* out: DB_SUCCESS or
3397
DB_CANNOT_DROP_CONSTRAINT if
3398
syntax error or the constraint
3399
id does not match */
3400
mem_heap_t* heap, /* in: heap from which we can
3402
trx_t* trx, /* in: transaction */
3403
dict_table_t* table, /* in: table */
3404
ulint* n, /* out: number of constraints
3406
const char*** constraints_to_drop) /* out: id's of the
3407
constraints to drop */
3409
dict_foreign_t* foreign;
3414
FILE* ef = dict_foreign_err_file;
3415
struct charset_info_st* cs;
3418
ut_a(trx->mysql_thd);
3420
cs = innobase_get_charset(trx->mysql_thd);
3424
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3426
str = dict_strip_comments(*trx->mysql_query_str,
3427
*trx->mysql_query_len);
3430
ut_ad(mutex_own(&(dict_sys->mutex)));
3432
ptr = dict_scan_to(ptr, "DROP");
3440
ptr = dict_accept(cs, ptr, "DROP", &success);
3442
if (!my_isspace(cs, *ptr)) {
3447
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3449
if (!success || !my_isspace(cs, *ptr)) {
3454
ptr = dict_accept(cs, ptr, "KEY", &success);
3461
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3469
(*constraints_to_drop)[*n] = id;
3472
/* Look for the given constraint id */
3474
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3476
while (foreign != NULL) {
3477
if (0 == strcmp(foreign->id, id)
3478
|| (strchr(foreign->id, '/')
3480
dict_remove_db_name(foreign->id)))) {
3485
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3488
if (foreign == NULL) {
3489
mutex_enter(&dict_foreign_err_mutex);
3491
ut_print_timestamp(ef);
3492
fputs(" Error in dropping of a foreign key constraint"
3494
ut_print_name(ef, NULL, TRUE, table->name);
3496
"in SQL command\n", ef);
3498
fputs("\nCannot find a constraint with the given id ", ef);
3499
ut_print_name(ef, NULL, FALSE, id);
3501
mutex_exit(&dict_foreign_err_mutex);
3505
return(DB_CANNOT_DROP_CONSTRAINT);
3511
mutex_enter(&dict_foreign_err_mutex);
3513
ut_print_timestamp(ef);
3514
fputs(" Syntax error in dropping of a"
3515
" foreign key constraint of table ", ef);
3516
ut_print_name(ef, NULL, TRUE, table->name);
3518
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
3519
mutex_exit(&dict_foreign_err_mutex);
3523
return(DB_CANNOT_DROP_CONSTRAINT);
3525
#endif /* UNIV_HOTBACKUP */
3527
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3530
/**************************************************************************
3531
Returns an index object if it is found in the dictionary cache. */
3534
dict_index_get_if_in_cache(
3535
/*=======================*/
3536
/* out: index, NULL if not found */
3537
dulint index_id) /* in: index id */
3539
dict_index_t* index;
3541
if (dict_sys == NULL) {
3545
mutex_enter(&(dict_sys->mutex));
3547
index = dict_index_find_on_id_low(index_id);
3549
mutex_exit(&(dict_sys->mutex));
3553
#endif /* UNIV_DEBUG */
3556
/**************************************************************************
3557
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3558
no comparison can occur with the page number field in a node pointer. */
3561
dict_index_check_search_tuple(
3562
/*==========================*/
3563
/* out: TRUE if ok */
3564
dict_index_t* index, /* in: index tree */
3565
dtuple_t* tuple) /* in: tuple used in a search */
3568
ut_a(dtuple_get_n_fields_cmp(tuple)
3569
<= dict_index_get_n_unique_in_tree(index));
3572
#endif /* UNIV_DEBUG */
3574
/**************************************************************************
3575
Builds a node pointer out of a physical record and a page number. */
3578
dict_index_build_node_ptr(
3579
/*======================*/
3580
/* out, own: node pointer */
3581
dict_index_t* index, /* in: index tree */
3582
rec_t* rec, /* in: record for which to build node
3584
ulint page_no,/* in: page number to put in node pointer */
3585
mem_heap_t* heap, /* in: memory heap where pointer created */
3586
ulint level) /* in: level of rec in tree: 0 means leaf
3594
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3595
/* In a universal index tree, we take the whole record as
3596
the node pointer if the record is on the leaf level,
3597
on non-leaf levels we remove the last field, which
3598
contains the page number of the child page */
3600
ut_a(!dict_table_is_comp(index->table));
3601
n_unique = rec_get_n_fields_old(rec);
3608
n_unique = dict_index_get_n_unique_in_tree(index);
3611
tuple = dtuple_create(heap, n_unique + 1);
3613
/* When searching in the tree for the node pointer, we must not do
3614
comparison on the last field, the page number field, as on upper
3615
levels in the tree there may be identical node pointers with a
3616
different page number; therefore, we set the n_fields_cmp to one
3619
dtuple_set_n_fields_cmp(tuple, n_unique);
3621
dict_index_copy_types(tuple, index, n_unique);
3623
buf = mem_heap_alloc(heap, 4);
3625
mach_write_to_4(buf, page_no);
3627
field = dtuple_get_nth_field(tuple, n_unique);
3628
dfield_set_data(field, buf, 4);
3630
dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3632
rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3633
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3634
| REC_STATUS_NODE_PTR);
3636
ut_ad(dtuple_check_typed(tuple));
3641
/**************************************************************************
3642
Copies an initial segment of a physical record, long enough to specify an
3643
index entry uniquely. */
3646
dict_index_copy_rec_order_prefix(
3647
/*=============================*/
3648
/* out: pointer to the prefix record */
3649
dict_index_t* index, /* in: index tree */
3650
rec_t* rec, /* in: record for which to copy prefix */
3651
ulint* n_fields,/* out: number of fields copied */
3652
byte** buf, /* in/out: memory buffer for the copied prefix,
3654
ulint* buf_size)/* in/out: buffer size */
3658
UNIV_PREFETCH_R(rec);
3660
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3661
ut_a(!dict_table_is_comp(index->table));
3662
n = rec_get_n_fields_old(rec);
3664
n = dict_index_get_n_unique_in_tree(index);
3668
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
3671
/**************************************************************************
3672
Builds a typed data tuple out of a physical record. */
3675
dict_index_build_data_tuple(
3676
/*========================*/
3677
/* out, own: data tuple */
3678
dict_index_t* index, /* in: index tree */
3679
rec_t* rec, /* in: record for which to build data tuple */
3680
ulint n_fields,/* in: number of data fields */
3681
mem_heap_t* heap) /* in: memory heap where tuple created */
3685
ut_ad(dict_table_is_comp(index->table)
3686
|| n_fields <= rec_get_n_fields_old(rec));
3688
tuple = dtuple_create(heap, n_fields);
3690
dict_index_copy_types(tuple, index, n_fields);
3692
rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
3694
ut_ad(dtuple_check_typed(tuple));
3699
/*************************************************************************
3700
Calculates the minimum record length in an index. */
3703
dict_index_calc_min_rec_len(
3704
/*========================*/
3705
dict_index_t* index) /* in: index */
3710
if (dict_table_is_comp(index->table)) {
3712
sum = REC_N_NEW_EXTRA_BYTES;
3713
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3714
const dict_col_t* col
3715
= dict_index_get_nth_col(index, i);
3716
ulint size = dict_col_get_fixed_size(col);
3720
sum += size < 128 ? 1 : 2;
3722
if (!(col->prtype & DATA_NOT_NULL)) {
3727
/* round the NULL flags up to full bytes */
3728
sum += UT_BITS_IN_BYTES(nullable);
3733
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3734
sum += dict_col_get_fixed_size(
3735
dict_index_get_nth_col(index, i));
3739
sum += 2 * dict_index_get_n_fields(index);
3741
sum += dict_index_get_n_fields(index);
3744
sum += REC_N_OLD_EXTRA_BYTES;
3749
/*************************************************************************
3750
Calculates new estimates for table and index statistics. The statistics
3751
are used in query optimization. */
3754
dict_update_statistics_low(
3755
/*=======================*/
3756
dict_table_t* table, /* in: table */
3757
ibool has_dict_mutex __attribute__((unused)))
3758
/* in: TRUE if the caller has the
3761
dict_index_t* index;
3762
ulint sum_of_index_sizes = 0;
3764
if (table->ibd_file_missing) {
3765
ut_print_timestamp(stderr);
3767
" InnoDB: cannot calculate statistics for table %s\n"
3768
"InnoDB: because the .ibd file is missing. For help,"
3769
" please refer to\n"
3770
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3771
"innodb-troubleshooting.html\n",
3777
/* Find out the sizes of the indexes and how many different values
3778
for the key they approximately have */
3780
index = dict_table_get_first_index(table);
3782
if (index == NULL) {
3783
/* Table definition is corrupt */
3791
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
3792
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
3793
&& (index->type & DICT_CLUSTERED)))) {
3795
size = btr_get_size(index, BTR_TOTAL_SIZE);
3797
index->stat_index_size = size;
3799
sum_of_index_sizes += size;
3801
size = btr_get_size(index, BTR_N_LEAF_PAGES);
3804
/* The root node of the tree is a leaf */
3808
index->stat_n_leaf_pages = size;
3810
btr_estimate_number_of_different_key_vals(index);
3812
/* If we have set a high innodb_force_recovery
3813
level, do not calculate statistics, as a badly
3814
corrupted index can cause a crash in it.
3815
Initialize some bogus index cardinality
3816
statistics, so that the data can be queried in
3817
various means, also via secondary indexes. */
3820
sum_of_index_sizes++;
3821
index->stat_index_size = index->stat_n_leaf_pages = 1;
3823
for (i = dict_index_get_n_unique(index); i; ) {
3824
index->stat_n_diff_key_vals[i--] = 1;
3827
memset(index->stat_n_non_null_key_vals, 0,
3828
(1 + dict_index_get_n_unique(index))
3829
* sizeof(*index->stat_n_non_null_key_vals));
3832
index = dict_table_get_next_index(index);
3835
index = dict_table_get_first_index(table);
3837
table->stat_n_rows = index->stat_n_diff_key_vals[
3838
dict_index_get_n_unique(index)];
3840
table->stat_clustered_index_size = index->stat_index_size;
3842
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
3843
- index->stat_index_size;
3845
table->stat_initialized = TRUE;
3847
table->stat_modified_counter = 0;
3850
/*************************************************************************
3851
Calculates new estimates for table and index statistics. The statistics
3852
are used in query optimization. */
3855
dict_update_statistics(
3856
/*===================*/
3857
dict_table_t* table) /* in: table */
3859
dict_update_statistics_low(table, FALSE);
3862
/**************************************************************************
3863
A noninlined version of dict_table_get_low. */
3866
dict_table_get_low_noninlined(
3867
/*==========================*/
3868
/* out: table, NULL if not found */
3869
const char* table_name) /* in: table name */
3871
return(dict_table_get_low(table_name));
3874
/**************************************************************************
3875
Prints info of a foreign key constraint. */
3878
dict_foreign_print_low(
3879
/*===================*/
3880
dict_foreign_t* foreign) /* in: foreign key constraint */
3884
ut_ad(mutex_own(&(dict_sys->mutex)));
3886
fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
3887
foreign->id, foreign->foreign_table_name);
3889
for (i = 0; i < foreign->n_fields; i++) {
3890
fprintf(stderr, " %s", foreign->foreign_col_names[i]);
3893
fprintf(stderr, " )\n"
3895
foreign->referenced_table_name);
3897
for (i = 0; i < foreign->n_fields; i++) {
3898
fprintf(stderr, " %s", foreign->referenced_col_names[i]);
3901
fputs(" )\n", stderr);
3904
/**************************************************************************
3905
Prints a table data. */
3910
dict_table_t* table) /* in: table */
3912
mutex_enter(&(dict_sys->mutex));
3913
dict_table_print_low(table);
3914
mutex_exit(&(dict_sys->mutex));
3917
/**************************************************************************
3918
Prints a table data when we know the table name. */
3921
dict_table_print_by_name(
3922
/*=====================*/
3925
dict_table_t* table;
3927
mutex_enter(&(dict_sys->mutex));
3929
table = dict_table_get_low(name);
3933
dict_table_print_low(table);
3934
mutex_exit(&(dict_sys->mutex));
3937
/**************************************************************************
3938
Prints a table data. */
3941
dict_table_print_low(
3942
/*=================*/
3943
dict_table_t* table) /* in: table */
3945
dict_index_t* index;
3946
dict_foreign_t* foreign;
3949
ut_ad(mutex_own(&(dict_sys->mutex)));
3951
dict_update_statistics_low(table, TRUE);
3954
"--------------------------------------\n"
3955
"TABLE: name %s, id %lu %lu, columns %lu, indexes %lu,"
3959
(ulong) ut_dulint_get_high(table->id),
3960
(ulong) ut_dulint_get_low(table->id),
3961
(ulong) table->n_cols,
3962
(ulong) UT_LIST_GET_LEN(table->indexes),
3963
(ulong) table->stat_n_rows);
3965
for (i = 0; i < (ulint) table->n_cols; i++) {
3966
dict_col_print_low(table, dict_table_get_nth_col(table, i));
3967
fputs("; ", stderr);
3972
index = UT_LIST_GET_FIRST(table->indexes);
3974
while (index != NULL) {
3975
dict_index_print_low(index);
3976
index = UT_LIST_GET_NEXT(indexes, index);
3979
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3981
while (foreign != NULL) {
3982
dict_foreign_print_low(foreign);
3983
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3986
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3988
while (foreign != NULL) {
3989
dict_foreign_print_low(foreign);
3990
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3994
/**************************************************************************
3995
Prints a column data. */
4000
const dict_table_t* table, /* in: table */
4001
const dict_col_t* col) /* in: column */
4005
ut_ad(mutex_own(&(dict_sys->mutex)));
4007
dict_col_copy_type(col, &type);
4008
fprintf(stderr, "%s: ", dict_table_get_col_name(table,
4009
dict_col_get_no(col)));
4014
/**************************************************************************
4015
Prints an index data. */
4018
dict_index_print_low(
4019
/*=================*/
4020
dict_index_t* index) /* in: index */
4025
ut_ad(mutex_own(&(dict_sys->mutex)));
4027
if (index->n_user_defined_cols > 0) {
4028
n_vals = index->stat_n_diff_key_vals[
4029
index->n_user_defined_cols];
4031
n_vals = index->stat_n_diff_key_vals[1];
4035
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
4036
" uniq %lu, type %lu\n"
4037
" root page %lu, appr.key vals %lu,"
4038
" leaf pages %lu, size pages %lu\n"
4041
(ulong) ut_dulint_get_high(index->id),
4042
(ulong) ut_dulint_get_low(index->id),
4043
(ulong) index->n_user_defined_cols,
4044
(ulong) index->n_fields,
4045
(ulong) index->n_uniq,
4046
(ulong) index->type,
4047
(ulong) index->page,
4049
(ulong) index->stat_n_leaf_pages,
4050
(ulong) index->stat_index_size);
4052
for (i = 0; i < index->n_fields; i++) {
4053
dict_field_print_low(dict_index_get_nth_field(index, i));
4058
#ifdef UNIV_BTR_PRINT
4059
btr_print_size(index);
4061
btr_print_index(index, 7);
4062
#endif /* UNIV_BTR_PRINT */
4065
/**************************************************************************
4066
Prints a field data. */
4069
dict_field_print_low(
4070
/*=================*/
4071
dict_field_t* field) /* in: field */
4073
ut_ad(mutex_own(&(dict_sys->mutex)));
4075
fprintf(stderr, " %s", field->name);
4077
if (field->prefix_len != 0) {
4078
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4082
/**************************************************************************
4083
Outputs info on a foreign key of a table in a format suitable for
4087
dict_print_info_on_foreign_key_in_create_format(
4088
/*============================================*/
4089
FILE* file, /* in: file where to print */
4090
trx_t* trx, /* in: transaction */
4091
dict_foreign_t* foreign, /* in: foreign key constraint */
4092
ibool add_newline) /* in: whether to add a newline */
4094
const char* stripped_id;
4097
if (strchr(foreign->id, '/')) {
4098
/* Strip the preceding database name from the constraint id */
4099
stripped_id = foreign->id + 1
4100
+ dict_get_db_name_len(foreign->id);
4102
stripped_id = foreign->id;
4108
/* SHOW CREATE TABLE wants constraints each printed nicely
4109
on its own line, while error messages want no newlines
4114
fputs(" CONSTRAINT ", file);
4115
ut_print_name(file, trx, FALSE, stripped_id);
4116
fputs(" FOREIGN KEY (", file);
4119
ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4120
if (++i < foreign->n_fields) {
4127
fputs(") REFERENCES ", file);
4129
if (dict_tables_have_same_db(foreign->foreign_table_name,
4130
foreign->referenced_table_name)) {
4131
/* Do not print the database name of the referenced table */
4132
ut_print_name(file, trx, TRUE,
4133
dict_remove_db_name(
4134
foreign->referenced_table_name));
4136
ut_print_name(file, trx, TRUE,
4137
foreign->referenced_table_name);
4144
ut_print_name(file, trx, FALSE,
4145
foreign->referenced_col_names[i]);
4146
if (++i < foreign->n_fields) {
4155
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4156
fputs(" ON DELETE CASCADE", file);
4159
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4160
fputs(" ON DELETE SET NULL", file);
4163
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4164
fputs(" ON DELETE NO ACTION", file);
4167
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4168
fputs(" ON UPDATE CASCADE", file);
4171
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4172
fputs(" ON UPDATE SET NULL", file);
4175
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4176
fputs(" ON UPDATE NO ACTION", file);
4180
/**************************************************************************
4181
Outputs info on foreign keys of a table. */
4184
dict_print_info_on_foreign_keys(
4185
/*============================*/
4186
ibool create_table_format, /* in: if TRUE then print in
4187
a format suitable to be inserted into
4188
a CREATE TABLE, otherwise in the format
4189
of SHOW TABLE STATUS */
4190
FILE* file, /* in: file where to print */
4191
trx_t* trx, /* in: transaction */
4192
dict_table_t* table) /* in: table */
4194
dict_foreign_t* foreign;
4196
mutex_enter(&(dict_sys->mutex));
4198
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4200
if (foreign == NULL) {
4201
mutex_exit(&(dict_sys->mutex));
4206
while (foreign != NULL) {
4207
if (create_table_format) {
4208
dict_print_info_on_foreign_key_in_create_format(
4209
file, trx, foreign, TRUE);
4214
for (i = 0; i < foreign->n_fields; i++) {
4219
ut_print_name(file, trx, FALSE,
4220
foreign->foreign_col_names[i]);
4223
fputs(") REFER ", file);
4224
ut_print_name(file, trx, TRUE,
4225
foreign->referenced_table_name);
4228
for (i = 0; i < foreign->n_fields; i++) {
4234
foreign->referenced_col_names[i]);
4239
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4240
fputs(" ON DELETE CASCADE", file);
4243
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4244
fputs(" ON DELETE SET NULL", file);
4247
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4248
fputs(" ON DELETE NO ACTION", file);
4251
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4252
fputs(" ON UPDATE CASCADE", file);
4255
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4256
fputs(" ON UPDATE SET NULL", file);
4259
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4260
fputs(" ON UPDATE NO ACTION", file);
4264
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4267
mutex_exit(&(dict_sys->mutex));
4270
/************************************************************************
4271
Displays the names of the index and the table. */
4273
dict_index_name_print(
4274
/*==================*/
4275
FILE* file, /* in: output stream */
4276
trx_t* trx, /* in: transaction */
4277
const dict_index_t* index) /* in: index to print */
4279
fputs("index ", file);
4280
ut_print_name(file, trx, FALSE, index->name);
4281
fputs(" of table ", file);
4282
ut_print_name(file, trx, TRUE, index->table_name);