~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2009-09-30 07:01:32 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20090930070132-b1ol1xu1rpajdddy
Small namespace cleanup.

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