~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-10-23 00:05:28 UTC
  • Revision ID: monty@inaugust.com-20081023000528-grdvrd8c4058nutm
Moved my_handler to myisam, which is where it actually belongs.

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