~vadim-tk/percona-server/percona-galera-5.1.57-0.8.1

« back to all changes in this revision

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

  • Committer: root
  • Date: 2011-07-28 00:14:23 UTC
  • Revision ID: root@r815.office.percona.com-20110728001423-6pw0v4b7r0dkbsr4
Ported to Galera 0.8.1

Show diffs side-by-side

added added

removed removed

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