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 <mystrings/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_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
50
hash table fixed size in bytes */
52
/* Identifies generated InnoDB foreign key names */
53
static char dict_ibfk[] = "_ibfk_";
55
#ifndef UNIV_HOTBACKUP
56
/**********************************************************************
57
Converts an identifier to a table name.
59
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
60
this function, you MUST change also the prototype here! */
63
innobase_convert_from_table_id(
64
/*===========================*/
65
char* to, /* out: converted identifier */
66
const char* from, /* in: identifier to convert */
67
ulint len); /* in: length of 'to', in bytes;
68
should be at least 5 * strlen(to) + 1 */
69
/**********************************************************************
70
Converts an identifier to UTF-8.
72
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
73
this function, you MUST change also the prototype here! */
76
innobase_convert_from_id(
77
/*=====================*/
78
char* to, /* out: converted identifier */
79
const char* from, /* in: identifier to convert */
80
ulint len); /* in: length of 'to', in bytes;
81
should be at least 3 * strlen(to) + 1 */
82
/**********************************************************************
83
Compares NUL-terminated UTF-8 strings case insensitively.
85
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
86
this function, you MUST change also the prototype here! */
91
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
92
const char* a, /* in: first string to compare */
93
const char* b); /* in: second string to compare */
95
/**********************************************************************
96
Makes all characters in a NUL-terminated UTF-8 string lower case.
98
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
99
this function, you MUST change also the prototype here! */
104
char* a); /* in/out: string to put in lower case */
106
/**************************************************************************
107
Determines the connection character set.
109
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
110
this function, you MUST change also the prototype here! */
111
struct charset_info_st*
112
innobase_get_charset(
113
/*=================*/
114
/* out: connection character set */
115
void* mysql_session); /* in: MySQL thread handle */
116
#endif /* !UNIV_HOTBACKUP */
118
/**************************************************************************
119
Removes an index from the dictionary cache. */
122
dict_index_remove_from_cache(
123
/*=========================*/
124
dict_table_t* table, /* in: table */
125
dict_index_t* index); /* in, own: index */
126
/***********************************************************************
127
Copies fields contained in index2 to index1. */
132
dict_index_t* index1, /* in: index to copy to */
133
dict_index_t* index2, /* in: index to copy from */
134
dict_table_t* table, /* in: table */
135
ulint start, /* in: first position to copy */
136
ulint end); /* in: last position to copy */
137
/***********************************************************************
138
Tries to find column names for the index and sets the col field of the
142
dict_index_find_cols(
143
/*=================*/
144
dict_table_t* table, /* in: table */
145
dict_index_t* index); /* in: index */
146
/***********************************************************************
147
Builds the internal dictionary cache representation for a clustered
148
index, containing also system fields not defined by the user. */
151
dict_index_build_internal_clust(
152
/*============================*/
153
/* out, own: the internal representation
154
of the clustered index */
155
dict_table_t* table, /* in: table */
156
dict_index_t* index); /* in: user representation of a clustered
158
/***********************************************************************
159
Builds the internal dictionary cache representation for a non-clustered
160
index, containing also system fields not defined by the user. */
163
dict_index_build_internal_non_clust(
164
/*================================*/
165
/* out, own: the internal representation
166
of the non-clustered index */
167
dict_table_t* table, /* in: table */
168
dict_index_t* index); /* in: user representation of a non-clustered
170
/**************************************************************************
171
Removes a foreign constraint struct from the dictionary cache. */
174
dict_foreign_remove_from_cache(
175
/*===========================*/
176
dict_foreign_t* foreign); /* in, own: foreign constraint */
177
/**************************************************************************
178
Prints a column data. */
183
const dict_table_t* table, /* in: table */
184
const dict_col_t* col); /* in: column */
185
/**************************************************************************
186
Prints an index data. */
189
dict_index_print_low(
190
/*=================*/
191
dict_index_t* index); /* in: index */
192
/**************************************************************************
193
Prints a field data. */
196
dict_field_print_low(
197
/*=================*/
198
dict_field_t* field); /* in: field */
199
/*************************************************************************
200
Frees a foreign key struct. */
205
dict_foreign_t* foreign); /* in, own: foreign key struct */
207
/* Stream for storing detailed information about the latest foreign key
208
and unique key errors */
209
FILE* dict_foreign_err_file = NULL;
210
mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign
211
and unique error buffers */
213
#ifndef UNIV_HOTBACKUP
214
/**********************************************************************
215
Makes all characters in a NUL-terminated UTF-8 string lower case. */
220
char* a) /* in/out: string to put in lower case */
222
innobase_casedn_str(a);
224
#endif /* !UNIV_HOTBACKUP */
226
/************************************************************************
227
Checks if the database name in two table names is the same. */
230
dict_tables_have_same_db(
231
/*=====================*/
232
/* out: TRUE if same db name */
233
const char* name1, /* in: table name in the form
234
dbname '/' tablename */
235
const char* name2) /* in: table name in the form
236
dbname '/' tablename */
238
for (; *name1 == *name2; name1++, name2++) {
242
ut_a(*name1); /* the names must contain '/' */
247
/************************************************************************
248
Return the end of table name where we have removed dbname and '/'. */
253
/* out: table name */
254
const char* name) /* in: table name in the form
255
dbname '/' tablename */
257
const char* s = strchr(name, '/');
263
/************************************************************************
264
Get the database name length in a table name. */
267
dict_get_db_name_len(
268
/*=================*/
269
/* out: database name length */
270
const char* name) /* in: table name in the form
271
dbname '/' tablename */
274
s = strchr(name, '/');
279
/************************************************************************
280
Reserves the dictionary system mutex for MySQL. */
283
dict_mutex_enter_for_mysql(void)
284
/*============================*/
286
mutex_enter(&(dict_sys->mutex));
289
/************************************************************************
290
Releases the dictionary system mutex for MySQL. */
293
dict_mutex_exit_for_mysql(void)
294
/*===========================*/
296
mutex_exit(&(dict_sys->mutex));
299
/************************************************************************
300
Decrements the count of open MySQL handles to a table. */
303
dict_table_decrement_handle_count(
304
/*==============================*/
305
dict_table_t* table) /* in: table */
307
mutex_enter(&(dict_sys->mutex));
309
ut_a(table->n_mysql_handles_opened > 0);
311
table->n_mysql_handles_opened--;
313
mutex_exit(&(dict_sys->mutex));
316
/*************************************************************************
317
Gets the column data type. */
320
dict_col_copy_type_noninline(
321
/*=========================*/
322
const dict_col_t* col, /* in: column */
323
dtype_t* type) /* out: data type */
325
dict_col_copy_type(col, type);
328
/************************************************************************
329
Gets the nth column of a table. */
332
dict_table_get_nth_col_noninline(
333
/*=============================*/
334
/* out: pointer to column object */
335
const dict_table_t* table, /* in: table */
336
ulint pos) /* in: position of column */
338
return(dict_table_get_nth_col(table, pos));
341
/************************************************************************
342
Gets the first index on the table (the clustered index). */
345
dict_table_get_first_index_noninline(
346
/*=================================*/
347
/* out: index, NULL if none exists */
348
dict_table_t* table) /* in: table */
350
return(dict_table_get_first_index(table));
353
/************************************************************************
354
Gets the next index on the table. */
357
dict_table_get_next_index_noninline(
358
/*================================*/
359
/* out: index, NULL if none left */
360
dict_index_t* index) /* in: index */
362
return(dict_table_get_next_index(index));
365
/**************************************************************************
366
Returns an index object. */
369
dict_table_get_index_noninline(
370
/*===========================*/
371
/* out: index, NULL if does not exist */
372
dict_table_t* table, /* in: table */
373
const char* name) /* in: index name */
375
return(dict_table_get_index(table, name));
378
/**************************************************************************
379
Returns a column's name. */
382
dict_table_get_col_name(
383
/*====================*/
384
/* out: column name. NOTE: not
385
guaranteed to stay valid if table is
386
modified in any way (columns added,
388
const dict_table_t* table, /* in: table */
389
ulint col_nr) /* in: column number */
395
ut_ad(col_nr < table->n_def);
396
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
398
s = table->col_names;
400
for (i = 0; i < col_nr; i++) {
409
/************************************************************************
410
Acquire the autoinc lock.*/
413
dict_table_autoinc_lock(
414
/*====================*/
417
mutex_enter(&table->autoinc_mutex);
420
/************************************************************************
421
Initializes the autoinc counter. It is not an error to initialize an already
422
initialized counter. */
425
dict_table_autoinc_initialize(
426
/*==========================*/
427
dict_table_t* table, /* in: table */
428
ib_longlong value) /* in: next value to assign to a row */
430
ut_ad(mutex_own(&table->autoinc_mutex));
432
table->autoinc_inited = TRUE;
433
table->autoinc = value;
436
/************************************************************************
437
Reads the next autoinc value (== autoinc counter value), 0 if not yet
441
dict_table_autoinc_read(
442
/*====================*/
443
/* out: value for a new row, or 0 */
444
dict_table_t* table) /* in: table */
448
ut_ad(mutex_own(&table->autoinc_mutex));
450
if (!table->autoinc_inited) {
454
value = table->autoinc;
460
/************************************************************************
461
Updates the autoinc counter if the value supplied is greater than the
462
current value. If not inited, does nothing. */
465
dict_table_autoinc_update(
466
/*======================*/
468
dict_table_t* table, /* in: table */
469
ib_longlong value) /* in: value which was assigned to a row */
471
if (table->autoinc_inited && value > table->autoinc) {
473
table->autoinc = value;
477
/************************************************************************
478
Release the autoinc lock.*/
481
dict_table_autoinc_unlock(
482
/*======================*/
483
dict_table_t* table) /* in: release autoinc lock for this table */
485
mutex_exit(&table->autoinc_mutex);
488
/************************************************************************
489
Looks for column n in an index. */
492
dict_index_get_nth_col_pos(
493
/*=======================*/
494
/* out: position in internal representation
495
of the index; if not contained, returns
497
dict_index_t* index, /* in: index */
498
ulint n) /* in: column number */
500
const dict_field_t* field;
501
const dict_col_t* col;
506
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
508
col = dict_table_get_nth_col(index->table, n);
510
if (index->type & DICT_CLUSTERED) {
512
return(dict_col_get_clust_pos(col, index));
515
n_fields = dict_index_get_n_fields(index);
517
for (pos = 0; pos < n_fields; pos++) {
518
field = dict_index_get_nth_field(index, pos);
520
if (col == field->col && field->prefix_len == 0) {
526
return(ULINT_UNDEFINED);
529
/************************************************************************
530
Returns TRUE if the index contains a column or a prefix of that column. */
533
dict_index_contains_col_or_prefix(
534
/*==============================*/
535
/* out: TRUE if contains the column or its
537
dict_index_t* index, /* in: index */
538
ulint n) /* in: column number */
540
const dict_field_t* field;
541
const dict_col_t* col;
546
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
548
if (index->type & DICT_CLUSTERED) {
553
col = dict_table_get_nth_col(index->table, n);
555
n_fields = dict_index_get_n_fields(index);
557
for (pos = 0; pos < n_fields; pos++) {
558
field = dict_index_get_nth_field(index, pos);
560
if (col == field->col) {
569
/************************************************************************
570
Looks for a matching field in an index. The column has to be the same. The
571
column in index must be complete, or must contain a prefix longer than the
572
column in index2. That is, we must be able to construct the prefix in index2
573
from the prefix in index. */
576
dict_index_get_nth_field_pos(
577
/*=========================*/
578
/* out: position in internal representation
579
of the index; if not contained, returns
581
dict_index_t* index, /* in: index from which to search */
582
dict_index_t* index2, /* in: index */
583
ulint n) /* in: field number in index2 */
586
dict_field_t* field2;
591
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
593
field2 = dict_index_get_nth_field(index2, n);
595
n_fields = dict_index_get_n_fields(index);
597
for (pos = 0; pos < n_fields; pos++) {
598
field = dict_index_get_nth_field(index, pos);
600
if (field->col == field2->col
601
&& (field->prefix_len == 0
602
|| (field->prefix_len >= field2->prefix_len
603
&& field2->prefix_len != 0))) {
609
return(ULINT_UNDEFINED);
612
/**************************************************************************
613
Returns a table object based on table id. */
616
dict_table_get_on_id(
617
/*=================*/
618
/* out: table, NULL if does not exist */
619
dulint table_id, /* in: table id */
620
trx_t* trx) /* in: transaction handle */
624
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
625
|| trx->dict_operation_lock_mode == RW_X_LATCH) {
626
/* It is a system table which will always exist in the table
627
cache: we avoid acquiring the dictionary mutex, because
628
if we are doing a rollback to handle an error in TABLE
629
CREATE, for example, we already have the mutex! */
631
ut_ad(mutex_own(&(dict_sys->mutex))
632
|| trx->dict_operation_lock_mode == RW_X_LATCH);
634
return(dict_table_get_on_id_low(table_id));
637
mutex_enter(&(dict_sys->mutex));
639
table = dict_table_get_on_id_low(table_id);
641
mutex_exit(&(dict_sys->mutex));
646
/************************************************************************
647
Looks for column n position in the clustered index. */
650
dict_table_get_nth_col_pos(
651
/*=======================*/
652
/* out: position in internal representation
653
of the clustered index */
654
dict_table_t* table, /* in: table */
655
ulint n) /* in: column number */
657
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
661
/************************************************************************
662
Check whether the table uses the compact page format. */
665
dict_table_is_comp_noninline(
666
/*=========================*/
667
/* out: TRUE if table uses the
668
compact page format */
669
const dict_table_t* table) /* in: table */
671
return(dict_table_is_comp(table));
674
/************************************************************************
675
Checks if a column is in the ordering columns of the clustered index of a
676
table. Column prefixes are treated like whole columns. */
679
dict_table_col_in_clustered_key(
680
/*============================*/
681
/* out: TRUE if the column, or its prefix, is
682
in the clustered key */
683
dict_table_t* table, /* in: table */
684
ulint n) /* in: column number */
687
const dict_field_t* field;
688
const dict_col_t* col;
694
col = dict_table_get_nth_col(table, n);
696
index = dict_table_get_first_index(table);
698
n_fields = dict_index_get_n_unique(index);
700
for (pos = 0; pos < n_fields; pos++) {
701
field = dict_index_get_nth_field(index, pos);
703
if (col == field->col) {
712
/**************************************************************************
713
Inits the data dictionary module. */
719
dict_sys = mem_alloc(sizeof(dict_sys_t));
721
mutex_create(&dict_sys->mutex, SYNC_DICT);
723
dict_sys->table_hash = hash_create(buf_pool_get_max_size()
724
/ (DICT_POOL_PER_TABLE_HASH
726
dict_sys->table_id_hash = hash_create(buf_pool_get_max_size()
727
/ (DICT_POOL_PER_TABLE_HASH
731
UT_LIST_INIT(dict_sys->table_LRU);
733
rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
735
dict_foreign_err_file = os_file_create_tmpfile();
736
ut_a(dict_foreign_err_file);
738
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
741
/**************************************************************************
742
Returns a table object and optionally increment its MySQL open handle count.
743
NOTE! This is a high-level function to be used mainly from outside the
744
'dict' directory. Inside this directory dict_table_get_low is usually the
745
appropriate function. */
750
/* out: table, NULL if
752
const char* table_name, /* in: table name */
753
ibool inc_mysql_count)
754
/* in: whether to increment the open
755
handle count on the table */
759
mutex_enter(&(dict_sys->mutex));
761
table = dict_table_get_low(table_name);
763
if (inc_mysql_count && table) {
764
table->n_mysql_handles_opened++;
767
mutex_exit(&(dict_sys->mutex));
770
if (!table->stat_initialized) {
771
/* If table->ibd_file_missing == TRUE, this will
772
print an error message and return without doing
774
dict_update_statistics(table);
781
/**************************************************************************
782
Adds system columns to a table object. */
785
dict_table_add_system_columns(
786
/*==========================*/
787
dict_table_t* table, /* in/out: table */
788
mem_heap_t* heap) /* in: temporary heap */
791
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
792
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
793
ut_ad(!table->cached);
795
/* NOTE: the system columns MUST be added in the following order
796
(so that they can be indexed by the numerical value of DATA_ROW_ID,
797
etc.) and as the last columns of the table memory object.
798
The clustered index will not always physically contain all
801
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
802
DATA_ROW_ID | DATA_NOT_NULL,
805
#error "DATA_ROW_ID != 0"
807
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
808
DATA_TRX_ID | DATA_NOT_NULL,
811
#error "DATA_TRX_ID != 1"
813
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
814
DATA_ROLL_PTR | DATA_NOT_NULL,
816
#if DATA_ROLL_PTR != 2
817
#error "DATA_ROLL_PTR != 2"
820
/* This check reminds that if a new system column is added to
821
the program, it should be dealt with here */
822
#if DATA_N_SYS_COLS != 3
823
#error "DATA_N_SYS_COLS != 3"
827
/**************************************************************************
828
Adds a table object to the dictionary cache. */
831
dict_table_add_to_cache(
832
/*====================*/
833
dict_table_t* table, /* in: table */
834
mem_heap_t* heap) /* in: temporary heap */
841
/* The lower limit for what we consider a "big" row */
842
#define BIG_ROW_SIZE 1024
844
ut_ad(mutex_own(&(dict_sys->mutex)));
846
dict_table_add_system_columns(table, heap);
848
table->cached = TRUE;
850
fold = ut_fold_string(table->name);
851
id_fold = ut_fold_dulint(table->id);
854
for (i = 0; i < table->n_def; i++) {
855
ulint col_len = dict_col_get_max_size(
856
dict_table_get_nth_col(table, i));
860
/* If we have a single unbounded field, or several gigantic
861
fields, mark the maximum row size as BIG_ROW_SIZE. */
862
if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
863
row_len = BIG_ROW_SIZE;
869
table->big_rows = row_len >= BIG_ROW_SIZE;
871
/* Look for a table with the same name: error if such exists */
873
dict_table_t* table2;
874
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
875
(ut_strcmp(table2->name, table->name) == 0));
876
ut_a(table2 == NULL);
879
/* Look for a table with the same id: error if such exists */
881
dict_table_t* table2;
882
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2,
883
(ut_dulint_cmp(table2->id, table->id) == 0));
884
ut_a(table2 == NULL);
887
/* Add table to hash table of tables */
888
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
891
/* Add table to hash table of tables based on table id */
892
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
894
/* Add table to LRU list of tables */
895
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
897
dict_sys->size += mem_heap_get_size(table->heap);
900
/**************************************************************************
901
Looks for an index with the given id. NOTE that we do not reserve
902
the dictionary mutex: this function is for emergency purposes like
903
printing info of a corrupt database page! */
906
dict_index_find_on_id_low(
907
/*======================*/
908
/* out: index or NULL if not found from cache */
909
dulint id) /* in: index id */
914
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
917
index = dict_table_get_first_index(table);
920
if (0 == ut_dulint_cmp(id, index->id)) {
926
index = dict_table_get_next_index(index);
929
table = UT_LIST_GET_NEXT(table_LRU, table);
935
/**************************************************************************
936
Renames a table object. */
939
dict_table_rename_in_cache(
940
/*=======================*/
941
/* out: TRUE if success */
942
dict_table_t* table, /* in: table */
943
const char* new_name, /* in: new name */
944
ibool rename_also_foreigns)/* in: in ALTER TABLE we want
945
to preserve the original table name
946
in constraints which reference it */
948
dict_foreign_t* foreign;
956
ut_ad(mutex_own(&(dict_sys->mutex)));
958
old_size = mem_heap_get_size(table->heap);
960
fold = ut_fold_string(new_name);
962
/* Look for a table with the same name: error if such exists */
964
dict_table_t* table2;
965
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
966
(ut_strcmp(table2->name, new_name) == 0));
969
"InnoDB: Error: dictionary cache"
970
" already contains a table of name %s\n",
976
/* If the table is stored in a single-table tablespace, rename the
979
if (table->space != 0) {
980
if (table->dir_path_of_temp_table != NULL) {
982
"InnoDB: Error: trying to rename a table"
983
" %s (%s) created with CREATE\n"
984
"InnoDB: TEMPORARY TABLE\n",
985
table->name, table->dir_path_of_temp_table);
988
success = fil_rename_tablespace(
989
table->name, table->space, new_name);
998
/* Remove table from the hash tables of tables */
999
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1000
ut_fold_string(table->name), table);
1001
old_name = mem_heap_strdup(table->heap, table->name);
1002
table->name = mem_heap_strdup(table->heap, new_name);
1004
/* Add table to hash table of tables */
1005
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1007
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
1009
/* Update the table_name field in indexes */
1010
index = dict_table_get_first_index(table);
1012
while (index != NULL) {
1013
index->table_name = table->name;
1015
index = dict_table_get_next_index(index);
1018
if (!rename_also_foreigns) {
1019
/* In ALTER TABLE we think of the rename table operation
1020
in the direction table -> temporary table (#sql...)
1021
as dropping the table with the old name and creating
1022
a new with the new name. Thus we kind of drop the
1023
constraints from the dictionary cache here. The foreign key
1024
constraints will be inherited to the new table from the
1025
system tables through a call of dict_load_foreigns. */
1027
/* Remove the foreign constraints from the cache */
1028
foreign = UT_LIST_GET_LAST(table->foreign_list);
1030
while (foreign != NULL) {
1031
dict_foreign_remove_from_cache(foreign);
1032
foreign = UT_LIST_GET_LAST(table->foreign_list);
1035
/* Reset table field in referencing constraints */
1037
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1039
while (foreign != NULL) {
1040
foreign->referenced_table = NULL;
1041
foreign->referenced_index = NULL;
1043
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1046
/* Make the list of referencing constraints empty */
1048
UT_LIST_INIT(table->referenced_list);
1053
/* Update the table name fields in foreign constraints, and update also
1054
the constraint id of new format >= 4.0.18 constraints. Note that at
1055
this point we have already changed table->name to the new name. */
1057
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1059
while (foreign != NULL) {
1060
if (ut_strlen(foreign->foreign_table_name)
1061
< ut_strlen(table->name)) {
1062
/* Allocate a longer name buffer;
1063
TODO: store buf len to save memory */
1065
foreign->foreign_table_name
1066
= mem_heap_alloc(foreign->heap,
1067
ut_strlen(table->name) + 1);
1070
strcpy(foreign->foreign_table_name, table->name);
1072
if (strchr(foreign->id, '/')) {
1076
/* This is a >= 4.0.18 format id */
1078
old_id = mem_strdup(foreign->id);
1080
if (ut_strlen(foreign->id) > ut_strlen(old_name)
1081
+ ((sizeof dict_ibfk) - 1)
1082
&& !memcmp(foreign->id, old_name,
1083
ut_strlen(old_name))
1084
&& !memcmp(foreign->id + ut_strlen(old_name),
1085
dict_ibfk, (sizeof dict_ibfk) - 1)) {
1087
/* This is a generated >= 4.0.18 format id */
1089
if (strlen(table->name) > strlen(old_name)) {
1090
foreign->id = mem_heap_alloc(
1093
+ strlen(old_id) + 1);
1096
/* Replace the prefix 'databasename/tablename'
1097
with the new names */
1098
strcpy(foreign->id, table->name);
1100
old_id + ut_strlen(old_name));
1102
/* This is a >= 4.0.18 format id where the user
1104
db_len = dict_get_db_name_len(table->name) + 1;
1106
if (dict_get_db_name_len(table->name)
1107
> dict_get_db_name_len(foreign->id)) {
1109
foreign->id = mem_heap_alloc(
1111
db_len + strlen(old_id) + 1);
1114
/* Replace the database prefix in id with the
1115
one from table->name */
1117
ut_memcpy(foreign->id, table->name, db_len);
1119
strcpy(foreign->id + db_len,
1120
dict_remove_db_name(old_id));
1126
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1129
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1131
while (foreign != NULL) {
1132
if (ut_strlen(foreign->referenced_table_name)
1133
< ut_strlen(table->name)) {
1134
/* Allocate a longer name buffer;
1135
TODO: store buf len to save memory */
1137
foreign->referenced_table_name = mem_heap_alloc(
1138
foreign->heap, strlen(table->name) + 1);
1141
strcpy(foreign->referenced_table_name, table->name);
1143
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1149
/**************************************************************************
1150
Change the id of a table object in the dictionary cache. This is used in
1151
DISCARD TABLESPACE. */
1154
dict_table_change_id_in_cache(
1155
/*==========================*/
1156
dict_table_t* table, /* in: table object already in cache */
1157
dulint new_id) /* in: new id to set */
1160
ut_ad(mutex_own(&(dict_sys->mutex)));
1161
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1163
/* Remove the table from the hash table of id's */
1165
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1166
ut_fold_dulint(table->id), table);
1169
/* Add the table back to the hash table */
1170
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1171
ut_fold_dulint(table->id), table);
1174
/**************************************************************************
1175
Removes a table object from the dictionary cache. */
1178
dict_table_remove_from_cache(
1179
/*=========================*/
1180
dict_table_t* table) /* in, own: table */
1182
dict_foreign_t* foreign;
1183
dict_index_t* index;
1187
ut_ad(mutex_own(&(dict_sys->mutex)));
1188
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1191
fputs("Removing table ", stderr);
1192
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1193
fputs(" from dictionary cache\n", stderr);
1196
/* Remove the foreign constraints from the cache */
1197
foreign = UT_LIST_GET_LAST(table->foreign_list);
1199
while (foreign != NULL) {
1200
dict_foreign_remove_from_cache(foreign);
1201
foreign = UT_LIST_GET_LAST(table->foreign_list);
1204
/* Reset table field in referencing constraints */
1206
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1208
while (foreign != NULL) {
1209
foreign->referenced_table = NULL;
1210
foreign->referenced_index = NULL;
1212
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1215
/* Remove the indexes from the cache */
1216
index = UT_LIST_GET_LAST(table->indexes);
1218
while (index != NULL) {
1219
dict_index_remove_from_cache(table, index);
1220
index = UT_LIST_GET_LAST(table->indexes);
1223
/* Remove table from the hash tables of tables */
1224
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1225
ut_fold_string(table->name), table);
1226
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1227
ut_fold_dulint(table->id), table);
1229
/* Remove table from LRU list of tables */
1230
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1232
size = mem_heap_get_size(table->heap);
1234
ut_ad(dict_sys->size >= size);
1236
dict_sys->size -= size;
1238
dict_mem_table_free(table);
1241
/*************************************************************************
1242
Gets the column position in the clustered index. */
1245
dict_col_get_clust_pos_noninline(
1246
/*=============================*/
1247
const dict_col_t* col, /* in: table column */
1248
const dict_index_t* clust_index) /* in: clustered index */
1250
return(dict_col_get_clust_pos(col, clust_index));
1253
/********************************************************************
1254
If the given column name is reserved for InnoDB system columns, return
1258
dict_col_name_is_reserved(
1259
/*======================*/
1260
/* out: TRUE if name is reserved */
1261
const char* name) /* in: column name */
1263
/* This check reminds that if a new system column is added to
1264
the program, it should be dealt with here. */
1265
#if DATA_N_SYS_COLS != 3
1266
#error "DATA_N_SYS_COLS != 3"
1269
static const char* reserved_names[] = {
1270
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1275
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1276
if (strcmp(name, reserved_names[i]) == 0) {
1285
/**************************************************************************
1286
Adds an index to the dictionary cache. */
1289
dict_index_add_to_cache(
1290
/*====================*/
1291
dict_table_t* table, /* in: table on which the index is */
1292
dict_index_t* index, /* in, own: index; NOTE! The index memory
1293
object is freed in this function! */
1294
ulint page_no)/* in: root page number of the index */
1296
dict_index_t* new_index;
1301
ut_ad(mutex_own(&(dict_sys->mutex)));
1302
ut_ad(index->n_def == index->n_fields);
1303
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1305
ut_ad(mem_heap_validate(index->heap));
1309
dict_index_t* index2;
1310
index2 = UT_LIST_GET_FIRST(table->indexes);
1312
while (index2 != NULL) {
1313
ut_ad(ut_strcmp(index->name, index2->name) != 0);
1315
index2 = UT_LIST_GET_NEXT(indexes, index2);
1318
#endif /* UNIV_DEBUG */
1320
ut_a(!(index->type & DICT_CLUSTERED)
1321
|| UT_LIST_GET_LEN(table->indexes) == 0);
1323
dict_index_find_cols(table, index);
1325
/* Build the cache internal representation of the index,
1326
containing also the added system fields */
1328
if (index->type & DICT_CLUSTERED) {
1329
new_index = dict_index_build_internal_clust(table, index);
1331
new_index = dict_index_build_internal_non_clust(table, index);
1334
new_index->search_info = btr_search_info_create(new_index->heap);
1336
/* Set the n_fields value in new_index to the actual defined
1337
number of fields in the cache internal representation */
1339
new_index->n_fields = new_index->n_def;
1341
/* Add the new index as the last index for the table */
1343
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1344
new_index->table = table;
1345
new_index->table_name = table->name;
1347
/* Increment the ord_part counts in columns which are ordering */
1349
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1350
n_ord = new_index->n_fields;
1352
n_ord = dict_index_get_n_unique(new_index);
1355
for (i = 0; i < n_ord; i++) {
1357
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1360
new_index->page = (unsigned int) page_no;
1361
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1363
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1365
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1367
(1 + dict_index_get_n_unique(new_index))
1368
* sizeof(ib_longlong));
1369
/* Give some sensible values to stat_n_... in case we do
1370
not calculate statistics quickly enough */
1372
for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1374
new_index->stat_n_diff_key_vals[i] = 100;
1378
dict_sys->size += mem_heap_get_size(new_index->heap);
1380
dict_mem_index_free(index);
1383
/**************************************************************************
1384
Removes an index from the dictionary cache. */
1387
dict_index_remove_from_cache(
1388
/*=========================*/
1389
dict_table_t* table, /* in: table */
1390
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
rw_lock_free(&index->lock);
1401
/* Remove the index from the list of indexes of the table */
1402
UT_LIST_REMOVE(indexes, table->indexes, index);
1404
size = mem_heap_get_size(index->heap);
1406
ut_ad(dict_sys->size >= size);
1408
dict_sys->size -= size;
1410
dict_mem_index_free(index);
1413
/***********************************************************************
1414
Tries to find column names for the index and sets the col field of the
1418
dict_index_find_cols(
1419
/*=================*/
1420
dict_table_t* table, /* in: table */
1421
dict_index_t* index) /* in: index */
1425
ut_ad(table && index);
1426
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1427
ut_ad(mutex_own(&(dict_sys->mutex)));
1429
for (i = 0; i < index->n_fields; i++) {
1431
dict_field_t* field = dict_index_get_nth_field(index, i);
1433
for (j = 0; j < table->n_cols; j++) {
1434
if (!strcmp(dict_table_get_col_name(table, j),
1436
field->col = (dict_col_t*)
1437
dict_table_get_nth_col(table, j);
1443
/* It is an error not to find a matching column. */
1451
/***********************************************************************
1452
Adds a column to index. */
1457
dict_index_t* index, /* in: index */
1458
dict_table_t* table, /* in: table */
1459
dict_col_t* col, /* in: column */
1460
ulint prefix_len) /* in: column prefix length */
1462
dict_field_t* field;
1463
const char* col_name;
1465
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1467
dict_mem_index_add_field(index, col_name, prefix_len);
1469
field = dict_index_get_nth_field(index, index->n_def - 1);
1472
field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1474
if (prefix_len && field->fixed_len > prefix_len) {
1475
field->fixed_len = (unsigned int) prefix_len;
1478
/* Long fixed-length fields that need external storage are treated as
1479
variable-length fields, so that the extern flag can be embedded in
1482
if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1483
field->fixed_len = 0;
1485
#if DICT_MAX_INDEX_COL_LEN != 768
1486
/* The comparison limit above must be constant. If it were
1487
changed, the disk format of some fixed-length columns would
1488
change, which would be a disaster. */
1489
# error "DICT_MAX_INDEX_COL_LEN != 768"
1492
if (!(col->prtype & DATA_NOT_NULL)) {
1493
index->n_nullable++;
1497
/***********************************************************************
1498
Copies fields contained in index2 to index1. */
1503
dict_index_t* index1, /* in: index to copy to */
1504
dict_index_t* index2, /* in: index to copy from */
1505
dict_table_t* table, /* in: table */
1506
ulint start, /* in: first position to copy */
1507
ulint end) /* in: last position to copy */
1509
dict_field_t* field;
1512
/* Copy fields contained in index2 */
1514
for (i = start; i < end; i++) {
1516
field = dict_index_get_nth_field(index2, i);
1517
dict_index_add_col(index1, table, field->col,
1522
/***********************************************************************
1523
Copies types of fields contained in index to tuple. */
1526
dict_index_copy_types(
1527
/*==================*/
1528
dtuple_t* tuple, /* in: data tuple */
1529
dict_index_t* index, /* in: index */
1530
ulint n_fields) /* in: number of field types to copy */
1534
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1535
dtuple_set_types_binary(tuple, n_fields);
1540
for (i = 0; i < n_fields; i++) {
1541
dict_field_t* ifield;
1542
dtype_t* dfield_type;
1544
ifield = dict_index_get_nth_field(index, i);
1545
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1546
dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1550
/***********************************************************************
1551
Copies types of columns contained in table to tuple. */
1554
dict_table_copy_types(
1555
/*==================*/
1556
dtuple_t* tuple, /* in: data tuple */
1557
dict_table_t* table) /* in: index */
1559
dtype_t* dfield_type;
1562
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1564
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1565
dict_col_copy_type(dict_table_get_nth_col(table, i),
1570
/***********************************************************************
1571
Builds the internal dictionary cache representation for a clustered
1572
index, containing also system fields not defined by the user. */
1575
dict_index_build_internal_clust(
1576
/*============================*/
1577
/* out, own: the internal representation
1578
of the clustered index */
1579
dict_table_t* table, /* in: table */
1580
dict_index_t* index) /* in: user representation of a clustered
1583
dict_index_t* new_index;
1584
dict_field_t* field;
1590
ut_ad(table && index);
1591
ut_ad(index->type & DICT_CLUSTERED);
1592
ut_ad(mutex_own(&(dict_sys->mutex)));
1593
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1595
/* Create a new index object with certainly enough fields */
1596
new_index = dict_mem_index_create(table->name,
1597
index->name, table->space,
1599
index->n_fields + table->n_cols);
1601
/* Copy other relevant data from the old index struct to the new
1602
struct: it inherits the values */
1604
new_index->n_user_defined_cols = index->n_fields;
1606
new_index->id = index->id;
1608
/* Copy the fields of index */
1609
dict_index_copy(new_index, index, table, 0, index->n_fields);
1611
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1612
/* No fixed number of fields determines an entry uniquely */
1614
new_index->n_uniq = REC_MAX_N_FIELDS;
1616
} else if (index->type & DICT_UNIQUE) {
1617
/* Only the fields defined so far are needed to identify
1618
the index entry uniquely */
1620
new_index->n_uniq = new_index->n_def;
1622
/* Also the row id is needed to identify the entry */
1623
new_index->n_uniq = 1 + new_index->n_def;
1626
new_index->trx_id_offset = 0;
1628
if (!(index->type & DICT_IBUF)) {
1629
/* Add system columns, trx id first */
1631
trx_id_pos = new_index->n_def;
1633
#if DATA_ROW_ID != 0
1634
# error "DATA_ROW_ID != 0"
1636
#if DATA_TRX_ID != 1
1637
# error "DATA_TRX_ID != 1"
1639
#if DATA_ROLL_PTR != 2
1640
# error "DATA_ROLL_PTR != 2"
1643
if (!(index->type & DICT_UNIQUE)) {
1644
dict_index_add_col(new_index, table, (dict_col_t*)
1645
dict_table_get_sys_col(
1646
table, DATA_ROW_ID),
1651
dict_index_add_col(new_index, table, (dict_col_t*)
1652
dict_table_get_sys_col(table, DATA_TRX_ID),
1655
dict_index_add_col(new_index, table, (dict_col_t*)
1656
dict_table_get_sys_col(table,
1660
for (i = 0; i < trx_id_pos; i++) {
1662
fixed_size = dict_col_get_fixed_size(
1663
dict_index_get_nth_col(new_index, i));
1665
if (fixed_size == 0) {
1666
new_index->trx_id_offset = 0;
1671
if (dict_index_get_nth_field(new_index, i)->prefix_len
1673
new_index->trx_id_offset = 0;
1678
new_index->trx_id_offset += (unsigned int) fixed_size;
1683
/* Remember the table columns already contained in new_index */
1684
indexed = mem_alloc(table->n_cols * sizeof *indexed);
1685
memset(indexed, 0, table->n_cols * sizeof *indexed);
1687
/* Mark with 0 the table columns already contained in new_index */
1688
for (i = 0; i < new_index->n_def; i++) {
1690
field = dict_index_get_nth_field(new_index, i);
1692
/* If there is only a prefix of the column in the index
1693
field, do not mark the column as contained in the index */
1695
if (field->prefix_len == 0) {
1697
indexed[field->col->ind] = TRUE;
1701
/* Add to new_index non-system columns of table not yet included
1703
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1705
dict_col_t* col = (dict_col_t*)
1706
dict_table_get_nth_col(table, i);
1707
ut_ad(col->mtype != DATA_SYS);
1709
if (!indexed[col->ind]) {
1710
dict_index_add_col(new_index, table, col, 0);
1716
ut_ad((index->type & DICT_IBUF)
1717
|| (UT_LIST_GET_LEN(table->indexes) == 0));
1719
new_index->cached = TRUE;
1724
/***********************************************************************
1725
Builds the internal dictionary cache representation for a non-clustered
1726
index, containing also system fields not defined by the user. */
1729
dict_index_build_internal_non_clust(
1730
/*================================*/
1731
/* out, own: the internal representation
1732
of the non-clustered index */
1733
dict_table_t* table, /* in: table */
1734
dict_index_t* index) /* in: user representation of a non-clustered
1737
dict_field_t* field;
1738
dict_index_t* new_index;
1739
dict_index_t* clust_index;
1743
ut_ad(table && index);
1744
ut_ad(0 == (index->type & DICT_CLUSTERED));
1745
ut_ad(mutex_own(&(dict_sys->mutex)));
1746
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1748
/* The clustered index should be the first in the list of indexes */
1749
clust_index = UT_LIST_GET_FIRST(table->indexes);
1752
ut_ad(clust_index->type & DICT_CLUSTERED);
1753
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
1755
/* Create a new index */
1756
new_index = dict_mem_index_create(
1757
table->name, index->name, index->space, index->type,
1758
index->n_fields + 1 + clust_index->n_uniq);
1760
/* Copy other relevant data from the old index
1761
struct to the new struct: it inherits the values */
1763
new_index->n_user_defined_cols = index->n_fields;
1765
new_index->id = index->id;
1767
/* Copy fields from index to new_index */
1768
dict_index_copy(new_index, index, table, 0, index->n_fields);
1770
/* Remember the table columns already contained in new_index */
1771
indexed = mem_alloc(table->n_cols * sizeof *indexed);
1772
memset(indexed, 0, table->n_cols * sizeof *indexed);
1774
/* Mark with 0 table columns already contained in new_index */
1775
for (i = 0; i < new_index->n_def; i++) {
1777
field = dict_index_get_nth_field(new_index, i);
1779
/* If there is only a prefix of the column in the index
1780
field, do not mark the column as contained in the index */
1782
if (field->prefix_len == 0) {
1784
indexed[field->col->ind] = TRUE;
1788
/* Add to new_index the columns necessary to determine the clustered
1789
index entry uniquely */
1791
for (i = 0; i < clust_index->n_uniq; i++) {
1793
field = dict_index_get_nth_field(clust_index, i);
1795
if (!indexed[field->col->ind]) {
1796
dict_index_add_col(new_index, table, field->col,
1803
if ((index->type) & DICT_UNIQUE) {
1804
new_index->n_uniq = index->n_fields;
1806
new_index->n_uniq = new_index->n_def;
1809
/* Set the n_fields value in new_index to the actual defined
1812
new_index->n_fields = new_index->n_def;
1814
new_index->cached = TRUE;
1819
/*====================== FOREIGN KEY PROCESSING ========================*/
1821
/*************************************************************************
1822
Checks if a table is referenced by foreign keys. */
1825
dict_table_referenced_by_foreign_key(
1826
/*=================================*/
1827
/* out: TRUE if table is referenced by a
1829
dict_table_t* table) /* in: InnoDB table */
1831
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
1839
/*************************************************************************
1840
Frees a foreign key struct. */
1845
dict_foreign_t* foreign) /* in, own: foreign key struct */
1847
mem_heap_free(foreign->heap);
1850
/**************************************************************************
1851
Removes a foreign constraint struct from the dictionary cache. */
1854
dict_foreign_remove_from_cache(
1855
/*===========================*/
1856
dict_foreign_t* foreign) /* in, own: foreign constraint */
1858
ut_ad(mutex_own(&(dict_sys->mutex)));
1861
if (foreign->referenced_table) {
1862
UT_LIST_REMOVE(referenced_list,
1863
foreign->referenced_table->referenced_list,
1867
if (foreign->foreign_table) {
1868
UT_LIST_REMOVE(foreign_list,
1869
foreign->foreign_table->foreign_list,
1873
dict_foreign_free(foreign);
1876
/**************************************************************************
1877
Looks for the foreign constraint from the foreign and referenced lists
1883
/* out: foreign constraint */
1884
dict_table_t* table, /* in: table object */
1885
const char* id) /* in: foreign constraint id */
1887
dict_foreign_t* foreign;
1889
ut_ad(mutex_own(&(dict_sys->mutex)));
1891
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1894
if (ut_strcmp(id, foreign->id) == 0) {
1899
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1902
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1905
if (ut_strcmp(id, foreign->id) == 0) {
1910
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1916
#ifndef UNIV_HOTBACKUP
1917
/*************************************************************************
1918
Tries to find an index whose first fields are the columns in the array,
1919
in the same order. */
1922
dict_foreign_find_index(
1923
/*====================*/
1924
/* out: matching index, NULL if not found */
1925
dict_table_t* table, /* in: table */
1926
const char** columns,/* in: array of column names */
1927
ulint n_cols, /* in: number of columns */
1928
dict_index_t* types_idx, /* in: NULL or an index to whose types the
1929
column types must match */
1930
ibool check_charsets,
1931
/* in: whether to check charsets.
1932
only has an effect if types_idx != NULL */
1934
/* in: nonzero if none of the columns must
1935
be declared NOT NULL */
1937
dict_index_t* index;
1938
dict_field_t* field;
1939
const char* col_name;
1942
index = dict_table_get_first_index(table);
1944
while (index != NULL) {
1945
if (dict_index_get_n_fields(index) >= n_cols) {
1947
for (i = 0; i < n_cols; i++) {
1948
field = dict_index_get_nth_field(index, i);
1950
col_name = dict_table_get_col_name(
1951
table, dict_col_get_no(field->col));
1953
if (field->prefix_len != 0) {
1954
/* We do not accept column prefix
1960
if (0 != innobase_strcasecmp(columns[i],
1966
&& (field->col->prtype & DATA_NOT_NULL)) {
1971
if (types_idx && !cmp_cols_are_equal(
1972
dict_index_get_nth_col(index, i),
1973
dict_index_get_nth_col(types_idx,
1982
/* We found a matching index */
1988
index = dict_table_get_next_index(index);
1994
/**************************************************************************
1995
Report an error in a foreign key definition. */
1998
dict_foreign_error_report_low(
1999
/*==========================*/
2000
FILE* file, /* in: output stream */
2001
const char* name) /* in: table name */
2004
ut_print_timestamp(file);
2005
fprintf(file, " Error in foreign key constraint of table %s:\n",
2009
/**************************************************************************
2010
Report an error in a foreign key definition. */
2013
dict_foreign_error_report(
2014
/*======================*/
2015
FILE* file, /* in: output stream */
2016
dict_foreign_t* fk, /* in: foreign key constraint */
2017
const char* msg) /* in: the error message */
2019
mutex_enter(&dict_foreign_err_mutex);
2020
dict_foreign_error_report_low(file, fk->foreign_table_name);
2022
fputs(" Constraint:\n", file);
2023
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2025
if (fk->foreign_index) {
2026
fputs("The index in the foreign key in table is ", file);
2027
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2029
"See http://dev.mysql.com/doc/refman/5.1/en/"
2030
"innodb-foreign-key-constraints.html\n"
2031
"for correct foreign key definition.\n",
2034
mutex_exit(&dict_foreign_err_mutex);
2037
/**************************************************************************
2038
Adds a foreign key constraint object to the dictionary cache. May free
2039
the object if there already is an object with the same identifier in.
2040
At least one of the foreign table and the referenced table must already
2041
be in the dictionary cache! */
2044
dict_foreign_add_to_cache(
2045
/*======================*/
2046
/* out: DB_SUCCESS or error code */
2047
dict_foreign_t* foreign, /* in, own: foreign key constraint */
2048
ibool check_charsets) /* in: TRUE=check charset
2051
dict_table_t* for_table;
2052
dict_table_t* ref_table;
2053
dict_foreign_t* for_in_cache = NULL;
2054
dict_index_t* index;
2055
ibool added_to_referenced_list= FALSE;
2056
FILE* ef = dict_foreign_err_file;
2058
ut_ad(mutex_own(&(dict_sys->mutex)));
2060
for_table = dict_table_check_if_in_cache_low(
2061
foreign->foreign_table_name);
2063
ref_table = dict_table_check_if_in_cache_low(
2064
foreign->referenced_table_name);
2065
ut_a(for_table || ref_table);
2068
for_in_cache = dict_foreign_find(for_table, foreign->id);
2071
if (!for_in_cache && ref_table) {
2072
for_in_cache = dict_foreign_find(ref_table, foreign->id);
2076
/* Free the foreign object */
2077
mem_heap_free(foreign->heap);
2079
for_in_cache = foreign;
2082
if (for_in_cache->referenced_table == NULL && ref_table) {
2083
index = dict_foreign_find_index(
2085
(const char**) for_in_cache->referenced_col_names,
2086
for_in_cache->n_fields, for_in_cache->foreign_index,
2087
check_charsets, FALSE);
2089
if (index == NULL) {
2090
dict_foreign_error_report(
2092
"there is no index in referenced table"
2093
" which would contain\n"
2094
"the columns as the first columns,"
2095
" or the data types in the\n"
2096
"referenced table do not match"
2097
" the ones in table.");
2099
if (for_in_cache == foreign) {
2100
mem_heap_free(foreign->heap);
2103
return(DB_CANNOT_ADD_CONSTRAINT);
2106
for_in_cache->referenced_table = ref_table;
2107
for_in_cache->referenced_index = index;
2108
UT_LIST_ADD_LAST(referenced_list,
2109
ref_table->referenced_list,
2111
added_to_referenced_list = TRUE;
2114
if (for_in_cache->foreign_table == NULL && for_table) {
2115
index = dict_foreign_find_index(
2117
(const char**) for_in_cache->foreign_col_names,
2118
for_in_cache->n_fields,
2119
for_in_cache->referenced_index, check_charsets,
2121
& (DICT_FOREIGN_ON_DELETE_SET_NULL
2122
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
2124
if (index == NULL) {
2125
dict_foreign_error_report(
2127
"there is no index in the table"
2128
" which would contain\n"
2129
"the columns as the first columns,"
2130
" or the data types in the\n"
2131
"table do not match"
2132
" the ones in the referenced table\n"
2133
"or one of the ON ... SET NULL columns"
2134
" is declared NOT NULL.");
2136
if (for_in_cache == foreign) {
2137
if (added_to_referenced_list) {
2140
ref_table->referenced_list,
2144
mem_heap_free(foreign->heap);
2147
return(DB_CANNOT_ADD_CONSTRAINT);
2150
for_in_cache->foreign_table = for_table;
2151
for_in_cache->foreign_index = index;
2152
UT_LIST_ADD_LAST(foreign_list,
2153
for_table->foreign_list,
2160
/*************************************************************************
2161
Scans from pointer onwards. Stops if is at the start of a copy of
2162
'string' where characters are compared without case sensitivity, and
2163
only outside `` or "" quotes. Stops also at '\0'. */
2168
/* out: scanned up to this */
2169
const char* ptr, /* in: scan from */
2170
const char* string) /* in: look for this */
2174
for (; *ptr; ptr++) {
2175
if (*ptr == quote) {
2176
/* Closing quote character: do not look for
2177
starting quote or the keyword. */
2180
/* Within quotes: do nothing. */
2181
} else if (*ptr == '`' || *ptr == '"') {
2182
/* Starting quote: remember the quote character. */
2185
/* Outside quotes: look for the keyword. */
2187
for (i = 0; string[i]; i++) {
2188
if (toupper((int)(unsigned char)(ptr[i]))
2189
!= toupper((int)(unsigned char)
2203
/*************************************************************************
2204
Accepts a specified string. Comparisons are case-insensitive. */
2209
/* out: if string was accepted, the pointer
2210
is moved after that, else ptr is returned */
2211
struct charset_info_st* cs,/* in: the character set of ptr */
2212
const char* ptr, /* in: scan from this */
2213
const char* string, /* in: accept only this string as the next
2214
non-whitespace string */
2215
ibool* success)/* out: TRUE if accepted */
2217
const char* old_ptr = ptr;
2218
const char* old_ptr2;
2222
while (my_isspace(cs, *ptr)) {
2228
ptr = dict_scan_to(ptr, string);
2230
if (*ptr == '\0' || old_ptr2 != ptr) {
2236
return(ptr + ut_strlen(string));
2239
/*************************************************************************
2240
Scans an id. For the lexical definition of an 'id', see the code below.
2241
Strips backquotes or double quotes from around the id. */
2246
/* out: scanned to */
2247
struct charset_info_st* cs,/* in: the character set of ptr */
2248
const char* ptr, /* in: scanned to */
2249
mem_heap_t* heap, /* in: heap where to allocate the id
2250
(NULL=id will not be allocated, but it
2251
will point to string near ptr) */
2252
const char** id, /* out,own: the id; NULL if no id was
2254
ibool table_id,/* in: TRUE=convert the allocated id
2255
as a table name; FALSE=convert to UTF-8 */
2256
ibool accept_also_dot)
2257
/* in: TRUE if also a dot can appear in a
2258
non-quoted id; in a quoted id it can appear
2269
while (my_isspace(cs, *ptr)) {
2278
if (*ptr == '`' || *ptr == '"') {
2290
if (*ptr == quote) {
2292
if (*ptr != quote) {
2300
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2301
&& (accept_also_dot || *ptr != '.')
2302
&& *ptr != ',' && *ptr != '\0') {
2310
if (UNIV_UNLIKELY(!heap)) {
2311
/* no heap given: id will point to source string */
2318
str = d = mem_heap_alloc(heap, len + 1);
2320
if ((*d++ = *s++) == quote) {
2327
ut_ad(s + 1 == ptr);
2329
str = mem_heap_strdupl(heap, s, len);
2334
/* Convert the identifier from connection character set
2337
*id = dst = mem_heap_alloc(heap, len);
2339
innobase_convert_from_id(dst, str, len);
2340
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2341
sizeof srv_mysql50_table_name_prefix)) {
2342
/* This is a pre-5.1 table name
2343
containing chars other than [A-Za-z0-9].
2344
Discard the prefix and use raw UTF-8 encoding. */
2345
str += sizeof srv_mysql50_table_name_prefix;
2346
len -= sizeof srv_mysql50_table_name_prefix;
2349
/* Encode using filename-safe characters. */
2351
*id = dst = mem_heap_alloc(heap, len);
2353
innobase_convert_from_table_id(dst, str, len);
2359
/*************************************************************************
2360
Tries to scan a column name. */
2365
/* out: scanned to */
2366
struct charset_info_st* cs, /* in: the character set of ptr */
2367
const char* ptr, /* in: scanned to */
2368
ibool* success,/* out: TRUE if success */
2369
dict_table_t* table, /* in: table in which the column is */
2370
const dict_col_t** column, /* out: pointer to column if success */
2371
mem_heap_t* heap, /* in: heap where to allocate */
2372
const char** name) /* out,own: the column name;
2373
NULL if no name was scannable */
2379
ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2381
if (*name == NULL) {
2383
return(ptr); /* Syntax error */
2386
if (table == NULL) {
2390
for (i = 0; i < dict_table_get_n_cols(table); i++) {
2392
const char* col_name = dict_table_get_col_name(
2395
if (0 == innobase_strcasecmp(col_name, *name)) {
2399
*column = dict_table_get_nth_col(table, i);
2400
strcpy((char*) *name, col_name);
2410
/*************************************************************************
2411
Scans a table name from an SQL string. */
2414
dict_scan_table_name(
2415
/*=================*/
2416
/* out: scanned to */
2417
struct charset_info_st* cs,/* in: the character set of ptr */
2418
const char* ptr, /* in: scanned to */
2419
dict_table_t** table, /* out: table object or NULL */
2420
const char* name, /* in: foreign key table name */
2421
ibool* success,/* out: TRUE if ok name found */
2422
mem_heap_t* heap, /* in: heap where to allocate the id */
2423
const char** ref_name)/* out,own: the table name;
2424
NULL if no name was scannable */
2426
const char* database_name = NULL;
2427
ulint database_name_len = 0;
2428
const char* table_name = NULL;
2429
ulint table_name_len;
2430
const char* scan_name;
2436
ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2438
if (scan_name == NULL) {
2440
return(ptr); /* Syntax error */
2444
/* We scanned the database name; scan also the table name */
2448
database_name = scan_name;
2449
database_name_len = strlen(database_name);
2451
ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2453
if (table_name == NULL) {
2455
return(ptr); /* Syntax error */
2458
/* To be able to read table dumps made with InnoDB-4.0.17 or
2459
earlier, we must allow the dot separator between the database
2460
name and the table name also to appear within a quoted
2461
identifier! InnoDB used to print a constraint as:
2462
... REFERENCES `databasename.tablename` ...
2463
starting from 4.0.18 it is
2464
... REFERENCES `databasename`.`tablename` ... */
2467
for (s = scan_name; *s; s++) {
2469
database_name = scan_name;
2470
database_name_len = s - scan_name;
2472
break;/* to do: multiple dots? */
2476
table_name = scan_name;
2479
if (database_name == NULL) {
2480
/* Use the database name of the foreign key table */
2482
database_name = name;
2483
database_name_len = dict_get_db_name_len(name);
2486
table_name_len = strlen(table_name);
2488
/* Copy database_name, '/', table_name, '\0' */
2489
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2490
memcpy(ref, database_name, database_name_len);
2491
ref[database_name_len] = '/';
2492
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2494
if (srv_lower_case_table_names) {
2495
#endif /* !__WIN__ */
2496
/* The table name is always put to lower case on Windows. */
2497
innobase_casedn_str(ref);
2500
#endif /* !__WIN__ */
2504
*table = dict_table_get_low(ref);
2509
/*************************************************************************
2510
Skips one id. The id is allowed to contain also '.'. */
2515
/* out: scanned to */
2516
struct charset_info_st* cs,/* in: the character set of ptr */
2517
const char* ptr, /* in: scanned to */
2518
ibool* success)/* out: TRUE if success, FALSE if just spaces
2519
left in string or a syntax error */
2525
ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2534
/*************************************************************************
2535
Removes MySQL comments from an SQL string. A comment is either
2536
(a) '#' to the end of the line,
2537
(b) '--<space>' to the end of the line, or
2538
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
2539
C comment syntax). */
2542
dict_strip_comments(
2543
/*================*/
2544
/* out, own: SQL string stripped from
2545
comments; the caller must free this
2547
const char* sql_string) /* in: SQL string */
2552
/* unclosed quote character (0 if none) */
2555
str = mem_alloc(strlen(sql_string) + 1);
2562
if (*sptr == '\0') {
2565
ut_a(ptr <= str + strlen(sql_string));
2570
if (*sptr == quote) {
2571
/* Closing quote character: do not look for
2572
starting quote or comments. */
2575
/* Within quotes: do not look for
2576
starting quotes or comments. */
2577
} else if (*sptr == '"' || *sptr == '`') {
2578
/* Starting quote: remember the quote character. */
2580
} else if (*sptr == '#'
2581
|| (sptr[0] == '-' && sptr[1] == '-'
2582
&& sptr[2] == ' ')) {
2584
/* In Unix a newline is 0x0A while in Windows
2585
it is 0x0D followed by 0x0A */
2587
if (*sptr == (char)0x0A
2588
|| *sptr == (char)0x0D
2596
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
2598
if (*sptr == '*' && *(sptr + 1) == '/') {
2605
if (*sptr == '\0') {
2621
/*************************************************************************
2622
Finds the highest <number> for foreign key constraints of the table. Looks
2623
only at the >= 4.0.18-format id's, which are of the form
2624
databasename/tablename_ibfk_<number>. */
2627
dict_table_get_highest_foreign_id(
2628
/*==============================*/
2629
/* out: highest number, 0 if table has no new
2630
format foreign key constraints */
2631
dict_table_t* table) /* in: table in the dictionary memory cache */
2633
dict_foreign_t* foreign;
2635
ulint biggest_id = 0;
2641
len = ut_strlen(table->name);
2642
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2645
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
2646
&& 0 == ut_memcmp(foreign->id, table->name, len)
2647
&& 0 == ut_memcmp(foreign->id + len,
2648
dict_ibfk, (sizeof dict_ibfk) - 1)
2649
&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
2650
/* It is of the >= 4.0.18 format */
2652
id = strtoul(foreign->id + len
2653
+ ((sizeof dict_ibfk) - 1),
2655
if (*endp == '\0') {
2656
ut_a(id != biggest_id);
2658
if (id > biggest_id) {
2664
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2670
/*************************************************************************
2671
Reports a simple foreign key create clause syntax error. */
2674
dict_foreign_report_syntax_err(
2675
/*===========================*/
2676
const char* name, /* in: table name */
2677
const char* start_of_latest_foreign,
2678
/* in: start of the foreign key clause
2679
in the SQL string */
2680
const char* ptr) /* in: place of the syntax error */
2682
FILE* ef = dict_foreign_err_file;
2684
mutex_enter(&dict_foreign_err_mutex);
2685
dict_foreign_error_report_low(ef, name);
2686
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
2687
start_of_latest_foreign, ptr);
2688
mutex_exit(&dict_foreign_err_mutex);
2691
/*************************************************************************
2692
Scans a table create SQL string and adds to the data dictionary the foreign
2693
key constraints declared in the string. This function should be called after
2694
the indexes for a table have been created. Each foreign key constraint must
2695
be accompanied with indexes in both participating tables. The indexes are
2696
allowed to contain more fields than mentioned in the constraint. */
2699
dict_create_foreign_constraints_low(
2700
/*================================*/
2701
/* out: error code or DB_SUCCESS */
2702
trx_t* trx, /* in: transaction */
2703
mem_heap_t* heap, /* in: memory heap */
2704
struct charset_info_st* cs,/* in: the character set of sql_string */
2705
const char* sql_string,
2706
/* in: CREATE TABLE or ALTER TABLE statement
2707
where foreign keys are declared like:
2708
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2709
table2 can be written also with the database
2710
name before it: test.table2; the default
2711
database is the database of parameter name */
2712
const char* name, /* in: table full name in the normalized form
2713
database_name/table_name */
2715
/* in: if TRUE, fail with error code
2716
DB_CANNOT_ADD_CONSTRAINT if any foreign
2719
dict_table_t* table;
2720
dict_table_t* referenced_table;
2721
dict_table_t* table_to_alter;
2722
ulint highest_id_so_far = 0;
2723
dict_index_t* index;
2724
dict_foreign_t* foreign;
2725
const char* ptr = sql_string;
2726
const char* start_of_latest_foreign = sql_string;
2727
FILE* ef = dict_foreign_err_file;
2728
const char* constraint_name;
2738
const dict_col_t*columns[500];
2739
const char* column_names[500];
2740
const char* referenced_table_name;
2742
ut_ad(mutex_own(&(dict_sys->mutex)));
2744
table = dict_table_get_low(name);
2746
if (table == NULL) {
2747
mutex_enter(&dict_foreign_err_mutex);
2748
dict_foreign_error_report_low(ef, name);
2750
"Cannot find the table in the internal"
2751
" data dictionary of InnoDB.\n"
2752
"Create table statement:\n%s\n", sql_string);
2753
mutex_exit(&dict_foreign_err_mutex);
2758
/* First check if we are actually doing an ALTER TABLE, and in that
2759
case look for the table being altered */
2761
ptr = dict_accept(cs, ptr, "ALTER", &success);
2768
ptr = dict_accept(cs, ptr, "TABLE", &success);
2775
/* We are doing an ALTER TABLE: scan the table name we are altering */
2777
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
2778
&success, heap, &referenced_table_name);
2781
"InnoDB: Error: could not find"
2782
" the table being ALTERED in:\n%s\n",
2788
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
2789
format databasename/tablename_ibfk_<number>, where <number> is local
2790
to the table; look for the highest <number> for table_to_alter, so
2791
that we can assign to new constraints higher numbers. */
2793
/* If we are altering a temporary table, the table name after ALTER
2794
TABLE does not correspond to the internal table name, and
2795
table_to_alter is NULL. TODO: should we fix this somehow? */
2797
if (table_to_alter == NULL) {
2798
highest_id_so_far = 0;
2800
highest_id_so_far = dict_table_get_highest_foreign_id(
2804
/* Scan for foreign key declarations in a loop */
2806
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
2808
ptr1 = dict_scan_to(ptr, "CONSTRAINT");
2809
ptr2 = dict_scan_to(ptr, "FOREIGN");
2811
constraint_name = NULL;
2814
/* The user may have specified a constraint name. Pick it so
2815
that we can store 'databasename/constraintname' as the id of
2816
of the constraint to system tables. */
2819
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
2823
if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
2827
while (my_isspace(cs, *ptr)) {
2831
/* read constraint name unless got "CONSTRAINT FOREIGN" */
2833
ptr = dict_scan_id(cs, ptr, heap,
2834
&constraint_name, FALSE, FALSE);
2841
/* The proper way to reject foreign keys for temporary
2842
tables would be to split the lexing and syntactical
2843
analysis of foreign key clauses from the actual adding
2844
of them, so that ha_innodb.cc could first parse the SQL
2845
command, determine if there are any foreign keys, and
2846
if so, immediately reject the command if the table is a
2847
temporary one. For now, this kludge will work. */
2848
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
2850
return(DB_CANNOT_ADD_CONSTRAINT);
2853
/**********************************************************/
2854
/* The following call adds the foreign key constraints
2855
to the data dictionary system tables on disk */
2857
error = dict_create_add_foreigns_to_dictionary(
2858
highest_id_so_far, table, trx);
2862
start_of_latest_foreign = ptr;
2864
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
2870
if (!my_isspace(cs, *ptr)) {
2874
ptr = dict_accept(cs, ptr, "KEY", &success);
2880
ptr = dict_accept(cs, ptr, "(", &success);
2883
/* MySQL allows also an index id before the '('; we
2885
ptr = dict_skip_word(cs, ptr, &success);
2888
dict_foreign_report_syntax_err(
2889
name, start_of_latest_foreign, ptr);
2891
return(DB_CANNOT_ADD_CONSTRAINT);
2894
ptr = dict_accept(cs, ptr, "(", &success);
2897
/* We do not flag a syntax error here because in an
2898
ALTER TABLE we may also have DROP FOREIGN KEY abc */
2906
/* Scan the columns in the first list */
2908
ut_a(i < (sizeof column_names) / sizeof *column_names);
2909
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
2910
heap, column_names + i);
2912
mutex_enter(&dict_foreign_err_mutex);
2913
dict_foreign_error_report_low(ef, name);
2914
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
2915
start_of_latest_foreign, ptr);
2916
mutex_exit(&dict_foreign_err_mutex);
2918
return(DB_CANNOT_ADD_CONSTRAINT);
2923
ptr = dict_accept(cs, ptr, ",", &success);
2929
ptr = dict_accept(cs, ptr, ")", &success);
2932
dict_foreign_report_syntax_err(
2933
name, start_of_latest_foreign, ptr);
2934
return(DB_CANNOT_ADD_CONSTRAINT);
2937
/* Try to find an index which contains the columns
2938
as the first fields and in the right order */
2940
index = dict_foreign_find_index(table, column_names, i,
2944
mutex_enter(&dict_foreign_err_mutex);
2945
dict_foreign_error_report_low(ef, name);
2946
fputs("There is no index in table ", ef);
2947
ut_print_name(ef, NULL, TRUE, name);
2948
fprintf(ef, " where the columns appear\n"
2949
"as the first columns. Constraint:\n%s\n"
2950
"See http://dev.mysql.com/doc/refman/5.1/en/"
2951
"innodb-foreign-key-constraints.html\n"
2952
"for correct foreign key definition.\n",
2953
start_of_latest_foreign);
2954
mutex_exit(&dict_foreign_err_mutex);
2956
return(DB_CANNOT_ADD_CONSTRAINT);
2958
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
2960
if (!success || !my_isspace(cs, *ptr)) {
2961
dict_foreign_report_syntax_err(
2962
name, start_of_latest_foreign, ptr);
2963
return(DB_CANNOT_ADD_CONSTRAINT);
2966
/* Let us create a constraint struct */
2968
foreign = dict_mem_foreign_create();
2970
if (constraint_name) {
2973
/* Catenate 'databasename/' to the constraint name specified
2974
by the user: we conceive the constraint as belonging to the
2975
same MySQL 'database' as the table itself. We store the name
2978
db_len = dict_get_db_name_len(table->name);
2980
foreign->id = mem_heap_alloc(
2981
foreign->heap, db_len + strlen(constraint_name) + 2);
2983
ut_memcpy(foreign->id, table->name, db_len);
2984
foreign->id[db_len] = '/';
2985
strcpy(foreign->id + db_len + 1, constraint_name);
2988
foreign->foreign_table = table;
2989
foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
2991
foreign->foreign_index = index;
2992
foreign->n_fields = (unsigned int) i;
2993
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
2995
for (i = 0; i < foreign->n_fields; i++) {
2996
foreign->foreign_col_names[i] = mem_heap_strdup(
2998
dict_table_get_col_name(table,
2999
dict_col_get_no(columns[i])));
3002
ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3003
&success, heap, &referenced_table_name);
3005
/* Note that referenced_table can be NULL if the user has suppressed
3006
checking of foreign key constraints! */
3008
if (!success || (!referenced_table && trx->check_foreigns)) {
3009
dict_foreign_free(foreign);
3011
mutex_enter(&dict_foreign_err_mutex);
3012
dict_foreign_error_report_low(ef, name);
3013
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3015
start_of_latest_foreign, ptr);
3016
mutex_exit(&dict_foreign_err_mutex);
3018
return(DB_CANNOT_ADD_CONSTRAINT);
3021
ptr = dict_accept(cs, ptr, "(", &success);
3024
dict_foreign_free(foreign);
3025
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3027
return(DB_CANNOT_ADD_CONSTRAINT);
3030
/* Scan the columns in the second list */
3034
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3035
heap, column_names + i);
3039
dict_foreign_free(foreign);
3041
mutex_enter(&dict_foreign_err_mutex);
3042
dict_foreign_error_report_low(ef, name);
3043
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3045
start_of_latest_foreign, ptr);
3046
mutex_exit(&dict_foreign_err_mutex);
3048
return(DB_CANNOT_ADD_CONSTRAINT);
3051
ptr = dict_accept(cs, ptr, ",", &success);
3057
ptr = dict_accept(cs, ptr, ")", &success);
3059
if (!success || foreign->n_fields != i) {
3060
dict_foreign_free(foreign);
3062
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3064
return(DB_CANNOT_ADD_CONSTRAINT);
3071
/* Loop here as long as we can find ON ... conditions */
3073
ptr = dict_accept(cs, ptr, "ON", &success);
3077
goto try_find_index;
3080
ptr = dict_accept(cs, ptr, "DELETE", &success);
3083
ptr = dict_accept(cs, ptr, "UPDATE", &success);
3086
dict_foreign_free(foreign);
3088
dict_foreign_report_syntax_err(
3089
name, start_of_latest_foreign, ptr);
3090
return(DB_CANNOT_ADD_CONSTRAINT);
3093
is_on_delete = FALSE;
3096
is_on_delete = TRUE;
3100
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3103
goto scan_on_conditions;
3106
ptr = dict_accept(cs, ptr, "CASCADE", &success);
3110
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3112
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3115
goto scan_on_conditions;
3118
ptr = dict_accept(cs, ptr, "NO", &success);
3121
ptr = dict_accept(cs, ptr, "ACTION", &success);
3124
dict_foreign_free(foreign);
3125
dict_foreign_report_syntax_err(
3126
name, start_of_latest_foreign, ptr);
3128
return(DB_CANNOT_ADD_CONSTRAINT);
3132
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3134
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3137
goto scan_on_conditions;
3140
ptr = dict_accept(cs, ptr, "SET", &success);
3143
dict_foreign_free(foreign);
3144
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3146
return(DB_CANNOT_ADD_CONSTRAINT);
3149
ptr = dict_accept(cs, ptr, "NULL", &success);
3152
dict_foreign_free(foreign);
3153
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3155
return(DB_CANNOT_ADD_CONSTRAINT);
3158
for (j = 0; j < foreign->n_fields; j++) {
3159
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3162
/* It is not sensible to define SET NULL
3163
if the column is not allowed to be NULL! */
3165
dict_foreign_free(foreign);
3167
mutex_enter(&dict_foreign_err_mutex);
3168
dict_foreign_error_report_low(ef, name);
3170
"You have defined a SET NULL condition"
3171
" though some of the\n"
3172
"columns are defined as NOT NULL.\n",
3173
start_of_latest_foreign);
3174
mutex_exit(&dict_foreign_err_mutex);
3176
return(DB_CANNOT_ADD_CONSTRAINT);
3181
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3183
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3186
goto scan_on_conditions;
3189
if (n_on_deletes > 1 || n_on_updates > 1) {
3190
/* It is an error to define more than 1 action */
3192
dict_foreign_free(foreign);
3194
mutex_enter(&dict_foreign_err_mutex);
3195
dict_foreign_error_report_low(ef, name);
3197
"You have twice an ON DELETE clause"
3198
" or twice an ON UPDATE clause.\n",
3199
start_of_latest_foreign);
3200
mutex_exit(&dict_foreign_err_mutex);
3202
return(DB_CANNOT_ADD_CONSTRAINT);
3205
/* Try to find an index which contains the columns as the first fields
3206
and in the right order, and the types are the same as in
3207
foreign->foreign_index */
3209
if (referenced_table) {
3210
index = dict_foreign_find_index(referenced_table,
3212
foreign->foreign_index,
3215
dict_foreign_free(foreign);
3216
mutex_enter(&dict_foreign_err_mutex);
3217
dict_foreign_error_report_low(ef, name);
3219
"Cannot find an index in the"
3220
" referenced table where the\n"
3221
"referenced columns appear as the"
3222
" first columns, or column types\n"
3223
"in the table and the referenced table"
3224
" do not match for constraint.\n"
3225
"Note that the internal storage type of"
3226
" ENUM and SET changed in\n"
3227
"tables created with >= InnoDB-4.1.12,"
3228
" and such columns in old tables\n"
3229
"cannot be referenced by such columns"
3231
"See http://dev.mysql.com/doc/refman/5.1/en/"
3232
"innodb-foreign-key-constraints.html\n"
3233
"for correct foreign key definition.\n",
3234
start_of_latest_foreign);
3235
mutex_exit(&dict_foreign_err_mutex);
3237
return(DB_CANNOT_ADD_CONSTRAINT);
3240
ut_a(trx->check_foreigns == FALSE);
3244
foreign->referenced_index = index;
3245
foreign->referenced_table = referenced_table;
3247
foreign->referenced_table_name
3248
= mem_heap_strdup(foreign->heap, referenced_table_name);
3250
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3252
for (i = 0; i < foreign->n_fields; i++) {
3253
foreign->referenced_col_names[i]
3254
= mem_heap_strdup(foreign->heap, column_names[i]);
3257
/* We found an ok constraint definition: add to the lists */
3259
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3261
if (referenced_table) {
3262
UT_LIST_ADD_LAST(referenced_list,
3263
referenced_table->referenced_list,
3270
/**************************************************************************
3271
Determines whether a string starts with the specified keyword. */
3274
dict_str_starts_with_keyword(
3275
/*=========================*/
3276
/* out: TRUE if str starts
3278
void* mysql_session, /* in: MySQL thread handle */
3279
const char* str, /* in: string to scan for keyword */
3280
const char* keyword) /* in: keyword to look for */
3282
struct charset_info_st* cs = innobase_get_charset(mysql_session);
3285
dict_accept(cs, str, keyword, &success);
3289
/*************************************************************************
3290
Scans a table create SQL string and adds to the data dictionary the foreign
3291
key constraints declared in the string. This function should be called after
3292
the indexes for a table have been created. Each foreign key constraint must
3293
be accompanied with indexes in both participating tables. The indexes are
3294
allowed to contain more fields than mentioned in the constraint. */
3297
dict_create_foreign_constraints(
3298
/*============================*/
3299
/* out: error code or DB_SUCCESS */
3300
trx_t* trx, /* in: transaction */
3301
const char* sql_string, /* in: table create statement where
3302
foreign keys are declared like:
3303
FOREIGN KEY (a, b) REFERENCES
3304
table2(c, d), table2 can be written
3305
also with the database
3306
name before it: test.table2; the
3307
default database id the database of
3309
const char* name, /* in: table full name in the
3311
database_name/table_name */
3312
ibool reject_fks) /* in: if TRUE, fail with error
3313
code DB_CANNOT_ADD_CONSTRAINT if
3314
any foreign keys are found. */
3321
ut_a(trx->mysql_session);
3323
str = dict_strip_comments(sql_string);
3324
heap = mem_heap_create(10000);
3326
err = dict_create_foreign_constraints_low(
3327
trx, heap, innobase_get_charset(trx->mysql_session), str, name,
3330
mem_heap_free(heap);
3336
/**************************************************************************
3337
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3340
dict_foreign_parse_drop_constraints(
3341
/*================================*/
3342
/* out: DB_SUCCESS or
3343
DB_CANNOT_DROP_CONSTRAINT if
3344
syntax error or the constraint
3345
id does not match */
3346
mem_heap_t* heap, /* in: heap from which we can
3348
trx_t* trx, /* in: transaction */
3349
dict_table_t* table, /* in: table */
3350
ulint* n, /* out: number of constraints
3352
const char*** constraints_to_drop) /* out: id's of the
3353
constraints to drop */
3355
dict_foreign_t* foreign;
3360
FILE* ef = dict_foreign_err_file;
3361
struct charset_info_st* cs;
3364
ut_a(trx->mysql_session);
3366
cs = innobase_get_charset(trx->mysql_session);
3370
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3372
str = dict_strip_comments(*(trx->mysql_query_str));
3375
ut_ad(mutex_own(&(dict_sys->mutex)));
3377
ptr = dict_scan_to(ptr, "DROP");
3385
ptr = dict_accept(cs, ptr, "DROP", &success);
3387
if (!my_isspace(cs, *ptr)) {
3392
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3394
if (!success || !my_isspace(cs, *ptr)) {
3399
ptr = dict_accept(cs, ptr, "KEY", &success);
3406
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3414
(*constraints_to_drop)[*n] = id;
3417
/* Look for the given constraint id */
3419
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3421
while (foreign != NULL) {
3422
if (0 == strcmp(foreign->id, id)
3423
|| (strchr(foreign->id, '/')
3425
dict_remove_db_name(foreign->id)))) {
3430
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3433
if (foreign == NULL) {
3434
mutex_enter(&dict_foreign_err_mutex);
3436
ut_print_timestamp(ef);
3437
fputs(" Error in dropping of a foreign key constraint"
3439
ut_print_name(ef, NULL, TRUE, table->name);
3441
"in SQL command\n", ef);
3443
fputs("\nCannot find a constraint with the given id ", ef);
3444
ut_print_name(ef, NULL, FALSE, id);
3446
mutex_exit(&dict_foreign_err_mutex);
3450
return(DB_CANNOT_DROP_CONSTRAINT);
3456
mutex_enter(&dict_foreign_err_mutex);
3458
ut_print_timestamp(ef);
3459
fputs(" Syntax error in dropping of a"
3460
" foreign key constraint of table ", ef);
3461
ut_print_name(ef, NULL, TRUE, table->name);
3463
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
3464
mutex_exit(&dict_foreign_err_mutex);
3468
return(DB_CANNOT_DROP_CONSTRAINT);
3470
#endif /* UNIV_HOTBACKUP */
3472
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3475
/**************************************************************************
3476
Returns an index object if it is found in the dictionary cache. */
3479
dict_index_get_if_in_cache(
3480
/*=======================*/
3481
/* out: index, NULL if not found */
3482
dulint index_id) /* in: index id */
3484
dict_index_t* index;
3486
if (dict_sys == NULL) {
3490
mutex_enter(&(dict_sys->mutex));
3492
index = dict_index_find_on_id_low(index_id);
3494
mutex_exit(&(dict_sys->mutex));
3498
#endif /* UNIV_DEBUG */
3501
/**************************************************************************
3502
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3503
no comparison can occur with the page number field in a node pointer. */
3506
dict_index_check_search_tuple(
3507
/*==========================*/
3508
/* out: TRUE if ok */
3509
dict_index_t* index, /* in: index tree */
3510
dtuple_t* tuple) /* in: tuple used in a search */
3513
ut_a(dtuple_get_n_fields_cmp(tuple)
3514
<= dict_index_get_n_unique_in_tree(index));
3517
#endif /* UNIV_DEBUG */
3519
/**************************************************************************
3520
Builds a node pointer out of a physical record and a page number. */
3523
dict_index_build_node_ptr(
3524
/*======================*/
3525
/* out, own: node pointer */
3526
dict_index_t* index, /* in: index tree */
3527
rec_t* rec, /* in: record for which to build node
3529
ulint page_no,/* in: page number to put in node pointer */
3530
mem_heap_t* heap, /* in: memory heap where pointer created */
3531
ulint level) /* in: level of rec in tree: 0 means leaf
3539
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3540
/* In a universal index tree, we take the whole record as
3541
the node pointer if the record is on the leaf level,
3542
on non-leaf levels we remove the last field, which
3543
contains the page number of the child page */
3545
ut_a(!dict_table_is_comp(index->table));
3546
n_unique = rec_get_n_fields_old(rec);
3553
n_unique = dict_index_get_n_unique_in_tree(index);
3556
tuple = dtuple_create(heap, n_unique + 1);
3558
/* When searching in the tree for the node pointer, we must not do
3559
comparison on the last field, the page number field, as on upper
3560
levels in the tree there may be identical node pointers with a
3561
different page number; therefore, we set the n_fields_cmp to one
3564
dtuple_set_n_fields_cmp(tuple, n_unique);
3566
dict_index_copy_types(tuple, index, n_unique);
3568
buf = mem_heap_alloc(heap, 4);
3570
mach_write_to_4(buf, page_no);
3572
field = dtuple_get_nth_field(tuple, n_unique);
3573
dfield_set_data(field, buf, 4);
3575
dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3577
rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3578
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3579
| REC_STATUS_NODE_PTR);
3581
ut_ad(dtuple_check_typed(tuple));
3586
/**************************************************************************
3587
Copies an initial segment of a physical record, long enough to specify an
3588
index entry uniquely. */
3591
dict_index_copy_rec_order_prefix(
3592
/*=============================*/
3593
/* out: pointer to the prefix record */
3594
dict_index_t* index, /* in: index tree */
3595
rec_t* rec, /* in: record for which to copy prefix */
3596
ulint* n_fields,/* out: number of fields copied */
3597
byte** buf, /* in/out: memory buffer for the copied prefix,
3599
ulint* buf_size)/* in/out: buffer size */
3603
UNIV_PREFETCH_R(rec);
3605
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3606
ut_a(!dict_table_is_comp(index->table));
3607
n = rec_get_n_fields_old(rec);
3609
n = dict_index_get_n_unique_in_tree(index);
3613
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
3616
/**************************************************************************
3617
Builds a typed data tuple out of a physical record. */
3620
dict_index_build_data_tuple(
3621
/*========================*/
3622
/* out, own: data tuple */
3623
dict_index_t* index, /* in: index tree */
3624
rec_t* rec, /* in: record for which to build data tuple */
3625
ulint n_fields,/* in: number of data fields */
3626
mem_heap_t* heap) /* in: memory heap where tuple created */
3630
ut_ad(dict_table_is_comp(index->table)
3631
|| n_fields <= rec_get_n_fields_old(rec));
3633
tuple = dtuple_create(heap, n_fields);
3635
dict_index_copy_types(tuple, index, n_fields);
3637
rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
3639
ut_ad(dtuple_check_typed(tuple));
3644
/*************************************************************************
3645
Calculates the minimum record length in an index. */
3648
dict_index_calc_min_rec_len(
3649
/*========================*/
3650
dict_index_t* index) /* in: index */
3655
if (dict_table_is_comp(index->table)) {
3657
sum = REC_N_NEW_EXTRA_BYTES;
3658
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3659
const dict_col_t* col
3660
= dict_index_get_nth_col(index, i);
3661
ulint size = dict_col_get_fixed_size(col);
3665
sum += size < 128 ? 1 : 2;
3667
if (!(col->prtype & DATA_NOT_NULL)) {
3672
/* round the NULL flags up to full bytes */
3673
sum += UT_BITS_IN_BYTES(nullable);
3678
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3679
sum += dict_col_get_fixed_size(
3680
dict_index_get_nth_col(index, i));
3684
sum += 2 * dict_index_get_n_fields(index);
3686
sum += dict_index_get_n_fields(index);
3689
sum += REC_N_OLD_EXTRA_BYTES;
3694
/*************************************************************************
3695
Calculates new estimates for table and index statistics. The statistics
3696
are used in query optimization. */
3699
dict_update_statistics_low(
3700
/*=======================*/
3701
dict_table_t* table, /* in: table */
3702
ibool has_dict_mutex __attribute__((unused)))
3703
/* in: TRUE if the caller has the
3706
dict_index_t* index;
3708
ulint sum_of_index_sizes = 0;
3710
if (table->ibd_file_missing) {
3711
ut_print_timestamp(stderr);
3713
" InnoDB: cannot calculate statistics for table %s\n"
3714
"InnoDB: because the .ibd file is missing. For help,"
3715
" please refer to\n"
3716
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3717
"innodb-troubleshooting.html\n",
3723
/* If we have set a high innodb_force_recovery level, do not calculate
3724
statistics, as a badly corrupted index can cause a crash in it. */
3726
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3731
/* Find out the sizes of the indexes and how many different values
3732
for the key they approximately have */
3734
index = dict_table_get_first_index(table);
3736
if (index == NULL) {
3737
/* Table definition is corrupt */
3743
size = btr_get_size(index, BTR_TOTAL_SIZE);
3745
index->stat_index_size = size;
3747
sum_of_index_sizes += size;
3749
size = btr_get_size(index, BTR_N_LEAF_PAGES);
3752
/* The root node of the tree is a leaf */
3756
index->stat_n_leaf_pages = size;
3758
btr_estimate_number_of_different_key_vals(index);
3760
index = dict_table_get_next_index(index);
3763
index = dict_table_get_first_index(table);
3765
table->stat_n_rows = index->stat_n_diff_key_vals[
3766
dict_index_get_n_unique(index)];
3768
table->stat_clustered_index_size = index->stat_index_size;
3770
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
3771
- index->stat_index_size;
3773
table->stat_initialized = TRUE;
3775
table->stat_modified_counter = 0;
3778
/*************************************************************************
3779
Calculates new estimates for table and index statistics. The statistics
3780
are used in query optimization. */
3783
dict_update_statistics(
3784
/*===================*/
3785
dict_table_t* table) /* in: table */
3787
dict_update_statistics_low(table, FALSE);
3790
/**************************************************************************
3791
A noninlined version of dict_table_get_low. */
3794
dict_table_get_low_noninlined(
3795
/*==========================*/
3796
/* out: table, NULL if not found */
3797
const char* table_name) /* in: table name */
3799
return(dict_table_get_low(table_name));
3802
/**************************************************************************
3803
Prints info of a foreign key constraint. */
3806
dict_foreign_print_low(
3807
/*===================*/
3808
dict_foreign_t* foreign) /* in: foreign key constraint */
3812
ut_ad(mutex_own(&(dict_sys->mutex)));
3814
fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
3815
foreign->id, foreign->foreign_table_name);
3817
for (i = 0; i < foreign->n_fields; i++) {
3818
fprintf(stderr, " %s", foreign->foreign_col_names[i]);
3821
fprintf(stderr, " )\n"
3823
foreign->referenced_table_name);
3825
for (i = 0; i < foreign->n_fields; i++) {
3826
fprintf(stderr, " %s", foreign->referenced_col_names[i]);
3829
fputs(" )\n", stderr);
3832
/**************************************************************************
3833
Prints a table data. */
3838
dict_table_t* table) /* in: table */
3840
mutex_enter(&(dict_sys->mutex));
3841
dict_table_print_low(table);
3842
mutex_exit(&(dict_sys->mutex));
3845
/**************************************************************************
3846
Prints a table data when we know the table name. */
3849
dict_table_print_by_name(
3850
/*=====================*/
3853
dict_table_t* table;
3855
mutex_enter(&(dict_sys->mutex));
3857
table = dict_table_get_low(name);
3861
dict_table_print_low(table);
3862
mutex_exit(&(dict_sys->mutex));
3865
/**************************************************************************
3866
Prints a table data. */
3869
dict_table_print_low(
3870
/*=================*/
3871
dict_table_t* table) /* in: table */
3873
dict_index_t* index;
3874
dict_foreign_t* foreign;
3877
ut_ad(mutex_own(&(dict_sys->mutex)));
3879
dict_update_statistics_low(table, TRUE);
3882
"--------------------------------------\n"
3883
"TABLE: name %s, id %lu %lu, columns %lu, indexes %lu,"
3887
(ulong) ut_dulint_get_high(table->id),
3888
(ulong) ut_dulint_get_low(table->id),
3889
(ulong) table->n_cols,
3890
(ulong) UT_LIST_GET_LEN(table->indexes),
3891
(ulong) table->stat_n_rows);
3893
for (i = 0; i + 1 < (ulint) table->n_cols; i++) {
3894
dict_col_print_low(table, dict_table_get_nth_col(table, i));
3895
fputs("; ", stderr);
3900
index = UT_LIST_GET_FIRST(table->indexes);
3902
while (index != NULL) {
3903
dict_index_print_low(index);
3904
index = UT_LIST_GET_NEXT(indexes, index);
3907
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3909
while (foreign != NULL) {
3910
dict_foreign_print_low(foreign);
3911
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3914
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3916
while (foreign != NULL) {
3917
dict_foreign_print_low(foreign);
3918
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3922
/**************************************************************************
3923
Prints a column data. */
3928
const dict_table_t* table, /* in: table */
3929
const dict_col_t* col) /* in: column */
3933
ut_ad(mutex_own(&(dict_sys->mutex)));
3935
dict_col_copy_type(col, &type);
3936
fprintf(stderr, "%s: ", dict_table_get_col_name(table,
3937
dict_col_get_no(col)));
3942
/**************************************************************************
3943
Prints an index data. */
3946
dict_index_print_low(
3947
/*=================*/
3948
dict_index_t* index) /* in: index */
3953
ut_ad(mutex_own(&(dict_sys->mutex)));
3955
if (index->n_user_defined_cols > 0) {
3956
n_vals = index->stat_n_diff_key_vals[
3957
index->n_user_defined_cols];
3959
n_vals = index->stat_n_diff_key_vals[1];
3963
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
3964
" uniq %lu, type %lu\n"
3965
" root page %lu, appr.key vals %lu,"
3966
" leaf pages %lu, size pages %lu\n"
3969
(ulong) ut_dulint_get_high(index->id),
3970
(ulong) ut_dulint_get_low(index->id),
3971
(ulong) index->n_user_defined_cols,
3972
(ulong) index->n_fields,
3973
(ulong) index->n_uniq,
3974
(ulong) index->type,
3975
(ulong) index->page,
3977
(ulong) index->stat_n_leaf_pages,
3978
(ulong) index->stat_index_size);
3980
for (i = 0; i < index->n_fields; i++) {
3981
dict_field_print_low(dict_index_get_nth_field(index, i));
3986
#ifdef UNIV_BTR_PRINT
3987
btr_print_size(index);
3989
btr_print_index(index, 7);
3990
#endif /* UNIV_BTR_PRINT */
3993
/**************************************************************************
3994
Prints a field data. */
3997
dict_field_print_low(
3998
/*=================*/
3999
dict_field_t* field) /* in: field */
4001
ut_ad(mutex_own(&(dict_sys->mutex)));
4003
fprintf(stderr, " %s", field->name);
4005
if (field->prefix_len != 0) {
4006
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4010
/**************************************************************************
4011
Outputs info on a foreign key of a table in a format suitable for
4015
dict_print_info_on_foreign_key_in_create_format(
4016
/*============================================*/
4017
FILE* file, /* in: file where to print */
4018
trx_t* trx, /* in: transaction */
4019
dict_foreign_t* foreign, /* in: foreign key constraint */
4020
ibool add_newline) /* in: whether to add a newline */
4022
const char* stripped_id;
4025
if (strchr(foreign->id, '/')) {
4026
/* Strip the preceding database name from the constraint id */
4027
stripped_id = foreign->id + 1
4028
+ dict_get_db_name_len(foreign->id);
4030
stripped_id = foreign->id;
4036
/* SHOW CREATE TABLE wants constraints each printed nicely
4037
on its own line, while error messages want no newlines
4042
fputs(" CONSTRAINT ", file);
4043
ut_print_name(file, trx, FALSE, stripped_id);
4044
fputs(" FOREIGN KEY (", file);
4047
ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4048
if (++i < foreign->n_fields) {
4055
fputs(") REFERENCES ", file);
4057
if (dict_tables_have_same_db(foreign->foreign_table_name,
4058
foreign->referenced_table_name)) {
4059
/* Do not print the database name of the referenced table */
4060
ut_print_name(file, trx, TRUE,
4061
dict_remove_db_name(
4062
foreign->referenced_table_name));
4064
ut_print_name(file, trx, TRUE,
4065
foreign->referenced_table_name);
4072
ut_print_name(file, trx, FALSE,
4073
foreign->referenced_col_names[i]);
4074
if (++i < foreign->n_fields) {
4083
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4084
fputs(" ON DELETE CASCADE", file);
4087
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4088
fputs(" ON DELETE SET NULL", file);
4091
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4092
fputs(" ON DELETE NO ACTION", file);
4095
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4096
fputs(" ON UPDATE CASCADE", file);
4099
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4100
fputs(" ON UPDATE SET NULL", file);
4103
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4104
fputs(" ON UPDATE NO ACTION", file);
4108
/**************************************************************************
4109
Outputs info on foreign keys of a table. */
4112
dict_print_info_on_foreign_keys(
4113
/*============================*/
4114
ibool create_table_format, /* in: if TRUE then print in
4115
a format suitable to be inserted into
4116
a CREATE TABLE, otherwise in the format
4117
of SHOW TABLE STATUS */
4118
FILE* file, /* in: file where to print */
4119
trx_t* trx, /* in: transaction */
4120
dict_table_t* table) /* in: table */
4122
dict_foreign_t* foreign;
4124
mutex_enter(&(dict_sys->mutex));
4126
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4128
if (foreign == NULL) {
4129
mutex_exit(&(dict_sys->mutex));
4134
while (foreign != NULL) {
4135
if (create_table_format) {
4136
dict_print_info_on_foreign_key_in_create_format(
4137
file, trx, foreign, TRUE);
4142
for (i = 0; i < foreign->n_fields; i++) {
4147
ut_print_name(file, trx, FALSE,
4148
foreign->foreign_col_names[i]);
4151
fputs(") REFER ", file);
4152
ut_print_name(file, trx, TRUE,
4153
foreign->referenced_table_name);
4156
for (i = 0; i < foreign->n_fields; i++) {
4162
foreign->referenced_col_names[i]);
4167
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4168
fputs(" ON DELETE CASCADE", file);
4171
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4172
fputs(" ON DELETE SET NULL", file);
4175
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4176
fputs(" ON DELETE NO ACTION", file);
4179
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4180
fputs(" ON UPDATE CASCADE", file);
4183
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4184
fputs(" ON UPDATE SET NULL", file);
4187
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4188
fputs(" ON UPDATE NO ACTION", file);
4192
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4195
mutex_exit(&(dict_sys->mutex));
4198
/************************************************************************
4199
Displays the names of the index and the table. */
4201
dict_index_name_print(
4202
/*==================*/
4203
FILE* file, /* in: output stream */
4204
trx_t* trx, /* in: transaction */
4205
const dict_index_t* index) /* in: index to print */
4207
fputs("index ", file);
4208
ut_print_name(file, trx, FALSE, index->name);
4209
fputs(" of table ", file);
4210
ut_print_name(file, trx, TRUE, index->table_name);