mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / dict / dict0dict.c
blobe580ffa3b3beb200713e821d0cff5a8a402f8b6e
1 /**********************************************************************
2 Data dictionary system
4 (c) 1996 Innobase Oy
6 Created 1/8/1996 Heikki Tuuri
7 ***********************************************************************/
9 #include "dict0dict.h"
11 #ifdef UNIV_NONINL
12 #include "dict0dict.ic"
13 #endif
15 #include "buf0buf.h"
16 #include "data0type.h"
17 #include "mach0data.h"
18 #include "dict0boot.h"
19 #include "dict0mem.h"
20 #include "dict0crea.h"
21 #include "trx0undo.h"
22 #include "btr0btr.h"
23 #include "btr0cur.h"
24 #include "btr0sea.h"
25 #include "pars0pars.h"
26 #include "pars0sym.h"
27 #include "que0que.h"
28 #include "rem0cmp.h"
29 #include "m_string.h"
30 #include "my_sys.h"
31 #ifndef UNIV_HOTBACKUP
32 # include "m_ctype.h" /* my_isspace() */
33 #endif /* !UNIV_HOTBACKUP */
34 #include "ha_prototypes.h"
36 #include <ctype.h>
38 dict_sys_t* dict_sys = NULL; /* the dictionary system */
40 rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
41 this in X-mode; implicit or backround
42 operations purge, rollback, foreign
43 key checks reserve this in S-mode; we
44 cannot trust that MySQL protects
45 implicit or background operations
46 a table drop since MySQL does not
47 know of them; therefore we need this;
48 NOTE: a transaction which reserves
49 this must keep book on the mode in
50 trx->dict_operation_lock_mode */
52 #define DICT_HEAP_SIZE 100 /* initial memory heap size when
53 creating a table or index object */
54 #define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
55 hash table fixed size in bytes */
56 #define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data
57 dictionary varying size in bytes */
59 /* Identifies generated InnoDB foreign key names */
60 static char dict_ibfk[] = "_ibfk_";
62 #ifndef UNIV_HOTBACKUP
63 /**********************************************************************
64 Converts an identifier to a table name.
66 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
67 this function, you MUST change also the prototype here! */
68 extern
69 void
70 innobase_convert_from_table_id(
71 /*===========================*/
72 char* to, /* out: converted identifier */
73 const char* from, /* in: identifier to convert */
74 ulint len); /* in: length of 'to', in bytes;
75 should be at least 5 * strlen(to) + 1 */
76 /**********************************************************************
77 Converts an identifier to UTF-8.
79 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
80 this function, you MUST change also the prototype here! */
81 extern
82 void
83 innobase_convert_from_id(
84 /*=====================*/
85 char* to, /* out: converted identifier */
86 const char* from, /* in: identifier to convert */
87 ulint len); /* in: length of 'to', in bytes;
88 should be at least 3 * strlen(to) + 1 */
89 /**********************************************************************
90 Compares NUL-terminated UTF-8 strings case insensitively.
92 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
93 this function, you MUST change also the prototype here! */
94 extern
95 int
96 innobase_strcasecmp(
97 /*================*/
98 /* out: 0 if a=b, <0 if a<b, >1 if a>b */
99 const char* a, /* in: first string to compare */
100 const char* b); /* in: second string to compare */
102 /**********************************************************************
103 Makes all characters in a NUL-terminated UTF-8 string lower case.
105 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
106 this function, you MUST change also the prototype here! */
107 extern
108 void
109 innobase_casedn_str(
110 /*================*/
111 char* a); /* in/out: string to put in lower case */
113 /**************************************************************************
114 Determines the connection character set.
116 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
117 this function, you MUST change also the prototype here! */
118 struct charset_info_st*
119 innobase_get_charset(
120 /*=================*/
121 /* out: connection character set */
122 void* mysql_thd); /* in: MySQL thread handle */
123 #endif /* !UNIV_HOTBACKUP */
125 /**************************************************************************
126 Removes an index from the dictionary cache. */
127 static
128 void
129 dict_index_remove_from_cache(
130 /*=========================*/
131 dict_table_t* table, /* in: table */
132 dict_index_t* index); /* in, own: index */
133 /***********************************************************************
134 Copies fields contained in index2 to index1. */
135 static
136 void
137 dict_index_copy(
138 /*============*/
139 dict_index_t* index1, /* in: index to copy to */
140 dict_index_t* index2, /* in: index to copy from */
141 dict_table_t* table, /* in: table */
142 ulint start, /* in: first position to copy */
143 ulint end); /* in: last position to copy */
144 /***********************************************************************
145 Tries to find column names for the index and sets the col field of the
146 index. */
147 static
148 void
149 dict_index_find_cols(
150 /*=================*/
151 dict_table_t* table, /* in: table */
152 dict_index_t* index); /* in: index */
153 /***********************************************************************
154 Builds the internal dictionary cache representation for a clustered
155 index, containing also system fields not defined by the user. */
156 static
157 dict_index_t*
158 dict_index_build_internal_clust(
159 /*============================*/
160 /* out, own: the internal representation
161 of the clustered index */
162 dict_table_t* table, /* in: table */
163 dict_index_t* index); /* in: user representation of a clustered
164 index */
165 /***********************************************************************
166 Builds the internal dictionary cache representation for a non-clustered
167 index, containing also system fields not defined by the user. */
168 static
169 dict_index_t*
170 dict_index_build_internal_non_clust(
171 /*================================*/
172 /* out, own: the internal representation
173 of the non-clustered index */
174 dict_table_t* table, /* in: table */
175 dict_index_t* index); /* in: user representation of a non-clustered
176 index */
177 /**************************************************************************
178 Removes a foreign constraint struct from the dictionary cache. */
179 static
180 void
181 dict_foreign_remove_from_cache(
182 /*===========================*/
183 dict_foreign_t* foreign); /* in, own: foreign constraint */
184 /**************************************************************************
185 Prints a column data. */
186 static
187 void
188 dict_col_print_low(
189 /*===============*/
190 const dict_table_t* table, /* in: table */
191 const dict_col_t* col); /* in: column */
192 /**************************************************************************
193 Prints an index data. */
194 static
195 void
196 dict_index_print_low(
197 /*=================*/
198 dict_index_t* index); /* in: index */
199 /**************************************************************************
200 Prints a field data. */
201 static
202 void
203 dict_field_print_low(
204 /*=================*/
205 dict_field_t* field); /* in: field */
206 /*************************************************************************
207 Frees a foreign key struct. */
208 static
209 void
210 dict_foreign_free(
211 /*==============*/
212 dict_foreign_t* foreign); /* in, own: foreign key struct */
214 /* Stream for storing detailed information about the latest foreign key
215 and unique key errors */
216 FILE* dict_foreign_err_file = NULL;
217 mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign
218 and unique error buffers */
220 #ifndef UNIV_HOTBACKUP
221 /**********************************************************************
222 Makes all characters in a NUL-terminated UTF-8 string lower case. */
224 void
225 dict_casedn_str(
226 /*============*/
227 char* a) /* in/out: string to put in lower case */
229 innobase_casedn_str(a);
231 #endif /* !UNIV_HOTBACKUP */
233 /************************************************************************
234 Checks if the database name in two table names is the same. */
236 ibool
237 dict_tables_have_same_db(
238 /*=====================*/
239 /* out: TRUE if same db name */
240 const char* name1, /* in: table name in the form
241 dbname '/' tablename */
242 const char* name2) /* in: table name in the form
243 dbname '/' tablename */
245 for (; *name1 == *name2; name1++, name2++) {
246 if (*name1 == '/') {
247 return(TRUE);
249 ut_a(*name1); /* the names must contain '/' */
251 return(FALSE);
254 /************************************************************************
255 Return the end of table name where we have removed dbname and '/'. */
257 const char*
258 dict_remove_db_name(
259 /*================*/
260 /* out: table name */
261 const char* name) /* in: table name in the form
262 dbname '/' tablename */
264 const char* s = strchr(name, '/');
265 ut_a(s);
267 return(s + 1);
270 /************************************************************************
271 Get the database name length in a table name. */
273 ulint
274 dict_get_db_name_len(
275 /*=================*/
276 /* out: database name length */
277 const char* name) /* in: table name in the form
278 dbname '/' tablename */
280 const char* s;
281 s = strchr(name, '/');
282 ut_a(s);
283 return(s - name);
286 /************************************************************************
287 Reserves the dictionary system mutex for MySQL. */
289 void
290 dict_mutex_enter_for_mysql(void)
291 /*============================*/
293 mutex_enter(&(dict_sys->mutex));
296 /************************************************************************
297 Releases the dictionary system mutex for MySQL. */
299 void
300 dict_mutex_exit_for_mysql(void)
301 /*===========================*/
303 mutex_exit(&(dict_sys->mutex));
306 /************************************************************************
307 Decrements the count of open MySQL handles to a table. */
309 void
310 dict_table_decrement_handle_count(
311 /*==============================*/
312 dict_table_t* table) /* in: table */
314 mutex_enter(&(dict_sys->mutex));
316 ut_a(table->n_mysql_handles_opened > 0);
318 table->n_mysql_handles_opened--;
320 mutex_exit(&(dict_sys->mutex));
323 /*************************************************************************
324 Gets the column data type. */
326 void
327 dict_col_copy_type_noninline(
328 /*=========================*/
329 const dict_col_t* col, /* in: column */
330 dtype_t* type) /* out: data type */
332 dict_col_copy_type(col, type);
335 /************************************************************************
336 Gets the nth column of a table. */
338 const dict_col_t*
339 dict_table_get_nth_col_noninline(
340 /*=============================*/
341 /* out: pointer to column object */
342 const dict_table_t* table, /* in: table */
343 ulint pos) /* in: position of column */
345 return(dict_table_get_nth_col(table, pos));
348 /************************************************************************
349 Gets the first index on the table (the clustered index). */
351 dict_index_t*
352 dict_table_get_first_index_noninline(
353 /*=================================*/
354 /* out: index, NULL if none exists */
355 dict_table_t* table) /* in: table */
357 return(dict_table_get_first_index(table));
360 /************************************************************************
361 Gets the next index on the table. */
363 dict_index_t*
364 dict_table_get_next_index_noninline(
365 /*================================*/
366 /* out: index, NULL if none left */
367 dict_index_t* index) /* in: index */
369 return(dict_table_get_next_index(index));
372 /**************************************************************************
373 Returns an index object. */
375 dict_index_t*
376 dict_table_get_index_noninline(
377 /*===========================*/
378 /* out: index, NULL if does not exist */
379 dict_table_t* table, /* in: table */
380 const char* name) /* in: index name */
382 return(dict_table_get_index(table, name));
385 /**************************************************************************
386 Returns a column's name. */
388 const char*
389 dict_table_get_col_name(
390 /*====================*/
391 /* out: column name. NOTE: not
392 guaranteed to stay valid if table is
393 modified in any way (columns added,
394 etc.). */
395 const dict_table_t* table, /* in: table */
396 ulint col_nr) /* in: column number */
398 ulint i;
399 const char* s;
401 ut_ad(table);
402 ut_ad(col_nr < table->n_def);
403 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
405 s = table->col_names;
406 if (s) {
407 for (i = 0; i < col_nr; i++) {
408 s += strlen(s) + 1;
412 return(s);
416 /************************************************************************
417 Acquire the autoinc lock.*/
419 void
420 dict_table_autoinc_lock(
421 /*====================*/
422 dict_table_t* table)
424 mutex_enter(&table->autoinc_mutex);
427 /************************************************************************
428 Unconditionally set the autoinc counter. */
430 void
431 dict_table_autoinc_initialize(
432 /*==========================*/
433 dict_table_t* table, /* in: table */
434 ib_ulonglong value) /* in: next value to assign to a row */
436 ut_ad(mutex_own(&table->autoinc_mutex));
438 table->autoinc = value;
441 /************************************************************************
442 Reads the next autoinc value (== autoinc counter value), 0 if not yet
443 initialized. */
445 ib_ulonglong
446 dict_table_autoinc_read(
447 /*====================*/
448 /* out: value for a new row, or 0 */
449 dict_table_t* table) /* in: table */
451 ut_ad(mutex_own(&table->autoinc_mutex));
453 return(table->autoinc);
456 /************************************************************************
457 Updates the autoinc counter if the value supplied is greater than the
458 current value. */
460 void
461 dict_table_autoinc_update_if_greater(
462 /*=================================*/
464 dict_table_t* table, /* in: table */
465 ib_ulonglong value) /* in: value which was assigned to a row */
467 ut_ad(mutex_own(&table->autoinc_mutex));
469 if (value > table->autoinc) {
471 table->autoinc = value;
475 /************************************************************************
476 Release the autoinc lock.*/
478 void
479 dict_table_autoinc_unlock(
480 /*======================*/
481 dict_table_t* table) /* in: release autoinc lock for this table */
483 mutex_exit(&table->autoinc_mutex);
486 /************************************************************************
487 Looks for column n in an index. */
489 ulint
490 dict_index_get_nth_col_pos(
491 /*=======================*/
492 /* out: position in internal representation
493 of the index; if not contained, returns
494 ULINT_UNDEFINED */
495 dict_index_t* index, /* in: index */
496 ulint n) /* in: column number */
498 const dict_field_t* field;
499 const dict_col_t* col;
500 ulint pos;
501 ulint n_fields;
503 ut_ad(index);
504 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
506 col = dict_table_get_nth_col(index->table, n);
508 if (index->type & DICT_CLUSTERED) {
510 return(dict_col_get_clust_pos(col, index));
513 n_fields = dict_index_get_n_fields(index);
515 for (pos = 0; pos < n_fields; pos++) {
516 field = dict_index_get_nth_field(index, pos);
518 if (col == field->col && field->prefix_len == 0) {
520 return(pos);
524 return(ULINT_UNDEFINED);
527 /************************************************************************
528 Returns TRUE if the index contains a column or a prefix of that column. */
530 ibool
531 dict_index_contains_col_or_prefix(
532 /*==============================*/
533 /* out: TRUE if contains the column or its
534 prefix */
535 dict_index_t* index, /* in: index */
536 ulint n) /* in: column number */
538 const dict_field_t* field;
539 const dict_col_t* col;
540 ulint pos;
541 ulint n_fields;
543 ut_ad(index);
544 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
546 if (index->type & DICT_CLUSTERED) {
548 return(TRUE);
551 col = dict_table_get_nth_col(index->table, n);
553 n_fields = dict_index_get_n_fields(index);
555 for (pos = 0; pos < n_fields; pos++) {
556 field = dict_index_get_nth_field(index, pos);
558 if (col == field->col) {
560 return(TRUE);
564 return(FALSE);
567 /************************************************************************
568 Looks for a matching field in an index. The column has to be the same. The
569 column in index must be complete, or must contain a prefix longer than the
570 column in index2. That is, we must be able to construct the prefix in index2
571 from the prefix in index. */
573 ulint
574 dict_index_get_nth_field_pos(
575 /*=========================*/
576 /* out: position in internal representation
577 of the index; if not contained, returns
578 ULINT_UNDEFINED */
579 dict_index_t* index, /* in: index from which to search */
580 dict_index_t* index2, /* in: index */
581 ulint n) /* in: field number in index2 */
583 dict_field_t* field;
584 dict_field_t* field2;
585 ulint n_fields;
586 ulint pos;
588 ut_ad(index);
589 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
591 field2 = dict_index_get_nth_field(index2, n);
593 n_fields = dict_index_get_n_fields(index);
595 for (pos = 0; pos < n_fields; pos++) {
596 field = dict_index_get_nth_field(index, pos);
598 if (field->col == field2->col
599 && (field->prefix_len == 0
600 || (field->prefix_len >= field2->prefix_len
601 && field2->prefix_len != 0))) {
603 return(pos);
607 return(ULINT_UNDEFINED);
610 /**************************************************************************
611 Returns a table object based on table id. */
613 dict_table_t*
614 dict_table_get_on_id(
615 /*=================*/
616 /* out: table, NULL if does not exist */
617 dulint table_id, /* in: table id */
618 trx_t* trx) /* in: transaction handle */
620 dict_table_t* table;
622 if (trx->dict_operation_lock_mode == RW_X_LATCH) {
624 /* Note: An X latch implies that the transaction
625 already owns the dictionary mutex. */
627 ut_ad(mutex_own(&dict_sys->mutex));
629 return(dict_table_get_on_id_low(table_id));
632 mutex_enter(&(dict_sys->mutex));
634 table = dict_table_get_on_id_low(table_id);
636 mutex_exit(&(dict_sys->mutex));
638 return(table);
641 /************************************************************************
642 Looks for column n position in the clustered index. */
644 ulint
645 dict_table_get_nth_col_pos(
646 /*=======================*/
647 /* out: position in internal representation
648 of the clustered index */
649 dict_table_t* table, /* in: table */
650 ulint n) /* in: column number */
652 return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
653 n));
656 /************************************************************************
657 Check whether the table uses the compact page format. */
659 ibool
660 dict_table_is_comp_noninline(
661 /*=========================*/
662 /* out: TRUE if table uses the
663 compact page format */
664 const dict_table_t* table) /* in: table */
666 return(dict_table_is_comp(table));
669 /************************************************************************
670 Checks if a column is in the ordering columns of the clustered index of a
671 table. Column prefixes are treated like whole columns. */
673 ibool
674 dict_table_col_in_clustered_key(
675 /*============================*/
676 /* out: TRUE if the column, or its prefix, is
677 in the clustered key */
678 dict_table_t* table, /* in: table */
679 ulint n) /* in: column number */
681 dict_index_t* index;
682 const dict_field_t* field;
683 const dict_col_t* col;
684 ulint pos;
685 ulint n_fields;
687 ut_ad(table);
689 col = dict_table_get_nth_col(table, n);
691 index = dict_table_get_first_index(table);
693 n_fields = dict_index_get_n_unique(index);
695 for (pos = 0; pos < n_fields; pos++) {
696 field = dict_index_get_nth_field(index, pos);
698 if (col == field->col) {
700 return(TRUE);
704 return(FALSE);
707 /**************************************************************************
708 Inits the data dictionary module. */
710 void
711 dict_init(void)
712 /*===========*/
714 dict_sys = mem_alloc(sizeof(dict_sys_t));
716 mutex_create(&dict_sys->mutex, SYNC_DICT);
718 dict_sys->table_hash = hash_create(buf_pool_get_max_size()
719 / (DICT_POOL_PER_TABLE_HASH
720 * UNIV_WORD_SIZE));
721 dict_sys->table_id_hash = hash_create(buf_pool_get_max_size()
722 / (DICT_POOL_PER_TABLE_HASH
723 * UNIV_WORD_SIZE));
724 dict_sys->size = 0;
726 UT_LIST_INIT(dict_sys->table_LRU);
728 rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
730 dict_foreign_err_file = os_file_create_tmpfile();
731 ut_a(dict_foreign_err_file);
733 mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
736 /**************************************************************************
737 Returns a table object and optionally increment its MySQL open handle count.
738 NOTE! This is a high-level function to be used mainly from outside the
739 'dict' directory. Inside this directory dict_table_get_low is usually the
740 appropriate function. */
742 dict_table_t*
743 dict_table_get(
744 /*===========*/
745 /* out: table, NULL if
746 does not exist */
747 const char* table_name, /* in: table name */
748 ibool inc_mysql_count)
749 /* in: whether to increment the open
750 handle count on the table */
752 dict_table_t* table;
754 mutex_enter(&(dict_sys->mutex));
756 table = dict_table_get_low(table_name);
758 if (inc_mysql_count && table) {
759 table->n_mysql_handles_opened++;
762 mutex_exit(&(dict_sys->mutex));
764 if (table != NULL) {
765 if (!table->stat_initialized) {
766 /* If table->ibd_file_missing == TRUE, this will
767 print an error message and return without doing
768 anything. */
769 dict_update_statistics(table);
773 return(table);
776 /**************************************************************************
777 Adds system columns to a table object. */
779 void
780 dict_table_add_system_columns(
781 /*==========================*/
782 dict_table_t* table, /* in/out: table */
783 mem_heap_t* heap) /* in: temporary heap */
785 ut_ad(table);
786 ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
787 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
788 ut_ad(!table->cached);
790 /* NOTE: the system columns MUST be added in the following order
791 (so that they can be indexed by the numerical value of DATA_ROW_ID,
792 etc.) and as the last columns of the table memory object.
793 The clustered index will not always physically contain all
794 system columns. */
796 dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
797 DATA_ROW_ID | DATA_NOT_NULL,
798 DATA_ROW_ID_LEN);
799 #if DATA_ROW_ID != 0
800 #error "DATA_ROW_ID != 0"
801 #endif
802 dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
803 DATA_TRX_ID | DATA_NOT_NULL,
804 DATA_TRX_ID_LEN);
805 #if DATA_TRX_ID != 1
806 #error "DATA_TRX_ID != 1"
807 #endif
808 dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
809 DATA_ROLL_PTR | DATA_NOT_NULL,
810 DATA_ROLL_PTR_LEN);
811 #if DATA_ROLL_PTR != 2
812 #error "DATA_ROLL_PTR != 2"
813 #endif
815 /* This check reminds that if a new system column is added to
816 the program, it should be dealt with here */
817 #if DATA_N_SYS_COLS != 3
818 #error "DATA_N_SYS_COLS != 3"
819 #endif
822 /**************************************************************************
823 Adds a table object to the dictionary cache. */
825 void
826 dict_table_add_to_cache(
827 /*====================*/
828 dict_table_t* table, /* in: table */
829 mem_heap_t* heap) /* in: temporary heap */
831 ulint fold;
832 ulint id_fold;
833 ulint i;
834 ulint row_len;
836 /* The lower limit for what we consider a "big" row */
837 #define BIG_ROW_SIZE 1024
839 ut_ad(mutex_own(&(dict_sys->mutex)));
841 dict_table_add_system_columns(table, heap);
843 table->cached = TRUE;
845 fold = ut_fold_string(table->name);
846 id_fold = ut_fold_dulint(table->id);
848 row_len = 0;
849 for (i = 0; i < table->n_def; i++) {
850 ulint col_len = dict_col_get_max_size(
851 dict_table_get_nth_col(table, i));
853 row_len += col_len;
855 /* If we have a single unbounded field, or several gigantic
856 fields, mark the maximum row size as BIG_ROW_SIZE. */
857 if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
858 row_len = BIG_ROW_SIZE;
860 break;
864 table->big_rows = row_len >= BIG_ROW_SIZE;
866 /* Look for a table with the same name: error if such exists */
868 dict_table_t* table2;
869 HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
870 (ut_strcmp(table2->name, table->name) == 0));
871 ut_a(table2 == NULL);
874 /* Look for a table with the same id: error if such exists */
876 dict_table_t* table2;
877 HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2,
878 (ut_dulint_cmp(table2->id, table->id) == 0));
879 ut_a(table2 == NULL);
882 /* Add table to hash table of tables */
883 HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
884 table);
886 /* Add table to hash table of tables based on table id */
887 HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
888 table);
889 /* Add table to LRU list of tables */
890 UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
892 dict_sys->size += mem_heap_get_size(table->heap);
895 /**************************************************************************
896 Looks for an index with the given id. NOTE that we do not reserve
897 the dictionary mutex: this function is for emergency purposes like
898 printing info of a corrupt database page! */
900 dict_index_t*
901 dict_index_find_on_id_low(
902 /*======================*/
903 /* out: index or NULL if not found from cache */
904 dulint id) /* in: index id */
906 dict_table_t* table;
907 dict_index_t* index;
909 table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
911 while (table) {
912 index = dict_table_get_first_index(table);
914 while (index) {
915 if (0 == ut_dulint_cmp(id, index->id)) {
916 /* Found */
918 return(index);
921 index = dict_table_get_next_index(index);
924 table = UT_LIST_GET_NEXT(table_LRU, table);
927 return(NULL);
930 /**************************************************************************
931 Renames a table object. */
933 ibool
934 dict_table_rename_in_cache(
935 /*=======================*/
936 /* out: TRUE if success */
937 dict_table_t* table, /* in: table */
938 const char* new_name, /* in: new name */
939 ibool rename_also_foreigns)/* in: in ALTER TABLE we want
940 to preserve the original table name
941 in constraints which reference it */
943 dict_foreign_t* foreign;
944 dict_index_t* index;
945 ulint fold;
946 ulint old_size;
947 char* old_name;
948 ibool success;
950 ut_ad(table);
951 ut_ad(mutex_own(&(dict_sys->mutex)));
953 old_size = mem_heap_get_size(table->heap);
955 fold = ut_fold_string(new_name);
957 /* Look for a table with the same name: error if such exists */
959 dict_table_t* table2;
960 HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
961 (ut_strcmp(table2->name, new_name) == 0));
962 if (table2) {
963 fprintf(stderr,
964 "InnoDB: Error: dictionary cache"
965 " already contains a table of name %s\n",
966 new_name);
967 return(FALSE);
971 /* If the table is stored in a single-table tablespace, rename the
972 .ibd file */
974 if (table->space != 0) {
975 if (table->dir_path_of_temp_table != NULL) {
976 fprintf(stderr,
977 "InnoDB: Error: trying to rename a table"
978 " %s (%s) created with CREATE\n"
979 "InnoDB: TEMPORARY TABLE\n",
980 table->name, table->dir_path_of_temp_table);
981 success = FALSE;
982 } else {
983 success = fil_rename_tablespace(
984 table->name, table->space, new_name);
987 if (!success) {
989 return(FALSE);
993 /* Remove table from the hash tables of tables */
994 HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
995 ut_fold_string(table->name), table);
996 old_name = mem_heap_strdup(table->heap, table->name);
997 table->name = mem_heap_strdup(table->heap, new_name);
999 /* Add table to hash table of tables */
1000 HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1001 table);
1002 dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
1004 /* Update the table_name field in indexes */
1005 index = dict_table_get_first_index(table);
1007 while (index != NULL) {
1008 index->table_name = table->name;
1010 index = dict_table_get_next_index(index);
1013 if (!rename_also_foreigns) {
1014 /* In ALTER TABLE we think of the rename table operation
1015 in the direction table -> temporary table (#sql...)
1016 as dropping the table with the old name and creating
1017 a new with the new name. Thus we kind of drop the
1018 constraints from the dictionary cache here. The foreign key
1019 constraints will be inherited to the new table from the
1020 system tables through a call of dict_load_foreigns. */
1022 /* Remove the foreign constraints from the cache */
1023 foreign = UT_LIST_GET_LAST(table->foreign_list);
1025 while (foreign != NULL) {
1026 dict_foreign_remove_from_cache(foreign);
1027 foreign = UT_LIST_GET_LAST(table->foreign_list);
1030 /* Reset table field in referencing constraints */
1032 foreign = UT_LIST_GET_FIRST(table->referenced_list);
1034 while (foreign != NULL) {
1035 foreign->referenced_table = NULL;
1036 foreign->referenced_index = NULL;
1038 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1041 /* Make the list of referencing constraints empty */
1043 UT_LIST_INIT(table->referenced_list);
1045 return(TRUE);
1048 /* Update the table name fields in foreign constraints, and update also
1049 the constraint id of new format >= 4.0.18 constraints. Note that at
1050 this point we have already changed table->name to the new name. */
1052 foreign = UT_LIST_GET_FIRST(table->foreign_list);
1054 while (foreign != NULL) {
1056 if (ut_strlen(foreign->foreign_table_name)
1057 < ut_strlen(table->name)) {
1058 /* Allocate a longer name buffer;
1059 TODO: store buf len to save memory */
1061 foreign->foreign_table_name
1062 = mem_heap_alloc(foreign->heap,
1063 ut_strlen(table->name) + 1);
1066 strcpy(foreign->foreign_table_name, table->name);
1068 if (strchr(foreign->id, '/')) {
1069 /* This is a >= 4.0.18 format id */
1071 ulint db_len;
1072 char* old_id;
1073 char old_name_cs_filename[MAX_TABLE_NAME_LEN+20];
1074 uint errors = 0;
1076 /* All table names are internally stored in charset
1077 my_charset_filename (except the temp tables and the
1078 partition identifier suffix in partition tables). The
1079 foreign key constraint names are internally stored
1080 in UTF-8 charset. The variable fkid here is used
1081 to store foreign key constraint name in charset
1082 my_charset_filename for comparison further below. */
1083 char fkid[MAX_TABLE_NAME_LEN+20];
1084 ibool on_tmp = FALSE;
1086 /* The old table name in my_charset_filename is stored
1087 in old_name_cs_filename */
1089 strncpy(old_name_cs_filename, old_name,
1090 MAX_TABLE_NAME_LEN);
1091 if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) {
1093 innobase_convert_to_system_charset(
1094 strchr(old_name_cs_filename, '/') + 1,
1095 strchr(old_name, '/') + 1,
1096 MAX_TABLE_NAME_LEN, &errors);
1098 if (errors) {
1099 /* There has been an error to convert
1100 old table into UTF-8. This probably
1101 means that the old table name is
1102 actually in UTF-8. */
1103 innobase_convert_to_filename_charset(
1104 strchr(old_name_cs_filename,
1105 '/') + 1,
1106 strchr(old_name, '/') + 1,
1107 MAX_TABLE_NAME_LEN);
1108 } else {
1109 /* Old name already in
1110 my_charset_filename */
1111 strncpy(old_name_cs_filename, old_name,
1112 MAX_TABLE_NAME_LEN);
1116 strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
1118 if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) {
1119 innobase_convert_to_filename_charset(
1120 strchr(fkid, '/') + 1,
1121 strchr(foreign->id, '/') + 1,
1122 MAX_TABLE_NAME_LEN+20);
1123 } else {
1124 on_tmp = TRUE;
1127 old_id = mem_strdup(foreign->id);
1129 if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename)
1130 + ((sizeof dict_ibfk) - 1)
1131 && !memcmp(fkid, old_name_cs_filename,
1132 ut_strlen(old_name_cs_filename))
1133 && !memcmp(fkid + ut_strlen(old_name_cs_filename),
1134 dict_ibfk, (sizeof dict_ibfk) - 1)) {
1136 char table_name[MAX_TABLE_NAME_LEN] = "";
1137 uint errors = 0;
1139 /* This is a generated >= 4.0.18 format id */
1141 if (strlen(table->name) > strlen(old_name)) {
1142 foreign->id = mem_heap_zalloc(
1143 foreign->heap,
1144 strlen(table->name)
1145 + strlen(old_id) + 1);
1148 /* Convert the table name to UTF-8 */
1149 strncpy(table_name, table->name,
1150 MAX_TABLE_NAME_LEN);
1151 innobase_convert_to_system_charset(
1152 strchr(table_name, '/') + 1,
1153 strchr(table->name, '/') + 1,
1154 MAX_TABLE_NAME_LEN, &errors);
1156 if (errors) {
1157 /* Table name could not be converted
1158 from charset my_charset_filename to
1159 UTF-8. This means that the table name
1160 is already in UTF-8 (#mysql#50). */
1161 strncpy(table_name, table->name,
1162 MAX_TABLE_NAME_LEN);
1165 /* Replace the prefix 'databasename/tablename'
1166 with the new names */
1167 strcpy(foreign->id, table_name);
1168 if (on_tmp) {
1169 strcat(foreign->id,
1170 old_id + ut_strlen(old_name));
1171 } else {
1172 sprintf(strchr(foreign->id, '/') + 1,
1173 "%s%s",
1174 strchr(table_name, '/') +1,
1175 strstr(old_id, "_ibfk_") );
1178 } else {
1179 /* This is a >= 4.0.18 format id where the user
1180 gave the id name */
1181 db_len = dict_get_db_name_len(table->name) + 1;
1183 if (dict_get_db_name_len(table->name)
1184 > dict_get_db_name_len(foreign->id)) {
1186 foreign->id = mem_heap_alloc(
1187 foreign->heap,
1188 db_len + strlen(old_id) + 1);
1191 /* Replace the database prefix in id with the
1192 one from table->name */
1194 ut_memcpy(foreign->id, table->name, db_len);
1196 strcpy(foreign->id + db_len,
1197 dict_remove_db_name(old_id));
1200 mem_free(old_id);
1203 foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1206 foreign = UT_LIST_GET_FIRST(table->referenced_list);
1208 while (foreign != NULL) {
1209 if (ut_strlen(foreign->referenced_table_name)
1210 < ut_strlen(table->name)) {
1211 /* Allocate a longer name buffer;
1212 TODO: store buf len to save memory */
1214 foreign->referenced_table_name = mem_heap_alloc(
1215 foreign->heap, strlen(table->name) + 1);
1218 strcpy(foreign->referenced_table_name, table->name);
1220 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1223 return(TRUE);
1226 /**************************************************************************
1227 Change the id of a table object in the dictionary cache. This is used in
1228 DISCARD TABLESPACE. */
1230 void
1231 dict_table_change_id_in_cache(
1232 /*==========================*/
1233 dict_table_t* table, /* in: table object already in cache */
1234 dulint new_id) /* in: new id to set */
1236 ut_ad(table);
1237 ut_ad(mutex_own(&(dict_sys->mutex)));
1238 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1240 /* Remove the table from the hash table of id's */
1242 HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1243 ut_fold_dulint(table->id), table);
1244 table->id = new_id;
1246 /* Add the table back to the hash table */
1247 HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1248 ut_fold_dulint(table->id), table);
1251 /**************************************************************************
1252 Removes a table object from the dictionary cache. */
1254 void
1255 dict_table_remove_from_cache(
1256 /*=========================*/
1257 dict_table_t* table) /* in, own: table */
1259 dict_foreign_t* foreign;
1260 dict_index_t* index;
1261 ulint size;
1263 ut_ad(table);
1264 ut_ad(mutex_own(&(dict_sys->mutex)));
1265 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1267 #if 0
1268 fputs("Removing table ", stderr);
1269 ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1270 fputs(" from dictionary cache\n", stderr);
1271 #endif
1273 /* Remove the foreign constraints from the cache */
1274 foreign = UT_LIST_GET_LAST(table->foreign_list);
1276 while (foreign != NULL) {
1277 dict_foreign_remove_from_cache(foreign);
1278 foreign = UT_LIST_GET_LAST(table->foreign_list);
1281 /* Reset table field in referencing constraints */
1283 foreign = UT_LIST_GET_FIRST(table->referenced_list);
1285 while (foreign != NULL) {
1286 foreign->referenced_table = NULL;
1287 foreign->referenced_index = NULL;
1289 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1292 /* Remove the indexes from the cache */
1293 index = UT_LIST_GET_LAST(table->indexes);
1295 while (index != NULL) {
1296 dict_index_remove_from_cache(table, index);
1297 index = UT_LIST_GET_LAST(table->indexes);
1300 /* Remove table from the hash tables of tables */
1301 HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1302 ut_fold_string(table->name), table);
1303 HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1304 ut_fold_dulint(table->id), table);
1306 /* Remove table from LRU list of tables */
1307 UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1309 size = mem_heap_get_size(table->heap);
1311 ut_ad(dict_sys->size >= size);
1313 dict_sys->size -= size;
1315 dict_mem_table_free(table);
1318 /*************************************************************************
1319 Gets the column position in the clustered index. */
1321 ulint
1322 dict_col_get_clust_pos_noninline(
1323 /*=============================*/
1324 const dict_col_t* col, /* in: table column */
1325 const dict_index_t* clust_index) /* in: clustered index */
1327 return(dict_col_get_clust_pos(col, clust_index));
1330 /********************************************************************
1331 If the given column name is reserved for InnoDB system columns, return
1332 TRUE. */
1334 ibool
1335 dict_col_name_is_reserved(
1336 /*======================*/
1337 /* out: TRUE if name is reserved */
1338 const char* name) /* in: column name */
1340 /* This check reminds that if a new system column is added to
1341 the program, it should be dealt with here. */
1342 #if DATA_N_SYS_COLS != 3
1343 #error "DATA_N_SYS_COLS != 3"
1344 #endif
1346 static const char* reserved_names[] = {
1347 "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1350 ulint i;
1352 for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1353 if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1355 return(TRUE);
1359 return(FALSE);
1362 /**************************************************************************
1363 Adds an index to the dictionary cache. */
1365 void
1366 dict_index_add_to_cache(
1367 /*====================*/
1368 dict_table_t* table, /* in: table on which the index is */
1369 dict_index_t* index, /* in, own: index; NOTE! The index memory
1370 object is freed in this function! */
1371 ulint page_no)/* in: root page number of the index */
1373 dict_index_t* new_index;
1374 ulint n_ord;
1375 ulint i;
1377 ut_ad(index);
1378 ut_ad(mutex_own(&(dict_sys->mutex)));
1379 ut_ad(index->n_def == index->n_fields);
1380 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1382 ut_ad(mem_heap_validate(index->heap));
1384 #ifdef UNIV_DEBUG
1386 dict_index_t* index2;
1387 index2 = UT_LIST_GET_FIRST(table->indexes);
1389 while (index2 != NULL) {
1390 ut_ad(ut_strcmp(index->name, index2->name) != 0);
1392 index2 = UT_LIST_GET_NEXT(indexes, index2);
1395 #endif /* UNIV_DEBUG */
1397 ut_a(!(index->type & DICT_CLUSTERED)
1398 || UT_LIST_GET_LEN(table->indexes) == 0);
1400 dict_index_find_cols(table, index);
1402 /* Build the cache internal representation of the index,
1403 containing also the added system fields */
1405 if (index->type & DICT_CLUSTERED) {
1406 new_index = dict_index_build_internal_clust(table, index);
1407 } else {
1408 new_index = dict_index_build_internal_non_clust(table, index);
1411 new_index->search_info = btr_search_info_create(new_index->heap);
1413 /* Set the n_fields value in new_index to the actual defined
1414 number of fields in the cache internal representation */
1416 new_index->n_fields = new_index->n_def;
1418 /* Add the new index as the last index for the table */
1420 UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1421 new_index->table = table;
1422 new_index->table_name = table->name;
1424 /* Increment the ord_part counts in columns which are ordering */
1426 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1427 n_ord = new_index->n_fields;
1428 } else {
1429 n_ord = dict_index_get_n_unique(new_index);
1432 for (i = 0; i < n_ord; i++) {
1434 dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1437 new_index->page = (unsigned int) page_no;
1438 rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1440 if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1442 new_index->stat_n_diff_key_vals = mem_heap_alloc(
1443 new_index->heap,
1444 (1 + dict_index_get_n_unique(new_index))
1445 * sizeof(ib_longlong));
1447 new_index->stat_n_non_null_key_vals = mem_heap_zalloc(
1448 new_index->heap,
1449 (1 + dict_index_get_n_unique(new_index))
1450 * sizeof(*new_index->stat_n_non_null_key_vals));
1452 /* Give some sensible values to stat_n_... in case we do
1453 not calculate statistics quickly enough */
1455 for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1457 new_index->stat_n_diff_key_vals[i] = 100;
1461 dict_sys->size += mem_heap_get_size(new_index->heap);
1463 dict_mem_index_free(index);
1466 /**************************************************************************
1467 Removes an index from the dictionary cache. */
1468 static
1469 void
1470 dict_index_remove_from_cache(
1471 /*=========================*/
1472 dict_table_t* table, /* in: table */
1473 dict_index_t* index) /* in, own: index */
1475 ulint size;
1476 ulint retries = 0;
1477 btr_search_t* info;
1479 ut_ad(table && index);
1480 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1481 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1482 ut_ad(mutex_own(&(dict_sys->mutex)));
1484 /* We always create search info whether or not adaptive
1485 hash index is enabled or not. */
1486 info = index->search_info;
1487 ut_ad(info);
1489 /* We are not allowed to free the in-memory index struct
1490 dict_index_t until all entries in the adaptive hash index
1491 that point to any of the page belonging to his b-tree index
1492 are dropped. This is so because dropping of these entries
1493 require access to dict_index_t struct. To avoid such scenario
1494 We keep a count of number of such pages in the search_info and
1495 only free the dict_index_t struct when this count drops to
1496 zero. */
1498 for (;;) {
1499 ulint ref_count = btr_search_info_get_ref_count(info);
1500 if (ref_count == 0) {
1501 break;
1504 /* Sleep for 10ms before trying again. */
1505 os_thread_sleep(10000);
1506 ++retries;
1508 if (retries % 500 == 0) {
1509 /* No luck after 5 seconds of wait. */
1510 fprintf(stderr, "InnoDB: Error: Waited for"
1511 " %lu secs for hash index"
1512 " ref_count (%lu) to drop"
1513 " to 0.\n"
1514 "index: \"%s\""
1515 " table: \"%s\"\n",
1516 retries/100,
1517 ref_count,
1518 index->name,
1519 table->name);
1522 /* To avoid a hang here we commit suicide if the
1523 ref_count doesn't drop to zero in 600 seconds. */
1524 if (retries >= 60000) {
1525 ut_error;
1529 rw_lock_free(&index->lock);
1531 /* Remove the index from the list of indexes of the table */
1532 UT_LIST_REMOVE(indexes, table->indexes, index);
1534 size = mem_heap_get_size(index->heap);
1536 ut_ad(dict_sys->size >= size);
1538 dict_sys->size -= size;
1540 dict_mem_index_free(index);
1543 /***********************************************************************
1544 Tries to find column names for the index and sets the col field of the
1545 index. */
1546 static
1547 void
1548 dict_index_find_cols(
1549 /*=================*/
1550 dict_table_t* table, /* in: table */
1551 dict_index_t* index) /* in: index */
1553 ulint i;
1555 ut_ad(table && index);
1556 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1557 ut_ad(mutex_own(&(dict_sys->mutex)));
1559 for (i = 0; i < index->n_fields; i++) {
1560 ulint j;
1561 dict_field_t* field = dict_index_get_nth_field(index, i);
1563 for (j = 0; j < table->n_cols; j++) {
1564 if (!strcmp(dict_table_get_col_name(table, j),
1565 field->name)) {
1566 field->col = (dict_col_t*)
1567 dict_table_get_nth_col(table, j);
1569 goto found;
1573 /* It is an error not to find a matching column. */
1574 ut_error;
1576 found:
1581 /***********************************************************************
1582 Adds a column to index. */
1584 void
1585 dict_index_add_col(
1586 /*===============*/
1587 dict_index_t* index, /* in: index */
1588 dict_table_t* table, /* in: table */
1589 dict_col_t* col, /* in: column */
1590 ulint prefix_len) /* in: column prefix length */
1592 dict_field_t* field;
1593 const char* col_name;
1595 col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1597 dict_mem_index_add_field(index, col_name, prefix_len);
1599 field = dict_index_get_nth_field(index, index->n_def - 1);
1601 field->col = col;
1602 field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1604 if (prefix_len && field->fixed_len > prefix_len) {
1605 field->fixed_len = (unsigned int) prefix_len;
1608 /* Long fixed-length fields that need external storage are treated as
1609 variable-length fields, so that the extern flag can be embedded in
1610 the length word. */
1612 if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1613 field->fixed_len = 0;
1615 #if DICT_MAX_INDEX_COL_LEN != 768
1616 /* The comparison limit above must be constant. If it were
1617 changed, the disk format of some fixed-length columns would
1618 change, which would be a disaster. */
1619 # error "DICT_MAX_INDEX_COL_LEN != 768"
1620 #endif
1622 if (!(col->prtype & DATA_NOT_NULL)) {
1623 index->n_nullable++;
1627 /***********************************************************************
1628 Copies fields contained in index2 to index1. */
1629 static
1630 void
1631 dict_index_copy(
1632 /*============*/
1633 dict_index_t* index1, /* in: index to copy to */
1634 dict_index_t* index2, /* in: index to copy from */
1635 dict_table_t* table, /* in: table */
1636 ulint start, /* in: first position to copy */
1637 ulint end) /* in: last position to copy */
1639 dict_field_t* field;
1640 ulint i;
1642 /* Copy fields contained in index2 */
1644 for (i = start; i < end; i++) {
1646 field = dict_index_get_nth_field(index2, i);
1647 dict_index_add_col(index1, table, field->col,
1648 field->prefix_len);
1652 /***********************************************************************
1653 Copies types of fields contained in index to tuple. */
1655 void
1656 dict_index_copy_types(
1657 /*==================*/
1658 dtuple_t* tuple, /* in: data tuple */
1659 dict_index_t* index, /* in: index */
1660 ulint n_fields) /* in: number of field types to copy */
1662 ulint i;
1664 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1665 dtuple_set_types_binary(tuple, n_fields);
1667 return;
1670 for (i = 0; i < n_fields; i++) {
1671 dict_field_t* ifield;
1672 dtype_t* dfield_type;
1674 ifield = dict_index_get_nth_field(index, i);
1675 dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1676 dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1680 /***********************************************************************
1681 Copies types of columns contained in table to tuple. */
1683 void
1684 dict_table_copy_types(
1685 /*==================*/
1686 dtuple_t* tuple, /* in: data tuple */
1687 dict_table_t* table) /* in: index */
1689 dtype_t* dfield_type;
1690 ulint i;
1692 for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1694 dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1695 dict_col_copy_type(dict_table_get_nth_col(table, i),
1696 dfield_type);
1700 /***********************************************************************
1701 Builds the internal dictionary cache representation for a clustered
1702 index, containing also system fields not defined by the user. */
1703 static
1704 dict_index_t*
1705 dict_index_build_internal_clust(
1706 /*============================*/
1707 /* out, own: the internal representation
1708 of the clustered index */
1709 dict_table_t* table, /* in: table */
1710 dict_index_t* index) /* in: user representation of a clustered
1711 index */
1713 dict_index_t* new_index;
1714 dict_field_t* field;
1715 ulint trx_id_pos;
1716 ulint i;
1717 ibool* indexed;
1719 ut_ad(table && index);
1720 ut_ad(index->type & DICT_CLUSTERED);
1721 ut_ad(mutex_own(&(dict_sys->mutex)));
1722 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1724 /* Create a new index object with certainly enough fields */
1725 new_index = dict_mem_index_create(table->name,
1726 index->name, table->space,
1727 index->type,
1728 index->n_fields + table->n_cols);
1730 /* Copy other relevant data from the old index struct to the new
1731 struct: it inherits the values */
1733 new_index->n_user_defined_cols = index->n_fields;
1735 new_index->id = index->id;
1737 /* Copy the fields of index */
1738 dict_index_copy(new_index, index, table, 0, index->n_fields);
1740 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1741 /* No fixed number of fields determines an entry uniquely */
1743 new_index->n_uniq = REC_MAX_N_FIELDS;
1745 } else if (index->type & DICT_UNIQUE) {
1746 /* Only the fields defined so far are needed to identify
1747 the index entry uniquely */
1749 new_index->n_uniq = new_index->n_def;
1750 } else {
1751 /* Also the row id is needed to identify the entry */
1752 new_index->n_uniq = 1 + new_index->n_def;
1755 new_index->trx_id_offset = 0;
1757 if (!(index->type & DICT_IBUF)) {
1758 /* Add system columns, trx id first */
1760 trx_id_pos = new_index->n_def;
1762 #if DATA_ROW_ID != 0
1763 # error "DATA_ROW_ID != 0"
1764 #endif
1765 #if DATA_TRX_ID != 1
1766 # error "DATA_TRX_ID != 1"
1767 #endif
1768 #if DATA_ROLL_PTR != 2
1769 # error "DATA_ROLL_PTR != 2"
1770 #endif
1772 if (!(index->type & DICT_UNIQUE)) {
1773 dict_index_add_col(new_index, table, (dict_col_t*)
1774 dict_table_get_sys_col(
1775 table, DATA_ROW_ID),
1777 trx_id_pos++;
1780 dict_index_add_col(new_index, table, (dict_col_t*)
1781 dict_table_get_sys_col(table, DATA_TRX_ID),
1784 dict_index_add_col(new_index, table, (dict_col_t*)
1785 dict_table_get_sys_col(table,
1786 DATA_ROLL_PTR),
1789 for (i = 0; i < trx_id_pos; i++) {
1791 ulint fixed_size = dict_col_get_fixed_size(
1792 dict_index_get_nth_col(new_index, i));
1794 if (fixed_size == 0) {
1795 new_index->trx_id_offset = 0;
1797 break;
1800 if (dict_index_get_nth_field(new_index, i)->prefix_len
1801 > 0) {
1802 new_index->trx_id_offset = 0;
1804 break;
1807 /* Add fixed_size to new_index->trx_id_offset.
1808 Because the latter is a bit-field, an overflow
1809 can theoretically occur. Check for it. */
1810 fixed_size += new_index->trx_id_offset;
1812 new_index->trx_id_offset = fixed_size;
1814 if (new_index->trx_id_offset != fixed_size) {
1815 /* Overflow. Pretend that this is a
1816 variable-length PRIMARY KEY. */
1817 ut_ad(0);
1818 new_index->trx_id_offset = 0;
1819 break;
1825 /* Remember the table columns already contained in new_index */
1826 indexed = mem_alloc(table->n_cols * sizeof *indexed);
1827 memset(indexed, 0, table->n_cols * sizeof *indexed);
1829 /* Mark with 0 the table columns already contained in new_index */
1830 for (i = 0; i < new_index->n_def; i++) {
1832 field = dict_index_get_nth_field(new_index, i);
1834 /* If there is only a prefix of the column in the index
1835 field, do not mark the column as contained in the index */
1837 if (field->prefix_len == 0) {
1839 indexed[field->col->ind] = TRUE;
1843 /* Add to new_index non-system columns of table not yet included
1844 there */
1845 for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1847 dict_col_t* col = (dict_col_t*)
1848 dict_table_get_nth_col(table, i);
1849 ut_ad(col->mtype != DATA_SYS);
1851 if (!indexed[col->ind]) {
1852 dict_index_add_col(new_index, table, col, 0);
1856 mem_free(indexed);
1858 ut_ad((index->type & DICT_IBUF)
1859 || (UT_LIST_GET_LEN(table->indexes) == 0));
1861 new_index->cached = TRUE;
1863 return(new_index);
1866 /***********************************************************************
1867 Builds the internal dictionary cache representation for a non-clustered
1868 index, containing also system fields not defined by the user. */
1869 static
1870 dict_index_t*
1871 dict_index_build_internal_non_clust(
1872 /*================================*/
1873 /* out, own: the internal representation
1874 of the non-clustered index */
1875 dict_table_t* table, /* in: table */
1876 dict_index_t* index) /* in: user representation of a non-clustered
1877 index */
1879 dict_field_t* field;
1880 dict_index_t* new_index;
1881 dict_index_t* clust_index;
1882 ulint i;
1883 ibool* indexed;
1885 ut_ad(table && index);
1886 ut_ad(0 == (index->type & DICT_CLUSTERED));
1887 ut_ad(mutex_own(&(dict_sys->mutex)));
1888 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1890 /* The clustered index should be the first in the list of indexes */
1891 clust_index = UT_LIST_GET_FIRST(table->indexes);
1893 ut_ad(clust_index);
1894 ut_ad(clust_index->type & DICT_CLUSTERED);
1895 ut_ad(!(clust_index->type & DICT_UNIVERSAL));
1897 /* Create a new index */
1898 new_index = dict_mem_index_create(
1899 table->name, index->name, index->space, index->type,
1900 index->n_fields + 1 + clust_index->n_uniq);
1902 /* Copy other relevant data from the old index
1903 struct to the new struct: it inherits the values */
1905 new_index->n_user_defined_cols = index->n_fields;
1907 new_index->id = index->id;
1909 /* Copy fields from index to new_index */
1910 dict_index_copy(new_index, index, table, 0, index->n_fields);
1912 /* Remember the table columns already contained in new_index */
1913 indexed = mem_alloc(table->n_cols * sizeof *indexed);
1914 memset(indexed, 0, table->n_cols * sizeof *indexed);
1916 /* Mark with 0 table columns already contained in new_index */
1917 for (i = 0; i < new_index->n_def; i++) {
1919 field = dict_index_get_nth_field(new_index, i);
1921 /* If there is only a prefix of the column in the index
1922 field, do not mark the column as contained in the index */
1924 if (field->prefix_len == 0) {
1926 indexed[field->col->ind] = TRUE;
1930 /* Add to new_index the columns necessary to determine the clustered
1931 index entry uniquely */
1933 for (i = 0; i < clust_index->n_uniq; i++) {
1935 field = dict_index_get_nth_field(clust_index, i);
1937 if (!indexed[field->col->ind]) {
1938 dict_index_add_col(new_index, table, field->col,
1939 field->prefix_len);
1943 mem_free(indexed);
1945 if ((index->type) & DICT_UNIQUE) {
1946 new_index->n_uniq = index->n_fields;
1947 } else {
1948 new_index->n_uniq = new_index->n_def;
1951 /* Set the n_fields value in new_index to the actual defined
1952 number of fields */
1954 new_index->n_fields = new_index->n_def;
1956 new_index->cached = TRUE;
1958 return(new_index);
1961 /*====================== FOREIGN KEY PROCESSING ========================*/
1963 /*************************************************************************
1964 Checks if a table is referenced by foreign keys. */
1966 ibool
1967 dict_table_referenced_by_foreign_key(
1968 /*=================================*/
1969 /* out: TRUE if table is referenced by a
1970 foreign key */
1971 dict_table_t* table) /* in: InnoDB table */
1973 if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
1975 return(TRUE);
1978 return(FALSE);
1981 /*************************************************************************
1982 Frees a foreign key struct. */
1983 static
1984 void
1985 dict_foreign_free(
1986 /*==============*/
1987 dict_foreign_t* foreign) /* in, own: foreign key struct */
1989 ut_a(foreign->foreign_table->n_foreign_key_checks_running == 0);
1991 mem_heap_free(foreign->heap);
1994 /**************************************************************************
1995 Removes a foreign constraint struct from the dictionary cache. */
1996 static
1997 void
1998 dict_foreign_remove_from_cache(
1999 /*===========================*/
2000 dict_foreign_t* foreign) /* in, own: foreign constraint */
2002 ut_ad(mutex_own(&(dict_sys->mutex)));
2003 ut_a(foreign);
2005 if (foreign->referenced_table) {
2006 UT_LIST_REMOVE(referenced_list,
2007 foreign->referenced_table->referenced_list,
2008 foreign);
2011 if (foreign->foreign_table) {
2012 UT_LIST_REMOVE(foreign_list,
2013 foreign->foreign_table->foreign_list,
2014 foreign);
2017 dict_foreign_free(foreign);
2020 /**************************************************************************
2021 Looks for the foreign constraint from the foreign and referenced lists
2022 of a table. */
2023 static
2024 dict_foreign_t*
2025 dict_foreign_find(
2026 /*==============*/
2027 /* out: foreign constraint */
2028 dict_table_t* table, /* in: table object */
2029 const char* id) /* in: foreign constraint id */
2031 dict_foreign_t* foreign;
2033 ut_ad(mutex_own(&(dict_sys->mutex)));
2035 foreign = UT_LIST_GET_FIRST(table->foreign_list);
2037 while (foreign) {
2038 if (ut_strcmp(id, foreign->id) == 0) {
2040 return(foreign);
2043 foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2046 foreign = UT_LIST_GET_FIRST(table->referenced_list);
2048 while (foreign) {
2049 if (ut_strcmp(id, foreign->id) == 0) {
2051 return(foreign);
2054 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2057 return(NULL);
2060 #ifndef UNIV_HOTBACKUP
2061 /*************************************************************************
2062 Tries to find an index whose first fields are the columns in the array,
2063 in the same order. */
2064 static
2065 dict_index_t*
2066 dict_foreign_find_index(
2067 /*====================*/
2068 /* out: matching index, NULL if not found */
2069 dict_table_t* table, /* in: table */
2070 const char** columns,/* in: array of column names */
2071 ulint n_cols, /* in: number of columns */
2072 dict_index_t* types_idx, /* in: NULL or an index to whose types the
2073 column types must match */
2074 ibool check_charsets,
2075 /* in: whether to check charsets.
2076 only has an effect if types_idx != NULL */
2077 ulint check_null)
2078 /* in: nonzero if none of the columns must
2079 be declared NOT NULL */
2081 dict_index_t* index;
2082 dict_field_t* field;
2083 const char* col_name;
2084 ulint i;
2086 index = dict_table_get_first_index(table);
2088 while (index != NULL) {
2089 if (dict_index_get_n_fields(index) >= n_cols) {
2091 for (i = 0; i < n_cols; i++) {
2092 field = dict_index_get_nth_field(index, i);
2094 col_name = dict_table_get_col_name(
2095 table, dict_col_get_no(field->col));
2097 if (field->prefix_len != 0) {
2098 /* We do not accept column prefix
2099 indexes here */
2101 break;
2104 if (0 != innobase_strcasecmp(columns[i],
2105 col_name)) {
2106 break;
2109 if (check_null
2110 && (field->col->prtype & DATA_NOT_NULL)) {
2112 return(NULL);
2115 if (types_idx && !cmp_cols_are_equal(
2116 dict_index_get_nth_col(index, i),
2117 dict_index_get_nth_col(types_idx,
2119 check_charsets)) {
2121 break;
2125 if (i == n_cols) {
2126 /* We found a matching index */
2128 return(index);
2132 index = dict_table_get_next_index(index);
2135 return(NULL);
2138 /**************************************************************************
2139 Report an error in a foreign key definition. */
2140 static
2141 void
2142 dict_foreign_error_report_low(
2143 /*==========================*/
2144 FILE* file, /* in: output stream */
2145 const char* name) /* in: table name */
2147 rewind(file);
2148 ut_print_timestamp(file);
2149 fprintf(file, " Error in foreign key constraint of table %s:\n",
2150 name);
2153 /**************************************************************************
2154 Report an error in a foreign key definition. */
2155 static
2156 void
2157 dict_foreign_error_report(
2158 /*======================*/
2159 FILE* file, /* in: output stream */
2160 dict_foreign_t* fk, /* in: foreign key constraint */
2161 const char* msg) /* in: the error message */
2163 mutex_enter(&dict_foreign_err_mutex);
2164 dict_foreign_error_report_low(file, fk->foreign_table_name);
2165 fputs(msg, file);
2166 fputs(" Constraint:\n", file);
2167 dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2168 putc('\n', file);
2169 if (fk->foreign_index) {
2170 fputs("The index in the foreign key in table is ", file);
2171 ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2172 fputs("\n"
2173 "See http://dev.mysql.com/doc/refman/5.1/en/"
2174 "innodb-foreign-key-constraints.html\n"
2175 "for correct foreign key definition.\n",
2176 file);
2178 mutex_exit(&dict_foreign_err_mutex);
2181 /**************************************************************************
2182 Adds a foreign key constraint object to the dictionary cache. May free
2183 the object if there already is an object with the same identifier in.
2184 At least one of the foreign table and the referenced table must already
2185 be in the dictionary cache! */
2187 ulint
2188 dict_foreign_add_to_cache(
2189 /*======================*/
2190 /* out: DB_SUCCESS or error code */
2191 dict_foreign_t* foreign, /* in, own: foreign key constraint */
2192 ibool check_charsets) /* in: TRUE=check charset
2193 compatibility */
2195 dict_table_t* for_table;
2196 dict_table_t* ref_table;
2197 dict_foreign_t* for_in_cache = NULL;
2198 dict_index_t* index;
2199 ibool added_to_referenced_list= FALSE;
2200 FILE* ef = dict_foreign_err_file;
2202 ut_ad(mutex_own(&(dict_sys->mutex)));
2204 for_table = dict_table_check_if_in_cache_low(
2205 foreign->foreign_table_name);
2207 ref_table = dict_table_check_if_in_cache_low(
2208 foreign->referenced_table_name);
2209 ut_a(for_table || ref_table);
2211 if (for_table) {
2212 for_in_cache = dict_foreign_find(for_table, foreign->id);
2215 if (!for_in_cache && ref_table) {
2216 for_in_cache = dict_foreign_find(ref_table, foreign->id);
2219 if (for_in_cache) {
2220 /* Free the foreign object */
2221 mem_heap_free(foreign->heap);
2222 } else {
2223 for_in_cache = foreign;
2226 if (for_in_cache->referenced_table == NULL && ref_table) {
2227 index = dict_foreign_find_index(
2228 ref_table,
2229 (const char**) for_in_cache->referenced_col_names,
2230 for_in_cache->n_fields, for_in_cache->foreign_index,
2231 check_charsets, FALSE);
2233 if (index == NULL) {
2234 dict_foreign_error_report(
2235 ef, for_in_cache,
2236 "there is no index in referenced table"
2237 " which would contain\n"
2238 "the columns as the first columns,"
2239 " or the data types in the\n"
2240 "referenced table do not match"
2241 " the ones in table.");
2243 if (for_in_cache == foreign) {
2244 mem_heap_free(foreign->heap);
2247 return(DB_FOREIGN_NO_INDEX);
2250 for_in_cache->referenced_table = ref_table;
2251 for_in_cache->referenced_index = index;
2252 UT_LIST_ADD_LAST(referenced_list,
2253 ref_table->referenced_list,
2254 for_in_cache);
2255 added_to_referenced_list = TRUE;
2258 if (for_in_cache->foreign_table == NULL && for_table) {
2259 index = dict_foreign_find_index(
2260 for_table,
2261 (const char**) for_in_cache->foreign_col_names,
2262 for_in_cache->n_fields,
2263 for_in_cache->referenced_index, check_charsets,
2264 for_in_cache->type
2265 & (DICT_FOREIGN_ON_DELETE_SET_NULL
2266 | DICT_FOREIGN_ON_UPDATE_SET_NULL));
2268 if (index == NULL) {
2269 dict_foreign_error_report(
2270 ef, for_in_cache,
2271 "there is no index in the table"
2272 " which would contain\n"
2273 "the columns as the first columns,"
2274 " or the data types in the\n"
2275 "table do not match"
2276 " the ones in the referenced table\n"
2277 "or one of the ON ... SET NULL columns"
2278 " is declared NOT NULL.");
2280 if (for_in_cache == foreign) {
2281 if (added_to_referenced_list) {
2282 UT_LIST_REMOVE(
2283 referenced_list,
2284 ref_table->referenced_list,
2285 for_in_cache);
2288 mem_heap_free(foreign->heap);
2291 return(DB_REFERENCING_NO_INDEX);
2294 for_in_cache->foreign_table = for_table;
2295 for_in_cache->foreign_index = index;
2296 UT_LIST_ADD_LAST(foreign_list,
2297 for_table->foreign_list,
2298 for_in_cache);
2301 return(DB_SUCCESS);
2304 /*************************************************************************
2305 Scans from pointer onwards. Stops if is at the start of a copy of
2306 'string' where characters are compared without case sensitivity, and
2307 only outside `` or "" quotes. Stops also at '\0'. */
2309 const char*
2310 dict_scan_to(
2311 /*=========*/
2312 /* out: scanned up to this */
2313 const char* ptr, /* in: scan from */
2314 const char* string) /* in: look for this */
2316 char quote = '\0';
2318 for (; *ptr; ptr++) {
2319 if (*ptr == quote) {
2320 /* Closing quote character: do not look for
2321 starting quote or the keyword. */
2322 quote = '\0';
2323 } else if (quote) {
2324 /* Within quotes: do nothing. */
2325 } else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
2326 /* Starting quote: remember the quote character. */
2327 quote = *ptr;
2328 } else {
2329 /* Outside quotes: look for the keyword. */
2330 ulint i;
2331 for (i = 0; string[i]; i++) {
2332 if (toupper((int)(unsigned char)(ptr[i]))
2333 != toupper((int)(unsigned char)
2334 (string[i]))) {
2335 goto nomatch;
2338 break;
2339 nomatch:
2344 return(ptr);
2347 /*************************************************************************
2348 Accepts a specified string. Comparisons are case-insensitive. */
2349 static
2350 const char*
2351 dict_accept(
2352 /*========*/
2353 /* out: if string was accepted, the pointer
2354 is moved after that, else ptr is returned */
2355 struct charset_info_st* cs,/* in: the character set of ptr */
2356 const char* ptr, /* in: scan from this */
2357 const char* string, /* in: accept only this string as the next
2358 non-whitespace string */
2359 ibool* success)/* out: TRUE if accepted */
2361 const char* old_ptr = ptr;
2362 const char* old_ptr2;
2364 *success = FALSE;
2366 while (my_isspace(cs, *ptr)) {
2367 ptr++;
2370 old_ptr2 = ptr;
2372 ptr = dict_scan_to(ptr, string);
2374 if (*ptr == '\0' || old_ptr2 != ptr) {
2375 return(old_ptr);
2378 *success = TRUE;
2380 return(ptr + ut_strlen(string));
2383 /*************************************************************************
2384 Scans an id. For the lexical definition of an 'id', see the code below.
2385 Strips backquotes or double quotes from around the id. */
2386 static
2387 const char*
2388 dict_scan_id(
2389 /*=========*/
2390 /* out: scanned to */
2391 struct charset_info_st* cs,/* in: the character set of ptr */
2392 const char* ptr, /* in: scanned to */
2393 mem_heap_t* heap, /* in: heap where to allocate the id
2394 (NULL=id will not be allocated, but it
2395 will point to string near ptr) */
2396 const char** id, /* out,own: the id; NULL if no id was
2397 scannable */
2398 ibool table_id,/* in: TRUE=convert the allocated id
2399 as a table name; FALSE=convert to UTF-8 */
2400 ibool accept_also_dot)
2401 /* in: TRUE if also a dot can appear in a
2402 non-quoted id; in a quoted id it can appear
2403 always */
2405 char quote = '\0';
2406 ulint len = 0;
2407 const char* s;
2408 char* str;
2409 char* dst;
2411 *id = NULL;
2413 while (my_isspace(cs, *ptr)) {
2414 ptr++;
2417 if (*ptr == '\0') {
2419 return(ptr);
2422 if (*ptr == '`' || *ptr == '"') {
2423 quote = *ptr++;
2426 s = ptr;
2428 if (quote) {
2429 for (;;) {
2430 if (!*ptr) {
2431 /* Syntax error */
2432 return(ptr);
2434 if (*ptr == quote) {
2435 ptr++;
2436 if (*ptr != quote) {
2437 break;
2440 ptr++;
2441 len++;
2443 } else {
2444 while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2445 && (accept_also_dot || *ptr != '.')
2446 && *ptr != ',' && *ptr != '\0') {
2448 ptr++;
2451 len = ptr - s;
2454 if (UNIV_UNLIKELY(!heap)) {
2455 /* no heap given: id will point to source string */
2456 *id = s;
2457 return(ptr);
2460 if (quote) {
2461 char* d;
2462 str = d = mem_heap_alloc(heap, len + 1);
2463 while (len--) {
2464 if ((*d++ = *s++) == quote) {
2465 s++;
2468 *d++ = 0;
2469 len = d - str;
2470 ut_ad(*s == quote);
2471 ut_ad(s + 1 == ptr);
2472 } else {
2473 str = mem_heap_strdupl(heap, s, len);
2476 if (!table_id) {
2477 convert_id:
2478 /* Convert the identifier from connection character set
2479 to UTF-8. */
2480 len = 3 * len + 1;
2481 *id = dst = mem_heap_alloc(heap, len);
2483 innobase_convert_from_id(dst, str, len);
2484 } else if (!strncmp(str, srv_mysql50_table_name_prefix,
2485 sizeof srv_mysql50_table_name_prefix)) {
2486 /* This is a pre-5.1 table name
2487 containing chars other than [A-Za-z0-9].
2488 Discard the prefix and use raw UTF-8 encoding. */
2489 str += sizeof srv_mysql50_table_name_prefix;
2490 len -= sizeof srv_mysql50_table_name_prefix;
2491 goto convert_id;
2492 } else {
2493 /* Encode using filename-safe characters. */
2494 len = 5 * len + 1;
2495 *id = dst = mem_heap_alloc(heap, len);
2497 innobase_convert_from_table_id(dst, str, len);
2500 return(ptr);
2503 /*************************************************************************
2504 Tries to scan a column name. */
2505 static
2506 const char*
2507 dict_scan_col(
2508 /*==========*/
2509 /* out: scanned to */
2510 struct charset_info_st* cs, /* in: the character set of ptr */
2511 const char* ptr, /* in: scanned to */
2512 ibool* success,/* out: TRUE if success */
2513 dict_table_t* table, /* in: table in which the column is */
2514 const dict_col_t** column, /* out: pointer to column if success */
2515 mem_heap_t* heap, /* in: heap where to allocate */
2516 const char** name) /* out,own: the column name;
2517 NULL if no name was scannable */
2519 ulint i;
2521 *success = FALSE;
2523 ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2525 if (*name == NULL) {
2527 return(ptr); /* Syntax error */
2530 if (table == NULL) {
2531 *success = TRUE;
2532 *column = NULL;
2533 } else {
2534 for (i = 0; i < dict_table_get_n_cols(table); i++) {
2536 const char* col_name = dict_table_get_col_name(
2537 table, i);
2539 if (0 == innobase_strcasecmp(col_name, *name)) {
2540 /* Found */
2542 *success = TRUE;
2543 *column = dict_table_get_nth_col(table, i);
2544 strcpy((char*) *name, col_name);
2546 break;
2551 return(ptr);
2554 /*************************************************************************
2555 Scans a table name from an SQL string. */
2556 static
2557 const char*
2558 dict_scan_table_name(
2559 /*=================*/
2560 /* out: scanned to */
2561 struct charset_info_st* cs,/* in: the character set of ptr */
2562 const char* ptr, /* in: scanned to */
2563 dict_table_t** table, /* out: table object or NULL */
2564 const char* name, /* in: foreign key table name */
2565 ibool* success,/* out: TRUE if ok name found */
2566 mem_heap_t* heap, /* in: heap where to allocate the id */
2567 const char** ref_name)/* out,own: the table name;
2568 NULL if no name was scannable */
2570 const char* database_name = NULL;
2571 ulint database_name_len = 0;
2572 const char* table_name = NULL;
2573 ulint table_name_len;
2574 const char* scan_name;
2575 char* ref;
2577 *success = FALSE;
2578 *table = NULL;
2580 ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2582 if (scan_name == NULL) {
2584 return(ptr); /* Syntax error */
2587 if (*ptr == '.') {
2588 /* We scanned the database name; scan also the table name */
2590 ptr++;
2592 database_name = scan_name;
2593 database_name_len = strlen(database_name);
2595 ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2597 if (table_name == NULL) {
2599 return(ptr); /* Syntax error */
2601 } else {
2602 /* To be able to read table dumps made with InnoDB-4.0.17 or
2603 earlier, we must allow the dot separator between the database
2604 name and the table name also to appear within a quoted
2605 identifier! InnoDB used to print a constraint as:
2606 ... REFERENCES `databasename.tablename` ...
2607 starting from 4.0.18 it is
2608 ... REFERENCES `databasename`.`tablename` ... */
2609 const char* s;
2611 for (s = scan_name; *s; s++) {
2612 if (*s == '.') {
2613 database_name = scan_name;
2614 database_name_len = s - scan_name;
2615 scan_name = ++s;
2616 break;/* to do: multiple dots? */
2620 table_name = scan_name;
2623 if (database_name == NULL) {
2624 /* Use the database name of the foreign key table */
2626 database_name = name;
2627 database_name_len = dict_get_db_name_len(name);
2630 table_name_len = strlen(table_name);
2632 /* Copy database_name, '/', table_name, '\0' */
2633 ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2634 memcpy(ref, database_name, database_name_len);
2635 ref[database_name_len] = '/';
2636 memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2637 #ifndef __WIN__
2638 if (srv_lower_case_table_names) {
2639 #endif /* !__WIN__ */
2640 /* The table name is always put to lower case on Windows. */
2641 innobase_casedn_str(ref);
2642 #ifndef __WIN__
2644 #endif /* !__WIN__ */
2646 *success = TRUE;
2647 *ref_name = ref;
2648 *table = dict_table_get_low(ref);
2650 return(ptr);
2653 /*************************************************************************
2654 Skips one id. The id is allowed to contain also '.'. */
2655 static
2656 const char*
2657 dict_skip_word(
2658 /*===========*/
2659 /* out: scanned to */
2660 struct charset_info_st* cs,/* in: the character set of ptr */
2661 const char* ptr, /* in: scanned to */
2662 ibool* success)/* out: TRUE if success, FALSE if just spaces
2663 left in string or a syntax error */
2665 const char* start;
2667 *success = FALSE;
2669 ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2671 if (start) {
2672 *success = TRUE;
2675 return(ptr);
2678 /*************************************************************************
2679 Removes MySQL comments from an SQL string. A comment is either
2680 (a) '#' to the end of the line,
2681 (b) '--<space>' to the end of the line, or
2682 (c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
2683 C comment syntax). */
2684 static
2685 char*
2686 dict_strip_comments(
2687 /*================*/
2688 /* out, own: SQL string stripped from
2689 comments; the caller must free this
2690 with mem_free()! */
2691 const char* sql_string, /* in: SQL string */
2692 size_t sql_length) /* in: length of sql_string */
2694 char* str;
2695 const char* sptr;
2696 const char* eptr = sql_string + sql_length;
2697 char* ptr;
2698 /* unclosed quote character (0 if none) */
2699 char quote = 0;
2701 str = mem_alloc(sql_length + 1);
2703 sptr = sql_string;
2704 ptr = str;
2706 for (;;) {
2707 scan_more:
2708 if (sptr >= eptr || *sptr == '\0') {
2709 end_of_string:
2710 *ptr = '\0';
2712 ut_a(ptr <= str + sql_length);
2714 return(str);
2717 if (*sptr == quote) {
2718 /* Closing quote character: do not look for
2719 starting quote or comments. */
2720 quote = 0;
2721 } else if (quote) {
2722 /* Within quotes: do not look for
2723 starting quotes or comments. */
2724 } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
2725 /* Starting quote: remember the quote character. */
2726 quote = *sptr;
2727 } else if (*sptr == '#'
2728 || (sptr[0] == '-' && sptr[1] == '-'
2729 && sptr[2] == ' ')) {
2730 for (;;) {
2731 if (++sptr >= eptr) {
2732 goto end_of_string;
2735 /* In Unix a newline is 0x0A while in Windows
2736 it is 0x0D followed by 0x0A */
2738 switch (*sptr) {
2739 case (char) 0X0A:
2740 case (char) 0x0D:
2741 case '\0':
2742 goto scan_more;
2745 } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
2746 sptr += 2;
2747 for (;;) {
2748 if (sptr >= eptr) {
2749 goto end_of_string;
2752 switch (*sptr) {
2753 case '\0':
2754 goto scan_more;
2755 case '*':
2756 if (sptr[1] == '/') {
2757 sptr += 2;
2758 goto scan_more;
2762 sptr++;
2766 *ptr = *sptr;
2768 ptr++;
2769 sptr++;
2773 /*************************************************************************
2774 Finds the highest <number> for foreign key constraints of the table. Looks
2775 only at the >= 4.0.18-format id's, which are of the form
2776 databasename/tablename_ibfk_<number>. */
2777 static
2778 ulint
2779 dict_table_get_highest_foreign_id(
2780 /*==============================*/
2781 /* out: highest number, 0 if table has no new
2782 format foreign key constraints */
2783 dict_table_t* table) /* in: table in the dictionary memory cache */
2785 dict_foreign_t* foreign;
2786 char* endp;
2787 ulint biggest_id = 0;
2788 ulint id;
2789 ulint len;
2791 ut_a(table);
2793 len = ut_strlen(table->name);
2794 foreign = UT_LIST_GET_FIRST(table->foreign_list);
2796 while (foreign) {
2797 if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
2798 && 0 == ut_memcmp(foreign->id, table->name, len)
2799 && 0 == ut_memcmp(foreign->id + len,
2800 dict_ibfk, (sizeof dict_ibfk) - 1)
2801 && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
2802 /* It is of the >= 4.0.18 format */
2804 id = strtoul(foreign->id + len
2805 + ((sizeof dict_ibfk) - 1),
2806 &endp, 10);
2807 if (*endp == '\0') {
2808 ut_a(id != biggest_id);
2810 if (id > biggest_id) {
2811 biggest_id = id;
2816 foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2819 return(biggest_id);
2822 /*************************************************************************
2823 Reports a simple foreign key create clause syntax error. */
2824 static
2825 void
2826 dict_foreign_report_syntax_err(
2827 /*===========================*/
2828 const char* name, /* in: table name */
2829 const char* start_of_latest_foreign,
2830 /* in: start of the foreign key clause
2831 in the SQL string */
2832 const char* ptr) /* in: place of the syntax error */
2834 FILE* ef = dict_foreign_err_file;
2836 mutex_enter(&dict_foreign_err_mutex);
2837 dict_foreign_error_report_low(ef, name);
2838 fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
2839 start_of_latest_foreign, ptr);
2840 mutex_exit(&dict_foreign_err_mutex);
2843 /*************************************************************************
2844 Scans a table create SQL string and adds to the data dictionary the foreign
2845 key constraints declared in the string. This function should be called after
2846 the indexes for a table have been created. Each foreign key constraint must
2847 be accompanied with indexes in both participating tables. The indexes are
2848 allowed to contain more fields than mentioned in the constraint. */
2849 static
2850 ulint
2851 dict_create_foreign_constraints_low(
2852 /*================================*/
2853 /* out: error code or DB_SUCCESS */
2854 trx_t* trx, /* in: transaction */
2855 mem_heap_t* heap, /* in: memory heap */
2856 struct charset_info_st* cs,/* in: the character set of sql_string */
2857 const char* sql_string,
2858 /* in: CREATE TABLE or ALTER TABLE statement
2859 where foreign keys are declared like:
2860 FOREIGN KEY (a, b) REFERENCES table2(c, d),
2861 table2 can be written also with the database
2862 name before it: test.table2; the default
2863 database is the database of parameter name */
2864 const char* name, /* in: table full name in the normalized form
2865 database_name/table_name */
2866 ibool reject_fks)
2867 /* in: if TRUE, fail with error code
2868 DB_CANNOT_ADD_CONSTRAINT if any foreign
2869 keys are found. */
2871 dict_table_t* table;
2872 dict_table_t* referenced_table;
2873 dict_table_t* table_to_alter;
2874 ulint highest_id_so_far = 0;
2875 dict_index_t* index;
2876 dict_foreign_t* foreign;
2877 const char* ptr = sql_string;
2878 const char* start_of_latest_foreign = sql_string;
2879 FILE* ef = dict_foreign_err_file;
2880 const char* constraint_name;
2881 ibool success;
2882 ulint error;
2883 const char* ptr1;
2884 const char* ptr2;
2885 ulint i;
2886 ulint j;
2887 ibool is_on_delete;
2888 ulint n_on_deletes;
2889 ulint n_on_updates;
2890 const dict_col_t*columns[500];
2891 const char* column_names[500];
2892 const char* referenced_table_name;
2894 ut_ad(mutex_own(&(dict_sys->mutex)));
2896 table = dict_table_get_low(name);
2898 if (table == NULL) {
2899 mutex_enter(&dict_foreign_err_mutex);
2900 dict_foreign_error_report_low(ef, name);
2901 fprintf(ef,
2902 "Cannot find the table in the internal"
2903 " data dictionary of InnoDB.\n"
2904 "Create table statement:\n%s\n", sql_string);
2905 mutex_exit(&dict_foreign_err_mutex);
2907 return(DB_ERROR);
2910 /* First check if we are actually doing an ALTER TABLE, and in that
2911 case look for the table being altered */
2913 ptr = dict_accept(cs, ptr, "ALTER", &success);
2915 if (!success) {
2917 goto loop;
2920 ptr = dict_accept(cs, ptr, "TABLE", &success);
2922 if (!success) {
2924 goto loop;
2927 /* We are doing an ALTER TABLE: scan the table name we are altering */
2929 ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
2930 &success, heap, &referenced_table_name);
2931 if (!success) {
2932 fprintf(stderr,
2933 "InnoDB: Error: could not find"
2934 " the table being ALTERED in:\n%s\n",
2935 sql_string);
2937 return(DB_ERROR);
2940 /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
2941 format databasename/tablename_ibfk_<number>, where <number> is local
2942 to the table; look for the highest <number> for table_to_alter, so
2943 that we can assign to new constraints higher numbers. */
2945 /* If we are altering a temporary table, the table name after ALTER
2946 TABLE does not correspond to the internal table name, and
2947 table_to_alter is NULL. TODO: should we fix this somehow? */
2949 if (table_to_alter == NULL) {
2950 highest_id_so_far = 0;
2951 } else {
2952 highest_id_so_far = dict_table_get_highest_foreign_id(
2953 table_to_alter);
2956 /* Scan for foreign key declarations in a loop */
2957 loop:
2958 /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
2960 ptr1 = dict_scan_to(ptr, "CONSTRAINT");
2961 ptr2 = dict_scan_to(ptr, "FOREIGN");
2963 constraint_name = NULL;
2965 if (ptr1 < ptr2) {
2966 /* The user may have specified a constraint name. Pick it so
2967 that we can store 'databasename/constraintname' as the id of
2968 of the constraint to system tables. */
2969 ptr = ptr1;
2971 ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
2973 ut_a(success);
2975 if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
2976 goto loop;
2979 while (my_isspace(cs, *ptr)) {
2980 ptr++;
2983 /* read constraint name unless got "CONSTRAINT FOREIGN" */
2984 if (ptr != ptr2) {
2985 ptr = dict_scan_id(cs, ptr, heap,
2986 &constraint_name, FALSE, FALSE);
2988 } else {
2989 ptr = ptr2;
2992 if (*ptr == '\0') {
2993 /* The proper way to reject foreign keys for temporary
2994 tables would be to split the lexing and syntactical
2995 analysis of foreign key clauses from the actual adding
2996 of them, so that ha_innodb.cc could first parse the SQL
2997 command, determine if there are any foreign keys, and
2998 if so, immediately reject the command if the table is a
2999 temporary one. For now, this kludge will work. */
3000 if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
3002 return(DB_CANNOT_ADD_CONSTRAINT);
3005 /**********************************************************/
3006 /* The following call adds the foreign key constraints
3007 to the data dictionary system tables on disk */
3009 error = dict_create_add_foreigns_to_dictionary(
3010 highest_id_so_far, table, trx);
3011 return(error);
3014 start_of_latest_foreign = ptr;
3016 ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3018 if (!success) {
3019 goto loop;
3022 if (!my_isspace(cs, *ptr)) {
3023 goto loop;
3026 ptr = dict_accept(cs, ptr, "KEY", &success);
3028 if (!success) {
3029 goto loop;
3032 ptr = dict_accept(cs, ptr, "(", &success);
3034 if (!success) {
3035 /* MySQL allows also an index id before the '('; we
3036 skip it */
3037 ptr = dict_skip_word(cs, ptr, &success);
3039 if (!success) {
3040 dict_foreign_report_syntax_err(
3041 name, start_of_latest_foreign, ptr);
3043 return(DB_CANNOT_ADD_CONSTRAINT);
3046 ptr = dict_accept(cs, ptr, "(", &success);
3048 if (!success) {
3049 /* We do not flag a syntax error here because in an
3050 ALTER TABLE we may also have DROP FOREIGN KEY abc */
3052 goto loop;
3056 i = 0;
3058 /* Scan the columns in the first list */
3059 col_loop1:
3060 ut_a(i < (sizeof column_names) / sizeof *column_names);
3061 ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
3062 heap, column_names + i);
3063 if (!success) {
3064 mutex_enter(&dict_foreign_err_mutex);
3065 dict_foreign_error_report_low(ef, name);
3066 fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
3067 start_of_latest_foreign, ptr);
3068 mutex_exit(&dict_foreign_err_mutex);
3070 return(DB_CANNOT_ADD_CONSTRAINT);
3073 i++;
3075 ptr = dict_accept(cs, ptr, ",", &success);
3077 if (success) {
3078 goto col_loop1;
3081 ptr = dict_accept(cs, ptr, ")", &success);
3083 if (!success) {
3084 dict_foreign_report_syntax_err(
3085 name, start_of_latest_foreign, ptr);
3086 return(DB_CANNOT_ADD_CONSTRAINT);
3089 /* Try to find an index which contains the columns
3090 as the first fields and in the right order */
3092 index = dict_foreign_find_index(table, column_names, i,
3093 NULL, TRUE, FALSE);
3095 if (!index) {
3096 mutex_enter(&dict_foreign_err_mutex);
3097 dict_foreign_error_report_low(ef, name);
3098 fputs("There is no index in table ", ef);
3099 ut_print_name(ef, NULL, TRUE, name);
3100 fprintf(ef, " where the columns appear\n"
3101 "as the first columns. Constraint:\n%s\n"
3102 "See http://dev.mysql.com/doc/refman/5.1/en/"
3103 "innodb-foreign-key-constraints.html\n"
3104 "for correct foreign key definition.\n",
3105 start_of_latest_foreign);
3106 mutex_exit(&dict_foreign_err_mutex);
3108 return(DB_CANNOT_ADD_CONSTRAINT);
3110 ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3112 if (!success || !my_isspace(cs, *ptr)) {
3113 dict_foreign_report_syntax_err(
3114 name, start_of_latest_foreign, ptr);
3115 return(DB_CANNOT_ADD_CONSTRAINT);
3118 /* Let us create a constraint struct */
3120 foreign = dict_mem_foreign_create();
3122 if (constraint_name) {
3123 ulint db_len;
3125 /* Catenate 'databasename/' to the constraint name specified
3126 by the user: we conceive the constraint as belonging to the
3127 same MySQL 'database' as the table itself. We store the name
3128 to foreign->id. */
3130 db_len = dict_get_db_name_len(table->name);
3132 foreign->id = mem_heap_alloc(
3133 foreign->heap, db_len + strlen(constraint_name) + 2);
3135 ut_memcpy(foreign->id, table->name, db_len);
3136 foreign->id[db_len] = '/';
3137 strcpy(foreign->id + db_len + 1, constraint_name);
3140 foreign->foreign_table = table;
3141 foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
3142 table->name);
3143 foreign->foreign_index = index;
3144 foreign->n_fields = (unsigned int) i;
3145 foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3146 i * sizeof(void*));
3147 for (i = 0; i < foreign->n_fields; i++) {
3148 foreign->foreign_col_names[i] = mem_heap_strdup(
3149 foreign->heap,
3150 dict_table_get_col_name(table,
3151 dict_col_get_no(columns[i])));
3154 ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3155 &success, heap, &referenced_table_name);
3157 /* Note that referenced_table can be NULL if the user has suppressed
3158 checking of foreign key constraints! */
3160 if (!success || (!referenced_table && trx->check_foreigns)) {
3161 dict_foreign_free(foreign);
3163 mutex_enter(&dict_foreign_err_mutex);
3164 dict_foreign_error_report_low(ef, name);
3165 fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3166 "%s\n",
3167 start_of_latest_foreign, ptr);
3168 mutex_exit(&dict_foreign_err_mutex);
3170 return(DB_CANNOT_ADD_CONSTRAINT);
3173 ptr = dict_accept(cs, ptr, "(", &success);
3175 if (!success) {
3176 dict_foreign_free(foreign);
3177 dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3178 ptr);
3179 return(DB_CANNOT_ADD_CONSTRAINT);
3182 /* Scan the columns in the second list */
3183 i = 0;
3185 col_loop2:
3186 ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3187 heap, column_names + i);
3188 i++;
3190 if (!success) {
3191 dict_foreign_free(foreign);
3193 mutex_enter(&dict_foreign_err_mutex);
3194 dict_foreign_error_report_low(ef, name);
3195 fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3196 "%s\n",
3197 start_of_latest_foreign, ptr);
3198 mutex_exit(&dict_foreign_err_mutex);
3200 return(DB_CANNOT_ADD_CONSTRAINT);
3203 ptr = dict_accept(cs, ptr, ",", &success);
3205 if (success) {
3206 goto col_loop2;
3209 ptr = dict_accept(cs, ptr, ")", &success);
3211 if (!success || foreign->n_fields != i) {
3212 dict_foreign_free(foreign);
3214 dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3215 ptr);
3216 return(DB_CANNOT_ADD_CONSTRAINT);
3219 n_on_deletes = 0;
3220 n_on_updates = 0;
3222 scan_on_conditions:
3223 /* Loop here as long as we can find ON ... conditions */
3225 ptr = dict_accept(cs, ptr, "ON", &success);
3227 if (!success) {
3229 goto try_find_index;
3232 ptr = dict_accept(cs, ptr, "DELETE", &success);
3234 if (!success) {
3235 ptr = dict_accept(cs, ptr, "UPDATE", &success);
3237 if (!success) {
3238 dict_foreign_free(foreign);
3240 dict_foreign_report_syntax_err(
3241 name, start_of_latest_foreign, ptr);
3242 return(DB_CANNOT_ADD_CONSTRAINT);
3245 is_on_delete = FALSE;
3246 n_on_updates++;
3247 } else {
3248 is_on_delete = TRUE;
3249 n_on_deletes++;
3252 ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3254 if (success) {
3255 goto scan_on_conditions;
3258 ptr = dict_accept(cs, ptr, "CASCADE", &success);
3260 if (success) {
3261 if (is_on_delete) {
3262 foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3263 } else {
3264 foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3267 goto scan_on_conditions;
3270 ptr = dict_accept(cs, ptr, "NO", &success);
3272 if (success) {
3273 ptr = dict_accept(cs, ptr, "ACTION", &success);
3275 if (!success) {
3276 dict_foreign_free(foreign);
3277 dict_foreign_report_syntax_err(
3278 name, start_of_latest_foreign, ptr);
3280 return(DB_CANNOT_ADD_CONSTRAINT);
3283 if (is_on_delete) {
3284 foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3285 } else {
3286 foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3289 goto scan_on_conditions;
3292 ptr = dict_accept(cs, ptr, "SET", &success);
3294 if (!success) {
3295 dict_foreign_free(foreign);
3296 dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3297 ptr);
3298 return(DB_CANNOT_ADD_CONSTRAINT);
3301 ptr = dict_accept(cs, ptr, "NULL", &success);
3303 if (!success) {
3304 dict_foreign_free(foreign);
3305 dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3306 ptr);
3307 return(DB_CANNOT_ADD_CONSTRAINT);
3310 for (j = 0; j < foreign->n_fields; j++) {
3311 if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3312 & DATA_NOT_NULL) {
3314 /* It is not sensible to define SET NULL
3315 if the column is not allowed to be NULL! */
3317 dict_foreign_free(foreign);
3319 mutex_enter(&dict_foreign_err_mutex);
3320 dict_foreign_error_report_low(ef, name);
3321 fprintf(ef, "%s:\n"
3322 "You have defined a SET NULL condition"
3323 " though some of the\n"
3324 "columns are defined as NOT NULL.\n",
3325 start_of_latest_foreign);
3326 mutex_exit(&dict_foreign_err_mutex);
3328 return(DB_CANNOT_ADD_CONSTRAINT);
3332 if (is_on_delete) {
3333 foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3334 } else {
3335 foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3338 goto scan_on_conditions;
3340 try_find_index:
3341 if (n_on_deletes > 1 || n_on_updates > 1) {
3342 /* It is an error to define more than 1 action */
3344 dict_foreign_free(foreign);
3346 mutex_enter(&dict_foreign_err_mutex);
3347 dict_foreign_error_report_low(ef, name);
3348 fprintf(ef, "%s:\n"
3349 "You have twice an ON DELETE clause"
3350 " or twice an ON UPDATE clause.\n",
3351 start_of_latest_foreign);
3352 mutex_exit(&dict_foreign_err_mutex);
3354 return(DB_CANNOT_ADD_CONSTRAINT);
3357 /* Try to find an index which contains the columns as the first fields
3358 and in the right order, and the types are the same as in
3359 foreign->foreign_index */
3361 if (referenced_table) {
3362 index = dict_foreign_find_index(referenced_table,
3363 column_names, i,
3364 foreign->foreign_index,
3365 TRUE, FALSE);
3366 if (!index) {
3367 dict_foreign_free(foreign);
3368 mutex_enter(&dict_foreign_err_mutex);
3369 dict_foreign_error_report_low(ef, name);
3370 fprintf(ef, "%s:\n"
3371 "Cannot find an index in the"
3372 " referenced table where the\n"
3373 "referenced columns appear as the"
3374 " first columns, or column types\n"
3375 "in the table and the referenced table"
3376 " do not match for constraint.\n"
3377 "Note that the internal storage type of"
3378 " ENUM and SET changed in\n"
3379 "tables created with >= InnoDB-4.1.12,"
3380 " and such columns in old tables\n"
3381 "cannot be referenced by such columns"
3382 " in new tables.\n"
3383 "See http://dev.mysql.com/doc/refman/5.1/en/"
3384 "innodb-foreign-key-constraints.html\n"
3385 "for correct foreign key definition.\n",
3386 start_of_latest_foreign);
3387 mutex_exit(&dict_foreign_err_mutex);
3389 return(DB_CANNOT_ADD_CONSTRAINT);
3391 } else {
3392 ut_a(trx->check_foreigns == FALSE);
3393 index = NULL;
3396 foreign->referenced_index = index;
3397 foreign->referenced_table = referenced_table;
3399 foreign->referenced_table_name
3400 = mem_heap_strdup(foreign->heap, referenced_table_name);
3402 foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3403 i * sizeof(void*));
3404 for (i = 0; i < foreign->n_fields; i++) {
3405 foreign->referenced_col_names[i]
3406 = mem_heap_strdup(foreign->heap, column_names[i]);
3409 /* We found an ok constraint definition: add to the lists */
3411 UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3413 if (referenced_table) {
3414 UT_LIST_ADD_LAST(referenced_list,
3415 referenced_table->referenced_list,
3416 foreign);
3419 goto loop;
3422 /**************************************************************************
3423 Determines whether a string starts with the specified keyword. */
3425 ibool
3426 dict_str_starts_with_keyword(
3427 /*=========================*/
3428 /* out: TRUE if str starts
3429 with keyword */
3430 void* mysql_thd, /* in: MySQL thread handle */
3431 const char* str, /* in: string to scan for keyword */
3432 const char* keyword) /* in: keyword to look for */
3434 struct charset_info_st* cs = innobase_get_charset(mysql_thd);
3435 ibool success;
3437 dict_accept(cs, str, keyword, &success);
3438 return(success);
3441 /*************************************************************************
3442 Scans a table create SQL string and adds to the data dictionary the foreign
3443 key constraints declared in the string. This function should be called after
3444 the indexes for a table have been created. Each foreign key constraint must
3445 be accompanied with indexes in both participating tables. The indexes are
3446 allowed to contain more fields than mentioned in the constraint. */
3448 ulint
3449 dict_create_foreign_constraints(
3450 /*============================*/
3451 /* out: error code or DB_SUCCESS */
3452 trx_t* trx, /* in: transaction */
3453 const char* sql_string, /* in: table create statement where
3454 foreign keys are declared like:
3455 FOREIGN KEY (a, b) REFERENCES
3456 table2(c, d), table2 can be written
3457 also with the database
3458 name before it: test.table2; the
3459 default database id the database of
3460 parameter name */
3461 size_t sql_length, /* in: length of sql_string */
3462 const char* name, /* in: table full name in the
3463 normalized form
3464 database_name/table_name */
3465 ibool reject_fks) /* in: if TRUE, fail with error
3466 code DB_CANNOT_ADD_CONSTRAINT if
3467 any foreign keys are found. */
3469 char* str;
3470 ulint err;
3471 mem_heap_t* heap;
3473 ut_a(trx);
3474 ut_a(trx->mysql_thd);
3476 str = dict_strip_comments(sql_string, sql_length);
3477 heap = mem_heap_create(10000);
3479 err = dict_create_foreign_constraints_low(
3480 trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3481 reject_fks);
3483 mem_heap_free(heap);
3484 mem_free(str);
3486 return(err);
3489 /**************************************************************************
3490 Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3492 ulint
3493 dict_foreign_parse_drop_constraints(
3494 /*================================*/
3495 /* out: DB_SUCCESS or
3496 DB_CANNOT_DROP_CONSTRAINT if
3497 syntax error or the constraint
3498 id does not match */
3499 mem_heap_t* heap, /* in: heap from which we can
3500 allocate memory */
3501 trx_t* trx, /* in: transaction */
3502 dict_table_t* table, /* in: table */
3503 ulint* n, /* out: number of constraints
3504 to drop */
3505 const char*** constraints_to_drop) /* out: id's of the
3506 constraints to drop */
3508 dict_foreign_t* foreign;
3509 ibool success;
3510 char* str;
3511 const char* ptr;
3512 const char* id;
3513 FILE* ef = dict_foreign_err_file;
3514 struct charset_info_st* cs;
3516 ut_a(trx);
3517 ut_a(trx->mysql_thd);
3519 cs = innobase_get_charset(trx->mysql_thd);
3521 *n = 0;
3523 *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3525 str = dict_strip_comments(*trx->mysql_query_str,
3526 *trx->mysql_query_len);
3527 ptr = str;
3529 ut_ad(mutex_own(&(dict_sys->mutex)));
3530 loop:
3531 ptr = dict_scan_to(ptr, "DROP");
3533 if (*ptr == '\0') {
3534 mem_free(str);
3536 return(DB_SUCCESS);
3539 ptr = dict_accept(cs, ptr, "DROP", &success);
3541 if (!my_isspace(cs, *ptr)) {
3543 goto loop;
3546 ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3548 if (!success || !my_isspace(cs, *ptr)) {
3550 goto loop;
3553 ptr = dict_accept(cs, ptr, "KEY", &success);
3555 if (!success) {
3557 goto syntax_error;
3560 ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3562 if (id == NULL) {
3564 goto syntax_error;
3567 ut_a(*n < 1000);
3568 (*constraints_to_drop)[*n] = id;
3569 (*n)++;
3571 /* Look for the given constraint id */
3573 foreign = UT_LIST_GET_FIRST(table->foreign_list);
3575 while (foreign != NULL) {
3576 if (0 == strcmp(foreign->id, id)
3577 || (strchr(foreign->id, '/')
3578 && 0 == strcmp(id,
3579 dict_remove_db_name(foreign->id)))) {
3580 /* Found */
3581 break;
3584 foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3587 if (foreign == NULL) {
3588 mutex_enter(&dict_foreign_err_mutex);
3589 rewind(ef);
3590 ut_print_timestamp(ef);
3591 fputs(" Error in dropping of a foreign key constraint"
3592 " of table ", ef);
3593 ut_print_name(ef, NULL, TRUE, table->name);
3594 fputs(",\n"
3595 "in SQL command\n", ef);
3596 fputs(str, ef);
3597 fputs("\nCannot find a constraint with the given id ", ef);
3598 ut_print_name(ef, NULL, FALSE, id);
3599 fputs(".\n", ef);
3600 mutex_exit(&dict_foreign_err_mutex);
3602 mem_free(str);
3604 return(DB_CANNOT_DROP_CONSTRAINT);
3607 goto loop;
3609 syntax_error:
3610 mutex_enter(&dict_foreign_err_mutex);
3611 rewind(ef);
3612 ut_print_timestamp(ef);
3613 fputs(" Syntax error in dropping of a"
3614 " foreign key constraint of table ", ef);
3615 ut_print_name(ef, NULL, TRUE, table->name);
3616 fprintf(ef, ",\n"
3617 "close to:\n%s\n in SQL command\n%s\n", ptr, str);
3618 mutex_exit(&dict_foreign_err_mutex);
3620 mem_free(str);
3622 return(DB_CANNOT_DROP_CONSTRAINT);
3624 #endif /* UNIV_HOTBACKUP */
3626 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
3628 #ifdef UNIV_DEBUG
3629 /**************************************************************************
3630 Returns an index object if it is found in the dictionary cache. */
3632 dict_index_t*
3633 dict_index_get_if_in_cache(
3634 /*=======================*/
3635 /* out: index, NULL if not found */
3636 dulint index_id) /* in: index id */
3638 dict_index_t* index;
3640 if (dict_sys == NULL) {
3641 return(NULL);
3644 mutex_enter(&(dict_sys->mutex));
3646 index = dict_index_find_on_id_low(index_id);
3648 mutex_exit(&(dict_sys->mutex));
3650 return(index);
3652 #endif /* UNIV_DEBUG */
3654 #ifdef UNIV_DEBUG
3655 /**************************************************************************
3656 Checks that a tuple has n_fields_cmp value in a sensible range, so that
3657 no comparison can occur with the page number field in a node pointer. */
3659 ibool
3660 dict_index_check_search_tuple(
3661 /*==========================*/
3662 /* out: TRUE if ok */
3663 dict_index_t* index, /* in: index tree */
3664 dtuple_t* tuple) /* in: tuple used in a search */
3666 ut_a(index);
3667 ut_a(dtuple_get_n_fields_cmp(tuple)
3668 <= dict_index_get_n_unique_in_tree(index));
3669 return(TRUE);
3671 #endif /* UNIV_DEBUG */
3673 /**************************************************************************
3674 Builds a node pointer out of a physical record and a page number. */
3676 dtuple_t*
3677 dict_index_build_node_ptr(
3678 /*======================*/
3679 /* out, own: node pointer */
3680 dict_index_t* index, /* in: index tree */
3681 rec_t* rec, /* in: record for which to build node
3682 pointer */
3683 ulint page_no,/* in: page number to put in node pointer */
3684 mem_heap_t* heap, /* in: memory heap where pointer created */
3685 ulint level) /* in: level of rec in tree: 0 means leaf
3686 level */
3688 dtuple_t* tuple;
3689 dfield_t* field;
3690 byte* buf;
3691 ulint n_unique;
3693 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3694 /* In a universal index tree, we take the whole record as
3695 the node pointer if the record is on the leaf level,
3696 on non-leaf levels we remove the last field, which
3697 contains the page number of the child page */
3699 ut_a(!dict_table_is_comp(index->table));
3700 n_unique = rec_get_n_fields_old(rec);
3702 if (level > 0) {
3703 ut_a(n_unique > 1);
3704 n_unique--;
3706 } else {
3707 n_unique = dict_index_get_n_unique_in_tree(index);
3710 tuple = dtuple_create(heap, n_unique + 1);
3712 /* When searching in the tree for the node pointer, we must not do
3713 comparison on the last field, the page number field, as on upper
3714 levels in the tree there may be identical node pointers with a
3715 different page number; therefore, we set the n_fields_cmp to one
3716 less: */
3718 dtuple_set_n_fields_cmp(tuple, n_unique);
3720 dict_index_copy_types(tuple, index, n_unique);
3722 buf = mem_heap_alloc(heap, 4);
3724 mach_write_to_4(buf, page_no);
3726 field = dtuple_get_nth_field(tuple, n_unique);
3727 dfield_set_data(field, buf, 4);
3729 dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3731 rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3732 dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3733 | REC_STATUS_NODE_PTR);
3735 ut_ad(dtuple_check_typed(tuple));
3737 return(tuple);
3740 /**************************************************************************
3741 Copies an initial segment of a physical record, long enough to specify an
3742 index entry uniquely. */
3744 rec_t*
3745 dict_index_copy_rec_order_prefix(
3746 /*=============================*/
3747 /* out: pointer to the prefix record */
3748 dict_index_t* index, /* in: index tree */
3749 rec_t* rec, /* in: record for which to copy prefix */
3750 ulint* n_fields,/* out: number of fields copied */
3751 byte** buf, /* in/out: memory buffer for the copied prefix,
3752 or NULL */
3753 ulint* buf_size)/* in/out: buffer size */
3755 ulint n;
3757 UNIV_PREFETCH_R(rec);
3759 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3760 ut_a(!dict_table_is_comp(index->table));
3761 n = rec_get_n_fields_old(rec);
3762 } else {
3763 n = dict_index_get_n_unique_in_tree(index);
3766 *n_fields = n;
3767 return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
3770 /**************************************************************************
3771 Builds a typed data tuple out of a physical record. */
3773 dtuple_t*
3774 dict_index_build_data_tuple(
3775 /*========================*/
3776 /* out, own: data tuple */
3777 dict_index_t* index, /* in: index tree */
3778 rec_t* rec, /* in: record for which to build data tuple */
3779 ulint n_fields,/* in: number of data fields */
3780 mem_heap_t* heap) /* in: memory heap where tuple created */
3782 dtuple_t* tuple;
3784 ut_ad(dict_table_is_comp(index->table)
3785 || n_fields <= rec_get_n_fields_old(rec));
3787 tuple = dtuple_create(heap, n_fields);
3789 dict_index_copy_types(tuple, index, n_fields);
3791 rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
3793 ut_ad(dtuple_check_typed(tuple));
3795 return(tuple);
3798 /*************************************************************************
3799 Calculates the minimum record length in an index. */
3801 ulint
3802 dict_index_calc_min_rec_len(
3803 /*========================*/
3804 dict_index_t* index) /* in: index */
3806 ulint sum = 0;
3807 ulint i;
3809 if (dict_table_is_comp(index->table)) {
3810 ulint nullable = 0;
3811 sum = REC_N_NEW_EXTRA_BYTES;
3812 for (i = 0; i < dict_index_get_n_fields(index); i++) {
3813 const dict_col_t* col
3814 = dict_index_get_nth_col(index, i);
3815 ulint size = dict_col_get_fixed_size(col);
3816 sum += size;
3817 if (!size) {
3818 size = col->len;
3819 sum += size < 128 ? 1 : 2;
3821 if (!(col->prtype & DATA_NOT_NULL)) {
3822 nullable++;
3826 /* round the NULL flags up to full bytes */
3827 sum += UT_BITS_IN_BYTES(nullable);
3829 return(sum);
3832 for (i = 0; i < dict_index_get_n_fields(index); i++) {
3833 sum += dict_col_get_fixed_size(
3834 dict_index_get_nth_col(index, i));
3837 if (sum > 127) {
3838 sum += 2 * dict_index_get_n_fields(index);
3839 } else {
3840 sum += dict_index_get_n_fields(index);
3843 sum += REC_N_OLD_EXTRA_BYTES;
3845 return(sum);
3848 /*************************************************************************
3849 Calculates new estimates for table and index statistics. The statistics
3850 are used in query optimization. */
3852 void
3853 dict_update_statistics_low(
3854 /*=======================*/
3855 dict_table_t* table, /* in: table */
3856 ibool has_dict_mutex __attribute__((unused)))
3857 /* in: TRUE if the caller has the
3858 dictionary mutex */
3860 dict_index_t* index;
3861 ulint sum_of_index_sizes = 0;
3863 if (table->ibd_file_missing) {
3864 ut_print_timestamp(stderr);
3865 fprintf(stderr,
3866 " InnoDB: cannot calculate statistics for table %s\n"
3867 "InnoDB: because the .ibd file is missing. For help,"
3868 " please refer to\n"
3869 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3870 "innodb-troubleshooting.html\n",
3871 table->name);
3873 return;
3876 /* Find out the sizes of the indexes and how many different values
3877 for the key they approximately have */
3879 index = dict_table_get_first_index(table);
3881 if (index == NULL) {
3882 /* Table definition is corrupt */
3884 return;
3888 do {
3889 if (UNIV_LIKELY
3890 (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
3891 || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
3892 && (index->type & DICT_CLUSTERED)))) {
3893 ulint size;
3894 size = btr_get_size(index, BTR_TOTAL_SIZE);
3896 index->stat_index_size = size;
3898 sum_of_index_sizes += size;
3900 size = btr_get_size(index, BTR_N_LEAF_PAGES);
3902 if (size == 0) {
3903 /* The root node of the tree is a leaf */
3904 size = 1;
3907 index->stat_n_leaf_pages = size;
3909 btr_estimate_number_of_different_key_vals(index);
3910 } else {
3911 /* If we have set a high innodb_force_recovery
3912 level, do not calculate statistics, as a badly
3913 corrupted index can cause a crash in it.
3914 Initialize some bogus index cardinality
3915 statistics, so that the data can be queried in
3916 various means, also via secondary indexes. */
3917 ulint i;
3919 sum_of_index_sizes++;
3920 index->stat_index_size = index->stat_n_leaf_pages = 1;
3922 for (i = dict_index_get_n_unique(index); i; ) {
3923 index->stat_n_diff_key_vals[i--] = 1;
3926 memset(index->stat_n_non_null_key_vals, 0,
3927 (1 + dict_index_get_n_unique(index))
3928 * sizeof(*index->stat_n_non_null_key_vals));
3931 index = dict_table_get_next_index(index);
3932 } while (index);
3934 index = dict_table_get_first_index(table);
3936 table->stat_n_rows = index->stat_n_diff_key_vals[
3937 dict_index_get_n_unique(index)];
3939 table->stat_clustered_index_size = index->stat_index_size;
3941 table->stat_sum_of_other_index_sizes = sum_of_index_sizes
3942 - index->stat_index_size;
3944 table->stat_initialized = TRUE;
3946 table->stat_modified_counter = 0;
3949 /*************************************************************************
3950 Calculates new estimates for table and index statistics. The statistics
3951 are used in query optimization. */
3953 void
3954 dict_update_statistics(
3955 /*===================*/
3956 dict_table_t* table) /* in: table */
3958 dict_update_statistics_low(table, FALSE);
3961 /**************************************************************************
3962 A noninlined version of dict_table_get_low. */
3964 dict_table_t*
3965 dict_table_get_low_noninlined(
3966 /*==========================*/
3967 /* out: table, NULL if not found */
3968 const char* table_name) /* in: table name */
3970 return(dict_table_get_low(table_name));
3973 /**************************************************************************
3974 Prints info of a foreign key constraint. */
3975 static
3976 void
3977 dict_foreign_print_low(
3978 /*===================*/
3979 dict_foreign_t* foreign) /* in: foreign key constraint */
3981 ulint i;
3983 ut_ad(mutex_own(&(dict_sys->mutex)));
3985 fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
3986 foreign->id, foreign->foreign_table_name);
3988 for (i = 0; i < foreign->n_fields; i++) {
3989 fprintf(stderr, " %s", foreign->foreign_col_names[i]);
3992 fprintf(stderr, " )\n"
3993 " REFERENCES %s (",
3994 foreign->referenced_table_name);
3996 for (i = 0; i < foreign->n_fields; i++) {
3997 fprintf(stderr, " %s", foreign->referenced_col_names[i]);
4000 fputs(" )\n", stderr);
4003 /**************************************************************************
4004 Prints a table data. */
4006 void
4007 dict_table_print(
4008 /*=============*/
4009 dict_table_t* table) /* in: table */
4011 mutex_enter(&(dict_sys->mutex));
4012 dict_table_print_low(table);
4013 mutex_exit(&(dict_sys->mutex));
4016 /**************************************************************************
4017 Prints a table data when we know the table name. */
4019 void
4020 dict_table_print_by_name(
4021 /*=====================*/
4022 const char* name)
4024 dict_table_t* table;
4026 mutex_enter(&(dict_sys->mutex));
4028 table = dict_table_get_low(name);
4030 ut_a(table);
4032 dict_table_print_low(table);
4033 mutex_exit(&(dict_sys->mutex));
4036 /**************************************************************************
4037 Prints a table data. */
4039 void
4040 dict_table_print_low(
4041 /*=================*/
4042 dict_table_t* table) /* in: table */
4044 dict_index_t* index;
4045 dict_foreign_t* foreign;
4046 ulint i;
4048 ut_ad(mutex_own(&(dict_sys->mutex)));
4050 dict_update_statistics_low(table, TRUE);
4052 fprintf(stderr,
4053 "--------------------------------------\n"
4054 "TABLE: name %s, id %lu %lu, columns %lu, indexes %lu,"
4055 " appr.rows %lu\n"
4056 " COLUMNS: ",
4057 table->name,
4058 (ulong) ut_dulint_get_high(table->id),
4059 (ulong) ut_dulint_get_low(table->id),
4060 (ulong) table->n_cols,
4061 (ulong) UT_LIST_GET_LEN(table->indexes),
4062 (ulong) table->stat_n_rows);
4064 for (i = 0; i < (ulint) table->n_cols; i++) {
4065 dict_col_print_low(table, dict_table_get_nth_col(table, i));
4066 fputs("; ", stderr);
4069 putc('\n', stderr);
4071 index = UT_LIST_GET_FIRST(table->indexes);
4073 while (index != NULL) {
4074 dict_index_print_low(index);
4075 index = UT_LIST_GET_NEXT(indexes, index);
4078 foreign = UT_LIST_GET_FIRST(table->foreign_list);
4080 while (foreign != NULL) {
4081 dict_foreign_print_low(foreign);
4082 foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4085 foreign = UT_LIST_GET_FIRST(table->referenced_list);
4087 while (foreign != NULL) {
4088 dict_foreign_print_low(foreign);
4089 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
4093 /**************************************************************************
4094 Prints a column data. */
4095 static
4096 void
4097 dict_col_print_low(
4098 /*===============*/
4099 const dict_table_t* table, /* in: table */
4100 const dict_col_t* col) /* in: column */
4102 dtype_t type;
4104 ut_ad(mutex_own(&(dict_sys->mutex)));
4106 dict_col_copy_type(col, &type);
4107 fprintf(stderr, "%s: ", dict_table_get_col_name(table,
4108 dict_col_get_no(col)));
4110 dtype_print(&type);
4113 /**************************************************************************
4114 Prints an index data. */
4115 static
4116 void
4117 dict_index_print_low(
4118 /*=================*/
4119 dict_index_t* index) /* in: index */
4121 ib_longlong n_vals;
4122 ulint i;
4124 ut_ad(mutex_own(&(dict_sys->mutex)));
4126 if (index->n_user_defined_cols > 0) {
4127 n_vals = index->stat_n_diff_key_vals[
4128 index->n_user_defined_cols];
4129 } else {
4130 n_vals = index->stat_n_diff_key_vals[1];
4133 fprintf(stderr,
4134 " INDEX: name %s, id %lu %lu, fields %lu/%lu,"
4135 " uniq %lu, type %lu\n"
4136 " root page %lu, appr.key vals %lu,"
4137 " leaf pages %lu, size pages %lu\n"
4138 " FIELDS: ",
4139 index->name,
4140 (ulong) ut_dulint_get_high(index->id),
4141 (ulong) ut_dulint_get_low(index->id),
4142 (ulong) index->n_user_defined_cols,
4143 (ulong) index->n_fields,
4144 (ulong) index->n_uniq,
4145 (ulong) index->type,
4146 (ulong) index->page,
4147 (ulong) n_vals,
4148 (ulong) index->stat_n_leaf_pages,
4149 (ulong) index->stat_index_size);
4151 for (i = 0; i < index->n_fields; i++) {
4152 dict_field_print_low(dict_index_get_nth_field(index, i));
4155 putc('\n', stderr);
4157 #ifdef UNIV_BTR_PRINT
4158 btr_print_size(index);
4160 btr_print_index(index, 7);
4161 #endif /* UNIV_BTR_PRINT */
4164 /**************************************************************************
4165 Prints a field data. */
4166 static
4167 void
4168 dict_field_print_low(
4169 /*=================*/
4170 dict_field_t* field) /* in: field */
4172 ut_ad(mutex_own(&(dict_sys->mutex)));
4174 fprintf(stderr, " %s", field->name);
4176 if (field->prefix_len != 0) {
4177 fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4181 /**************************************************************************
4182 Outputs info on a foreign key of a table in a format suitable for
4183 CREATE TABLE. */
4185 void
4186 dict_print_info_on_foreign_key_in_create_format(
4187 /*============================================*/
4188 FILE* file, /* in: file where to print */
4189 trx_t* trx, /* in: transaction */
4190 dict_foreign_t* foreign, /* in: foreign key constraint */
4191 ibool add_newline) /* in: whether to add a newline */
4193 const char* stripped_id;
4194 ulint i;
4196 if (strchr(foreign->id, '/')) {
4197 /* Strip the preceding database name from the constraint id */
4198 stripped_id = foreign->id + 1
4199 + dict_get_db_name_len(foreign->id);
4200 } else {
4201 stripped_id = foreign->id;
4204 putc(',', file);
4206 if (add_newline) {
4207 /* SHOW CREATE TABLE wants constraints each printed nicely
4208 on its own line, while error messages want no newlines
4209 inserted. */
4210 fputs("\n ", file);
4213 fputs(" CONSTRAINT ", file);
4214 ut_print_name(file, trx, FALSE, stripped_id);
4215 fputs(" FOREIGN KEY (", file);
4217 for (i = 0;;) {
4218 ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4219 if (++i < foreign->n_fields) {
4220 fputs(", ", file);
4221 } else {
4222 break;
4226 fputs(") REFERENCES ", file);
4228 if (dict_tables_have_same_db(foreign->foreign_table_name,
4229 foreign->referenced_table_name)) {
4230 /* Do not print the database name of the referenced table */
4231 ut_print_name(file, trx, TRUE,
4232 dict_remove_db_name(
4233 foreign->referenced_table_name));
4234 } else {
4235 ut_print_name(file, trx, TRUE,
4236 foreign->referenced_table_name);
4239 putc(' ', file);
4240 putc('(', file);
4242 for (i = 0;;) {
4243 ut_print_name(file, trx, FALSE,
4244 foreign->referenced_col_names[i]);
4245 if (++i < foreign->n_fields) {
4246 fputs(", ", file);
4247 } else {
4248 break;
4252 putc(')', file);
4254 if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4255 fputs(" ON DELETE CASCADE", file);
4258 if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4259 fputs(" ON DELETE SET NULL", file);
4262 if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4263 fputs(" ON DELETE NO ACTION", file);
4266 if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4267 fputs(" ON UPDATE CASCADE", file);
4270 if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4271 fputs(" ON UPDATE SET NULL", file);
4274 if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4275 fputs(" ON UPDATE NO ACTION", file);
4279 /**************************************************************************
4280 Outputs info on foreign keys of a table. */
4282 void
4283 dict_print_info_on_foreign_keys(
4284 /*============================*/
4285 ibool create_table_format, /* in: if TRUE then print in
4286 a format suitable to be inserted into
4287 a CREATE TABLE, otherwise in the format
4288 of SHOW TABLE STATUS */
4289 FILE* file, /* in: file where to print */
4290 trx_t* trx, /* in: transaction */
4291 dict_table_t* table) /* in: table */
4293 dict_foreign_t* foreign;
4295 mutex_enter(&(dict_sys->mutex));
4297 foreign = UT_LIST_GET_FIRST(table->foreign_list);
4299 if (foreign == NULL) {
4300 mutex_exit(&(dict_sys->mutex));
4302 return;
4305 while (foreign != NULL) {
4306 if (create_table_format) {
4307 dict_print_info_on_foreign_key_in_create_format(
4308 file, trx, foreign, TRUE);
4309 } else {
4310 ulint i;
4311 fputs("; (", file);
4313 for (i = 0; i < foreign->n_fields; i++) {
4314 if (i) {
4315 putc(' ', file);
4318 ut_print_name(file, trx, FALSE,
4319 foreign->foreign_col_names[i]);
4322 fputs(") REFER ", file);
4323 ut_print_name(file, trx, TRUE,
4324 foreign->referenced_table_name);
4325 putc('(', file);
4327 for (i = 0; i < foreign->n_fields; i++) {
4328 if (i) {
4329 putc(' ', file);
4331 ut_print_name(
4332 file, trx, FALSE,
4333 foreign->referenced_col_names[i]);
4336 putc(')', file);
4338 if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4339 fputs(" ON DELETE CASCADE", file);
4342 if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4343 fputs(" ON DELETE SET NULL", file);
4346 if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4347 fputs(" ON DELETE NO ACTION", file);
4350 if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4351 fputs(" ON UPDATE CASCADE", file);
4354 if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4355 fputs(" ON UPDATE SET NULL", file);
4358 if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4359 fputs(" ON UPDATE NO ACTION", file);
4363 foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4366 mutex_exit(&(dict_sys->mutex));
4369 /************************************************************************
4370 Displays the names of the index and the table. */
4371 void
4372 dict_index_name_print(
4373 /*==================*/
4374 FILE* file, /* in: output stream */
4375 trx_t* trx, /* in: transaction */
4376 const dict_index_t* index) /* in: index to print */
4378 fputs("index ", file);
4379 ut_print_name(file, trx, FALSE, index->name);
4380 fputs(" of table ", file);
4381 ut_print_name(file, trx, TRUE, index->table_name);