~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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