26
26
#include "pars0sym.h"
27
27
#include "que0que.h"
28
28
#include "rem0cmp.h"
29
#include "row0merge.h"
30
29
#ifndef UNIV_HOTBACKUP
31
# if defined(BUILD_DRIZZLE)
32
# include <mystrings/m_ctype.h>
34
# include "m_ctype.h" /* my_isspace() */
36
# include "ha_prototypes.h" /* innobase_strcasecmp() */
30
# include <mystrings/m_ctype.h> /* my_isspace() */
37
31
#endif /* !UNIV_HOTBACKUP */
41
/* the dictionary system */
42
UNIV_INTERN dict_sys_t* dict_sys = NULL;
44
/* table create, drop, etc. reserve this in X-mode; implicit or
45
backround operations purge, rollback, foreign key checks reserve this
46
in S-mode; we cannot trust that MySQL protects implicit or background
47
operations a table drop since MySQL does not know of them; therefore
48
we need this; NOTE: a transaction which reserves this must keep book
49
on the mode in trx->dict_operation_lock_mode */
50
UNIV_INTERN rw_lock_t dict_operation_lock;
35
dict_sys_t* dict_sys = NULL; /* the dictionary system */
37
rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
38
this in X-mode; implicit or backround
39
operations purge, rollback, foreign
40
key checks reserve this in S-mode; we
41
cannot trust that MySQL protects
42
implicit or background operations
43
a table drop since MySQL does not
44
know of them; therefore we need this;
45
NOTE: a transaction which reserves
46
this must keep book on the mode in
47
trx->dict_operation_lock_mode */
49
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
50
creating a table or index object */
52
51
#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
53
52
hash table fixed size in bytes */
53
#define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data
54
dictionary varying size in bytes */
55
56
/* Identifies generated InnoDB foreign key names */
56
57
static char dict_ibfk[] = "_ibfk_";
83
84
ulint len); /* in: length of 'to', in bytes;
84
85
should be at least 3 * strlen(to) + 1 */
85
86
/**********************************************************************
87
Compares NUL-terminated UTF-8 strings case insensitively.
89
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
90
this function, you MUST change also the prototype here! */
95
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
96
const char* a, /* in: first string to compare */
97
const char* b); /* in: second string to compare */
99
/**********************************************************************
86
100
Makes all characters in a NUL-terminated UTF-8 string lower case.
88
102
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
89
103
this function, you MUST change also the prototype here! */
92
106
innobase_casedn_str(
93
107
/*================*/
105
119
void* mysql_thd); /* in: MySQL thread handle */
106
120
#endif /* !UNIV_HOTBACKUP */
122
/**************************************************************************
123
Removes an index from the dictionary cache. */
126
dict_index_remove_from_cache(
127
/*=========================*/
128
dict_table_t* table, /* in: table */
129
dict_index_t* index); /* in, own: index */
130
/***********************************************************************
131
Copies fields contained in index2 to index1. */
136
dict_index_t* index1, /* in: index to copy to */
137
dict_index_t* index2, /* in: index to copy from */
138
dict_table_t* table, /* in: table */
139
ulint start, /* in: first position to copy */
140
ulint end); /* in: last position to copy */
108
141
/***********************************************************************
109
142
Tries to find column names for the index and sets the col field of the
122
155
dict_index_build_internal_clust(
123
156
/*============================*/
124
/* out, own: the internal
125
representation of the clustered
127
const dict_table_t* table, /* in: table */
128
dict_index_t* index); /* in: user representation of
157
/* out, own: the internal representation
158
of the clustered index */
159
dict_table_t* table, /* in: table */
160
dict_index_t* index); /* in: user representation of a clustered
130
162
/***********************************************************************
131
163
Builds the internal dictionary cache representation for a non-clustered
132
164
index, containing also system fields not defined by the user. */
135
167
dict_index_build_internal_non_clust(
136
168
/*================================*/
137
/* out, own: the internal
138
representation of the non-clustered
140
const dict_table_t* table, /* in: table */
141
dict_index_t* index); /* in: user representation of
142
a non-clustered index */
169
/* out, own: the internal representation
170
of the non-clustered index */
171
dict_table_t* table, /* in: table */
172
dict_index_t* index); /* in: user representation of a non-clustered
143
174
/**************************************************************************
144
175
Removes a foreign constraint struct from the dictionary cache. */
272
303
/************************************************************************
273
304
Decrements the count of open MySQL handles to a table. */
276
307
dict_table_decrement_handle_count(
277
308
/*==============================*/
278
dict_table_t* table, /* in/out: table */
279
ibool dict_locked) /* in: TRUE=data dictionary locked */
309
dict_table_t* table) /* in: table */
282
mutex_enter(&dict_sys->mutex);
311
mutex_enter(&(dict_sys->mutex));
285
ut_ad(mutex_own(&dict_sys->mutex));
286
313
ut_a(table->n_mysql_handles_opened > 0);
288
315
table->n_mysql_handles_opened--;
291
mutex_exit(&dict_sys->mutex);
317
mutex_exit(&(dict_sys->mutex));
320
/*************************************************************************
321
Gets the column data type. */
324
dict_col_copy_type_noninline(
325
/*=========================*/
326
const dict_col_t* col, /* in: column */
327
dtype_t* type) /* out: data type */
329
dict_col_copy_type(col, type);
332
/************************************************************************
333
Gets the nth column of a table. */
336
dict_table_get_nth_col_noninline(
337
/*=============================*/
338
/* out: pointer to column object */
339
const dict_table_t* table, /* in: table */
340
ulint pos) /* in: position of column */
342
return(dict_table_get_nth_col(table, pos));
345
/************************************************************************
346
Gets the first index on the table (the clustered index). */
349
dict_table_get_first_index_noninline(
350
/*=================================*/
351
/* out: index, NULL if none exists */
352
dict_table_t* table) /* in: table */
354
return(dict_table_get_first_index(table));
357
/************************************************************************
358
Gets the next index on the table. */
361
dict_table_get_next_index_noninline(
362
/*================================*/
363
/* out: index, NULL if none left */
364
dict_index_t* index) /* in: index */
366
return(dict_table_get_next_index(index));
369
/**************************************************************************
370
Returns an index object. */
373
dict_table_get_index_noninline(
374
/*===========================*/
375
/* out: index, NULL if does not exist */
376
dict_table_t* table, /* in: table */
377
const char* name) /* in: index name */
379
return(dict_table_get_index(table, name));
295
382
/**************************************************************************
296
383
Returns a column's name. */
299
386
dict_table_get_col_name(
300
387
/*====================*/
394
481
/************************************************************************
395
482
Release the autoinc lock.*/
398
485
dict_table_autoinc_unlock(
399
486
/*======================*/
400
dict_table_t* table) /* in/out: table */
487
dict_table_t* table) /* in: release autoinc lock for this table */
402
489
mutex_exit(&table->autoinc_mutex);
405
/**************************************************************************
406
Looks for an index with the given table and index id.
407
NOTE that we do not reserve the dictionary mutex. */
410
dict_index_get_on_id_low(
411
/*=====================*/
412
/* out: index or NULL if not found
414
dict_table_t* table, /* in: table */
415
dulint id) /* in: index id */
419
index = dict_table_get_first_index(table);
422
if (0 == ut_dulint_cmp(id, index->id)) {
428
index = dict_table_get_next_index(index);
434
492
/************************************************************************
435
493
Looks for column n in an index. */
438
496
dict_index_get_nth_col_pos(
439
497
/*=======================*/
440
/* out: position in internal
441
representation of the index;
442
if not contained, returns
444
const dict_index_t* index, /* in: index */
445
ulint n) /* in: column number */
498
/* out: position in internal representation
499
of the index; if not contained, returns
501
dict_index_t* index, /* in: index */
502
ulint n) /* in: column number */
447
504
const dict_field_t* field;
448
505
const dict_col_t* col;
518
575
column in index must be complete, or must contain a prefix longer than the
519
576
column in index2. That is, we must be able to construct the prefix in index2
520
577
from the prefix in index. */
523
580
dict_index_get_nth_field_pos(
524
581
/*=========================*/
525
/* out: position in internal
526
representation of the index;
527
if not contained, returns
529
const dict_index_t* index, /* in: index from which to search */
530
const dict_index_t* index2, /* in: index */
531
ulint n) /* in: field number in index2 */
582
/* out: position in internal representation
583
of the index; if not contained, returns
585
dict_index_t* index, /* in: index from which to search */
586
dict_index_t* index2, /* in: index */
587
ulint n) /* in: field number in index2 */
533
const dict_field_t* field;
534
const dict_field_t* field2;
590
dict_field_t* field2;
539
595
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
594
650
/************************************************************************
595
651
Looks for column n position in the clustered index. */
598
654
dict_table_get_nth_col_pos(
599
655
/*=======================*/
600
/* out: position in internal
602
the clustered index */
603
const dict_table_t* table, /* in: table */
604
ulint n) /* in: column number */
656
/* out: position in internal representation
657
of the clustered index */
658
dict_table_t* table, /* in: table */
659
ulint n) /* in: column number */
606
661
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
610
665
/************************************************************************
666
Check whether the table uses the compact page format. */
669
dict_table_is_comp_noninline(
670
/*=========================*/
671
/* out: TRUE if table uses the
672
compact page format */
673
const dict_table_t* table) /* in: table */
675
return(dict_table_is_comp(table));
678
/************************************************************************
611
679
Checks if a column is in the ordering columns of the clustered index of a
612
680
table. Column prefixes are treated like whole columns. */
615
683
dict_table_col_in_clustered_key(
616
684
/*============================*/
617
/* out: TRUE if the column, or its
618
prefix, is in the clustered key */
619
const dict_table_t* table, /* in: table */
620
ulint n) /* in: column number */
685
/* out: TRUE if the column, or its prefix, is
686
in the clustered key */
687
dict_table_t* table, /* in: table */
688
ulint n) /* in: column number */
622
const dict_index_t* index;
623
691
const dict_field_t* field;
624
692
const dict_col_t* col;
887
953
dict_index_t* index;
890
const char* old_name;
893
960
ut_ad(mutex_own(&(dict_sys->mutex)));
895
962
old_size = mem_heap_get_size(table->heap);
896
old_name = table->name;
898
964
fold = ut_fold_string(new_name);
900
966
/* Look for a table with the same name: error if such exists */
902
968
dict_table_t* table2;
903
HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
904
dict_table_t*, table2,
969
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
905
970
(ut_strcmp(table2->name, new_name) == 0));
906
if (UNIV_LIKELY_NULL(table2)) {
907
ut_print_timestamp(stderr);
908
fputs(" InnoDB: Error: dictionary cache"
909
" already contains a table ", stderr);
910
ut_print_name(stderr, NULL, TRUE, new_name);
912
"InnoDB: cannot rename table ", stderr);
913
ut_print_name(stderr, NULL, TRUE, old_name);
973
"InnoDB: Error: dictionary cache"
974
" already contains a table of name %s\n",
922
983
if (table->space != 0) {
923
984
if (table->dir_path_of_temp_table != NULL) {
924
ut_print_timestamp(stderr);
925
fputs(" InnoDB: Error: trying to rename a"
926
" TEMPORARY TABLE ", stderr);
927
ut_print_name(stderr, NULL, TRUE, old_name);
929
ut_print_filename(stderr,
930
table->dir_path_of_temp_table);
931
fputs(" )\n", stderr);
933
} else if (!fil_rename_tablespace(old_name, table->space,
986
"InnoDB: Error: trying to rename a table"
987
" %s (%s) created with CREATE\n"
988
"InnoDB: TEMPORARY TABLE\n",
989
table->name, table->dir_path_of_temp_table);
992
success = fil_rename_tablespace(
993
table->name, table->space, new_name);
939
1002
/* Remove table from the hash tables of tables */
940
1003
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
941
ut_fold_string(old_name), table);
1004
ut_fold_string(table->name), table);
1005
old_name = mem_heap_strdup(table->heap, table->name);
942
1006
table->name = mem_heap_strdup(table->heap, new_name);
944
1008
/* Add table to hash table of tables */
1178
1242
dict_mem_table_free(table);
1245
/*************************************************************************
1246
Gets the column position in the clustered index. */
1249
dict_col_get_clust_pos_noninline(
1250
/*=============================*/
1251
const dict_col_t* col, /* in: table column */
1252
const dict_index_t* clust_index) /* in: clustered index */
1254
return(dict_col_get_clust_pos(col, clust_index));
1181
1257
/********************************************************************
1182
1258
If the given column name is reserved for InnoDB system columns, return
1186
1262
dict_col_name_is_reserved(
1187
1263
/*======================*/
1213
/********************************************************************
1214
If an undo log record for this table might not fit on a single page,
1218
dict_index_too_big_for_undo(
1219
/*========================*/
1220
/* out: TRUE if the undo log
1221
record could become too big */
1222
const dict_table_t* table, /* in: table */
1223
const dict_index_t* new_index) /* in: index */
1225
/* Make sure that all column prefixes will fit in the undo log record
1226
in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1229
const dict_index_t* clust_index
1230
= dict_table_get_first_index(table);
1232
= TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
1233
+ 2 /* next record pointer */
1235
+ 11 /* trx->undo_no */ - 11 /* table->id */
1236
+ 1 /* rec_get_info_bits() */
1237
+ 11 /* DB_TRX_ID */
1238
+ 11 /* DB_ROLL_PTR */
1239
+ 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
1240
+ 2/* pointer to previous undo log record */;
1242
if (UNIV_UNLIKELY(!clust_index)) {
1243
ut_a(dict_index_is_clust(new_index));
1244
clust_index = new_index;
1247
/* Add the size of the ordering columns in the
1249
for (i = 0; i < clust_index->n_uniq; i++) {
1250
const dict_col_t* col
1251
= dict_index_get_nth_col(clust_index, i);
1253
/* Use the maximum output size of
1254
mach_write_compressed(), although the encoded
1255
length should always fit in 2 bytes. */
1256
undo_page_len += 5 + dict_col_get_max_size(col);
1259
/* Add the old values of the columns to be updated.
1260
First, the amount and the numbers of the columns.
1261
These are written by mach_write_compressed() whose
1262
maximum output length is 5 bytes. However, given that
1263
the quantities are below REC_MAX_N_FIELDS (10 bits),
1264
the maximum length is 2 bytes per item. */
1265
undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
1267
for (i = 0; i < clust_index->n_def; i++) {
1268
const dict_col_t* col
1269
= dict_index_get_nth_col(clust_index, i);
1271
= dict_col_get_max_size(col);
1273
= dict_col_get_fixed_size(col);
1276
/* Fixed-size columns are stored locally. */
1277
max_size = fixed_size;
1278
} else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
1279
/* Short columns are stored locally. */
1280
} else if (!col->ord_part) {
1281
/* See if col->ord_part would be set
1282
because of new_index. */
1285
for (j = 0; j < new_index->n_uniq; j++) {
1286
if (dict_index_get_nth_col(
1287
new_index, j) == col) {
1293
/* This is not an ordering column in any index.
1294
Thus, it can be stored completely externally. */
1295
max_size = BTR_EXTERN_FIELD_REF_SIZE;
1298
/* This is an ordering column in some index.
1299
A long enough prefix must be written to the
1300
undo log. See trx_undo_page_fetch_ext(). */
1302
if (max_size > REC_MAX_INDEX_COL_LEN) {
1303
max_size = REC_MAX_INDEX_COL_LEN;
1306
max_size += BTR_EXTERN_FIELD_REF_SIZE;
1309
undo_page_len += 5 + max_size;
1312
return(undo_page_len >= UNIV_PAGE_SIZE);
1315
1289
/**************************************************************************
1316
1290
Adds an index to the dictionary cache. */
1319
1293
dict_index_add_to_cache(
1320
1294
/*====================*/
1321
/* out: DB_SUCCESS or DB_TOO_BIG_RECORD */
1322
1295
dict_table_t* table, /* in: table on which the index is */
1323
1296
dict_index_t* index, /* in, own: index; NOTE! The index memory
1324
1297
object is freed in this function! */
1342
1329
/* Build the cache internal representation of the index,
1343
1330
containing also the added system fields */
1345
if (dict_index_is_clust(index)) {
1332
if (index->type & DICT_CLUSTERED) {
1346
1333
new_index = dict_index_build_internal_clust(table, index);
1348
1335
new_index = dict_index_build_internal_non_clust(table, index);
1338
new_index->search_info = btr_search_info_create(new_index->heap);
1351
1340
/* Set the n_fields value in new_index to the actual defined
1352
1341
number of fields in the cache internal representation */
1354
1343
new_index->n_fields = new_index->n_def;
1356
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1357
n_ord = new_index->n_fields;
1359
n_ord = new_index->n_uniq;
1362
for (i = 0; i < n_ord; i++) {
1363
const dict_field_t* field
1364
= dict_index_get_nth_field(new_index, i);
1365
const dict_col_t* col
1366
= dict_field_get_col(field);
1368
/* In dtuple_convert_big_rec(), variable-length columns
1369
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1370
may be chosen for external storage. If the column appears
1371
in an ordering column of an index, a longer prefix of
1372
REC_MAX_INDEX_COL_LEN will be copied to the undo log
1373
by trx_undo_page_report_modify() and
1374
trx_undo_page_fetch_ext(). It suffices to check the
1375
capacity of the undo log whenever new_index includes
1376
a column prefix on a column that may be stored externally. */
1378
if (field->prefix_len /* prefix index */
1379
&& !col->ord_part /* not yet ordering column */
1380
&& !dict_col_get_fixed_size(col) /* variable-length */
1381
&& dict_col_get_max_size(col)
1382
> BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
1384
if (dict_index_too_big_for_undo(table, new_index)) {
1385
/* An undo log record might not fit in
1386
a single page. Refuse to create this index. */
1387
dict_mem_index_free(new_index);
1388
dict_mem_index_free(index);
1389
return(DB_TOO_BIG_RECORD);
1396
/* Flag the ordering columns */
1398
for (i = 0; i < n_ord; i++) {
1400
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1403
1345
/* Add the new index as the last index for the table */
1405
1347
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1406
1348
new_index->table = table;
1407
1349
new_index->table_name = table->name;
1409
new_index->search_info = btr_search_info_create(new_index->heap);
1411
new_index->stat_index_size = 1;
1412
new_index->stat_n_leaf_pages = 1;
1414
new_index->page = page_no;
1351
/* Increment the ord_part counts in columns which are ordering */
1353
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1354
n_ord = new_index->n_fields;
1356
n_ord = dict_index_get_n_unique(new_index);
1359
for (i = 0; i < n_ord; i++) {
1361
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1364
new_index->page = (unsigned int) page_no;
1415
1365
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1417
1367
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1498
1447
/* It is an error not to find a matching column. */
1506
1455
/***********************************************************************
1507
1456
Adds a column to index. */
1510
1459
dict_index_add_col(
1511
1460
/*===============*/
1512
dict_index_t* index, /* in/out: index */
1513
const dict_table_t* table, /* in: table */
1514
dict_col_t* col, /* in: column */
1515
ulint prefix_len) /* in: column prefix length */
1461
dict_index_t* index, /* in: index */
1462
dict_table_t* table, /* in: table */
1463
dict_col_t* col, /* in: column */
1464
ulint prefix_len) /* in: column prefix length */
1517
1466
dict_field_t* field;
1518
1467
const char* col_name;
1556
1505
dict_index_copy(
1557
1506
/*============*/
1558
dict_index_t* index1, /* in: index to copy to */
1559
dict_index_t* index2, /* in: index to copy from */
1560
const dict_table_t* table, /* in: table */
1561
ulint start, /* in: first position to copy */
1562
ulint end) /* in: last position to copy */
1507
dict_index_t* index1, /* in: index to copy to */
1508
dict_index_t* index2, /* in: index to copy from */
1509
dict_table_t* table, /* in: table */
1510
ulint start, /* in: first position to copy */
1511
ulint end) /* in: last position to copy */
1564
1513
dict_field_t* field;
1606
1554
/***********************************************************************
1607
Copies types of columns contained in table to tuple and sets all
1608
fields of the tuple to the SQL NULL value. This function should
1609
be called right after dtuple_create(). */
1555
Copies types of columns contained in table to tuple. */
1612
1558
dict_table_copy_types(
1613
1559
/*==================*/
1614
dtuple_t* tuple, /* in/out: data tuple */
1615
const dict_table_t* table) /* in: table */
1560
dtuple_t* tuple, /* in: data tuple */
1561
dict_table_t* table) /* in: index */
1563
dtype_t* dfield_type;
1619
1566
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1621
dfield_t* dfield = dtuple_get_nth_field(tuple, i);
1622
dtype_t* dtype = dfield_get_type(dfield);
1624
dfield_set_null(dfield);
1625
dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
1568
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1569
dict_col_copy_type(dict_table_get_nth_col(table, i),
1700
1644
# error "DATA_ROLL_PTR != 2"
1703
if (!dict_index_is_unique(index)) {
1704
dict_index_add_col(new_index, table,
1647
if (!(index->type & DICT_UNIQUE)) {
1648
dict_index_add_col(new_index, table, (dict_col_t*)
1705
1649
dict_table_get_sys_col(
1706
1650
table, DATA_ROW_ID),
1711
dict_index_add_col(new_index, table,
1655
dict_index_add_col(new_index, table, (dict_col_t*)
1712
1656
dict_table_get_sys_col(table, DATA_TRX_ID),
1715
dict_index_add_col(new_index, table,
1659
dict_index_add_col(new_index, table, (dict_col_t*)
1716
1660
dict_table_get_sys_col(table,
1717
1661
DATA_ROLL_PTR),
1879
1825
/*************************************************************************
1880
1826
Checks if a table is referenced by foreign keys. */
1883
dict_table_is_referenced_by_foreign_key(
1884
/*====================================*/
1885
/* out: TRUE if table is referenced
1887
const dict_table_t* table) /* in: InnoDB table */
1889
return(UT_LIST_GET_LEN(table->referenced_list) > 0);
1892
/*************************************************************************
1893
Check if the index is referenced by a foreign key, if TRUE return foreign
1897
dict_table_get_referenced_constraint(
1829
dict_table_referenced_by_foreign_key(
1898
1830
/*=================================*/
1899
/* out: pointer to foreign key struct if index
1900
is defined for foreign key, otherwise NULL */
1901
dict_table_t* table, /* in: InnoDB table */
1902
dict_index_t* index) /* in: InnoDB index */
1904
dict_foreign_t* foreign = NULL;
1906
ut_ad(index && table);
1908
/* If the referenced list is empty, nothing to do */
1910
if (UT_LIST_GET_LEN(table->referenced_list) == 0) {
1915
foreign = UT_LIST_GET_FIRST(table->referenced_list);
1918
if (foreign->referenced_index == index
1919
|| foreign->referenced_index == index) {
1924
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1930
/*************************************************************************
1931
Checks if a index is defined for a foreign key constraint. Index is a part
1932
of a foreign key constraint if the index is referenced by foreign key
1933
or index is a foreign key index. */
1936
dict_table_get_foreign_constraint(
1937
/*==============================*/
1938
/* out: pointer to foreign key struct if index
1939
is defined for foreign key, otherwise NULL */
1940
dict_table_t* table, /* in: InnoDB table */
1941
dict_index_t* index) /* in: InnoDB index */
1943
dict_foreign_t* foreign = NULL;
1945
ut_ad(index && table);
1947
/* If list empty then nothgin to do */
1949
if (UT_LIST_GET_LEN(table->foreign_list) == 0) {
1954
/* Check whether this index is defined for a foreign key */
1956
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1959
if (foreign->foreign_index == index
1960
|| foreign->referenced_index == index) {
1965
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1831
/* out: TRUE if table is referenced by a
1833
dict_table_t* table) /* in: InnoDB table */
1835
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
1971
1843
/*************************************************************************
2135
1998
/**************************************************************************
2136
Returns an index object by matching on the name and column names and
2137
if more than one index matches return the index with the max id */
2140
dict_table_get_index_by_max_id(
2141
/*===========================*/
2142
/* out: matching index, NULL if not found */
2143
dict_table_t* table, /* in: table */
2144
const char* name, /* in: the index name to find */
2145
const char** columns,/* in: array of column names */
2146
ulint n_cols) /* in: number of columns */
2148
dict_index_t* index;
2149
dict_index_t* found;
2152
index = dict_table_get_first_index(table);
2154
while (index != NULL) {
2155
if (ut_strcmp(index->name, name) == 0
2156
&& dict_index_get_n_ordering_defined_by_user(index)
2161
for (i = 0; i < n_cols; i++) {
2162
dict_field_t* field;
2163
const char* col_name;
2165
field = dict_index_get_nth_field(index, i);
2167
col_name = dict_table_get_col_name(
2168
table, dict_col_get_no(field->col));
2170
if (0 != innobase_strcasecmp(
2171
columns[i], col_name)) {
2178
/* We found a matching index, select
2179
the index with the higher id*/
2182
|| ut_dulint_cmp(index->id, found->id) > 0) {
2189
index = dict_table_get_next_index(index);
2195
/**************************************************************************
2196
1999
Report an error in a foreign key definition. */
3673
3476
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3675
/**************************************************************************
3676
Returns an index object if it is found in the dictionary cache.
3677
Assumes that dict_sys->mutex is already being held. */
3680
dict_index_get_if_in_cache_low(
3681
/*===========================*/
3682
/* out: index, NULL if not found */
3683
dulint index_id) /* in: index id */
3685
ut_ad(mutex_own(&(dict_sys->mutex)));
3687
return(dict_index_find_on_id_low(index_id));
3690
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
3691
3479
/**************************************************************************
3692
3480
Returns an index object if it is found in the dictionary cache. */
3695
3483
dict_index_get_if_in_cache(
3696
3484
/*=======================*/
3706
3494
mutex_enter(&(dict_sys->mutex));
3708
index = dict_index_get_if_in_cache_low(index_id);
3496
index = dict_index_find_on_id_low(index_id);
3710
3498
mutex_exit(&(dict_sys->mutex));
3714
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
3502
#endif /* UNIV_DEBUG */
3716
3504
#ifdef UNIV_DEBUG
3717
3505
/**************************************************************************
3718
3506
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3719
3507
no comparison can occur with the page number field in a node pointer. */
3722
3510
dict_index_check_search_tuple(
3723
3511
/*==========================*/
3724
/* out: TRUE if ok */
3725
const dict_index_t* index, /* in: index tree */
3726
const dtuple_t* tuple) /* in: tuple used in a search */
3512
/* out: TRUE if ok */
3513
dict_index_t* index, /* in: index tree */
3514
dtuple_t* tuple) /* in: tuple used in a search */
3729
3517
ut_a(dtuple_get_n_fields_cmp(tuple)
3735
3523
/**************************************************************************
3736
3524
Builds a node pointer out of a physical record and a page number. */
3739
3527
dict_index_build_node_ptr(
3740
3528
/*======================*/
3741
/* out, own: node pointer */
3742
const dict_index_t* index, /* in: index */
3743
const rec_t* rec, /* in: record for which to build node
3745
ulint page_no,/* in: page number to put in node
3747
mem_heap_t* heap, /* in: memory heap where pointer
3749
ulint level) /* in: level of rec in tree:
3750
0 means leaf level */
3529
/* out, own: node pointer */
3530
dict_index_t* index, /* in: index tree */
3531
rec_t* rec, /* in: record for which to build node
3533
ulint page_no,/* in: page number to put in node pointer */
3534
mem_heap_t* heap, /* in: memory heap where pointer created */
3535
ulint level) /* in: level of rec in tree: 0 means leaf
3752
3538
dtuple_t* tuple;
3753
3539
dfield_t* field;
3804
3590
/**************************************************************************
3805
3591
Copies an initial segment of a physical record, long enough to specify an
3806
3592
index entry uniquely. */
3809
3595
dict_index_copy_rec_order_prefix(
3810
3596
/*=============================*/
3811
/* out: pointer to the prefix record */
3812
const dict_index_t* index, /* in: index */
3813
const rec_t* rec, /* in: record for which to
3815
ulint* n_fields,/* out: number of fields copied */
3816
byte** buf, /* in/out: memory buffer for the
3817
copied prefix, or NULL */
3818
ulint* buf_size)/* in/out: buffer size */
3597
/* out: pointer to the prefix record */
3598
dict_index_t* index, /* in: index tree */
3599
rec_t* rec, /* in: record for which to copy prefix */
3600
ulint* n_fields,/* out: number of fields copied */
3601
byte** buf, /* in/out: memory buffer for the copied prefix,
3603
ulint* buf_size)/* in/out: buffer size */
3997
3782
/*************************************************************************
3998
3783
Calculates new estimates for table and index statistics. The statistics
3999
3784
are used in query optimization. */
4002
3787
dict_update_statistics(
4003
3788
/*===================*/
4004
dict_table_t* table) /* in/out: table */
3789
dict_table_t* table) /* in: table */
4006
3791
dict_update_statistics_low(table, FALSE);
4009
3794
/**************************************************************************
3795
A noninlined version of dict_table_get_low. */
3798
dict_table_get_low_noninlined(
3799
/*==========================*/
3800
/* out: table, NULL if not found */
3801
const char* table_name) /* in: table name */
3803
return(dict_table_get_low(table_name));
3806
/**************************************************************************
4010
3807
Prints info of a foreign key constraint. */
4427
4213
fputs(" of table ", file);
4428
4214
ut_print_name(file, trx, TRUE, index->table_name);
4431
/**************************************************************************
4432
Get index by name */
4435
dict_table_get_index_on_name(
4436
/*=========================*/
4437
/* out: index, NULL if does not exist */
4438
dict_table_t* table, /* in: table */
4439
const char* name) /* in: name of the index to find */
4441
dict_index_t* index;
4443
index = dict_table_get_first_index(table);
4445
while (index != NULL) {
4446
if (ut_strcmp(index->name, name) == 0) {
4451
index = dict_table_get_next_index(index);
4458
/**************************************************************************
4459
Find and index that is equivalent to the one passed in. */
4462
dict_table_find_equivalent_index(
4463
/*=============================*/
4464
dict_table_t* table, /* in/out: table */
4465
dict_index_t* index) /* in: index to match */
4468
const char** column_names;
4469
dict_index_t* equiv_index;
4471
if (UT_LIST_GET_LEN(table->foreign_list) == 0) {
4476
column_names = mem_alloc(index->n_fields * sizeof *column_names);
4478
/* Convert the column names to the format & type accepted by the find
4480
for (i = 0; i < index->n_fields; i++) {
4481
column_names[i] = index->fields[i].name;
4484
equiv_index = dict_foreign_find_index(
4485
table, column_names, index->n_fields,
4486
index, TRUE, FALSE);
4488
mem_free((void*) column_names);
4490
return(equiv_index);
4493
/**************************************************************************
4494
Replace the index passed in with another equivalent index in the tables
4495
foreign key list. */
4498
dict_table_replace_index_in_foreign_list(
4499
/*=====================================*/
4500
dict_table_t* table, /* in/out: table */
4501
dict_index_t* index) /* in: index to be replaced */
4503
dict_index_t* new_index;
4505
new_index = dict_table_find_equivalent_index(table, index);
4507
/* If match found */
4509
dict_foreign_t* foreign;
4511
ut_a(new_index != index);
4513
foreign = UT_LIST_GET_FIRST(table->foreign_list);
4515
/* If the list is not empty then this should hold */
4518
/* Iterate over the foreign index list and replace the index
4519
passed in with the new index */
4522
if (foreign->foreign_index == index) {
4523
foreign->foreign_index = new_index;
4526
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4531
/**************************************************************************
4532
In case there is more than one index with the same name return the index
4533
with the min(id). */
4536
dict_table_get_index_on_name_and_min_id(
4537
/*=====================================*/
4538
/* out: index, NULL if does not exist */
4539
dict_table_t* table, /* in: table */
4540
const char* name) /* in: name of the index to find */
4542
dict_index_t* index;
4543
dict_index_t* min_index; /* Index with matching name and min(id) */
4546
index = dict_table_get_first_index(table);
4548
while (index != NULL) {
4549
if (ut_strcmp(index->name, name) == 0) {
4551
|| ut_dulint_cmp(index->id, min_index->id) < 0) {
4557
index = dict_table_get_next_index(index);
4565
/**************************************************************************
4566
Check for duplicate index entries in a table [using the index name] */
4569
dict_table_check_for_dup_indexes(
4570
/*=============================*/
4571
const dict_table_t* table) /* in: Check for dup indexes
4574
/* Check for duplicates, ignoring indexes that are marked
4577
const dict_index_t* index1;
4578
const dict_index_t* index2;
4580
/* The primary index _must_ exist */
4581
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
4583
index1 = UT_LIST_GET_FIRST(table->indexes);
4584
index2 = UT_LIST_GET_NEXT(indexes, index1);
4586
while (index1 && index2) {
4590
if (!index2->to_be_dropped) {
4591
ut_ad(ut_strcmp(index1->name, index2->name));
4594
index2 = UT_LIST_GET_NEXT(indexes, index2);
4597
index1 = UT_LIST_GET_NEXT(indexes, index1);
4598
index2 = UT_LIST_GET_NEXT(indexes, index1);
4601
#endif /* UNIV_DEBUG */