~ubuntu-branches/ubuntu/trusty/mariadb-5.5/trusty-proposed

« back to all changes in this revision

Viewing changes to storage/xtradb/dict/dict0dict.c

  • Committer: Package Import Robot
  • Author(s): Otto Kekäläinen
  • Date: 2013-12-22 10:27:05 UTC
  • Revision ID: package-import@ubuntu.com-20131222102705-mndw7s12mz0szrcn
Tags: upstream-5.5.32
Import upstream version 5.5.32

Show diffs side-by-side

added added

removed removed

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