1
/*****************************************************************************
3
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc.,
15
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
*****************************************************************************/
19
/******************************************************************//**
20
@file dict/dict0dict.c
21
Data dictionary system
23
Created 1/8/1996 Heikki Tuuri
24
***********************************************************************/
26
#include "dict0dict.h"
29
#include "dict0dict.ic"
32
/** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
33
UNIV_INTERN dict_index_t* dict_ind_redundant;
34
/** dummy index for ROW_FORMAT=COMPACT supremum and infimum records */
35
UNIV_INTERN dict_index_t* dict_ind_compact;
37
#ifndef UNIV_HOTBACKUP
39
#include "data0type.h"
40
#include "mach0data.h"
41
#include "dict0boot.h"
43
#include "dict0crea.h"
49
#include "page0page.h"
50
#include "pars0pars.h"
54
#include "row0merge.h"
55
#include "m_ctype.h" /* my_isspace() */
56
#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
58
#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
64
/** the dictionary system */
65
UNIV_INTERN dict_sys_t* dict_sys = NULL;
67
/** @brief the data dictionary rw-latch protecting dict_sys
69
table create, drop, etc. reserve this in X-mode; implicit or
70
backround operations purge, rollback, foreign key checks reserve this
71
in S-mode; we cannot trust that MySQL protects implicit or background
72
operations a table drop since MySQL does not know of them; therefore
73
we need this; NOTE: a transaction which reserves this must keep book
74
on the mode in trx_struct::dict_operation_lock_mode */
75
UNIV_INTERN rw_lock_t dict_operation_lock;
77
/* Keys to register rwlocks and mutexes with performance schema */
78
#ifdef UNIV_PFS_RWLOCK
79
UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key;
80
UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key;
81
UNIV_INTERN mysql_pfs_key_t dict_table_stats_latch_key;
82
#endif /* UNIV_PFS_RWLOCK */
85
UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key;
86
UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
87
#endif /* UNIV_PFS_MUTEX */
89
#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
90
creating a table or index object */
91
#define DICT_POOL_PER_TABLE_HASH 512 /*!< buffer pool max size per table
92
hash table fixed size in bytes */
93
#define DICT_POOL_PER_VARYING 4 /*!< buffer pool max size per data
94
dictionary varying size in bytes */
96
/** Identifies generated InnoDB foreign key names */
97
static char dict_ibfk[] = "_ibfk_";
99
/** array of rw locks protecting
100
dict_table_t::stat_initialized
101
dict_table_t::stat_n_rows (*)
102
dict_table_t::stat_clustered_index_size
103
dict_table_t::stat_sum_of_other_index_sizes
104
dict_table_t::stat_modified_counter (*)
105
dict_table_t::indexes*::stat_n_diff_key_vals[]
106
dict_table_t::indexes*::stat_index_size
107
dict_table_t::indexes*::stat_n_leaf_pages
108
(*) those are not always protected for performance reasons */
109
#define DICT_TABLE_STATS_LATCHES_SIZE 64
110
static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
112
/*******************************************************************//**
113
Tries to find column names for the index and sets the col field of the
115
@return TRUE if the column names were found */
118
dict_index_find_cols(
119
/*=================*/
120
dict_table_t* table, /*!< in: table */
121
dict_index_t* index); /*!< in: index */
122
/*******************************************************************//**
123
Builds the internal dictionary cache representation for a clustered
124
index, containing also system fields not defined by the user.
125
@return own: the internal representation of the clustered index */
128
dict_index_build_internal_clust(
129
/*============================*/
130
const dict_table_t* table, /*!< in: table */
131
dict_index_t* index); /*!< in: user representation of
133
/*******************************************************************//**
134
Builds the internal dictionary cache representation for a non-clustered
135
index, containing also system fields not defined by the user.
136
@return own: the internal representation of the non-clustered index */
139
dict_index_build_internal_non_clust(
140
/*================================*/
141
const dict_table_t* table, /*!< in: table */
142
dict_index_t* index); /*!< in: user representation of
143
a non-clustered index */
144
/**********************************************************************//**
145
Removes a foreign constraint struct from the dictionary cache. */
148
dict_foreign_remove_from_cache(
149
/*===========================*/
150
dict_foreign_t* foreign); /*!< in, own: foreign constraint */
151
/**********************************************************************//**
152
Prints a column data. */
157
const dict_table_t* table, /*!< in: table */
158
const dict_col_t* col); /*!< in: column */
159
/**********************************************************************//**
160
Prints an index data. */
163
dict_index_print_low(
164
/*=================*/
165
dict_index_t* index); /*!< in: index */
166
/**********************************************************************//**
167
Prints a field data. */
170
dict_field_print_low(
171
/*=================*/
172
const dict_field_t* field); /*!< in: field */
173
#ifndef UNIV_HOTBACKUP
174
/*********************************************************************//**
175
Frees a foreign key struct. */
180
dict_foreign_t* foreign); /*!< in, own: foreign key struct */
182
/* Stream for storing detailed information about the latest foreign key
183
and unique key errors */
184
UNIV_INTERN FILE* dict_foreign_err_file = NULL;
185
/* mutex protecting the foreign and unique error buffers */
186
UNIV_INTERN mutex_t dict_foreign_err_mutex;
187
#endif /* !UNIV_HOTBACKUP */
188
/******************************************************************//**
189
Makes all characters in a NUL-terminated UTF-8 string lower case. */
194
char* a) /*!< in/out: string to put in lower case */
196
innobase_casedn_str(a);
199
/********************************************************************//**
200
Checks if the database name in two table names is the same.
201
@return TRUE if same db name */
204
dict_tables_have_same_db(
205
/*=====================*/
206
const char* name1, /*!< in: table name in the form
207
dbname '/' tablename */
208
const char* name2) /*!< in: table name in the form
209
dbname '/' tablename */
211
for (; *name1 == *name2; name1++, name2++) {
215
ut_a(*name1); /* the names must contain '/' */
220
/********************************************************************//**
221
Return the end of table name where we have removed dbname and '/'.
222
@return table name */
227
const char* name) /*!< in: table name in the form
228
dbname '/' tablename */
230
const char* s = strchr(name, '/');
236
/********************************************************************//**
237
Get the database name length in a table name.
238
@return database name length */
241
dict_get_db_name_len(
242
/*=================*/
243
const char* name) /*!< in: table name in the form
244
dbname '/' tablename */
247
s = strchr(name, '/');
252
/********************************************************************//**
253
Reserves the dictionary system mutex for MySQL. */
256
dict_mutex_enter_for_mysql(void)
257
/*============================*/
259
mutex_enter(&(dict_sys->mutex));
262
/********************************************************************//**
263
Releases the dictionary system mutex for MySQL. */
266
dict_mutex_exit_for_mysql(void)
267
/*===========================*/
269
mutex_exit(&(dict_sys->mutex));
272
/** Get the latch that protects the stats of a given table */
273
#define GET_TABLE_STATS_LATCH(table) \
274
(&dict_table_stats_latches[ut_fold_ull(table->id) \
275
% DICT_TABLE_STATS_LATCHES_SIZE])
277
/**********************************************************************//**
278
Lock the appropriate latch to protect a given table's statistics.
279
table->id is used to pick the corresponding latch from a global array of
283
dict_table_stats_lock(
284
/*==================*/
285
const dict_table_t* table, /*!< in: table */
286
ulint latch_mode) /*!< in: RW_S_LATCH or
289
ut_ad(table != NULL);
290
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
292
switch (latch_mode) {
294
rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
297
rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
306
/**********************************************************************//**
307
Unlock the latch that has been locked by dict_table_stats_lock() */
310
dict_table_stats_unlock(
311
/*====================*/
312
const dict_table_t* table, /*!< in: table */
313
ulint latch_mode) /*!< in: RW_S_LATCH or
316
ut_ad(table != NULL);
317
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
319
switch (latch_mode) {
321
rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
324
rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
333
/********************************************************************//**
334
Decrements the count of open MySQL handles to a table. */
337
dict_table_decrement_handle_count(
338
/*==============================*/
339
dict_table_t* table, /*!< in/out: table */
340
ibool dict_locked) /*!< in: TRUE=data dictionary locked */
343
mutex_enter(&dict_sys->mutex);
346
ut_ad(mutex_own(&dict_sys->mutex));
347
ut_a(table->n_mysql_handles_opened > 0);
349
table->n_mysql_handles_opened--;
352
mutex_exit(&dict_sys->mutex);
355
#endif /* !UNIV_HOTBACKUP */
357
/**********************************************************************//**
358
Returns a column's name.
359
@return column name. NOTE: not guaranteed to stay valid if table is
360
modified in any way (columns added, etc.). */
363
dict_table_get_col_name(
364
/*====================*/
365
const dict_table_t* table, /*!< in: table */
366
ulint col_nr) /*!< in: column number */
372
ut_ad(col_nr < table->n_def);
373
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
375
s = table->col_names;
377
for (i = 0; i < col_nr; i++) {
385
#ifndef UNIV_HOTBACKUP
386
/********************************************************************//**
387
Acquire the autoinc lock. */
390
dict_table_autoinc_lock(
391
/*====================*/
392
dict_table_t* table) /*!< in/out: table */
394
mutex_enter(&table->autoinc_mutex);
397
/********************************************************************//**
398
Unconditionally set the autoinc counter. */
401
dict_table_autoinc_initialize(
402
/*==========================*/
403
dict_table_t* table, /*!< in/out: table */
404
ib_uint64_t value) /*!< in: next value to assign to a row */
406
ut_ad(mutex_own(&table->autoinc_mutex));
408
table->autoinc = value;
411
/********************************************************************//**
412
Reads the next autoinc value (== autoinc counter value), 0 if not yet
414
@return value for a new row, or 0 */
417
dict_table_autoinc_read(
418
/*====================*/
419
const dict_table_t* table) /*!< in: table */
421
ut_ad(mutex_own(&table->autoinc_mutex));
423
return(table->autoinc);
426
/********************************************************************//**
427
Updates the autoinc counter if the value supplied is greater than the
431
dict_table_autoinc_update_if_greater(
432
/*=================================*/
434
dict_table_t* table, /*!< in/out: table */
435
ib_uint64_t value) /*!< in: value which was assigned to a row */
437
ut_ad(mutex_own(&table->autoinc_mutex));
439
if (value > table->autoinc) {
441
table->autoinc = value;
445
/********************************************************************//**
446
Release the autoinc lock. */
449
dict_table_autoinc_unlock(
450
/*======================*/
451
dict_table_t* table) /*!< in/out: table */
453
mutex_exit(&table->autoinc_mutex);
456
/**********************************************************************//**
457
Looks for an index with the given table and index id.
458
NOTE that we do not reserve the dictionary mutex.
459
@return index or NULL if not found from cache */
462
dict_index_get_on_id_low(
463
/*=====================*/
464
dict_table_t* table, /*!< in: table */
465
index_id_t id) /*!< in: index id */
469
index = dict_table_get_first_index(table);
472
if (id == index->id) {
478
index = dict_table_get_next_index(index);
483
#endif /* !UNIV_HOTBACKUP */
485
/********************************************************************//**
486
Looks for column n in an index.
487
@return position in internal representation of the index;
488
ULINT_UNDEFINED if not contained */
491
dict_index_get_nth_col_or_prefix_pos(
492
/*=================================*/
493
const dict_index_t* index, /*!< in: index */
494
ulint n, /*!< in: column number */
495
ibool inc_prefix) /*!< in: TRUE=consider
496
column prefixes too */
498
const dict_field_t* field;
499
const dict_col_t* col;
504
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
506
col = dict_table_get_nth_col(index->table, n);
508
if (dict_index_is_clust(index)) {
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
519
&& (inc_prefix || field->prefix_len == 0)) {
525
return(ULINT_UNDEFINED);
528
/********************************************************************//**
529
Looks for column n in an index.
530
@return position in internal representation of the index;
531
ULINT_UNDEFINED if not contained */
534
dict_index_get_nth_col_pos(
535
/*=======================*/
536
const dict_index_t* index, /*!< in: index */
537
ulint n) /*!< in: column number */
539
return(dict_index_get_nth_col_or_prefix_pos(index, n, FALSE));
542
#ifndef UNIV_HOTBACKUP
543
/********************************************************************//**
544
Returns TRUE if the index contains a column or a prefix of that column.
545
@return TRUE if contains the column or its prefix */
548
dict_index_contains_col_or_prefix(
549
/*==============================*/
550
const dict_index_t* index, /*!< in: index */
551
ulint n) /*!< in: column number */
553
const dict_field_t* field;
554
const dict_col_t* col;
559
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
561
if (dict_index_is_clust(index)) {
566
col = dict_table_get_nth_col(index->table, n);
568
n_fields = dict_index_get_n_fields(index);
570
for (pos = 0; pos < n_fields; pos++) {
571
field = dict_index_get_nth_field(index, pos);
573
if (col == field->col) {
582
/********************************************************************//**
583
Looks for a matching field in an index. The column has to be the same. The
584
column in index must be complete, or must contain a prefix longer than the
585
column in index2. That is, we must be able to construct the prefix in index2
586
from the prefix in index.
587
@return position in internal representation of the index;
588
ULINT_UNDEFINED if not contained */
591
dict_index_get_nth_field_pos(
592
/*=========================*/
593
const dict_index_t* index, /*!< in: index from which to search */
594
const dict_index_t* index2, /*!< in: index */
595
ulint n) /*!< in: field number in index2 */
597
const dict_field_t* field;
598
const dict_field_t* field2;
603
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
605
field2 = dict_index_get_nth_field(index2, n);
607
n_fields = dict_index_get_n_fields(index);
609
for (pos = 0; pos < n_fields; pos++) {
610
field = dict_index_get_nth_field(index, pos);
612
if (field->col == field2->col
613
&& (field->prefix_len == 0
614
|| (field->prefix_len >= field2->prefix_len
615
&& field2->prefix_len != 0))) {
621
return(ULINT_UNDEFINED);
624
/**********************************************************************//**
625
Returns a table object based on table id.
626
@return table, NULL if does not exist */
629
dict_table_get_on_id(
630
/*=================*/
631
table_id_t table_id, /*!< in: table id */
632
trx_t* trx) /*!< in: transaction handle */
636
if (trx->dict_operation_lock_mode == RW_X_LATCH) {
638
/* Note: An X latch implies that the transaction
639
already owns the dictionary mutex. */
641
ut_ad(mutex_own(&dict_sys->mutex));
643
return(dict_table_get_on_id_low(table_id));
646
mutex_enter(&(dict_sys->mutex));
648
table = dict_table_get_on_id_low(table_id);
650
dict_table_LRU_trim(table);
652
mutex_exit(&(dict_sys->mutex));
657
/********************************************************************//**
658
Looks for column n position in the clustered index.
659
@return position in internal representation of the clustered index */
662
dict_table_get_nth_col_pos(
663
/*=======================*/
664
const dict_table_t* table, /*!< in: table */
665
ulint n) /*!< in: column number */
667
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
671
/********************************************************************//**
672
Checks if a column is in the ordering columns of the clustered index of a
673
table. Column prefixes are treated like whole columns.
674
@return TRUE if the column, or its prefix, is in the clustered key */
677
dict_table_col_in_clustered_key(
678
/*============================*/
679
const dict_table_t* table, /*!< in: table */
680
ulint n) /*!< in: column number */
682
const dict_index_t* index;
683
const dict_field_t* field;
684
const dict_col_t* col;
690
col = dict_table_get_nth_col(table, n);
692
index = dict_table_get_first_index(table);
694
n_fields = dict_index_get_n_unique(index);
696
for (pos = 0; pos < n_fields; pos++) {
697
field = dict_index_get_nth_field(index, pos);
699
if (col == field->col) {
708
/**********************************************************************//**
709
Inits the data dictionary module. */
717
dict_sys = mem_alloc(sizeof(dict_sys_t));
719
mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
721
dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
722
/ (DICT_POOL_PER_TABLE_HASH
724
dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
725
/ (DICT_POOL_PER_TABLE_HASH
729
UT_LIST_INIT(dict_sys->table_LRU);
731
rw_lock_create(dict_operation_lock_key,
732
&dict_operation_lock, SYNC_DICT_OPERATION);
734
dict_foreign_err_file = os_file_create_tmpfile();
735
ut_a(dict_foreign_err_file);
737
mutex_create(dict_foreign_err_mutex_key,
738
&dict_foreign_err_mutex, SYNC_ANY_LATCH);
740
for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
741
rw_lock_create(dict_table_stats_latch_key,
742
&dict_table_stats_latches[i], SYNC_INDEX_TREE);
746
/**********************************************************************//**
747
Returns a table object and optionally increment its MySQL open handle count.
748
NOTE! This is a high-level function to be used mainly from outside the
749
'dict' directory. Inside this directory dict_table_get_low is usually the
750
appropriate function.
751
@return table, NULL if does not exist */
756
const char* table_name, /*!< in: table name */
757
ibool inc_mysql_count)/*!< in: whether to increment the open
758
handle count on the table */
762
mutex_enter(&(dict_sys->mutex));
764
table = dict_table_get_low(table_name);
766
if (inc_mysql_count && table) {
767
table->n_mysql_handles_opened++;
770
dict_table_LRU_trim(table);
772
mutex_exit(&(dict_sys->mutex));
774
if (table != NULL && !table->is_corrupt) {
775
/* If table->ibd_file_missing == TRUE, this will
776
print an error message and return without doing
778
dict_update_statistics(
780
TRUE, /* only update stats if not initialized */
782
FALSE /* update even if not changed too much */);
787
#endif /* !UNIV_HOTBACKUP */
789
/**********************************************************************//**
790
Adds system columns to a table object. */
793
dict_table_add_system_columns(
794
/*==========================*/
795
dict_table_t* table, /*!< in/out: table */
796
mem_heap_t* heap) /*!< in: temporary heap */
799
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
800
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
801
ut_ad(!table->cached);
803
/* NOTE: the system columns MUST be added in the following order
804
(so that they can be indexed by the numerical value of DATA_ROW_ID,
805
etc.) and as the last columns of the table memory object.
806
The clustered index will not always physically contain all
809
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
810
DATA_ROW_ID | DATA_NOT_NULL,
813
#error "DATA_ROW_ID != 0"
815
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
816
DATA_TRX_ID | DATA_NOT_NULL,
819
#error "DATA_TRX_ID != 1"
821
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
822
DATA_ROLL_PTR | DATA_NOT_NULL,
824
#if DATA_ROLL_PTR != 2
825
#error "DATA_ROLL_PTR != 2"
828
/* This check reminds that if a new system column is added to
829
the program, it should be dealt with here */
830
#if DATA_N_SYS_COLS != 3
831
#error "DATA_N_SYS_COLS != 3"
835
#ifndef UNIV_HOTBACKUP
836
/**********************************************************************//**
837
Adds a table object to the dictionary cache. */
840
dict_table_add_to_cache(
841
/*====================*/
842
dict_table_t* table, /*!< in: table */
843
mem_heap_t* heap) /*!< in: temporary heap */
850
/* The lower limit for what we consider a "big" row */
851
#define BIG_ROW_SIZE 1024
853
ut_ad(mutex_own(&(dict_sys->mutex)));
855
dict_table_add_system_columns(table, heap);
857
table->cached = TRUE;
859
fold = ut_fold_string(table->name);
860
id_fold = ut_fold_ull(table->id);
863
for (i = 0; i < table->n_def; i++) {
864
ulint col_len = dict_col_get_max_size(
865
dict_table_get_nth_col(table, i));
869
/* If we have a single unbounded field, or several gigantic
870
fields, mark the maximum row size as BIG_ROW_SIZE. */
871
if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
872
row_len = BIG_ROW_SIZE;
878
table->big_rows = row_len >= BIG_ROW_SIZE;
880
/* Look for a table with the same name: error if such exists */
882
dict_table_t* table2;
883
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
884
dict_table_t*, table2, ut_ad(table2->cached),
885
ut_strcmp(table2->name, table->name) == 0);
886
ut_a(table2 == NULL);
889
/* Look for the same table pointer with a different name */
890
HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
891
dict_table_t*, table2, ut_ad(table2->cached),
893
ut_ad(table2 == NULL);
894
#endif /* UNIV_DEBUG */
897
/* Look for a table with the same id: error if such exists */
899
dict_table_t* table2;
900
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
901
dict_table_t*, table2, ut_ad(table2->cached),
902
table2->id == table->id);
903
ut_a(table2 == NULL);
906
/* Look for the same table pointer with a different id */
907
HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
908
dict_table_t*, table2, ut_ad(table2->cached),
910
ut_ad(table2 == NULL);
911
#endif /* UNIV_DEBUG */
914
/* Add table to hash table of tables */
915
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
918
/* Add table to hash table of tables based on table id */
919
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
921
/* Add table to LRU list of tables */
922
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
924
dict_sys->size += mem_heap_get_size(table->heap)
925
+ strlen(table->name) + 1;
928
/**********************************************************************//**
929
Looks for an index with the given id. NOTE that we do not reserve
930
the dictionary mutex: this function is for emergency purposes like
931
printing info of a corrupt database page!
932
@return index or NULL if not found from cache */
935
dict_index_find_on_id_low(
936
/*======================*/
937
index_id_t id) /*!< in: index id */
942
/* This can happen if the system tablespace is the wrong page size */
943
if (dict_sys == NULL) {
947
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
950
index = dict_table_get_first_index(table);
953
if (id == index->id) {
959
index = dict_table_get_next_index(index);
962
table = UT_LIST_GET_NEXT(table_LRU, table);
968
/**********************************************************************//**
969
Renames a table object.
970
@return TRUE if success */
973
dict_table_rename_in_cache(
974
/*=======================*/
975
dict_table_t* table, /*!< in/out: table */
976
const char* new_name, /*!< in: new name */
977
ibool rename_also_foreigns)/*!< in: in ALTER TABLE we want
978
to preserve the original table name
979
in constraints which reference it */
981
dict_foreign_t* foreign;
984
char old_name[MAX_FULL_NAME_LEN + 1];
987
ut_ad(mutex_own(&(dict_sys->mutex)));
989
/* store the old/current name to an automatic variable */
990
if (strlen(table->name) + 1 <= sizeof(old_name)) {
991
memcpy(old_name, table->name, strlen(table->name) + 1);
993
ut_print_timestamp(stderr);
994
fprintf(stderr, "InnoDB: too long table name: '%s', "
995
"max length is %d\n", table->name,
1000
fold = ut_fold_string(new_name);
1002
/* Look for a table with the same name: error if such exists */
1004
dict_table_t* table2;
1005
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
1006
dict_table_t*, table2, ut_ad(table2->cached),
1007
(ut_strcmp(table2->name, new_name) == 0));
1008
if (UNIV_LIKELY_NULL(table2)) {
1009
ut_print_timestamp(stderr);
1010
fputs(" InnoDB: Error: dictionary cache"
1011
" already contains a table ", stderr);
1012
ut_print_name(stderr, NULL, TRUE, new_name);
1014
"InnoDB: cannot rename table ", stderr);
1015
ut_print_name(stderr, NULL, TRUE, old_name);
1021
/* If the table is stored in a single-table tablespace, rename the
1024
if (table->space != 0) {
1025
if (table->dir_path_of_temp_table != NULL) {
1026
ut_print_timestamp(stderr);
1027
fputs(" InnoDB: Error: trying to rename a"
1028
" TEMPORARY TABLE ", stderr);
1029
ut_print_name(stderr, NULL, TRUE, old_name);
1030
fputs(" (", stderr);
1031
ut_print_filename(stderr,
1032
table->dir_path_of_temp_table);
1033
fputs(" )\n", stderr);
1035
} else if (!fil_rename_tablespace(old_name, table->space,
1041
/* Remove table from the hash tables of tables */
1042
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1043
ut_fold_string(old_name), table);
1045
if (strlen(new_name) > strlen(table->name)) {
1046
/* We allocate MAX_FULL_NAME_LEN + 1 bytes here to avoid
1047
memory fragmentation, we assume a repeated calls of
1048
ut_realloc() with the same size do not cause fragmentation */
1049
ut_a(strlen(new_name) <= MAX_FULL_NAME_LEN);
1050
table->name = ut_realloc(table->name, MAX_FULL_NAME_LEN + 1);
1052
memcpy(table->name, new_name, strlen(new_name) + 1);
1054
/* Add table to hash table of tables */
1055
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1058
dict_sys->size += strlen(new_name) - strlen(old_name);
1059
ut_a(dict_sys->size > 0);
1061
/* Update the table_name field in indexes */
1062
index = dict_table_get_first_index(table);
1064
while (index != NULL) {
1065
index->table_name = table->name;
1067
index = dict_table_get_next_index(index);
1070
if (!rename_also_foreigns) {
1071
/* In ALTER TABLE we think of the rename table operation
1072
in the direction table -> temporary table (#sql...)
1073
as dropping the table with the old name and creating
1074
a new with the new name. Thus we kind of drop the
1075
constraints from the dictionary cache here. The foreign key
1076
constraints will be inherited to the new table from the
1077
system tables through a call of dict_load_foreigns. */
1079
/* Remove the foreign constraints from the cache */
1080
foreign = UT_LIST_GET_LAST(table->foreign_list);
1082
while (foreign != NULL) {
1083
dict_foreign_remove_from_cache(foreign);
1084
foreign = UT_LIST_GET_LAST(table->foreign_list);
1087
/* Reset table field in referencing constraints */
1089
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1091
while (foreign != NULL) {
1092
foreign->referenced_table = NULL;
1093
foreign->referenced_index = NULL;
1095
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1098
/* Make the list of referencing constraints empty */
1100
UT_LIST_INIT(table->referenced_list);
1105
/* Update the table name fields in foreign constraints, and update also
1106
the constraint id of new format >= 4.0.18 constraints. Note that at
1107
this point we have already changed table->name to the new name. */
1109
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1111
while (foreign != NULL) {
1112
if (ut_strlen(foreign->foreign_table_name)
1113
< ut_strlen(table->name)) {
1114
/* Allocate a longer name buffer;
1115
TODO: store buf len to save memory */
1117
foreign->foreign_table_name = mem_heap_strdup(
1118
foreign->heap, table->name);
1119
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
1121
strcpy(foreign->foreign_table_name, table->name);
1122
dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
1124
if (strchr(foreign->id, '/')) {
1125
/* This is a >= 4.0.18 format id */
1129
char old_name_cs_filename[MAX_TABLE_NAME_LEN+20];
1132
/* All table names are internally stored in charset
1133
my_charset_filename (except the temp tables and the
1134
partition identifier suffix in partition tables). The
1135
foreign key constraint names are internally stored
1136
in UTF-8 charset. The variable fkid here is used
1137
to store foreign key constraint name in charset
1138
my_charset_filename for comparison further below. */
1139
char fkid[MAX_TABLE_NAME_LEN+20];
1140
ibool on_tmp = FALSE;
1142
/* The old table name in my_charset_filename is stored
1143
in old_name_cs_filename */
1145
strncpy(old_name_cs_filename, old_name,
1146
MAX_TABLE_NAME_LEN);
1147
if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) {
1149
innobase_convert_to_system_charset(
1150
strchr(old_name_cs_filename, '/') + 1,
1151
strchr(old_name, '/') + 1,
1152
MAX_TABLE_NAME_LEN, &errors);
1155
/* There has been an error to convert
1156
old table into UTF-8. This probably
1157
means that the old table name is
1158
actually in UTF-8. */
1159
innobase_convert_to_filename_charset(
1160
strchr(old_name_cs_filename,
1162
strchr(old_name, '/') + 1,
1163
MAX_TABLE_NAME_LEN);
1165
/* Old name already in
1166
my_charset_filename */
1167
strncpy(old_name_cs_filename, old_name,
1168
MAX_TABLE_NAME_LEN);
1172
strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
1174
if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) {
1175
innobase_convert_to_filename_charset(
1176
strchr(fkid, '/') + 1,
1177
strchr(foreign->id, '/') + 1,
1178
MAX_TABLE_NAME_LEN+20);
1183
old_id = mem_strdup(foreign->id);
1185
if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename)
1186
+ ((sizeof dict_ibfk) - 1)
1187
&& !memcmp(fkid, old_name_cs_filename,
1188
ut_strlen(old_name_cs_filename))
1189
&& !memcmp(fkid + ut_strlen(old_name_cs_filename),
1190
dict_ibfk, (sizeof dict_ibfk) - 1)) {
1192
/* This is a generated >= 4.0.18 format id */
1194
char table_name[MAX_TABLE_NAME_LEN] = "";
1197
if (strlen(table->name) > strlen(old_name)) {
1198
foreign->id = mem_heap_alloc(
1201
+ strlen(old_id) + 1);
1204
/* Convert the table name to UTF-8 */
1205
strncpy(table_name, table->name,
1206
MAX_TABLE_NAME_LEN);
1207
innobase_convert_to_system_charset(
1208
strchr(table_name, '/') + 1,
1209
strchr(table->name, '/') + 1,
1210
MAX_TABLE_NAME_LEN, &errors);
1213
/* Table name could not be converted
1214
from charset my_charset_filename to
1215
UTF-8. This means that the table name
1216
is already in UTF-8 (#mysql#50). */
1217
strncpy(table_name, table->name,
1218
MAX_TABLE_NAME_LEN);
1221
/* Replace the prefix 'databasename/tablename'
1222
with the new names */
1223
strcpy(foreign->id, table_name);
1226
old_id + ut_strlen(old_name));
1228
sprintf(strchr(foreign->id, '/') + 1,
1230
strchr(table_name, '/') +1,
1231
strstr(old_id, "_ibfk_") );
1235
/* This is a >= 4.0.18 format id where the user
1237
db_len = dict_get_db_name_len(table->name) + 1;
1239
if (dict_get_db_name_len(table->name)
1240
> dict_get_db_name_len(foreign->id)) {
1242
foreign->id = mem_heap_alloc(
1244
db_len + strlen(old_id) + 1);
1247
/* Replace the database prefix in id with the
1248
one from table->name */
1250
ut_memcpy(foreign->id, table->name, db_len);
1252
strcpy(foreign->id + db_len,
1253
dict_remove_db_name(old_id));
1259
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1262
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1264
while (foreign != NULL) {
1265
if (ut_strlen(foreign->referenced_table_name)
1266
< ut_strlen(table->name)) {
1267
/* Allocate a longer name buffer;
1268
TODO: store buf len to save memory */
1270
foreign->referenced_table_name = mem_heap_strdup(
1271
foreign->heap, table->name);
1272
dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
1274
/* Use the same buffer */
1275
strcpy(foreign->referenced_table_name, table->name);
1276
dict_mem_referenced_table_name_lookup_set(foreign, FALSE);
1278
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1284
/**********************************************************************//**
1285
Change the id of a table object in the dictionary cache. This is used in
1286
DISCARD TABLESPACE. */
1289
dict_table_change_id_in_cache(
1290
/*==========================*/
1291
dict_table_t* table, /*!< in/out: table object already in cache */
1292
table_id_t new_id) /*!< in: new id to set */
1295
ut_ad(mutex_own(&(dict_sys->mutex)));
1296
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1298
/* Remove the table from the hash table of id's */
1300
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1301
ut_fold_ull(table->id), table);
1304
/* Add the table back to the hash table */
1305
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1306
ut_fold_ull(table->id), table);
1309
/**********************************************************************//**
1310
Removes a table object from the dictionary cache. */
1313
dict_table_remove_from_cache(
1314
/*=========================*/
1315
dict_table_t* table) /*!< in, own: table */
1317
dict_foreign_t* foreign;
1318
dict_index_t* index;
1322
ut_ad(mutex_own(&(dict_sys->mutex)));
1323
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1326
fputs("Removing table ", stderr);
1327
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1328
fputs(" from dictionary cache\n", stderr);
1331
/* Remove the foreign constraints from the cache */
1332
foreign = UT_LIST_GET_LAST(table->foreign_list);
1334
while (foreign != NULL) {
1335
dict_foreign_remove_from_cache(foreign);
1336
foreign = UT_LIST_GET_LAST(table->foreign_list);
1339
/* Reset table field in referencing constraints */
1341
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1343
while (foreign != NULL) {
1344
foreign->referenced_table = NULL;
1345
foreign->referenced_index = NULL;
1347
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1350
/* Remove the indexes from the cache */
1351
index = UT_LIST_GET_LAST(table->indexes);
1353
while (index != NULL) {
1354
dict_index_remove_from_cache(table, index);
1355
index = UT_LIST_GET_LAST(table->indexes);
1358
/* Remove table from the hash tables of tables */
1359
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1360
ut_fold_string(table->name), table);
1361
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1362
ut_fold_ull(table->id), table);
1364
/* Remove table from LRU list of tables */
1365
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1367
size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
1369
ut_ad(dict_sys->size >= size);
1371
dict_sys->size -= size;
1373
dict_mem_table_free(table);
1376
/**************************************************************************
1377
Frees tables from the end of table_LRU if the dictionary cache occupies
1381
dict_table_LRU_trim(
1382
/*================*/
1385
dict_table_t* table;
1386
dict_table_t* prev_table;
1387
dict_foreign_t* foreign;
1389
ulint n_have_parent;
1390
ulint cached_foreign_tables;
1392
#ifdef UNIV_SYNC_DEBUG
1393
ut_ad(mutex_own(&(dict_sys->mutex)));
1394
#endif /* UNIV_SYNC_DEBUG */
1397
n_removed = n_have_parent = 0;
1398
table = UT_LIST_GET_LAST(dict_sys->table_LRU);
1400
while ( srv_dict_size_limit && table
1401
&& ((dict_sys->table_hash->n_cells
1402
+ dict_sys->table_id_hash->n_cells) * sizeof(hash_cell_t)
1403
+ dict_sys->size) > srv_dict_size_limit ) {
1404
prev_table = UT_LIST_GET_PREV(table_LRU, table);
1406
if (table == self || table->n_mysql_handles_opened || table->is_corrupt)
1409
cached_foreign_tables = 0;
1410
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1411
while (foreign != NULL) {
1412
if (foreign->referenced_table)
1413
cached_foreign_tables++;
1414
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1417
if (cached_foreign_tables == 0) {
1418
dict_table_remove_from_cache(table);
1427
if ( srv_dict_size_limit && n_have_parent && n_removed
1428
&& ((dict_sys->table_hash->n_cells
1429
+ dict_sys->table_id_hash->n_cells) * sizeof(hash_cell_t)
1430
+ dict_sys->size) > srv_dict_size_limit )
1434
/****************************************************************//**
1435
If the given column name is reserved for InnoDB system columns, return
1437
@return TRUE if name is reserved */
1440
dict_col_name_is_reserved(
1441
/*======================*/
1442
const char* name) /*!< in: column name */
1444
/* This check reminds that if a new system column is added to
1445
the program, it should be dealt with here. */
1446
#if DATA_N_SYS_COLS != 3
1447
#error "DATA_N_SYS_COLS != 3"
1450
static const char* reserved_names[] = {
1451
"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1456
for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1457
if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1466
/****************************************************************//**
1467
If an undo log record for this table might not fit on a single page,
1469
@return TRUE if the undo log record could become too big */
1472
dict_index_too_big_for_undo(
1473
/*========================*/
1474
const dict_table_t* table, /*!< in: table */
1475
const dict_index_t* new_index) /*!< in: index */
1477
/* Make sure that all column prefixes will fit in the undo log record
1478
in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1481
const dict_index_t* clust_index
1482
= dict_table_get_first_index(table);
1484
= TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
1485
+ 2 /* next record pointer */
1487
+ 11 /* trx->undo_no */ + 11 /* table->id */
1488
+ 1 /* rec_get_info_bits() */
1489
+ 11 /* DB_TRX_ID */
1490
+ 11 /* DB_ROLL_PTR */
1491
+ 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
1492
+ 2/* pointer to previous undo log record */;
1494
if (UNIV_UNLIKELY(!clust_index)) {
1495
ut_a(dict_index_is_clust(new_index));
1496
clust_index = new_index;
1499
/* Add the size of the ordering columns in the
1501
for (i = 0; i < clust_index->n_uniq; i++) {
1502
const dict_col_t* col
1503
= dict_index_get_nth_col(clust_index, i);
1505
/* Use the maximum output size of
1506
mach_write_compressed(), although the encoded
1507
length should always fit in 2 bytes. */
1508
undo_page_len += 5 + dict_col_get_max_size(col);
1511
/* Add the old values of the columns to be updated.
1512
First, the amount and the numbers of the columns.
1513
These are written by mach_write_compressed() whose
1514
maximum output length is 5 bytes. However, given that
1515
the quantities are below REC_MAX_N_FIELDS (10 bits),
1516
the maximum length is 2 bytes per item. */
1517
undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
1519
for (i = 0; i < clust_index->n_def; i++) {
1520
const dict_col_t* col
1521
= dict_index_get_nth_col(clust_index, i);
1523
= dict_col_get_max_size(col);
1525
= dict_col_get_fixed_size(col,
1526
dict_table_is_comp(table));
1531
/* Fixed-size columns are stored locally. */
1532
max_size = fixed_size;
1533
} else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
1534
/* Short columns are stored locally. */
1535
} else if (!col->ord_part
1537
< (ulint) DICT_MAX_FIELD_LEN_BY_FORMAT(table))) {
1538
/* See if col->ord_part would be set
1539
because of new_index. Also check if the new
1540
index could have longer prefix on columns
1541
that already had ord_part set */
1544
for (j = 0; j < new_index->n_uniq; j++) {
1545
if (dict_index_get_nth_col(
1546
new_index, j) == col) {
1547
const dict_field_t* field
1548
= dict_index_get_nth_field(
1551
if (field->prefix_len
1552
> col->max_prefix) {
1561
if (col->ord_part) {
1565
/* This is not an ordering column in any index.
1566
Thus, it can be stored completely externally. */
1567
max_size = BTR_EXTERN_FIELD_REF_SIZE;
1569
ulint max_field_len;
1571
max_field_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
1573
/* This is an ordering column in some index.
1574
A long enough prefix must be written to the
1575
undo log. See trx_undo_page_fetch_ext(). */
1576
max_size = ut_min(max_size, max_field_len);
1578
/* We only store the needed prefix length in undo log */
1580
ut_ad(dict_table_get_format(table)
1581
>= DICT_TF_FORMAT_ZIP);
1583
max_size = ut_min(max_prefix, max_size);
1586
max_size += BTR_EXTERN_FIELD_REF_SIZE;
1589
undo_page_len += 5 + max_size;
1592
return(undo_page_len >= UNIV_PAGE_SIZE);
1595
/****************************************************************//**
1596
If a record of this index might not fit on a single B-tree page,
1598
@return TRUE if the index record could become too big */
1601
dict_index_too_big_for_tree(
1602
/*========================*/
1603
const dict_table_t* table, /*!< in: table */
1604
const dict_index_t* new_index) /*!< in: index */
1609
/* maximum possible storage size of a record */
1611
/* maximum allowed size of a record on a leaf page */
1613
/* maximum allowed size of a node pointer record */
1617
"ib_force_create_table",
1620
comp = dict_table_is_comp(table);
1621
zip_size = dict_table_zip_size(table);
1623
if (zip_size && zip_size < UNIV_PAGE_SIZE) {
1624
/* On a compressed page, two records must fit in the
1625
uncompressed page modification log. On compressed
1626
pages with zip_size == UNIV_PAGE_SIZE, this limit will
1627
never be reached. */
1629
/* The maximum allowed record size is the size of
1630
an empty page, minus a byte for recoding the heap
1631
number in the page modification log. The maximum
1632
allowed node pointer size is half that. */
1633
page_rec_max = page_zip_empty_size(new_index->n_fields,
1638
page_ptr_max = page_rec_max / 2;
1639
/* On a compressed page, there is a two-byte entry in
1640
the dense page directory for every record. But there
1641
is no record header. */
1644
/* The maximum allowed record size is half a B-tree
1645
page. No additional sparse page directory entry will
1646
be generated for the first few user records. */
1647
page_rec_max = page_get_free_space_of_empty(comp) / 2;
1648
page_ptr_max = page_rec_max;
1649
/* Each record has a header. */
1651
? REC_N_NEW_EXTRA_BYTES
1652
: REC_N_OLD_EXTRA_BYTES;
1656
/* Include the "null" flags in the
1657
maximum possible record size. */
1658
rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
1660
/* For each column, include a 2-byte offset and a
1661
"null" flag. The 1-byte format is only used in short
1662
records that do not contain externally stored columns.
1663
Such records could never exceed the page limit, even
1664
when using the 2-byte format. */
1665
rec_max_size += 2 * new_index->n_fields;
1668
/* Compute the maximum possible record size. */
1669
for (i = 0; i < new_index->n_fields; i++) {
1670
const dict_field_t* field
1671
= dict_index_get_nth_field(new_index, i);
1672
const dict_col_t* col
1673
= dict_field_get_col(field);
1674
ulint field_max_size;
1675
ulint field_ext_max_size;
1677
/* In dtuple_convert_big_rec(), variable-length columns
1678
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1679
may be chosen for external storage.
1681
Fixed-length columns, and all columns of secondary
1682
index records are always stored inline. */
1684
/* Determine the maximum length of the index field.
1685
The field_ext_max_size should be computed as the worst
1686
case in rec_get_converted_size_comp() for
1687
REC_STATUS_ORDINARY records. */
1689
field_max_size = dict_col_get_fixed_size(col, comp);
1690
if (field_max_size) {
1691
/* dict_index_add_col() should guarantee this */
1692
ut_ad(!field->prefix_len
1693
|| field->fixed_len == field->prefix_len);
1694
/* Fixed lengths are not encoded
1695
in ROW_FORMAT=COMPACT. */
1696
field_ext_max_size = 0;
1697
goto add_field_size;
1700
field_max_size = dict_col_get_max_size(col);
1701
field_ext_max_size = field_max_size < 256 ? 1 : 2;
1703
if (field->prefix_len) {
1704
if (field->prefix_len < field_max_size) {
1705
field_max_size = field->prefix_len;
1707
} else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
1708
&& dict_index_is_clust(new_index)) {
1710
/* In the worst case, we have a locally stored
1711
column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
1712
The length can be stored in one byte. If the
1713
column were stored externally, the lengths in
1714
the clustered index page would be
1715
BTR_EXTERN_FIELD_REF_SIZE and 2. */
1716
field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
1717
field_ext_max_size = 1;
1721
/* Add the extra size for ROW_FORMAT=COMPACT.
1722
For ROW_FORMAT=REDUNDANT, these bytes were
1723
added to rec_max_size before this loop. */
1724
rec_max_size += field_ext_max_size;
1727
rec_max_size += field_max_size;
1729
/* Check the size limit on leaf pages. */
1730
if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
1735
/* Check the size limit on non-leaf pages. Records
1736
stored in non-leaf B-tree pages consist of the unique
1737
columns of the record (the key columns of the B-tree)
1738
and a node pointer field. When we have processed the
1739
unique columns, rec_max_size equals the size of the
1740
node pointer record minus the node pointer column. */
1741
if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
1742
&& rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
1751
/**********************************************************************//**
1752
Adds an index to the dictionary cache.
1753
@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
1756
dict_index_add_to_cache(
1757
/*====================*/
1758
dict_table_t* table, /*!< in: table on which the index is */
1759
dict_index_t* index, /*!< in, own: index; NOTE! The index memory
1760
object is freed in this function! */
1761
ulint page_no,/*!< in: root page number of the index */
1762
ibool strict) /*!< in: TRUE=refuse to create the index
1763
if records could be too big to fit in
1766
dict_index_t* new_index;
1771
ut_ad(mutex_own(&(dict_sys->mutex)));
1772
ut_ad(index->n_def == index->n_fields);
1773
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1775
ut_ad(mem_heap_validate(index->heap));
1776
ut_a(!dict_index_is_clust(index)
1777
|| UT_LIST_GET_LEN(table->indexes) == 0);
1779
if (!dict_index_find_cols(table, index)) {
1781
dict_mem_index_free(index);
1782
return(DB_CORRUPTION);
1785
/* Build the cache internal representation of the index,
1786
containing also the added system fields */
1788
if (dict_index_is_clust(index)) {
1789
new_index = dict_index_build_internal_clust(table, index);
1791
new_index = dict_index_build_internal_non_clust(table, index);
1794
/* Set the n_fields value in new_index to the actual defined
1795
number of fields in the cache internal representation */
1797
new_index->n_fields = new_index->n_def;
1799
if (strict && dict_index_too_big_for_tree(table, new_index)) {
1801
dict_mem_index_free(new_index);
1802
dict_mem_index_free(index);
1803
return(DB_TOO_BIG_RECORD);
1806
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1807
n_ord = new_index->n_fields;
1809
n_ord = new_index->n_uniq;
1812
switch (dict_table_get_format(table)) {
1813
case DICT_TF_FORMAT_51:
1814
/* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
1815
prefixes of externally stored columns locally within
1816
the record. There are no special considerations for
1817
the undo log record size. */
1820
case DICT_TF_FORMAT_ZIP:
1821
/* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
1822
column prefix indexes require that prefixes of
1823
externally stored columns are written to the undo log.
1824
This may make the undo log record bigger than the
1825
record on the B-tree page. The maximum size of an
1826
undo log record is the page size. That must be
1827
checked for below. */
1830
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
1831
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
1835
for (i = 0; i < n_ord; i++) {
1836
const dict_field_t* field
1837
= dict_index_get_nth_field(new_index, i);
1838
const dict_col_t* col
1839
= dict_field_get_col(field);
1841
/* In dtuple_convert_big_rec(), variable-length columns
1842
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1843
may be chosen for external storage. If the column appears
1844
in an ordering column of an index, a longer prefix determined
1845
by dict_max_field_len_store_undo() will be copied to the undo
1846
log by trx_undo_page_report_modify() and
1847
trx_undo_page_fetch_ext(). It suffices to check the
1848
capacity of the undo log whenever new_index includes
1849
a column prefix on a column that may be stored externally. */
1851
if (field->prefix_len /* prefix index */
1852
&& (!col->ord_part /* not yet ordering column */
1853
|| field->prefix_len > col->max_prefix)
1854
&& !dict_col_get_fixed_size(col, TRUE) /* variable-length */
1855
&& dict_col_get_max_size(col)
1856
> BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
1858
if (dict_index_too_big_for_undo(table, new_index)) {
1859
/* An undo log record might not fit in
1860
a single page. Refuse to create this index. */
1870
/* Flag the ordering columns and also set column max_prefix */
1872
for (i = 0; i < n_ord; i++) {
1873
const dict_field_t* field
1874
= dict_index_get_nth_field(new_index, i);
1876
field->col->ord_part = 1;
1878
if (field->prefix_len > field->col->max_prefix) {
1879
field->col->max_prefix = field->prefix_len;
1883
/* Add the new index as the last index for the table */
1885
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1886
new_index->table = table;
1887
new_index->table_name = table->name;
1889
new_index->search_info = btr_search_info_create(new_index->heap);
1891
new_index->stat_index_size = 1;
1892
new_index->stat_n_leaf_pages = 1;
1894
new_index->page = page_no;
1895
rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
1896
dict_index_is_ibuf(index)
1897
? SYNC_IBUF_INDEX_TREE : SYNC_INDEX_TREE);
1899
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1901
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1903
(1 + dict_index_get_n_unique(new_index))
1904
* sizeof(ib_int64_t));
1906
new_index->stat_n_non_null_key_vals = mem_heap_zalloc(
1908
(1 + dict_index_get_n_unique(new_index))
1909
* sizeof(*new_index->stat_n_non_null_key_vals));
1911
/* Give some sensible values to stat_n_... in case we do
1912
not calculate statistics quickly enough */
1914
for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1916
new_index->stat_n_diff_key_vals[i] = 100;
1920
dict_sys->size += mem_heap_get_size(new_index->heap);
1922
dict_mem_index_free(index);
1927
/**********************************************************************//**
1928
Removes an index from the dictionary cache. */
1931
dict_index_remove_from_cache(
1932
/*=========================*/
1933
dict_table_t* table, /*!< in/out: table */
1934
dict_index_t* index) /*!< in, own: index */
1940
ut_ad(table && index);
1941
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1942
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1943
ut_ad(mutex_own(&(dict_sys->mutex)));
1945
/* remove all entry of the index from adaptive hash index,
1946
because removing from adaptive hash index needs dict_index */
1947
if (btr_search_enabled && srv_dict_size_limit)
1948
btr_search_drop_page_hash_index_on_index(index);
1950
/* We always create search info whether or not adaptive
1951
hash index is enabled or not. */
1952
info = index->search_info;
1955
/* We are not allowed to free the in-memory index struct
1956
dict_index_t until all entries in the adaptive hash index
1957
that point to any of the page belonging to his b-tree index
1958
are dropped. This is so because dropping of these entries
1959
require access to dict_index_t struct. To avoid such scenario
1960
We keep a count of number of such pages in the search_info and
1961
only free the dict_index_t struct when this count drops to
1965
ulint ref_count = btr_search_info_get_ref_count(info, index->id);
1966
if (ref_count == 0) {
1970
/* Sleep for 10ms before trying again. */
1971
os_thread_sleep(10000);
1974
if (retries % 500 == 0) {
1975
/* No luck after 5 seconds of wait. */
1976
fprintf(stderr, "InnoDB: Error: Waited for"
1977
" %lu secs for hash index"
1978
" ref_count (%lu) to drop"
1988
/* To avoid a hang here we commit suicide if the
1989
ref_count doesn't drop to zero in 600 seconds. */
1990
if (retries >= 60000) {
1995
rw_lock_free(&index->lock);
1997
/* Remove the index from the list of indexes of the table */
1998
UT_LIST_REMOVE(indexes, table->indexes, index);
2000
size = mem_heap_get_size(index->heap);
2002
ut_ad(dict_sys->size >= size);
2004
dict_sys->size -= size;
2006
dict_mem_index_free(index);
2009
/*******************************************************************//**
2010
Tries to find column names for the index and sets the col field of the
2012
@return TRUE if the column names were found */
2015
dict_index_find_cols(
2016
/*=================*/
2017
dict_table_t* table, /*!< in: table */
2018
dict_index_t* index) /*!< in: index */
2022
ut_ad(table && index);
2023
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2024
ut_ad(mutex_own(&(dict_sys->mutex)));
2026
for (i = 0; i < index->n_fields; i++) {
2028
dict_field_t* field = dict_index_get_nth_field(index, i);
2030
for (j = 0; j < table->n_cols; j++) {
2031
if (!strcmp(dict_table_get_col_name(table, j),
2033
field->col = dict_table_get_nth_col(table, j);
2040
/* It is an error not to find a matching column. */
2041
fputs("InnoDB: Error: no matching column for ", stderr);
2042
ut_print_name(stderr, NULL, FALSE, field->name);
2043
fputs(" in ", stderr);
2044
dict_index_name_print(stderr, NULL, index);
2045
fputs("!\n", stderr);
2046
#endif /* UNIV_DEBUG */
2055
#endif /* !UNIV_HOTBACKUP */
2057
/*******************************************************************//**
2058
Adds a column to index. */
2063
dict_index_t* index, /*!< in/out: index */
2064
const dict_table_t* table, /*!< in: table */
2065
dict_col_t* col, /*!< in: column */
2066
ulint prefix_len) /*!< in: column prefix length */
2068
dict_field_t* field;
2069
const char* col_name;
2071
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
2073
dict_mem_index_add_field(index, col_name, prefix_len);
2075
field = dict_index_get_nth_field(index, index->n_def - 1);
2078
field->fixed_len = (unsigned int) dict_col_get_fixed_size(
2079
col, dict_table_is_comp(table));
2081
if (prefix_len && field->fixed_len > prefix_len) {
2082
field->fixed_len = (unsigned int) prefix_len;
2085
/* Long fixed-length fields that need external storage are treated as
2086
variable-length fields, so that the extern flag can be embedded in
2089
if (field->fixed_len > DICT_MAX_FIXED_COL_LEN) {
2090
field->fixed_len = 0;
2092
#if DICT_MAX_FIXED_COL_LEN != 768
2093
/* The comparison limit above must be constant. If it were
2094
changed, the disk format of some fixed-length columns would
2095
change, which would be a disaster. */
2096
# error "DICT_MAX_FIXED_COL_LEN != 768"
2099
if (!(col->prtype & DATA_NOT_NULL)) {
2100
index->n_nullable++;
2104
#ifndef UNIV_HOTBACKUP
2105
/*******************************************************************//**
2106
Copies fields contained in index2 to index1. */
2111
dict_index_t* index1, /*!< in: index to copy to */
2112
dict_index_t* index2, /*!< in: index to copy from */
2113
const dict_table_t* table, /*!< in: table */
2114
ulint start, /*!< in: first position to copy */
2115
ulint end) /*!< in: last position to copy */
2117
dict_field_t* field;
2120
/* Copy fields contained in index2 */
2122
for (i = start; i < end; i++) {
2124
field = dict_index_get_nth_field(index2, i);
2125
dict_index_add_col(index1, table, field->col,
2130
/*******************************************************************//**
2131
Copies types of fields contained in index to tuple. */
2134
dict_index_copy_types(
2135
/*==================*/
2136
dtuple_t* tuple, /*!< in/out: data tuple */
2137
const dict_index_t* index, /*!< in: index */
2138
ulint n_fields) /*!< in: number of
2139
field types to copy */
2143
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
2144
dtuple_set_types_binary(tuple, n_fields);
2149
for (i = 0; i < n_fields; i++) {
2150
const dict_field_t* ifield;
2151
dtype_t* dfield_type;
2153
ifield = dict_index_get_nth_field(index, i);
2154
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
2155
dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
2159
/*******************************************************************//**
2160
Copies types of columns contained in table to tuple and sets all
2161
fields of the tuple to the SQL NULL value. This function should
2162
be called right after dtuple_create(). */
2165
dict_table_copy_types(
2166
/*==================*/
2167
dtuple_t* tuple, /*!< in/out: data tuple */
2168
const dict_table_t* table) /*!< in: table */
2172
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
2174
dfield_t* dfield = dtuple_get_nth_field(tuple, i);
2175
dtype_t* dtype = dfield_get_type(dfield);
2177
dfield_set_null(dfield);
2178
dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
2182
/*******************************************************************//**
2183
Builds the internal dictionary cache representation for a clustered
2184
index, containing also system fields not defined by the user.
2185
@return own: the internal representation of the clustered index */
2188
dict_index_build_internal_clust(
2189
/*============================*/
2190
const dict_table_t* table, /*!< in: table */
2191
dict_index_t* index) /*!< in: user representation of
2192
a clustered index */
2194
dict_index_t* new_index;
2195
dict_field_t* field;
2200
ut_ad(table && index);
2201
ut_ad(dict_index_is_clust(index));
2202
ut_ad(mutex_own(&(dict_sys->mutex)));
2203
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2205
/* Create a new index object with certainly enough fields */
2206
new_index = dict_mem_index_create(table->name,
2207
index->name, table->space,
2209
index->n_fields + table->n_cols);
2211
/* Copy other relevant data from the old index struct to the new
2212
struct: it inherits the values */
2214
new_index->n_user_defined_cols = index->n_fields;
2216
new_index->id = index->id;
2218
/* Copy the fields of index */
2219
dict_index_copy(new_index, index, table, 0, index->n_fields);
2221
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
2222
/* No fixed number of fields determines an entry uniquely */
2224
new_index->n_uniq = REC_MAX_N_FIELDS;
2226
} else if (dict_index_is_unique(index)) {
2227
/* Only the fields defined so far are needed to identify
2228
the index entry uniquely */
2230
new_index->n_uniq = new_index->n_def;
2232
/* Also the row id is needed to identify the entry */
2233
new_index->n_uniq = 1 + new_index->n_def;
2236
new_index->trx_id_offset = 0;
2238
if (!dict_index_is_ibuf(index)) {
2239
/* Add system columns, trx id first */
2241
trx_id_pos = new_index->n_def;
2243
#if DATA_ROW_ID != 0
2244
# error "DATA_ROW_ID != 0"
2246
#if DATA_TRX_ID != 1
2247
# error "DATA_TRX_ID != 1"
2249
#if DATA_ROLL_PTR != 2
2250
# error "DATA_ROLL_PTR != 2"
2253
if (!dict_index_is_unique(index)) {
2254
dict_index_add_col(new_index, table,
2255
dict_table_get_sys_col(
2256
table, DATA_ROW_ID),
2261
dict_index_add_col(new_index, table,
2262
dict_table_get_sys_col(table, DATA_TRX_ID),
2265
dict_index_add_col(new_index, table,
2266
dict_table_get_sys_col(table,
2270
for (i = 0; i < trx_id_pos; i++) {
2272
ulint fixed_size = dict_col_get_fixed_size(
2273
dict_index_get_nth_col(new_index, i),
2274
dict_table_is_comp(table));
2276
if (fixed_size == 0) {
2277
new_index->trx_id_offset = 0;
2282
if (dict_index_get_nth_field(new_index, i)->prefix_len
2284
new_index->trx_id_offset = 0;
2289
/* Add fixed_size to new_index->trx_id_offset.
2290
Because the latter is a bit-field, an overflow
2291
can theoretically occur. Check for it. */
2292
fixed_size += new_index->trx_id_offset;
2294
new_index->trx_id_offset = fixed_size;
2296
if (new_index->trx_id_offset != fixed_size) {
2297
/* Overflow. Pretend that this is a
2298
variable-length PRIMARY KEY. */
2300
new_index->trx_id_offset = 0;
2307
/* Remember the table columns already contained in new_index */
2308
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2310
/* Mark the table columns already contained in new_index */
2311
for (i = 0; i < new_index->n_def; i++) {
2313
field = dict_index_get_nth_field(new_index, i);
2315
/* If there is only a prefix of the column in the index
2316
field, do not mark the column as contained in the index */
2318
if (field->prefix_len == 0) {
2320
indexed[field->col->ind] = TRUE;
2324
/* Add to new_index non-system columns of table not yet included
2326
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
2328
dict_col_t* col = dict_table_get_nth_col(table, i);
2329
ut_ad(col->mtype != DATA_SYS);
2331
if (!indexed[col->ind]) {
2332
dict_index_add_col(new_index, table, col, 0);
2338
ut_ad(dict_index_is_ibuf(index)
2339
|| (UT_LIST_GET_LEN(table->indexes) == 0));
2341
new_index->cached = TRUE;
2346
/*******************************************************************//**
2347
Builds the internal dictionary cache representation for a non-clustered
2348
index, containing also system fields not defined by the user.
2349
@return own: the internal representation of the non-clustered index */
2352
dict_index_build_internal_non_clust(
2353
/*================================*/
2354
const dict_table_t* table, /*!< in: table */
2355
dict_index_t* index) /*!< in: user representation of
2356
a non-clustered index */
2358
dict_field_t* field;
2359
dict_index_t* new_index;
2360
dict_index_t* clust_index;
2364
ut_ad(table && index);
2365
ut_ad(!dict_index_is_clust(index));
2366
ut_ad(mutex_own(&(dict_sys->mutex)));
2367
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2369
/* The clustered index should be the first in the list of indexes */
2370
clust_index = UT_LIST_GET_FIRST(table->indexes);
2373
ut_ad(dict_index_is_clust(clust_index));
2374
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
2376
/* Create a new index */
2377
new_index = dict_mem_index_create(
2378
table->name, index->name, index->space, index->type,
2379
index->n_fields + 1 + clust_index->n_uniq);
2381
/* Copy other relevant data from the old index
2382
struct to the new struct: it inherits the values */
2384
new_index->n_user_defined_cols = index->n_fields;
2386
new_index->id = index->id;
2388
/* Copy fields from index to new_index */
2389
dict_index_copy(new_index, index, table, 0, index->n_fields);
2391
/* Remember the table columns already contained in new_index */
2392
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2394
/* Mark the table columns already contained in new_index */
2395
for (i = 0; i < new_index->n_def; i++) {
2397
field = dict_index_get_nth_field(new_index, i);
2399
/* If there is only a prefix of the column in the index
2400
field, do not mark the column as contained in the index */
2402
if (field->prefix_len == 0) {
2404
indexed[field->col->ind] = TRUE;
2408
/* Add to new_index the columns necessary to determine the clustered
2409
index entry uniquely */
2411
for (i = 0; i < clust_index->n_uniq; i++) {
2413
field = dict_index_get_nth_field(clust_index, i);
2415
if (!indexed[field->col->ind]) {
2416
dict_index_add_col(new_index, table, field->col,
2423
if (dict_index_is_unique(index)) {
2424
new_index->n_uniq = index->n_fields;
2426
new_index->n_uniq = new_index->n_def;
2429
/* Set the n_fields value in new_index to the actual defined
2432
new_index->n_fields = new_index->n_def;
2434
new_index->cached = TRUE;
2439
#ifndef UNIV_HOTBACKUP
2440
/*====================== FOREIGN KEY PROCESSING ========================*/
2442
/*********************************************************************//**
2443
Checks if a table is referenced by foreign keys.
2444
@return TRUE if table is referenced by a foreign key */
2447
dict_table_is_referenced_by_foreign_key(
2448
/*====================================*/
2449
const dict_table_t* table) /*!< in: InnoDB table */
2451
return(UT_LIST_GET_LEN(table->referenced_list) > 0);
2454
/*********************************************************************//**
2455
Check if the index is referenced by a foreign key, if TRUE return foreign
2457
@return pointer to foreign key struct if index is defined for foreign
2458
key, otherwise NULL */
2461
dict_table_get_referenced_constraint(
2462
/*=================================*/
2463
dict_table_t* table, /*!< in: InnoDB table */
2464
dict_index_t* index) /*!< in: InnoDB index */
2466
dict_foreign_t* foreign;
2468
ut_ad(index != NULL);
2469
ut_ad(table != NULL);
2471
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
2473
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
2475
if (foreign->referenced_index == index) {
2484
/*********************************************************************//**
2485
Checks if a index is defined for a foreign key constraint. Index is a part
2486
of a foreign key constraint if the index is referenced by foreign key
2487
or index is a foreign key index.
2488
@return pointer to foreign key struct if index is defined for foreign
2489
key, otherwise NULL */
2492
dict_table_get_foreign_constraint(
2493
/*==============================*/
2494
dict_table_t* table, /*!< in: InnoDB table */
2495
dict_index_t* index) /*!< in: InnoDB index */
2497
dict_foreign_t* foreign;
2499
ut_ad(index != NULL);
2500
ut_ad(table != NULL);
2502
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
2504
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
2506
if (foreign->foreign_index == index
2507
|| foreign->referenced_index == index) {
2516
/*********************************************************************//**
2517
Frees a foreign key struct. */
2522
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
2524
ut_a(foreign->foreign_table->n_foreign_key_checks_running == 0);
2526
mem_heap_free(foreign->heap);
2529
/**********************************************************************//**
2530
Removes a foreign constraint struct from the dictionary cache. */
2533
dict_foreign_remove_from_cache(
2534
/*===========================*/
2535
dict_foreign_t* foreign) /*!< in, own: foreign constraint */
2537
ut_ad(mutex_own(&(dict_sys->mutex)));
2540
if (foreign->referenced_table) {
2541
UT_LIST_REMOVE(referenced_list,
2542
foreign->referenced_table->referenced_list,
2546
if (foreign->foreign_table) {
2547
UT_LIST_REMOVE(foreign_list,
2548
foreign->foreign_table->foreign_list,
2552
dict_foreign_free(foreign);
2555
/**********************************************************************//**
2556
Looks for the foreign constraint from the foreign and referenced lists
2558
@return foreign constraint */
2563
dict_table_t* table, /*!< in: table object */
2564
const char* id) /*!< in: foreign constraint id */
2566
dict_foreign_t* foreign;
2568
ut_ad(mutex_own(&(dict_sys->mutex)));
2570
foreign = UT_LIST_GET_FIRST(table->foreign_list);
2573
if (ut_strcmp(id, foreign->id) == 0) {
2578
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2581
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2584
if (ut_strcmp(id, foreign->id) == 0) {
2589
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2595
/*********************************************************************//**
2596
Tries to find an index whose first fields are the columns in the array,
2597
in the same order and is not marked for deletion and is not the same
2599
@return matching index, NULL if not found */
2602
dict_foreign_find_index(
2603
/*====================*/
2604
dict_table_t* table, /*!< in: table */
2605
const char** columns,/*!< in: array of column names */
2606
ulint n_cols, /*!< in: number of columns */
2607
dict_index_t* types_idx, /*!< in: NULL or an index to whose types the
2608
column types must match */
2609
ibool check_charsets,
2610
/*!< in: whether to check charsets.
2611
only has an effect if types_idx != NULL */
2613
/*!< in: nonzero if none of the columns must
2614
be declared NOT NULL */
2616
dict_index_t* index;
2618
index = dict_table_get_first_index(table);
2620
while (index != NULL) {
2621
/* Ignore matches that refer to the same instance
2622
or the index is to be dropped */
2623
if (index->to_be_dropped || types_idx == index) {
2627
} else if (dict_index_get_n_fields(index) >= n_cols) {
2630
for (i = 0; i < n_cols; i++) {
2631
dict_field_t* field;
2632
const char* col_name;
2634
field = dict_index_get_nth_field(index, i);
2636
col_name = dict_table_get_col_name(
2637
table, dict_col_get_no(field->col));
2639
if (field->prefix_len != 0) {
2640
/* We do not accept column prefix
2646
if (0 != innobase_strcasecmp(columns[i],
2652
&& (field->col->prtype & DATA_NOT_NULL)) {
2657
if (types_idx && !cmp_cols_are_equal(
2658
dict_index_get_nth_col(index, i),
2659
dict_index_get_nth_col(types_idx,
2668
/* We found a matching index */
2675
index = dict_table_get_next_index(index);
2681
/**********************************************************************//**
2682
Find an index that is equivalent to the one passed in and is not marked
2684
@return index equivalent to foreign->foreign_index, or NULL */
2687
dict_foreign_find_equiv_index(
2688
/*==========================*/
2689
dict_foreign_t* foreign)/*!< in: foreign key */
2691
ut_a(foreign != NULL);
2693
/* Try to find an index which contains the columns as the
2694
first fields and in the right order, and the types are the
2695
same as in foreign->foreign_index */
2697
return(dict_foreign_find_index(
2698
foreign->foreign_table,
2699
foreign->foreign_col_names, foreign->n_fields,
2700
foreign->foreign_index, TRUE, /* check types */
2701
FALSE/* allow columns to be NULL */));
2704
#endif /* !UNIV_HOTBACKUP */
2705
/**********************************************************************//**
2706
Returns an index object by matching on the name and column names and
2707
if more than one index matches return the index with the max id
2708
@return matching index, NULL if not found */
2711
dict_table_get_index_by_max_id(
2712
/*===========================*/
2713
dict_table_t* table, /*!< in: table */
2714
const char* name, /*!< in: the index name to find */
2715
const char** columns,/*!< in: array of column names */
2716
ulint n_cols) /*!< in: number of columns */
2718
dict_index_t* index;
2719
dict_index_t* found;
2722
index = dict_table_get_first_index(table);
2724
while (index != NULL) {
2725
if (ut_strcmp(index->name, name) == 0
2726
&& dict_index_get_n_ordering_defined_by_user(index)
2731
for (i = 0; i < n_cols; i++) {
2732
dict_field_t* field;
2733
const char* col_name;
2735
field = dict_index_get_nth_field(index, i);
2737
col_name = dict_table_get_col_name(
2738
table, dict_col_get_no(field->col));
2740
if (0 != innobase_strcasecmp(
2741
columns[i], col_name)) {
2748
/* We found a matching index, select
2749
the index with the higher id*/
2751
if (!found || index->id > found->id) {
2758
index = dict_table_get_next_index(index);
2764
#ifndef UNIV_HOTBACKUP
2765
/**********************************************************************//**
2766
Report an error in a foreign key definition. */
2769
dict_foreign_error_report_low(
2770
/*==========================*/
2771
FILE* file, /*!< in: output stream */
2772
const char* name) /*!< in: table name */
2775
ut_print_timestamp(file);
2776
fprintf(file, " Error in foreign key constraint of table %s:\n",
2780
/**********************************************************************//**
2781
Report an error in a foreign key definition. */
2784
dict_foreign_error_report(
2785
/*======================*/
2786
FILE* file, /*!< in: output stream */
2787
dict_foreign_t* fk, /*!< in: foreign key constraint */
2788
const char* msg) /*!< in: the error message */
2790
mutex_enter(&dict_foreign_err_mutex);
2791
dict_foreign_error_report_low(file, fk->foreign_table_name);
2793
fputs(" Constraint:\n", file);
2794
dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2796
if (fk->foreign_index) {
2797
fputs("The index in the foreign key in table is ", file);
2798
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2800
"See " REFMAN "innodb-foreign-key-constraints.html\n"
2801
"for correct foreign key definition.\n",
2804
mutex_exit(&dict_foreign_err_mutex);
2807
/**********************************************************************//**
2808
Adds a foreign key constraint object to the dictionary cache. May free
2809
the object if there already is an object with the same identifier in.
2810
At least one of the foreign table and the referenced table must already
2811
be in the dictionary cache!
2812
@return DB_SUCCESS or error code */
2815
dict_foreign_add_to_cache(
2816
/*======================*/
2817
dict_foreign_t* foreign, /*!< in, own: foreign key constraint */
2818
ibool check_charsets) /*!< in: TRUE=check charset
2821
dict_table_t* for_table;
2822
dict_table_t* ref_table;
2823
dict_foreign_t* for_in_cache = NULL;
2824
dict_index_t* index;
2825
ibool added_to_referenced_list= FALSE;
2826
FILE* ef = dict_foreign_err_file;
2828
ut_ad(mutex_own(&(dict_sys->mutex)));
2830
for_table = dict_table_check_if_in_cache_low(
2831
foreign->foreign_table_name_lookup);
2833
ref_table = dict_table_check_if_in_cache_low(
2834
foreign->referenced_table_name_lookup);
2835
ut_a(for_table || ref_table);
2838
for_in_cache = dict_foreign_find(for_table, foreign->id);
2841
if (!for_in_cache && ref_table) {
2842
for_in_cache = dict_foreign_find(ref_table, foreign->id);
2846
/* Free the foreign object */
2847
mem_heap_free(foreign->heap);
2849
for_in_cache = foreign;
2852
if (for_in_cache->referenced_table == NULL && ref_table) {
2853
index = dict_foreign_find_index(
2855
for_in_cache->referenced_col_names,
2856
for_in_cache->n_fields, for_in_cache->foreign_index,
2857
check_charsets, FALSE);
2859
if (index == NULL) {
2860
dict_foreign_error_report(
2862
"there is no index in referenced table"
2863
" which would contain\n"
2864
"the columns as the first columns,"
2865
" or the data types in the\n"
2866
"referenced table do not match"
2867
" the ones in table.");
2869
if (for_in_cache == foreign) {
2870
mem_heap_free(foreign->heap);
2873
return(DB_CANNOT_ADD_CONSTRAINT);
2876
for_in_cache->referenced_table = ref_table;
2877
for_in_cache->referenced_index = index;
2878
UT_LIST_ADD_LAST(referenced_list,
2879
ref_table->referenced_list,
2881
added_to_referenced_list = TRUE;
2884
if (for_in_cache->foreign_table == NULL && for_table) {
2885
index = dict_foreign_find_index(
2887
for_in_cache->foreign_col_names,
2888
for_in_cache->n_fields,
2889
for_in_cache->referenced_index, check_charsets,
2891
& (DICT_FOREIGN_ON_DELETE_SET_NULL
2892
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
2894
if (index == NULL) {
2895
dict_foreign_error_report(
2897
"there is no index in the table"
2898
" which would contain\n"
2899
"the columns as the first columns,"
2900
" or the data types in the\n"
2901
"table do not match"
2902
" the ones in the referenced table\n"
2903
"or one of the ON ... SET NULL columns"
2904
" is declared NOT NULL.");
2906
if (for_in_cache == foreign) {
2907
if (added_to_referenced_list) {
2910
ref_table->referenced_list,
2914
mem_heap_free(foreign->heap);
2917
return(DB_CANNOT_ADD_CONSTRAINT);
2920
for_in_cache->foreign_table = for_table;
2921
for_in_cache->foreign_index = index;
2922
UT_LIST_ADD_LAST(foreign_list,
2923
for_table->foreign_list,
2930
#endif /* !UNIV_HOTBACKUP */
2931
/*********************************************************************//**
2932
Scans from pointer onwards. Stops if is at the start of a copy of
2933
'string' where characters are compared without case sensitivity, and
2934
only outside `` or "" quotes. Stops also at NUL.
2935
@return scanned up to this */
2940
const char* ptr, /*!< in: scan from */
2941
const char* string) /*!< in: look for this */
2945
for (; *ptr; ptr++) {
2946
if (*ptr == quote) {
2947
/* Closing quote character: do not look for
2948
starting quote or the keyword. */
2951
/* Within quotes: do nothing. */
2952
} else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
2953
/* Starting quote: remember the quote character. */
2956
/* Outside quotes: look for the keyword. */
2958
for (i = 0; string[i]; i++) {
2959
if (toupper((int)(unsigned char)(ptr[i]))
2960
!= toupper((int)(unsigned char)
2974
/*********************************************************************//**
2975
Accepts a specified string. Comparisons are case-insensitive.
2976
@return if string was accepted, the pointer is moved after that, else
2982
struct charset_info_st* cs,/*!< in: the character set of ptr */
2983
const char* ptr, /*!< in: scan from this */
2984
const char* string, /*!< in: accept only this string as the next
2985
non-whitespace string */
2986
ibool* success)/*!< out: TRUE if accepted */
2988
const char* old_ptr = ptr;
2989
const char* old_ptr2;
2993
while (my_isspace(cs, *ptr)) {
2999
ptr = dict_scan_to(ptr, string);
3001
if (*ptr == '\0' || old_ptr2 != ptr) {
3007
return(ptr + ut_strlen(string));
3010
/*********************************************************************//**
3011
Scans an id. For the lexical definition of an 'id', see the code below.
3012
Strips backquotes or double quotes from around the id.
3013
@return scanned to */
3018
struct charset_info_st* cs,/*!< in: the character set of ptr */
3019
const char* ptr, /*!< in: scanned to */
3020
mem_heap_t* heap, /*!< in: heap where to allocate the id
3021
(NULL=id will not be allocated, but it
3022
will point to string near ptr) */
3023
const char** id, /*!< out,own: the id; NULL if no id was
3025
ibool table_id,/*!< in: TRUE=convert the allocated id
3026
as a table name; FALSE=convert to UTF-8 */
3027
ibool accept_also_dot)
3028
/*!< in: TRUE if also a dot can appear in a
3029
non-quoted id; in a quoted id it can appear
3040
while (my_isspace(cs, *ptr)) {
3049
if (*ptr == '`' || *ptr == '"') {
3061
if (*ptr == quote) {
3063
if (*ptr != quote) {
3071
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
3072
&& (accept_also_dot || *ptr != '.')
3073
&& *ptr != ',' && *ptr != '\0') {
3081
if (UNIV_UNLIKELY(!heap)) {
3082
/* no heap given: id will point to source string */
3089
str = d = mem_heap_alloc(heap, len + 1);
3091
if ((*d++ = *s++) == quote) {
3098
ut_ad(s + 1 == ptr);
3100
str = mem_heap_strdupl(heap, s, len);
3105
/* Convert the identifier from connection character set
3108
*id = dst = mem_heap_alloc(heap, len);
3110
innobase_convert_from_id(cs, dst, str, len);
3111
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
3112
sizeof srv_mysql50_table_name_prefix)) {
3113
/* This is a pre-5.1 table name
3114
containing chars other than [A-Za-z0-9].
3115
Discard the prefix and use raw UTF-8 encoding. */
3116
str += sizeof srv_mysql50_table_name_prefix;
3117
len -= sizeof srv_mysql50_table_name_prefix;
3120
/* Encode using filename-safe characters. */
3122
*id = dst = mem_heap_alloc(heap, len);
3124
innobase_convert_from_table_id(cs, dst, str, len);
3130
/*********************************************************************//**
3131
Tries to scan a column name.
3132
@return scanned to */
3137
struct charset_info_st* cs, /*!< in: the character set of ptr */
3138
const char* ptr, /*!< in: scanned to */
3139
ibool* success,/*!< out: TRUE if success */
3140
dict_table_t* table, /*!< in: table in which the column is */
3141
const dict_col_t** column, /*!< out: pointer to column if success */
3142
mem_heap_t* heap, /*!< in: heap where to allocate */
3143
const char** name) /*!< out,own: the column name;
3144
NULL if no name was scannable */
3150
ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
3152
if (*name == NULL) {
3154
return(ptr); /* Syntax error */
3157
if (table == NULL) {
3161
for (i = 0; i < dict_table_get_n_cols(table); i++) {
3163
const char* col_name = dict_table_get_col_name(
3166
if (0 == innobase_strcasecmp(col_name, *name)) {
3170
*column = dict_table_get_nth_col(table, i);
3171
strcpy((char*) *name, col_name);
3181
/*********************************************************************//**
3182
Scans a table name from an SQL string.
3183
@return scanned to */
3186
dict_scan_table_name(
3187
/*=================*/
3188
struct charset_info_st* cs,/*!< in: the character set of ptr */
3189
const char* ptr, /*!< in: scanned to */
3190
dict_table_t** table, /*!< out: table object or NULL */
3191
const char* name, /*!< in: foreign key table name */
3192
ibool* success,/*!< out: TRUE if ok name found */
3193
mem_heap_t* heap, /*!< in: heap where to allocate the id */
3194
const char** ref_name)/*!< out,own: the table name;
3195
NULL if no name was scannable */
3197
const char* database_name = NULL;
3198
ulint database_name_len = 0;
3199
const char* table_name = NULL;
3200
ulint table_name_len;
3201
const char* scan_name;
3207
ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
3209
if (scan_name == NULL) {
3211
return(ptr); /* Syntax error */
3215
/* We scanned the database name; scan also the table name */
3219
database_name = scan_name;
3220
database_name_len = strlen(database_name);
3222
ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
3224
if (table_name == NULL) {
3226
return(ptr); /* Syntax error */
3229
/* To be able to read table dumps made with InnoDB-4.0.17 or
3230
earlier, we must allow the dot separator between the database
3231
name and the table name also to appear within a quoted
3232
identifier! InnoDB used to print a constraint as:
3233
... REFERENCES `databasename.tablename` ...
3234
starting from 4.0.18 it is
3235
... REFERENCES `databasename`.`tablename` ... */
3238
for (s = scan_name; *s; s++) {
3240
database_name = scan_name;
3241
database_name_len = s - scan_name;
3243
break;/* to do: multiple dots? */
3247
table_name = scan_name;
3250
if (database_name == NULL) {
3251
/* Use the database name of the foreign key table */
3253
database_name = name;
3254
database_name_len = dict_get_db_name_len(name);
3257
table_name_len = strlen(table_name);
3259
/* Copy database_name, '/', table_name, '\0' */
3260
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
3261
memcpy(ref, database_name, database_name_len);
3262
ref[database_name_len] = '/';
3263
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3265
/* Values; 0 = Store and compare as given; case sensitive
3266
1 = Store and compare in lower; case insensitive
3267
2 = Store as given, compare in lower; case semi-sensitive */
3268
if (innobase_get_lower_case_table_names() == 2) {
3269
innobase_casedn_str(ref);
3270
*table = dict_table_get_low(ref);
3271
memcpy(ref, database_name, database_name_len);
3272
ref[database_name_len] = '/';
3273
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3277
if (innobase_get_lower_case_table_names() == 1) {
3278
innobase_casedn_str(ref);
3281
innobase_casedn_str(ref);
3282
#endif /* !__WIN__ */
3283
*table = dict_table_get_low(ref);
3291
/*********************************************************************//**
3292
Skips one id. The id is allowed to contain also '.'.
3293
@return scanned to */
3298
struct charset_info_st* cs,/*!< in: the character set of ptr */
3299
const char* ptr, /*!< in: scanned to */
3300
ibool* success)/*!< out: TRUE if success, FALSE if just spaces
3301
left in string or a syntax error */
3307
ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
3316
/*********************************************************************//**
3317
Removes MySQL comments from an SQL string. A comment is either
3318
(a) '#' to the end of the line,
3319
(b) '--[space]' to the end of the line, or
3320
(c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
3322
@return own: SQL string stripped from comments; the caller must free
3323
this with mem_free()! */
3326
dict_strip_comments(
3327
/*================*/
3328
const char* sql_string, /*!< in: SQL string */
3329
size_t sql_length) /*!< in: length of sql_string */
3333
const char* eptr = sql_string + sql_length;
3335
/* unclosed quote character (0 if none) */
3338
str = mem_alloc(sql_length + 1);
3345
if (sptr >= eptr || *sptr == '\0') {
3349
ut_a(ptr <= str + sql_length);
3354
if (*sptr == quote) {
3355
/* Closing quote character: do not look for
3356
starting quote or comments. */
3359
/* Within quotes: do not look for
3360
starting quotes or comments. */
3361
} else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
3362
/* Starting quote: remember the quote character. */
3364
} else if (*sptr == '#'
3365
|| (sptr[0] == '-' && sptr[1] == '-'
3366
&& sptr[2] == ' ')) {
3368
if (++sptr >= eptr) {
3372
/* In Unix a newline is 0x0A while in Windows
3373
it is 0x0D followed by 0x0A */
3382
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3393
if (sptr[1] == '/') {
3410
#ifndef UNIV_HOTBACKUP
3411
/*********************************************************************//**
3412
Finds the highest [number] for foreign key constraints of the table. Looks
3413
only at the >= 4.0.18-format id's, which are of the form
3414
databasename/tablename_ibfk_[number].
3415
@return highest number, 0 if table has no new format foreign key constraints */
3418
dict_table_get_highest_foreign_id(
3419
/*==============================*/
3420
dict_table_t* table) /*!< in: table in the dictionary memory cache */
3422
dict_foreign_t* foreign;
3424
ulint biggest_id = 0;
3430
len = ut_strlen(table->name);
3431
foreign = UT_LIST_GET_FIRST(table->foreign_list);
3434
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
3435
&& 0 == ut_memcmp(foreign->id, table->name, len)
3436
&& 0 == ut_memcmp(foreign->id + len,
3437
dict_ibfk, (sizeof dict_ibfk) - 1)
3438
&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
3439
/* It is of the >= 4.0.18 format */
3441
id = strtoul(foreign->id + len
3442
+ ((sizeof dict_ibfk) - 1),
3444
if (*endp == '\0') {
3445
ut_a(id != biggest_id);
3447
if (id > biggest_id) {
3453
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3459
/*********************************************************************//**
3460
Reports a simple foreign key create clause syntax error. */
3463
dict_foreign_report_syntax_err(
3464
/*===========================*/
3465
const char* name, /*!< in: table name */
3466
const char* start_of_latest_foreign,
3467
/*!< in: start of the foreign key clause
3468
in the SQL string */
3469
const char* ptr) /*!< in: place of the syntax error */
3471
FILE* ef = dict_foreign_err_file;
3473
mutex_enter(&dict_foreign_err_mutex);
3474
dict_foreign_error_report_low(ef, name);
3475
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
3476
start_of_latest_foreign, ptr);
3477
mutex_exit(&dict_foreign_err_mutex);
3480
/*********************************************************************//**
3481
Scans a table create SQL string and adds to the data dictionary the foreign
3482
key constraints declared in the string. This function should be called after
3483
the indexes for a table have been created. Each foreign key constraint must
3484
be accompanied with indexes in both participating tables. The indexes are
3485
allowed to contain more fields than mentioned in the constraint.
3486
@return error code or DB_SUCCESS */
3489
dict_create_foreign_constraints_low(
3490
/*================================*/
3491
trx_t* trx, /*!< in: transaction */
3492
mem_heap_t* heap, /*!< in: memory heap */
3493
struct charset_info_st* cs,/*!< in: the character set of sql_string */
3494
const char* sql_string,
3495
/*!< in: CREATE TABLE or ALTER TABLE statement
3496
where foreign keys are declared like:
3497
FOREIGN KEY (a, b) REFERENCES table2(c, d),
3498
table2 can be written also with the database
3499
name before it: test.table2; the default
3500
database is the database of parameter name */
3501
const char* name, /*!< in: table full name in the normalized form
3502
database_name/table_name */
3504
/*!< in: if TRUE, fail with error code
3505
DB_CANNOT_ADD_CONSTRAINT if any foreign
3508
dict_table_t* table;
3509
dict_table_t* referenced_table;
3510
dict_table_t* table_to_alter;
3511
ulint highest_id_so_far = 0;
3512
dict_index_t* index;
3513
dict_foreign_t* foreign;
3514
const char* ptr = sql_string;
3515
const char* start_of_latest_foreign = sql_string;
3516
FILE* ef = dict_foreign_err_file;
3517
const char* constraint_name;
3527
const dict_col_t*columns[500];
3528
const char* column_names[500];
3529
const char* referenced_table_name;
3531
ut_ad(mutex_own(&(dict_sys->mutex)));
3533
table = dict_table_get_low(name);
3535
if (table == NULL) {
3536
mutex_enter(&dict_foreign_err_mutex);
3537
dict_foreign_error_report_low(ef, name);
3539
"Cannot find the table in the internal"
3540
" data dictionary of InnoDB.\n"
3541
"Create table statement:\n%s\n", sql_string);
3542
mutex_exit(&dict_foreign_err_mutex);
3547
/* First check if we are actually doing an ALTER TABLE, and in that
3548
case look for the table being altered */
3550
ptr = dict_accept(cs, ptr, "ALTER", &success);
3557
ptr = dict_accept(cs, ptr, "TABLE", &success);
3564
/* We are doing an ALTER TABLE: scan the table name we are altering */
3566
ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
3567
&success, heap, &referenced_table_name);
3570
"InnoDB: Error: could not find"
3571
" the table being ALTERED in:\n%s\n",
3577
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
3578
format databasename/tablename_ibfk_[number], where [number] is local
3579
to the table; look for the highest [number] for table_to_alter, so
3580
that we can assign to new constraints higher numbers. */
3582
/* If we are altering a temporary table, the table name after ALTER
3583
TABLE does not correspond to the internal table name, and
3584
table_to_alter is NULL. TODO: should we fix this somehow? */
3586
if (table_to_alter == NULL) {
3587
highest_id_so_far = 0;
3589
highest_id_so_far = dict_table_get_highest_foreign_id(
3593
/* Scan for foreign key declarations in a loop */
3595
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
3597
ptr1 = dict_scan_to(ptr, "CONSTRAINT");
3598
ptr2 = dict_scan_to(ptr, "FOREIGN");
3600
constraint_name = NULL;
3603
/* The user may have specified a constraint name. Pick it so
3604
that we can store 'databasename/constraintname' as the id of
3605
of the constraint to system tables. */
3608
ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
3612
if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
3616
while (my_isspace(cs, *ptr)) {
3620
/* read constraint name unless got "CONSTRAINT FOREIGN" */
3622
ptr = dict_scan_id(cs, ptr, heap,
3623
&constraint_name, FALSE, FALSE);
3630
/* The proper way to reject foreign keys for temporary
3631
tables would be to split the lexing and syntactical
3632
analysis of foreign key clauses from the actual adding
3633
of them, so that ha_innodb.cc could first parse the SQL
3634
command, determine if there are any foreign keys, and
3635
if so, immediately reject the command if the table is a
3636
temporary one. For now, this kludge will work. */
3637
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
3639
return(DB_CANNOT_ADD_CONSTRAINT);
3642
/**********************************************************/
3643
/* The following call adds the foreign key constraints
3644
to the data dictionary system tables on disk */
3646
error = dict_create_add_foreigns_to_dictionary(
3647
highest_id_so_far, table, trx);
3651
start_of_latest_foreign = ptr;
3653
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3659
if (!my_isspace(cs, *ptr)) {
3663
ptr = dict_accept(cs, ptr, "KEY", &success);
3669
ptr = dict_accept(cs, ptr, "(", &success);
3672
/* MySQL allows also an index id before the '('; we
3674
ptr = dict_skip_word(cs, ptr, &success);
3677
dict_foreign_report_syntax_err(
3678
name, start_of_latest_foreign, ptr);
3680
return(DB_CANNOT_ADD_CONSTRAINT);
3683
ptr = dict_accept(cs, ptr, "(", &success);
3686
/* We do not flag a syntax error here because in an
3687
ALTER TABLE we may also have DROP FOREIGN KEY abc */
3695
/* Scan the columns in the first list */
3697
ut_a(i < (sizeof column_names) / sizeof *column_names);
3698
ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
3699
heap, column_names + i);
3701
mutex_enter(&dict_foreign_err_mutex);
3702
dict_foreign_error_report_low(ef, name);
3703
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
3704
start_of_latest_foreign, ptr);
3705
mutex_exit(&dict_foreign_err_mutex);
3707
return(DB_CANNOT_ADD_CONSTRAINT);
3712
ptr = dict_accept(cs, ptr, ",", &success);
3718
ptr = dict_accept(cs, ptr, ")", &success);
3721
dict_foreign_report_syntax_err(
3722
name, start_of_latest_foreign, ptr);
3723
return(DB_CANNOT_ADD_CONSTRAINT);
3726
/* Try to find an index which contains the columns
3727
as the first fields and in the right order */
3729
index = dict_foreign_find_index(table, column_names, i,
3733
mutex_enter(&dict_foreign_err_mutex);
3734
dict_foreign_error_report_low(ef, name);
3735
fputs("There is no index in table ", ef);
3736
ut_print_name(ef, NULL, TRUE, name);
3737
fprintf(ef, " where the columns appear\n"
3738
"as the first columns. Constraint:\n%s\n"
3739
"See " REFMAN "innodb-foreign-key-constraints.html\n"
3740
"for correct foreign key definition.\n",
3741
start_of_latest_foreign);
3742
mutex_exit(&dict_foreign_err_mutex);
3744
return(DB_CHILD_NO_INDEX);
3746
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3748
if (!success || !my_isspace(cs, *ptr)) {
3749
dict_foreign_report_syntax_err(
3750
name, start_of_latest_foreign, ptr);
3751
return(DB_CANNOT_ADD_CONSTRAINT);
3754
/* Let us create a constraint struct */
3756
foreign = dict_mem_foreign_create();
3758
if (constraint_name) {
3761
/* Catenate 'databasename/' to the constraint name specified
3762
by the user: we conceive the constraint as belonging to the
3763
same MySQL 'database' as the table itself. We store the name
3766
db_len = dict_get_db_name_len(table->name);
3768
foreign->id = mem_heap_alloc(
3769
foreign->heap, db_len + strlen(constraint_name) + 2);
3771
ut_memcpy(foreign->id, table->name, db_len);
3772
foreign->id[db_len] = '/';
3773
strcpy(foreign->id + db_len + 1, constraint_name);
3776
foreign->foreign_table = table;
3777
foreign->foreign_table_name = mem_heap_strdup(
3778
foreign->heap, table->name);
3779
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
3781
foreign->foreign_index = index;
3782
foreign->n_fields = (unsigned int) i;
3783
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3785
for (i = 0; i < foreign->n_fields; i++) {
3786
foreign->foreign_col_names[i] = mem_heap_strdup(
3788
dict_table_get_col_name(table,
3789
dict_col_get_no(columns[i])));
3792
ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3793
&success, heap, &referenced_table_name);
3795
/* Note that referenced_table can be NULL if the user has suppressed
3796
checking of foreign key constraints! */
3798
if (!success || (!referenced_table && trx->check_foreigns)) {
3799
dict_foreign_free(foreign);
3801
mutex_enter(&dict_foreign_err_mutex);
3802
dict_foreign_error_report_low(ef, name);
3803
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3805
start_of_latest_foreign, ptr);
3806
mutex_exit(&dict_foreign_err_mutex);
3808
return(DB_CANNOT_ADD_CONSTRAINT);
3811
ptr = dict_accept(cs, ptr, "(", &success);
3814
dict_foreign_free(foreign);
3815
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3817
return(DB_CANNOT_ADD_CONSTRAINT);
3820
/* Scan the columns in the second list */
3824
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3825
heap, column_names + i);
3829
dict_foreign_free(foreign);
3831
mutex_enter(&dict_foreign_err_mutex);
3832
dict_foreign_error_report_low(ef, name);
3833
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3835
start_of_latest_foreign, ptr);
3836
mutex_exit(&dict_foreign_err_mutex);
3838
return(DB_CANNOT_ADD_CONSTRAINT);
3841
ptr = dict_accept(cs, ptr, ",", &success);
3847
ptr = dict_accept(cs, ptr, ")", &success);
3849
if (!success || foreign->n_fields != i) {
3850
dict_foreign_free(foreign);
3852
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3854
return(DB_CANNOT_ADD_CONSTRAINT);
3861
/* Loop here as long as we can find ON ... conditions */
3863
ptr = dict_accept(cs, ptr, "ON", &success);
3867
goto try_find_index;
3870
ptr = dict_accept(cs, ptr, "DELETE", &success);
3873
ptr = dict_accept(cs, ptr, "UPDATE", &success);
3876
dict_foreign_free(foreign);
3878
dict_foreign_report_syntax_err(
3879
name, start_of_latest_foreign, ptr);
3880
return(DB_CANNOT_ADD_CONSTRAINT);
3883
is_on_delete = FALSE;
3886
is_on_delete = TRUE;
3890
ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3893
goto scan_on_conditions;
3896
ptr = dict_accept(cs, ptr, "CASCADE", &success);
3900
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3902
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3905
goto scan_on_conditions;
3908
ptr = dict_accept(cs, ptr, "NO", &success);
3911
ptr = dict_accept(cs, ptr, "ACTION", &success);
3914
dict_foreign_free(foreign);
3915
dict_foreign_report_syntax_err(
3916
name, start_of_latest_foreign, ptr);
3918
return(DB_CANNOT_ADD_CONSTRAINT);
3922
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3924
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3927
goto scan_on_conditions;
3930
ptr = dict_accept(cs, ptr, "SET", &success);
3933
dict_foreign_free(foreign);
3934
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3936
return(DB_CANNOT_ADD_CONSTRAINT);
3939
ptr = dict_accept(cs, ptr, "NULL", &success);
3942
dict_foreign_free(foreign);
3943
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3945
return(DB_CANNOT_ADD_CONSTRAINT);
3948
for (j = 0; j < foreign->n_fields; j++) {
3949
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3952
/* It is not sensible to define SET NULL
3953
if the column is not allowed to be NULL! */
3955
dict_foreign_free(foreign);
3957
mutex_enter(&dict_foreign_err_mutex);
3958
dict_foreign_error_report_low(ef, name);
3960
"You have defined a SET NULL condition"
3961
" though some of the\n"
3962
"columns are defined as NOT NULL.\n",
3963
start_of_latest_foreign);
3964
mutex_exit(&dict_foreign_err_mutex);
3966
return(DB_CANNOT_ADD_CONSTRAINT);
3971
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3973
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3976
goto scan_on_conditions;
3979
if (n_on_deletes > 1 || n_on_updates > 1) {
3980
/* It is an error to define more than 1 action */
3982
dict_foreign_free(foreign);
3984
mutex_enter(&dict_foreign_err_mutex);
3985
dict_foreign_error_report_low(ef, name);
3987
"You have twice an ON DELETE clause"
3988
" or twice an ON UPDATE clause.\n",
3989
start_of_latest_foreign);
3990
mutex_exit(&dict_foreign_err_mutex);
3992
return(DB_CANNOT_ADD_CONSTRAINT);
3995
/* Try to find an index which contains the columns as the first fields
3996
and in the right order, and the types are the same as in
3997
foreign->foreign_index */
3999
if (referenced_table) {
4000
index = dict_foreign_find_index(referenced_table,
4002
foreign->foreign_index,
4005
dict_foreign_free(foreign);
4006
mutex_enter(&dict_foreign_err_mutex);
4007
dict_foreign_error_report_low(ef, name);
4009
"Cannot find an index in the"
4010
" referenced table where the\n"
4011
"referenced columns appear as the"
4012
" first columns, or column types\n"
4013
"in the table and the referenced table"
4014
" do not match for constraint.\n"
4015
"Note that the internal storage type of"
4016
" ENUM and SET changed in\n"
4017
"tables created with >= InnoDB-4.1.12,"
4018
" and such columns in old tables\n"
4019
"cannot be referenced by such columns"
4022
"innodb-foreign-key-constraints.html\n"
4023
"for correct foreign key definition.\n",
4024
start_of_latest_foreign);
4025
mutex_exit(&dict_foreign_err_mutex);
4027
return(DB_PARENT_NO_INDEX);
4030
ut_a(trx->check_foreigns == FALSE);
4034
foreign->referenced_index = index;
4035
foreign->referenced_table = referenced_table;
4037
foreign->referenced_table_name = mem_heap_strdup(
4038
foreign->heap, referenced_table_name);
4039
dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
4041
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
4043
for (i = 0; i < foreign->n_fields; i++) {
4044
foreign->referenced_col_names[i]
4045
= mem_heap_strdup(foreign->heap, column_names[i]);
4048
/* We found an ok constraint definition: add to the lists */
4050
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
4052
if (referenced_table) {
4053
UT_LIST_ADD_LAST(referenced_list,
4054
referenced_table->referenced_list,
4061
/*********************************************************************//**
4062
Scans a table create SQL string and adds to the data dictionary the foreign
4063
key constraints declared in the string. This function should be called after
4064
the indexes for a table have been created. Each foreign key constraint must
4065
be accompanied with indexes in both participating tables. The indexes are
4066
allowed to contain more fields than mentioned in the constraint.
4067
@return error code or DB_SUCCESS */
4070
dict_create_foreign_constraints(
4071
/*============================*/
4072
trx_t* trx, /*!< in: transaction */
4073
const char* sql_string, /*!< in: table create statement where
4074
foreign keys are declared like:
4075
FOREIGN KEY (a, b) REFERENCES
4076
table2(c, d), table2 can be written
4077
also with the database
4078
name before it: test.table2; the
4079
default database id the database of
4081
size_t sql_length, /*!< in: length of sql_string */
4082
const char* name, /*!< in: table full name in the
4084
database_name/table_name */
4085
ibool reject_fks) /*!< in: if TRUE, fail with error
4086
code DB_CANNOT_ADD_CONSTRAINT if
4087
any foreign keys are found. */
4094
ut_a(trx->mysql_thd);
4096
str = dict_strip_comments(sql_string, sql_length);
4097
heap = mem_heap_create(10000);
4099
err = dict_create_foreign_constraints_low(
4100
trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
4103
mem_heap_free(heap);
4109
/**********************************************************************//**
4110
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
4111
@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
4112
constraint id does not match */
4115
dict_foreign_parse_drop_constraints(
4116
/*================================*/
4117
mem_heap_t* heap, /*!< in: heap from which we can
4119
trx_t* trx, /*!< in: transaction */
4120
dict_table_t* table, /*!< in: table */
4121
ulint* n, /*!< out: number of constraints
4123
const char*** constraints_to_drop) /*!< out: id's of the
4124
constraints to drop */
4126
dict_foreign_t* foreign;
4132
FILE* ef = dict_foreign_err_file;
4133
struct charset_info_st* cs;
4136
ut_a(trx->mysql_thd);
4138
cs = innobase_get_charset(trx->mysql_thd);
4142
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
4144
ptr = innobase_get_stmt(trx->mysql_thd, &len);
4146
str = dict_strip_comments(ptr, len);
4150
ut_ad(mutex_own(&(dict_sys->mutex)));
4152
ptr = dict_scan_to(ptr, "DROP");
4160
ptr = dict_accept(cs, ptr, "DROP", &success);
4162
if (!my_isspace(cs, *ptr)) {
4167
ptr = dict_accept(cs, ptr, "FOREIGN", &success);
4169
if (!success || !my_isspace(cs, *ptr)) {
4174
ptr = dict_accept(cs, ptr, "KEY", &success);
4181
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
4189
(*constraints_to_drop)[*n] = id;
4192
/* Look for the given constraint id */
4194
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4196
while (foreign != NULL) {
4197
if (0 == strcmp(foreign->id, id)
4198
|| (strchr(foreign->id, '/')
4200
dict_remove_db_name(foreign->id)))) {
4205
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4208
if (foreign == NULL) {
4209
mutex_enter(&dict_foreign_err_mutex);
4211
ut_print_timestamp(ef);
4212
fputs(" Error in dropping of a foreign key constraint"
4214
ut_print_name(ef, NULL, TRUE, table->name);
4216
"in SQL command\n", ef);
4218
fputs("\nCannot find a constraint with the given id ", ef);
4219
ut_print_name(ef, NULL, FALSE, id);
4221
mutex_exit(&dict_foreign_err_mutex);
4225
return(DB_CANNOT_DROP_CONSTRAINT);
4231
mutex_enter(&dict_foreign_err_mutex);
4233
ut_print_timestamp(ef);
4234
fputs(" Syntax error in dropping of a"
4235
" foreign key constraint of table ", ef);
4236
ut_print_name(ef, NULL, TRUE, table->name);
4238
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
4239
mutex_exit(&dict_foreign_err_mutex);
4243
return(DB_CANNOT_DROP_CONSTRAINT);
4246
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
4247
#endif /* !UNIV_HOTBACKUP */
4248
/**********************************************************************//**
4249
Returns an index object if it is found in the dictionary cache.
4250
Assumes that dict_sys->mutex is already being held.
4251
@return index, NULL if not found */
4254
dict_index_get_if_in_cache_low(
4255
/*===========================*/
4256
index_id_t index_id) /*!< in: index id */
4258
ut_ad(mutex_own(&(dict_sys->mutex)));
4260
return(dict_index_find_on_id_low(index_id));
4263
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
4264
/**********************************************************************//**
4265
Returns an index object if it is found in the dictionary cache.
4266
@return index, NULL if not found */
4269
dict_index_get_if_in_cache(
4270
/*=======================*/
4271
index_id_t index_id) /*!< in: index id */
4273
dict_index_t* index;
4275
if (dict_sys == NULL) {
4279
mutex_enter(&(dict_sys->mutex));
4281
index = dict_index_get_if_in_cache_low(index_id);
4283
mutex_exit(&(dict_sys->mutex));
4287
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
4290
/**********************************************************************//**
4291
Checks that a tuple has n_fields_cmp value in a sensible range, so that
4292
no comparison can occur with the page number field in a node pointer.
4293
@return TRUE if ok */
4296
dict_index_check_search_tuple(
4297
/*==========================*/
4298
const dict_index_t* index, /*!< in: index tree */
4299
const dtuple_t* tuple) /*!< in: tuple used in a search */
4302
ut_a(dtuple_get_n_fields_cmp(tuple)
4303
<= dict_index_get_n_unique_in_tree(index));
4306
#endif /* UNIV_DEBUG */
4308
/**********************************************************************//**
4309
Builds a node pointer out of a physical record and a page number.
4310
@return own: node pointer */
4313
dict_index_build_node_ptr(
4314
/*======================*/
4315
const dict_index_t* index, /*!< in: index */
4316
const rec_t* rec, /*!< in: record for which to build node
4318
ulint page_no,/*!< in: page number to put in node
4320
mem_heap_t* heap, /*!< in: memory heap where pointer
4322
ulint level) /*!< in: level of rec in tree:
4323
0 means leaf level */
4330
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
4331
/* In a universal index tree, we take the whole record as
4332
the node pointer if the record is on the leaf level,
4333
on non-leaf levels we remove the last field, which
4334
contains the page number of the child page */
4336
ut_a(!dict_table_is_comp(index->table));
4337
n_unique = rec_get_n_fields_old(rec);
4344
n_unique = dict_index_get_n_unique_in_tree(index);
4347
tuple = dtuple_create(heap, n_unique + 1);
4349
/* When searching in the tree for the node pointer, we must not do
4350
comparison on the last field, the page number field, as on upper
4351
levels in the tree there may be identical node pointers with a
4352
different page number; therefore, we set the n_fields_cmp to one
4355
dtuple_set_n_fields_cmp(tuple, n_unique);
4357
dict_index_copy_types(tuple, index, n_unique);
4359
buf = mem_heap_alloc(heap, 4);
4361
mach_write_to_4(buf, page_no);
4363
field = dtuple_get_nth_field(tuple, n_unique);
4364
dfield_set_data(field, buf, 4);
4366
dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
4368
rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
4369
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
4370
| REC_STATUS_NODE_PTR);
4372
ut_ad(dtuple_check_typed(tuple));
4377
/**********************************************************************//**
4378
Copies an initial segment of a physical record, long enough to specify an
4379
index entry uniquely.
4380
@return pointer to the prefix record */
4383
dict_index_copy_rec_order_prefix(
4384
/*=============================*/
4385
const dict_index_t* index, /*!< in: index */
4386
const rec_t* rec, /*!< in: record for which to
4388
ulint* n_fields,/*!< out: number of fields copied */
4389
byte** buf, /*!< in/out: memory buffer for the
4390
copied prefix, or NULL */
4391
ulint* buf_size)/*!< in/out: buffer size */
4395
UNIV_PREFETCH_R(rec);
4397
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
4398
ut_a(!dict_table_is_comp(index->table));
4399
n = rec_get_n_fields_old(rec);
4401
n = dict_index_get_n_unique_in_tree(index);
4405
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
4408
/**********************************************************************//**
4409
Builds a typed data tuple out of a physical record.
4410
@return own: data tuple */
4413
dict_index_build_data_tuple(
4414
/*========================*/
4415
dict_index_t* index, /*!< in: index tree */
4416
rec_t* rec, /*!< in: record for which to build data tuple */
4417
ulint n_fields,/*!< in: number of data fields */
4418
mem_heap_t* heap) /*!< in: memory heap where tuple created */
4422
ut_ad(dict_table_is_comp(index->table)
4423
|| n_fields <= rec_get_n_fields_old(rec));
4425
tuple = dtuple_create(heap, n_fields);
4427
dict_index_copy_types(tuple, index, n_fields);
4429
rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
4431
ut_ad(dtuple_check_typed(tuple));
4436
/*********************************************************************//**
4437
Calculates the minimum record length in an index. */
4440
dict_index_calc_min_rec_len(
4441
/*========================*/
4442
const dict_index_t* index) /*!< in: index */
4446
ulint comp = dict_table_is_comp(index->table);
4450
sum = REC_N_NEW_EXTRA_BYTES;
4451
for (i = 0; i < dict_index_get_n_fields(index); i++) {
4452
const dict_col_t* col
4453
= dict_index_get_nth_col(index, i);
4454
ulint size = dict_col_get_fixed_size(col, comp);
4458
sum += size < 128 ? 1 : 2;
4460
if (!(col->prtype & DATA_NOT_NULL)) {
4465
/* round the NULL flags up to full bytes */
4466
sum += UT_BITS_IN_BYTES(nullable);
4471
for (i = 0; i < dict_index_get_n_fields(index); i++) {
4472
sum += dict_col_get_fixed_size(
4473
dict_index_get_nth_col(index, i), comp);
4477
sum += 2 * dict_index_get_n_fields(index);
4479
sum += dict_index_get_n_fields(index);
4482
sum += REC_N_OLD_EXTRA_BYTES;
4487
/*********************************************************************//**
4488
functions to use SYS_STATS system table. */
4491
dict_reload_statistics(
4492
/*===================*/
4493
dict_table_t* table,
4494
ulint* sum_of_index_sizes)
4496
dict_index_t* index;
4500
index = dict_table_get_first_index(table);
4502
if (index == NULL) {
4503
/* Table definition is corrupt */
4508
heap = mem_heap_create(1000);
4513
if (UNIV_UNLIKELY(table->is_corrupt)) {
4514
ut_a(srv_pass_corrupt_table);
4515
mem_heap_free(heap);
4520
mtr_s_lock(dict_index_get_lock(index), &mtr);
4522
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
4524
index->stat_index_size = size;
4526
*sum_of_index_sizes += size;
4528
size = btr_get_size(index, BTR_N_LEAF_PAGES, &mtr);
4531
/* The root node of the tree is a leaf */
4537
index->stat_n_leaf_pages = size;
4539
/*===========================================*/
4541
dict_table_t* sys_stats;
4542
dict_index_t* sys_index;
4552
ib_int64_t* stat_n_diff_key_vals_tmp;
4553
ib_int64_t* stat_n_non_null_key_vals_tmp;
4558
n_cols = dict_index_get_n_unique(index);
4559
stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
4560
stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
4562
sys_stats = dict_sys->sys_stats;
4563
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
4564
ut_a(!dict_table_is_comp(sys_stats));
4566
tuple = dtuple_create(heap, 1);
4567
dfield = dtuple_get_nth_field(tuple, 0);
4569
buf = mem_heap_alloc(heap, 8);
4570
mach_write_to_8(buf, index->id);
4572
dfield_set_data(dfield, buf, 8);
4573
dict_index_copy_types(tuple, sys_index, 1);
4577
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
4578
BTR_SEARCH_LEAF, &pcur, &mtr);
4579
for (i = 0; i <= n_cols; i++) {
4580
rec = btr_pcur_get_rec(&pcur);
4582
if (!btr_pcur_is_on_user_rec(&pcur)
4583
|| mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
4585
/* not found: even 1 if not found should not be alowed */
4586
fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
4587
" not found in SYS_STATS\n",
4588
index->table_name, index->name, i, n_cols);
4589
btr_pcur_close(&pcur);
4591
mem_heap_free(heap);
4595
if (rec_get_deleted_flag(rec, 0)) {
4601
n_fields = rec_get_n_fields_old(rec);
4603
field = rec_get_nth_field_old(rec, 1, &len);
4606
key_cols = mach_read_from_4(field);
4608
ut_a(i == key_cols);
4610
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
4613
stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
4615
if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
4616
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
4619
stat_n_non_null_key_vals_tmp[i] = mach_read_from_8(field);
4621
/* not enough fields: should be older */
4622
fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
4623
" in SYS_STATS seems older format. "
4624
"Please execute ANALYZE TABLE for it.\n",
4625
index->table_name, index->name, i, n_cols);
4627
stat_n_non_null_key_vals_tmp[i] = ((ib_int64_t)(-1));
4630
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
4633
btr_pcur_close(&pcur);
4636
for (i = 0; i <= n_cols; i++) {
4637
index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
4638
if (stat_n_non_null_key_vals_tmp[i] == ((ib_int64_t)(-1))) {
4639
/* approximate value */
4640
index->stat_n_non_null_key_vals[i] = stat_n_diff_key_vals_tmp[n_cols];
4642
index->stat_n_non_null_key_vals[i] = stat_n_non_null_key_vals_tmp[i];
4646
/*===========================================*/
4648
index = dict_table_get_next_index(index);
4651
mem_heap_free(heap);
4657
dict_store_statistics(
4658
/*==================*/
4659
dict_table_t* table)
4661
dict_index_t* index;
4664
index = dict_table_get_first_index(table);
4668
heap = mem_heap_create(1000);
4671
if (UNIV_UNLIKELY(table->is_corrupt)) {
4672
ut_a(srv_pass_corrupt_table);
4673
mem_heap_free(heap);
4677
/*===========================================*/
4679
dict_table_t* sys_stats;
4680
dict_index_t* sys_index;
4691
ib_int64_t* stat_n_diff_key_vals_tmp;
4692
ib_int64_t* stat_n_non_null_key_vals_tmp;
4697
n_cols = dict_index_get_n_unique(index);
4698
stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
4699
stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
4701
for (i = 0; i <= n_cols; i++) {
4702
stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
4703
stat_n_non_null_key_vals_tmp[i] = index->stat_n_non_null_key_vals[i];
4706
sys_stats = dict_sys->sys_stats;
4707
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
4708
ut_a(!dict_table_is_comp(sys_stats));
4710
tuple = dtuple_create(heap, 1);
4711
dfield = dtuple_get_nth_field(tuple, 0);
4713
buf = mem_heap_alloc(heap, 8);
4714
mach_write_to_8(buf, index->id);
4716
dfield_set_data(dfield, buf, 8);
4717
dict_index_copy_types(tuple, sys_index, 1);
4721
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
4722
BTR_MODIFY_LEAF, &pcur, &mtr);
4724
for (i = 0; i <= n_cols; i++) {
4725
rec = btr_pcur_get_rec(&pcur);
4727
if (!btr_pcur_is_on_user_rec(&pcur)
4728
|| mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
4736
btr_pcur_store_position(&pcur, &mtr);
4738
if (rec_get_deleted_flag(rec, 0)) {
4744
n_fields = rec_get_n_fields_old(rec);
4746
if (n_fields <= DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
4747
/* not update for the older smaller format */
4748
fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
4749
" in SYS_STATS seems older format. Please ANALYZE TABLE it.\n",
4750
index->table_name, index->name, i, n_cols);
4754
field = rec_get_nth_field_old(rec, 1, &len);
4757
key_cols = mach_read_from_4(field);
4759
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
4762
mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
4764
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
4767
mlog_write_ull((byte*)field, stat_n_non_null_key_vals_tmp[key_cols], &mtr);
4774
btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr);
4776
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
4778
btr_pcur_close(&pcur);
4781
/*===========================================*/
4783
index = dict_table_get_next_index(index);
4786
mem_heap_free(heap);
4789
/*********************************************************************//**
4790
Calculates new estimates for table and index statistics. The statistics
4791
are used in query optimization. */
4794
dict_update_statistics(
4795
/*===================*/
4796
dict_table_t* table, /*!< in/out: table */
4797
ibool only_calc_if_missing_stats,/*!< in: only
4798
update/recalc the stats if they have
4799
not been initialized yet, otherwise
4801
ibool sync, /*!< in: TRUE if must update
4803
ibool only_calc_if_changed_too_much)/*!< in: only
4804
update/recalc the stats if the table
4805
has been changed too much since the
4806
last stats update/recalc */
4808
dict_index_t* index;
4809
ulint sum_of_index_sizes = 0;
4811
if (table->ibd_file_missing) {
4812
ut_print_timestamp(stderr);
4814
" InnoDB: cannot calculate statistics for table %s\n"
4815
"InnoDB: because the .ibd file is missing. For help,"
4816
" please refer to\n"
4817
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
4823
if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) && !sync) {
4824
dict_table_stats_lock(table, RW_X_LATCH);
4826
/* reload statistics from SYS_STATS table */
4827
if (dict_reload_statistics(table, &sum_of_index_sizes)) {
4830
fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n",
4836
dict_table_stats_unlock(table, RW_X_LATCH);
4839
fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
4842
sum_of_index_sizes = 0;
4844
/* Find out the sizes of the indexes and how many different values
4845
for the key they approximately have */
4847
index = dict_table_get_first_index(table);
4849
if (index == NULL) {
4850
/* Table definition is corrupt */
4855
dict_table_stats_lock(table, RW_X_LATCH);
4857
if ((only_calc_if_missing_stats && table->stat_initialized)
4858
|| (only_calc_if_changed_too_much
4859
&& !DICT_TABLE_CHANGED_TOO_MUCH(table))) {
4861
dict_table_stats_unlock(table, RW_X_LATCH);
4867
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
4868
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
4869
&& dict_index_is_clust(index)))) {
4873
if (UNIV_UNLIKELY(table->is_corrupt)) {
4874
ut_a(srv_pass_corrupt_table);
4875
dict_table_stats_unlock(table, RW_X_LATCH);
4880
mtr_s_lock(dict_index_get_lock(index), &mtr);
4882
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
4884
if (size != ULINT_UNDEFINED) {
4885
sum_of_index_sizes += size;
4886
index->stat_index_size = size;
4887
size = btr_get_size(
4888
index, BTR_N_LEAF_PAGES, &mtr);
4894
case ULINT_UNDEFINED:
4895
goto fake_statistics;
4897
/* The root node of the tree is a leaf */
4901
index->stat_n_leaf_pages = size;
4903
btr_estimate_number_of_different_key_vals(index);
4905
/* If we have set a high innodb_force_recovery
4906
level, do not calculate statistics, as a badly
4907
corrupted index can cause a crash in it.
4908
Initialize some bogus index cardinality
4909
statistics, so that the data can be queried in
4910
various means, also via secondary indexes. */
4914
sum_of_index_sizes++;
4915
index->stat_index_size = index->stat_n_leaf_pages = 1;
4917
for (i = dict_index_get_n_unique(index); i; ) {
4918
index->stat_n_diff_key_vals[i--] = 1;
4921
memset(index->stat_n_non_null_key_vals, 0,
4922
(1 + dict_index_get_n_unique(index))
4923
* sizeof(*index->stat_n_non_null_key_vals));
4926
index = dict_table_get_next_index(index);
4929
if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) {
4930
/* store statistics to SYS_STATS table */
4931
dict_store_statistics(table);
4934
index = dict_table_get_first_index(table);
4936
table->stat_n_rows = index->stat_n_diff_key_vals[
4937
dict_index_get_n_unique(index)];
4939
table->stat_clustered_index_size = index->stat_index_size;
4941
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
4942
- index->stat_index_size;
4944
table->stat_initialized = TRUE;
4946
table->stat_modified_counter = 0;
4948
dict_table_stats_unlock(table, RW_X_LATCH);
4951
/*********************************************************************//**
4955
dict_is_older_statistics(
4956
/*=====================*/
4957
dict_index_t* index)
4960
dict_table_t* sys_stats;
4961
dict_index_t* sys_index;
4971
heap = mem_heap_create(100);
4973
sys_stats = dict_sys->sys_stats;
4974
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
4975
ut_a(!dict_table_is_comp(sys_stats));
4977
tuple = dtuple_create(heap, 1);
4978
dfield = dtuple_get_nth_field(tuple, 0);
4980
buf = mem_heap_alloc(heap, 8);
4981
mach_write_to_8(buf, index->id);
4983
dfield_set_data(dfield, buf, 8);
4984
dict_index_copy_types(tuple, sys_index, 1);
4988
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
4989
BTR_SEARCH_LEAF, &pcur, &mtr);
4992
rec = btr_pcur_get_rec(&pcur);
4994
if (!btr_pcur_is_on_user_rec(&pcur)
4995
|| mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
4998
btr_pcur_close(&pcur);
5000
mem_heap_free(heap);
5001
/* no statistics == not older statistics */
5005
if (rec_get_deleted_flag(rec, 0)) {
5006
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
5010
n_fields = rec_get_n_fields_old(rec);
5012
btr_pcur_close(&pcur);
5014
mem_heap_free(heap);
5016
if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
5023
#ifndef UNIV_HOTBACKUP
5024
/**********************************************************************//**
5025
Prints info of a foreign key constraint. */
5028
dict_foreign_print_low(
5029
/*===================*/
5030
dict_foreign_t* foreign) /*!< in: foreign key constraint */
5034
ut_ad(mutex_own(&(dict_sys->mutex)));
5036
fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
5037
foreign->id, foreign->foreign_table_name);
5039
for (i = 0; i < foreign->n_fields; i++) {
5040
fprintf(stderr, " %s", foreign->foreign_col_names[i]);
5043
fprintf(stderr, " )\n"
5045
foreign->referenced_table_name);
5047
for (i = 0; i < foreign->n_fields; i++) {
5048
fprintf(stderr, " %s", foreign->referenced_col_names[i]);
5051
fputs(" )\n", stderr);
5054
#endif /* !UNIV_HOTBACKUP */
5055
/**********************************************************************//**
5056
Prints a table data. */
5061
dict_table_t* table) /*!< in: table */
5063
mutex_enter(&(dict_sys->mutex));
5064
dict_table_print_low(table);
5065
mutex_exit(&(dict_sys->mutex));
5068
/**********************************************************************//**
5069
Prints a table data when we know the table name. */
5072
dict_table_print_by_name(
5073
/*=====================*/
5074
const char* name) /*!< in: table name */
5076
dict_table_t* table;
5078
mutex_enter(&(dict_sys->mutex));
5080
table = dict_table_get_low(name);
5084
dict_table_print_low(table);
5085
mutex_exit(&(dict_sys->mutex));
5088
/**********************************************************************//**
5089
Prints a table data. */
5092
dict_table_print_low(
5093
/*=================*/
5094
dict_table_t* table) /*!< in: table */
5096
dict_index_t* index;
5097
dict_foreign_t* foreign;
5100
ut_ad(mutex_own(&(dict_sys->mutex)));
5102
if (srv_stats_auto_update) {
5104
dict_update_statistics(
5106
FALSE /* update even if initialized */,
5108
FALSE /* update even if not changed too much */);
5111
dict_table_stats_lock(table, RW_S_LATCH);
5114
"--------------------------------------\n"
5115
"TABLE: name %s, id %llu, flags %lx, columns %lu,"
5116
" indexes %lu, appr.rows %lu\n"
5120
(ulong) table->flags,
5121
(ulong) table->n_cols,
5122
(ulong) UT_LIST_GET_LEN(table->indexes),
5123
(ulong) table->stat_n_rows);
5125
for (i = 0; i < (ulint) table->n_cols; i++) {
5126
dict_col_print_low(table, dict_table_get_nth_col(table, i));
5127
fputs("; ", stderr);
5132
index = UT_LIST_GET_FIRST(table->indexes);
5134
while (index != NULL) {
5135
dict_index_print_low(index);
5136
index = UT_LIST_GET_NEXT(indexes, index);
5139
dict_table_stats_unlock(table, RW_S_LATCH);
5141
foreign = UT_LIST_GET_FIRST(table->foreign_list);
5143
while (foreign != NULL) {
5144
dict_foreign_print_low(foreign);
5145
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
5148
foreign = UT_LIST_GET_FIRST(table->referenced_list);
5150
while (foreign != NULL) {
5151
dict_foreign_print_low(foreign);
5152
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
5156
/**********************************************************************//**
5157
Prints a column data. */
5162
const dict_table_t* table, /*!< in: table */
5163
const dict_col_t* col) /*!< in: column */
5167
ut_ad(mutex_own(&(dict_sys->mutex)));
5169
dict_col_copy_type(col, &type);
5170
fprintf(stderr, "%s: ", dict_table_get_col_name(table,
5171
dict_col_get_no(col)));
5176
/**********************************************************************//**
5177
Prints an index data. */
5180
dict_index_print_low(
5181
/*=================*/
5182
dict_index_t* index) /*!< in: index */
5187
ut_ad(mutex_own(&(dict_sys->mutex)));
5189
if (index->n_user_defined_cols > 0) {
5190
n_vals = index->stat_n_diff_key_vals[
5191
index->n_user_defined_cols];
5193
n_vals = index->stat_n_diff_key_vals[1];
5197
" INDEX: name %s, id %llu, fields %lu/%lu,"
5198
" uniq %lu, type %lu\n"
5199
" root page %lu, appr.key vals %lu,"
5200
" leaf pages %lu, size pages %lu\n"
5204
(ulong) index->n_user_defined_cols,
5205
(ulong) index->n_fields,
5206
(ulong) index->n_uniq,
5207
(ulong) index->type,
5208
(ulong) index->page,
5210
(ulong) index->stat_n_leaf_pages,
5211
(ulong) index->stat_index_size);
5213
for (i = 0; i < index->n_fields; i++) {
5214
dict_field_print_low(dict_index_get_nth_field(index, i));
5219
#ifdef UNIV_BTR_PRINT
5220
btr_print_size(index);
5222
btr_print_index(index, 7);
5223
#endif /* UNIV_BTR_PRINT */
5226
/**********************************************************************//**
5227
Prints a field data. */
5230
dict_field_print_low(
5231
/*=================*/
5232
const dict_field_t* field) /*!< in: field */
5234
ut_ad(mutex_own(&(dict_sys->mutex)));
5236
fprintf(stderr, " %s", field->name);
5238
if (field->prefix_len != 0) {
5239
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
5243
#ifndef UNIV_HOTBACKUP
5244
/**********************************************************************//**
5245
Outputs info on a foreign key of a table in a format suitable for
5249
dict_print_info_on_foreign_key_in_create_format(
5250
/*============================================*/
5251
FILE* file, /*!< in: file where to print */
5252
trx_t* trx, /*!< in: transaction */
5253
dict_foreign_t* foreign, /*!< in: foreign key constraint */
5254
ibool add_newline) /*!< in: whether to add a newline */
5256
const char* stripped_id;
5259
if (strchr(foreign->id, '/')) {
5260
/* Strip the preceding database name from the constraint id */
5261
stripped_id = foreign->id + 1
5262
+ dict_get_db_name_len(foreign->id);
5264
stripped_id = foreign->id;
5270
/* SHOW CREATE TABLE wants constraints each printed nicely
5271
on its own line, while error messages want no newlines
5276
fputs(" CONSTRAINT ", file);
5277
ut_print_name(file, trx, FALSE, stripped_id);
5278
fputs(" FOREIGN KEY (", file);
5281
ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
5282
if (++i < foreign->n_fields) {
5289
fputs(") REFERENCES ", file);
5291
if (dict_tables_have_same_db(foreign->foreign_table_name_lookup,
5292
foreign->referenced_table_name_lookup)) {
5293
/* Do not print the database name of the referenced table */
5294
ut_print_name(file, trx, TRUE,
5295
dict_remove_db_name(
5296
foreign->referenced_table_name));
5298
ut_print_name(file, trx, TRUE,
5299
foreign->referenced_table_name);
5306
ut_print_name(file, trx, FALSE,
5307
foreign->referenced_col_names[i]);
5308
if (++i < foreign->n_fields) {
5317
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
5318
fputs(" ON DELETE CASCADE", file);
5321
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
5322
fputs(" ON DELETE SET NULL", file);
5325
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
5326
fputs(" ON DELETE NO ACTION", file);
5329
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
5330
fputs(" ON UPDATE CASCADE", file);
5333
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
5334
fputs(" ON UPDATE SET NULL", file);
5337
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
5338
fputs(" ON UPDATE NO ACTION", file);
5342
/**********************************************************************//**
5343
Outputs info on foreign keys of a table. */
5346
dict_print_info_on_foreign_keys(
5347
/*============================*/
5348
ibool create_table_format, /*!< in: if TRUE then print in
5349
a format suitable to be inserted into
5350
a CREATE TABLE, otherwise in the format
5351
of SHOW TABLE STATUS */
5352
FILE* file, /*!< in: file where to print */
5353
trx_t* trx, /*!< in: transaction */
5354
dict_table_t* table) /*!< in: table */
5356
dict_foreign_t* foreign;
5358
mutex_enter(&(dict_sys->mutex));
5360
foreign = UT_LIST_GET_FIRST(table->foreign_list);
5362
if (foreign == NULL) {
5363
mutex_exit(&(dict_sys->mutex));
5368
while (foreign != NULL) {
5369
if (create_table_format) {
5370
dict_print_info_on_foreign_key_in_create_format(
5371
file, trx, foreign, TRUE);
5376
for (i = 0; i < foreign->n_fields; i++) {
5381
ut_print_name(file, trx, FALSE,
5382
foreign->foreign_col_names[i]);
5385
fputs(") REFER ", file);
5386
ut_print_name(file, trx, TRUE,
5387
foreign->referenced_table_name);
5390
for (i = 0; i < foreign->n_fields; i++) {
5396
foreign->referenced_col_names[i]);
5401
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
5402
fputs(" ON DELETE CASCADE", file);
5405
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
5406
fputs(" ON DELETE SET NULL", file);
5409
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
5410
fputs(" ON DELETE NO ACTION", file);
5413
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
5414
fputs(" ON UPDATE CASCADE", file);
5417
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
5418
fputs(" ON UPDATE SET NULL", file);
5421
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
5422
fputs(" ON UPDATE NO ACTION", file);
5426
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
5429
mutex_exit(&(dict_sys->mutex));
5432
#endif /* !UNIV_HOTBACKUP */
5433
/********************************************************************//**
5434
Displays the names of the index and the table. */
5437
dict_index_name_print(
5438
/*==================*/
5439
FILE* file, /*!< in: output stream */
5440
trx_t* trx, /*!< in: transaction */
5441
const dict_index_t* index) /*!< in: index to print */
5443
fputs("index ", file);
5444
ut_print_name(file, trx, FALSE, index->name);
5445
fputs(" of table ", file);
5446
ut_print_name(file, trx, TRUE, index->table_name);
5448
#endif /* !UNIV_HOTBACKUP */
5450
/**********************************************************************//**
5451
Inits dict_ind_redundant and dict_ind_compact. */
5457
dict_table_t* table;
5459
/* create dummy table and index for REDUNDANT infimum and supremum */
5460
table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
5461
dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
5462
DATA_ENGLISH | DATA_NOT_NULL, 8);
5464
dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
5465
DICT_HDR_SPACE, 0, 1);
5466
dict_index_add_col(dict_ind_redundant, table,
5467
dict_table_get_nth_col(table, 0), 0);
5468
dict_ind_redundant->table = table;
5469
/* create dummy table and index for COMPACT infimum and supremum */
5470
table = dict_mem_table_create("SYS_DUMMY2",
5471
DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
5472
dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
5473
DATA_ENGLISH | DATA_NOT_NULL, 8);
5474
dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
5475
DICT_HDR_SPACE, 0, 1);
5476
dict_index_add_col(dict_ind_compact, table,
5477
dict_table_get_nth_col(table, 0), 0);
5478
dict_ind_compact->table = table;
5480
/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
5481
dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
5484
/**********************************************************************//**
5485
Frees dict_ind_redundant and dict_ind_compact. */
5491
dict_table_t* table;
5493
table = dict_ind_compact->table;
5494
dict_mem_index_free(dict_ind_compact);
5495
dict_ind_compact = NULL;
5496
dict_mem_table_free(table);
5498
table = dict_ind_redundant->table;
5499
dict_mem_index_free(dict_ind_redundant);
5500
dict_ind_redundant = NULL;
5501
dict_mem_table_free(table);
5504
#ifndef UNIV_HOTBACKUP
5505
/**********************************************************************//**
5507
@return index, NULL if does not exist */
5510
dict_table_get_index_on_name(
5511
/*=========================*/
5512
dict_table_t* table, /*!< in: table */
5513
const char* name) /*!< in: name of the index to find */
5515
dict_index_t* index;
5517
index = dict_table_get_first_index(table);
5519
while (index != NULL) {
5520
if (ut_strcmp(index->name, name) == 0) {
5525
index = dict_table_get_next_index(index);
5532
/**********************************************************************//**
5533
Replace the index passed in with another equivalent index in the tables
5534
foreign key list. */
5537
dict_table_replace_index_in_foreign_list(
5538
/*=====================================*/
5539
dict_table_t* table, /*!< in/out: table */
5540
dict_index_t* index, /*!< in: index to be replaced */
5541
const trx_t* trx) /*!< in: transaction handle */
5543
dict_foreign_t* foreign;
5545
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
5547
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
5549
if (foreign->foreign_index == index) {
5550
dict_index_t* new_index
5551
= dict_foreign_find_equiv_index(foreign);
5553
/* There must exist an alternative index if
5554
check_foreigns (FOREIGN_KEY_CHECKS) is on,
5555
since ha_innobase::prepare_drop_index had done
5556
the check before we reach here. */
5558
ut_a(new_index || !trx->check_foreigns);
5560
foreign->foreign_index = new_index;
5565
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
5567
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
5569
dict_index_t* new_index;
5571
if (foreign->referenced_index == index) {
5572
ut_ad(foreign->referenced_table == index->table);
5574
new_index = dict_foreign_find_index(
5575
foreign->referenced_table,
5576
foreign->referenced_col_names,
5577
foreign->n_fields, index,
5578
/*check_charsets=*/TRUE, /*check_null=*/FALSE);
5579
ut_ad(new_index || !trx->check_foreigns);
5580
ut_ad(!new_index || new_index->table == index->table);
5582
foreign->referenced_index = new_index;
5587
/**********************************************************************//**
5588
In case there is more than one index with the same name return the index
5590
@return index, NULL if does not exist */
5593
dict_table_get_index_on_name_and_min_id(
5594
/*=====================================*/
5595
dict_table_t* table, /*!< in: table */
5596
const char* name) /*!< in: name of the index to find */
5598
dict_index_t* index;
5599
dict_index_t* min_index; /* Index with matching name and min(id) */
5602
index = dict_table_get_first_index(table);
5604
while (index != NULL) {
5605
if (ut_strcmp(index->name, name) == 0) {
5606
if (!min_index || index->id < min_index->id) {
5612
index = dict_table_get_next_index(index);
5620
/**********************************************************************//**
5621
Check for duplicate index entries in a table [using the index name] */
5624
dict_table_check_for_dup_indexes(
5625
/*=============================*/
5626
const dict_table_t* table, /*!< in: Check for dup indexes
5628
ibool tmp_ok) /*!< in: TRUE=allow temporary
5631
/* Check for duplicates, ignoring indexes that are marked
5634
const dict_index_t* index1;
5635
const dict_index_t* index2;
5637
ut_ad(mutex_own(&dict_sys->mutex));
5639
/* The primary index _must_ exist */
5640
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
5642
index1 = UT_LIST_GET_FIRST(table->indexes);
5645
ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);
5647
index2 = UT_LIST_GET_NEXT(indexes, index1);
5651
if (!index2->to_be_dropped) {
5652
ut_ad(ut_strcmp(index1->name, index2->name));
5655
index2 = UT_LIST_GET_NEXT(indexes, index2);
5658
index1 = UT_LIST_GET_NEXT(indexes, index1);
5661
#endif /* UNIV_DEBUG */
5663
/**************************************************************************
5664
Closes the data dictionary module. */
5672
/* Free the hash elements. We don't remove them from the table
5673
because we are going to destroy the table anyway. */
5674
for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
5675
dict_table_t* table;
5677
table = HASH_GET_FIRST(dict_sys->table_hash, i);
5680
dict_table_t* prev_table = table;
5682
table = HASH_GET_NEXT(name_hash, prev_table);
5684
ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
5686
/* Acquire only because it's a pre-condition. */
5687
mutex_enter(&dict_sys->mutex);
5689
dict_table_remove_from_cache(prev_table);
5691
mutex_exit(&dict_sys->mutex);
5695
hash_table_free(dict_sys->table_hash);
5697
/* The elements are the same instance as in dict_sys->table_hash,
5698
therefore we don't delete the individual elements. */
5699
hash_table_free(dict_sys->table_id_hash);
5703
mutex_free(&dict_sys->mutex);
5705
rw_lock_free(&dict_operation_lock);
5706
memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
5708
mutex_free(&dict_foreign_err_mutex);
5713
for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
5714
rw_lock_free(&dict_table_stats_latches[i]);
5718
/**********************************************************************//**
5719
Find a table in dict_sys->table_LRU list with specified space id
5720
@return table if found, NULL if not */
5723
dict_find_table_by_space(
5724
/*=====================*/
5725
ulint space_id) /*!< in: space ID */
5727
dict_table_t* table;
5731
ut_ad(space_id > 0);
5733
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
5734
num_item = UT_LIST_GET_LEN(dict_sys->table_LRU);
5736
/* This function intentionally does not acquire mutex as it is used
5737
by error handling code in deep call stack as last means to avoid
5738
killing the server, so it worth to risk some consequencies for
5740
while (table && count < num_item) {
5741
if (table->space == space_id) {
5745
table = UT_LIST_GET_NEXT(table_LRU, table);
5752
/**********************************************************************//**
5753
Flags a table with specified space_id corrupted in the data dictionary
5755
@return TRUE if successful */
5758
dict_set_corrupted_by_space(
5759
/*========================*/
5760
ulint space_id) /*!< in: space ID */
5762
dict_table_t* table;
5764
table = dict_find_table_by_space(space_id);
5770
/* mark the table->corrupted bit only, since the caller
5771
could be too deep in the stack for SYS_INDEXES update */
5772
table->corrupted = TRUE;
5777
/**********************************************************************//**
5778
Flags an index corrupted both in the data dictionary cache
5779
and in the SYS_INDEXES */
5784
dict_index_t* index) /*!< in/out: index */
5788
dict_index_t* sys_index;
5796
ut_ad(mutex_own(&dict_sys->mutex));
5797
ut_ad(!dict_table_is_comp(dict_sys->sys_tables));
5798
ut_ad(!dict_table_is_comp(dict_sys->sys_indexes));
5800
#ifdef UNIV_SYNC_DEBUG
5801
ut_ad(sync_thread_levels_empty_except_dict());
5804
/* Mark the table as corrupted only if the clustered index
5806
if (dict_index_is_clust(index)) {
5807
index->table->corrupted = TRUE;
5810
if (UNIV_UNLIKELY(dict_index_is_corrupted(index))) {
5811
/* The index was already flagged corrupted. */
5812
ut_ad(index->table->corrupted);
5816
heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
5817
+ sizeof(que_fork_t) + sizeof(upd_node_t)
5818
+ sizeof(upd_t) + 12));
5820
index->type |= DICT_CORRUPT;
5822
sys_index = UT_LIST_GET_FIRST(dict_sys->sys_indexes->indexes);
5824
/* Find the index row in SYS_INDEXES */
5825
tuple = dtuple_create(heap, 2);
5827
dfield = dtuple_get_nth_field(tuple, 0);
5828
buf = mem_heap_alloc(heap, 8);
5829
mach_write_to_8(buf, index->table->id);
5830
dfield_set_data(dfield, buf, 8);
5832
dfield = dtuple_get_nth_field(tuple, 1);
5833
buf = mem_heap_alloc(heap, 8);
5834
mach_write_to_8(buf, index->id);
5835
dfield_set_data(dfield, buf, 8);
5837
dict_index_copy_types(tuple, sys_index, 2);
5839
btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE,
5841
&cursor, 0, __FILE__, __LINE__, &mtr);
5843
if (cursor.up_match == dtuple_get_n_fields(tuple)) {
5844
/* UPDATE SYS_INDEXES SET TYPE=index->type
5845
WHERE TABLE_ID=index->table->id AND INDEX_ID=index->id */
5847
byte* field = rec_get_nth_field_old(
5848
btr_cur_get_rec(&cursor),
5849
DICT_SYS_INDEXES_TYPE_FIELD, &len);
5853
mlog_write_ulint(field, index->type, MLOG_4BYTES, &mtr);
5854
status = " InnoDB: Flagged corruption of ";
5857
status = " InnoDB: Unable to flag corruption of ";
5861
mem_heap_free(heap);
5863
ut_print_timestamp(stderr);
5864
fputs(status, stderr);
5865
dict_index_name_print(stderr, NULL, index);
5869
/**********************************************************************//**
5870
Flags an index corrupted in the data dictionary cache only. This
5871
is used mostly to mark a corrupted index when index's own dictionary
5872
is corrupted, and we force to load such index for repair purpose */
5875
dict_set_corrupted_index_cache_only(
5876
/*================================*/
5877
dict_index_t* index, /*!< in/out: index */
5878
dict_table_t* table) /*!< in/out: table */
5881
ut_ad(mutex_own(&dict_sys->mutex));
5882
ut_ad(!dict_table_is_comp(dict_sys->sys_tables));
5883
ut_ad(!dict_table_is_comp(dict_sys->sys_indexes));
5885
/* Mark the table as corrupted only if the clustered index
5887
if (dict_index_is_clust(index)) {
5888
dict_table_t* corrupt_table;
5890
corrupt_table = table ? table : index->table;
5891
ut_ad(!index->table || !table || index->table == table);
5893
if (corrupt_table) {
5894
corrupt_table->corrupted = TRUE;
5898
index->type |= DICT_CORRUPT;
5901
/*************************************************************************
5902
set is_corrupt flag by space_id*/
5905
dict_table_set_corrupt_by_space(
5906
/*============================*/
5910
dict_table_t* table;
5911
ibool found = FALSE;
5913
ut_a(!trx_sys_sys_space(space_id) && space_id < SRV_LOG_SPACE_FIRST_ID);
5916
mutex_enter(&(dict_sys->mutex));
5918
table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
5921
if (table->space == space_id) {
5922
table->is_corrupt = TRUE;
5926
table = UT_LIST_GET_NEXT(table_LRU, table);
5930
mutex_exit(&(dict_sys->mutex));
5933
fprintf(stderr, "InnoDB: space to be marked as "
5934
"crashed was not found for id %lu.\n",
5938
#endif /* !UNIV_HOTBACKUP */