~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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