~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

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 <mystrings/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
 
}