1
/**********************************************************************
6
Created 1/8/1996 Heikki Tuuri
7
***********************************************************************/
12
#include "dict0dict.ic"
16
#include "data0type.h"
17
#include "mach0data.h"
18
#include "dict0boot.h"
20
#include "dict0crea.h"
25
#include "pars0pars.h"
29
#ifndef UNIV_HOTBACKUP
30
# include "m_ctype.h" /* my_isspace() */
31
#endif /* !UNIV_HOTBACKUP */
35
dict_sys_t* dict_sys = NULL; /* the dictionary system */
37
rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
38
this in X-mode; implicit or backround
39
operations purge, rollback, foreign
40
key checks reserve this in S-mode; we
41
cannot trust that MySQL protects
42
implicit or background operations
43
a table drop since MySQL does not
44
know of them; therefore we need this;
45
NOTE: a transaction which reserves
46
this must keep book on the mode in
47
trx->dict_operation_lock_mode */
49
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
50
creating a table or index object */
51
#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
52
hash table fixed size in bytes */
53
#define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data
54
dictionary varying size in bytes */
56
/* Identifies generated InnoDB foreign key names */
57
static char dict_ibfk[] = "_ibfk_";
59
#ifndef UNIV_HOTBACKUP
60
/**********************************************************************
61
Converts an identifier to a table name.
63
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
64
this function, you MUST change also the prototype here! */
67
innobase_convert_from_table_id(
68
/*===========================*/
69
char* to, /* out: converted identifier */
70
const char* from, /* in: identifier to convert */
71
ulint len); /* in: length of 'to', in bytes;
72
should be at least 5 * strlen(to) + 1 */
73
/**********************************************************************
74
Converts an identifier to UTF-8.
76
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
77
this function, you MUST change also the prototype here! */
80
innobase_convert_from_id(
81
/*=====================*/
82
char* to, /* out: converted identifier */
83
const char* from, /* in: identifier to convert */
84
ulint len); /* in: length of 'to', in bytes;
85
should be at least 3 * strlen(to) + 1 */
86
/**********************************************************************
87
Compares NUL-terminated UTF-8 strings case insensitively.
89
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
90
this function, you MUST change also the prototype here! */
95
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
96
const char* a, /* in: first string to compare */
97
const char* b); /* in: second string to compare */
99
/**********************************************************************
100
Makes all characters in a NUL-terminated UTF-8 string lower case.
102
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
103
this function, you MUST change also the prototype here! */
108
char* a); /* in/out: string to put in lower case */
110
/**************************************************************************
111
Determines the connection character set.
113
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
114
this function, you MUST change also the prototype here! */
115
struct charset_info_st*
116
innobase_get_charset(
117
/*=================*/
118
/* out: connection character set */
119
void* mysql_thd); /* in: MySQL thread handle */
120
#endif /* !UNIV_HOTBACKUP */
122
/**************************************************************************
123
Removes an index from the dictionary cache. */
126
dict_index_remove_from_cache(
127
/*=========================*/
128
dict_table_t* table, /* in: table */
129
dict_index_t* index); /* in, own: index */
130
/***********************************************************************
131
Copies fields contained in index2 to index1. */
136
dict_index_t* index1, /* in: index to copy to */
137
dict_index_t* index2, /* in: index to copy from */
138
dict_table_t* table, /* in: table */
139
ulint start, /* in: first position to copy */
140
ulint end); /* in: last position to copy */
141
/***********************************************************************
142
Tries to find column names for the index and sets the col field of the
146
dict_index_find_cols(
147
/*=================*/
148
dict_table_t* table, /* in: table */
149
dict_index_t* index); /* in: index */
150
/***********************************************************************
151
Builds the internal dictionary cache representation for a clustered
152
index, containing also system fields not defined by the user. */
155
dict_index_build_internal_clust(
156
/*============================*/
157
/* out, own: the internal representation
158
of the clustered index */
159
dict_table_t* table, /* in: table */
160
dict_index_t* index); /* in: user representation of a clustered
162
/***********************************************************************
163
Builds the internal dictionary cache representation for a non-clustered
164
index, containing also system fields not defined by the user. */
167
dict_index_build_internal_non_clust(
168
/*================================*/
169
/* out, own: the internal representation
170
of the non-clustered index */
171
dict_table_t* table, /* in: table */
172
dict_index_t* index); /* in: user representation of a non-clustered
174
/**************************************************************************
175
Removes a foreign constraint struct from the dictionary cache. */
178
dict_foreign_remove_from_cache(
179
/*===========================*/
180
dict_foreign_t* foreign); /* in, own: foreign constraint */
181
/**************************************************************************
182
Prints a column data. */
187
const dict_table_t* table, /* in: table */
188
const dict_col_t* col); /* in: column */
189
/**************************************************************************
190
Prints an index data. */
193
dict_index_print_low(
194
/*=================*/
195
dict_index_t* index); /* in: index */
196
/**************************************************************************
197
Prints a field data. */
200
dict_field_print_low(
201
/*=================*/
202
dict_field_t* field); /* in: field */
203
/*************************************************************************
204
Frees a foreign key struct. */
209
dict_foreign_t* foreign); /* in, own: foreign key struct */
211
/* Stream for storing detailed information about the latest foreign key
212
and unique key errors */
213
FILE* dict_foreign_err_file = NULL;
214
mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign
215
and unique error buffers */
217
#ifndef UNIV_HOTBACKUP
218
/**********************************************************************
219
Makes all characters in a NUL-terminated UTF-8 string lower case. */
224
char* a) /* in/out: string to put in lower case */
226
innobase_casedn_str(a);
228
#endif /* !UNIV_HOTBACKUP */
230
/************************************************************************
231
Checks if the database name in two table names is the same. */
234
dict_tables_have_same_db(
235
/*=====================*/
236
/* out: TRUE if same db name */
237
const char* name1, /* in: table name in the form
238
dbname '/' tablename */
239
const char* name2) /* in: table name in the form
240
dbname '/' tablename */
242
for (; *name1 == *name2; name1++, name2++) {
246
ut_a(*name1); /* the names must contain '/' */
251
/************************************************************************
252
Return the end of table name where we have removed dbname and '/'. */
257
/* out: table name */
258
const char* name) /* in: table name in the form
259
dbname '/' tablename */
261
const char* s = strchr(name, '/');
267
/************************************************************************
268
Get the database name length in a table name. */
271
dict_get_db_name_len(
272
/*=================*/
273
/* out: database name length */
274
const char* name) /* in: table name in the form
275
dbname '/' tablename */
278
s = strchr(name, '/');
283
/************************************************************************
284
Reserves the dictionary system mutex for MySQL. */
287
dict_mutex_enter_for_mysql(void)
288
/*============================*/
290
mutex_enter(&(dict_sys->mutex));
293
/************************************************************************
294
Releases the dictionary system mutex for MySQL. */
297
dict_mutex_exit_for_mysql(void)
298
/*===========================*/
300
mutex_exit(&(dict_sys->mutex));
303
/************************************************************************
304
Decrements the count of open MySQL handles to a table. */
307
dict_table_decrement_handle_count(
308
/*==============================*/
309
dict_table_t* table) /* in: table */
311
mutex_enter(&(dict_sys->mutex));
313
ut_a(table->n_mysql_handles_opened > 0);
315
table->n_mysql_handles_opened--;
317
mutex_exit(&(dict_sys->mutex));
320
/*************************************************************************
321
Gets the column data type. */
324
dict_col_copy_type_noninline(
325
/*=========================*/
326
const dict_col_t* col, /* in: column */
327
dtype_t* type) /* out: data type */
329
dict_col_copy_type(col, type);
332
/************************************************************************
333
Gets the nth column of a table. */
336
dict_table_get_nth_col_noninline(
337
/*=============================*/
338
/* out: pointer to column object */
339
const dict_table_t* table, /* in: table */
340
ulint pos) /* in: position of column */
342
return(dict_table_get_nth_col(table, pos));
345
/************************************************************************
346
Gets the first index on the table (the clustered index). */
349
dict_table_get_first_index_noninline(
350
/*=================================*/
351
/* out: index, NULL if none exists */
352
dict_table_t* table) /* in: table */
354
return(dict_table_get_first_index(table));
357
/************************************************************************
358
Gets the next index on the table. */
361
dict_table_get_next_index_noninline(
362
/*================================*/
363
/* out: index, NULL if none left */
364
dict_index_t* index) /* in: index */
366
return(dict_table_get_next_index(index));
369
/**************************************************************************
370
Returns an index object. */
373
dict_table_get_index_noninline(
374
/*===========================*/
375
/* out: index, NULL if does not exist */
376
dict_table_t* table, /* in: table */
377
const char* name) /* in: index name */
379
return(dict_table_get_index(table, name));
382
/**************************************************************************
383
Returns a column's name. */
386
dict_table_get_col_name(
387
/*====================*/
388
/* out: column name. NOTE: not
389
guaranteed to stay valid if table is
390
modified in any way (columns added,
392
const dict_table_t* table, /* in: table */
393
ulint col_nr) /* in: column number */
399
ut_ad(col_nr < table->n_def);
400
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
402
s = table->col_names;
404
for (i = 0; i < col_nr; i++) {
413
/************************************************************************
414
Acquire the autoinc lock.*/
417
dict_table_autoinc_lock(
418
/*====================*/
421
mutex_enter(&table->autoinc_mutex);
424
/************************************************************************
425
Initializes the autoinc counter. It is not an error to initialize an already
426
initialized counter. */
429
dict_table_autoinc_initialize(
430
/*==========================*/
431
dict_table_t* table, /* in: table */
432
ib_longlong value) /* in: next value to assign to a row */
434
ut_ad(mutex_own(&table->autoinc_mutex));
436
table->autoinc_inited = TRUE;
437
table->autoinc = value;
440
/************************************************************************
441
Reads the next autoinc value (== autoinc counter value), 0 if not yet
445
dict_table_autoinc_read(
446
/*====================*/
447
/* out: value for a new row, or 0 */
448
dict_table_t* table) /* in: table */
452
ut_ad(mutex_own(&table->autoinc_mutex));
454
if (!table->autoinc_inited) {
458
value = table->autoinc;
464
/************************************************************************
465
Updates the autoinc counter if the value supplied is greater than the
466
current value. If not inited, does nothing. */
469
dict_table_autoinc_update(
470
/*======================*/
472
dict_table_t* table, /* in: table */
473
ib_longlong value) /* in: value which was assigned to a row */
475
if (table->autoinc_inited && value > table->autoinc) {
477
table->autoinc = value;
481
/************************************************************************
482
Release the autoinc lock.*/
485
dict_table_autoinc_unlock(
486
/*======================*/
487
dict_table_t* table) /* in: release autoinc lock for this table */
489
mutex_exit(&table->autoinc_mutex);
492
/************************************************************************
493
Looks for column n in an index. */
496
dict_index_get_nth_col_pos(
497
/*=======================*/
498
/* out: position in internal representation
499
of the index; if not contained, returns
501
dict_index_t* index, /* in: index */
502
ulint n) /* in: column number */
504
const dict_field_t* field;
505
const dict_col_t* col;
510
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
512
col = dict_table_get_nth_col(index->table, n);
514
if (index->type & DICT_CLUSTERED) {
516
return(dict_col_get_clust_pos(col, index));
519
n_fields = dict_index_get_n_fields(index);
521
for (pos = 0; pos < n_fields; pos++) {
522
field = dict_index_get_nth_field(index, pos);
524
if (col == field->col && field->prefix_len == 0) {
530
return(ULINT_UNDEFINED);
533
/************************************************************************
534
Returns TRUE if the index contains a column or a prefix of that column. */
537
dict_index_contains_col_or_prefix(
538
/*==============================*/
539
/* out: TRUE if contains the column or its
541
dict_index_t* index, /* in: index */
542
ulint n) /* in: column number */
544
const dict_field_t* field;
545
const dict_col_t* col;
550
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
552
if (index->type & DICT_CLUSTERED) {
557
col = dict_table_get_nth_col(index->table, n);
559
n_fields = dict_index_get_n_fields(index);
561
for (pos = 0; pos < n_fields; pos++) {
562
field = dict_index_get_nth_field(index, pos);
564
if (col == field->col) {
573
/************************************************************************
574
Looks for a matching field in an index. The column has to be the same. The
575
column in index must be complete, or must contain a prefix longer than the
576
column in index2. That is, we must be able to construct the prefix in index2
577
from the prefix in index. */
580
dict_index_get_nth_field_pos(
581
/*=========================*/
582
/* out: position in internal representation
583
of the index; if not contained, returns
585
dict_index_t* index, /* in: index from which to search */
586
dict_index_t* index2, /* in: index */
587
ulint n) /* in: field number in index2 */
590
dict_field_t* field2;
595
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
597
field2 = dict_index_get_nth_field(index2, n);
599
n_fields = dict_index_get_n_fields(index);
601
for (pos = 0; pos < n_fields; pos++) {
602
field = dict_index_get_nth_field(index, pos);
604
if (field->col == field2->col
605
&& (field->prefix_len == 0
606
|| (field->prefix_len >= field2->prefix_len
607
&& field2->prefix_len != 0))) {
613
return(ULINT_UNDEFINED);
616
/**************************************************************************
617
Returns a table object based on table id. */
620
dict_table_get_on_id(
621
/*=================*/
622
/* out: table, NULL if does not exist */
623
dulint table_id, /* in: table id */
624
trx_t* trx) /* in: transaction handle */
628
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
629
|| trx->dict_operation_lock_mode == RW_X_LATCH) {
630
/* It is a system table which will always exist in the table
631
cache: we avoid acquiring the dictionary mutex, because
632
if we are doing a rollback to handle an error in TABLE
633
CREATE, for example, we already have the mutex! */
635
ut_ad(mutex_own(&(dict_sys->mutex))
636
|| trx->dict_operation_lock_mode == RW_X_LATCH);
638
return(dict_table_get_on_id_low(table_id));
641
mutex_enter(&(dict_sys->mutex));
643
table = dict_table_get_on_id_low(table_id);
645
mutex_exit(&(dict_sys->mutex));
650
/************************************************************************
651
Looks for column n position in the clustered index. */
654
dict_table_get_nth_col_pos(
655
/*=======================*/
656
/* out: position in internal representation
657
of the clustered index */
658
dict_table_t* table, /* in: table */
659
ulint n) /* in: column number */
661
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
665
/************************************************************************
666
Check whether the table uses the compact page format. */
669
dict_table_is_comp_noninline(
670
/*=========================*/
671
/* out: TRUE if table uses the
672
compact page format */
673
const dict_table_t* table) /* in: table */
675
return(dict_table_is_comp(table));
678
/************************************************************************
679
Checks if a column is in the ordering columns of the clustered index of a
680
table. Column prefixes are treated like whole columns. */
683
dict_table_col_in_clustered_key(
684
/*============================*/
685
/* out: TRUE if the column, or its prefix, is
686
in the clustered key */
687
dict_table_t* table, /* in: table */
688
ulint n) /* in: column number */
691
const dict_field_t* field;
692
const dict_col_t* col;
698
col = dict_table_get_nth_col(table, n);
700
index = dict_table_get_first_index(table);
702
n_fields = dict_index_get_n_unique(index);
704
for (pos = 0; pos < n_fields; pos++) {
705
field = dict_index_get_nth_field(index, pos);
707
if (col == field->col) {
716
/**************************************************************************
717
Inits the data dictionary module. */
723
dict_sys = mem_alloc(sizeof(dict_sys_t));
725
mutex_create(&dict_sys->mutex, SYNC_DICT);
727
dict_sys->table_hash = hash_create(buf_pool_get_max_size()
728
/ (DICT_POOL_PER_TABLE_HASH
730
dict_sys->table_id_hash = hash_create(buf_pool_get_max_size()
731
/ (DICT_POOL_PER_TABLE_HASH
735
UT_LIST_INIT(dict_sys->table_LRU);
737
rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
739
dict_foreign_err_file = os_file_create_tmpfile();
740
ut_a(dict_foreign_err_file);
742
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
745
/**************************************************************************
746
Returns a table object and optionally increment its MySQL open handle count.
747
NOTE! This is a high-level function to be used mainly from outside the
748
'dict' directory. Inside this directory dict_table_get_low is usually the
749
appropriate function. */
754
/* out: table, NULL if
756
const char* table_name, /* in: table name */
757
ibool inc_mysql_count)
758
/* in: whether to increment the open
759
handle count on the table */
763
mutex_enter(&(dict_sys->mutex));
765
table = dict_table_get_low(table_name);
767
if (inc_mysql_count && table) {
768
table->n_mysql_handles_opened++;
771
mutex_exit(&(dict_sys->mutex));
774
if (!table->stat_initialized) {
775
/* If table->ibd_file_missing == TRUE, this will
776
print an error message and return without doing
778
dict_update_statistics(table);
785
/**************************************************************************
786
Adds system columns to a table object. */
789
dict_table_add_system_columns(
790
/*==========================*/
791
dict_table_t* table, /* in/out: table */
792
mem_heap_t* heap) /* in: temporary heap */
795
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
796
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
797
ut_ad(!table->cached);
799
/* NOTE: the system columns MUST be added in the following order
800
(so that they can be indexed by the numerical value of DATA_ROW_ID,
801
etc.) and as the last columns of the table memory object.
802
The clustered index will not always physically contain all
805
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
806
DATA_ROW_ID | DATA_NOT_NULL,
809
#error "DATA_ROW_ID != 0"
811
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
812
DATA_TRX_ID | DATA_NOT_NULL,
815
#error "DATA_TRX_ID != 1"
817
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
818
DATA_ROLL_PTR | DATA_NOT_NULL,
820
#if DATA_ROLL_PTR != 2
821
#error "DATA_ROLL_PTR != 2"
824
/* This check reminds that if a new system column is added to
825
the program, it should be dealt with here */
826
#if DATA_N_SYS_COLS != 3
827
#error "DATA_N_SYS_COLS != 3"
831
/**************************************************************************
832
Adds a table object to the dictionary cache. */
835
dict_table_add_to_cache(
836
/*====================*/
837
dict_table_t* table, /* in: table */
838
mem_heap_t* heap) /* in: temporary heap */
845
/* The lower limit for what we consider a "big" row */
846
#define BIG_ROW_SIZE 1024
848
ut_ad(mutex_own(&(dict_sys->mutex)));
850
dict_table_add_system_columns(table, heap);
852
table->cached = TRUE;
854
fold = ut_fold_string(table->name);
855
id_fold = ut_fold_dulint(table->id);
858
for (i = 0; i < table->n_def; i++) {
859
ulint col_len = dict_col_get_max_size(
860
dict_table_get_nth_col(table, i));
864
/* If we have a single unbounded field, or several gigantic
865
fields, mark the maximum row size as BIG_ROW_SIZE. */
866
if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
867
row_len = BIG_ROW_SIZE;
873
table->big_rows = row_len >= BIG_ROW_SIZE;
875
/* Look for a table with the same name: error if such exists */
877
dict_table_t* table2;
878
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
879
(ut_strcmp(table2->name, table->name) == 0));
880
ut_a(table2 == NULL);
883
/* Look for a table with the same id: error if such exists */
885
dict_table_t* table2;
886
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2,
887
(ut_dulint_cmp(table2->id, table->id) == 0));
888
ut_a(table2 == NULL);
891
/* Add table to hash table of tables */
892
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
895
/* Add table to hash table of tables based on table id */
896
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
898
/* Add table to LRU list of tables */
899
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
901
dict_sys->size += mem_heap_get_size(table->heap);
904
/**************************************************************************
905
Looks for an index with the given id. NOTE that we do not reserve
906
the dictionary mutex: this function is for emergency purposes like
907
printing info of a corrupt database page! */
910
dict_index_find_on_id_low(
911
/*======================*/
912
/* out: index or NULL if not found from cache */
913
dulint id) /* in: index id */
918
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
921
index = dict_table_get_first_index(table);
924
if (0 == ut_dulint_cmp(id, index->id)) {
930
index = dict_table_get_next_index(index);
933
table = UT_LIST_GET_NEXT(table_LRU, table);
939
/**************************************************************************
940
Renames a table object. */
943
dict_table_rename_in_cache(
944
/*=======================*/
945
/* out: TRUE if success */
946
dict_table_t* table, /* in: table */
947
const char* new_name, /* in: new name */
948
ibool rename_also_foreigns)/* in: in ALTER TABLE we want
949
to preserve the original table name
950
in constraints which reference it */
952
dict_foreign_t* foreign;
960
ut_ad(mutex_own(&(dict_sys->mutex)));
962
old_size = mem_heap_get_size(table->heap);
964
fold = ut_fold_string(new_name);
966
/* Look for a table with the same name: error if such exists */
968
dict_table_t* table2;
969
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
970
(ut_strcmp(table2->name, new_name) == 0));
973
"InnoDB: Error: dictionary cache"
974
" already contains a table of name %s\n",
980
/* If the table is stored in a single-table tablespace, rename the
983
if (table->space != 0) {
984
if (table->dir_path_of_temp_table != NULL) {
986
"InnoDB: Error: trying to rename a table"
987
" %s (%s) created with CREATE\n"
988
"InnoDB: TEMPORARY TABLE\n",
989
table->name, table->dir_path_of_temp_table);
992
success = fil_rename_tablespace(
993
table->name, table->space, new_name);
1002
/* Remove table from the hash tables of tables */
1003
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1004
ut_fold_string(table->name), table);
1005
old_name = mem_heap_strdup(table->heap, table->name);
1006
table->name = mem_heap_strdup(table->heap, new_name);
1008
/* Add table to hash table of tables */
1009
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1011
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
1013
/* Update the table_name field in indexes */
1014
index = dict_table_get_first_index(table);
1016
while (index != NULL) {
1017
index->table_name = table->name;
1019
index = dict_table_get_next_index(index);
1022
if (!rename_also_foreigns) {
1023
/* In ALTER TABLE we think of the rename table operation
1024
in the direction table -> temporary table (#sql...)
1025
as dropping the table with the old name and creating
1026
a new with the new name. Thus we kind of drop the
1027
constraints from the dictionary cache here. The foreign key
1028
constraints will be inherited to the new table from the
1029
system tables through a call of dict_load_foreigns. */
1031
/* Remove the foreign constraints from the cache */
1032
foreign = UT_LIST_GET_LAST(table->foreign_list);
1034
while (foreign != NULL) {
1035
dict_foreign_remove_from_cache(foreign);
1036
foreign = UT_LIST_GET_LAST(table->foreign_list);
1039
/* Reset table field in referencing constraints */
1041
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1043
while (foreign != NULL) {
1044
foreign->referenced_table = NULL;
1045
foreign->referenced_index = NULL;
1047
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1050
/* Make the list of referencing constraints empty */
1052
UT_LIST_INIT(table->referenced_list);
1057
/* Update the table name fields in foreign constraints, and update also
1058
the constraint id of new format >= 4.0.18 constraints. Note that at
1059
this point we have already changed table->name to the new name. */
1061
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1063
while (foreign != NULL) {
1064
if (ut_strlen(foreign->foreign_table_name)
1065
< ut_strlen(table->name)) {
1066
/* Allocate a longer name buffer;
1067
TODO: store buf len to save memory */
1069
foreign->foreign_table_name
1070
= mem_heap_alloc(foreign->heap,
1071
ut_strlen(table->name) + 1);
1074
strcpy(foreign->foreign_table_name, table->name);
1076
if (strchr(foreign->id, '/')) {
1080
/* This is a >= 4.0.18 format id */
1082
old_id = mem_strdup(foreign->id);
1084
if (ut_strlen(foreign->id) > ut_strlen(old_name)
1085
+ ((sizeof dict_ibfk) - 1)
1086
&& !memcmp(foreign->id, old_name,
1087
ut_strlen(old_name))
1088
&& !memcmp(foreign->id + ut_strlen(old_name),
1089
dict_ibfk, (sizeof dict_ibfk) - 1)) {
1091
/* This is a generated >= 4.0.18 format id */
1093
if (strlen(table->name) > strlen(old_name)) {
1094
foreign->id = mem_heap_alloc(
1097
+ strlen(old_id) + 1);
1100
/* Replace the prefix 'databasename/tablename'
1101
with the new names */
1102
strcpy(foreign->id, table->name);
1104
old_id + ut_strlen(old_name));
1106
/* This is a >= 4.0.18 format id where the user
1108
db_len = dict_get_db_name_len(table->name) + 1;
1110
if (dict_get_db_name_len(table->name)
1111
> dict_get_db_name_len(foreign->id)) {
1113
foreign->id = mem_heap_alloc(
1115
db_len + strlen(old_id) + 1);
1118
/* Replace the database prefix in id with the
1119
one from table->name */
1121
ut_memcpy(foreign->id, table->name, db_len);
1123
strcpy(foreign->id + db_len,
1124
dict_remove_db_name(old_id));
1130
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1133
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1135
while (foreign != NULL) {
1136
if (ut_strlen(foreign->referenced_table_name)
1137
< ut_strlen(table->name)) {
1138
/* Allocate a longer name buffer;
1139
TODO: store buf len to save memory */
1141
foreign->referenced_table_name = mem_heap_alloc(
1142
foreign->heap, strlen(table->name) + 1);
1145
strcpy(foreign->referenced_table_name, table->name);
1147
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1153
/**************************************************************************
1154
Change the id of a table object in the dictionary cache. This is used in
1155
DISCARD TABLESPACE. */
1158
dict_table_change_id_in_cache(
1159
/*==========================*/
1160
dict_table_t* table, /* in: table object already in cache */
1161
dulint new_id) /* in: new id to set */
1164
ut_ad(mutex_own(&(dict_sys->mutex)));
1165
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1167
/* Remove the table from the hash table of id's */
1169
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1170
ut_fold_dulint(table->id), table);
1173
/* Add the table back to the hash table */
1174
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1175
ut_fold_dulint(table->id), table);
1178
/**************************************************************************
1179
Removes a table object from the dictionary cache. */
1182
dict_table_remove_from_cache(
1183
/*=========================*/
1184
dict_table_t* table) /* in, own: table */
1186
dict_foreign_t* foreign;
1187
dict_index_t* index;
1191
ut_ad(mutex_own(&(dict_sys->mutex)));
1192
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1195
fputs("Removing table ", stderr);
1196
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1197
fputs(" from dictionary cache\n", stderr);
1200
/* Remove the foreign constraints from the cache */
1201
foreign = UT_LIST_GET_LAST(table->foreign_list);
1203
while (foreign != NULL) {
1204
dict_foreign_remove_from_cache(foreign);
1205
foreign = UT_LIST_GET_LAST(table->foreign_list);
1208
/* Reset table field in referencing constraints */
1210
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1212
while (foreign != NULL) {
1213
foreign->referenced_table = NULL;
1214
foreign->referenced_index = NULL;
1216
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1219
/* Remove the indexes from the cache */
1220
index = UT_LIST_GET_LAST(table->indexes);
1222
while (index != NULL) {
1223
dict_index_remove_from_cache(table, index);
1224
index = UT_LIST_GET_LAST(table->indexes);
1227
/* Remove table from the hash tables of tables */
1228
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1229
ut_fold_string(table->name), table);
1230
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1231
ut_fold_dulint(table->id), table);
1233
/* Remove table from LRU list of tables */
1234
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1236
size = mem_heap_get_size(table->heap);
1238
ut_ad(dict_sys->size >= size);
1240
dict_sys->size -= size;
1242
dict_mem_table_free(table);
1245
/*************************************************************************
1246
Gets the column position in the clustered index. */
1249
dict_col_get_clust_pos_noninline(
1250
/*=============================*/
1251
const dict_col_t* col, /* in: table column */
1252
const dict_index_t* clust_index) /* in: clustered index */
1254
return(dict_col_get_clust_pos(col, clust_index));
1257
/********************************************************************
1258
If the given column name is reserved for InnoDB system columns, return
1262
dict_col_name_is_reserved(
1263
/*======================*/
1264
/* out: TRUE if name is reserved */
1265
const char* name) /* in: column name */
1267
/* This check reminds that if a new system column is added to
1268
the program, it should be dealt with here. */
1269
#if DATA_N_SYS_COLS != 3
1270
#error "DATA_N_SYS_COLS != 3"
1273
static const char* reserved_names[] = {
1274
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1279
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1280
if (strcmp(name, reserved_names[i]) == 0) {
1289
/**************************************************************************
1290
Adds an index to the dictionary cache. */
1293
dict_index_add_to_cache(
1294
/*====================*/
1295
dict_table_t* table, /* in: table on which the index is */
1296
dict_index_t* index, /* in, own: index; NOTE! The index memory
1297
object is freed in this function! */
1298
ulint page_no)/* in: root page number of the index */
1300
dict_index_t* new_index;
1305
ut_ad(mutex_own(&(dict_sys->mutex)));
1306
ut_ad(index->n_def == index->n_fields);
1307
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1309
ut_ad(mem_heap_validate(index->heap));
1313
dict_index_t* index2;
1314
index2 = UT_LIST_GET_FIRST(table->indexes);
1316
while (index2 != NULL) {
1317
ut_ad(ut_strcmp(index->name, index2->name) != 0);
1319
index2 = UT_LIST_GET_NEXT(indexes, index2);
1322
#endif /* UNIV_DEBUG */
1324
ut_a(!(index->type & DICT_CLUSTERED)
1325
|| UT_LIST_GET_LEN(table->indexes) == 0);
1327
dict_index_find_cols(table, index);
1329
/* Build the cache internal representation of the index,
1330
containing also the added system fields */
1332
if (index->type & DICT_CLUSTERED) {
1333
new_index = dict_index_build_internal_clust(table, index);
1335
new_index = dict_index_build_internal_non_clust(table, index);
1338
new_index->search_info = btr_search_info_create(new_index->heap);
1340
/* Set the n_fields value in new_index to the actual defined
1341
number of fields in the cache internal representation */
1343
new_index->n_fields = new_index->n_def;
1345
/* Add the new index as the last index for the table */
1347
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1348
new_index->table = table;
1349
new_index->table_name = table->name;
1351
/* Increment the ord_part counts in columns which are ordering */
1353
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1354
n_ord = new_index->n_fields;
1356
n_ord = dict_index_get_n_unique(new_index);
1359
for (i = 0; i < n_ord; i++) {
1361
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1364
new_index->page = (unsigned int) page_no;
1365
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1367
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1369
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1371
(1 + dict_index_get_n_unique(new_index))
1372
* sizeof(ib_longlong));
1373
/* Give some sensible values to stat_n_... in case we do
1374
not calculate statistics quickly enough */
1376
for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1378
new_index->stat_n_diff_key_vals[i] = 100;
1382
dict_sys->size += mem_heap_get_size(new_index->heap);
1384
dict_mem_index_free(index);
1387
/**************************************************************************
1388
Removes an index from the dictionary cache. */
1391
dict_index_remove_from_cache(
1392
/*=========================*/
1393
dict_table_t* table, /* in: table */
1394
dict_index_t* index) /* in, own: index */
1398
ut_ad(table && index);
1399
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1400
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1401
ut_ad(mutex_own(&(dict_sys->mutex)));
1403
rw_lock_free(&index->lock);
1405
/* Remove the index from the list of indexes of the table */
1406
UT_LIST_REMOVE(indexes, table->indexes, index);
1408
size = mem_heap_get_size(index->heap);
1410
ut_ad(dict_sys->size >= size);
1412
dict_sys->size -= size;
1414
dict_mem_index_free(index);
1417
/***********************************************************************
1418
Tries to find column names for the index and sets the col field of the
1422
dict_index_find_cols(
1423
/*=================*/
1424
dict_table_t* table, /* in: table */
1425
dict_index_t* index) /* in: index */
1429
ut_ad(table && index);
1430
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1431
ut_ad(mutex_own(&(dict_sys->mutex)));
1433
for (i = 0; i < index->n_fields; i++) {
1435
dict_field_t* field = dict_index_get_nth_field(index, i);
1437
for (j = 0; j < table->n_cols; j++) {
1438
if (!strcmp(dict_table_get_col_name(table, j),
1440
field->col = (dict_col_t*)
1441
dict_table_get_nth_col(table, j);
1447
/* It is an error not to find a matching column. */
1455
/***********************************************************************
1456
Adds a column to index. */
1461
dict_index_t* index, /* in: index */
1462
dict_table_t* table, /* in: table */
1463
dict_col_t* col, /* in: column */
1464
ulint prefix_len) /* in: column prefix length */
1466
dict_field_t* field;
1467
const char* col_name;
1469
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1471
dict_mem_index_add_field(index, col_name, prefix_len);
1473
field = dict_index_get_nth_field(index, index->n_def - 1);
1476
field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1478
if (prefix_len && field->fixed_len > prefix_len) {
1479
field->fixed_len = (unsigned int) prefix_len;
1482
/* Long fixed-length fields that need external storage are treated as
1483
variable-length fields, so that the extern flag can be embedded in
1486
if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1487
field->fixed_len = 0;
1489
#if DICT_MAX_INDEX_COL_LEN != 768
1490
/* The comparison limit above must be constant. If it were
1491
changed, the disk format of some fixed-length columns would
1492
change, which would be a disaster. */
1493
# error "DICT_MAX_INDEX_COL_LEN != 768"
1496
if (!(col->prtype & DATA_NOT_NULL)) {
1497
index->n_nullable++;
1501
/***********************************************************************
1502
Copies fields contained in index2 to index1. */
1507
dict_index_t* index1, /* in: index to copy to */
1508
dict_index_t* index2, /* in: index to copy from */
1509
dict_table_t* table, /* in: table */
1510
ulint start, /* in: first position to copy */
1511
ulint end) /* in: last position to copy */
1513
dict_field_t* field;
1516
/* Copy fields contained in index2 */
1518
for (i = start; i < end; i++) {
1520
field = dict_index_get_nth_field(index2, i);
1521
dict_index_add_col(index1, table, field->col,
1526
/***********************************************************************
1527
Copies types of fields contained in index to tuple. */
1530
dict_index_copy_types(
1531
/*==================*/
1532
dtuple_t* tuple, /* in: data tuple */
1533
dict_index_t* index, /* in: index */
1534
ulint n_fields) /* in: number of field types to copy */
1538
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1539
dtuple_set_types_binary(tuple, n_fields);
1544
for (i = 0; i < n_fields; i++) {
1545
dict_field_t* ifield;
1546
dtype_t* dfield_type;
1548
ifield = dict_index_get_nth_field(index, i);
1549
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1550
dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1554
/***********************************************************************
1555
Copies types of columns contained in table to tuple. */
1558
dict_table_copy_types(
1559
/*==================*/
1560
dtuple_t* tuple, /* in: data tuple */
1561
dict_table_t* table) /* in: index */
1563
dtype_t* dfield_type;
1566
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1568
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1569
dict_col_copy_type(dict_table_get_nth_col(table, i),
1574
/***********************************************************************
1575
Builds the internal dictionary cache representation for a clustered
1576
index, containing also system fields not defined by the user. */
1579
dict_index_build_internal_clust(
1580
/*============================*/
1581
/* out, own: the internal representation
1582
of the clustered index */
1583
dict_table_t* table, /* in: table */
1584
dict_index_t* index) /* in: user representation of a clustered
1587
dict_index_t* new_index;
1588
dict_field_t* field;
1594
ut_ad(table && index);
1595
ut_ad(index->type & DICT_CLUSTERED);
1596
ut_ad(mutex_own(&(dict_sys->mutex)));
1597
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1599
/* Create a new index object with certainly enough fields */
1600
new_index = dict_mem_index_create(table->name,
1601
index->name, table->space,
1603
index->n_fields + table->n_cols);
1605
/* Copy other relevant data from the old index struct to the new
1606
struct: it inherits the values */
1608
new_index->n_user_defined_cols = index->n_fields;
1610
new_index->id = index->id;
1612
/* Copy the fields of index */
1613
dict_index_copy(new_index, index, table, 0, index->n_fields);
1615
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1616
/* No fixed number of fields determines an entry uniquely */
1618
new_index->n_uniq = REC_MAX_N_FIELDS;
1620
} else if (index->type & DICT_UNIQUE) {
1621
/* Only the fields defined so far are needed to identify
1622
the index entry uniquely */
1624
new_index->n_uniq = new_index->n_def;
1626
/* Also the row id is needed to identify the entry */
1627
new_index->n_uniq = 1 + new_index->n_def;
1630
new_index->trx_id_offset = 0;
1632
if (!(index->type & DICT_IBUF)) {
1633
/* Add system columns, trx id first */
1635
trx_id_pos = new_index->n_def;
1637
#if DATA_ROW_ID != 0
1638
# error "DATA_ROW_ID != 0"
1640
#if DATA_TRX_ID != 1
1641
# error "DATA_TRX_ID != 1"
1643
#if DATA_ROLL_PTR != 2
1644
# error "DATA_ROLL_PTR != 2"
1647
if (!(index->type & DICT_UNIQUE)) {
1648
dict_index_add_col(new_index, table, (dict_col_t*)
1649
dict_table_get_sys_col(
1650
table, DATA_ROW_ID),
1655
dict_index_add_col(new_index, table, (dict_col_t*)
1656
dict_table_get_sys_col(table, DATA_TRX_ID),
1659
dict_index_add_col(new_index, table, (dict_col_t*)
1660
dict_table_get_sys_col(table,
1664
for (i = 0; i < trx_id_pos; i++) {
1666
fixed_size = dict_col_get_fixed_size(
1667
dict_index_get_nth_col(new_index, i));
1669
if (fixed_size == 0) {
1670
new_index->trx_id_offset = 0;
1675
if (dict_index_get_nth_field(new_index, i)->prefix_len
1677
new_index->trx_id_offset = 0;
1682
new_index->trx_id_offset += (unsigned int) fixed_size;
1687
/* Remember the table columns already contained in new_index */
1688
indexed = mem_alloc(table->n_cols * sizeof *indexed);
1689
memset(indexed, 0, table->n_cols * sizeof *indexed);
1691
/* Mark with 0 the table columns already contained in new_index */
1692
for (i = 0; i < new_index->n_def; i++) {
1694
field = dict_index_get_nth_field(new_index, i);
1696
/* If there is only a prefix of the column in the index
1697
field, do not mark the column as contained in the index */
1699
if (field->prefix_len == 0) {
1701
indexed[field->col->ind] = TRUE;
1705
/* Add to new_index non-system columns of table not yet included
1707
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1709
dict_col_t* col = (dict_col_t*)
1710
dict_table_get_nth_col(table, i);
1711
ut_ad(col->mtype != DATA_SYS);
1713
if (!indexed[col->ind]) {
1714
dict_index_add_col(new_index, table, col, 0);
1720
ut_ad((index->type & DICT_IBUF)
1721
|| (UT_LIST_GET_LEN(table->indexes) == 0));
1723
new_index->cached = TRUE;
1728
/***********************************************************************
1729
Builds the internal dictionary cache representation for a non-clustered
1730
index, containing also system fields not defined by the user. */
1733
dict_index_build_internal_non_clust(
1734
/*================================*/
1735
/* out, own: the internal representation
1736
of the non-clustered index */
1737
dict_table_t* table, /* in: table */
1738
dict_index_t* index) /* in: user representation of a non-clustered
1741
dict_field_t* field;
1742
dict_index_t* new_index;
1743
dict_index_t* clust_index;
1747
ut_ad(table && index);
1748
ut_ad(0 == (index->type & DICT_CLUSTERED));
1749
ut_ad(mutex_own(&(dict_sys->mutex)));
1750
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1752
/* The clustered index should be the first in the list of indexes */
1753
clust_index = UT_LIST_GET_FIRST(table->indexes);
1756
ut_ad(clust_index->type & DICT_CLUSTERED);
1757
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
1759
/* Create a new index */
1760
new_index = dict_mem_index_create(
1761
table->name, index->name, index->space, index->type,
1762
index->n_fields + 1 + clust_index->n_uniq);
1764
/* Copy other relevant data from the old index
1765
struct to the new struct: it inherits the values */
1767
new_index->n_user_defined_cols = index->n_fields;
1769
new_index->id = index->id;
1771
/* Copy fields from index to new_index */
1772
dict_index_copy(new_index, index, table, 0, index->n_fields);
1774
/* Remember the table columns already contained in new_index */
1775
indexed = mem_alloc(table->n_cols * sizeof *indexed);
1776
memset(indexed, 0, table->n_cols * sizeof *indexed);
1778
/* Mark with 0 table columns already contained in new_index */
1779
for (i = 0; i < new_index->n_def; i++) {
1781
field = dict_index_get_nth_field(new_index, i);
1783
/* If there is only a prefix of the column in the index
1784
field, do not mark the column as contained in the index */
1786
if (field->prefix_len == 0) {
1788
indexed[field->col->ind] = TRUE;
1792
/* Add to new_index the columns necessary to determine the clustered
1793
index entry uniquely */
1795
for (i = 0; i < clust_index->n_uniq; i++) {
1797
field = dict_index_get_nth_field(clust_index, i);
1799
if (!indexed[field->col->ind]) {
1800
dict_index_add_col(new_index, table, field->col,
1807
if ((index->type) & DICT_UNIQUE) {
1808
new_index->n_uniq = index->n_fields;
1810
new_index->n_uniq = new_index->n_def;
1813
/* Set the n_fields value in new_index to the actual defined
1816
new_index->n_fields = new_index->n_def;
1818
new_index->cached = TRUE;
1823
/*====================== FOREIGN KEY PROCESSING ========================*/
1825
/*************************************************************************
1826
Checks if a table is referenced by foreign keys. */
1829
dict_table_referenced_by_foreign_key(
1830
/*=================================*/
1831
/* out: TRUE if table is referenced by a
1833
dict_table_t* table) /* in: InnoDB table */
1835
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
1843
/*************************************************************************
1844
Frees a foreign key struct. */
1849
dict_foreign_t* foreign) /* in, own: foreign key struct */
1851
mem_heap_free(foreign->heap);
1854
/**************************************************************************
1855
Removes a foreign constraint struct from the dictionary cache. */
1858
dict_foreign_remove_from_cache(
1859
/*===========================*/
1860
dict_foreign_t* foreign) /* in, own: foreign constraint */
1862
ut_ad(mutex_own(&(dict_sys->mutex)));
1865
if (foreign->referenced_table) {
1866
UT_LIST_REMOVE(referenced_list,
1867
foreign->referenced_table->referenced_list,
1871
if (foreign->foreign_table) {
1872
UT_LIST_REMOVE(foreign_list,
1873
foreign->foreign_table->foreign_list,
1877
dict_foreign_free(foreign);
1880
/**************************************************************************
1881
Looks for the foreign constraint from the foreign and referenced lists
1887
/* out: foreign constraint */
1888
dict_table_t* table, /* in: table object */
1889
const char* id) /* in: foreign constraint id */
1891
dict_foreign_t* foreign;
1893
ut_ad(mutex_own(&(dict_sys->mutex)));
1895
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1898
if (ut_strcmp(id, foreign->id) == 0) {
1903
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1906
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1909
if (ut_strcmp(id, foreign->id) == 0) {
1914
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1920
#ifndef UNIV_HOTBACKUP
1921
/*************************************************************************
1922
Tries to find an index whose first fields are the columns in the array,
1923
in the same order. */
1926
dict_foreign_find_index(
1927
/*====================*/
1928
/* out: matching index, NULL if not found */
1929
dict_table_t* table, /* in: table */
1930
const char** columns,/* in: array of column names */
1931
ulint n_cols, /* in: number of columns */
1932
dict_index_t* types_idx, /* in: NULL or an index to whose types the
1933
column types must match */
1934
ibool check_charsets,
1935
/* in: whether to check charsets.
1936
only has an effect if types_idx != NULL */
1938
/* in: nonzero if none of the columns must
1939
be declared NOT NULL */
1941
dict_index_t* index;
1942
dict_field_t* field;
1943
const char* col_name;
1946
index = dict_table_get_first_index(table);
1948
while (index != NULL) {
1949
if (dict_index_get_n_fields(index) >= n_cols) {
1951
for (i = 0; i < n_cols; i++) {
1952
field = dict_index_get_nth_field(index, i);
1954
col_name = dict_table_get_col_name(
1955
table, dict_col_get_no(field->col));
1957
if (field->prefix_len != 0) {
1958
/* We do not accept column prefix
1964
if (0 != innobase_strcasecmp(columns[i],
1970
&& (field->col->prtype & DATA_NOT_NULL)) {
1975
if (types_idx && !cmp_cols_are_equal(
1976
dict_index_get_nth_col(index, i),
1977
dict_index_get_nth_col(types_idx,
1986
/* We found a matching index */
1992
index = dict_table_get_next_index(index);
1998
/**************************************************************************
1999
Report an error in a foreign key definition. */
2002
dict_foreign_error_report_low(
2003
/*==========================*/
2004
FILE* file, /* in: output stream */
2005
const char* name) /* in: table name */
2008
ut_print_timestamp(file);
2009
fprintf(file, " Error in foreign key constraint of table %s:\n",
2013
/**************************************************************************
2014
Report an error in a foreign key definition. */
2017
dict_foreign_error_report(
2018
/*======================*/
2019
FILE* file, /* in: output stream */
2020
dict_foreign_t* fk, /* in: foreign key constraint */
2021
const char* msg) /* in: the error message */
2023
mutex_enter(&dict_foreign_err_mutex);
2024
dict_foreign_error_report_low(file, fk->foreign_table_name);
2026
fputs(" Constraint:\n", file);
2027
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2029
if (fk->foreign_index) {
2030
fputs("The index in the foreign key in table is ", file);
2031
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2033
"See http://dev.mysql.com/doc/refman/5.1/en/"
2034
"innodb-foreign-key-constraints.html\n"
2035
"for correct foreign key definition.\n",
2038
mutex_exit(&dict_foreign_err_mutex);
2041
/**************************************************************************
2042
Adds a foreign key constraint object to the dictionary cache. May free
2043
the object if there already is an object with the same identifier in.
2044
At least one of the foreign table and the referenced table must already
2045
be in the dictionary cache! */
2048
dict_foreign_add_to_cache(
2049
/*======================*/
2050
/* out: DB_SUCCESS or error code */
2051
dict_foreign_t* foreign, /* in, own: foreign key constraint */
2052
ibool check_charsets) /* in: TRUE=check charset
2055
dict_table_t* for_table;
2056
dict_table_t* ref_table;
2057
dict_foreign_t* for_in_cache = NULL;
2058
dict_index_t* index;
2059
ibool added_to_referenced_list= FALSE;
2060
FILE* ef = dict_foreign_err_file;
2062
ut_ad(mutex_own(&(dict_sys->mutex)));
2064
for_table = dict_table_check_if_in_cache_low(
2065
foreign->foreign_table_name);
2067
ref_table = dict_table_check_if_in_cache_low(
2068
foreign->referenced_table_name);
2069
ut_a(for_table || ref_table);
2072
for_in_cache = dict_foreign_find(for_table, foreign->id);
2075
if (!for_in_cache && ref_table) {
2076
for_in_cache = dict_foreign_find(ref_table, foreign->id);
2080
/* Free the foreign object */
2081
mem_heap_free(foreign->heap);
2083
for_in_cache = foreign;
2086
if (for_in_cache->referenced_table == NULL && ref_table) {
2087
index = dict_foreign_find_index(
2089
(const char**) for_in_cache->referenced_col_names,
2090
for_in_cache->n_fields, for_in_cache->foreign_index,
2091
check_charsets, FALSE);
2093
if (index == NULL) {
2094
dict_foreign_error_report(
2096
"there is no index in referenced table"
2097
" which would contain\n"
2098
"the columns as the first columns,"
2099
" or the data types in the\n"
2100
"referenced table do not match"
2101
" the ones in table.");
2103
if (for_in_cache == foreign) {
2104
mem_heap_free(foreign->heap);
2107
return(DB_CANNOT_ADD_CONSTRAINT);
2110
for_in_cache->referenced_table = ref_table;
2111
for_in_cache->referenced_index = index;
2112
UT_LIST_ADD_LAST(referenced_list,
2113
ref_table->referenced_list,
2115
added_to_referenced_list = TRUE;
2118
if (for_in_cache->foreign_table == NULL && for_table) {
2119
index = dict_foreign_find_index(
2121
(const char**) for_in_cache->foreign_col_names,
2122
for_in_cache->n_fields,
2123
for_in_cache->referenced_index, check_charsets,
2125
& (DICT_FOREIGN_ON_DELETE_SET_NULL
2126
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
2128
if (index == NULL) {
2129
dict_foreign_error_report(
2131
"there is no index in the table"
2132
" which would contain\n"
2133
"the columns as the first columns,"
2134
" or the data types in the\n"
2135
"table do not match"
2136
" the ones in the referenced table\n"
2137
"or one of the ON ... SET NULL columns"
2138
" is declared NOT NULL.");
2140
if (for_in_cache == foreign) {
2141
if (added_to_referenced_list) {
2144
ref_table->referenced_list,
2148
mem_heap_free(foreign->heap);
2151
return(DB_CANNOT_ADD_CONSTRAINT);
2154
for_in_cache->foreign_table = for_table;
2155
for_in_cache->foreign_index = index;
2156
UT_LIST_ADD_LAST(foreign_list,
2157
for_table->foreign_list,
2164
/*************************************************************************
2165
Scans from pointer onwards. Stops if is at the start of a copy of
2166
'string' where characters are compared without case sensitivity, and
2167
only outside `` or "" quotes. Stops also at '\0'. */
2172
/* out: scanned up to this */
2173
const char* ptr, /* in: scan from */
2174
const char* string) /* in: look for this */
2178
for (; *ptr; ptr++) {
2179
if (*ptr == quote) {
2180
/* Closing quote character: do not look for
2181
starting quote or the keyword. */
2184
/* Within quotes: do nothing. */
2185
} else if (*ptr == '`' || *ptr == '"') {
2186
/* Starting quote: remember the quote character. */
2189
/* Outside quotes: look for the keyword. */
2191
for (i = 0; string[i]; i++) {
2192
if (toupper((int)(unsigned char)(ptr[i]))
2193
!= toupper((int)(unsigned char)
2207
/*************************************************************************
2208
Accepts a specified string. Comparisons are case-insensitive. */
2213
/* out: if string was accepted, the pointer
2214
is moved after that, else ptr is returned */
2215
struct charset_info_st* cs,/* in: the character set of ptr */
2216
const char* ptr, /* in: scan from this */
2217
const char* string, /* in: accept only this string as the next
2218
non-whitespace string */
2219
ibool* success)/* out: TRUE if accepted */
2221
const char* old_ptr = ptr;
2222
const char* old_ptr2;
2226
while (my_isspace(cs, *ptr)) {
2232
ptr = dict_scan_to(ptr, string);
2234
if (*ptr == '\0' || old_ptr2 != ptr) {
2240
return(ptr + ut_strlen(string));
2243
/*************************************************************************
2244
Scans an id. For the lexical definition of an 'id', see the code below.
2245
Strips backquotes or double quotes from around the id. */
2250
/* out: scanned to */
2251
struct charset_info_st* cs,/* in: the character set of ptr */
2252
const char* ptr, /* in: scanned to */
2253
mem_heap_t* heap, /* in: heap where to allocate the id
2254
(NULL=id will not be allocated, but it
2255
will point to string near ptr) */
2256
const char** id, /* out,own: the id; NULL if no id was
2258
ibool table_id,/* in: TRUE=convert the allocated id
2259
as a table name; FALSE=convert to UTF-8 */
2260
ibool accept_also_dot)
2261
/* in: TRUE if also a dot can appear in a
2262
non-quoted id; in a quoted id it can appear
2273
while (my_isspace(cs, *ptr)) {
2282
if (*ptr == '`' || *ptr == '"') {
2294
if (*ptr == quote) {
2296
if (*ptr != quote) {
2304
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2305
&& (accept_also_dot || *ptr != '.')
2306
&& *ptr != ',' && *ptr != '\0') {
2314
if (UNIV_UNLIKELY(!heap)) {
2315
/* no heap given: id will point to source string */
2322
str = d = mem_heap_alloc(heap, len + 1);
2324
if ((*d++ = *s++) == quote) {
2331
ut_ad(s + 1 == ptr);
2333
str = mem_heap_strdupl(heap, s, len);
2338
/* Convert the identifier from connection character set
2341
*id = dst = mem_heap_alloc(heap, len);
2343
innobase_convert_from_id(dst, str, len);
2344
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2345
sizeof srv_mysql50_table_name_prefix)) {
2346
/* This is a pre-5.1 table name
2347
containing chars other than [A-Za-z0-9].
2348
Discard the prefix and use raw UTF-8 encoding. */
2349
str += sizeof srv_mysql50_table_name_prefix;
2350
len -= sizeof srv_mysql50_table_name_prefix;
2353
/* Encode using filename-safe characters. */
2355
*id = dst = mem_heap_alloc(heap, len);
2357
innobase_convert_from_table_id(dst, str, len);
2363
/*************************************************************************
2364
Tries to scan a column name. */
2369
/* out: scanned to */
2370
struct charset_info_st* cs, /* in: the character set of ptr */
2371
const char* ptr, /* in: scanned to */
2372
ibool* success,/* out: TRUE if success */
2373
dict_table_t* table, /* in: table in which the column is */
2374
const dict_col_t** column, /* out: pointer to column if success */
2375
mem_heap_t* heap, /* in: heap where to allocate */
2376
const char** name) /* out,own: the column name;
2377
NULL if no name was scannable */
2383
ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2385
if (*name == NULL) {
2387
return(ptr); /* Syntax error */
2390
if (table == NULL) {
2394
for (i = 0; i < dict_table_get_n_cols(table); i++) {
2396
const char* col_name = dict_table_get_col_name(
2399
if (0 == innobase_strcasecmp(col_name, *name)) {
2403
*column = dict_table_get_nth_col(table, i);
2404
strcpy((char*) *name, col_name);
2414
/*************************************************************************
2415
Scans a table name from an SQL string. */
2418
dict_scan_table_name(
2419
/*=================*/
2420
/* out: scanned to */
2421
struct charset_info_st* cs,/* in: the character set of ptr */
2422
const char* ptr, /* in: scanned to */
2423
dict_table_t** table, /* out: table object or NULL */
2424
const char* name, /* in: foreign key table name */
2425
ibool* success,/* out: TRUE if ok name found */
2426
mem_heap_t* heap, /* in: heap where to allocate the id */
2427
const char** ref_name)/* out,own: the table name;
2428
NULL if no name was scannable */
2430
const char* database_name = NULL;
2431
ulint database_name_len = 0;
2432
const char* table_name = NULL;
2433
ulint table_name_len;
2434
const char* scan_name;
2440
ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2442
if (scan_name == NULL) {
2444
return(ptr); /* Syntax error */
2448
/* We scanned the database name; scan also the table name */
2452
database_name = scan_name;
2453
database_name_len = strlen(database_name);
2455
ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2457
if (table_name == NULL) {
2459
return(ptr); /* Syntax error */
2462
/* To be able to read table dumps made with InnoDB-4.0.17 or
2463
earlier, we must allow the dot separator between the database
2464
name and the table name also to appear within a quoted
2465
identifier! InnoDB used to print a constraint as:
2466
... REFERENCES `databasename.tablename` ...
2467
starting from 4.0.18 it is
2468
... REFERENCES `databasename`.`tablename` ... */
2471
for (s = scan_name; *s; s++) {
2473
database_name = scan_name;
2474
database_name_len = s - scan_name;
2476
break;/* to do: multiple dots? */
2480
table_name = scan_name;
2483
if (database_name == NULL) {
2484
/* Use the database name of the foreign key table */
2486
database_name = name;
2487
database_name_len = dict_get_db_name_len(name);
2490
table_name_len = strlen(table_name);
2492
/* Copy database_name, '/', table_name, '\0' */
2493
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2494
memcpy(ref, database_name, database_name_len);
2495
ref[database_name_len] = '/';
2496
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2498
if (srv_lower_case_table_names) {
2499
#endif /* !__WIN__ */
2500
/* The table name is always put to lower case on Windows. */
2501
innobase_casedn_str(ref);
2504
#endif /* !__WIN__ */
2508
*table = dict_table_get_low(ref);
2513
/*************************************************************************
2514
Skips one id. The id is allowed to contain also '.'. */
2519
/* out: scanned to */
2520
struct charset_info_st* cs,/* in: the character set of ptr */
2521
const char* ptr, /* in: scanned to */
2522
ibool* success)/* out: TRUE if success, FALSE if just spaces
2523
left in string or a syntax error */
2529
ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2538
/*************************************************************************
2539
Removes MySQL comments from an SQL string. A comment is either
2540
(a) '#' to the end of the line,
2541
(b) '--<space>' to the end of the line, or
2542
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
2543
C comment syntax). */
2546
dict_strip_comments(
2547
/*================*/
2548
/* out, own: SQL string stripped from
2549
comments; the caller must free this
2551
const char* sql_string) /* in: SQL string */
2556
/* unclosed quote character (0 if none) */
2559
str = mem_alloc(strlen(sql_string) + 1);
2566
if (*sptr == '\0') {
2569
ut_a(ptr <= str + strlen(sql_string));
2574
if (*sptr == quote) {
2575
/* Closing quote character: do not look for
2576
starting quote or comments. */
2579
/* Within quotes: do not look for
2580
starting quotes or comments. */
2581
} else if (*sptr == '"' || *sptr == '`') {
2582
/* Starting quote: remember the quote character. */
2584
} else if (*sptr == '#'
2585
|| (sptr[0] == '-' && sptr[1] == '-'
2586
&& sptr[2] == ' ')) {
2588
/* In Unix a newline is 0x0A while in Windows
2589
it is 0x0D followed by 0x0A */
2591
if (*sptr == (char)0x0A
2592
|| *sptr == (char)0x0D
2600
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
2602
if (*sptr == '*' && *(sptr + 1) == '/') {
2609
if (*sptr == '\0') {
2625
/*************************************************************************
2626
Finds the highest <number> for foreign key constraints of the table. Looks
2627
only at the >= 4.0.18-format id's, which are of the form
2628
databasename/tablename_ibfk_<number>. */
2631
dict_table_get_highest_foreign_id(
2632
/*==============================*/
2633
/* out: highest number, 0 if table has no new
2634
format foreign key constraints */
2635
dict_table_t* table) /* in: table in the dictionary memory cache */
2637
dict_foreign_t* foreign;
2639
ulint biggest_id = 0;
2645
len = ut_strlen(table->name);
2646
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2649
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
2650
&& 0 == ut_memcmp(foreign->id, table->name, len)
2651
&& 0 == ut_memcmp(foreign->id + len,
2652
dict_ibfk, (sizeof dict_ibfk) - 1)
2653
&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
2654
/* It is of the >= 4.0.18 format */
2656
id = strtoul(foreign->id + len
2657
+ ((sizeof dict_ibfk) - 1),
2659
if (*endp == '\0') {
2660
ut_a(id != biggest_id);
2662
if (id > biggest_id) {
2668
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2674
/*************************************************************************
2675
Reports a simple foreign key create clause syntax error. */
2678
dict_foreign_report_syntax_err(
2679
/*===========================*/
2680
const char* name, /* in: table name */
2681
const char* start_of_latest_foreign,
2682
/* in: start of the foreign key clause
2683
in the SQL string */
2684
const char* ptr) /* in: place of the syntax error */
2686
FILE* ef = dict_foreign_err_file;
2688
mutex_enter(&dict_foreign_err_mutex);
2689
dict_foreign_error_report_low(ef, name);
2690
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
2691
start_of_latest_foreign, ptr);
2692
mutex_exit(&dict_foreign_err_mutex);
2695
/*************************************************************************
2696
Scans a table create SQL string and adds to the data dictionary the foreign
2697
key constraints declared in the string. This function should be called after
2698
the indexes for a table have been created. Each foreign key constraint must
2699
be accompanied with indexes in both participating tables. The indexes are
2700
allowed to contain more fields than mentioned in the constraint. */
2703
dict_create_foreign_constraints_low(
2704
/*================================*/
2705
/* out: error code or DB_SUCCESS */
2706
trx_t* trx, /* in: transaction */
2707
mem_heap_t* heap, /* in: memory heap */
2708
struct charset_info_st* cs,/* in: the character set of sql_string */
2709
const char* sql_string,
2710
/* in: CREATE TABLE or ALTER TABLE statement
2711
where foreign keys are declared like:
2712
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2713
table2 can be written also with the database
2714
name before it: test.table2; the default
2715
database is the database of parameter name */
2716
const char* name, /* in: table full name in the normalized form
2717
database_name/table_name */
2719
/* in: if TRUE, fail with error code
2720
DB_CANNOT_ADD_CONSTRAINT if any foreign
2723
dict_table_t* table;
2724
dict_table_t* referenced_table;
2725
dict_table_t* table_to_alter;
2726
ulint highest_id_so_far = 0;
2727
dict_index_t* index;
2728
dict_foreign_t* foreign;
2729
const char* ptr = sql_string;
2730
const char* start_of_latest_foreign = sql_string;
2731
FILE* ef = dict_foreign_err_file;
2732
const char* constraint_name;
2742
const dict_col_t*columns[500];
2743
const char* column_names[500];
2744
const char* referenced_table_name;
2746
ut_ad(mutex_own(&(dict_sys->mutex)));
2748
table = dict_table_get_low(name);
2750
if (table == NULL) {
2751
mutex_enter(&dict_foreign_err_mutex);
2752
dict_foreign_error_report_low(ef, name);
2754
"Cannot find the table in the internal"
2755
" data dictionary of InnoDB.\n"
2756
"Create table statement:\n%s\n", sql_string);
2757
mutex_exit(&dict_foreign_err_mutex);
2762
/* First check if we are actually doing an ALTER TABLE, and in that
2763
case look for the table being altered */
2765
ptr = dict_accept(cs, ptr, "ALTER", &success);
2772
ptr = dict_accept(cs, ptr, "TABLE", &success);
2779
/* We are doing an ALTER TABLE: scan the table name we are altering */
2781
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
2782
&success, heap, &referenced_table_name);
2785
"InnoDB: Error: could not find"
2786
" the table being ALTERED in:\n%s\n",
2792
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
2793
format databasename/tablename_ibfk_<number>, where <number> is local
2794
to the table; look for the highest <number> for table_to_alter, so
2795
that we can assign to new constraints higher numbers. */
2797
/* If we are altering a temporary table, the table name after ALTER
2798
TABLE does not correspond to the internal table name, and
2799
table_to_alter is NULL. TODO: should we fix this somehow? */
2801
if (table_to_alter == NULL) {
2802
highest_id_so_far = 0;
2804
highest_id_so_far = dict_table_get_highest_foreign_id(
2808
/* Scan for foreign key declarations in a loop */
2810
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
2812
ptr1 = dict_scan_to(ptr, "CONSTRAINT");
2813
ptr2 = dict_scan_to(ptr, "FOREIGN");
2815
constraint_name = NULL;
2818
/* The user may have specified a constraint name. Pick it so
2819
that we can store 'databasename/constraintname' as the id of
2820
of the constraint to system tables. */
2823
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
2827
if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
2831
while (my_isspace(cs, *ptr)) {
2835
/* read constraint name unless got "CONSTRAINT FOREIGN" */
2837
ptr = dict_scan_id(cs, ptr, heap,
2838
&constraint_name, FALSE, FALSE);
2845
/* The proper way to reject foreign keys for temporary
2846
tables would be to split the lexing and syntactical
2847
analysis of foreign key clauses from the actual adding
2848
of them, so that ha_innodb.cc could first parse the SQL
2849
command, determine if there are any foreign keys, and
2850
if so, immediately reject the command if the table is a
2851
temporary one. For now, this kludge will work. */
2852
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
2854
return(DB_CANNOT_ADD_CONSTRAINT);
2857
/**********************************************************/
2858
/* The following call adds the foreign key constraints
2859
to the data dictionary system tables on disk */
2861
error = dict_create_add_foreigns_to_dictionary(
2862
highest_id_so_far, table, trx);
2866
start_of_latest_foreign = ptr;
2868
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
2874
if (!my_isspace(cs, *ptr)) {
2878
ptr = dict_accept(cs, ptr, "KEY", &success);
2884
ptr = dict_accept(cs, ptr, "(", &success);
2887
/* MySQL allows also an index id before the '('; we
2889
ptr = dict_skip_word(cs, ptr, &success);
2892
dict_foreign_report_syntax_err(
2893
name, start_of_latest_foreign, ptr);
2895
return(DB_CANNOT_ADD_CONSTRAINT);
2898
ptr = dict_accept(cs, ptr, "(", &success);
2901
/* We do not flag a syntax error here because in an
2902
ALTER TABLE we may also have DROP FOREIGN KEY abc */
2910
/* Scan the columns in the first list */
2912
ut_a(i < (sizeof column_names) / sizeof *column_names);
2913
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
2914
heap, column_names + i);
2916
mutex_enter(&dict_foreign_err_mutex);
2917
dict_foreign_error_report_low(ef, name);
2918
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
2919
start_of_latest_foreign, ptr);
2920
mutex_exit(&dict_foreign_err_mutex);
2922
return(DB_CANNOT_ADD_CONSTRAINT);
2927
ptr = dict_accept(cs, ptr, ",", &success);
2933
ptr = dict_accept(cs, ptr, ")", &success);
2936
dict_foreign_report_syntax_err(
2937
name, start_of_latest_foreign, ptr);
2938
return(DB_CANNOT_ADD_CONSTRAINT);
2941
/* Try to find an index which contains the columns
2942
as the first fields and in the right order */
2944
index = dict_foreign_find_index(table, column_names, i,
2948
mutex_enter(&dict_foreign_err_mutex);
2949
dict_foreign_error_report_low(ef, name);
2950
fputs("There is no index in table ", ef);
2951
ut_print_name(ef, NULL, TRUE, name);
2952
fprintf(ef, " where the columns appear\n"
2953
"as the first columns. Constraint:\n%s\n"
2954
"See http://dev.mysql.com/doc/refman/5.1/en/"
2955
"innodb-foreign-key-constraints.html\n"
2956
"for correct foreign key definition.\n",
2957
start_of_latest_foreign);
2958
mutex_exit(&dict_foreign_err_mutex);
2960
return(DB_CANNOT_ADD_CONSTRAINT);
2962
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
2964
if (!success || !my_isspace(cs, *ptr)) {
2965
dict_foreign_report_syntax_err(
2966
name, start_of_latest_foreign, ptr);
2967
return(DB_CANNOT_ADD_CONSTRAINT);
2970
/* Let us create a constraint struct */
2972
foreign = dict_mem_foreign_create();
2974
if (constraint_name) {
2977
/* Catenate 'databasename/' to the constraint name specified
2978
by the user: we conceive the constraint as belonging to the
2979
same MySQL 'database' as the table itself. We store the name
2982
db_len = dict_get_db_name_len(table->name);
2984
foreign->id = mem_heap_alloc(
2985
foreign->heap, db_len + strlen(constraint_name) + 2);
2987
ut_memcpy(foreign->id, table->name, db_len);
2988
foreign->id[db_len] = '/';
2989
strcpy(foreign->id + db_len + 1, constraint_name);
2992
foreign->foreign_table = table;
2993
foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
2995
foreign->foreign_index = index;
2996
foreign->n_fields = (unsigned int) i;
2997
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
2999
for (i = 0; i < foreign->n_fields; i++) {
3000
foreign->foreign_col_names[i] = mem_heap_strdup(
3002
dict_table_get_col_name(table,
3003
dict_col_get_no(columns[i])));
3006
ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3007
&success, heap, &referenced_table_name);
3009
/* Note that referenced_table can be NULL if the user has suppressed
3010
checking of foreign key constraints! */
3012
if (!success || (!referenced_table && trx->check_foreigns)) {
3013
dict_foreign_free(foreign);
3015
mutex_enter(&dict_foreign_err_mutex);
3016
dict_foreign_error_report_low(ef, name);
3017
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3019
start_of_latest_foreign, ptr);
3020
mutex_exit(&dict_foreign_err_mutex);
3022
return(DB_CANNOT_ADD_CONSTRAINT);
3025
ptr = dict_accept(cs, ptr, "(", &success);
3028
dict_foreign_free(foreign);
3029
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3031
return(DB_CANNOT_ADD_CONSTRAINT);
3034
/* Scan the columns in the second list */
3038
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3039
heap, column_names + i);
3043
dict_foreign_free(foreign);
3045
mutex_enter(&dict_foreign_err_mutex);
3046
dict_foreign_error_report_low(ef, name);
3047
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3049
start_of_latest_foreign, ptr);
3050
mutex_exit(&dict_foreign_err_mutex);
3052
return(DB_CANNOT_ADD_CONSTRAINT);
3055
ptr = dict_accept(cs, ptr, ",", &success);
3061
ptr = dict_accept(cs, ptr, ")", &success);
3063
if (!success || foreign->n_fields != i) {
3064
dict_foreign_free(foreign);
3066
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3068
return(DB_CANNOT_ADD_CONSTRAINT);
3075
/* Loop here as long as we can find ON ... conditions */
3077
ptr = dict_accept(cs, ptr, "ON", &success);
3081
goto try_find_index;
3084
ptr = dict_accept(cs, ptr, "DELETE", &success);
3087
ptr = dict_accept(cs, ptr, "UPDATE", &success);
3090
dict_foreign_free(foreign);
3092
dict_foreign_report_syntax_err(
3093
name, start_of_latest_foreign, ptr);
3094
return(DB_CANNOT_ADD_CONSTRAINT);
3097
is_on_delete = FALSE;
3100
is_on_delete = TRUE;
3104
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3107
goto scan_on_conditions;
3110
ptr = dict_accept(cs, ptr, "CASCADE", &success);
3114
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3116
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3119
goto scan_on_conditions;
3122
ptr = dict_accept(cs, ptr, "NO", &success);
3125
ptr = dict_accept(cs, ptr, "ACTION", &success);
3128
dict_foreign_free(foreign);
3129
dict_foreign_report_syntax_err(
3130
name, start_of_latest_foreign, ptr);
3132
return(DB_CANNOT_ADD_CONSTRAINT);
3136
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3138
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3141
goto scan_on_conditions;
3144
ptr = dict_accept(cs, ptr, "SET", &success);
3147
dict_foreign_free(foreign);
3148
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3150
return(DB_CANNOT_ADD_CONSTRAINT);
3153
ptr = dict_accept(cs, ptr, "NULL", &success);
3156
dict_foreign_free(foreign);
3157
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3159
return(DB_CANNOT_ADD_CONSTRAINT);
3162
for (j = 0; j < foreign->n_fields; j++) {
3163
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3166
/* It is not sensible to define SET NULL
3167
if the column is not allowed to be NULL! */
3169
dict_foreign_free(foreign);
3171
mutex_enter(&dict_foreign_err_mutex);
3172
dict_foreign_error_report_low(ef, name);
3174
"You have defined a SET NULL condition"
3175
" though some of the\n"
3176
"columns are defined as NOT NULL.\n",
3177
start_of_latest_foreign);
3178
mutex_exit(&dict_foreign_err_mutex);
3180
return(DB_CANNOT_ADD_CONSTRAINT);
3185
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3187
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3190
goto scan_on_conditions;
3193
if (n_on_deletes > 1 || n_on_updates > 1) {
3194
/* It is an error to define more than 1 action */
3196
dict_foreign_free(foreign);
3198
mutex_enter(&dict_foreign_err_mutex);
3199
dict_foreign_error_report_low(ef, name);
3201
"You have twice an ON DELETE clause"
3202
" or twice an ON UPDATE clause.\n",
3203
start_of_latest_foreign);
3204
mutex_exit(&dict_foreign_err_mutex);
3206
return(DB_CANNOT_ADD_CONSTRAINT);
3209
/* Try to find an index which contains the columns as the first fields
3210
and in the right order, and the types are the same as in
3211
foreign->foreign_index */
3213
if (referenced_table) {
3214
index = dict_foreign_find_index(referenced_table,
3216
foreign->foreign_index,
3219
dict_foreign_free(foreign);
3220
mutex_enter(&dict_foreign_err_mutex);
3221
dict_foreign_error_report_low(ef, name);
3223
"Cannot find an index in the"
3224
" referenced table where the\n"
3225
"referenced columns appear as the"
3226
" first columns, or column types\n"
3227
"in the table and the referenced table"
3228
" do not match for constraint.\n"
3229
"Note that the internal storage type of"
3230
" ENUM and SET changed in\n"
3231
"tables created with >= InnoDB-4.1.12,"
3232
" and such columns in old tables\n"
3233
"cannot be referenced by such columns"
3235
"See http://dev.mysql.com/doc/refman/5.1/en/"
3236
"innodb-foreign-key-constraints.html\n"
3237
"for correct foreign key definition.\n",
3238
start_of_latest_foreign);
3239
mutex_exit(&dict_foreign_err_mutex);
3241
return(DB_CANNOT_ADD_CONSTRAINT);
3244
ut_a(trx->check_foreigns == FALSE);
3248
foreign->referenced_index = index;
3249
foreign->referenced_table = referenced_table;
3251
foreign->referenced_table_name
3252
= mem_heap_strdup(foreign->heap, referenced_table_name);
3254
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3256
for (i = 0; i < foreign->n_fields; i++) {
3257
foreign->referenced_col_names[i]
3258
= mem_heap_strdup(foreign->heap, column_names[i]);
3261
/* We found an ok constraint definition: add to the lists */
3263
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3265
if (referenced_table) {
3266
UT_LIST_ADD_LAST(referenced_list,
3267
referenced_table->referenced_list,
3274
/**************************************************************************
3275
Determines whether a string starts with the specified keyword. */
3278
dict_str_starts_with_keyword(
3279
/*=========================*/
3280
/* out: TRUE if str starts
3282
void* mysql_thd, /* in: MySQL thread handle */
3283
const char* str, /* in: string to scan for keyword */
3284
const char* keyword) /* in: keyword to look for */
3286
struct charset_info_st* cs = innobase_get_charset(mysql_thd);
3289
dict_accept(cs, str, keyword, &success);
3293
/*************************************************************************
3294
Scans a table create SQL string and adds to the data dictionary the foreign
3295
key constraints declared in the string. This function should be called after
3296
the indexes for a table have been created. Each foreign key constraint must
3297
be accompanied with indexes in both participating tables. The indexes are
3298
allowed to contain more fields than mentioned in the constraint. */
3301
dict_create_foreign_constraints(
3302
/*============================*/
3303
/* out: error code or DB_SUCCESS */
3304
trx_t* trx, /* in: transaction */
3305
const char* sql_string, /* in: table create statement where
3306
foreign keys are declared like:
3307
FOREIGN KEY (a, b) REFERENCES
3308
table2(c, d), table2 can be written
3309
also with the database
3310
name before it: test.table2; the
3311
default database id the database of
3313
const char* name, /* in: table full name in the
3315
database_name/table_name */
3316
ibool reject_fks) /* in: if TRUE, fail with error
3317
code DB_CANNOT_ADD_CONSTRAINT if
3318
any foreign keys are found. */
3325
ut_a(trx->mysql_thd);
3327
str = dict_strip_comments(sql_string);
3328
heap = mem_heap_create(10000);
3330
err = dict_create_foreign_constraints_low(
3331
trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3334
mem_heap_free(heap);
3340
/**************************************************************************
3341
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3344
dict_foreign_parse_drop_constraints(
3345
/*================================*/
3346
/* out: DB_SUCCESS or
3347
DB_CANNOT_DROP_CONSTRAINT if
3348
syntax error or the constraint
3349
id does not match */
3350
mem_heap_t* heap, /* in: heap from which we can
3352
trx_t* trx, /* in: transaction */
3353
dict_table_t* table, /* in: table */
3354
ulint* n, /* out: number of constraints
3356
const char*** constraints_to_drop) /* out: id's of the
3357
constraints to drop */
3359
dict_foreign_t* foreign;
3364
FILE* ef = dict_foreign_err_file;
3365
struct charset_info_st* cs;
3368
ut_a(trx->mysql_thd);
3370
cs = innobase_get_charset(trx->mysql_thd);
3374
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3376
str = dict_strip_comments(*(trx->mysql_query_str));
3379
ut_ad(mutex_own(&(dict_sys->mutex)));
3381
ptr = dict_scan_to(ptr, "DROP");
3389
ptr = dict_accept(cs, ptr, "DROP", &success);
3391
if (!my_isspace(cs, *ptr)) {
3396
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3398
if (!success || !my_isspace(cs, *ptr)) {
3403
ptr = dict_accept(cs, ptr, "KEY", &success);
3410
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3418
(*constraints_to_drop)[*n] = id;
3421
/* Look for the given constraint id */
3423
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3425
while (foreign != NULL) {
3426
if (0 == strcmp(foreign->id, id)
3427
|| (strchr(foreign->id, '/')
3429
dict_remove_db_name(foreign->id)))) {
3434
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3437
if (foreign == NULL) {
3438
mutex_enter(&dict_foreign_err_mutex);
3440
ut_print_timestamp(ef);
3441
fputs(" Error in dropping of a foreign key constraint"
3443
ut_print_name(ef, NULL, TRUE, table->name);
3445
"in SQL command\n", ef);
3447
fputs("\nCannot find a constraint with the given id ", ef);
3448
ut_print_name(ef, NULL, FALSE, id);
3450
mutex_exit(&dict_foreign_err_mutex);
3454
return(DB_CANNOT_DROP_CONSTRAINT);
3460
mutex_enter(&dict_foreign_err_mutex);
3462
ut_print_timestamp(ef);
3463
fputs(" Syntax error in dropping of a"
3464
" foreign key constraint of table ", ef);
3465
ut_print_name(ef, NULL, TRUE, table->name);
3467
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
3468
mutex_exit(&dict_foreign_err_mutex);
3472
return(DB_CANNOT_DROP_CONSTRAINT);
3474
#endif /* UNIV_HOTBACKUP */
3476
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3479
/**************************************************************************
3480
Returns an index object if it is found in the dictionary cache. */
3483
dict_index_get_if_in_cache(
3484
/*=======================*/
3485
/* out: index, NULL if not found */
3486
dulint index_id) /* in: index id */
3488
dict_index_t* index;
3490
if (dict_sys == NULL) {
3494
mutex_enter(&(dict_sys->mutex));
3496
index = dict_index_find_on_id_low(index_id);
3498
mutex_exit(&(dict_sys->mutex));
3502
#endif /* UNIV_DEBUG */
3505
/**************************************************************************
3506
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3507
no comparison can occur with the page number field in a node pointer. */
3510
dict_index_check_search_tuple(
3511
/*==========================*/
3512
/* out: TRUE if ok */
3513
dict_index_t* index, /* in: index tree */
3514
dtuple_t* tuple) /* in: tuple used in a search */
3517
ut_a(dtuple_get_n_fields_cmp(tuple)
3518
<= dict_index_get_n_unique_in_tree(index));
3521
#endif /* UNIV_DEBUG */
3523
/**************************************************************************
3524
Builds a node pointer out of a physical record and a page number. */
3527
dict_index_build_node_ptr(
3528
/*======================*/
3529
/* out, own: node pointer */
3530
dict_index_t* index, /* in: index tree */
3531
rec_t* rec, /* in: record for which to build node
3533
ulint page_no,/* in: page number to put in node pointer */
3534
mem_heap_t* heap, /* in: memory heap where pointer created */
3535
ulint level) /* in: level of rec in tree: 0 means leaf
3543
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3544
/* In a universal index tree, we take the whole record as
3545
the node pointer if the record is on the leaf level,
3546
on non-leaf levels we remove the last field, which
3547
contains the page number of the child page */
3549
ut_a(!dict_table_is_comp(index->table));
3550
n_unique = rec_get_n_fields_old(rec);
3557
n_unique = dict_index_get_n_unique_in_tree(index);
3560
tuple = dtuple_create(heap, n_unique + 1);
3562
/* When searching in the tree for the node pointer, we must not do
3563
comparison on the last field, the page number field, as on upper
3564
levels in the tree there may be identical node pointers with a
3565
different page number; therefore, we set the n_fields_cmp to one
3568
dtuple_set_n_fields_cmp(tuple, n_unique);
3570
dict_index_copy_types(tuple, index, n_unique);
3572
buf = mem_heap_alloc(heap, 4);
3574
mach_write_to_4(buf, page_no);
3576
field = dtuple_get_nth_field(tuple, n_unique);
3577
dfield_set_data(field, buf, 4);
3579
dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3581
rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3582
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3583
| REC_STATUS_NODE_PTR);
3585
ut_ad(dtuple_check_typed(tuple));
3590
/**************************************************************************
3591
Copies an initial segment of a physical record, long enough to specify an
3592
index entry uniquely. */
3595
dict_index_copy_rec_order_prefix(
3596
/*=============================*/
3597
/* out: pointer to the prefix record */
3598
dict_index_t* index, /* in: index tree */
3599
rec_t* rec, /* in: record for which to copy prefix */
3600
ulint* n_fields,/* out: number of fields copied */
3601
byte** buf, /* in/out: memory buffer for the copied prefix,
3603
ulint* buf_size)/* in/out: buffer size */
3607
UNIV_PREFETCH_R(rec);
3609
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3610
ut_a(!dict_table_is_comp(index->table));
3611
n = rec_get_n_fields_old(rec);
3613
n = dict_index_get_n_unique_in_tree(index);
3617
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
3620
/**************************************************************************
3621
Builds a typed data tuple out of a physical record. */
3624
dict_index_build_data_tuple(
3625
/*========================*/
3626
/* out, own: data tuple */
3627
dict_index_t* index, /* in: index tree */
3628
rec_t* rec, /* in: record for which to build data tuple */
3629
ulint n_fields,/* in: number of data fields */
3630
mem_heap_t* heap) /* in: memory heap where tuple created */
3634
ut_ad(dict_table_is_comp(index->table)
3635
|| n_fields <= rec_get_n_fields_old(rec));
3637
tuple = dtuple_create(heap, n_fields);
3639
dict_index_copy_types(tuple, index, n_fields);
3641
rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
3643
ut_ad(dtuple_check_typed(tuple));
3648
/*************************************************************************
3649
Calculates the minimum record length in an index. */
3652
dict_index_calc_min_rec_len(
3653
/*========================*/
3654
dict_index_t* index) /* in: index */
3659
if (dict_table_is_comp(index->table)) {
3661
sum = REC_N_NEW_EXTRA_BYTES;
3662
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3663
const dict_col_t* col
3664
= dict_index_get_nth_col(index, i);
3665
ulint size = dict_col_get_fixed_size(col);
3669
sum += size < 128 ? 1 : 2;
3671
if (!(col->prtype & DATA_NOT_NULL)) {
3676
/* round the NULL flags up to full bytes */
3677
sum += UT_BITS_IN_BYTES(nullable);
3682
for (i = 0; i < dict_index_get_n_fields(index); i++) {
3683
sum += dict_col_get_fixed_size(
3684
dict_index_get_nth_col(index, i));
3688
sum += 2 * dict_index_get_n_fields(index);
3690
sum += dict_index_get_n_fields(index);
3693
sum += REC_N_OLD_EXTRA_BYTES;
3698
/*************************************************************************
3699
Calculates new estimates for table and index statistics. The statistics
3700
are used in query optimization. */
3703
dict_update_statistics_low(
3704
/*=======================*/
3705
dict_table_t* table, /* in: table */
3706
ibool has_dict_mutex __attribute__((unused)))
3707
/* in: TRUE if the caller has the
3710
dict_index_t* index;
3712
ulint sum_of_index_sizes = 0;
3714
if (table->ibd_file_missing) {
3715
ut_print_timestamp(stderr);
3717
" InnoDB: cannot calculate statistics for table %s\n"
3718
"InnoDB: because the .ibd file is missing. For help,"
3719
" please refer to\n"
3720
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3721
"innodb-troubleshooting.html\n",
3727
/* If we have set a high innodb_force_recovery level, do not calculate
3728
statistics, as a badly corrupted index can cause a crash in it. */
3730
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3735
/* Find out the sizes of the indexes and how many different values
3736
for the key they approximately have */
3738
index = dict_table_get_first_index(table);
3740
if (index == NULL) {
3741
/* Table definition is corrupt */
3747
size = btr_get_size(index, BTR_TOTAL_SIZE);
3749
index->stat_index_size = size;
3751
sum_of_index_sizes += size;
3753
size = btr_get_size(index, BTR_N_LEAF_PAGES);
3756
/* The root node of the tree is a leaf */
3760
index->stat_n_leaf_pages = size;
3762
btr_estimate_number_of_different_key_vals(index);
3764
index = dict_table_get_next_index(index);
3767
index = dict_table_get_first_index(table);
3769
table->stat_n_rows = index->stat_n_diff_key_vals[
3770
dict_index_get_n_unique(index)];
3772
table->stat_clustered_index_size = index->stat_index_size;
3774
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
3775
- index->stat_index_size;
3777
table->stat_initialized = TRUE;
3779
table->stat_modified_counter = 0;
3782
/*************************************************************************
3783
Calculates new estimates for table and index statistics. The statistics
3784
are used in query optimization. */
3787
dict_update_statistics(
3788
/*===================*/
3789
dict_table_t* table) /* in: table */
3791
dict_update_statistics_low(table, FALSE);
3794
/**************************************************************************
3795
A noninlined version of dict_table_get_low. */
3798
dict_table_get_low_noninlined(
3799
/*==========================*/
3800
/* out: table, NULL if not found */
3801
const char* table_name) /* in: table name */
3803
return(dict_table_get_low(table_name));
3806
/**************************************************************************
3807
Prints info of a foreign key constraint. */
3810
dict_foreign_print_low(
3811
/*===================*/
3812
dict_foreign_t* foreign) /* in: foreign key constraint */
3816
ut_ad(mutex_own(&(dict_sys->mutex)));
3818
fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
3819
foreign->id, foreign->foreign_table_name);
3821
for (i = 0; i < foreign->n_fields; i++) {
3822
fprintf(stderr, " %s", foreign->foreign_col_names[i]);
3825
fprintf(stderr, " )\n"
3827
foreign->referenced_table_name);
3829
for (i = 0; i < foreign->n_fields; i++) {
3830
fprintf(stderr, " %s", foreign->referenced_col_names[i]);
3833
fputs(" )\n", stderr);
3836
/**************************************************************************
3837
Prints a table data. */
3842
dict_table_t* table) /* in: table */
3844
mutex_enter(&(dict_sys->mutex));
3845
dict_table_print_low(table);
3846
mutex_exit(&(dict_sys->mutex));
3849
/**************************************************************************
3850
Prints a table data when we know the table name. */
3853
dict_table_print_by_name(
3854
/*=====================*/
3857
dict_table_t* table;
3859
mutex_enter(&(dict_sys->mutex));
3861
table = dict_table_get_low(name);
3865
dict_table_print_low(table);
3866
mutex_exit(&(dict_sys->mutex));
3869
/**************************************************************************
3870
Prints a table data. */
3873
dict_table_print_low(
3874
/*=================*/
3875
dict_table_t* table) /* in: table */
3877
dict_index_t* index;
3878
dict_foreign_t* foreign;
3881
ut_ad(mutex_own(&(dict_sys->mutex)));
3883
dict_update_statistics_low(table, TRUE);
3886
"--------------------------------------\n"
3887
"TABLE: name %s, id %lu %lu, columns %lu, indexes %lu,"
3891
(ulong) ut_dulint_get_high(table->id),
3892
(ulong) ut_dulint_get_low(table->id),
3893
(ulong) table->n_cols,
3894
(ulong) UT_LIST_GET_LEN(table->indexes),
3895
(ulong) table->stat_n_rows);
3897
for (i = 0; i + 1 < (ulint) table->n_cols; i++) {
3898
dict_col_print_low(table, dict_table_get_nth_col(table, i));
3899
fputs("; ", stderr);
3904
index = UT_LIST_GET_FIRST(table->indexes);
3906
while (index != NULL) {
3907
dict_index_print_low(index);
3908
index = UT_LIST_GET_NEXT(indexes, index);
3911
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3913
while (foreign != NULL) {
3914
dict_foreign_print_low(foreign);
3915
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3918
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3920
while (foreign != NULL) {
3921
dict_foreign_print_low(foreign);
3922
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3926
/**************************************************************************
3927
Prints a column data. */
3932
const dict_table_t* table, /* in: table */
3933
const dict_col_t* col) /* in: column */
3937
ut_ad(mutex_own(&(dict_sys->mutex)));
3939
dict_col_copy_type(col, &type);
3940
fprintf(stderr, "%s: ", dict_table_get_col_name(table,
3941
dict_col_get_no(col)));
3946
/**************************************************************************
3947
Prints an index data. */
3950
dict_index_print_low(
3951
/*=================*/
3952
dict_index_t* index) /* in: index */
3957
ut_ad(mutex_own(&(dict_sys->mutex)));
3959
if (index->n_user_defined_cols > 0) {
3960
n_vals = index->stat_n_diff_key_vals[
3961
index->n_user_defined_cols];
3963
n_vals = index->stat_n_diff_key_vals[1];
3967
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
3968
" uniq %lu, type %lu\n"
3969
" root page %lu, appr.key vals %lu,"
3970
" leaf pages %lu, size pages %lu\n"
3973
(ulong) ut_dulint_get_high(index->id),
3974
(ulong) ut_dulint_get_low(index->id),
3975
(ulong) index->n_user_defined_cols,
3976
(ulong) index->n_fields,
3977
(ulong) index->n_uniq,
3978
(ulong) index->type,
3979
(ulong) index->page,
3981
(ulong) index->stat_n_leaf_pages,
3982
(ulong) index->stat_index_size);
3984
for (i = 0; i < index->n_fields; i++) {
3985
dict_field_print_low(dict_index_get_nth_field(index, i));
3990
#ifdef UNIV_BTR_PRINT
3991
btr_print_size(index);
3993
btr_print_index(index, 7);
3994
#endif /* UNIV_BTR_PRINT */
3997
/**************************************************************************
3998
Prints a field data. */
4001
dict_field_print_low(
4002
/*=================*/
4003
dict_field_t* field) /* in: field */
4005
ut_ad(mutex_own(&(dict_sys->mutex)));
4007
fprintf(stderr, " %s", field->name);
4009
if (field->prefix_len != 0) {
4010
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4014
/**************************************************************************
4015
Outputs info on a foreign key of a table in a format suitable for
4019
dict_print_info_on_foreign_key_in_create_format(
4020
/*============================================*/
4021
FILE* file, /* in: file where to print */
4022
trx_t* trx, /* in: transaction */
4023
dict_foreign_t* foreign, /* in: foreign key constraint */
4024
ibool add_newline) /* in: whether to add a newline */
4026
const char* stripped_id;
4029
if (strchr(foreign->id, '/')) {
4030
/* Strip the preceding database name from the constraint id */
4031
stripped_id = foreign->id + 1
4032
+ dict_get_db_name_len(foreign->id);
4034
stripped_id = foreign->id;
4040
/* SHOW CREATE TABLE wants constraints each printed nicely
4041
on its own line, while error messages want no newlines
4046
fputs(" CONSTRAINT ", file);
4047
ut_print_name(file, trx, FALSE, stripped_id);
4048
fputs(" FOREIGN KEY (", file);
4051
ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4052
if (++i < foreign->n_fields) {
4059
fputs(") REFERENCES ", file);
4061
if (dict_tables_have_same_db(foreign->foreign_table_name,
4062
foreign->referenced_table_name)) {
4063
/* Do not print the database name of the referenced table */
4064
ut_print_name(file, trx, TRUE,
4065
dict_remove_db_name(
4066
foreign->referenced_table_name));
4068
ut_print_name(file, trx, TRUE,
4069
foreign->referenced_table_name);
4076
ut_print_name(file, trx, FALSE,
4077
foreign->referenced_col_names[i]);
4078
if (++i < foreign->n_fields) {
4087
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4088
fputs(" ON DELETE CASCADE", file);
4091
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4092
fputs(" ON DELETE SET NULL", file);
4095
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4096
fputs(" ON DELETE NO ACTION", file);
4099
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4100
fputs(" ON UPDATE CASCADE", file);
4103
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4104
fputs(" ON UPDATE SET NULL", file);
4107
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4108
fputs(" ON UPDATE NO ACTION", file);
4112
/**************************************************************************
4113
Outputs info on foreign keys of a table. */
4116
dict_print_info_on_foreign_keys(
4117
/*============================*/
4118
ibool create_table_format, /* in: if TRUE then print in
4119
a format suitable to be inserted into
4120
a CREATE TABLE, otherwise in the format
4121
of SHOW TABLE STATUS */
4122
FILE* file, /* in: file where to print */
4123
trx_t* trx, /* in: transaction */
4124
dict_table_t* table) /* in: table */
4126
dict_foreign_t* foreign;
4128
mutex_enter(&(dict_sys->mutex));
4130
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4132
if (foreign == NULL) {
4133
mutex_exit(&(dict_sys->mutex));
4138
while (foreign != NULL) {
4139
if (create_table_format) {
4140
dict_print_info_on_foreign_key_in_create_format(
4141
file, trx, foreign, TRUE);
4146
for (i = 0; i < foreign->n_fields; i++) {
4151
ut_print_name(file, trx, FALSE,
4152
foreign->foreign_col_names[i]);
4155
fputs(") REFER ", file);
4156
ut_print_name(file, trx, TRUE,
4157
foreign->referenced_table_name);
4160
for (i = 0; i < foreign->n_fields; i++) {
4166
foreign->referenced_col_names[i]);
4171
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4172
fputs(" ON DELETE CASCADE", file);
4175
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4176
fputs(" ON DELETE SET NULL", file);
4179
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4180
fputs(" ON DELETE NO ACTION", file);
4183
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4184
fputs(" ON UPDATE CASCADE", file);
4187
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4188
fputs(" ON UPDATE SET NULL", file);
4191
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4192
fputs(" ON UPDATE NO ACTION", file);
4196
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4199
mutex_exit(&(dict_sys->mutex));
4202
/************************************************************************
4203
Displays the names of the index and the table. */
4205
dict_index_name_print(
4206
/*==================*/
4207
FILE* file, /* in: output stream */
4208
trx_t* trx, /* in: transaction */
4209
const dict_index_t* index) /* in: index to print */
4211
fputs("index ", file);
4212
ut_print_name(file, trx, FALSE, index->name);
4213
fputs(" of table ", file);
4214
ut_print_name(file, trx, TRUE, index->table_name);