~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Elan Ruusamäe
  • Date: 2008-12-04 19:38:26 UTC
  • mfrom: (644 drizzle)
  • mto: (641.3.10 devel)
  • mto: This revision was merged to the branch mainline in revision 649.
  • Revision ID: glen@haarber.alkohol.ee-20081204193826-xxyhd45ag121pf3z
- pull from trunk

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