~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/dict/dict0dict.c

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
 
4
 
 
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.
 
8
 
 
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.
 
12
 
 
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
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/******************************************************************//**
 
20
@file dict/dict0dict.c
 
21
Data dictionary system
 
22
 
 
23
Created 1/8/1996 Heikki Tuuri
 
24
***********************************************************************/
 
25
 
 
26
#include "dict0dict.h"
 
27
 
 
28
#ifdef UNIV_NONINL
 
29
#include "dict0dict.ic"
 
30
#endif
 
31
 
 
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;
 
36
 
 
37
#ifndef UNIV_HOTBACKUP
 
38
#include "buf0buf.h"
 
39
#include "data0type.h"
 
40
#include "mach0data.h"
 
41
#include "dict0boot.h"
 
42
#include "dict0mem.h"
 
43
#include "dict0crea.h"
 
44
#include "trx0undo.h"
 
45
#include "btr0btr.h"
 
46
#include "btr0cur.h"
 
47
#include "btr0sea.h"
 
48
#include "page0zip.h"
 
49
#include "page0page.h"
 
50
#include "pars0pars.h"
 
51
#include "pars0sym.h"
 
52
#include "que0que.h"
 
53
#include "rem0cmp.h"
 
54
#include "row0merge.h"
 
55
#include "ha_prototypes.h" /* innobase_strcasecmp() */
 
56
 
 
57
#include <ctype.h>
 
58
 
 
59
/** the dictionary system */
 
60
UNIV_INTERN dict_sys_t* dict_sys        = NULL;
 
61
 
 
62
/** @brief the data dictionary rw-latch protecting dict_sys
 
63
 
 
64
table create, drop, etc. reserve this in X-mode; implicit or
 
65
backround operations purge, rollback, foreign key checks reserve this
 
66
in S-mode; we cannot trust that MySQL protects implicit or background
 
67
operations a table drop since MySQL does not know of them; therefore
 
68
we need this; NOTE: a transaction which reserves this must keep book
 
69
on the mode in trx_struct::dict_operation_lock_mode */
 
70
UNIV_INTERN rw_lock_t   dict_operation_lock;
 
71
 
 
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 */
 
77
 
 
78
#ifdef UNIV_PFS_MUTEX
 
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 */
 
82
 
 
83
#define DICT_HEAP_SIZE          100     /*!< initial memory heap size when
 
84
                                        creating a table or index object */
 
85
#define DICT_POOL_PER_TABLE_HASH 512    /*!< buffer pool max size per table
 
86
                                        hash table fixed size in bytes */
 
87
#define DICT_POOL_PER_VARYING   4       /*!< buffer pool max size per data
 
88
                                        dictionary varying size in bytes */
 
89
 
 
90
/** Identifies generated InnoDB foreign key names */
 
91
static char     dict_ibfk[] = "_ibfk_";
 
92
 
 
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];
 
96
 
 
97
/*******************************************************************//**
 
98
Tries to find column names for the index and sets the col field of the
 
99
index.
 
100
@return TRUE if the column names were found */
 
101
static
 
102
ibool
 
103
dict_index_find_cols(
 
104
/*=================*/
 
105
        dict_table_t*   table,  /*!< in: table */
 
106
        dict_index_t*   index); /*!< in: index */
 
107
/*******************************************************************//**
 
108
Builds the internal dictionary cache representation for a clustered
 
109
index, containing also system fields not defined by the user.
 
110
@return own: the internal representation of the clustered index */
 
111
static
 
112
dict_index_t*
 
113
dict_index_build_internal_clust(
 
114
/*============================*/
 
115
        const dict_table_t*     table,  /*!< in: table */
 
116
        dict_index_t*           index); /*!< in: user representation of
 
117
                                        a clustered index */
 
118
/*******************************************************************//**
 
119
Builds the internal dictionary cache representation for a non-clustered
 
120
index, containing also system fields not defined by the user.
 
121
@return own: the internal representation of the non-clustered index */
 
122
static
 
123
dict_index_t*
 
124
dict_index_build_internal_non_clust(
 
125
/*================================*/
 
126
        const dict_table_t*     table,  /*!< in: table */
 
127
        dict_index_t*           index); /*!< in: user representation of
 
128
                                        a non-clustered index */
 
129
/**********************************************************************//**
 
130
Removes a foreign constraint struct from the dictionary cache. */
 
131
static
 
132
void
 
133
dict_foreign_remove_from_cache(
 
134
/*===========================*/
 
135
        dict_foreign_t* foreign);       /*!< in, own: foreign constraint */
 
136
/**********************************************************************//**
 
137
Prints a column data. */
 
138
static
 
139
void
 
140
dict_col_print_low(
 
141
/*===============*/
 
142
        const dict_table_t*     table,  /*!< in: table */
 
143
        const dict_col_t*       col);   /*!< in: column */
 
144
/**********************************************************************//**
 
145
Prints an index data. */
 
146
static
 
147
void
 
148
dict_index_print_low(
 
149
/*=================*/
 
150
        dict_index_t*   index); /*!< in: index */
 
151
/**********************************************************************//**
 
152
Prints a field data. */
 
153
static
 
154
void
 
155
dict_field_print_low(
 
156
/*=================*/
 
157
        const dict_field_t*     field); /*!< in: field */
 
158
/*********************************************************************//**
 
159
Frees a foreign key struct. */
 
160
static
 
161
void
 
162
dict_foreign_free(
 
163
/*==============*/
 
164
        dict_foreign_t* foreign);       /*!< in, own: foreign key struct */
 
165
 
 
166
/* Stream for storing detailed information about the latest foreign key
 
167
and unique key errors */
 
168
UNIV_INTERN FILE*       dict_foreign_err_file           = NULL;
 
169
/* mutex protecting the foreign and unique error buffers */
 
170
UNIV_INTERN mutex_t     dict_foreign_err_mutex;
 
171
 
 
172
/******************************************************************//**
 
173
Makes all characters in a NUL-terminated UTF-8 string lower case. */
 
174
UNIV_INTERN
 
175
void
 
176
dict_casedn_str(
 
177
/*============*/
 
178
        char*   a)      /*!< in/out: string to put in lower case */
 
179
{
 
180
        innobase_casedn_str(a);
 
181
}
 
182
 
 
183
/********************************************************************//**
 
184
Checks if the database name in two table names is the same.
 
185
@return TRUE if same db name */
 
186
UNIV_INTERN
 
187
ibool
 
188
dict_tables_have_same_db(
 
189
/*=====================*/
 
190
        const char*     name1,  /*!< in: table name in the form
 
191
                                dbname '/' tablename */
 
192
        const char*     name2)  /*!< in: table name in the form
 
193
                                dbname '/' tablename */
 
194
{
 
195
        for (; *name1 == *name2; name1++, name2++) {
 
196
                if (*name1 == '/') {
 
197
                        return(TRUE);
 
198
                }
 
199
                ut_a(*name1); /* the names must contain '/' */
 
200
        }
 
201
        return(FALSE);
 
202
}
 
203
 
 
204
/********************************************************************//**
 
205
Return the end of table name where we have removed dbname and '/'.
 
206
@return table name */
 
207
UNIV_INTERN
 
208
const char*
 
209
dict_remove_db_name(
 
210
/*================*/
 
211
        const char*     name)   /*!< in: table name in the form
 
212
                                dbname '/' tablename */
 
213
{
 
214
        const char*     s = strchr(name, '/');
 
215
        ut_a(s);
 
216
 
 
217
        return(s + 1);
 
218
}
 
219
 
 
220
/********************************************************************//**
 
221
Get the database name length in a table name.
 
222
@return database name length */
 
223
UNIV_INTERN
 
224
ulint
 
225
dict_get_db_name_len(
 
226
/*=================*/
 
227
        const char*     name)   /*!< in: table name in the form
 
228
                                dbname '/' tablename */
 
229
{
 
230
        const char*     s;
 
231
        s = strchr(name, '/');
 
232
        ut_a(s);
 
233
        return(s - name);
 
234
}
 
235
 
 
236
/********************************************************************//**
 
237
Reserves the dictionary system mutex for MySQL. */
 
238
UNIV_INTERN
 
239
void
 
240
dict_mutex_enter_for_mysql(void)
 
241
/*============================*/
 
242
{
 
243
        mutex_enter(&(dict_sys->mutex));
 
244
}
 
245
 
 
246
/********************************************************************//**
 
247
Releases the dictionary system mutex for MySQL. */
 
248
UNIV_INTERN
 
249
void
 
250
dict_mutex_exit_for_mysql(void)
 
251
/*===========================*/
 
252
{
 
253
        mutex_exit(&(dict_sys->mutex));
 
254
}
 
255
 
 
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])
 
260
 
 
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. */
 
265
UNIV_INTERN
 
266
void
 
267
dict_index_stat_mutex_enter(
 
268
/*========================*/
 
269
        const dict_index_t*     index)  /*!< in: index */
 
270
{
 
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);
 
275
 
 
276
        mutex_enter(GET_INDEX_STAT_MUTEX(index));
 
277
}
 
278
 
 
279
/**********************************************************************//**
 
280
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
 
281
UNIV_INTERN
 
282
void
 
283
dict_index_stat_mutex_exit(
 
284
/*=======================*/
 
285
        const dict_index_t*     index)  /*!< in: index */
 
286
{
 
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);
 
291
 
 
292
        mutex_exit(GET_INDEX_STAT_MUTEX(index));
 
293
}
 
294
 
 
295
/********************************************************************//**
 
296
Decrements the count of open MySQL handles to a table. */
 
297
UNIV_INTERN
 
298
void
 
299
dict_table_decrement_handle_count(
 
300
/*==============================*/
 
301
        dict_table_t*   table,          /*!< in/out: table */
 
302
        ibool           dict_locked)    /*!< in: TRUE=data dictionary locked */
 
303
{
 
304
        if (!dict_locked) {
 
305
                mutex_enter(&dict_sys->mutex);
 
306
        }
 
307
 
 
308
        ut_ad(mutex_own(&dict_sys->mutex));
 
309
        ut_a(table->n_mysql_handles_opened > 0);
 
310
 
 
311
        table->n_mysql_handles_opened--;
 
312
 
 
313
        if (!dict_locked) {
 
314
                mutex_exit(&dict_sys->mutex);
 
315
        }
 
316
}
 
317
#endif /* !UNIV_HOTBACKUP */
 
318
 
 
319
/**********************************************************************//**
 
320
Returns a column's name.
 
321
@return column name. NOTE: not guaranteed to stay valid if table is
 
322
modified in any way (columns added, etc.). */
 
323
UNIV_INTERN
 
324
const char*
 
325
dict_table_get_col_name(
 
326
/*====================*/
 
327
        const dict_table_t*     table,  /*!< in: table */
 
328
        ulint                   col_nr) /*!< in: column number */
 
329
{
 
330
        ulint           i;
 
331
        const char*     s;
 
332
 
 
333
        ut_ad(table);
 
334
        ut_ad(col_nr < table->n_def);
 
335
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
336
 
 
337
        s = table->col_names;
 
338
        if (s) {
 
339
                for (i = 0; i < col_nr; i++) {
 
340
                        s += strlen(s) + 1;
 
341
                }
 
342
        }
 
343
 
 
344
        return(s);
 
345
}
 
346
 
 
347
#ifndef UNIV_HOTBACKUP
 
348
/********************************************************************//**
 
349
Acquire the autoinc lock. */
 
350
UNIV_INTERN
 
351
void
 
352
dict_table_autoinc_lock(
 
353
/*====================*/
 
354
        dict_table_t*   table)  /*!< in/out: table */
 
355
{
 
356
        mutex_enter(&table->autoinc_mutex);
 
357
}
 
358
 
 
359
/********************************************************************//**
 
360
Unconditionally set the autoinc counter. */
 
361
UNIV_INTERN
 
362
void
 
363
dict_table_autoinc_initialize(
 
364
/*==========================*/
 
365
        dict_table_t*   table,  /*!< in/out: table */
 
366
        ib_uint64_t     value)  /*!< in: next value to assign to a row */
 
367
{
 
368
        ut_ad(mutex_own(&table->autoinc_mutex));
 
369
 
 
370
        table->autoinc = value;
 
371
}
 
372
 
 
373
/********************************************************************//**
 
374
Reads the next autoinc value (== autoinc counter value), 0 if not yet
 
375
initialized.
 
376
@return value for a new row, or 0 */
 
377
UNIV_INTERN
 
378
ib_uint64_t
 
379
dict_table_autoinc_read(
 
380
/*====================*/
 
381
        const dict_table_t*     table)  /*!< in: table */
 
382
{
 
383
        ut_ad(mutex_own(&table->autoinc_mutex));
 
384
 
 
385
        return(table->autoinc);
 
386
}
 
387
 
 
388
/********************************************************************//**
 
389
Updates the autoinc counter if the value supplied is greater than the
 
390
current value. */
 
391
UNIV_INTERN
 
392
void
 
393
dict_table_autoinc_update_if_greater(
 
394
/*=================================*/
 
395
 
 
396
        dict_table_t*   table,  /*!< in/out: table */
 
397
        ib_uint64_t     value)  /*!< in: value which was assigned to a row */
 
398
{
 
399
        ut_ad(mutex_own(&table->autoinc_mutex));
 
400
 
 
401
        if (value > table->autoinc) {
 
402
 
 
403
                table->autoinc = value;
 
404
        }
 
405
}
 
406
 
 
407
/********************************************************************//**
 
408
Release the autoinc lock. */
 
409
UNIV_INTERN
 
410
void
 
411
dict_table_autoinc_unlock(
 
412
/*======================*/
 
413
        dict_table_t*   table)  /*!< in/out: table */
 
414
{
 
415
        mutex_exit(&table->autoinc_mutex);
 
416
}
 
417
 
 
418
/**********************************************************************//**
 
419
Looks for an index with the given table and index id.
 
420
NOTE that we do not reserve the dictionary mutex.
 
421
@return index or NULL if not found from cache */
 
422
UNIV_INTERN
 
423
dict_index_t*
 
424
dict_index_get_on_id_low(
 
425
/*=====================*/
 
426
        dict_table_t*   table,  /*!< in: table */
 
427
        index_id_t      id)     /*!< in: index id */
 
428
{
 
429
        dict_index_t*   index;
 
430
 
 
431
        index = dict_table_get_first_index(table);
 
432
 
 
433
        while (index) {
 
434
                if (id == index->id) {
 
435
                        /* Found */
 
436
 
 
437
                        return(index);
 
438
                }
 
439
 
 
440
                index = dict_table_get_next_index(index);
 
441
        }
 
442
 
 
443
        return(NULL);
 
444
}
 
445
#endif /* !UNIV_HOTBACKUP */
 
446
 
 
447
/********************************************************************//**
 
448
Looks for column n in an index.
 
449
@return position in internal representation of the index;
 
450
ULINT_UNDEFINED if not contained */
 
451
UNIV_INTERN
 
452
ulint
 
453
dict_index_get_nth_col_pos(
 
454
/*=======================*/
 
455
        const dict_index_t*     index,  /*!< in: index */
 
456
        ulint                   n)      /*!< in: column number */
 
457
{
 
458
        const dict_field_t*     field;
 
459
        const dict_col_t*       col;
 
460
        ulint                   pos;
 
461
        ulint                   n_fields;
 
462
 
 
463
        ut_ad(index);
 
464
        ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
465
 
 
466
        col = dict_table_get_nth_col(index->table, n);
 
467
 
 
468
        if (dict_index_is_clust(index)) {
 
469
 
 
470
                return(dict_col_get_clust_pos(col, index));
 
471
        }
 
472
 
 
473
        n_fields = dict_index_get_n_fields(index);
 
474
 
 
475
        for (pos = 0; pos < n_fields; pos++) {
 
476
                field = dict_index_get_nth_field(index, pos);
 
477
 
 
478
                if (col == field->col && field->prefix_len == 0) {
 
479
 
 
480
                        return(pos);
 
481
                }
 
482
        }
 
483
 
 
484
        return(ULINT_UNDEFINED);
 
485
}
 
486
 
 
487
#ifndef UNIV_HOTBACKUP
 
488
/********************************************************************//**
 
489
Returns TRUE if the index contains a column or a prefix of that column.
 
490
@return TRUE if contains the column or its prefix */
 
491
UNIV_INTERN
 
492
ibool
 
493
dict_index_contains_col_or_prefix(
 
494
/*==============================*/
 
495
        const dict_index_t*     index,  /*!< in: index */
 
496
        ulint                   n)      /*!< in: column number */
 
497
{
 
498
        const dict_field_t*     field;
 
499
        const dict_col_t*       col;
 
500
        ulint                   pos;
 
501
        ulint                   n_fields;
 
502
 
 
503
        ut_ad(index);
 
504
        ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
505
 
 
506
        if (dict_index_is_clust(index)) {
 
507
 
 
508
                return(TRUE);
 
509
        }
 
510
 
 
511
        col = dict_table_get_nth_col(index->table, n);
 
512
 
 
513
        n_fields = dict_index_get_n_fields(index);
 
514
 
 
515
        for (pos = 0; pos < n_fields; pos++) {
 
516
                field = dict_index_get_nth_field(index, pos);
 
517
 
 
518
                if (col == field->col) {
 
519
 
 
520
                        return(TRUE);
 
521
                }
 
522
        }
 
523
 
 
524
        return(FALSE);
 
525
}
 
526
 
 
527
/********************************************************************//**
 
528
Looks for a matching field in an index. The column has to be the same. The
 
529
column in index must be complete, or must contain a prefix longer than the
 
530
column in index2. That is, we must be able to construct the prefix in index2
 
531
from the prefix in index.
 
532
@return position in internal representation of the index;
 
533
ULINT_UNDEFINED if not contained */
 
534
UNIV_INTERN
 
535
ulint
 
536
dict_index_get_nth_field_pos(
 
537
/*=========================*/
 
538
        const dict_index_t*     index,  /*!< in: index from which to search */
 
539
        const dict_index_t*     index2, /*!< in: index */
 
540
        ulint                   n)      /*!< in: field number in index2 */
 
541
{
 
542
        const dict_field_t*     field;
 
543
        const dict_field_t*     field2;
 
544
        ulint                   n_fields;
 
545
        ulint                   pos;
 
546
 
 
547
        ut_ad(index);
 
548
        ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
549
 
 
550
        field2 = dict_index_get_nth_field(index2, n);
 
551
 
 
552
        n_fields = dict_index_get_n_fields(index);
 
553
 
 
554
        for (pos = 0; pos < n_fields; pos++) {
 
555
                field = dict_index_get_nth_field(index, pos);
 
556
 
 
557
                if (field->col == field2->col
 
558
                    && (field->prefix_len == 0
 
559
                        || (field->prefix_len >= field2->prefix_len
 
560
                            && field2->prefix_len != 0))) {
 
561
 
 
562
                        return(pos);
 
563
                }
 
564
        }
 
565
 
 
566
        return(ULINT_UNDEFINED);
 
567
}
 
568
 
 
569
/**********************************************************************//**
 
570
Returns a table object based on table id.
 
571
@return table, NULL if does not exist */
 
572
UNIV_INTERN
 
573
dict_table_t*
 
574
dict_table_get_on_id(
 
575
/*=================*/
 
576
        table_id_t      table_id,       /*!< in: table id */
 
577
        trx_t*          trx)            /*!< in: transaction handle */
 
578
{
 
579
        dict_table_t*   table;
 
580
 
 
581
        if (trx->dict_operation_lock_mode == RW_X_LATCH) {
 
582
 
 
583
                /* Note: An X latch implies that the transaction
 
584
                already owns the dictionary mutex. */
 
585
 
 
586
                ut_ad(mutex_own(&dict_sys->mutex));
 
587
 
 
588
                return(dict_table_get_on_id_low(table_id));
 
589
        }
 
590
 
 
591
        mutex_enter(&(dict_sys->mutex));
 
592
 
 
593
        table = dict_table_get_on_id_low(table_id);
 
594
 
 
595
        mutex_exit(&(dict_sys->mutex));
 
596
 
 
597
        return(table);
 
598
}
 
599
 
 
600
/********************************************************************//**
 
601
Looks for column n position in the clustered index.
 
602
@return position in internal representation of the clustered index */
 
603
UNIV_INTERN
 
604
ulint
 
605
dict_table_get_nth_col_pos(
 
606
/*=======================*/
 
607
        const dict_table_t*     table,  /*!< in: table */
 
608
        ulint                   n)      /*!< in: column number */
 
609
{
 
610
        return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
 
611
                                          n));
 
612
}
 
613
 
 
614
/********************************************************************//**
 
615
Checks if a column is in the ordering columns of the clustered index of a
 
616
table. Column prefixes are treated like whole columns.
 
617
@return TRUE if the column, or its prefix, is in the clustered key */
 
618
UNIV_INTERN
 
619
ibool
 
620
dict_table_col_in_clustered_key(
 
621
/*============================*/
 
622
        const dict_table_t*     table,  /*!< in: table */
 
623
        ulint                   n)      /*!< in: column number */
 
624
{
 
625
        const dict_index_t*     index;
 
626
        const dict_field_t*     field;
 
627
        const dict_col_t*       col;
 
628
        ulint                   pos;
 
629
        ulint                   n_fields;
 
630
 
 
631
        ut_ad(table);
 
632
 
 
633
        col = dict_table_get_nth_col(table, n);
 
634
 
 
635
        index = dict_table_get_first_index(table);
 
636
 
 
637
        n_fields = dict_index_get_n_unique(index);
 
638
 
 
639
        for (pos = 0; pos < n_fields; pos++) {
 
640
                field = dict_index_get_nth_field(index, pos);
 
641
 
 
642
                if (col == field->col) {
 
643
 
 
644
                        return(TRUE);
 
645
                }
 
646
        }
 
647
 
 
648
        return(FALSE);
 
649
}
 
650
 
 
651
/**********************************************************************//**
 
652
Inits the data dictionary module. */
 
653
UNIV_INTERN
 
654
void
 
655
dict_init(void)
 
656
/*===========*/
 
657
{
 
658
        int     i;
 
659
 
 
660
        dict_sys = mem_alloc(sizeof(dict_sys_t));
 
661
 
 
662
        mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
 
663
 
 
664
        dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
 
665
                                           / (DICT_POOL_PER_TABLE_HASH
 
666
                                              * UNIV_WORD_SIZE));
 
667
        dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
 
668
                                              / (DICT_POOL_PER_TABLE_HASH
 
669
                                                 * UNIV_WORD_SIZE));
 
670
        dict_sys->size = 0;
 
671
 
 
672
        UT_LIST_INIT(dict_sys->table_LRU);
 
673
 
 
674
        rw_lock_create(dict_operation_lock_key,
 
675
                       &dict_operation_lock, SYNC_DICT_OPERATION);
 
676
 
 
677
        dict_foreign_err_file = os_file_create_tmpfile();
 
678
        ut_a(dict_foreign_err_file);
 
679
 
 
680
        mutex_create(dict_foreign_err_mutex_key,
 
681
                     &dict_foreign_err_mutex, SYNC_ANY_LATCH);
 
682
 
 
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);
 
686
        }
 
687
}
 
688
 
 
689
/**********************************************************************//**
 
690
Returns a table object and optionally increment its MySQL open handle count.
 
691
NOTE! This is a high-level function to be used mainly from outside the
 
692
'dict' directory. Inside this directory dict_table_get_low is usually the
 
693
appropriate function.
 
694
@return table, NULL if does not exist */
 
695
UNIV_INTERN
 
696
dict_table_t*
 
697
dict_table_get(
 
698
/*===========*/
 
699
        const char*     table_name,     /*!< in: table name */
 
700
        ibool           inc_mysql_count)/*!< in: whether to increment the open
 
701
                                        handle count on the table */
 
702
{
 
703
        dict_table_t*   table;
 
704
 
 
705
        mutex_enter(&(dict_sys->mutex));
 
706
 
 
707
        table = dict_table_get_low(table_name);
 
708
 
 
709
        if (inc_mysql_count && table) {
 
710
                table->n_mysql_handles_opened++;
 
711
        }
 
712
 
 
713
        mutex_exit(&(dict_sys->mutex));
 
714
 
 
715
        if (table != NULL) {
 
716
                if (!table->stat_initialized) {
 
717
                        /* If table->ibd_file_missing == TRUE, this will
 
718
                        print an error message and return without doing
 
719
                        anything. */
 
720
                        dict_update_statistics(table);
 
721
                }
 
722
        }
 
723
 
 
724
        return(table);
 
725
}
 
726
#endif /* !UNIV_HOTBACKUP */
 
727
 
 
728
/**********************************************************************//**
 
729
Adds system columns to a table object. */
 
730
UNIV_INTERN
 
731
void
 
732
dict_table_add_system_columns(
 
733
/*==========================*/
 
734
        dict_table_t*   table,  /*!< in/out: table */
 
735
        mem_heap_t*     heap)   /*!< in: temporary heap */
 
736
{
 
737
        ut_ad(table);
 
738
        ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
 
739
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
740
        ut_ad(!table->cached);
 
741
 
 
742
        /* NOTE: the system columns MUST be added in the following order
 
743
        (so that they can be indexed by the numerical value of DATA_ROW_ID,
 
744
        etc.) and as the last columns of the table memory object.
 
745
        The clustered index will not always physically contain all
 
746
        system columns. */
 
747
 
 
748
        dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
 
749
                               DATA_ROW_ID | DATA_NOT_NULL,
 
750
                               DATA_ROW_ID_LEN);
 
751
#if DATA_ROW_ID != 0
 
752
#error "DATA_ROW_ID != 0"
 
753
#endif
 
754
        dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
 
755
                               DATA_TRX_ID | DATA_NOT_NULL,
 
756
                               DATA_TRX_ID_LEN);
 
757
#if DATA_TRX_ID != 1
 
758
#error "DATA_TRX_ID != 1"
 
759
#endif
 
760
        dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
 
761
                               DATA_ROLL_PTR | DATA_NOT_NULL,
 
762
                               DATA_ROLL_PTR_LEN);
 
763
#if DATA_ROLL_PTR != 2
 
764
#error "DATA_ROLL_PTR != 2"
 
765
#endif
 
766
 
 
767
        /* This check reminds that if a new system column is added to
 
768
        the program, it should be dealt with here */
 
769
#if DATA_N_SYS_COLS != 3
 
770
#error "DATA_N_SYS_COLS != 3"
 
771
#endif
 
772
}
 
773
 
 
774
#ifndef UNIV_HOTBACKUP
 
775
/**********************************************************************//**
 
776
Adds a table object to the dictionary cache. */
 
777
UNIV_INTERN
 
778
void
 
779
dict_table_add_to_cache(
 
780
/*====================*/
 
781
        dict_table_t*   table,  /*!< in: table */
 
782
        mem_heap_t*     heap)   /*!< in: temporary heap */
 
783
{
 
784
        ulint   fold;
 
785
        ulint   id_fold;
 
786
        ulint   i;
 
787
        ulint   row_len;
 
788
 
 
789
        /* The lower limit for what we consider a "big" row */
 
790
#define BIG_ROW_SIZE 1024
 
791
 
 
792
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
793
 
 
794
        dict_table_add_system_columns(table, heap);
 
795
 
 
796
        table->cached = TRUE;
 
797
 
 
798
        fold = ut_fold_string(table->name);
 
799
        id_fold = ut_fold_ull(table->id);
 
800
 
 
801
        row_len = 0;
 
802
        for (i = 0; i < table->n_def; i++) {
 
803
                ulint   col_len = dict_col_get_max_size(
 
804
                        dict_table_get_nth_col(table, i));
 
805
 
 
806
                row_len += col_len;
 
807
 
 
808
                /* If we have a single unbounded field, or several gigantic
 
809
                fields, mark the maximum row size as BIG_ROW_SIZE. */
 
810
                if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
 
811
                        row_len = BIG_ROW_SIZE;
 
812
 
 
813
                        break;
 
814
                }
 
815
        }
 
816
 
 
817
        table->big_rows = row_len >= BIG_ROW_SIZE;
 
818
 
 
819
        /* Look for a table with the same name: error if such exists */
 
820
        {
 
821
                dict_table_t*   table2;
 
822
                HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
 
823
                            dict_table_t*, table2, ut_ad(table2->cached),
 
824
                            ut_strcmp(table2->name, table->name) == 0);
 
825
                ut_a(table2 == NULL);
 
826
 
 
827
#ifdef UNIV_DEBUG
 
828
                /* Look for the same table pointer with a different name */
 
829
                HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
 
830
                                dict_table_t*, table2, ut_ad(table2->cached),
 
831
                                table2 == table);
 
832
                ut_ad(table2 == NULL);
 
833
#endif /* UNIV_DEBUG */
 
834
        }
 
835
 
 
836
        /* Look for a table with the same id: error if such exists */
 
837
        {
 
838
                dict_table_t*   table2;
 
839
                HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
 
840
                            dict_table_t*, table2, ut_ad(table2->cached),
 
841
                            table2->id == table->id);
 
842
                ut_a(table2 == NULL);
 
843
 
 
844
#ifdef UNIV_DEBUG
 
845
                /* Look for the same table pointer with a different id */
 
846
                HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
 
847
                                dict_table_t*, table2, ut_ad(table2->cached),
 
848
                                table2 == table);
 
849
                ut_ad(table2 == NULL);
 
850
#endif /* UNIV_DEBUG */
 
851
        }
 
852
 
 
853
        /* Add table to hash table of tables */
 
854
        HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
 
855
                    table);
 
856
 
 
857
        /* Add table to hash table of tables based on table id */
 
858
        HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
 
859
                    table);
 
860
        /* Add table to LRU list of tables */
 
861
        UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
 
862
 
 
863
        dict_sys->size += mem_heap_get_size(table->heap)
 
864
                + strlen(table->name) + 1;
 
865
}
 
866
 
 
867
/**********************************************************************//**
 
868
Looks for an index with the given id. NOTE that we do not reserve
 
869
the dictionary mutex: this function is for emergency purposes like
 
870
printing info of a corrupt database page!
 
871
@return index or NULL if not found from cache */
 
872
UNIV_INTERN
 
873
dict_index_t*
 
874
dict_index_find_on_id_low(
 
875
/*======================*/
 
876
        index_id_t      id)     /*!< in: index id */
 
877
{
 
878
        dict_table_t*   table;
 
879
        dict_index_t*   index;
 
880
 
 
881
        table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
 
882
 
 
883
        while (table) {
 
884
                index = dict_table_get_first_index(table);
 
885
 
 
886
                while (index) {
 
887
                        if (id == index->id) {
 
888
                                /* Found */
 
889
 
 
890
                                return(index);
 
891
                        }
 
892
 
 
893
                        index = dict_table_get_next_index(index);
 
894
                }
 
895
 
 
896
                table = UT_LIST_GET_NEXT(table_LRU, table);
 
897
        }
 
898
 
 
899
        return(NULL);
 
900
}
 
901
 
 
902
/**********************************************************************//**
 
903
Renames a table object.
 
904
@return TRUE if success */
 
905
UNIV_INTERN
 
906
ibool
 
907
dict_table_rename_in_cache(
 
908
/*=======================*/
 
909
        dict_table_t*   table,          /*!< in/out: table */
 
910
        const char*     new_name,       /*!< in: new name */
 
911
        ibool           rename_also_foreigns)/*!< in: in ALTER TABLE we want
 
912
                                        to preserve the original table name
 
913
                                        in constraints which reference it */
 
914
{
 
915
        dict_foreign_t* foreign;
 
916
        dict_index_t*   index;
 
917
        ulint           fold;
 
918
        char            old_name[MAX_TABLE_NAME_LEN + 1];
 
919
 
 
920
        ut_ad(table);
 
921
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
922
 
 
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);
 
926
        } else {
 
927
                ut_print_timestamp(stderr);
 
928
                fprintf(stderr, "InnoDB: too long table name: '%s', "
 
929
                        "max length is %d\n", table->name,
 
930
                        MAX_TABLE_NAME_LEN);
 
931
                ut_error;
 
932
        }
 
933
 
 
934
        fold = ut_fold_string(new_name);
 
935
 
 
936
        /* Look for a table with the same name: error if such exists */
 
937
        {
 
938
                dict_table_t*   table2;
 
939
                HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
 
940
                            dict_table_t*, table2, ut_ad(table2->cached),
 
941
                            (ut_strcmp(table2->name, new_name) == 0));
 
942
                if (UNIV_LIKELY_NULL(table2)) {
 
943
                        ut_print_timestamp(stderr);
 
944
                        fputs("  InnoDB: Error: dictionary cache"
 
945
                              " already contains a table ", stderr);
 
946
                        ut_print_name(stderr, NULL, TRUE, new_name);
 
947
                        fputs("\n"
 
948
                              "InnoDB: cannot rename table ", stderr);
 
949
                        ut_print_name(stderr, NULL, TRUE, old_name);
 
950
                        putc('\n', stderr);
 
951
                        return(FALSE);
 
952
                }
 
953
        }
 
954
 
 
955
        /* If the table is stored in a single-table tablespace, rename the
 
956
        .ibd file */
 
957
 
 
958
        if (table->space != 0) {
 
959
                if (table->dir_path_of_temp_table != NULL) {
 
960
                        ut_print_timestamp(stderr);
 
961
                        fputs("  InnoDB: Error: trying to rename a"
 
962
                              " TEMPORARY TABLE ", stderr);
 
963
                        ut_print_name(stderr, NULL, TRUE, old_name);
 
964
                        fputs(" (", stderr);
 
965
                        ut_print_filename(stderr,
 
966
                                          table->dir_path_of_temp_table);
 
967
                        fputs(" )\n", stderr);
 
968
                        return(FALSE);
 
969
                } else if (!fil_rename_tablespace(old_name, table->space,
 
970
                                                  new_name)) {
 
971
                        return(FALSE);
 
972
                }
 
973
        }
 
974
 
 
975
        /* Remove table from the hash tables of tables */
 
976
        HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
 
977
                    ut_fold_string(old_name), table);
 
978
 
 
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);
 
985
        }
 
986
        memcpy(table->name, new_name, strlen(new_name) + 1);
 
987
 
 
988
        /* Add table to hash table of tables */
 
989
        HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
 
990
                    table);
 
991
 
 
992
        dict_sys->size += strlen(new_name) - strlen(old_name);
 
993
        ut_a(dict_sys->size > 0);
 
994
 
 
995
        /* Update the table_name field in indexes */
 
996
        index = dict_table_get_first_index(table);
 
997
 
 
998
        while (index != NULL) {
 
999
                index->table_name = table->name;
 
1000
 
 
1001
                index = dict_table_get_next_index(index);
 
1002
        }
 
1003
 
 
1004
        if (!rename_also_foreigns) {
 
1005
                /* In ALTER TABLE we think of the rename table operation
 
1006
                in the direction table -> temporary table (#sql...)
 
1007
                as dropping the table with the old name and creating
 
1008
                a new with the new name. Thus we kind of drop the
 
1009
                constraints from the dictionary cache here. The foreign key
 
1010
                constraints will be inherited to the new table from the
 
1011
                system tables through a call of dict_load_foreigns. */
 
1012
 
 
1013
                /* Remove the foreign constraints from the cache */
 
1014
                foreign = UT_LIST_GET_LAST(table->foreign_list);
 
1015
 
 
1016
                while (foreign != NULL) {
 
1017
                        dict_foreign_remove_from_cache(foreign);
 
1018
                        foreign = UT_LIST_GET_LAST(table->foreign_list);
 
1019
                }
 
1020
 
 
1021
                /* Reset table field in referencing constraints */
 
1022
 
 
1023
                foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
1024
 
 
1025
                while (foreign != NULL) {
 
1026
                        foreign->referenced_table = NULL;
 
1027
                        foreign->referenced_index = NULL;
 
1028
 
 
1029
                        foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
1030
                }
 
1031
 
 
1032
                /* Make the list of referencing constraints empty */
 
1033
 
 
1034
                UT_LIST_INIT(table->referenced_list);
 
1035
 
 
1036
                return(TRUE);
 
1037
        }
 
1038
 
 
1039
        /* Update the table name fields in foreign constraints, and update also
 
1040
        the constraint id of new format >= 4.0.18 constraints. Note that at
 
1041
        this point we have already changed table->name to the new name. */
 
1042
 
 
1043
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
1044
 
 
1045
        while (foreign != NULL) {
 
1046
                if (ut_strlen(foreign->foreign_table_name)
 
1047
                    < ut_strlen(table->name)) {
 
1048
                        /* Allocate a longer name buffer;
 
1049
                        TODO: store buf len to save memory */
 
1050
 
 
1051
                        foreign->foreign_table_name
 
1052
                                = mem_heap_alloc(foreign->heap,
 
1053
                                                 ut_strlen(table->name) + 1);
 
1054
                }
 
1055
 
 
1056
                strcpy(foreign->foreign_table_name, table->name);
 
1057
 
 
1058
                if (strchr(foreign->id, '/')) {
 
1059
                        ulint   db_len;
 
1060
                        char*   old_id;
 
1061
 
 
1062
                        /* This is a >= 4.0.18 format id */
 
1063
 
 
1064
                        old_id = mem_strdup(foreign->id);
 
1065
 
 
1066
                        if (ut_strlen(foreign->id) > ut_strlen(old_name)
 
1067
                            + ((sizeof dict_ibfk) - 1)
 
1068
                            && !memcmp(foreign->id, old_name,
 
1069
                                       ut_strlen(old_name))
 
1070
                            && !memcmp(foreign->id + ut_strlen(old_name),
 
1071
                                       dict_ibfk, (sizeof dict_ibfk) - 1)) {
 
1072
 
 
1073
                                /* This is a generated >= 4.0.18 format id */
 
1074
 
 
1075
                                if (strlen(table->name) > strlen(old_name)) {
 
1076
                                        foreign->id = mem_heap_alloc(
 
1077
                                                foreign->heap,
 
1078
                                                strlen(table->name)
 
1079
                                                + strlen(old_id) + 1);
 
1080
                                }
 
1081
 
 
1082
                                /* Replace the prefix 'databasename/tablename'
 
1083
                                with the new names */
 
1084
                                strcpy(foreign->id, table->name);
 
1085
                                strcat(foreign->id,
 
1086
                                       old_id + ut_strlen(old_name));
 
1087
                        } else {
 
1088
                                /* This is a >= 4.0.18 format id where the user
 
1089
                                gave the id name */
 
1090
                                db_len = dict_get_db_name_len(table->name) + 1;
 
1091
 
 
1092
                                if (dict_get_db_name_len(table->name)
 
1093
                                    > dict_get_db_name_len(foreign->id)) {
 
1094
 
 
1095
                                        foreign->id = mem_heap_alloc(
 
1096
                                                foreign->heap,
 
1097
                                                db_len + strlen(old_id) + 1);
 
1098
                                }
 
1099
 
 
1100
                                /* Replace the database prefix in id with the
 
1101
                                one from table->name */
 
1102
 
 
1103
                                ut_memcpy(foreign->id, table->name, db_len);
 
1104
 
 
1105
                                strcpy(foreign->id + db_len,
 
1106
                                       dict_remove_db_name(old_id));
 
1107
                        }
 
1108
 
 
1109
                        mem_free(old_id);
 
1110
                }
 
1111
 
 
1112
                foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
1113
        }
 
1114
 
 
1115
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
1116
 
 
1117
        while (foreign != NULL) {
 
1118
                if (ut_strlen(foreign->referenced_table_name)
 
1119
                    < ut_strlen(table->name)) {
 
1120
                        /* Allocate a longer name buffer;
 
1121
                        TODO: store buf len to save memory */
 
1122
 
 
1123
                        foreign->referenced_table_name = mem_heap_alloc(
 
1124
                                foreign->heap, strlen(table->name) + 1);
 
1125
                }
 
1126
 
 
1127
                strcpy(foreign->referenced_table_name, table->name);
 
1128
 
 
1129
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
1130
        }
 
1131
 
 
1132
        return(TRUE);
 
1133
}
 
1134
 
 
1135
/**********************************************************************//**
 
1136
Change the id of a table object in the dictionary cache. This is used in
 
1137
DISCARD TABLESPACE. */
 
1138
UNIV_INTERN
 
1139
void
 
1140
dict_table_change_id_in_cache(
 
1141
/*==========================*/
 
1142
        dict_table_t*   table,  /*!< in/out: table object already in cache */
 
1143
        table_id_t      new_id) /*!< in: new id to set */
 
1144
{
 
1145
        ut_ad(table);
 
1146
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1147
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
1148
 
 
1149
        /* Remove the table from the hash table of id's */
 
1150
 
 
1151
        HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
 
1152
                    ut_fold_ull(table->id), table);
 
1153
        table->id = new_id;
 
1154
 
 
1155
        /* Add the table back to the hash table */
 
1156
        HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
 
1157
                    ut_fold_ull(table->id), table);
 
1158
}
 
1159
 
 
1160
/**********************************************************************//**
 
1161
Removes a table object from the dictionary cache. */
 
1162
UNIV_INTERN
 
1163
void
 
1164
dict_table_remove_from_cache(
 
1165
/*=========================*/
 
1166
        dict_table_t*   table)  /*!< in, own: table */
 
1167
{
 
1168
        dict_foreign_t* foreign;
 
1169
        dict_index_t*   index;
 
1170
        ulint           size;
 
1171
 
 
1172
        ut_ad(table);
 
1173
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1174
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
1175
 
 
1176
#if 0
 
1177
        fputs("Removing table ", stderr);
 
1178
        ut_print_name(stderr, table->name, ULINT_UNDEFINED);
 
1179
        fputs(" from dictionary cache\n", stderr);
 
1180
#endif
 
1181
 
 
1182
        /* Remove the foreign constraints from the cache */
 
1183
        foreign = UT_LIST_GET_LAST(table->foreign_list);
 
1184
 
 
1185
        while (foreign != NULL) {
 
1186
                dict_foreign_remove_from_cache(foreign);
 
1187
                foreign = UT_LIST_GET_LAST(table->foreign_list);
 
1188
        }
 
1189
 
 
1190
        /* Reset table field in referencing constraints */
 
1191
 
 
1192
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
1193
 
 
1194
        while (foreign != NULL) {
 
1195
                foreign->referenced_table = NULL;
 
1196
                foreign->referenced_index = NULL;
 
1197
 
 
1198
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
1199
        }
 
1200
 
 
1201
        /* Remove the indexes from the cache */
 
1202
        index = UT_LIST_GET_LAST(table->indexes);
 
1203
 
 
1204
        while (index != NULL) {
 
1205
                dict_index_remove_from_cache(table, index);
 
1206
                index = UT_LIST_GET_LAST(table->indexes);
 
1207
        }
 
1208
 
 
1209
        /* Remove table from the hash tables of tables */
 
1210
        HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
 
1211
                    ut_fold_string(table->name), table);
 
1212
        HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
 
1213
                    ut_fold_ull(table->id), table);
 
1214
 
 
1215
        /* Remove table from LRU list of tables */
 
1216
        UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
 
1217
 
 
1218
        size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
 
1219
 
 
1220
        ut_ad(dict_sys->size >= size);
 
1221
 
 
1222
        dict_sys->size -= size;
 
1223
 
 
1224
        dict_mem_table_free(table);
 
1225
}
 
1226
 
 
1227
/****************************************************************//**
 
1228
If the given column name is reserved for InnoDB system columns, return
 
1229
TRUE.
 
1230
@return TRUE if name is reserved */
 
1231
UNIV_INTERN
 
1232
ibool
 
1233
dict_col_name_is_reserved(
 
1234
/*======================*/
 
1235
        const char*     name)   /*!< in: column name */
 
1236
{
 
1237
        /* This check reminds that if a new system column is added to
 
1238
        the program, it should be dealt with here. */
 
1239
#if DATA_N_SYS_COLS != 3
 
1240
#error "DATA_N_SYS_COLS != 3"
 
1241
#endif
 
1242
 
 
1243
        static const char*      reserved_names[] = {
 
1244
                "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
 
1245
        };
 
1246
 
 
1247
        ulint                   i;
 
1248
 
 
1249
        for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
 
1250
                if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
 
1251
 
 
1252
                        return(TRUE);
 
1253
                }
 
1254
        }
 
1255
 
 
1256
        return(FALSE);
 
1257
}
 
1258
 
 
1259
/****************************************************************//**
 
1260
If an undo log record for this table might not fit on a single page,
 
1261
return TRUE.
 
1262
@return TRUE if the undo log record could become too big */
 
1263
static
 
1264
ibool
 
1265
dict_index_too_big_for_undo(
 
1266
/*========================*/
 
1267
        const dict_table_t*     table,          /*!< in: table */
 
1268
        const dict_index_t*     new_index)      /*!< in: index */
 
1269
{
 
1270
        /* Make sure that all column prefixes will fit in the undo log record
 
1271
        in trx_undo_page_report_modify() right after trx_undo_page_init(). */
 
1272
 
 
1273
        ulint                   i;
 
1274
        const dict_index_t*     clust_index
 
1275
                = dict_table_get_first_index(table);
 
1276
        ulint                   undo_page_len
 
1277
                = TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
 
1278
                + 2 /* next record pointer */
 
1279
                + 1 /* type_cmpl */
 
1280
                + 11 /* trx->undo_no */ + 11 /* table->id */
 
1281
                + 1 /* rec_get_info_bits() */
 
1282
                + 11 /* DB_TRX_ID */
 
1283
                + 11 /* DB_ROLL_PTR */
 
1284
                + 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
 
1285
                + 2/* pointer to previous undo log record */;
 
1286
 
 
1287
        if (UNIV_UNLIKELY(!clust_index)) {
 
1288
                ut_a(dict_index_is_clust(new_index));
 
1289
                clust_index = new_index;
 
1290
        }
 
1291
 
 
1292
        /* Add the size of the ordering columns in the
 
1293
        clustered index. */
 
1294
        for (i = 0; i < clust_index->n_uniq; i++) {
 
1295
                const dict_col_t*       col
 
1296
                        = dict_index_get_nth_col(clust_index, i);
 
1297
 
 
1298
                /* Use the maximum output size of
 
1299
                mach_write_compressed(), although the encoded
 
1300
                length should always fit in 2 bytes. */
 
1301
                undo_page_len += 5 + dict_col_get_max_size(col);
 
1302
        }
 
1303
 
 
1304
        /* Add the old values of the columns to be updated.
 
1305
        First, the amount and the numbers of the columns.
 
1306
        These are written by mach_write_compressed() whose
 
1307
        maximum output length is 5 bytes.  However, given that
 
1308
        the quantities are below REC_MAX_N_FIELDS (10 bits),
 
1309
        the maximum length is 2 bytes per item. */
 
1310
        undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
 
1311
 
 
1312
        for (i = 0; i < clust_index->n_def; i++) {
 
1313
                const dict_col_t*       col
 
1314
                        = dict_index_get_nth_col(clust_index, i);
 
1315
                ulint                   max_size
 
1316
                        = dict_col_get_max_size(col);
 
1317
                ulint                   fixed_size
 
1318
                        = dict_col_get_fixed_size(col,
 
1319
                                                  dict_table_is_comp(table));
 
1320
 
 
1321
                if (fixed_size) {
 
1322
                        /* Fixed-size columns are stored locally. */
 
1323
                        max_size = fixed_size;
 
1324
                } else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
 
1325
                        /* Short columns are stored locally. */
 
1326
                } else if (!col->ord_part) {
 
1327
                        /* See if col->ord_part would be set
 
1328
                        because of new_index. */
 
1329
                        ulint   j;
 
1330
 
 
1331
                        for (j = 0; j < new_index->n_uniq; j++) {
 
1332
                                if (dict_index_get_nth_col(
 
1333
                                            new_index, j) == col) {
 
1334
 
 
1335
                                        goto is_ord_part;
 
1336
                                }
 
1337
                        }
 
1338
 
 
1339
                        /* This is not an ordering column in any index.
 
1340
                        Thus, it can be stored completely externally. */
 
1341
                        max_size = BTR_EXTERN_FIELD_REF_SIZE;
 
1342
                } else {
 
1343
is_ord_part:
 
1344
                        /* This is an ordering column in some index.
 
1345
                        A long enough prefix must be written to the
 
1346
                        undo log.  See trx_undo_page_fetch_ext(). */
 
1347
 
 
1348
                        if (max_size > REC_MAX_INDEX_COL_LEN) {
 
1349
                                max_size = REC_MAX_INDEX_COL_LEN;
 
1350
                        }
 
1351
 
 
1352
                        max_size += BTR_EXTERN_FIELD_REF_SIZE;
 
1353
                }
 
1354
 
 
1355
                undo_page_len += 5 + max_size;
 
1356
        }
 
1357
 
 
1358
        return(undo_page_len >= UNIV_PAGE_SIZE);
 
1359
}
 
1360
 
 
1361
/****************************************************************//**
 
1362
If a record of this index might not fit on a single B-tree page,
 
1363
return TRUE.
 
1364
@return TRUE if the index record could become too big */
 
1365
static
 
1366
ibool
 
1367
dict_index_too_big_for_tree(
 
1368
/*========================*/
 
1369
        const dict_table_t*     table,          /*!< in: table */
 
1370
        const dict_index_t*     new_index)      /*!< in: index */
 
1371
{
 
1372
        ulint   zip_size;
 
1373
        ulint   comp;
 
1374
        ulint   i;
 
1375
        /* maximum possible storage size of a record */
 
1376
        ulint   rec_max_size;
 
1377
        /* maximum allowed size of a record on a leaf page */
 
1378
        ulint   page_rec_max;
 
1379
        /* maximum allowed size of a node pointer record */
 
1380
        ulint   page_ptr_max;
 
1381
 
 
1382
        comp = dict_table_is_comp(table);
 
1383
        zip_size = dict_table_zip_size(table);
 
1384
 
 
1385
        if (zip_size && zip_size < UNIV_PAGE_SIZE) {
 
1386
                /* On a compressed page, two records must fit in the
 
1387
                uncompressed page modification log.  On compressed
 
1388
                pages with zip_size == UNIV_PAGE_SIZE, this limit will
 
1389
                never be reached. */
 
1390
                ut_ad(comp);
 
1391
                /* The maximum allowed record size is the size of
 
1392
                an empty page, minus a byte for recoding the heap
 
1393
                number in the page modification log.  The maximum
 
1394
                allowed node pointer size is half that. */
 
1395
                page_rec_max = page_zip_empty_size(new_index->n_fields,
 
1396
                                                   zip_size) - 1;
 
1397
                page_ptr_max = page_rec_max / 2;
 
1398
                /* On a compressed page, there is a two-byte entry in
 
1399
                the dense page directory for every record.  But there
 
1400
                is no record header. */
 
1401
                rec_max_size = 2;
 
1402
        } else {
 
1403
                /* The maximum allowed record size is half a B-tree
 
1404
                page.  No additional sparse page directory entry will
 
1405
                be generated for the first few user records. */
 
1406
                page_rec_max = page_get_free_space_of_empty(comp) / 2;
 
1407
                page_ptr_max = page_rec_max;
 
1408
                /* Each record has a header. */
 
1409
                rec_max_size = comp
 
1410
                        ? REC_N_NEW_EXTRA_BYTES
 
1411
                        : REC_N_OLD_EXTRA_BYTES;
 
1412
        }
 
1413
 
 
1414
        if (comp) {
 
1415
                /* Include the "null" flags in the
 
1416
                maximum possible record size. */
 
1417
                rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
 
1418
        } else {
 
1419
                /* For each column, include a 2-byte offset and a
 
1420
                "null" flag.  The 1-byte format is only used in short
 
1421
                records that do not contain externally stored columns.
 
1422
                Such records could never exceed the page limit, even
 
1423
                when using the 2-byte format. */
 
1424
                rec_max_size += 2 * new_index->n_fields;
 
1425
        }
 
1426
 
 
1427
        /* Compute the maximum possible record size. */
 
1428
        for (i = 0; i < new_index->n_fields; i++) {
 
1429
                const dict_field_t*     field
 
1430
                        = dict_index_get_nth_field(new_index, i);
 
1431
                const dict_col_t*       col
 
1432
                        = dict_field_get_col(field);
 
1433
                ulint                   field_max_size;
 
1434
                ulint                   field_ext_max_size;
 
1435
 
 
1436
                /* In dtuple_convert_big_rec(), variable-length columns
 
1437
                that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
 
1438
                may be chosen for external storage.
 
1439
 
 
1440
                Fixed-length columns, and all columns of secondary
 
1441
                index records are always stored inline. */
 
1442
 
 
1443
                /* Determine the maximum length of the index field.
 
1444
                The field_ext_max_size should be computed as the worst
 
1445
                case in rec_get_converted_size_comp() for
 
1446
                REC_STATUS_ORDINARY records. */
 
1447
 
 
1448
                field_max_size = dict_col_get_fixed_size(col, comp);
 
1449
                if (field_max_size) {
 
1450
                        /* dict_index_add_col() should guarantee this */
 
1451
                        ut_ad(!field->prefix_len
 
1452
                              || field->fixed_len == field->prefix_len);
 
1453
                        /* Fixed lengths are not encoded
 
1454
                        in ROW_FORMAT=COMPACT. */
 
1455
                        field_ext_max_size = 0;
 
1456
                        goto add_field_size;
 
1457
                }
 
1458
 
 
1459
                field_max_size = dict_col_get_max_size(col);
 
1460
                field_ext_max_size = field_max_size < 256 ? 1 : 2;
 
1461
 
 
1462
                if (field->prefix_len) {
 
1463
                        if (field->prefix_len < field_max_size) {
 
1464
                                field_max_size = field->prefix_len;
 
1465
                        }
 
1466
                } else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
 
1467
                           && dict_index_is_clust(new_index)) {
 
1468
 
 
1469
                        /* In the worst case, we have a locally stored
 
1470
                        column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
 
1471
                        The length can be stored in one byte.  If the
 
1472
                        column were stored externally, the lengths in
 
1473
                        the clustered index page would be
 
1474
                        BTR_EXTERN_FIELD_REF_SIZE and 2. */
 
1475
                        field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
 
1476
                        field_ext_max_size = 1;
 
1477
                }
 
1478
 
 
1479
                if (comp) {
 
1480
                        /* Add the extra size for ROW_FORMAT=COMPACT.
 
1481
                        For ROW_FORMAT=REDUNDANT, these bytes were
 
1482
                        added to rec_max_size before this loop. */
 
1483
                        rec_max_size += field_ext_max_size;
 
1484
                }
 
1485
add_field_size:
 
1486
                rec_max_size += field_max_size;
 
1487
 
 
1488
                /* Check the size limit on leaf pages. */
 
1489
                if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
 
1490
 
 
1491
                        return(TRUE);
 
1492
                }
 
1493
 
 
1494
                /* Check the size limit on non-leaf pages.  Records
 
1495
                stored in non-leaf B-tree pages consist of the unique
 
1496
                columns of the record (the key columns of the B-tree)
 
1497
                and a node pointer field.  When we have processed the
 
1498
                unique columns, rec_max_size equals the size of the
 
1499
                node pointer record minus the node pointer column. */
 
1500
                if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
 
1501
                    && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
 
1502
 
 
1503
                        return(TRUE);
 
1504
                }
 
1505
        }
 
1506
 
 
1507
        return(FALSE);
 
1508
}
 
1509
 
 
1510
/**********************************************************************//**
 
1511
Adds an index to the dictionary cache.
 
1512
@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
 
1513
UNIV_INTERN
 
1514
ulint
 
1515
dict_index_add_to_cache(
 
1516
/*====================*/
 
1517
        dict_table_t*   table,  /*!< in: table on which the index is */
 
1518
        dict_index_t*   index,  /*!< in, own: index; NOTE! The index memory
 
1519
                                object is freed in this function! */
 
1520
        ulint           page_no,/*!< in: root page number of the index */
 
1521
        ibool           strict) /*!< in: TRUE=refuse to create the index
 
1522
                                if records could be too big to fit in
 
1523
                                an B-tree page */
 
1524
{
 
1525
        dict_index_t*   new_index;
 
1526
        ulint           n_ord;
 
1527
        ulint           i;
 
1528
 
 
1529
        ut_ad(index);
 
1530
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1531
        ut_ad(index->n_def == index->n_fields);
 
1532
        ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
1533
 
 
1534
        ut_ad(mem_heap_validate(index->heap));
 
1535
        ut_a(!dict_index_is_clust(index)
 
1536
             || UT_LIST_GET_LEN(table->indexes) == 0);
 
1537
 
 
1538
        if (!dict_index_find_cols(table, index)) {
 
1539
 
 
1540
                dict_mem_index_free(index);
 
1541
                return(DB_CORRUPTION);
 
1542
        }
 
1543
 
 
1544
        /* Build the cache internal representation of the index,
 
1545
        containing also the added system fields */
 
1546
 
 
1547
        if (dict_index_is_clust(index)) {
 
1548
                new_index = dict_index_build_internal_clust(table, index);
 
1549
        } else {
 
1550
                new_index = dict_index_build_internal_non_clust(table, index);
 
1551
        }
 
1552
 
 
1553
        /* Set the n_fields value in new_index to the actual defined
 
1554
        number of fields in the cache internal representation */
 
1555
 
 
1556
        new_index->n_fields = new_index->n_def;
 
1557
 
 
1558
        if (strict && dict_index_too_big_for_tree(table, new_index)) {
 
1559
too_big:
 
1560
                dict_mem_index_free(new_index);
 
1561
                dict_mem_index_free(index);
 
1562
                return(DB_TOO_BIG_RECORD);
 
1563
        }
 
1564
 
 
1565
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
1566
                n_ord = new_index->n_fields;
 
1567
        } else {
 
1568
                n_ord = new_index->n_uniq;
 
1569
        }
 
1570
 
 
1571
        switch (dict_table_get_format(table)) {
 
1572
        case DICT_TF_FORMAT_51:
 
1573
                /* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
 
1574
                prefixes of externally stored columns locally within
 
1575
                the record.  There are no special considerations for
 
1576
                the undo log record size. */
 
1577
                goto undo_size_ok;
 
1578
 
 
1579
        case DICT_TF_FORMAT_ZIP:
 
1580
                /* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
 
1581
                column prefix indexes require that prefixes of
 
1582
                externally stored columns are written to the undo log.
 
1583
                This may make the undo log record bigger than the
 
1584
                record on the B-tree page.  The maximum size of an
 
1585
                undo log record is the page size.  That must be
 
1586
                checked for below. */
 
1587
                break;
 
1588
 
 
1589
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
 
1590
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
 
1591
#endif
 
1592
        }
 
1593
 
 
1594
        for (i = 0; i < n_ord; i++) {
 
1595
                const dict_field_t*     field
 
1596
                        = dict_index_get_nth_field(new_index, i);
 
1597
                const dict_col_t*       col
 
1598
                        = dict_field_get_col(field);
 
1599
 
 
1600
                /* In dtuple_convert_big_rec(), variable-length columns
 
1601
                that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
 
1602
                may be chosen for external storage.  If the column appears
 
1603
                in an ordering column of an index, a longer prefix of
 
1604
                REC_MAX_INDEX_COL_LEN will be copied to the undo log
 
1605
                by trx_undo_page_report_modify() and
 
1606
                trx_undo_page_fetch_ext().  It suffices to check the
 
1607
                capacity of the undo log whenever new_index includes
 
1608
                a column prefix on a column that may be stored externally. */
 
1609
 
 
1610
                if (field->prefix_len /* prefix index */
 
1611
                    && !col->ord_part /* not yet ordering column */
 
1612
                    && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
 
1613
                    && dict_col_get_max_size(col)
 
1614
                    > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
 
1615
 
 
1616
                        if (dict_index_too_big_for_undo(table, new_index)) {
 
1617
                                /* An undo log record might not fit in
 
1618
                                a single page.  Refuse to create this index. */
 
1619
 
 
1620
                                goto too_big;
 
1621
                        }
 
1622
 
 
1623
                        break;
 
1624
                }
 
1625
        }
 
1626
 
 
1627
undo_size_ok:
 
1628
        /* Flag the ordering columns */
 
1629
 
 
1630
        for (i = 0; i < n_ord; i++) {
 
1631
 
 
1632
                dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
 
1633
        }
 
1634
 
 
1635
        /* Add the new index as the last index for the table */
 
1636
 
 
1637
        UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
 
1638
        new_index->table = table;
 
1639
        new_index->table_name = table->name;
 
1640
 
 
1641
        new_index->search_info = btr_search_info_create(new_index->heap);
 
1642
 
 
1643
        new_index->stat_index_size = 1;
 
1644
        new_index->stat_n_leaf_pages = 1;
 
1645
 
 
1646
        new_index->page = page_no;
 
1647
        rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
 
1648
                       SYNC_INDEX_TREE);
 
1649
 
 
1650
        if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
 
1651
 
 
1652
                new_index->stat_n_diff_key_vals = mem_heap_alloc(
 
1653
                        new_index->heap,
 
1654
                        (1 + dict_index_get_n_unique(new_index))
 
1655
                        * sizeof(ib_int64_t));
 
1656
                /* Give some sensible values to stat_n_... in case we do
 
1657
                not calculate statistics quickly enough */
 
1658
 
 
1659
                for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
 
1660
 
 
1661
                        new_index->stat_n_diff_key_vals[i] = 100;
 
1662
                }
 
1663
        }
 
1664
 
 
1665
        dict_sys->size += mem_heap_get_size(new_index->heap);
 
1666
 
 
1667
        dict_mem_index_free(index);
 
1668
 
 
1669
        return(DB_SUCCESS);
 
1670
}
 
1671
 
 
1672
/**********************************************************************//**
 
1673
Removes an index from the dictionary cache. */
 
1674
UNIV_INTERN
 
1675
void
 
1676
dict_index_remove_from_cache(
 
1677
/*=========================*/
 
1678
        dict_table_t*   table,  /*!< in/out: table */
 
1679
        dict_index_t*   index)  /*!< in, own: index */
 
1680
{
 
1681
        ulint           size;
 
1682
        ulint           retries = 0;
 
1683
        btr_search_t*   info;
 
1684
 
 
1685
        ut_ad(table && index);
 
1686
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
1687
        ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
1688
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1689
 
 
1690
        /* We always create search info whether or not adaptive
 
1691
        hash index is enabled or not. */
 
1692
        info = index->search_info;
 
1693
        ut_ad(info);
 
1694
 
 
1695
        /* We are not allowed to free the in-memory index struct
 
1696
        dict_index_t until all entries in the adaptive hash index
 
1697
        that point to any of the page belonging to his b-tree index
 
1698
        are dropped. This is so because dropping of these entries
 
1699
        require access to dict_index_t struct. To avoid such scenario
 
1700
        We keep a count of number of such pages in the search_info and
 
1701
        only free the dict_index_t struct when this count drops to
 
1702
        zero. */
 
1703
 
 
1704
        for (;;) {
 
1705
                ulint ref_count = btr_search_info_get_ref_count(info);
 
1706
                if (ref_count == 0) {
 
1707
                        break;
 
1708
                }
 
1709
 
 
1710
                /* Sleep for 10ms before trying again. */
 
1711
                os_thread_sleep(10000);
 
1712
                ++retries;
 
1713
 
 
1714
                if (retries % 500 == 0) {
 
1715
                        /* No luck after 5 seconds of wait. */
 
1716
                        fprintf(stderr, "InnoDB: Error: Waited for"
 
1717
                                        " %lu secs for hash index"
 
1718
                                        " ref_count (%lu) to drop"
 
1719
                                        " to 0.\n"
 
1720
                                        "index: \"%s\""
 
1721
                                        " table: \"%s\"\n",
 
1722
                                        retries/100,
 
1723
                                        ref_count,
 
1724
                                        index->name,
 
1725
                                        table->name);
 
1726
                }
 
1727
 
 
1728
                /* To avoid a hang here we commit suicide if the
 
1729
                ref_count doesn't drop to zero in 600 seconds. */
 
1730
                if (retries >= 60000) {
 
1731
                        ut_error;
 
1732
                }
 
1733
        }
 
1734
 
 
1735
        rw_lock_free(&index->lock);
 
1736
 
 
1737
        /* Remove the index from the list of indexes of the table */
 
1738
        UT_LIST_REMOVE(indexes, table->indexes, index);
 
1739
 
 
1740
        size = mem_heap_get_size(index->heap);
 
1741
 
 
1742
        ut_ad(dict_sys->size >= size);
 
1743
 
 
1744
        dict_sys->size -= size;
 
1745
 
 
1746
        dict_mem_index_free(index);
 
1747
}
 
1748
 
 
1749
/*******************************************************************//**
 
1750
Tries to find column names for the index and sets the col field of the
 
1751
index.
 
1752
@return TRUE if the column names were found */
 
1753
static
 
1754
ibool
 
1755
dict_index_find_cols(
 
1756
/*=================*/
 
1757
        dict_table_t*   table,  /*!< in: table */
 
1758
        dict_index_t*   index)  /*!< in: index */
 
1759
{
 
1760
        ulint           i;
 
1761
 
 
1762
        ut_ad(table && index);
 
1763
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
1764
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1765
 
 
1766
        for (i = 0; i < index->n_fields; i++) {
 
1767
                ulint           j;
 
1768
                dict_field_t*   field = dict_index_get_nth_field(index, i);
 
1769
 
 
1770
                for (j = 0; j < table->n_cols; j++) {
 
1771
                        if (!strcmp(dict_table_get_col_name(table, j),
 
1772
                                    field->name)) {
 
1773
                                field->col = dict_table_get_nth_col(table, j);
 
1774
 
 
1775
                                goto found;
 
1776
                        }
 
1777
                }
 
1778
 
 
1779
#ifdef UNIV_DEBUG
 
1780
                /* It is an error not to find a matching column. */
 
1781
                fputs("InnoDB: Error: no matching column for ", stderr);
 
1782
                ut_print_name(stderr, NULL, FALSE, field->name);
 
1783
                fputs(" in ", stderr);
 
1784
                dict_index_name_print(stderr, NULL, index);
 
1785
                fputs("!\n", stderr);
 
1786
#endif /* UNIV_DEBUG */
 
1787
                return(FALSE);
 
1788
 
 
1789
found:
 
1790
                ;
 
1791
        }
 
1792
 
 
1793
        return(TRUE);
 
1794
}
 
1795
#endif /* !UNIV_HOTBACKUP */
 
1796
 
 
1797
/*******************************************************************//**
 
1798
Adds a column to index. */
 
1799
UNIV_INTERN
 
1800
void
 
1801
dict_index_add_col(
 
1802
/*===============*/
 
1803
        dict_index_t*           index,          /*!< in/out: index */
 
1804
        const dict_table_t*     table,          /*!< in: table */
 
1805
        dict_col_t*             col,            /*!< in: column */
 
1806
        ulint                   prefix_len)     /*!< in: column prefix length */
 
1807
{
 
1808
        dict_field_t*   field;
 
1809
        const char*     col_name;
 
1810
 
 
1811
        col_name = dict_table_get_col_name(table, dict_col_get_no(col));
 
1812
 
 
1813
        dict_mem_index_add_field(index, col_name, prefix_len);
 
1814
 
 
1815
        field = dict_index_get_nth_field(index, index->n_def - 1);
 
1816
 
 
1817
        field->col = col;
 
1818
        field->fixed_len = (unsigned int) dict_col_get_fixed_size(
 
1819
                col, dict_table_is_comp(table));
 
1820
 
 
1821
        if (prefix_len && field->fixed_len > prefix_len) {
 
1822
                field->fixed_len = (unsigned int) prefix_len;
 
1823
        }
 
1824
 
 
1825
        /* Long fixed-length fields that need external storage are treated as
 
1826
        variable-length fields, so that the extern flag can be embedded in
 
1827
        the length word. */
 
1828
 
 
1829
        if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
 
1830
                field->fixed_len = 0;
 
1831
        }
 
1832
#if DICT_MAX_INDEX_COL_LEN != 1024
 
1833
        /* The comparison limit above must be constant.  If it were
 
1834
        changed, the disk format of some fixed-length columns would
 
1835
        change, which would be a disaster. */
 
1836
# error "DICT_MAX_INDEX_COL_LEN != 1024"
 
1837
#endif
 
1838
 
 
1839
        if (!(col->prtype & DATA_NOT_NULL)) {
 
1840
                index->n_nullable++;
 
1841
        }
 
1842
}
 
1843
 
 
1844
#ifndef UNIV_HOTBACKUP
 
1845
/*******************************************************************//**
 
1846
Copies fields contained in index2 to index1. */
 
1847
static
 
1848
void
 
1849
dict_index_copy(
 
1850
/*============*/
 
1851
        dict_index_t*           index1, /*!< in: index to copy to */
 
1852
        dict_index_t*           index2, /*!< in: index to copy from */
 
1853
        const dict_table_t*     table,  /*!< in: table */
 
1854
        ulint                   start,  /*!< in: first position to copy */
 
1855
        ulint                   end)    /*!< in: last position to copy */
 
1856
{
 
1857
        dict_field_t*   field;
 
1858
        ulint           i;
 
1859
 
 
1860
        /* Copy fields contained in index2 */
 
1861
 
 
1862
        for (i = start; i < end; i++) {
 
1863
 
 
1864
                field = dict_index_get_nth_field(index2, i);
 
1865
                dict_index_add_col(index1, table, field->col,
 
1866
                                   field->prefix_len);
 
1867
        }
 
1868
}
 
1869
 
 
1870
/*******************************************************************//**
 
1871
Copies types of fields contained in index to tuple. */
 
1872
UNIV_INTERN
 
1873
void
 
1874
dict_index_copy_types(
 
1875
/*==================*/
 
1876
        dtuple_t*               tuple,          /*!< in/out: data tuple */
 
1877
        const dict_index_t*     index,          /*!< in: index */
 
1878
        ulint                   n_fields)       /*!< in: number of
 
1879
                                                field types to copy */
 
1880
{
 
1881
        ulint           i;
 
1882
 
 
1883
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
1884
                dtuple_set_types_binary(tuple, n_fields);
 
1885
 
 
1886
                return;
 
1887
        }
 
1888
 
 
1889
        for (i = 0; i < n_fields; i++) {
 
1890
                const dict_field_t*     ifield;
 
1891
                dtype_t*                dfield_type;
 
1892
 
 
1893
                ifield = dict_index_get_nth_field(index, i);
 
1894
                dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
 
1895
                dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
 
1896
        }
 
1897
}
 
1898
 
 
1899
/*******************************************************************//**
 
1900
Copies types of columns contained in table to tuple and sets all
 
1901
fields of the tuple to the SQL NULL value.  This function should
 
1902
be called right after dtuple_create(). */
 
1903
UNIV_INTERN
 
1904
void
 
1905
dict_table_copy_types(
 
1906
/*==================*/
 
1907
        dtuple_t*               tuple,  /*!< in/out: data tuple */
 
1908
        const dict_table_t*     table)  /*!< in: table */
 
1909
{
 
1910
        ulint           i;
 
1911
 
 
1912
        for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
 
1913
 
 
1914
                dfield_t*       dfield  = dtuple_get_nth_field(tuple, i);
 
1915
                dtype_t*        dtype   = dfield_get_type(dfield);
 
1916
 
 
1917
                dfield_set_null(dfield);
 
1918
                dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
 
1919
        }
 
1920
}
 
1921
 
 
1922
/*******************************************************************//**
 
1923
Builds the internal dictionary cache representation for a clustered
 
1924
index, containing also system fields not defined by the user.
 
1925
@return own: the internal representation of the clustered index */
 
1926
static
 
1927
dict_index_t*
 
1928
dict_index_build_internal_clust(
 
1929
/*============================*/
 
1930
        const dict_table_t*     table,  /*!< in: table */
 
1931
        dict_index_t*           index)  /*!< in: user representation of
 
1932
                                        a clustered index */
 
1933
{
 
1934
        dict_index_t*   new_index;
 
1935
        dict_field_t*   field;
 
1936
        ulint           fixed_size;
 
1937
        ulint           trx_id_pos;
 
1938
        ulint           i;
 
1939
        ibool*          indexed;
 
1940
 
 
1941
        ut_ad(table && index);
 
1942
        ut_ad(dict_index_is_clust(index));
 
1943
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1944
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
1945
 
 
1946
        /* Create a new index object with certainly enough fields */
 
1947
        new_index = dict_mem_index_create(table->name,
 
1948
                                          index->name, table->space,
 
1949
                                          index->type,
 
1950
                                          index->n_fields + table->n_cols);
 
1951
 
 
1952
        /* Copy other relevant data from the old index struct to the new
 
1953
        struct: it inherits the values */
 
1954
 
 
1955
        new_index->n_user_defined_cols = index->n_fields;
 
1956
 
 
1957
        new_index->id = index->id;
 
1958
 
 
1959
        /* Copy the fields of index */
 
1960
        dict_index_copy(new_index, index, table, 0, index->n_fields);
 
1961
 
 
1962
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
1963
                /* No fixed number of fields determines an entry uniquely */
 
1964
 
 
1965
                new_index->n_uniq = REC_MAX_N_FIELDS;
 
1966
 
 
1967
        } else if (dict_index_is_unique(index)) {
 
1968
                /* Only the fields defined so far are needed to identify
 
1969
                the index entry uniquely */
 
1970
 
 
1971
                new_index->n_uniq = new_index->n_def;
 
1972
        } else {
 
1973
                /* Also the row id is needed to identify the entry */
 
1974
                new_index->n_uniq = 1 + new_index->n_def;
 
1975
        }
 
1976
 
 
1977
        new_index->trx_id_offset = 0;
 
1978
 
 
1979
        if (!dict_index_is_ibuf(index)) {
 
1980
                /* Add system columns, trx id first */
 
1981
 
 
1982
                trx_id_pos = new_index->n_def;
 
1983
 
 
1984
#if DATA_ROW_ID != 0
 
1985
# error "DATA_ROW_ID != 0"
 
1986
#endif
 
1987
#if DATA_TRX_ID != 1
 
1988
# error "DATA_TRX_ID != 1"
 
1989
#endif
 
1990
#if DATA_ROLL_PTR != 2
 
1991
# error "DATA_ROLL_PTR != 2"
 
1992
#endif
 
1993
 
 
1994
                if (!dict_index_is_unique(index)) {
 
1995
                        dict_index_add_col(new_index, table,
 
1996
                                           dict_table_get_sys_col(
 
1997
                                                   table, DATA_ROW_ID),
 
1998
                                           0);
 
1999
                        trx_id_pos++;
 
2000
                }
 
2001
 
 
2002
                dict_index_add_col(new_index, table,
 
2003
                                   dict_table_get_sys_col(table, DATA_TRX_ID),
 
2004
                                   0);
 
2005
 
 
2006
                dict_index_add_col(new_index, table,
 
2007
                                   dict_table_get_sys_col(table,
 
2008
                                                          DATA_ROLL_PTR),
 
2009
                                   0);
 
2010
 
 
2011
                for (i = 0; i < trx_id_pos; i++) {
 
2012
 
 
2013
                        fixed_size = dict_col_get_fixed_size(
 
2014
                                dict_index_get_nth_col(new_index, i),
 
2015
                                dict_table_is_comp(table));
 
2016
 
 
2017
                        if (fixed_size == 0) {
 
2018
                                new_index->trx_id_offset = 0;
 
2019
 
 
2020
                                break;
 
2021
                        }
 
2022
 
 
2023
                        if (dict_index_get_nth_field(new_index, i)->prefix_len
 
2024
                            > 0) {
 
2025
                                new_index->trx_id_offset = 0;
 
2026
 
 
2027
                                break;
 
2028
                        }
 
2029
 
 
2030
                        new_index->trx_id_offset += (unsigned int) fixed_size;
 
2031
                }
 
2032
 
 
2033
        }
 
2034
 
 
2035
        /* Remember the table columns already contained in new_index */
 
2036
        indexed = mem_zalloc(table->n_cols * sizeof *indexed);
 
2037
 
 
2038
        /* Mark the table columns already contained in new_index */
 
2039
        for (i = 0; i < new_index->n_def; i++) {
 
2040
 
 
2041
                field = dict_index_get_nth_field(new_index, i);
 
2042
 
 
2043
                /* If there is only a prefix of the column in the index
 
2044
                field, do not mark the column as contained in the index */
 
2045
 
 
2046
                if (field->prefix_len == 0) {
 
2047
 
 
2048
                        indexed[field->col->ind] = TRUE;
 
2049
                }
 
2050
        }
 
2051
 
 
2052
        /* Add to new_index non-system columns of table not yet included
 
2053
        there */
 
2054
        for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
 
2055
 
 
2056
                dict_col_t*     col = dict_table_get_nth_col(table, i);
 
2057
                ut_ad(col->mtype != DATA_SYS);
 
2058
 
 
2059
                if (!indexed[col->ind]) {
 
2060
                        dict_index_add_col(new_index, table, col, 0);
 
2061
                }
 
2062
        }
 
2063
 
 
2064
        mem_free(indexed);
 
2065
 
 
2066
        ut_ad(dict_index_is_ibuf(index)
 
2067
              || (UT_LIST_GET_LEN(table->indexes) == 0));
 
2068
 
 
2069
        new_index->cached = TRUE;
 
2070
 
 
2071
        return(new_index);
 
2072
}
 
2073
 
 
2074
/*******************************************************************//**
 
2075
Builds the internal dictionary cache representation for a non-clustered
 
2076
index, containing also system fields not defined by the user.
 
2077
@return own: the internal representation of the non-clustered index */
 
2078
static
 
2079
dict_index_t*
 
2080
dict_index_build_internal_non_clust(
 
2081
/*================================*/
 
2082
        const dict_table_t*     table,  /*!< in: table */
 
2083
        dict_index_t*           index)  /*!< in: user representation of
 
2084
                                        a non-clustered index */
 
2085
{
 
2086
        dict_field_t*   field;
 
2087
        dict_index_t*   new_index;
 
2088
        dict_index_t*   clust_index;
 
2089
        ulint           i;
 
2090
        ibool*          indexed;
 
2091
 
 
2092
        ut_ad(table && index);
 
2093
        ut_ad(!dict_index_is_clust(index));
 
2094
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
2095
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 
2096
 
 
2097
        /* The clustered index should be the first in the list of indexes */
 
2098
        clust_index = UT_LIST_GET_FIRST(table->indexes);
 
2099
 
 
2100
        ut_ad(clust_index);
 
2101
        ut_ad(dict_index_is_clust(clust_index));
 
2102
        ut_ad(!(clust_index->type & DICT_UNIVERSAL));
 
2103
 
 
2104
        /* Create a new index */
 
2105
        new_index = dict_mem_index_create(
 
2106
                table->name, index->name, index->space, index->type,
 
2107
                index->n_fields + 1 + clust_index->n_uniq);
 
2108
 
 
2109
        /* Copy other relevant data from the old index
 
2110
        struct to the new struct: it inherits the values */
 
2111
 
 
2112
        new_index->n_user_defined_cols = index->n_fields;
 
2113
 
 
2114
        new_index->id = index->id;
 
2115
 
 
2116
        /* Copy fields from index to new_index */
 
2117
        dict_index_copy(new_index, index, table, 0, index->n_fields);
 
2118
 
 
2119
        /* Remember the table columns already contained in new_index */
 
2120
        indexed = mem_zalloc(table->n_cols * sizeof *indexed);
 
2121
 
 
2122
        /* Mark the table columns already contained in new_index */
 
2123
        for (i = 0; i < new_index->n_def; i++) {
 
2124
 
 
2125
                field = dict_index_get_nth_field(new_index, i);
 
2126
 
 
2127
                /* If there is only a prefix of the column in the index
 
2128
                field, do not mark the column as contained in the index */
 
2129
 
 
2130
                if (field->prefix_len == 0) {
 
2131
 
 
2132
                        indexed[field->col->ind] = TRUE;
 
2133
                }
 
2134
        }
 
2135
 
 
2136
        /* Add to new_index the columns necessary to determine the clustered
 
2137
        index entry uniquely */
 
2138
 
 
2139
        for (i = 0; i < clust_index->n_uniq; i++) {
 
2140
 
 
2141
                field = dict_index_get_nth_field(clust_index, i);
 
2142
 
 
2143
                if (!indexed[field->col->ind]) {
 
2144
                        dict_index_add_col(new_index, table, field->col,
 
2145
                                           field->prefix_len);
 
2146
                }
 
2147
        }
 
2148
 
 
2149
        mem_free(indexed);
 
2150
 
 
2151
        if (dict_index_is_unique(index)) {
 
2152
                new_index->n_uniq = index->n_fields;
 
2153
        } else {
 
2154
                new_index->n_uniq = new_index->n_def;
 
2155
        }
 
2156
 
 
2157
        /* Set the n_fields value in new_index to the actual defined
 
2158
        number of fields */
 
2159
 
 
2160
        new_index->n_fields = new_index->n_def;
 
2161
 
 
2162
        new_index->cached = TRUE;
 
2163
 
 
2164
        return(new_index);
 
2165
}
 
2166
 
 
2167
/*====================== FOREIGN KEY PROCESSING ========================*/
 
2168
 
 
2169
/*********************************************************************//**
 
2170
Checks if a table is referenced by foreign keys.
 
2171
@return TRUE if table is referenced by a foreign key */
 
2172
UNIV_INTERN
 
2173
ibool
 
2174
dict_table_is_referenced_by_foreign_key(
 
2175
/*====================================*/
 
2176
        const dict_table_t*     table)  /*!< in: InnoDB table */
 
2177
{
 
2178
        return(UT_LIST_GET_LEN(table->referenced_list) > 0);
 
2179
}
 
2180
 
 
2181
/*********************************************************************//**
 
2182
Check if the index is referenced by a foreign key, if TRUE return foreign
 
2183
else return NULL
 
2184
@return pointer to foreign key struct if index is defined for foreign
 
2185
key, otherwise NULL */
 
2186
UNIV_INTERN
 
2187
dict_foreign_t*
 
2188
dict_table_get_referenced_constraint(
 
2189
/*=================================*/
 
2190
        dict_table_t*   table,  /*!< in: InnoDB table */
 
2191
        dict_index_t*   index)  /*!< in: InnoDB index */
 
2192
{
 
2193
        dict_foreign_t* foreign;
 
2194
 
 
2195
        ut_ad(index != NULL);
 
2196
        ut_ad(table != NULL);
 
2197
 
 
2198
        for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
2199
             foreign;
 
2200
             foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
 
2201
 
 
2202
                if (foreign->referenced_index == index) {
 
2203
 
 
2204
                        return(foreign);
 
2205
                }
 
2206
        }
 
2207
 
 
2208
        return(NULL);
 
2209
}
 
2210
 
 
2211
/*********************************************************************//**
 
2212
Checks if a index is defined for a foreign key constraint. Index is a part
 
2213
of a foreign key constraint if the index is referenced by foreign key
 
2214
or index is a foreign key index.
 
2215
@return pointer to foreign key struct if index is defined for foreign
 
2216
key, otherwise NULL */
 
2217
UNIV_INTERN
 
2218
dict_foreign_t*
 
2219
dict_table_get_foreign_constraint(
 
2220
/*==============================*/
 
2221
        dict_table_t*   table,  /*!< in: InnoDB table */
 
2222
        dict_index_t*   index)  /*!< in: InnoDB index */
 
2223
{
 
2224
        dict_foreign_t* foreign;
 
2225
 
 
2226
        ut_ad(index != NULL);
 
2227
        ut_ad(table != NULL);
 
2228
 
 
2229
        for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
2230
             foreign;
 
2231
             foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
 
2232
 
 
2233
                if (foreign->foreign_index == index
 
2234
                    || foreign->referenced_index == index) {
 
2235
 
 
2236
                        return(foreign);
 
2237
                }
 
2238
        }
 
2239
 
 
2240
        return(NULL);
 
2241
}
 
2242
 
 
2243
/*********************************************************************//**
 
2244
Frees a foreign key struct. */
 
2245
static
 
2246
void
 
2247
dict_foreign_free(
 
2248
/*==============*/
 
2249
        dict_foreign_t* foreign)        /*!< in, own: foreign key struct */
 
2250
{
 
2251
        mem_heap_free(foreign->heap);
 
2252
}
 
2253
 
 
2254
/**********************************************************************//**
 
2255
Removes a foreign constraint struct from the dictionary cache. */
 
2256
static
 
2257
void
 
2258
dict_foreign_remove_from_cache(
 
2259
/*===========================*/
 
2260
        dict_foreign_t* foreign)        /*!< in, own: foreign constraint */
 
2261
{
 
2262
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
2263
        ut_a(foreign);
 
2264
 
 
2265
        if (foreign->referenced_table) {
 
2266
                UT_LIST_REMOVE(referenced_list,
 
2267
                               foreign->referenced_table->referenced_list,
 
2268
                               foreign);
 
2269
        }
 
2270
 
 
2271
        if (foreign->foreign_table) {
 
2272
                UT_LIST_REMOVE(foreign_list,
 
2273
                               foreign->foreign_table->foreign_list,
 
2274
                               foreign);
 
2275
        }
 
2276
 
 
2277
        dict_foreign_free(foreign);
 
2278
}
 
2279
 
 
2280
/**********************************************************************//**
 
2281
Looks for the foreign constraint from the foreign and referenced lists
 
2282
of a table.
 
2283
@return foreign constraint */
 
2284
static
 
2285
dict_foreign_t*
 
2286
dict_foreign_find(
 
2287
/*==============*/
 
2288
        dict_table_t*   table,  /*!< in: table object */
 
2289
        const char*     id)     /*!< in: foreign constraint id */
 
2290
{
 
2291
        dict_foreign_t* foreign;
 
2292
 
 
2293
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
2294
 
 
2295
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
2296
 
 
2297
        while (foreign) {
 
2298
                if (ut_strcmp(id, foreign->id) == 0) {
 
2299
 
 
2300
                        return(foreign);
 
2301
                }
 
2302
 
 
2303
                foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
2304
        }
 
2305
 
 
2306
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
2307
 
 
2308
        while (foreign) {
 
2309
                if (ut_strcmp(id, foreign->id) == 0) {
 
2310
 
 
2311
                        return(foreign);
 
2312
                }
 
2313
 
 
2314
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
2315
        }
 
2316
 
 
2317
        return(NULL);
 
2318
}
 
2319
 
 
2320
/*********************************************************************//**
 
2321
Tries to find an index whose first fields are the columns in the array,
 
2322
in the same order and is not marked for deletion and is not the same
 
2323
as types_idx.
 
2324
@return matching index, NULL if not found */
 
2325
static
 
2326
dict_index_t*
 
2327
dict_foreign_find_index(
 
2328
/*====================*/
 
2329
        dict_table_t*   table,  /*!< in: table */
 
2330
        const char**    columns,/*!< in: array of column names */
 
2331
        ulint           n_cols, /*!< in: number of columns */
 
2332
        dict_index_t*   types_idx, /*!< in: NULL or an index to whose types the
 
2333
                                   column types must match */
 
2334
        ibool           check_charsets,
 
2335
                                /*!< in: whether to check charsets.
 
2336
                                only has an effect if types_idx != NULL */
 
2337
        ulint           check_null)
 
2338
                                /*!< in: nonzero if none of the columns must
 
2339
                                be declared NOT NULL */
 
2340
{
 
2341
        dict_index_t*   index;
 
2342
 
 
2343
        index = dict_table_get_first_index(table);
 
2344
 
 
2345
        while (index != NULL) {
 
2346
                /* Ignore matches that refer to the same instance
 
2347
                or the index is to be dropped */
 
2348
                if (index->to_be_dropped || types_idx == index) {
 
2349
 
 
2350
                        goto next_rec;
 
2351
 
 
2352
                } else if (dict_index_get_n_fields(index) >= n_cols) {
 
2353
                        ulint           i;
 
2354
 
 
2355
                        for (i = 0; i < n_cols; i++) {
 
2356
                                dict_field_t*   field;
 
2357
                                const char*     col_name;
 
2358
 
 
2359
                                field = dict_index_get_nth_field(index, i);
 
2360
 
 
2361
                                col_name = dict_table_get_col_name(
 
2362
                                        table, dict_col_get_no(field->col));
 
2363
 
 
2364
                                if (field->prefix_len != 0) {
 
2365
                                        /* We do not accept column prefix
 
2366
                                        indexes here */
 
2367
 
 
2368
                                        break;
 
2369
                                }
 
2370
 
 
2371
                                if (0 != innobase_strcasecmp(columns[i],
 
2372
                                                             col_name)) {
 
2373
                                        break;
 
2374
                                }
 
2375
 
 
2376
                                if (check_null
 
2377
                                    && (field->col->prtype & DATA_NOT_NULL)) {
 
2378
 
 
2379
                                        return(NULL);
 
2380
                                }
 
2381
 
 
2382
                                if (types_idx && !cmp_cols_are_equal(
 
2383
                                            dict_index_get_nth_col(index, i),
 
2384
                                            dict_index_get_nth_col(types_idx,
 
2385
                                                                   i),
 
2386
                                            check_charsets)) {
 
2387
 
 
2388
                                        break;
 
2389
                                }
 
2390
                        }
 
2391
 
 
2392
                        if (i == n_cols) {
 
2393
                                /* We found a matching index */
 
2394
 
 
2395
                                return(index);
 
2396
                        }
 
2397
                }
 
2398
 
 
2399
next_rec:
 
2400
                index = dict_table_get_next_index(index);
 
2401
        }
 
2402
 
 
2403
        return(NULL);
 
2404
}
 
2405
 
 
2406
/**********************************************************************//**
 
2407
Find an index that is equivalent to the one passed in and is not marked
 
2408
for deletion.
 
2409
@return index equivalent to foreign->foreign_index, or NULL */
 
2410
UNIV_INTERN
 
2411
dict_index_t*
 
2412
dict_foreign_find_equiv_index(
 
2413
/*==========================*/
 
2414
        dict_foreign_t* foreign)/*!< in: foreign key */
 
2415
{
 
2416
        ut_a(foreign != NULL);
 
2417
 
 
2418
        /* Try to find an index which contains the columns as the
 
2419
        first fields and in the right order, and the types are the
 
2420
        same as in foreign->foreign_index */
 
2421
 
 
2422
        return(dict_foreign_find_index(
 
2423
                       foreign->foreign_table,
 
2424
                       foreign->foreign_col_names, foreign->n_fields,
 
2425
                       foreign->foreign_index, TRUE, /* check types */
 
2426
                       FALSE/* allow columns to be NULL */));
 
2427
}
 
2428
 
 
2429
/**********************************************************************//**
 
2430
Returns an index object by matching on the name and column names and
 
2431
if more than one index matches return the index with the max id
 
2432
@return matching index, NULL if not found */
 
2433
UNIV_INTERN
 
2434
dict_index_t*
 
2435
dict_table_get_index_by_max_id(
 
2436
/*===========================*/
 
2437
        dict_table_t*   table,  /*!< in: table */
 
2438
        const char*     name,   /*!< in: the index name to find */
 
2439
        const char**    columns,/*!< in: array of column names */
 
2440
        ulint           n_cols) /*!< in: number of columns */
 
2441
{
 
2442
        dict_index_t*   index;
 
2443
        dict_index_t*   found;
 
2444
 
 
2445
        found = NULL;
 
2446
        index = dict_table_get_first_index(table);
 
2447
 
 
2448
        while (index != NULL) {
 
2449
                if (ut_strcmp(index->name, name) == 0
 
2450
                    && dict_index_get_n_ordering_defined_by_user(index)
 
2451
                    == n_cols) {
 
2452
 
 
2453
                        ulint           i;
 
2454
 
 
2455
                        for (i = 0; i < n_cols; i++) {
 
2456
                                dict_field_t*   field;
 
2457
                                const char*     col_name;
 
2458
 
 
2459
                                field = dict_index_get_nth_field(index, i);
 
2460
 
 
2461
                                col_name = dict_table_get_col_name(
 
2462
                                        table, dict_col_get_no(field->col));
 
2463
 
 
2464
                                if (0 != innobase_strcasecmp(
 
2465
                                            columns[i], col_name)) {
 
2466
 
 
2467
                                        break;
 
2468
                                }
 
2469
                        }
 
2470
 
 
2471
                        if (i == n_cols) {
 
2472
                                /* We found a matching index, select
 
2473
                                the index with the higher id*/
 
2474
 
 
2475
                                if (!found || index->id > found->id) {
 
2476
 
 
2477
                                        found = index;
 
2478
                                }
 
2479
                        }
 
2480
                }
 
2481
 
 
2482
                index = dict_table_get_next_index(index);
 
2483
        }
 
2484
 
 
2485
        return(found);
 
2486
}
 
2487
 
 
2488
/**********************************************************************//**
 
2489
Report an error in a foreign key definition. */
 
2490
static
 
2491
void
 
2492
dict_foreign_error_report_low(
 
2493
/*==========================*/
 
2494
        FILE*           file,   /*!< in: output stream */
 
2495
        const char*     name)   /*!< in: table name */
 
2496
{
 
2497
        rewind(file);
 
2498
        ut_print_timestamp(file);
 
2499
        fprintf(file, " Error in foreign key constraint of table %s:\n",
 
2500
                name);
 
2501
}
 
2502
 
 
2503
/**********************************************************************//**
 
2504
Report an error in a foreign key definition. */
 
2505
static
 
2506
void
 
2507
dict_foreign_error_report(
 
2508
/*======================*/
 
2509
        FILE*           file,   /*!< in: output stream */
 
2510
        dict_foreign_t* fk,     /*!< in: foreign key constraint */
 
2511
        const char*     msg)    /*!< in: the error message */
 
2512
{
 
2513
        mutex_enter(&dict_foreign_err_mutex);
 
2514
        dict_foreign_error_report_low(file, fk->foreign_table_name);
 
2515
        fputs(msg, file);
 
2516
        fputs(" Constraint:\n", file);
 
2517
        dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
 
2518
        putc('\n', file);
 
2519
        if (fk->foreign_index) {
 
2520
                fputs("The index in the foreign key in table is ", file);
 
2521
                ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
 
2522
                fputs("\n"
 
2523
                      "See " REFMAN "innodb-foreign-key-constraints.html\n"
 
2524
                      "for correct foreign key definition.\n",
 
2525
                      file);
 
2526
        }
 
2527
        mutex_exit(&dict_foreign_err_mutex);
 
2528
}
 
2529
 
 
2530
/**********************************************************************//**
 
2531
Adds a foreign key constraint object to the dictionary cache. May free
 
2532
the object if there already is an object with the same identifier in.
 
2533
At least one of the foreign table and the referenced table must already
 
2534
be in the dictionary cache!
 
2535
@return DB_SUCCESS or error code */
 
2536
UNIV_INTERN
 
2537
ulint
 
2538
dict_foreign_add_to_cache(
 
2539
/*======================*/
 
2540
        dict_foreign_t* foreign,        /*!< in, own: foreign key constraint */
 
2541
        ibool           check_charsets) /*!< in: TRUE=check charset
 
2542
                                        compatibility */
 
2543
{
 
2544
        dict_table_t*   for_table;
 
2545
        dict_table_t*   ref_table;
 
2546
        dict_foreign_t* for_in_cache            = NULL;
 
2547
        dict_index_t*   index;
 
2548
        ibool           added_to_referenced_list= FALSE;
 
2549
        FILE*           ef                      = dict_foreign_err_file;
 
2550
 
 
2551
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
2552
 
 
2553
        for_table = dict_table_check_if_in_cache_low(
 
2554
                foreign->foreign_table_name);
 
2555
 
 
2556
        ref_table = dict_table_check_if_in_cache_low(
 
2557
                foreign->referenced_table_name);
 
2558
        ut_a(for_table || ref_table);
 
2559
 
 
2560
        if (for_table) {
 
2561
                for_in_cache = dict_foreign_find(for_table, foreign->id);
 
2562
        }
 
2563
 
 
2564
        if (!for_in_cache && ref_table) {
 
2565
                for_in_cache = dict_foreign_find(ref_table, foreign->id);
 
2566
        }
 
2567
 
 
2568
        if (for_in_cache) {
 
2569
                /* Free the foreign object */
 
2570
                mem_heap_free(foreign->heap);
 
2571
        } else {
 
2572
                for_in_cache = foreign;
 
2573
        }
 
2574
 
 
2575
        if (for_in_cache->referenced_table == NULL && ref_table) {
 
2576
                index = dict_foreign_find_index(
 
2577
                        ref_table,
 
2578
                        for_in_cache->referenced_col_names,
 
2579
                        for_in_cache->n_fields, for_in_cache->foreign_index,
 
2580
                        check_charsets, FALSE);
 
2581
 
 
2582
                if (index == NULL) {
 
2583
                        dict_foreign_error_report(
 
2584
                                ef, for_in_cache,
 
2585
                                "there is no index in referenced table"
 
2586
                                " which would contain\n"
 
2587
                                "the columns as the first columns,"
 
2588
                                " or the data types in the\n"
 
2589
                                "referenced table do not match"
 
2590
                                " the ones in table.");
 
2591
 
 
2592
                        if (for_in_cache == foreign) {
 
2593
                                mem_heap_free(foreign->heap);
 
2594
                        }
 
2595
 
 
2596
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
2597
                }
 
2598
 
 
2599
                for_in_cache->referenced_table = ref_table;
 
2600
                for_in_cache->referenced_index = index;
 
2601
                UT_LIST_ADD_LAST(referenced_list,
 
2602
                                 ref_table->referenced_list,
 
2603
                                 for_in_cache);
 
2604
                added_to_referenced_list = TRUE;
 
2605
        }
 
2606
 
 
2607
        if (for_in_cache->foreign_table == NULL && for_table) {
 
2608
                index = dict_foreign_find_index(
 
2609
                        for_table,
 
2610
                        for_in_cache->foreign_col_names,
 
2611
                        for_in_cache->n_fields,
 
2612
                        for_in_cache->referenced_index, check_charsets,
 
2613
                        for_in_cache->type
 
2614
                        & (DICT_FOREIGN_ON_DELETE_SET_NULL
 
2615
                           | DICT_FOREIGN_ON_UPDATE_SET_NULL));
 
2616
 
 
2617
                if (index == NULL) {
 
2618
                        dict_foreign_error_report(
 
2619
                                ef, for_in_cache,
 
2620
                                "there is no index in the table"
 
2621
                                " which would contain\n"
 
2622
                                "the columns as the first columns,"
 
2623
                                " or the data types in the\n"
 
2624
                                "table do not match"
 
2625
                                " the ones in the referenced table\n"
 
2626
                                "or one of the ON ... SET NULL columns"
 
2627
                                " is declared NOT NULL.");
 
2628
 
 
2629
                        if (for_in_cache == foreign) {
 
2630
                                if (added_to_referenced_list) {
 
2631
                                        UT_LIST_REMOVE(
 
2632
                                                referenced_list,
 
2633
                                                ref_table->referenced_list,
 
2634
                                                for_in_cache);
 
2635
                                }
 
2636
 
 
2637
                                mem_heap_free(foreign->heap);
 
2638
                        }
 
2639
 
 
2640
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
2641
                }
 
2642
 
 
2643
                for_in_cache->foreign_table = for_table;
 
2644
                for_in_cache->foreign_index = index;
 
2645
                UT_LIST_ADD_LAST(foreign_list,
 
2646
                                 for_table->foreign_list,
 
2647
                                 for_in_cache);
 
2648
        }
 
2649
 
 
2650
        return(DB_SUCCESS);
 
2651
}
 
2652
 
 
2653
/*********************************************************************//**
 
2654
Scans from pointer onwards. Stops if is at the start of a copy of
 
2655
'string' where characters are compared without case sensitivity, and
 
2656
only outside `` or "" quotes. Stops also at NUL.
 
2657
@return scanned up to this */
 
2658
static
 
2659
const char*
 
2660
dict_scan_to(
 
2661
/*=========*/
 
2662
        const char*     ptr,    /*!< in: scan from */
 
2663
        const char*     string) /*!< in: look for this */
 
2664
{
 
2665
        char    quote   = '\0';
 
2666
 
 
2667
        for (; *ptr; ptr++) {
 
2668
                if (*ptr == quote) {
 
2669
                        /* Closing quote character: do not look for
 
2670
                        starting quote or the keyword. */
 
2671
                        quote = '\0';
 
2672
                } else if (quote) {
 
2673
                        /* Within quotes: do nothing. */
 
2674
                } else if (*ptr == '`' || *ptr == '"') {
 
2675
                        /* Starting quote: remember the quote character. */
 
2676
                        quote = *ptr;
 
2677
                } else {
 
2678
                        /* Outside quotes: look for the keyword. */
 
2679
                        ulint   i;
 
2680
                        for (i = 0; string[i]; i++) {
 
2681
                                if (toupper((int)(unsigned char)(ptr[i]))
 
2682
                                    != toupper((int)(unsigned char)
 
2683
                                               (string[i]))) {
 
2684
                                        goto nomatch;
 
2685
                                }
 
2686
                        }
 
2687
                        break;
 
2688
nomatch:
 
2689
                        ;
 
2690
                }
 
2691
        }
 
2692
 
 
2693
        return(ptr);
 
2694
}
 
2695
 
 
2696
/*********************************************************************//**
 
2697
Accepts a specified string. Comparisons are case-insensitive.
 
2698
@return if string was accepted, the pointer is moved after that, else
 
2699
ptr is returned */
 
2700
static
 
2701
const char*
 
2702
dict_accept(
 
2703
/*========*/
 
2704
        const void*     cs,/*!< in: the character set of ptr */
 
2705
        const char*     ptr,    /*!< in: scan from this */
 
2706
        const char*     string, /*!< in: accept only this string as the next
 
2707
                                non-whitespace string */
 
2708
        ibool*          success)/*!< out: TRUE if accepted */
 
2709
{
 
2710
        const char*     old_ptr = ptr;
 
2711
        const char*     old_ptr2;
 
2712
 
 
2713
        *success = FALSE;
 
2714
 
 
2715
        while (innobase_isspace(cs, *ptr)) {
 
2716
                ptr++;
 
2717
        }
 
2718
 
 
2719
        old_ptr2 = ptr;
 
2720
 
 
2721
        ptr = dict_scan_to(ptr, string);
 
2722
 
 
2723
        if (*ptr == '\0' || old_ptr2 != ptr) {
 
2724
                return(old_ptr);
 
2725
        }
 
2726
 
 
2727
        *success = TRUE;
 
2728
 
 
2729
        return(ptr + ut_strlen(string));
 
2730
}
 
2731
 
 
2732
/*********************************************************************//**
 
2733
Scans an id. For the lexical definition of an 'id', see the code below.
 
2734
Strips backquotes or double quotes from around the id.
 
2735
@return scanned to */
 
2736
static
 
2737
const char*
 
2738
dict_scan_id(
 
2739
/*=========*/
 
2740
        const void*     cs,/*!< in: the character set of ptr */
 
2741
        const char*     ptr,    /*!< in: scanned to */
 
2742
        mem_heap_t*     heap,   /*!< in: heap where to allocate the id
 
2743
                                (NULL=id will not be allocated, but it
 
2744
                                will point to string near ptr) */
 
2745
        const char**    id,     /*!< out,own: the id; NULL if no id was
 
2746
                                scannable */
 
2747
        ibool           table_id,/*!< in: TRUE=convert the allocated id
 
2748
                                as a table name; FALSE=convert to UTF-8 */
 
2749
        ibool           accept_also_dot)
 
2750
                                /*!< in: TRUE if also a dot can appear in a
 
2751
                                non-quoted id; in a quoted id it can appear
 
2752
                                always */
 
2753
{
 
2754
        char            quote   = '\0';
 
2755
        ulint           len     = 0;
 
2756
        const char*     s;
 
2757
        char*           str;
 
2758
        char*           dst;
 
2759
 
 
2760
        *id = NULL;
 
2761
 
 
2762
        while (innobase_isspace(cs, *ptr)) {
 
2763
                ptr++;
 
2764
        }
 
2765
 
 
2766
        if (*ptr == '\0') {
 
2767
 
 
2768
                return(ptr);
 
2769
        }
 
2770
 
 
2771
        if (*ptr == '`' || *ptr == '"') {
 
2772
                quote = *ptr++;
 
2773
        }
 
2774
 
 
2775
        s = ptr;
 
2776
 
 
2777
        if (quote) {
 
2778
                for (;;) {
 
2779
                        if (!*ptr) {
 
2780
                                /* Syntax error */
 
2781
                                return(ptr);
 
2782
                        }
 
2783
                        if (*ptr == quote) {
 
2784
                                ptr++;
 
2785
                                if (*ptr != quote) {
 
2786
                                        break;
 
2787
                                }
 
2788
                        }
 
2789
                        ptr++;
 
2790
                        len++;
 
2791
                }
 
2792
        } else {
 
2793
                while (!innobase_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
 
2794
                       && (accept_also_dot || *ptr != '.')
 
2795
                       && *ptr != ',' && *ptr != '\0') {
 
2796
 
 
2797
                        ptr++;
 
2798
                }
 
2799
 
 
2800
                len = ptr - s;
 
2801
        }
 
2802
 
 
2803
        if (UNIV_UNLIKELY(!heap)) {
 
2804
                /* no heap given: id will point to source string */
 
2805
                *id = s;
 
2806
                return(ptr);
 
2807
        }
 
2808
 
 
2809
        if (quote) {
 
2810
                char*   d;
 
2811
                str = d = mem_heap_alloc(heap, len + 1);
 
2812
                while (len--) {
 
2813
                        if ((*d++ = *s++) == quote) {
 
2814
                                s++;
 
2815
                        }
 
2816
                }
 
2817
                *d++ = 0;
 
2818
                len = d - str;
 
2819
                ut_ad(*s == quote);
 
2820
                ut_ad(s + 1 == ptr);
 
2821
        } else {
 
2822
                str = mem_heap_strdupl(heap, s, len);
 
2823
        }
 
2824
 
 
2825
        if (!table_id) {
 
2826
convert_id:
 
2827
                /* Convert the identifier from connection character set
 
2828
                to UTF-8. */
 
2829
                len = 3 * len + 1;
 
2830
                *id = dst = mem_heap_alloc(heap, len);
 
2831
 
 
2832
                innobase_convert_from_id(cs, dst, str, len);
 
2833
        } else if (!strncmp(str, srv_mysql50_table_name_prefix,
 
2834
                            sizeof srv_mysql50_table_name_prefix)) {
 
2835
                /* This is a pre-5.1 table name
 
2836
                containing chars other than [A-Za-z0-9].
 
2837
                Discard the prefix and use raw UTF-8 encoding. */
 
2838
                str += sizeof srv_mysql50_table_name_prefix;
 
2839
                len -= sizeof srv_mysql50_table_name_prefix;
 
2840
                goto convert_id;
 
2841
        } else {
 
2842
                /* Encode using filename-safe characters. */
 
2843
                len = 5 * len + 1;
 
2844
                *id = dst = mem_heap_alloc(heap, len);
 
2845
 
 
2846
                innobase_convert_from_table_id(cs, dst, str, len);
 
2847
        }
 
2848
 
 
2849
        return(ptr);
 
2850
}
 
2851
 
 
2852
/*********************************************************************//**
 
2853
Tries to scan a column name.
 
2854
@return scanned to */
 
2855
static
 
2856
const char*
 
2857
dict_scan_col(
 
2858
/*==========*/
 
2859
        const void*     cs,     /*!< in: the character set of ptr */
 
2860
        const char*             ptr,    /*!< in: scanned to */
 
2861
        ibool*                  success,/*!< out: TRUE if success */
 
2862
        dict_table_t*           table,  /*!< in: table in which the column is */
 
2863
        const dict_col_t**      column, /*!< out: pointer to column if success */
 
2864
        mem_heap_t*             heap,   /*!< in: heap where to allocate */
 
2865
        const char**            name)   /*!< out,own: the column name;
 
2866
                                        NULL if no name was scannable */
 
2867
{
 
2868
        ulint           i;
 
2869
 
 
2870
        *success = FALSE;
 
2871
 
 
2872
        ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
 
2873
 
 
2874
        if (*name == NULL) {
 
2875
 
 
2876
                return(ptr);    /* Syntax error */
 
2877
        }
 
2878
 
 
2879
        if (table == NULL) {
 
2880
                *success = TRUE;
 
2881
                *column = NULL;
 
2882
        } else {
 
2883
                for (i = 0; i < dict_table_get_n_cols(table); i++) {
 
2884
 
 
2885
                        const char*     col_name = dict_table_get_col_name(
 
2886
                                table, i);
 
2887
 
 
2888
                        if (0 == innobase_strcasecmp(col_name, *name)) {
 
2889
                                /* Found */
 
2890
 
 
2891
                                *success = TRUE;
 
2892
                                *column = dict_table_get_nth_col(table, i);
 
2893
                                strcpy((char*) *name, col_name);
 
2894
 
 
2895
                                break;
 
2896
                        }
 
2897
                }
 
2898
        }
 
2899
 
 
2900
        return(ptr);
 
2901
}
 
2902
 
 
2903
/*********************************************************************//**
 
2904
Scans a table name from an SQL string.
 
2905
@return scanned to */
 
2906
static
 
2907
const char*
 
2908
dict_scan_table_name(
 
2909
/*=================*/
 
2910
        const void*     cs,/*!< in: the character set of ptr */
 
2911
        const char*     ptr,    /*!< in: scanned to */
 
2912
        dict_table_t**  table,  /*!< out: table object or NULL */
 
2913
        const char*     name,   /*!< in: foreign key table name */
 
2914
        ibool*          success,/*!< out: TRUE if ok name found */
 
2915
        mem_heap_t*     heap,   /*!< in: heap where to allocate the id */
 
2916
        const char**    ref_name)/*!< out,own: the table name;
 
2917
                                NULL if no name was scannable */
 
2918
{
 
2919
        const char*     database_name   = NULL;
 
2920
        ulint           database_name_len = 0;
 
2921
        const char*     table_name      = NULL;
 
2922
        ulint           table_name_len;
 
2923
        const char*     scan_name;
 
2924
        char*           ref;
 
2925
 
 
2926
        *success = FALSE;
 
2927
        *table = NULL;
 
2928
 
 
2929
        ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
 
2930
 
 
2931
        if (scan_name == NULL) {
 
2932
 
 
2933
                return(ptr);    /* Syntax error */
 
2934
        }
 
2935
 
 
2936
        if (*ptr == '.') {
 
2937
                /* We scanned the database name; scan also the table name */
 
2938
 
 
2939
                ptr++;
 
2940
 
 
2941
                database_name = scan_name;
 
2942
                database_name_len = strlen(database_name);
 
2943
 
 
2944
                ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
 
2945
 
 
2946
                if (table_name == NULL) {
 
2947
 
 
2948
                        return(ptr);    /* Syntax error */
 
2949
                }
 
2950
        } else {
 
2951
                /* To be able to read table dumps made with InnoDB-4.0.17 or
 
2952
                earlier, we must allow the dot separator between the database
 
2953
                name and the table name also to appear within a quoted
 
2954
                identifier! InnoDB used to print a constraint as:
 
2955
                ... REFERENCES `databasename.tablename` ...
 
2956
                starting from 4.0.18 it is
 
2957
                ... REFERENCES `databasename`.`tablename` ... */
 
2958
                const char* s;
 
2959
 
 
2960
                for (s = scan_name; *s; s++) {
 
2961
                        if (*s == '.') {
 
2962
                                database_name = scan_name;
 
2963
                                database_name_len = s - scan_name;
 
2964
                                scan_name = ++s;
 
2965
                                break;/* to do: multiple dots? */
 
2966
                        }
 
2967
                }
 
2968
 
 
2969
                table_name = scan_name;
 
2970
        }
 
2971
 
 
2972
        if (database_name == NULL) {
 
2973
                /* Use the database name of the foreign key table */
 
2974
 
 
2975
                database_name = name;
 
2976
                database_name_len = dict_get_db_name_len(name);
 
2977
        }
 
2978
 
 
2979
        table_name_len = strlen(table_name);
 
2980
 
 
2981
        /* Copy database_name, '/', table_name, '\0' */
 
2982
        ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
 
2983
        memcpy(ref, database_name, database_name_len);
 
2984
        ref[database_name_len] = '/';
 
2985
        memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
 
2986
#ifndef __WIN__
 
2987
        if (srv_lower_case_table_names) {
 
2988
#endif /* !__WIN__ */
 
2989
                /* The table name is always put to lower case on Windows. */
 
2990
                innobase_casedn_str(ref);
 
2991
#ifndef __WIN__
 
2992
        }
 
2993
#endif /* !__WIN__ */
 
2994
 
 
2995
        *success = TRUE;
 
2996
        *ref_name = ref;
 
2997
        *table = dict_table_get_low(ref);
 
2998
 
 
2999
        return(ptr);
 
3000
}
 
3001
 
 
3002
/*********************************************************************//**
 
3003
Skips one id. The id is allowed to contain also '.'.
 
3004
@return scanned to */
 
3005
static
 
3006
const char*
 
3007
dict_skip_word(
 
3008
/*===========*/
 
3009
        const void*     cs,/*!< in: the character set of ptr */
 
3010
        const char*     ptr,    /*!< in: scanned to */
 
3011
        ibool*          success)/*!< out: TRUE if success, FALSE if just spaces
 
3012
                                left in string or a syntax error */
 
3013
{
 
3014
        const char*     start;
 
3015
 
 
3016
        *success = FALSE;
 
3017
 
 
3018
        ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
 
3019
 
 
3020
        if (start) {
 
3021
                *success = TRUE;
 
3022
        }
 
3023
 
 
3024
        return(ptr);
 
3025
}
 
3026
 
 
3027
/*********************************************************************//**
 
3028
Removes MySQL comments from an SQL string. A comment is either
 
3029
(a) '#' to the end of the line,
 
3030
(b) '--[space]' to the end of the line, or
 
3031
(c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
 
3032
C comment syntax).
 
3033
@return own: SQL string stripped from comments; the caller must free
 
3034
this with mem_free()! */
 
3035
static
 
3036
char*
 
3037
dict_strip_comments(
 
3038
/*================*/
 
3039
        const char*     sql_string,     /*!< in: SQL string */
 
3040
        size_t          sql_length)     /*!< in: length of sql_string */
 
3041
{
 
3042
        char*           str;
 
3043
        const char*     sptr;
 
3044
        const char*     eptr    = sql_string + sql_length;
 
3045
        char*           ptr;
 
3046
        /* unclosed quote character (0 if none) */
 
3047
        char            quote   = 0;
 
3048
 
 
3049
        str = mem_alloc(sql_length + 1);
 
3050
 
 
3051
        sptr = sql_string;
 
3052
        ptr = str;
 
3053
 
 
3054
        for (;;) {
 
3055
scan_more:
 
3056
                if (sptr >= eptr || *sptr == '\0') {
 
3057
end_of_string:
 
3058
                        *ptr = '\0';
 
3059
 
 
3060
                        ut_a(ptr <= str + sql_length);
 
3061
 
 
3062
                        return(str);
 
3063
                }
 
3064
 
 
3065
                if (*sptr == quote) {
 
3066
                        /* Closing quote character: do not look for
 
3067
                        starting quote or comments. */
 
3068
                        quote = 0;
 
3069
                } else if (quote) {
 
3070
                        /* Within quotes: do not look for
 
3071
                        starting quotes or comments. */
 
3072
                } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
 
3073
                        /* Starting quote: remember the quote character. */
 
3074
                        quote = *sptr;
 
3075
                } else if (*sptr == '#'
 
3076
                           || (sptr[0] == '-' && sptr[1] == '-'
 
3077
                               && sptr[2] == ' ')) {
 
3078
                        for (;;) {
 
3079
                                if (++sptr >= eptr) {
 
3080
                                        goto end_of_string;
 
3081
                                }
 
3082
 
 
3083
                                /* In Unix a newline is 0x0A while in Windows
 
3084
                                it is 0x0D followed by 0x0A */
 
3085
 
 
3086
                                switch (*sptr) {
 
3087
                                case (char) 0X0A:
 
3088
                                case (char) 0x0D:
 
3089
                                case '\0':
 
3090
                                        goto scan_more;
 
3091
                                }
 
3092
                        }
 
3093
                } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
 
3094
                        sptr += 2;
 
3095
                        for (;;) {
 
3096
                                if (sptr >= eptr) {
 
3097
                                        goto end_of_string;
 
3098
                                }
 
3099
 
 
3100
                                switch (*sptr) {
 
3101
                                case '\0':
 
3102
                                        goto scan_more;
 
3103
                                case '*':
 
3104
                                        if (sptr[1] == '/') {
 
3105
                                                sptr += 2;
 
3106
                                                goto scan_more;
 
3107
                                        }
 
3108
                                }
 
3109
 
 
3110
                                sptr++;
 
3111
                        }
 
3112
                }
 
3113
 
 
3114
                *ptr = *sptr;
 
3115
 
 
3116
                ptr++;
 
3117
                sptr++;
 
3118
        }
 
3119
}
 
3120
 
 
3121
/*********************************************************************//**
 
3122
Finds the highest [number] for foreign key constraints of the table. Looks
 
3123
only at the >= 4.0.18-format id's, which are of the form
 
3124
databasename/tablename_ibfk_[number].
 
3125
@return highest number, 0 if table has no new format foreign key constraints */
 
3126
static
 
3127
ulint
 
3128
dict_table_get_highest_foreign_id(
 
3129
/*==============================*/
 
3130
        dict_table_t*   table)  /*!< in: table in the dictionary memory cache */
 
3131
{
 
3132
        dict_foreign_t* foreign;
 
3133
        char*           endp;
 
3134
        ulint           biggest_id      = 0;
 
3135
        ulint           id;
 
3136
        ulint           len;
 
3137
 
 
3138
        ut_a(table);
 
3139
 
 
3140
        len = ut_strlen(table->name);
 
3141
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
3142
 
 
3143
        while (foreign) {
 
3144
                if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
 
3145
                    && 0 == ut_memcmp(foreign->id, table->name, len)
 
3146
                    && 0 == ut_memcmp(foreign->id + len,
 
3147
                                      dict_ibfk, (sizeof dict_ibfk) - 1)
 
3148
                    && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
 
3149
                        /* It is of the >= 4.0.18 format */
 
3150
 
 
3151
                        id = strtoul(foreign->id + len
 
3152
                                     + ((sizeof dict_ibfk) - 1),
 
3153
                                     &endp, 10);
 
3154
                        if (*endp == '\0') {
 
3155
                                ut_a(id != biggest_id);
 
3156
 
 
3157
                                if (id > biggest_id) {
 
3158
                                        biggest_id = id;
 
3159
                                }
 
3160
                        }
 
3161
                }
 
3162
 
 
3163
                foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
3164
        }
 
3165
 
 
3166
        return(biggest_id);
 
3167
}
 
3168
 
 
3169
/*********************************************************************//**
 
3170
Reports a simple foreign key create clause syntax error. */
 
3171
static
 
3172
void
 
3173
dict_foreign_report_syntax_err(
 
3174
/*===========================*/
 
3175
        const char*     name,           /*!< in: table name */
 
3176
        const char*     start_of_latest_foreign,
 
3177
                                        /*!< in: start of the foreign key clause
 
3178
                                        in the SQL string */
 
3179
        const char*     ptr)            /*!< in: place of the syntax error */
 
3180
{
 
3181
        FILE*   ef = dict_foreign_err_file;
 
3182
 
 
3183
        mutex_enter(&dict_foreign_err_mutex);
 
3184
        dict_foreign_error_report_low(ef, name);
 
3185
        fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
 
3186
                start_of_latest_foreign, ptr);
 
3187
        mutex_exit(&dict_foreign_err_mutex);
 
3188
}
 
3189
 
 
3190
/*********************************************************************//**
 
3191
Scans a table create SQL string and adds to the data dictionary the foreign
 
3192
key constraints declared in the string. This function should be called after
 
3193
the indexes for a table have been created. Each foreign key constraint must
 
3194
be accompanied with indexes in both participating tables. The indexes are
 
3195
allowed to contain more fields than mentioned in the constraint.
 
3196
@return error code or DB_SUCCESS */
 
3197
static
 
3198
ulint
 
3199
dict_create_foreign_constraints_low(
 
3200
/*================================*/
 
3201
        trx_t*          trx,    /*!< in: transaction */
 
3202
        mem_heap_t*     heap,   /*!< in: memory heap */
 
3203
        const void*     cs,/*!< in: the character set of sql_string */
 
3204
        const char*     sql_string,
 
3205
                                /*!< in: CREATE TABLE or ALTER TABLE statement
 
3206
                                where foreign keys are declared like:
 
3207
                                FOREIGN KEY (a, b) REFERENCES table2(c, d),
 
3208
                                table2 can be written also with the database
 
3209
                                name before it: test.table2; the default
 
3210
                                database is the database of parameter name */
 
3211
        const char*     name,   /*!< in: table full name in the normalized form
 
3212
                                database_name/table_name */
 
3213
        ibool           reject_fks)
 
3214
                                /*!< in: if TRUE, fail with error code
 
3215
                                DB_CANNOT_ADD_CONSTRAINT if any foreign
 
3216
                                keys are found. */
 
3217
{
 
3218
        dict_table_t*   table;
 
3219
        dict_table_t*   referenced_table;
 
3220
        dict_table_t*   table_to_alter;
 
3221
        ulint           highest_id_so_far       = 0;
 
3222
        dict_index_t*   index;
 
3223
        dict_foreign_t* foreign;
 
3224
        const char*     ptr                     = sql_string;
 
3225
        const char*     start_of_latest_foreign = sql_string;
 
3226
        FILE*           ef                      = dict_foreign_err_file;
 
3227
        const char*     constraint_name;
 
3228
        ibool           success;
 
3229
        ulint           error;
 
3230
        const char*     ptr1;
 
3231
        const char*     ptr2;
 
3232
        ulint           i;
 
3233
        ulint           j;
 
3234
        ibool           is_on_delete;
 
3235
        ulint           n_on_deletes;
 
3236
        ulint           n_on_updates;
 
3237
        const dict_col_t*columns[500];
 
3238
        const char*     column_names[500];
 
3239
        const char*     referenced_table_name;
 
3240
 
 
3241
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
3242
 
 
3243
        table = dict_table_get_low(name);
 
3244
 
 
3245
        if (table == NULL) {
 
3246
                mutex_enter(&dict_foreign_err_mutex);
 
3247
                dict_foreign_error_report_low(ef, name);
 
3248
                fprintf(ef,
 
3249
                        "Cannot find the table in the internal"
 
3250
                        " data dictionary of InnoDB.\n"
 
3251
                        "Create table statement:\n%s\n", sql_string);
 
3252
                mutex_exit(&dict_foreign_err_mutex);
 
3253
 
 
3254
                return(DB_ERROR);
 
3255
        }
 
3256
 
 
3257
        /* First check if we are actually doing an ALTER TABLE, and in that
 
3258
        case look for the table being altered */
 
3259
 
 
3260
        ptr = dict_accept(cs, ptr, "ALTER", &success);
 
3261
 
 
3262
        if (!success) {
 
3263
 
 
3264
                goto loop;
 
3265
        }
 
3266
 
 
3267
        ptr = dict_accept(cs, ptr, "TABLE", &success);
 
3268
 
 
3269
        if (!success) {
 
3270
 
 
3271
                goto loop;
 
3272
        }
 
3273
 
 
3274
        /* We are doing an ALTER TABLE: scan the table name we are altering */
 
3275
 
 
3276
        ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
 
3277
                                   &success, heap, &referenced_table_name);
 
3278
        if (!success) {
 
3279
                fprintf(stderr,
 
3280
                        "InnoDB: Error: could not find"
 
3281
                        " the table being ALTERED in:\n%s\n",
 
3282
                        sql_string);
 
3283
 
 
3284
                return(DB_ERROR);
 
3285
        }
 
3286
 
 
3287
        /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
 
3288
        format databasename/tablename_ibfk_[number], where [number] is local
 
3289
        to the table; look for the highest [number] for table_to_alter, so
 
3290
        that we can assign to new constraints higher numbers. */
 
3291
 
 
3292
        /* If we are altering a temporary table, the table name after ALTER
 
3293
        TABLE does not correspond to the internal table name, and
 
3294
        table_to_alter is NULL. TODO: should we fix this somehow? */
 
3295
 
 
3296
        if (table_to_alter == NULL) {
 
3297
                highest_id_so_far = 0;
 
3298
        } else {
 
3299
                highest_id_so_far = dict_table_get_highest_foreign_id(
 
3300
                        table_to_alter);
 
3301
        }
 
3302
 
 
3303
        /* Scan for foreign key declarations in a loop */
 
3304
loop:
 
3305
        /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
 
3306
 
 
3307
        ptr1 = dict_scan_to(ptr, "CONSTRAINT");
 
3308
        ptr2 = dict_scan_to(ptr, "FOREIGN");
 
3309
 
 
3310
        constraint_name = NULL;
 
3311
 
 
3312
        if (ptr1 < ptr2) {
 
3313
                /* The user may have specified a constraint name. Pick it so
 
3314
                that we can store 'databasename/constraintname' as the id of
 
3315
                of the constraint to system tables. */
 
3316
                ptr = ptr1;
 
3317
 
 
3318
                ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
 
3319
 
 
3320
                ut_a(success);
 
3321
 
 
3322
                if (!innobase_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
 
3323
                        goto loop;
 
3324
                }
 
3325
 
 
3326
                while (innobase_isspace(cs, *ptr)) {
 
3327
                        ptr++;
 
3328
                }
 
3329
 
 
3330
                /* read constraint name unless got "CONSTRAINT FOREIGN" */
 
3331
                if (ptr != ptr2) {
 
3332
                        ptr = dict_scan_id(cs, ptr, heap,
 
3333
                                           &constraint_name, FALSE, FALSE);
 
3334
                }
 
3335
        } else {
 
3336
                ptr = ptr2;
 
3337
        }
 
3338
 
 
3339
        if (*ptr == '\0') {
 
3340
                /* The proper way to reject foreign keys for temporary
 
3341
                tables would be to split the lexing and syntactical
 
3342
                analysis of foreign key clauses from the actual adding
 
3343
                of them, so that ha_innodb.cc could first parse the SQL
 
3344
                command, determine if there are any foreign keys, and
 
3345
                if so, immediately reject the command if the table is a
 
3346
                temporary one. For now, this kludge will work. */
 
3347
                if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
 
3348
 
 
3349
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
3350
                }
 
3351
 
 
3352
                /**********************************************************/
 
3353
                /* The following call adds the foreign key constraints
 
3354
                to the data dictionary system tables on disk */
 
3355
 
 
3356
                error = dict_create_add_foreigns_to_dictionary(
 
3357
                        highest_id_so_far, table, trx);
 
3358
                return(error);
 
3359
        }
 
3360
 
 
3361
        start_of_latest_foreign = ptr;
 
3362
 
 
3363
        ptr = dict_accept(cs, ptr, "FOREIGN", &success);
 
3364
 
 
3365
        if (!success) {
 
3366
                goto loop;
 
3367
        }
 
3368
 
 
3369
        if (!innobase_isspace(cs, *ptr)) {
 
3370
                goto loop;
 
3371
        }
 
3372
 
 
3373
        ptr = dict_accept(cs, ptr, "KEY", &success);
 
3374
 
 
3375
        if (!success) {
 
3376
                goto loop;
 
3377
        }
 
3378
 
 
3379
        ptr = dict_accept(cs, ptr, "(", &success);
 
3380
 
 
3381
        if (!success) {
 
3382
                /* MySQL allows also an index id before the '('; we
 
3383
                skip it */
 
3384
                ptr = dict_skip_word(cs, ptr, &success);
 
3385
 
 
3386
                if (!success) {
 
3387
                        dict_foreign_report_syntax_err(
 
3388
                                name, start_of_latest_foreign, ptr);
 
3389
 
 
3390
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
3391
                }
 
3392
 
 
3393
                ptr = dict_accept(cs, ptr, "(", &success);
 
3394
 
 
3395
                if (!success) {
 
3396
                        /* We do not flag a syntax error here because in an
 
3397
                        ALTER TABLE we may also have DROP FOREIGN KEY abc */
 
3398
 
 
3399
                        goto loop;
 
3400
                }
 
3401
        }
 
3402
 
 
3403
        i = 0;
 
3404
 
 
3405
        /* Scan the columns in the first list */
 
3406
col_loop1:
 
3407
        ut_a(i < (sizeof column_names) / sizeof *column_names);
 
3408
        ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
 
3409
                            heap, column_names + i);
 
3410
        if (!success) {
 
3411
                mutex_enter(&dict_foreign_err_mutex);
 
3412
                dict_foreign_error_report_low(ef, name);
 
3413
                fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
 
3414
                        start_of_latest_foreign, ptr);
 
3415
                mutex_exit(&dict_foreign_err_mutex);
 
3416
 
 
3417
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3418
        }
 
3419
 
 
3420
        i++;
 
3421
 
 
3422
        ptr = dict_accept(cs, ptr, ",", &success);
 
3423
 
 
3424
        if (success) {
 
3425
                goto col_loop1;
 
3426
        }
 
3427
 
 
3428
        ptr = dict_accept(cs, ptr, ")", &success);
 
3429
 
 
3430
        if (!success) {
 
3431
                dict_foreign_report_syntax_err(
 
3432
                        name, start_of_latest_foreign, ptr);
 
3433
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3434
        }
 
3435
 
 
3436
        /* Try to find an index which contains the columns
 
3437
        as the first fields and in the right order */
 
3438
 
 
3439
        index = dict_foreign_find_index(table, column_names, i,
 
3440
                                        NULL, TRUE, FALSE);
 
3441
 
 
3442
        if (!index) {
 
3443
                mutex_enter(&dict_foreign_err_mutex);
 
3444
                dict_foreign_error_report_low(ef, name);
 
3445
                fputs("There is no index in table ", ef);
 
3446
                ut_print_name(ef, NULL, TRUE, name);
 
3447
                fprintf(ef, " where the columns appear\n"
 
3448
                        "as the first columns. Constraint:\n%s\n"
 
3449
                        "See " REFMAN "innodb-foreign-key-constraints.html\n"
 
3450
                        "for correct foreign key definition.\n",
 
3451
                        start_of_latest_foreign);
 
3452
                mutex_exit(&dict_foreign_err_mutex);
 
3453
 
 
3454
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3455
        }
 
3456
        ptr = dict_accept(cs, ptr, "REFERENCES", &success);
 
3457
 
 
3458
        if (!success || !innobase_isspace(cs, *ptr)) {
 
3459
                dict_foreign_report_syntax_err(
 
3460
                        name, start_of_latest_foreign, ptr);
 
3461
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3462
        }
 
3463
 
 
3464
        /* Let us create a constraint struct */
 
3465
 
 
3466
        foreign = dict_mem_foreign_create();
 
3467
 
 
3468
        if (constraint_name) {
 
3469
                ulint   db_len;
 
3470
 
 
3471
                /* Catenate 'databasename/' to the constraint name specified
 
3472
                by the user: we conceive the constraint as belonging to the
 
3473
                same MySQL 'database' as the table itself. We store the name
 
3474
                to foreign->id. */
 
3475
 
 
3476
                db_len = dict_get_db_name_len(table->name);
 
3477
 
 
3478
                foreign->id = mem_heap_alloc(
 
3479
                        foreign->heap, db_len + strlen(constraint_name) + 2);
 
3480
 
 
3481
                ut_memcpy(foreign->id, table->name, db_len);
 
3482
                foreign->id[db_len] = '/';
 
3483
                strcpy(foreign->id + db_len + 1, constraint_name);
 
3484
        }
 
3485
 
 
3486
        foreign->foreign_table = table;
 
3487
        foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
 
3488
                                                      table->name);
 
3489
        foreign->foreign_index = index;
 
3490
        foreign->n_fields = (unsigned int) i;
 
3491
        foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
 
3492
                                                    i * sizeof(void*));
 
3493
        for (i = 0; i < foreign->n_fields; i++) {
 
3494
                foreign->foreign_col_names[i] = mem_heap_strdup(
 
3495
                        foreign->heap,
 
3496
                        dict_table_get_col_name(table,
 
3497
                                                dict_col_get_no(columns[i])));
 
3498
        }
 
3499
 
 
3500
        ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
 
3501
                                   &success, heap, &referenced_table_name);
 
3502
 
 
3503
        /* Note that referenced_table can be NULL if the user has suppressed
 
3504
        checking of foreign key constraints! */
 
3505
 
 
3506
        if (!success || (!referenced_table && trx->check_foreigns)) {
 
3507
                dict_foreign_free(foreign);
 
3508
 
 
3509
                mutex_enter(&dict_foreign_err_mutex);
 
3510
                dict_foreign_error_report_low(ef, name);
 
3511
                fprintf(ef, "%s:\nCannot resolve table name close to:\n"
 
3512
                        "%s\n",
 
3513
                        start_of_latest_foreign, ptr);
 
3514
                mutex_exit(&dict_foreign_err_mutex);
 
3515
 
 
3516
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3517
        }
 
3518
 
 
3519
        ptr = dict_accept(cs, ptr, "(", &success);
 
3520
 
 
3521
        if (!success) {
 
3522
                dict_foreign_free(foreign);
 
3523
                dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 
3524
                                               ptr);
 
3525
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3526
        }
 
3527
 
 
3528
        /* Scan the columns in the second list */
 
3529
        i = 0;
 
3530
 
 
3531
col_loop2:
 
3532
        ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
 
3533
                            heap, column_names + i);
 
3534
        i++;
 
3535
 
 
3536
        if (!success) {
 
3537
                dict_foreign_free(foreign);
 
3538
 
 
3539
                mutex_enter(&dict_foreign_err_mutex);
 
3540
                dict_foreign_error_report_low(ef, name);
 
3541
                fprintf(ef, "%s:\nCannot resolve column name close to:\n"
 
3542
                        "%s\n",
 
3543
                        start_of_latest_foreign, ptr);
 
3544
                mutex_exit(&dict_foreign_err_mutex);
 
3545
 
 
3546
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3547
        }
 
3548
 
 
3549
        ptr = dict_accept(cs, ptr, ",", &success);
 
3550
 
 
3551
        if (success) {
 
3552
                goto col_loop2;
 
3553
        }
 
3554
 
 
3555
        ptr = dict_accept(cs, ptr, ")", &success);
 
3556
 
 
3557
        if (!success || foreign->n_fields != i) {
 
3558
                dict_foreign_free(foreign);
 
3559
 
 
3560
                dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 
3561
                                               ptr);
 
3562
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3563
        }
 
3564
 
 
3565
        n_on_deletes = 0;
 
3566
        n_on_updates = 0;
 
3567
 
 
3568
scan_on_conditions:
 
3569
        /* Loop here as long as we can find ON ... conditions */
 
3570
 
 
3571
        ptr = dict_accept(cs, ptr, "ON", &success);
 
3572
 
 
3573
        if (!success) {
 
3574
 
 
3575
                goto try_find_index;
 
3576
        }
 
3577
 
 
3578
        ptr = dict_accept(cs, ptr, "DELETE", &success);
 
3579
 
 
3580
        if (!success) {
 
3581
                ptr = dict_accept(cs, ptr, "UPDATE", &success);
 
3582
 
 
3583
                if (!success) {
 
3584
                        dict_foreign_free(foreign);
 
3585
 
 
3586
                        dict_foreign_report_syntax_err(
 
3587
                                name, start_of_latest_foreign, ptr);
 
3588
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
3589
                }
 
3590
 
 
3591
                is_on_delete = FALSE;
 
3592
                n_on_updates++;
 
3593
        } else {
 
3594
                is_on_delete = TRUE;
 
3595
                n_on_deletes++;
 
3596
        }
 
3597
 
 
3598
        ptr = dict_accept(cs, ptr, "RESTRICT", &success);
 
3599
 
 
3600
        if (success) {
 
3601
                goto scan_on_conditions;
 
3602
        }
 
3603
 
 
3604
        ptr = dict_accept(cs, ptr, "CASCADE", &success);
 
3605
 
 
3606
        if (success) {
 
3607
                if (is_on_delete) {
 
3608
                        foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
 
3609
                } else {
 
3610
                        foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
 
3611
                }
 
3612
 
 
3613
                goto scan_on_conditions;
 
3614
        }
 
3615
 
 
3616
        ptr = dict_accept(cs, ptr, "NO", &success);
 
3617
 
 
3618
        if (success) {
 
3619
                ptr = dict_accept(cs, ptr, "ACTION", &success);
 
3620
 
 
3621
                if (!success) {
 
3622
                        dict_foreign_free(foreign);
 
3623
                        dict_foreign_report_syntax_err(
 
3624
                                name, start_of_latest_foreign, ptr);
 
3625
 
 
3626
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
3627
                }
 
3628
 
 
3629
                if (is_on_delete) {
 
3630
                        foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
 
3631
                } else {
 
3632
                        foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
 
3633
                }
 
3634
 
 
3635
                goto scan_on_conditions;
 
3636
        }
 
3637
 
 
3638
        ptr = dict_accept(cs, ptr, "SET", &success);
 
3639
 
 
3640
        if (!success) {
 
3641
                dict_foreign_free(foreign);
 
3642
                dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 
3643
                                               ptr);
 
3644
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3645
        }
 
3646
 
 
3647
        ptr = dict_accept(cs, ptr, "NULL", &success);
 
3648
 
 
3649
        if (!success) {
 
3650
                dict_foreign_free(foreign);
 
3651
                dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 
3652
                                               ptr);
 
3653
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3654
        }
 
3655
 
 
3656
        for (j = 0; j < foreign->n_fields; j++) {
 
3657
                if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
 
3658
                    & DATA_NOT_NULL) {
 
3659
 
 
3660
                        /* It is not sensible to define SET NULL
 
3661
                        if the column is not allowed to be NULL! */
 
3662
 
 
3663
                        dict_foreign_free(foreign);
 
3664
 
 
3665
                        mutex_enter(&dict_foreign_err_mutex);
 
3666
                        dict_foreign_error_report_low(ef, name);
 
3667
                        fprintf(ef, "%s:\n"
 
3668
                                "You have defined a SET NULL condition"
 
3669
                                " though some of the\n"
 
3670
                                "columns are defined as NOT NULL.\n",
 
3671
                                start_of_latest_foreign);
 
3672
                        mutex_exit(&dict_foreign_err_mutex);
 
3673
 
 
3674
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
3675
                }
 
3676
        }
 
3677
 
 
3678
        if (is_on_delete) {
 
3679
                foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
 
3680
        } else {
 
3681
                foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
 
3682
        }
 
3683
 
 
3684
        goto scan_on_conditions;
 
3685
 
 
3686
try_find_index:
 
3687
        if (n_on_deletes > 1 || n_on_updates > 1) {
 
3688
                /* It is an error to define more than 1 action */
 
3689
 
 
3690
                dict_foreign_free(foreign);
 
3691
 
 
3692
                mutex_enter(&dict_foreign_err_mutex);
 
3693
                dict_foreign_error_report_low(ef, name);
 
3694
                fprintf(ef, "%s:\n"
 
3695
                        "You have twice an ON DELETE clause"
 
3696
                        " or twice an ON UPDATE clause.\n",
 
3697
                        start_of_latest_foreign);
 
3698
                mutex_exit(&dict_foreign_err_mutex);
 
3699
 
 
3700
                return(DB_CANNOT_ADD_CONSTRAINT);
 
3701
        }
 
3702
 
 
3703
        /* Try to find an index which contains the columns as the first fields
 
3704
        and in the right order, and the types are the same as in
 
3705
        foreign->foreign_index */
 
3706
 
 
3707
        if (referenced_table) {
 
3708
                index = dict_foreign_find_index(referenced_table,
 
3709
                                                column_names, i,
 
3710
                                                foreign->foreign_index,
 
3711
                                                TRUE, FALSE);
 
3712
                if (!index) {
 
3713
                        dict_foreign_free(foreign);
 
3714
                        mutex_enter(&dict_foreign_err_mutex);
 
3715
                        dict_foreign_error_report_low(ef, name);
 
3716
                        fprintf(ef, "%s:\n"
 
3717
                                "Cannot find an index in the"
 
3718
                                " referenced table where the\n"
 
3719
                                "referenced columns appear as the"
 
3720
                                " first columns, or column types\n"
 
3721
                                "in the table and the referenced table"
 
3722
                                " do not match for constraint.\n"
 
3723
                                "Note that the internal storage type of"
 
3724
                                " ENUM and SET changed in\n"
 
3725
                                "tables created with >= InnoDB-4.1.12,"
 
3726
                                " and such columns in old tables\n"
 
3727
                                "cannot be referenced by such columns"
 
3728
                                " in new tables.\n"
 
3729
                                "See " REFMAN
 
3730
                                "innodb-foreign-key-constraints.html\n"
 
3731
                                "for correct foreign key definition.\n",
 
3732
                                start_of_latest_foreign);
 
3733
                        mutex_exit(&dict_foreign_err_mutex);
 
3734
 
 
3735
                        return(DB_CANNOT_ADD_CONSTRAINT);
 
3736
                }
 
3737
        } else {
 
3738
                ut_a(trx->check_foreigns == FALSE);
 
3739
                index = NULL;
 
3740
        }
 
3741
 
 
3742
        foreign->referenced_index = index;
 
3743
        foreign->referenced_table = referenced_table;
 
3744
 
 
3745
        foreign->referenced_table_name
 
3746
                = mem_heap_strdup(foreign->heap, referenced_table_name);
 
3747
 
 
3748
        foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
 
3749
                                                       i * sizeof(void*));
 
3750
        for (i = 0; i < foreign->n_fields; i++) {
 
3751
                foreign->referenced_col_names[i]
 
3752
                        = mem_heap_strdup(foreign->heap, column_names[i]);
 
3753
        }
 
3754
 
 
3755
        /* We found an ok constraint definition: add to the lists */
 
3756
 
 
3757
        UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
 
3758
 
 
3759
        if (referenced_table) {
 
3760
                UT_LIST_ADD_LAST(referenced_list,
 
3761
                                 referenced_table->referenced_list,
 
3762
                                 foreign);
 
3763
        }
 
3764
 
 
3765
        goto loop;
 
3766
}
 
3767
 
 
3768
/*********************************************************************//**
 
3769
Scans a table create SQL string and adds to the data dictionary the foreign
 
3770
key constraints declared in the string. This function should be called after
 
3771
the indexes for a table have been created. Each foreign key constraint must
 
3772
be accompanied with indexes in both participating tables. The indexes are
 
3773
allowed to contain more fields than mentioned in the constraint.
 
3774
@return error code or DB_SUCCESS */
 
3775
UNIV_INTERN
 
3776
ulint
 
3777
dict_create_foreign_constraints(
 
3778
/*============================*/
 
3779
        trx_t*          trx,            /*!< in: transaction */
 
3780
        const char*     sql_string,     /*!< in: table create statement where
 
3781
                                        foreign keys are declared like:
 
3782
                                        FOREIGN KEY (a, b) REFERENCES
 
3783
                                        table2(c, d), table2 can be written
 
3784
                                        also with the database
 
3785
                                        name before it: test.table2; the
 
3786
                                        default database id the database of
 
3787
                                        parameter name */
 
3788
        size_t          sql_length,     /*!< in: length of sql_string */
 
3789
        const char*     name,           /*!< in: table full name in the
 
3790
                                        normalized form
 
3791
                                        database_name/table_name */
 
3792
        ibool           reject_fks)     /*!< in: if TRUE, fail with error
 
3793
                                        code DB_CANNOT_ADD_CONSTRAINT if
 
3794
                                        any foreign keys are found. */
 
3795
{
 
3796
        char*                   str;
 
3797
        ulint                   err;
 
3798
        mem_heap_t*             heap;
 
3799
 
 
3800
        ut_a(trx);
 
3801
        ut_a(trx->mysql_thd);
 
3802
 
 
3803
        str = dict_strip_comments(sql_string, sql_length);
 
3804
        heap = mem_heap_create(10000);
 
3805
 
 
3806
        err = dict_create_foreign_constraints_low(
 
3807
                trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
 
3808
                reject_fks);
 
3809
 
 
3810
        mem_heap_free(heap);
 
3811
        mem_free(str);
 
3812
 
 
3813
        return(err);
 
3814
}
 
3815
 
 
3816
/**********************************************************************//**
 
3817
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
 
3818
@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
 
3819
constraint id does not match */
 
3820
UNIV_INTERN
 
3821
ulint
 
3822
dict_foreign_parse_drop_constraints(
 
3823
/*================================*/
 
3824
        mem_heap_t*     heap,                   /*!< in: heap from which we can
 
3825
                                                allocate memory */
 
3826
        trx_t*          trx,                    /*!< in: transaction */
 
3827
        dict_table_t*   table,                  /*!< in: table */
 
3828
        ulint*          n,                      /*!< out: number of constraints
 
3829
                                                to drop */
 
3830
        const char***   constraints_to_drop)    /*!< out: id's of the
 
3831
                                                constraints to drop */
 
3832
{
 
3833
        dict_foreign_t*         foreign;
 
3834
        ibool                   success;
 
3835
        char*                   str;
 
3836
        size_t                  len;
 
3837
        const char*             ptr;
 
3838
        const char*             id;
 
3839
        FILE*                   ef      = dict_foreign_err_file;
 
3840
        const void*     cs;
 
3841
 
 
3842
        ut_a(trx);
 
3843
        ut_a(trx->mysql_thd);
 
3844
 
 
3845
        cs = innobase_get_charset(trx->mysql_thd);
 
3846
 
 
3847
        *n = 0;
 
3848
 
 
3849
        *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
 
3850
 
 
3851
        ptr = innobase_get_stmt(trx->mysql_thd, &len);
 
3852
 
 
3853
        str = dict_strip_comments(ptr, len);
 
3854
 
 
3855
        ptr = str;
 
3856
 
 
3857
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
3858
loop:
 
3859
        ptr = dict_scan_to(ptr, "DROP");
 
3860
 
 
3861
        if (*ptr == '\0') {
 
3862
                mem_free(str);
 
3863
 
 
3864
                return(DB_SUCCESS);
 
3865
        }
 
3866
 
 
3867
        ptr = dict_accept(cs, ptr, "DROP", &success);
 
3868
 
 
3869
        if (!innobase_isspace(cs, *ptr)) {
 
3870
 
 
3871
                goto loop;
 
3872
        }
 
3873
 
 
3874
        ptr = dict_accept(cs, ptr, "FOREIGN", &success);
 
3875
 
 
3876
        if (!success || !innobase_isspace(cs, *ptr)) {
 
3877
 
 
3878
                goto loop;
 
3879
        }
 
3880
 
 
3881
        ptr = dict_accept(cs, ptr, "KEY", &success);
 
3882
 
 
3883
        if (!success) {
 
3884
 
 
3885
                goto syntax_error;
 
3886
        }
 
3887
 
 
3888
        ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
 
3889
 
 
3890
        if (id == NULL) {
 
3891
 
 
3892
                goto syntax_error;
 
3893
        }
 
3894
 
 
3895
        ut_a(*n < 1000);
 
3896
        (*constraints_to_drop)[*n] = id;
 
3897
        (*n)++;
 
3898
 
 
3899
        /* Look for the given constraint id */
 
3900
 
 
3901
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
3902
 
 
3903
        while (foreign != NULL) {
 
3904
                if (0 == strcmp(foreign->id, id)
 
3905
                    || (strchr(foreign->id, '/')
 
3906
                        && 0 == strcmp(id,
 
3907
                                       dict_remove_db_name(foreign->id)))) {
 
3908
                        /* Found */
 
3909
                        break;
 
3910
                }
 
3911
 
 
3912
                foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
3913
        }
 
3914
 
 
3915
        if (foreign == NULL) {
 
3916
                mutex_enter(&dict_foreign_err_mutex);
 
3917
                rewind(ef);
 
3918
                ut_print_timestamp(ef);
 
3919
                fputs(" Error in dropping of a foreign key constraint"
 
3920
                      " of table ", ef);
 
3921
                ut_print_name(ef, NULL, TRUE, table->name);
 
3922
                fputs(",\n"
 
3923
                      "in SQL command\n", ef);
 
3924
                fputs(str, ef);
 
3925
                fputs("\nCannot find a constraint with the given id ", ef);
 
3926
                ut_print_name(ef, NULL, FALSE, id);
 
3927
                fputs(".\n", ef);
 
3928
                mutex_exit(&dict_foreign_err_mutex);
 
3929
 
 
3930
                mem_free(str);
 
3931
 
 
3932
                return(DB_CANNOT_DROP_CONSTRAINT);
 
3933
        }
 
3934
 
 
3935
        goto loop;
 
3936
 
 
3937
syntax_error:
 
3938
        mutex_enter(&dict_foreign_err_mutex);
 
3939
        rewind(ef);
 
3940
        ut_print_timestamp(ef);
 
3941
        fputs(" Syntax error in dropping of a"
 
3942
              " foreign key constraint of table ", ef);
 
3943
        ut_print_name(ef, NULL, TRUE, table->name);
 
3944
        fprintf(ef, ",\n"
 
3945
                "close to:\n%s\n in SQL command\n%s\n", ptr, str);
 
3946
        mutex_exit(&dict_foreign_err_mutex);
 
3947
 
 
3948
        mem_free(str);
 
3949
 
 
3950
        return(DB_CANNOT_DROP_CONSTRAINT);
 
3951
}
 
3952
 
 
3953
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
 
3954
 
 
3955
/**********************************************************************//**
 
3956
Returns an index object if it is found in the dictionary cache.
 
3957
Assumes that dict_sys->mutex is already being held.
 
3958
@return index, NULL if not found */
 
3959
UNIV_INTERN
 
3960
dict_index_t*
 
3961
dict_index_get_if_in_cache_low(
 
3962
/*===========================*/
 
3963
        index_id_t      index_id)       /*!< in: index id */
 
3964
{
 
3965
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
3966
 
 
3967
        return(dict_index_find_on_id_low(index_id));
 
3968
}
 
3969
 
 
3970
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 
3971
/**********************************************************************//**
 
3972
Returns an index object if it is found in the dictionary cache.
 
3973
@return index, NULL if not found */
 
3974
UNIV_INTERN
 
3975
dict_index_t*
 
3976
dict_index_get_if_in_cache(
 
3977
/*=======================*/
 
3978
        index_id_t      index_id)       /*!< in: index id */
 
3979
{
 
3980
        dict_index_t*   index;
 
3981
 
 
3982
        if (dict_sys == NULL) {
 
3983
                return(NULL);
 
3984
        }
 
3985
 
 
3986
        mutex_enter(&(dict_sys->mutex));
 
3987
 
 
3988
        index = dict_index_get_if_in_cache_low(index_id);
 
3989
 
 
3990
        mutex_exit(&(dict_sys->mutex));
 
3991
 
 
3992
        return(index);
 
3993
}
 
3994
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
 
3995
 
 
3996
#ifdef UNIV_DEBUG
 
3997
/**********************************************************************//**
 
3998
Checks that a tuple has n_fields_cmp value in a sensible range, so that
 
3999
no comparison can occur with the page number field in a node pointer.
 
4000
@return TRUE if ok */
 
4001
UNIV_INTERN
 
4002
ibool
 
4003
dict_index_check_search_tuple(
 
4004
/*==========================*/
 
4005
        const dict_index_t*     index,  /*!< in: index tree */
 
4006
        const dtuple_t*         tuple)  /*!< in: tuple used in a search */
 
4007
{
 
4008
        ut_a(index);
 
4009
        ut_a(dtuple_get_n_fields_cmp(tuple)
 
4010
             <= dict_index_get_n_unique_in_tree(index));
 
4011
        return(TRUE);
 
4012
}
 
4013
#endif /* UNIV_DEBUG */
 
4014
 
 
4015
/**********************************************************************//**
 
4016
Builds a node pointer out of a physical record and a page number.
 
4017
@return own: node pointer */
 
4018
UNIV_INTERN
 
4019
dtuple_t*
 
4020
dict_index_build_node_ptr(
 
4021
/*======================*/
 
4022
        const dict_index_t*     index,  /*!< in: index */
 
4023
        const rec_t*            rec,    /*!< in: record for which to build node
 
4024
                                        pointer */
 
4025
        ulint                   page_no,/*!< in: page number to put in node
 
4026
                                        pointer */
 
4027
        mem_heap_t*             heap,   /*!< in: memory heap where pointer
 
4028
                                        created */
 
4029
        ulint                   level)  /*!< in: level of rec in tree:
 
4030
                                        0 means leaf level */
 
4031
{
 
4032
        dtuple_t*       tuple;
 
4033
        dfield_t*       field;
 
4034
        byte*           buf;
 
4035
        ulint           n_unique;
 
4036
 
 
4037
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
4038
                /* In a universal index tree, we take the whole record as
 
4039
                the node pointer if the record is on the leaf level,
 
4040
                on non-leaf levels we remove the last field, which
 
4041
                contains the page number of the child page */
 
4042
 
 
4043
                ut_a(!dict_table_is_comp(index->table));
 
4044
                n_unique = rec_get_n_fields_old(rec);
 
4045
 
 
4046
                if (level > 0) {
 
4047
                        ut_a(n_unique > 1);
 
4048
                        n_unique--;
 
4049
                }
 
4050
        } else {
 
4051
                n_unique = dict_index_get_n_unique_in_tree(index);
 
4052
        }
 
4053
 
 
4054
        tuple = dtuple_create(heap, n_unique + 1);
 
4055
 
 
4056
        /* When searching in the tree for the node pointer, we must not do
 
4057
        comparison on the last field, the page number field, as on upper
 
4058
        levels in the tree there may be identical node pointers with a
 
4059
        different page number; therefore, we set the n_fields_cmp to one
 
4060
        less: */
 
4061
 
 
4062
        dtuple_set_n_fields_cmp(tuple, n_unique);
 
4063
 
 
4064
        dict_index_copy_types(tuple, index, n_unique);
 
4065
 
 
4066
        buf = mem_heap_alloc(heap, 4);
 
4067
 
 
4068
        mach_write_to_4(buf, page_no);
 
4069
 
 
4070
        field = dtuple_get_nth_field(tuple, n_unique);
 
4071
        dfield_set_data(field, buf, 4);
 
4072
 
 
4073
        dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
 
4074
 
 
4075
        rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
 
4076
        dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
 
4077
                             | REC_STATUS_NODE_PTR);
 
4078
 
 
4079
        ut_ad(dtuple_check_typed(tuple));
 
4080
 
 
4081
        return(tuple);
 
4082
}
 
4083
 
 
4084
/**********************************************************************//**
 
4085
Copies an initial segment of a physical record, long enough to specify an
 
4086
index entry uniquely.
 
4087
@return pointer to the prefix record */
 
4088
UNIV_INTERN
 
4089
rec_t*
 
4090
dict_index_copy_rec_order_prefix(
 
4091
/*=============================*/
 
4092
        const dict_index_t*     index,  /*!< in: index */
 
4093
        const rec_t*            rec,    /*!< in: record for which to
 
4094
                                        copy prefix */
 
4095
        ulint*                  n_fields,/*!< out: number of fields copied */
 
4096
        byte**                  buf,    /*!< in/out: memory buffer for the
 
4097
                                        copied prefix, or NULL */
 
4098
        ulint*                  buf_size)/*!< in/out: buffer size */
 
4099
{
 
4100
        ulint           n;
 
4101
 
 
4102
        UNIV_PREFETCH_R(rec);
 
4103
 
 
4104
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
4105
                ut_a(!dict_table_is_comp(index->table));
 
4106
                n = rec_get_n_fields_old(rec);
 
4107
        } else {
 
4108
                n = dict_index_get_n_unique_in_tree(index);
 
4109
        }
 
4110
 
 
4111
        *n_fields = n;
 
4112
        return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
 
4113
}
 
4114
 
 
4115
/**********************************************************************//**
 
4116
Builds a typed data tuple out of a physical record.
 
4117
@return own: data tuple */
 
4118
UNIV_INTERN
 
4119
dtuple_t*
 
4120
dict_index_build_data_tuple(
 
4121
/*========================*/
 
4122
        dict_index_t*   index,  /*!< in: index tree */
 
4123
        rec_t*          rec,    /*!< in: record for which to build data tuple */
 
4124
        ulint           n_fields,/*!< in: number of data fields */
 
4125
        mem_heap_t*     heap)   /*!< in: memory heap where tuple created */
 
4126
{
 
4127
        dtuple_t*       tuple;
 
4128
 
 
4129
        ut_ad(dict_table_is_comp(index->table)
 
4130
              || n_fields <= rec_get_n_fields_old(rec));
 
4131
 
 
4132
        tuple = dtuple_create(heap, n_fields);
 
4133
 
 
4134
        dict_index_copy_types(tuple, index, n_fields);
 
4135
 
 
4136
        rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
 
4137
 
 
4138
        ut_ad(dtuple_check_typed(tuple));
 
4139
 
 
4140
        return(tuple);
 
4141
}
 
4142
 
 
4143
/*********************************************************************//**
 
4144
Calculates the minimum record length in an index. */
 
4145
UNIV_INTERN
 
4146
ulint
 
4147
dict_index_calc_min_rec_len(
 
4148
/*========================*/
 
4149
        const dict_index_t*     index)  /*!< in: index */
 
4150
{
 
4151
        ulint   sum     = 0;
 
4152
        ulint   i;
 
4153
        ulint   comp    = dict_table_is_comp(index->table);
 
4154
 
 
4155
        if (comp) {
 
4156
                ulint nullable = 0;
 
4157
                sum = REC_N_NEW_EXTRA_BYTES;
 
4158
                for (i = 0; i < dict_index_get_n_fields(index); i++) {
 
4159
                        const dict_col_t*       col
 
4160
                                = dict_index_get_nth_col(index, i);
 
4161
                        ulint   size = dict_col_get_fixed_size(col, comp);
 
4162
                        sum += size;
 
4163
                        if (!size) {
 
4164
                                size = col->len;
 
4165
                                sum += size < 128 ? 1 : 2;
 
4166
                        }
 
4167
                        if (!(col->prtype & DATA_NOT_NULL)) {
 
4168
                                nullable++;
 
4169
                        }
 
4170
                }
 
4171
 
 
4172
                /* round the NULL flags up to full bytes */
 
4173
                sum += UT_BITS_IN_BYTES(nullable);
 
4174
 
 
4175
                return(sum);
 
4176
        }
 
4177
 
 
4178
        for (i = 0; i < dict_index_get_n_fields(index); i++) {
 
4179
                sum += dict_col_get_fixed_size(
 
4180
                        dict_index_get_nth_col(index, i), comp);
 
4181
        }
 
4182
 
 
4183
        if (sum > 127) {
 
4184
                sum += 2 * dict_index_get_n_fields(index);
 
4185
        } else {
 
4186
                sum += dict_index_get_n_fields(index);
 
4187
        }
 
4188
 
 
4189
        sum += REC_N_OLD_EXTRA_BYTES;
 
4190
 
 
4191
        return(sum);
 
4192
}
 
4193
 
 
4194
/*********************************************************************//**
 
4195
Calculates new estimates for table and index statistics. The statistics
 
4196
are used in query optimization. */
 
4197
UNIV_INTERN
 
4198
void
 
4199
dict_update_statistics_low(
 
4200
/*=======================*/
 
4201
        dict_table_t*   table,          /*!< in/out: table */
 
4202
        ibool           has_dict_mutex __attribute__((unused)))
 
4203
                                        /*!< in: TRUE if the caller has the
 
4204
                                        dictionary mutex */
 
4205
{
 
4206
        dict_index_t*   index;
 
4207
        ulint           sum_of_index_sizes      = 0;
 
4208
 
 
4209
        if (table->ibd_file_missing) {
 
4210
                ut_print_timestamp(stderr);
 
4211
                fprintf(stderr,
 
4212
                        "  InnoDB: cannot calculate statistics for table %s\n"
 
4213
                        "InnoDB: because the .ibd file is missing.  For help,"
 
4214
                        " please refer to\n"
 
4215
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
 
4216
                        table->name);
 
4217
 
 
4218
                return;
 
4219
        }
 
4220
 
 
4221
        /* Find out the sizes of the indexes and how many different values
 
4222
        for the key they approximately have */
 
4223
 
 
4224
        index = dict_table_get_first_index(table);
 
4225
 
 
4226
        if (index == NULL) {
 
4227
                /* Table definition is corrupt */
 
4228
 
 
4229
                return;
 
4230
        }
 
4231
 
 
4232
 
 
4233
        do {
 
4234
                if (UNIV_LIKELY
 
4235
                    (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
 
4236
                     || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
 
4237
                         && dict_index_is_clust(index)))) {
 
4238
                        ulint   size;
 
4239
                        size = btr_get_size(index, BTR_TOTAL_SIZE);
 
4240
 
 
4241
                        index->stat_index_size = size;
 
4242
 
 
4243
                        sum_of_index_sizes += size;
 
4244
 
 
4245
                        size = btr_get_size(index, BTR_N_LEAF_PAGES);
 
4246
 
 
4247
                        if (size == 0) {
 
4248
                                /* The root node of the tree is a leaf */
 
4249
                                size = 1;
 
4250
                        }
 
4251
 
 
4252
                        index->stat_n_leaf_pages = size;
 
4253
 
 
4254
                        btr_estimate_number_of_different_key_vals(index);
 
4255
                } else {
 
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. */
 
4262
                        ulint   i;
 
4263
 
 
4264
                        sum_of_index_sizes++;
 
4265
                        index->stat_index_size = index->stat_n_leaf_pages = 1;
 
4266
 
 
4267
                        for (i = dict_index_get_n_unique(index); i; ) {
 
4268
                                index->stat_n_diff_key_vals[i--] = 1;
 
4269
                        }
 
4270
                }
 
4271
 
 
4272
                index = dict_table_get_next_index(index);
 
4273
        } while (index);
 
4274
 
 
4275
        index = dict_table_get_first_index(table);
 
4276
 
 
4277
        dict_index_stat_mutex_enter(index);
 
4278
 
 
4279
        table->stat_n_rows = index->stat_n_diff_key_vals[
 
4280
                dict_index_get_n_unique(index)];
 
4281
 
 
4282
        dict_index_stat_mutex_exit(index);
 
4283
 
 
4284
        table->stat_clustered_index_size = index->stat_index_size;
 
4285
 
 
4286
        table->stat_sum_of_other_index_sizes = sum_of_index_sizes
 
4287
                - index->stat_index_size;
 
4288
 
 
4289
        table->stat_initialized = TRUE;
 
4290
 
 
4291
        table->stat_modified_counter = 0;
 
4292
}
 
4293
 
 
4294
/*********************************************************************//**
 
4295
Calculates new estimates for table and index statistics. The statistics
 
4296
are used in query optimization. */
 
4297
UNIV_INTERN
 
4298
void
 
4299
dict_update_statistics(
 
4300
/*===================*/
 
4301
        dict_table_t*   table)  /*!< in/out: table */
 
4302
{
 
4303
        dict_update_statistics_low(table, FALSE);
 
4304
}
 
4305
 
 
4306
/**********************************************************************//**
 
4307
Prints info of a foreign key constraint. */
 
4308
static
 
4309
void
 
4310
dict_foreign_print_low(
 
4311
/*===================*/
 
4312
        dict_foreign_t* foreign)        /*!< in: foreign key constraint */
 
4313
{
 
4314
        ulint   i;
 
4315
 
 
4316
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
4317
 
 
4318
        fprintf(stderr, "  FOREIGN KEY CONSTRAINT %s: %s (",
 
4319
                foreign->id, foreign->foreign_table_name);
 
4320
 
 
4321
        for (i = 0; i < foreign->n_fields; i++) {
 
4322
                fprintf(stderr, " %s", foreign->foreign_col_names[i]);
 
4323
        }
 
4324
 
 
4325
        fprintf(stderr, " )\n"
 
4326
                "             REFERENCES %s (",
 
4327
                foreign->referenced_table_name);
 
4328
 
 
4329
        for (i = 0; i < foreign->n_fields; i++) {
 
4330
                fprintf(stderr, " %s", foreign->referenced_col_names[i]);
 
4331
        }
 
4332
 
 
4333
        fputs(" )\n", stderr);
 
4334
}
 
4335
 
 
4336
/**********************************************************************//**
 
4337
Prints a table data. */
 
4338
UNIV_INTERN
 
4339
void
 
4340
dict_table_print(
 
4341
/*=============*/
 
4342
        dict_table_t*   table)  /*!< in: table */
 
4343
{
 
4344
        mutex_enter(&(dict_sys->mutex));
 
4345
        dict_table_print_low(table);
 
4346
        mutex_exit(&(dict_sys->mutex));
 
4347
}
 
4348
 
 
4349
/**********************************************************************//**
 
4350
Prints a table data when we know the table name. */
 
4351
UNIV_INTERN
 
4352
void
 
4353
dict_table_print_by_name(
 
4354
/*=====================*/
 
4355
        const char*     name)   /*!< in: table name */
 
4356
{
 
4357
        dict_table_t*   table;
 
4358
 
 
4359
        mutex_enter(&(dict_sys->mutex));
 
4360
 
 
4361
        table = dict_table_get_low(name);
 
4362
 
 
4363
        ut_a(table);
 
4364
 
 
4365
        dict_table_print_low(table);
 
4366
        mutex_exit(&(dict_sys->mutex));
 
4367
}
 
4368
 
 
4369
/**********************************************************************//**
 
4370
Prints a table data. */
 
4371
UNIV_INTERN
 
4372
void
 
4373
dict_table_print_low(
 
4374
/*=================*/
 
4375
        dict_table_t*   table)  /*!< in: table */
 
4376
{
 
4377
        dict_index_t*   index;
 
4378
        dict_foreign_t* foreign;
 
4379
        ulint           i;
 
4380
 
 
4381
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
4382
 
 
4383
        dict_update_statistics_low(table, TRUE);
 
4384
 
 
4385
        fprintf(stderr,
 
4386
                "--------------------------------------\n"
 
4387
                "TABLE: name %s, id %llu, flags %lx, columns %lu,"
 
4388
                " indexes %lu, appr.rows %lu\n"
 
4389
                "  COLUMNS: ",
 
4390
                table->name,
 
4391
                (ullint) table->id,
 
4392
                (ulong) table->flags,
 
4393
                (ulong) table->n_cols,
 
4394
                (ulong) UT_LIST_GET_LEN(table->indexes),
 
4395
                (ulong) table->stat_n_rows);
 
4396
 
 
4397
        for (i = 0; i < (ulint) table->n_cols; i++) {
 
4398
                dict_col_print_low(table, dict_table_get_nth_col(table, i));
 
4399
                fputs("; ", stderr);
 
4400
        }
 
4401
 
 
4402
        putc('\n', stderr);
 
4403
 
 
4404
        index = UT_LIST_GET_FIRST(table->indexes);
 
4405
 
 
4406
        while (index != NULL) {
 
4407
                dict_index_print_low(index);
 
4408
                index = UT_LIST_GET_NEXT(indexes, index);
 
4409
        }
 
4410
 
 
4411
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
4412
 
 
4413
        while (foreign != NULL) {
 
4414
                dict_foreign_print_low(foreign);
 
4415
                foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
4416
        }
 
4417
 
 
4418
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
4419
 
 
4420
        while (foreign != NULL) {
 
4421
                dict_foreign_print_low(foreign);
 
4422
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
4423
        }
 
4424
}
 
4425
 
 
4426
/**********************************************************************//**
 
4427
Prints a column data. */
 
4428
static
 
4429
void
 
4430
dict_col_print_low(
 
4431
/*===============*/
 
4432
        const dict_table_t*     table,  /*!< in: table */
 
4433
        const dict_col_t*       col)    /*!< in: column */
 
4434
{
 
4435
        dtype_t type;
 
4436
 
 
4437
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
4438
 
 
4439
        dict_col_copy_type(col, &type);
 
4440
        fprintf(stderr, "%s: ", dict_table_get_col_name(table,
 
4441
                                                        dict_col_get_no(col)));
 
4442
 
 
4443
        dtype_print(&type);
 
4444
}
 
4445
 
 
4446
/**********************************************************************//**
 
4447
Prints an index data. */
 
4448
static
 
4449
void
 
4450
dict_index_print_low(
 
4451
/*=================*/
 
4452
        dict_index_t*   index)  /*!< in: index */
 
4453
{
 
4454
        ib_int64_t      n_vals;
 
4455
        ulint           i;
 
4456
 
 
4457
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
4458
 
 
4459
        dict_index_stat_mutex_enter(index);
 
4460
 
 
4461
        if (index->n_user_defined_cols > 0) {
 
4462
                n_vals = index->stat_n_diff_key_vals[
 
4463
                        index->n_user_defined_cols];
 
4464
        } else {
 
4465
                n_vals = index->stat_n_diff_key_vals[1];
 
4466
        }
 
4467
 
 
4468
        dict_index_stat_mutex_exit(index);
 
4469
 
 
4470
        fprintf(stderr,
 
4471
                "  INDEX: name %s, id %llu, fields %lu/%lu,"
 
4472
                " uniq %lu, type %lu\n"
 
4473
                "   root page %lu, appr.key vals %lu,"
 
4474
                " leaf pages %lu, size pages %lu\n"
 
4475
                "   FIELDS: ",
 
4476
                index->name,
 
4477
                (ullint) index->id,
 
4478
                (ulong) index->n_user_defined_cols,
 
4479
                (ulong) index->n_fields,
 
4480
                (ulong) index->n_uniq,
 
4481
                (ulong) index->type,
 
4482
                (ulong) index->page,
 
4483
                (ulong) n_vals,
 
4484
                (ulong) index->stat_n_leaf_pages,
 
4485
                (ulong) index->stat_index_size);
 
4486
 
 
4487
        for (i = 0; i < index->n_fields; i++) {
 
4488
                dict_field_print_low(dict_index_get_nth_field(index, i));
 
4489
        }
 
4490
 
 
4491
        putc('\n', stderr);
 
4492
 
 
4493
#ifdef UNIV_BTR_PRINT
 
4494
        btr_print_size(index);
 
4495
 
 
4496
        btr_print_index(index, 7);
 
4497
#endif /* UNIV_BTR_PRINT */
 
4498
}
 
4499
 
 
4500
/**********************************************************************//**
 
4501
Prints a field data. */
 
4502
static
 
4503
void
 
4504
dict_field_print_low(
 
4505
/*=================*/
 
4506
        const dict_field_t*     field)  /*!< in: field */
 
4507
{
 
4508
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
4509
 
 
4510
        fprintf(stderr, " %s", field->name);
 
4511
 
 
4512
        if (field->prefix_len != 0) {
 
4513
                fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
 
4514
        }
 
4515
}
 
4516
 
 
4517
/**********************************************************************//**
 
4518
Outputs info on a foreign key of a table in a format suitable for
 
4519
CREATE TABLE. */
 
4520
UNIV_INTERN
 
4521
void
 
4522
dict_print_info_on_foreign_key_in_create_format(
 
4523
/*============================================*/
 
4524
        FILE*           file,           /*!< in: file where to print */
 
4525
        trx_t*          trx,            /*!< in: transaction */
 
4526
        dict_foreign_t* foreign,        /*!< in: foreign key constraint */
 
4527
        ibool           add_newline)    /*!< in: whether to add a newline */
 
4528
{
 
4529
        const char*     stripped_id;
 
4530
        ulint   i;
 
4531
 
 
4532
        if (strchr(foreign->id, '/')) {
 
4533
                /* Strip the preceding database name from the constraint id */
 
4534
                stripped_id = foreign->id + 1
 
4535
                        + dict_get_db_name_len(foreign->id);
 
4536
        } else {
 
4537
                stripped_id = foreign->id;
 
4538
        }
 
4539
 
 
4540
        putc(',', file);
 
4541
 
 
4542
        if (add_newline) {
 
4543
                /* SHOW CREATE TABLE wants constraints each printed nicely
 
4544
                on its own line, while error messages want no newlines
 
4545
                inserted. */
 
4546
                fputs("\n ", file);
 
4547
        }
 
4548
 
 
4549
        fputs(" CONSTRAINT ", file);
 
4550
        ut_print_name(file, trx, FALSE, stripped_id);
 
4551
        fputs(" FOREIGN KEY (", file);
 
4552
 
 
4553
        for (i = 0;;) {
 
4554
                ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
 
4555
                if (++i < foreign->n_fields) {
 
4556
                        fputs(", ", file);
 
4557
                } else {
 
4558
                        break;
 
4559
                }
 
4560
        }
 
4561
 
 
4562
        fputs(") REFERENCES ", file);
 
4563
 
 
4564
        if (dict_tables_have_same_db(foreign->foreign_table_name,
 
4565
                                     foreign->referenced_table_name)) {
 
4566
                /* Do not print the database name of the referenced table */
 
4567
                ut_print_name(file, trx, TRUE,
 
4568
                              dict_remove_db_name(
 
4569
                                      foreign->referenced_table_name));
 
4570
        } else {
 
4571
                ut_print_name(file, trx, TRUE,
 
4572
                              foreign->referenced_table_name);
 
4573
        }
 
4574
 
 
4575
        putc(' ', file);
 
4576
        putc('(', file);
 
4577
 
 
4578
        for (i = 0;;) {
 
4579
                ut_print_name(file, trx, FALSE,
 
4580
                              foreign->referenced_col_names[i]);
 
4581
                if (++i < foreign->n_fields) {
 
4582
                        fputs(", ", file);
 
4583
                } else {
 
4584
                        break;
 
4585
                }
 
4586
        }
 
4587
 
 
4588
        putc(')', file);
 
4589
 
 
4590
        if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
 
4591
                fputs(" ON DELETE CASCADE", file);
 
4592
        }
 
4593
 
 
4594
        if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
 
4595
                fputs(" ON DELETE SET NULL", file);
 
4596
        }
 
4597
 
 
4598
        if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
 
4599
                fputs(" ON DELETE NO ACTION", file);
 
4600
        }
 
4601
 
 
4602
        if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
 
4603
                fputs(" ON UPDATE CASCADE", file);
 
4604
        }
 
4605
 
 
4606
        if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
 
4607
                fputs(" ON UPDATE SET NULL", file);
 
4608
        }
 
4609
 
 
4610
        if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
 
4611
                fputs(" ON UPDATE NO ACTION", file);
 
4612
        }
 
4613
}
 
4614
 
 
4615
/**********************************************************************//**
 
4616
Outputs info on foreign keys of a table. */
 
4617
UNIV_INTERN
 
4618
void
 
4619
dict_print_info_on_foreign_keys(
 
4620
/*============================*/
 
4621
        ibool           create_table_format, /*!< in: if TRUE then print in
 
4622
                                a format suitable to be inserted into
 
4623
                                a CREATE TABLE, otherwise in the format
 
4624
                                of SHOW TABLE STATUS */
 
4625
        FILE*           file,   /*!< in: file where to print */
 
4626
        trx_t*          trx,    /*!< in: transaction */
 
4627
        dict_table_t*   table)  /*!< in: table */
 
4628
{
 
4629
        dict_foreign_t* foreign;
 
4630
 
 
4631
        mutex_enter(&(dict_sys->mutex));
 
4632
 
 
4633
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
4634
 
 
4635
        if (foreign == NULL) {
 
4636
                mutex_exit(&(dict_sys->mutex));
 
4637
 
 
4638
                return;
 
4639
        }
 
4640
 
 
4641
        while (foreign != NULL) {
 
4642
                if (create_table_format) {
 
4643
                        dict_print_info_on_foreign_key_in_create_format(
 
4644
                                file, trx, foreign, TRUE);
 
4645
                } else {
 
4646
                        ulint   i;
 
4647
                        fputs("; (", file);
 
4648
 
 
4649
                        for (i = 0; i < foreign->n_fields; i++) {
 
4650
                                if (i) {
 
4651
                                        putc(' ', file);
 
4652
                                }
 
4653
 
 
4654
                                ut_print_name(file, trx, FALSE,
 
4655
                                              foreign->foreign_col_names[i]);
 
4656
                        }
 
4657
 
 
4658
                        fputs(") REFER ", file);
 
4659
                        ut_print_name(file, trx, TRUE,
 
4660
                                      foreign->referenced_table_name);
 
4661
                        putc('(', file);
 
4662
 
 
4663
                        for (i = 0; i < foreign->n_fields; i++) {
 
4664
                                if (i) {
 
4665
                                        putc(' ', file);
 
4666
                                }
 
4667
                                ut_print_name(
 
4668
                                        file, trx, FALSE,
 
4669
                                        foreign->referenced_col_names[i]);
 
4670
                        }
 
4671
 
 
4672
                        putc(')', file);
 
4673
 
 
4674
                        if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
 
4675
                                fputs(" ON DELETE CASCADE", file);
 
4676
                        }
 
4677
 
 
4678
                        if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
 
4679
                                fputs(" ON DELETE SET NULL", file);
 
4680
                        }
 
4681
 
 
4682
                        if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
 
4683
                                fputs(" ON DELETE NO ACTION", file);
 
4684
                        }
 
4685
 
 
4686
                        if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
 
4687
                                fputs(" ON UPDATE CASCADE", file);
 
4688
                        }
 
4689
 
 
4690
                        if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
 
4691
                                fputs(" ON UPDATE SET NULL", file);
 
4692
                        }
 
4693
 
 
4694
                        if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
 
4695
                                fputs(" ON UPDATE NO ACTION", file);
 
4696
                        }
 
4697
                }
 
4698
 
 
4699
                foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
4700
        }
 
4701
 
 
4702
        mutex_exit(&(dict_sys->mutex));
 
4703
}
 
4704
 
 
4705
/********************************************************************//**
 
4706
Displays the names of the index and the table. */
 
4707
UNIV_INTERN
 
4708
void
 
4709
dict_index_name_print(
 
4710
/*==================*/
 
4711
        FILE*                   file,   /*!< in: output stream */
 
4712
        trx_t*                  trx,    /*!< in: transaction */
 
4713
        const dict_index_t*     index)  /*!< in: index to print */
 
4714
{
 
4715
        fputs("index ", file);
 
4716
        ut_print_name(file, trx, FALSE, index->name);
 
4717
        fputs(" of table ", file);
 
4718
        ut_print_name(file, trx, TRUE, index->table_name);
 
4719
}
 
4720
#endif /* !UNIV_HOTBACKUP */
 
4721
 
 
4722
/**********************************************************************//**
 
4723
Inits dict_ind_redundant and dict_ind_compact. */
 
4724
UNIV_INTERN
 
4725
void
 
4726
dict_ind_init(void)
 
4727
/*===============*/
 
4728
{
 
4729
        dict_table_t*           table;
 
4730
 
 
4731
        /* create dummy table and index for REDUNDANT infimum and supremum */
 
4732
        table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
 
4733
        dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
 
4734
                               DATA_ENGLISH | DATA_NOT_NULL, 8);
 
4735
 
 
4736
        dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
 
4737
                                                   DICT_HDR_SPACE, 0, 1);
 
4738
        dict_index_add_col(dict_ind_redundant, table,
 
4739
                           dict_table_get_nth_col(table, 0), 0);
 
4740
        dict_ind_redundant->table = table;
 
4741
        /* create dummy table and index for COMPACT infimum and supremum */
 
4742
        table = dict_mem_table_create("SYS_DUMMY2",
 
4743
                                      DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
 
4744
        dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
 
4745
                               DATA_ENGLISH | DATA_NOT_NULL, 8);
 
4746
        dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
 
4747
                                                 DICT_HDR_SPACE, 0, 1);
 
4748
        dict_index_add_col(dict_ind_compact, table,
 
4749
                           dict_table_get_nth_col(table, 0), 0);
 
4750
        dict_ind_compact->table = table;
 
4751
 
 
4752
        /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
 
4753
        dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
 
4754
}
 
4755
 
 
4756
/**********************************************************************//**
 
4757
Frees dict_ind_redundant and dict_ind_compact. */
 
4758
static
 
4759
void
 
4760
dict_ind_free(void)
 
4761
/*===============*/
 
4762
{
 
4763
        dict_table_t*   table;
 
4764
 
 
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);
 
4769
 
 
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);
 
4774
}
 
4775
 
 
4776
#ifndef UNIV_HOTBACKUP
 
4777
/**********************************************************************//**
 
4778
Get index by name
 
4779
@return index, NULL if does not exist */
 
4780
UNIV_INTERN
 
4781
dict_index_t*
 
4782
dict_table_get_index_on_name(
 
4783
/*=========================*/
 
4784
        dict_table_t*   table,  /*!< in: table */
 
4785
        const char*     name)   /*!< in: name of the index to find */
 
4786
{
 
4787
        dict_index_t*   index;
 
4788
 
 
4789
        index = dict_table_get_first_index(table);
 
4790
 
 
4791
        while (index != NULL) {
 
4792
                if (ut_strcmp(index->name, name) == 0) {
 
4793
 
 
4794
                        return(index);
 
4795
                }
 
4796
 
 
4797
                index = dict_table_get_next_index(index);
 
4798
        }
 
4799
 
 
4800
        return(NULL);
 
4801
 
 
4802
}
 
4803
 
 
4804
/**********************************************************************//**
 
4805
Replace the index passed in with another equivalent index in the tables
 
4806
foreign key list. */
 
4807
UNIV_INTERN
 
4808
void
 
4809
dict_table_replace_index_in_foreign_list(
 
4810
/*=====================================*/
 
4811
        dict_table_t*   table,  /*!< in/out: table */
 
4812
        dict_index_t*   index)  /*!< in: index to be replaced */
 
4813
{
 
4814
        dict_foreign_t* foreign;
 
4815
 
 
4816
        for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
4817
             foreign;
 
4818
             foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
 
4819
 
 
4820
                if (foreign->foreign_index == index) {
 
4821
                        dict_index_t*   new_index
 
4822
                                = dict_foreign_find_equiv_index(foreign);
 
4823
                        ut_a(new_index);
 
4824
 
 
4825
                        foreign->foreign_index = new_index;
 
4826
                }
 
4827
        }
 
4828
}
 
4829
 
 
4830
/**********************************************************************//**
 
4831
In case there is more than one index with the same name return the index
 
4832
with the min(id).
 
4833
@return index, NULL if does not exist */
 
4834
UNIV_INTERN
 
4835
dict_index_t*
 
4836
dict_table_get_index_on_name_and_min_id(
 
4837
/*=====================================*/
 
4838
        dict_table_t*   table,  /*!< in: table */
 
4839
        const char*     name)   /*!< in: name of the index to find */
 
4840
{
 
4841
        dict_index_t*   index;
 
4842
        dict_index_t*   min_index; /* Index with matching name and min(id) */
 
4843
 
 
4844
        min_index = NULL;
 
4845
        index = dict_table_get_first_index(table);
 
4846
 
 
4847
        while (index != NULL) {
 
4848
                if (ut_strcmp(index->name, name) == 0) {
 
4849
                        if (!min_index || index->id < min_index->id) {
 
4850
 
 
4851
                                min_index = index;
 
4852
                        }
 
4853
                }
 
4854
 
 
4855
                index = dict_table_get_next_index(index);
 
4856
        }
 
4857
 
 
4858
        return(min_index);
 
4859
 
 
4860
}
 
4861
 
 
4862
#ifdef UNIV_DEBUG
 
4863
/**********************************************************************//**
 
4864
Check for duplicate index entries in a table [using the index name] */
 
4865
UNIV_INTERN
 
4866
void
 
4867
dict_table_check_for_dup_indexes(
 
4868
/*=============================*/
 
4869
        const dict_table_t*     table,  /*!< in: Check for dup indexes
 
4870
                                        in this table */
 
4871
        ibool                   tmp_ok) /*!< in: TRUE=allow temporary
 
4872
                                        index names */
 
4873
{
 
4874
        /* Check for duplicates, ignoring indexes that are marked
 
4875
        as to be dropped */
 
4876
 
 
4877
        const dict_index_t*     index1;
 
4878
        const dict_index_t*     index2;
 
4879
 
 
4880
        ut_ad(mutex_own(&dict_sys->mutex));
 
4881
 
 
4882
        /* The primary index _must_ exist */
 
4883
        ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
 
4884
 
 
4885
        index1 = UT_LIST_GET_FIRST(table->indexes);
 
4886
 
 
4887
        do {
 
4888
                ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);
 
4889
 
 
4890
                index2 = UT_LIST_GET_NEXT(indexes, index1);
 
4891
 
 
4892
                while (index2) {
 
4893
 
 
4894
                        if (!index2->to_be_dropped) {
 
4895
                                ut_ad(ut_strcmp(index1->name, index2->name));
 
4896
                        }
 
4897
 
 
4898
                        index2 = UT_LIST_GET_NEXT(indexes, index2);
 
4899
                }
 
4900
 
 
4901
                index1 = UT_LIST_GET_NEXT(indexes, index1);
 
4902
        } while (index1);
 
4903
}
 
4904
#endif /* UNIV_DEBUG */
 
4905
 
 
4906
/**************************************************************************
 
4907
Closes the data dictionary module. */
 
4908
UNIV_INTERN
 
4909
void
 
4910
dict_close(void)
 
4911
/*============*/
 
4912
{
 
4913
        ulint   i;
 
4914
 
 
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;
 
4919
 
 
4920
                table = HASH_GET_FIRST(dict_sys->table_hash, i);
 
4921
 
 
4922
                while (table) {
 
4923
                        dict_table_t*   prev_table = table;
 
4924
 
 
4925
                        table = HASH_GET_NEXT(name_hash, prev_table);
 
4926
#ifdef UNIV_DEBUG
 
4927
                        ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
 
4928
#endif
 
4929
                        /* Acquire only because it's a pre-condition. */
 
4930
                        mutex_enter(&dict_sys->mutex);
 
4931
 
 
4932
                        dict_table_remove_from_cache(prev_table);
 
4933
 
 
4934
                        mutex_exit(&dict_sys->mutex);
 
4935
                }
 
4936
        }
 
4937
 
 
4938
        hash_table_free(dict_sys->table_hash);
 
4939
 
 
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);
 
4943
 
 
4944
        dict_ind_free();
 
4945
 
 
4946
        mutex_free(&dict_sys->mutex);
 
4947
 
 
4948
        rw_lock_free(&dict_operation_lock);
 
4949
        memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
 
4950
 
 
4951
        mutex_free(&dict_foreign_err_mutex);
 
4952
 
 
4953
        mem_free(dict_sys);
 
4954
        dict_sys = NULL;
 
4955
 
 
4956
        for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
 
4957
                mutex_free(&dict_index_stat_mutex[i]);
 
4958
        }
 
4959
}
 
4960
#endif /* !UNIV_HOTBACKUP */