1
1
/*****************************************************************************
3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
11
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
17
*****************************************************************************/
69
69
on the mode in trx_struct::dict_operation_lock_mode */
70
70
UNIV_INTERN rw_lock_t dict_operation_lock;
72
/* Keys to register rwlocks and mutexes with performance schema */
73
#ifdef UNIV_PFS_RWLOCK
74
UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key;
75
UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key;
76
#endif /* UNIV_PFS_RWLOCK */
79
UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key;
80
UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
81
#endif /* UNIV_PFS_MUTEX */
83
72
#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
84
73
creating a table or index object */
85
74
#define DICT_POOL_PER_TABLE_HASH 512 /*!< buffer pool max size per table
90
79
/** Identifies generated InnoDB foreign key names */
91
80
static char dict_ibfk[] = "_ibfk_";
93
/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */
94
#define DICT_INDEX_STAT_MUTEX_SIZE 32
95
static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
97
82
/*******************************************************************//**
98
83
Tries to find column names for the index and sets the col field of the
100
@return TRUE if the column names were found */
103
87
dict_index_find_cols(
104
88
/*=================*/
105
89
dict_table_t* table, /*!< in: table */
253
237
mutex_exit(&(dict_sys->mutex));
256
/** Get the mutex that protects index->stat_n_diff_key_vals[] */
257
#define GET_INDEX_STAT_MUTEX(index) \
258
(&dict_index_stat_mutex[ut_fold_ull(index->id) \
259
% DICT_INDEX_STAT_MUTEX_SIZE])
261
/**********************************************************************//**
262
Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
263
index->id is used to pick the right mutex and it should not change
264
before dict_index_stat_mutex_exit() is called on this index. */
267
dict_index_stat_mutex_enter(
268
/*========================*/
269
const dict_index_t* index) /*!< in: index */
271
ut_ad(index != NULL);
272
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
273
ut_ad(index->cached);
274
ut_ad(!index->to_be_dropped);
276
mutex_enter(GET_INDEX_STAT_MUTEX(index));
279
/**********************************************************************//**
280
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
283
dict_index_stat_mutex_exit(
284
/*=======================*/
285
const dict_index_t* index) /*!< in: index */
287
ut_ad(index != NULL);
288
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
289
ut_ad(index->cached);
290
ut_ad(!index->to_be_dropped);
292
mutex_exit(GET_INDEX_STAT_MUTEX(index));
295
240
/********************************************************************//**
296
241
Decrements the count of open MySQL handles to a table. */
424
369
dict_index_get_on_id_low(
425
370
/*=====================*/
426
371
dict_table_t* table, /*!< in: table */
427
index_id_t id) /*!< in: index id */
372
dulint id) /*!< in: index id */
429
374
dict_index_t* index;
431
376
index = dict_table_get_first_index(table);
434
if (id == index->id) {
379
if (0 == ut_dulint_cmp(id, index->id)) {
574
519
dict_table_get_on_id(
575
520
/*=================*/
576
table_id_t table_id, /*!< in: table id */
577
trx_t* trx) /*!< in: transaction handle */
521
dulint table_id, /*!< in: table id */
522
trx_t* trx) /*!< in: transaction handle */
579
524
dict_table_t* table;
581
if (trx->dict_operation_lock_mode == RW_X_LATCH) {
583
/* Note: An X latch implies that the transaction
584
already owns the dictionary mutex. */
586
ut_ad(mutex_own(&dict_sys->mutex));
526
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
527
|| trx->dict_operation_lock_mode == RW_X_LATCH) {
528
/* It is a system table which will always exist in the table
529
cache: we avoid acquiring the dictionary mutex, because
530
if we are doing a rollback to handle an error in TABLE
531
CREATE, for example, we already have the mutex! */
533
ut_ad(mutex_own(&(dict_sys->mutex))
534
|| trx->dict_operation_lock_mode == RW_X_LATCH);
588
536
return(dict_table_get_on_id_low(table_id));
660
606
dict_sys = mem_alloc(sizeof(dict_sys_t));
662
mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
608
mutex_create(&dict_sys->mutex, SYNC_DICT);
664
610
dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
665
611
/ (DICT_POOL_PER_TABLE_HASH
672
618
UT_LIST_INIT(dict_sys->table_LRU);
674
rw_lock_create(dict_operation_lock_key,
675
&dict_operation_lock, SYNC_DICT_OPERATION);
620
rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
677
622
dict_foreign_err_file = os_file_create_tmpfile();
678
623
ut_a(dict_foreign_err_file);
680
mutex_create(dict_foreign_err_mutex_key,
681
&dict_foreign_err_mutex, SYNC_ANY_LATCH);
683
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
684
mutex_create(PFS_NOT_INSTRUMENTED,
685
&dict_index_stat_mutex[i], SYNC_INDEX_TREE);
625
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
689
628
/**********************************************************************//**
838
777
dict_table_t* table2;
839
778
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
840
779
dict_table_t*, table2, ut_ad(table2->cached),
841
table2->id == table->id);
780
ut_dulint_cmp(table2->id, table->id) == 0);
842
781
ut_a(table2 == NULL);
844
783
#ifdef UNIV_DEBUG
860
799
/* Add table to LRU list of tables */
861
800
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
863
dict_sys->size += mem_heap_get_size(table->heap)
864
+ strlen(table->name) + 1;
802
dict_sys->size += mem_heap_get_size(table->heap);
867
805
/**********************************************************************//**
915
853
dict_foreign_t* foreign;
916
854
dict_index_t* index;
918
char old_name[MAX_TABLE_NAME_LEN + 1];
857
const char* old_name;
921
860
ut_ad(mutex_own(&(dict_sys->mutex)));
923
/* store the old/current name to an automatic variable */
924
if (strlen(table->name) + 1 <= sizeof(old_name)) {
925
memcpy(old_name, table->name, strlen(table->name) + 1);
927
ut_print_timestamp(stderr);
928
fprintf(stderr, "InnoDB: too long table name: '%s', "
929
"max length is %d\n", table->name,
862
old_size = mem_heap_get_size(table->heap);
863
old_name = table->name;
934
865
fold = ut_fold_string(new_name);
975
906
/* Remove table from the hash tables of tables */
976
907
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
977
908
ut_fold_string(old_name), table);
979
if (strlen(new_name) > strlen(table->name)) {
980
/* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
981
memory fragmentation, we assume a repeated calls of
982
ut_realloc() with the same size do not cause fragmentation */
983
ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
984
table->name = ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1);
986
memcpy(table->name, new_name, strlen(new_name) + 1);
909
table->name = mem_heap_strdup(table->heap, new_name);
988
911
/* Add table to hash table of tables */
989
912
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
992
dict_sys->size += strlen(new_name) - strlen(old_name);
993
ut_a(dict_sys->size > 0);
914
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
995
916
/* Update the table_name field in indexes */
996
917
index = dict_table_get_first_index(table);
1140
1061
dict_table_change_id_in_cache(
1141
1062
/*==========================*/
1142
1063
dict_table_t* table, /*!< in/out: table object already in cache */
1143
table_id_t new_id) /*!< in: new id to set */
1064
dulint new_id) /*!< in: new id to set */
1146
1067
ut_ad(mutex_own(&(dict_sys->mutex)));
1149
1070
/* Remove the table from the hash table of id's */
1151
1072
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1152
ut_fold_ull(table->id), table);
1073
ut_fold_dulint(table->id), table);
1153
1074
table->id = new_id;
1155
1076
/* Add the table back to the hash table */
1156
1077
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1157
ut_fold_ull(table->id), table);
1078
ut_fold_dulint(table->id), table);
1160
1081
/**********************************************************************//**
1210
1131
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1211
1132
ut_fold_string(table->name), table);
1212
1133
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1213
ut_fold_ull(table->id), table);
1134
ut_fold_dulint(table->id), table);
1215
1136
/* Remove table from LRU list of tables */
1216
1137
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1218
size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
1139
size = mem_heap_get_size(table->heap);
1220
1141
ut_ad(dict_sys->size >= size);
1277
1198
= TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
1278
1199
+ 2 /* next record pointer */
1279
1200
+ 1 /* type_cmpl */
1280
+ 11 /* trx->undo_no */ + 11 /* table->id */
1201
+ 11 /* trx->undo_no */ - 11 /* table->id */
1281
1202
+ 1 /* rec_get_info_bits() */
1282
1203
+ 11 /* DB_TRX_ID */
1283
1204
+ 11 /* DB_ROLL_PTR */
1510
1431
/**********************************************************************//**
1511
1432
Adds an index to the dictionary cache.
1512
@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
1433
@return DB_SUCCESS or DB_TOO_BIG_RECORD */
1515
1436
dict_index_add_to_cache(
1535
1456
ut_a(!dict_index_is_clust(index)
1536
1457
|| UT_LIST_GET_LEN(table->indexes) == 0);
1538
if (!dict_index_find_cols(table, index)) {
1540
dict_mem_index_free(index);
1541
return(DB_CORRUPTION);
1459
dict_index_find_cols(table, index);
1544
1461
/* Build the cache internal representation of the index,
1545
1462
containing also the added system fields */
1644
1561
new_index->stat_n_leaf_pages = 1;
1646
1563
new_index->page = page_no;
1647
rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
1564
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1650
1566
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1749
1665
/*******************************************************************//**
1750
1666
Tries to find column names for the index and sets the col field of the
1752
@return TRUE if the column names were found */
1755
1670
dict_index_find_cols(
1756
1671
/*=================*/
1757
1672
dict_table_t* table, /*!< in: table */
1780
1694
/* It is an error not to find a matching column. */
1781
1695
fputs("InnoDB: Error: no matching column for ", stderr);
1782
1696
ut_print_name(stderr, NULL, FALSE, field->name);
1783
1697
fputs(" in ", stderr);
1784
1698
dict_index_name_print(stderr, NULL, index);
1785
1699
fputs("!\n", stderr);
1786
#endif /* UNIV_DEBUG */
1795
1706
#endif /* !UNIV_HOTBACKUP */
2472
2383
/* We found a matching index, select
2473
2384
the index with the higher id*/
2475
if (!found || index->id > found->id) {
2387
|| ut_dulint_cmp(index->id, found->id) > 0) {
3037
2949
dict_strip_comments(
3038
2950
/*================*/
3039
const char* sql_string, /*!< in: SQL string */
3040
size_t sql_length) /*!< in: length of sql_string */
2951
const char* sql_string) /*!< in: SQL string */
3043
2954
const char* sptr;
3044
const char* eptr = sql_string + sql_length;
3046
2956
/* unclosed quote character (0 if none) */
3047
2957
char quote = 0;
3049
str = mem_alloc(sql_length + 1);
2959
str = mem_alloc(strlen(sql_string) + 1);
3051
2961
sptr = sql_string;
3056
if (sptr >= eptr || *sptr == '\0') {
2966
if (*sptr == '\0') {
3060
ut_a(ptr <= str + sql_length);
2969
ut_a(ptr <= str + strlen(sql_string));
3076
2985
|| (sptr[0] == '-' && sptr[1] == '-'
3077
2986
&& sptr[2] == ' ')) {
3079
if (++sptr >= eptr) {
3083
2988
/* In Unix a newline is 0x0A while in Windows
3084
2989
it is 0x0D followed by 0x0A */
2991
if (*sptr == (char)0x0A
2992
|| *sptr == (char)0x0D
3090
2995
goto scan_more;
3093
3000
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3002
if (*sptr == '*' && *(sptr + 1) == '/') {
3009
if (*sptr == '\0') {
3102
3011
goto scan_more;
3104
if (sptr[1] == '/') {
3785
3689
name before it: test.table2; the
3786
3690
default database id the database of
3787
3691
parameter name */
3788
size_t sql_length, /*!< in: length of sql_string */
3789
3692
const char* name, /*!< in: table full name in the
3790
3693
normalized form
3791
3694
database_name/table_name */
3801
3704
ut_a(trx->mysql_thd);
3803
str = dict_strip_comments(sql_string, sql_length);
3706
str = dict_strip_comments(sql_string);
3804
3707
heap = mem_heap_create(10000);
3806
3709
err = dict_create_foreign_constraints_low(
3849
3751
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3851
ptr = innobase_get_stmt(trx->mysql_thd, &len);
3853
str = dict_strip_comments(ptr, len);
3753
str = dict_strip_comments((trx->mysql_query_str));
3857
3756
ut_ad(mutex_own(&(dict_sys->mutex)));
3961
3860
dict_index_get_if_in_cache_low(
3962
3861
/*===========================*/
3963
index_id_t index_id) /*!< in: index id */
3862
dulint index_id) /*!< in: index id */
3965
3864
ut_ad(mutex_own(&(dict_sys->mutex)));
4121
/* If we have set a high innodb_force_recovery level, do not calculate
4122
statistics, as a badly corrupted index can cause a crash in it. */
4124
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
4221
4129
/* Find out the sizes of the indexes and how many different values
4222
4130
for the key they approximately have */
4235
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
4236
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
4237
&& dict_index_is_clust(index)))) {
4239
size = btr_get_size(index, BTR_TOTAL_SIZE);
4241
index->stat_index_size = size;
4243
sum_of_index_sizes += size;
4245
size = btr_get_size(index, BTR_N_LEAF_PAGES);
4248
/* The root node of the tree is a leaf */
4252
index->stat_n_leaf_pages = size;
4254
btr_estimate_number_of_different_key_vals(index);
4256
/* If we have set a high innodb_force_recovery
4257
level, do not calculate statistics, as a badly
4258
corrupted index can cause a crash in it.
4259
Initialize some bogus index cardinality
4260
statistics, so that the data can be queried in
4261
various means, also via secondary indexes. */
4264
sum_of_index_sizes++;
4265
index->stat_index_size = index->stat_n_leaf_pages = 1;
4267
for (i = dict_index_get_n_unique(index); i; ) {
4268
index->stat_n_diff_key_vals[i--] = 1;
4141
size = btr_get_size(index, BTR_TOTAL_SIZE);
4143
index->stat_index_size = size;
4145
sum_of_index_sizes += size;
4147
size = btr_get_size(index, BTR_N_LEAF_PAGES);
4150
/* The root node of the tree is a leaf */
4154
index->stat_n_leaf_pages = size;
4156
btr_estimate_number_of_different_key_vals(index);
4272
4158
index = dict_table_get_next_index(index);
4275
4161
index = dict_table_get_first_index(table);
4277
dict_index_stat_mutex_enter(index);
4279
4163
table->stat_n_rows = index->stat_n_diff_key_vals[
4280
4164
dict_index_get_n_unique(index)];
4282
dict_index_stat_mutex_exit(index);
4284
4166
table->stat_clustered_index_size = index->stat_index_size;
4286
4168
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
4385
4267
fprintf(stderr,
4386
4268
"--------------------------------------\n"
4387
"TABLE: name %s, id %llu, flags %lx, columns %lu,"
4269
"TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
4388
4270
" indexes %lu, appr.rows %lu\n"
4273
(ulong) ut_dulint_get_high(table->id),
4274
(ulong) ut_dulint_get_low(table->id),
4392
4275
(ulong) table->flags,
4393
4276
(ulong) table->n_cols,
4394
4277
(ulong) UT_LIST_GET_LEN(table->indexes),
4454
4337
ib_int64_t n_vals;
4339
const char* type_string;
4457
4341
ut_ad(mutex_own(&(dict_sys->mutex)));
4459
dict_index_stat_mutex_enter(index);
4461
4343
if (index->n_user_defined_cols > 0) {
4462
4344
n_vals = index->stat_n_diff_key_vals[
4463
4345
index->n_user_defined_cols];
4465
4347
n_vals = index->stat_n_diff_key_vals[1];
4468
dict_index_stat_mutex_exit(index);
4350
if (dict_index_is_clust(index)) {
4351
type_string = "clustered index";
4352
} else if (dict_index_is_unique(index)) {
4353
type_string = "unique index";
4355
type_string = "secondary index";
4470
4358
fprintf(stderr,
4471
" INDEX: name %s, id %llu, fields %lu/%lu,"
4359
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
4472
4360
" uniq %lu, type %lu\n"
4473
4361
" root page %lu, appr.key vals %lu,"
4474
4362
" leaf pages %lu, size pages %lu\n"
4365
(ulong) ut_dulint_get_high(index->id),
4366
(ulong) ut_dulint_get_low(index->id),
4478
4367
(ulong) index->n_user_defined_cols,
4479
4368
(ulong) index->n_fields,
4480
4369
(ulong) index->n_uniq,
4753
4642
dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
4756
/**********************************************************************//**
4757
Frees dict_ind_redundant and dict_ind_compact. */
4763
dict_table_t* table;
4765
table = dict_ind_compact->table;
4766
dict_mem_index_free(dict_ind_compact);
4767
dict_ind_compact = NULL;
4768
dict_mem_table_free(table);
4770
table = dict_ind_redundant->table;
4771
dict_mem_index_free(dict_ind_redundant);
4772
dict_ind_redundant = NULL;
4773
dict_mem_table_free(table);
4776
4645
#ifndef UNIV_HOTBACKUP
4777
4646
/**********************************************************************//**
4778
4647
Get index by name
4867
4737
dict_table_check_for_dup_indexes(
4868
4738
/*=============================*/
4869
const dict_table_t* table, /*!< in: Check for dup indexes
4739
const dict_table_t* table) /*!< in: Check for dup indexes
4870
4740
in this table */
4871
ibool tmp_ok) /*!< in: TRUE=allow temporary
4874
4742
/* Check for duplicates, ignoring indexes that are marked
4875
4743
as to be dropped */
4877
4745
const dict_index_t* index1;
4878
4746
const dict_index_t* index2;
4880
ut_ad(mutex_own(&dict_sys->mutex));
4882
4748
/* The primary index _must_ exist */
4883
4749
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
4885
4751
index1 = UT_LIST_GET_FIRST(table->indexes);
4888
ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);
4890
index2 = UT_LIST_GET_NEXT(indexes, index1);
4752
index2 = UT_LIST_GET_NEXT(indexes, index1);
4754
while (index1 && index2) {
4892
4756
while (index2) {
4901
4765
index1 = UT_LIST_GET_NEXT(indexes, index1);
4766
index2 = UT_LIST_GET_NEXT(indexes, index1);
4904
4769
#endif /* UNIV_DEBUG */
4906
/**************************************************************************
4907
Closes the data dictionary module. */
4915
/* Free the hash elements. We don't remove them from the table
4916
because we are going to destroy the table anyway. */
4917
for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
4918
dict_table_t* table;
4920
table = HASH_GET_FIRST(dict_sys->table_hash, i);
4923
dict_table_t* prev_table = table;
4925
table = HASH_GET_NEXT(name_hash, prev_table);
4927
ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
4929
/* Acquire only because it's a pre-condition. */
4930
mutex_enter(&dict_sys->mutex);
4932
dict_table_remove_from_cache(prev_table);
4934
mutex_exit(&dict_sys->mutex);
4938
hash_table_free(dict_sys->table_hash);
4940
/* The elements are the same instance as in dict_sys->table_hash,
4941
therefore we don't delete the individual elements. */
4942
hash_table_free(dict_sys->table_id_hash);
4946
mutex_free(&dict_sys->mutex);
4948
rw_lock_free(&dict_operation_lock);
4949
memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
4951
mutex_free(&dict_foreign_err_mutex);
4956
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
4957
mutex_free(&dict_index_stat_mutex[i]);
4960
4770
#endif /* !UNIV_HOTBACKUP */