~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Padraig O'Sullivan
  • Date: 2009-03-07 20:12:20 UTC
  • mto: (934.3.2 mordred)
  • mto: This revision was merged to the branch mainline in revision 938.
  • Revision ID: osullivan.padraig@gmail.com-20090307201220-u9r93y0knyyb8ggy
Cleaning up my function object a little bit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/******************************************************************//**
20
 
@file dict/dict0dict.c
 
1
/**********************************************************************
21
2
Data dictionary system
22
3
 
 
4
(c) 1996 Innobase Oy
 
5
 
23
6
Created 1/8/1996 Heikki Tuuri
24
7
***********************************************************************/
25
8
 
29
12
#include "dict0dict.ic"
30
13
#endif
31
14
 
32
 
/** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
33
 
UNIV_INTERN dict_index_t*       dict_ind_redundant;
34
 
/** dummy index for ROW_FORMAT=COMPACT supremum and infimum records */
35
 
UNIV_INTERN dict_index_t*       dict_ind_compact;
36
 
 
37
 
#ifndef UNIV_HOTBACKUP
38
15
#include "buf0buf.h"
39
16
#include "data0type.h"
40
17
#include "mach0data.h"
52
29
#include "que0que.h"
53
30
#include "rem0cmp.h"
54
31
#include "row0merge.h"
55
 
#include "ha_prototypes.h" /* innobase_strcasecmp() */
 
32
#ifndef UNIV_HOTBACKUP
 
33
# if defined(BUILD_DRIZZLE)
 
34
#  include <mystrings/m_ctype.h>
 
35
# else
 
36
#  include "m_ctype.h" /* my_isspace() */
 
37
# endif /* DRIZZLE */
 
38
# include "ha_prototypes.h" /* innobase_strcasecmp() */
 
39
#endif /* !UNIV_HOTBACKUP */
56
40
 
57
41
#include <ctype.h>
58
42
 
59
 
#include <drizzled/session.h>
60
 
 
61
 
/** the dictionary system */
 
43
/* the dictionary system */
62
44
UNIV_INTERN dict_sys_t* dict_sys        = NULL;
63
45
 
64
 
/** @brief the data dictionary rw-latch protecting dict_sys
65
 
 
66
 
table create, drop, etc. reserve this in X-mode; implicit or
 
46
/* table create, drop, etc. reserve this in X-mode; implicit or
67
47
backround operations purge, rollback, foreign key checks reserve this
68
48
in S-mode; we cannot trust that MySQL protects implicit or background
69
49
operations a table drop since MySQL does not know of them; therefore
70
50
we need this; NOTE: a transaction which reserves this must keep book
71
 
on the mode in trx_struct::dict_operation_lock_mode */
 
51
on the mode in trx->dict_operation_lock_mode */
72
52
UNIV_INTERN rw_lock_t   dict_operation_lock;
73
53
 
74
 
/* Keys to register rwlocks and mutexes with performance schema */
75
 
#ifdef UNIV_PFS_RWLOCK
76
 
UNIV_INTERN mysql_pfs_key_t     dict_operation_lock_key;
77
 
UNIV_INTERN mysql_pfs_key_t     index_tree_rw_lock_key;
78
 
#endif /* UNIV_PFS_RWLOCK */
79
 
 
80
 
#ifdef UNIV_PFS_MUTEX
81
 
UNIV_INTERN mysql_pfs_key_t     dict_sys_mutex_key;
82
 
UNIV_INTERN mysql_pfs_key_t     dict_foreign_err_mutex_key;
83
 
#endif /* UNIV_PFS_MUTEX */
84
 
 
85
 
#define DICT_HEAP_SIZE          100     /*!< initial memory heap size when
86
 
                                        creating a table or index object */
87
 
#define DICT_POOL_PER_TABLE_HASH 512    /*!< buffer pool max size per table
 
54
#define DICT_POOL_PER_TABLE_HASH 512    /* buffer pool max size per table
88
55
                                        hash table fixed size in bytes */
89
 
#define DICT_POOL_PER_VARYING   4       /*!< buffer pool max size per data
90
 
                                        dictionary varying size in bytes */
91
56
 
92
 
/** Identifies generated InnoDB foreign key names */
 
57
/* Identifies generated InnoDB foreign key names */
93
58
static char     dict_ibfk[] = "_ibfk_";
94
59
 
95
 
/** array of rw locks protecting
96
 
dict_table_t::stat_initialized
97
 
dict_table_t::stat_n_rows (*)
98
 
dict_table_t::stat_clustered_index_size
99
 
dict_table_t::stat_sum_of_other_index_sizes
100
 
dict_table_t::stat_modified_counter (*)
101
 
dict_table_t::indexes*::stat_n_diff_key_vals[]
102
 
dict_table_t::indexes*::stat_index_size
103
 
dict_table_t::indexes*::stat_n_leaf_pages
104
 
(*) those are not always protected for performance reasons */
105
 
#define DICT_TABLE_STATS_LATCHES_SIZE   64
106
 
static rw_lock_t        dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
107
 
 
108
 
/*******************************************************************//**
 
60
/***********************************************************************
109
61
Tries to find column names for the index and sets the col field of the
110
 
index.
111
 
@return TRUE if the column names were found */
 
62
index. */
112
63
static
113
 
ibool
 
64
void
114
65
dict_index_find_cols(
115
66
/*=================*/
116
 
        dict_table_t*   table,  /*!< in: table */
117
 
        dict_index_t*   index); /*!< in: index */
118
 
/*******************************************************************//**
 
67
        dict_table_t*   table,  /* in: table */
 
68
        dict_index_t*   index); /* in: index */
 
69
/***********************************************************************
119
70
Builds the internal dictionary cache representation for a clustered
120
 
index, containing also system fields not defined by the user.
121
 
@return own: the internal representation of the clustered index */
 
71
index, containing also system fields not defined by the user. */
122
72
static
123
73
dict_index_t*
124
74
dict_index_build_internal_clust(
125
75
/*============================*/
126
 
        const dict_table_t*     table,  /*!< in: table */
127
 
        dict_index_t*           index); /*!< in: user representation of
 
76
                                        /* out, own: the internal
 
77
                                        representation of the clustered
 
78
                                        index */
 
79
        const dict_table_t*     table,  /* in: table */
 
80
        dict_index_t*           index); /* in: user representation of
128
81
                                        a clustered index */
129
 
/*******************************************************************//**
 
82
/***********************************************************************
130
83
Builds the internal dictionary cache representation for a non-clustered
131
 
index, containing also system fields not defined by the user.
132
 
@return own: the internal representation of the non-clustered index */
 
84
index, containing also system fields not defined by the user. */
133
85
static
134
86
dict_index_t*
135
87
dict_index_build_internal_non_clust(
136
88
/*================================*/
137
 
        const dict_table_t*     table,  /*!< in: table */
138
 
        dict_index_t*           index); /*!< in: user representation of
 
89
                                        /* out, own: the internal
 
90
                                        representation of the non-clustered
 
91
                                        index */
 
92
        const dict_table_t*     table,  /* in: table */
 
93
        dict_index_t*           index); /* in: user representation of
139
94
                                        a non-clustered index */
140
 
/**********************************************************************//**
 
95
/**************************************************************************
141
96
Removes a foreign constraint struct from the dictionary cache. */
142
97
static
143
98
void
144
99
dict_foreign_remove_from_cache(
145
100
/*===========================*/
146
 
        dict_foreign_t* foreign);       /*!< in, own: foreign constraint */
147
 
/**********************************************************************//**
 
101
        dict_foreign_t* foreign);       /* in, own: foreign constraint */
 
102
/**************************************************************************
148
103
Prints a column data. */
149
104
static
150
105
void
151
106
dict_col_print_low(
152
107
/*===============*/
153
 
        const dict_table_t*     table,  /*!< in: table */
154
 
        const dict_col_t*       col);   /*!< in: column */
155
 
/**********************************************************************//**
 
108
        const dict_table_t*     table,  /* in: table */
 
109
        const dict_col_t*       col);   /* in: column */
 
110
/**************************************************************************
156
111
Prints an index data. */
157
112
static
158
113
void
159
114
dict_index_print_low(
160
115
/*=================*/
161
 
        dict_index_t*   index); /*!< in: index */
162
 
/**********************************************************************//**
 
116
        dict_index_t*   index); /* in: index */
 
117
/**************************************************************************
163
118
Prints a field data. */
164
119
static
165
120
void
166
121
dict_field_print_low(
167
122
/*=================*/
168
 
        const dict_field_t*     field); /*!< in: field */
169
 
/*********************************************************************//**
 
123
        dict_field_t*   field); /* in: field */
 
124
/*************************************************************************
170
125
Frees a foreign key struct. */
171
126
static
172
127
void
173
128
dict_foreign_free(
174
129
/*==============*/
175
 
        dict_foreign_t* foreign);       /*!< in, own: foreign key struct */
 
130
        dict_foreign_t* foreign);       /* in, own: foreign key struct */
176
131
 
177
132
/* Stream for storing detailed information about the latest foreign key
178
133
and unique key errors */
180
135
/* mutex protecting the foreign and unique error buffers */
181
136
UNIV_INTERN mutex_t     dict_foreign_err_mutex;
182
137
 
183
 
/******************************************************************//**
 
138
#ifndef UNIV_HOTBACKUP
 
139
/**********************************************************************
184
140
Makes all characters in a NUL-terminated UTF-8 string lower case. */
185
141
UNIV_INTERN
186
142
void
187
143
dict_casedn_str(
188
144
/*============*/
189
 
        char*   a)      /*!< in/out: string to put in lower case */
 
145
        char*   a)      /* in/out: string to put in lower case */
190
146
{
191
147
        innobase_casedn_str(a);
192
148
}
 
149
#endif /* !UNIV_HOTBACKUP */
193
150
 
194
 
/********************************************************************//**
195
 
Checks if the database name in two table names is the same.
196
 
@return TRUE if same db name */
 
151
/************************************************************************
 
152
Checks if the database name in two table names is the same. */
197
153
UNIV_INTERN
198
154
ibool
199
155
dict_tables_have_same_db(
200
156
/*=====================*/
201
 
        const char*     name1,  /*!< in: table name in the form
 
157
                                /* out: TRUE if same db name */
 
158
        const char*     name1,  /* in: table name in the form
202
159
                                dbname '/' tablename */
203
 
        const char*     name2)  /*!< in: table name in the form
 
160
        const char*     name2)  /* in: table name in the form
204
161
                                dbname '/' tablename */
205
162
{
206
163
        for (; *name1 == *name2; name1++, name2++) {
212
169
        return(FALSE);
213
170
}
214
171
 
215
 
/********************************************************************//**
216
 
Return the end of table name where we have removed dbname and '/'.
217
 
@return table name */
 
172
/************************************************************************
 
173
Return the end of table name where we have removed dbname and '/'. */
218
174
UNIV_INTERN
219
175
const char*
220
176
dict_remove_db_name(
221
177
/*================*/
222
 
        const char*     name)   /*!< in: table name in the form
 
178
                                /* out: table name */
 
179
        const char*     name)   /* in: table name in the form
223
180
                                dbname '/' tablename */
224
181
{
225
182
        const char*     s = strchr(name, '/');
228
185
        return(s + 1);
229
186
}
230
187
 
231
 
/********************************************************************//**
232
 
Get the database name length in a table name.
233
 
@return database name length */
 
188
/************************************************************************
 
189
Get the database name length in a table name. */
234
190
UNIV_INTERN
235
191
ulint
236
192
dict_get_db_name_len(
237
193
/*=================*/
238
 
        const char*     name)   /*!< in: table name in the form
 
194
                                /* out: database name length */
 
195
        const char*     name)   /* in: table name in the form
239
196
                                dbname '/' tablename */
240
197
{
241
198
        const char*     s;
244
201
        return(s - name);
245
202
}
246
203
 
247
 
/********************************************************************//**
 
204
/************************************************************************
248
205
Reserves the dictionary system mutex for MySQL. */
249
206
UNIV_INTERN
250
207
void
254
211
        mutex_enter(&(dict_sys->mutex));
255
212
}
256
213
 
257
 
/********************************************************************//**
 
214
/************************************************************************
258
215
Releases the dictionary system mutex for MySQL. */
259
216
UNIV_INTERN
260
217
void
264
221
        mutex_exit(&(dict_sys->mutex));
265
222
}
266
223
 
267
 
/** Get the latch that protects the stats of a given table */
268
 
#define GET_TABLE_STATS_LATCH(table) \
269
 
        (&dict_table_stats_latches[ut_fold_ull(table->id) \
270
 
                                   % DICT_TABLE_STATS_LATCHES_SIZE])
271
 
 
272
 
/**********************************************************************//**
273
 
Lock the appropriate latch to protect a given table's statistics.
274
 
table->id is used to pick the corresponding latch from a global array of
275
 
latches. */
276
 
UNIV_INTERN
277
 
void
278
 
dict_table_stats_lock(
279
 
/*==================*/
280
 
        const dict_table_t*     table,          /*!< in: table */
281
 
        ulint                   latch_mode)     /*!< in: RW_S_LATCH or
282
 
                                                RW_X_LATCH */
283
 
{
284
 
        ut_ad(table != NULL);
285
 
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
286
 
 
287
 
        switch (latch_mode) {
288
 
        case RW_S_LATCH:
289
 
                rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
290
 
                break;
291
 
        case RW_X_LATCH:
292
 
                rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
293
 
                break;
294
 
        case RW_NO_LATCH:
295
 
                /* fall through */
296
 
        default:
297
 
                ut_error;
298
 
        }
299
 
}
300
 
 
301
 
/**********************************************************************//**
302
 
Unlock the latch that has been locked by dict_table_stats_lock() */
303
 
UNIV_INTERN
304
 
void
305
 
dict_table_stats_unlock(
306
 
/*====================*/
307
 
        const dict_table_t*     table,          /*!< in: table */
308
 
        ulint                   latch_mode)     /*!< in: RW_S_LATCH or
309
 
                                                RW_X_LATCH */
310
 
{
311
 
        ut_ad(table != NULL);
312
 
        ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
313
 
 
314
 
        switch (latch_mode) {
315
 
        case RW_S_LATCH:
316
 
                rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
317
 
                break;
318
 
        case RW_X_LATCH:
319
 
                rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
320
 
                break;
321
 
        case RW_NO_LATCH:
322
 
                /* fall through */
323
 
        default:
324
 
                ut_error;
325
 
        }
326
 
}
327
 
 
328
 
/********************************************************************//**
 
224
/************************************************************************
329
225
Decrements the count of open MySQL handles to a table. */
330
226
UNIV_INTERN
331
227
void
332
228
dict_table_decrement_handle_count(
333
229
/*==============================*/
334
 
        dict_table_t*   table,          /*!< in/out: table */
335
 
        ibool           dict_locked)    /*!< in: TRUE=data dictionary locked */
 
230
        dict_table_t*   table,          /* in/out: table */
 
231
        ibool           dict_locked)    /* in: TRUE=data dictionary locked */
336
232
{
337
233
        if (!dict_locked) {
338
234
                mutex_enter(&dict_sys->mutex);
347
243
                mutex_exit(&dict_sys->mutex);
348
244
        }
349
245
}
350
 
#endif /* !UNIV_HOTBACKUP */
351
246
 
352
 
/**********************************************************************//**
353
 
Returns a column's name.
354
 
@return column name. NOTE: not guaranteed to stay valid if table is
355
 
modified in any way (columns added, etc.). */
 
247
/**************************************************************************
 
248
Returns a column's name. */
356
249
UNIV_INTERN
357
250
const char*
358
251
dict_table_get_col_name(
359
252
/*====================*/
360
 
        const dict_table_t*     table,  /*!< in: table */
361
 
        ulint                   col_nr) /*!< in: column number */
 
253
                                        /* out: column name. NOTE: not
 
254
                                        guaranteed to stay valid if table is
 
255
                                        modified in any way (columns added,
 
256
                                        etc.). */
 
257
        const dict_table_t*     table,  /* in: table */
 
258
        ulint                   col_nr) /* in: column number */
362
259
{
363
260
        ulint           i;
364
261
        const char*     s;
377
274
        return(s);
378
275
}
379
276
 
380
 
#ifndef UNIV_HOTBACKUP
381
 
/********************************************************************//**
382
 
Acquire the autoinc lock. */
 
277
 
 
278
/************************************************************************
 
279
Acquire the autoinc lock.*/
383
280
UNIV_INTERN
384
281
void
385
282
dict_table_autoinc_lock(
386
283
/*====================*/
387
 
        dict_table_t*   table)  /*!< in/out: table */
 
284
        dict_table_t*   table)  /* in/out: table */
388
285
{
389
286
        mutex_enter(&table->autoinc_mutex);
390
287
}
391
288
 
392
 
/********************************************************************//**
 
289
/************************************************************************
393
290
Unconditionally set the autoinc counter. */
394
291
UNIV_INTERN
395
292
void
396
293
dict_table_autoinc_initialize(
397
294
/*==========================*/
398
 
        dict_table_t*   table,  /*!< in/out: table */
399
 
        ib_uint64_t     value)  /*!< in: next value to assign to a row */
 
295
        dict_table_t*   table,  /* in/out: table */
 
296
        ib_uint64_t     value)  /* in: next value to assign to a row */
400
297
{
401
298
        ut_ad(mutex_own(&table->autoinc_mutex));
402
299
 
403
300
        table->autoinc = value;
404
301
}
405
302
 
406
 
/********************************************************************//**
 
303
/************************************************************************
407
304
Reads the next autoinc value (== autoinc counter value), 0 if not yet
408
 
initialized.
409
 
@return value for a new row, or 0 */
 
305
initialized. */
410
306
UNIV_INTERN
411
307
ib_uint64_t
412
308
dict_table_autoinc_read(
413
309
/*====================*/
414
 
        const dict_table_t*     table)  /*!< in: table */
 
310
                                        /* out: value for a new row, or 0 */
 
311
        const dict_table_t*     table)  /* in: table */
415
312
{
416
313
        ut_ad(mutex_own(&table->autoinc_mutex));
417
314
 
418
315
        return(table->autoinc);
419
316
}
420
317
 
421
 
/********************************************************************//**
 
318
/************************************************************************
422
319
Updates the autoinc counter if the value supplied is greater than the
423
320
current value. */
424
321
UNIV_INTERN
426
323
dict_table_autoinc_update_if_greater(
427
324
/*=================================*/
428
325
 
429
 
        dict_table_t*   table,  /*!< in/out: table */
430
 
        ib_uint64_t     value)  /*!< in: value which was assigned to a row */
 
326
        dict_table_t*   table,  /* in/out: table */
 
327
        ib_uint64_t     value)  /* in: value which was assigned to a row */
431
328
{
432
329
        ut_ad(mutex_own(&table->autoinc_mutex));
433
330
 
437
334
        }
438
335
}
439
336
 
440
 
/********************************************************************//**
441
 
Release the autoinc lock. */
 
337
/************************************************************************
 
338
Release the autoinc lock.*/
442
339
UNIV_INTERN
443
340
void
444
341
dict_table_autoinc_unlock(
445
342
/*======================*/
446
 
        dict_table_t*   table)  /*!< in/out: table */
 
343
        dict_table_t*   table)  /* in/out: table */
447
344
{
448
345
        mutex_exit(&table->autoinc_mutex);
449
346
}
450
347
 
451
 
/**********************************************************************//**
 
348
/**************************************************************************
452
349
Looks for an index with the given table and index id.
453
 
NOTE that we do not reserve the dictionary mutex.
454
 
@return index or NULL if not found from cache */
 
350
NOTE that we do not reserve the dictionary mutex. */
455
351
UNIV_INTERN
456
352
dict_index_t*
457
353
dict_index_get_on_id_low(
458
354
/*=====================*/
459
 
        dict_table_t*   table,  /*!< in: table */
460
 
        index_id_t      id)     /*!< in: index id */
 
355
                                /* out: index or NULL if not found
 
356
                                from cache */
 
357
        dict_table_t*   table,  /* in: table */
 
358
        dulint          id)     /* in: index id */
461
359
{
462
360
        dict_index_t*   index;
463
361
 
464
362
        index = dict_table_get_first_index(table);
465
363
 
466
364
        while (index) {
467
 
                if (id == index->id) {
 
365
                if (0 == ut_dulint_cmp(id, index->id)) {
468
366
                        /* Found */
469
367
 
470
368
                        return(index);
475
373
 
476
374
        return(NULL);
477
375
}
478
 
#endif /* !UNIV_HOTBACKUP */
479
376
 
480
 
/********************************************************************//**
481
 
Looks for column n in an index.
482
 
@return position in internal representation of the index;
483
 
ULINT_UNDEFINED if not contained */
 
377
/************************************************************************
 
378
Looks for column n in an index. */
484
379
UNIV_INTERN
485
380
ulint
486
381
dict_index_get_nth_col_pos(
487
382
/*=======================*/
488
 
        const dict_index_t*     index,  /*!< in: index */
489
 
        ulint                   n)      /*!< in: column number */
 
383
                                        /* out: position in internal
 
384
                                        representation of the index;
 
385
                                        if not contained, returns
 
386
                                        ULINT_UNDEFINED */
 
387
        const dict_index_t*     index,  /* in: index */
 
388
        ulint                   n)      /* in: column number */
490
389
{
491
390
        const dict_field_t*     field;
492
391
        const dict_col_t*       col;
517
416
        return(ULINT_UNDEFINED);
518
417
}
519
418
 
520
 
#ifndef UNIV_HOTBACKUP
521
 
/********************************************************************//**
522
 
Returns TRUE if the index contains a column or a prefix of that column.
523
 
@return TRUE if contains the column or its prefix */
 
419
/************************************************************************
 
420
Returns TRUE if the index contains a column or a prefix of that column. */
524
421
UNIV_INTERN
525
422
ibool
526
423
dict_index_contains_col_or_prefix(
527
424
/*==============================*/
528
 
        const dict_index_t*     index,  /*!< in: index */
529
 
        ulint                   n)      /*!< in: column number */
 
425
                                        /* out: TRUE if contains the column
 
426
                                        or its prefix */
 
427
        const dict_index_t*     index,  /* in: index */
 
428
        ulint                   n)      /* in: column number */
530
429
{
531
430
        const dict_field_t*     field;
532
431
        const dict_col_t*       col;
557
456
        return(FALSE);
558
457
}
559
458
 
560
 
/********************************************************************//**
 
459
/************************************************************************
561
460
Looks for a matching field in an index. The column has to be the same. The
562
461
column in index must be complete, or must contain a prefix longer than the
563
462
column in index2. That is, we must be able to construct the prefix in index2
564
 
from the prefix in index.
565
 
@return position in internal representation of the index;
566
 
ULINT_UNDEFINED if not contained */
 
463
from the prefix in index. */
567
464
UNIV_INTERN
568
465
ulint
569
466
dict_index_get_nth_field_pos(
570
467
/*=========================*/
571
 
        const dict_index_t*     index,  /*!< in: index from which to search */
572
 
        const dict_index_t*     index2, /*!< in: index */
573
 
        ulint                   n)      /*!< in: field number in index2 */
 
468
                                        /* out: position in internal
 
469
                                        representation of the index;
 
470
                                        if not contained, returns
 
471
                                        ULINT_UNDEFINED */
 
472
        const dict_index_t*     index,  /* in: index from which to search */
 
473
        const dict_index_t*     index2, /* in: index */
 
474
        ulint                   n)      /* in: field number in index2 */
574
475
{
575
476
        const dict_field_t*     field;
576
477
        const dict_field_t*     field2;
599
500
        return(ULINT_UNDEFINED);
600
501
}
601
502
 
602
 
/**********************************************************************//**
603
 
Returns a table object based on table id.
604
 
@return table, NULL if does not exist */
 
503
/**************************************************************************
 
504
Returns a table object based on table id. */
605
505
UNIV_INTERN
606
506
dict_table_t*
607
507
dict_table_get_on_id(
608
508
/*=================*/
609
 
        table_id_t      table_id,       /*!< in: table id */
610
 
        trx_t*          trx)            /*!< in: transaction handle */
 
509
                                /* out: table, NULL if does not exist */
 
510
        dulint  table_id,       /* in: table id */
 
511
        trx_t*  trx)            /* in: transaction handle */
611
512
{
612
513
        dict_table_t*   table;
613
514
 
614
 
        if (trx->dict_operation_lock_mode == RW_X_LATCH) {
615
 
 
616
 
                /* Note: An X latch implies that the transaction
617
 
                already owns the dictionary mutex. */
618
 
 
619
 
                ut_ad(mutex_own(&dict_sys->mutex));
 
515
        if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
 
516
            || trx->dict_operation_lock_mode == RW_X_LATCH) {
 
517
                /* It is a system table which will always exist in the table
 
518
                cache: we avoid acquiring the dictionary mutex, because
 
519
                if we are doing a rollback to handle an error in TABLE
 
520
                CREATE, for example, we already have the mutex! */
 
521
 
 
522
                ut_ad(mutex_own(&(dict_sys->mutex))
 
523
                      || trx->dict_operation_lock_mode == RW_X_LATCH);
620
524
 
621
525
                return(dict_table_get_on_id_low(table_id));
622
526
        }
630
534
        return(table);
631
535
}
632
536
 
633
 
/********************************************************************//**
634
 
Looks for column n position in the clustered index.
635
 
@return position in internal representation of the clustered index */
 
537
/************************************************************************
 
538
Looks for column n position in the clustered index. */
636
539
UNIV_INTERN
637
540
ulint
638
541
dict_table_get_nth_col_pos(
639
542
/*=======================*/
640
 
        const dict_table_t*     table,  /*!< in: table */
641
 
        ulint                   n)      /*!< in: column number */
 
543
                                        /* out: position in internal
 
544
                                        representation of
 
545
                                        the clustered index */
 
546
        const dict_table_t*     table,  /* in: table */
 
547
        ulint                   n)      /* in: column number */
642
548
{
643
549
        return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
644
550
                                          n));
645
551
}
646
552
 
647
 
/********************************************************************//**
 
553
/************************************************************************
648
554
Checks if a column is in the ordering columns of the clustered index of a
649
 
table. Column prefixes are treated like whole columns.
650
 
@return TRUE if the column, or its prefix, is in the clustered key */
 
555
table. Column prefixes are treated like whole columns. */
651
556
UNIV_INTERN
652
557
ibool
653
558
dict_table_col_in_clustered_key(
654
559
/*============================*/
655
 
        const dict_table_t*     table,  /*!< in: table */
656
 
        ulint                   n)      /*!< in: column number */
 
560
                                        /* out: TRUE if the column, or its
 
561
                                        prefix, is in the clustered key */
 
562
        const dict_table_t*     table,  /* in: table */
 
563
        ulint                   n)      /* in: column number */
657
564
{
658
565
        const dict_index_t*     index;
659
566
        const dict_field_t*     field;
681
588
        return(FALSE);
682
589
}
683
590
 
684
 
/**********************************************************************//**
 
591
/**************************************************************************
685
592
Inits the data dictionary module. */
686
593
UNIV_INTERN
687
594
void
688
595
dict_init(void)
689
596
/*===========*/
690
597
{
691
 
        int     i;
692
 
 
693
 
        dict_sys = static_cast<dict_sys_t *>(mem_alloc(sizeof(dict_sys_t)));
694
 
 
695
 
        mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
 
598
        dict_sys = mem_alloc(sizeof(dict_sys_t));
 
599
 
 
600
        mutex_create(&dict_sys->mutex, SYNC_DICT);
696
601
 
697
602
        dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
698
603
                                           / (DICT_POOL_PER_TABLE_HASH
704
609
 
705
610
        UT_LIST_INIT(dict_sys->table_LRU);
706
611
 
707
 
        rw_lock_create(dict_operation_lock_key,
708
 
                       &dict_operation_lock, SYNC_DICT_OPERATION);
 
612
        rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
709
613
 
710
614
        dict_foreign_err_file = os_file_create_tmpfile();
711
615
        ut_a(dict_foreign_err_file);
712
616
 
713
 
        mutex_create(dict_foreign_err_mutex_key,
714
 
                     &dict_foreign_err_mutex, SYNC_ANY_LATCH);
715
 
 
716
 
        for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
717
 
                rw_lock_create(PFS_NOT_INSTRUMENTED,
718
 
                               &dict_table_stats_latches[i], SYNC_INDEX_TREE);
719
 
        }
 
617
        mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
720
618
}
721
619
 
722
 
/**********************************************************************//**
 
620
/**************************************************************************
723
621
Returns a table object and optionally increment its MySQL open handle count.
724
622
NOTE! This is a high-level function to be used mainly from outside the
725
623
'dict' directory. Inside this directory dict_table_get_low is usually the
726
 
appropriate function.
727
 
@return table, NULL if does not exist */
 
624
appropriate function. */
728
625
UNIV_INTERN
729
626
dict_table_t*
730
627
dict_table_get(
731
628
/*===========*/
732
 
        const char*     table_name,     /*!< in: table name */
733
 
        ibool           inc_mysql_count)/*!< in: whether to increment the open
 
629
                                        /* out: table, NULL if
 
630
                                        does not exist */
 
631
        const char*     table_name,     /* in: table name */
 
632
        ibool           inc_mysql_count)
 
633
                                        /* in: whether to increment the open
734
634
                                        handle count on the table */
735
635
{
736
636
        dict_table_t*   table;
746
646
        mutex_exit(&(dict_sys->mutex));
747
647
 
748
648
        if (table != NULL) {
749
 
                /* If table->ibd_file_missing == TRUE, this will
750
 
                print an error message and return without doing
751
 
                anything. */
752
 
                dict_update_statistics(table, TRUE /* only update stats
753
 
                                       if they have not been initialized */);
 
649
                if (!table->stat_initialized) {
 
650
                        /* If table->ibd_file_missing == TRUE, this will
 
651
                        print an error message and return without doing
 
652
                        anything. */
 
653
                        dict_update_statistics(table);
 
654
                }
754
655
        }
755
656
 
756
657
        return(table);
757
658
}
758
 
#endif /* !UNIV_HOTBACKUP */
759
659
 
760
 
/**********************************************************************//**
 
660
/**************************************************************************
761
661
Adds system columns to a table object. */
762
662
UNIV_INTERN
763
663
void
764
664
dict_table_add_system_columns(
765
665
/*==========================*/
766
 
        dict_table_t*   table,  /*!< in/out: table */
767
 
        mem_heap_t*     heap)   /*!< in: temporary heap */
 
666
        dict_table_t*   table,  /* in/out: table */
 
667
        mem_heap_t*     heap)   /* in: temporary heap */
768
668
{
769
669
        ut_ad(table);
770
670
        ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
803
703
#endif
804
704
}
805
705
 
806
 
#ifndef UNIV_HOTBACKUP
807
 
/**********************************************************************//**
 
706
/**************************************************************************
808
707
Adds a table object to the dictionary cache. */
809
708
UNIV_INTERN
810
709
void
811
710
dict_table_add_to_cache(
812
711
/*====================*/
813
 
        dict_table_t*   table,  /*!< in: table */
814
 
        mem_heap_t*     heap)   /*!< in: temporary heap */
 
712
        dict_table_t*   table,  /* in: table */
 
713
        mem_heap_t*     heap)   /* in: temporary heap */
815
714
{
816
715
        ulint   fold;
817
716
        ulint   id_fold;
828
727
        table->cached = TRUE;
829
728
 
830
729
        fold = ut_fold_string(table->name);
831
 
        id_fold = ut_fold_ull(table->id);
 
730
        id_fold = ut_fold_dulint(table->id);
832
731
 
833
732
        row_len = 0;
834
733
        for (i = 0; i < table->n_def; i++) {
852
751
        {
853
752
                dict_table_t*   table2;
854
753
                HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
855
 
                            dict_table_t*, table2, ut_ad(table2->cached),
856
 
                            ut_strcmp(table2->name, table->name) == 0);
 
754
                            dict_table_t*, table2,
 
755
                            (ut_strcmp(table2->name, table->name) == 0));
857
756
                ut_a(table2 == NULL);
858
 
 
859
 
#ifdef UNIV_DEBUG
860
 
                /* Look for the same table pointer with a different name */
861
 
                HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
862
 
                                dict_table_t*, table2, ut_ad(table2->cached),
863
 
                                table2 == table);
864
 
                ut_ad(table2 == NULL);
865
 
#endif /* UNIV_DEBUG */
866
757
        }
867
758
 
868
759
        /* Look for a table with the same id: error if such exists */
869
760
        {
870
761
                dict_table_t*   table2;
871
762
                HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
872
 
                            dict_table_t*, table2, ut_ad(table2->cached),
873
 
                            table2->id == table->id);
 
763
                            dict_table_t*, table2,
 
764
                            (ut_dulint_cmp(table2->id, table->id) == 0));
874
765
                ut_a(table2 == NULL);
875
 
 
876
 
#ifdef UNIV_DEBUG
877
 
                /* Look for the same table pointer with a different id */
878
 
                HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
879
 
                                dict_table_t*, table2, ut_ad(table2->cached),
880
 
                                table2 == table);
881
 
                ut_ad(table2 == NULL);
882
 
#endif /* UNIV_DEBUG */
883
766
        }
884
767
 
885
768
        /* Add table to hash table of tables */
892
775
        /* Add table to LRU list of tables */
893
776
        UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
894
777
 
895
 
        dict_sys->size += mem_heap_get_size(table->heap)
896
 
                + strlen(table->name) + 1;
 
778
        dict_sys->size += mem_heap_get_size(table->heap);
897
779
}
898
780
 
899
 
/**********************************************************************//**
 
781
/**************************************************************************
900
782
Looks for an index with the given id. NOTE that we do not reserve
901
783
the dictionary mutex: this function is for emergency purposes like
902
 
printing info of a corrupt database page!
903
 
@return index or NULL if not found from cache */
 
784
printing info of a corrupt database page! */
904
785
UNIV_INTERN
905
786
dict_index_t*
906
787
dict_index_find_on_id_low(
907
788
/*======================*/
908
 
        index_id_t      id)     /*!< in: index id */
 
789
                        /* out: index or NULL if not found from cache */
 
790
        dulint  id)     /* in: index id */
909
791
{
910
792
        dict_table_t*   table;
911
793
        dict_index_t*   index;
916
798
                index = dict_table_get_first_index(table);
917
799
 
918
800
                while (index) {
919
 
                        if (id == index->id) {
 
801
                        if (0 == ut_dulint_cmp(id, index->id)) {
920
802
                                /* Found */
921
803
 
922
804
                                return(index);
931
813
        return(NULL);
932
814
}
933
815
 
934
 
/**********************************************************************//**
935
 
Renames a table object.
936
 
@return TRUE if success */
 
816
/**************************************************************************
 
817
Renames a table object. */
937
818
UNIV_INTERN
938
819
ibool
939
820
dict_table_rename_in_cache(
940
821
/*=======================*/
941
 
        dict_table_t*   table,          /*!< in/out: table */
942
 
        const char*     new_name,       /*!< in: new name */
943
 
        ibool           rename_also_foreigns)/*!< in: in ALTER TABLE we want
 
822
                                        /* out: TRUE if success */
 
823
        dict_table_t*   table,          /* in/out: table */
 
824
        const char*     new_name,       /* in: new name */
 
825
        ibool           rename_also_foreigns)/* in: in ALTER TABLE we want
944
826
                                        to preserve the original table name
945
827
                                        in constraints which reference it */
946
828
{
947
829
        dict_foreign_t* foreign;
948
830
        dict_index_t*   index;
949
831
        ulint           fold;
950
 
        char            old_name[MAX_TABLE_NAME_LEN + 1];
 
832
        ulint           old_size;
 
833
        const char*     old_name;
951
834
 
952
835
        ut_ad(table);
953
836
        ut_ad(mutex_own(&(dict_sys->mutex)));
954
837
 
955
 
        /* store the old/current name to an automatic variable */
956
 
        if (strlen(table->name) + 1 <= sizeof(old_name)) {
957
 
                memcpy(old_name, table->name, strlen(table->name) + 1);
958
 
        } else {
959
 
                ut_print_timestamp(stderr);
960
 
                fprintf(stderr, "InnoDB: too long table name: '%s', "
961
 
                        "max length is %d\n", table->name,
962
 
                        MAX_TABLE_NAME_LEN);
963
 
                ut_error;
964
 
        }
 
838
        old_size = mem_heap_get_size(table->heap);
 
839
        old_name = table->name;
965
840
 
966
841
        fold = ut_fold_string(new_name);
967
842
 
969
844
        {
970
845
                dict_table_t*   table2;
971
846
                HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
972
 
                            dict_table_t*, table2, ut_ad(table2->cached),
 
847
                            dict_table_t*, table2,
973
848
                            (ut_strcmp(table2->name, new_name) == 0));
974
849
                if (UNIV_LIKELY_NULL(table2)) {
975
850
                        ut_print_timestamp(stderr);
1007
882
        /* Remove table from the hash tables of tables */
1008
883
        HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1009
884
                    ut_fold_string(old_name), table);
1010
 
 
1011
 
        if (strlen(new_name) > strlen(table->name)) {
1012
 
                /* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
1013
 
                memory fragmentation, we assume a repeated calls of
1014
 
                ut_realloc() with the same size do not cause fragmentation */
1015
 
                ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
1016
 
                table->name = static_cast<char *>(ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1));
1017
 
        }
1018
 
        memcpy(table->name, new_name, strlen(new_name) + 1);
 
885
        table->name = mem_heap_strdup(table->heap, new_name);
1019
886
 
1020
887
        /* Add table to hash table of tables */
1021
888
        HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1022
889
                    table);
1023
 
 
1024
 
        dict_sys->size += strlen(new_name) - strlen(old_name);
1025
 
        ut_a(dict_sys->size > 0);
 
890
        dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
1026
891
 
1027
892
        /* Update the table_name field in indexes */
1028
893
        index = dict_table_get_first_index(table);
1081
946
                        TODO: store buf len to save memory */
1082
947
 
1083
948
                        foreign->foreign_table_name
1084
 
                                = static_cast<char *>(mem_heap_alloc(foreign->heap,
1085
 
                                                 ut_strlen(table->name) + 1));
 
949
                                = mem_heap_alloc(foreign->heap,
 
950
                                                 ut_strlen(table->name) + 1);
1086
951
                }
1087
952
 
1088
953
                strcpy(foreign->foreign_table_name, table->name);
1105
970
                                /* This is a generated >= 4.0.18 format id */
1106
971
 
1107
972
                                if (strlen(table->name) > strlen(old_name)) {
1108
 
                                        foreign->id = static_cast<char *>(mem_heap_alloc(
 
973
                                        foreign->id = mem_heap_alloc(
1109
974
                                                foreign->heap,
1110
975
                                                strlen(table->name)
1111
 
                                                + strlen(old_id) + 1));
 
976
                                                + strlen(old_id) + 1);
1112
977
                                }
1113
978
 
1114
979
                                /* Replace the prefix 'databasename/tablename'
1124
989
                                if (dict_get_db_name_len(table->name)
1125
990
                                    > dict_get_db_name_len(foreign->id)) {
1126
991
 
1127
 
                                        foreign->id = static_cast<char *>(mem_heap_alloc(
 
992
                                        foreign->id = mem_heap_alloc(
1128
993
                                                foreign->heap,
1129
 
                                                db_len + strlen(old_id) + 1));
 
994
                                                db_len + strlen(old_id) + 1);
1130
995
                                }
1131
996
 
1132
997
                                /* Replace the database prefix in id with the
1152
1017
                        /* Allocate a longer name buffer;
1153
1018
                        TODO: store buf len to save memory */
1154
1019
 
1155
 
                        foreign->referenced_table_name = static_cast<char *>(mem_heap_alloc(
1156
 
                                foreign->heap, strlen(table->name) + 1));
 
1020
                        foreign->referenced_table_name = mem_heap_alloc(
 
1021
                                foreign->heap, strlen(table->name) + 1);
1157
1022
                }
1158
1023
 
1159
1024
                strcpy(foreign->referenced_table_name, table->name);
1164
1029
        return(TRUE);
1165
1030
}
1166
1031
 
1167
 
/**********************************************************************//**
 
1032
/**************************************************************************
1168
1033
Change the id of a table object in the dictionary cache. This is used in
1169
1034
DISCARD TABLESPACE. */
1170
1035
UNIV_INTERN
1171
1036
void
1172
1037
dict_table_change_id_in_cache(
1173
1038
/*==========================*/
1174
 
        dict_table_t*   table,  /*!< in/out: table object already in cache */
1175
 
        table_id_t      new_id) /*!< in: new id to set */
 
1039
        dict_table_t*   table,  /* in/out: table object already in cache */
 
1040
        dulint          new_id) /* in: new id to set */
1176
1041
{
1177
1042
        ut_ad(table);
1178
1043
        ut_ad(mutex_own(&(dict_sys->mutex)));
1181
1046
        /* Remove the table from the hash table of id's */
1182
1047
 
1183
1048
        HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1184
 
                    ut_fold_ull(table->id), table);
 
1049
                    ut_fold_dulint(table->id), table);
1185
1050
        table->id = new_id;
1186
1051
 
1187
1052
        /* Add the table back to the hash table */
1188
1053
        HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1189
 
                    ut_fold_ull(table->id), table);
 
1054
                    ut_fold_dulint(table->id), table);
1190
1055
}
1191
1056
 
1192
 
/**********************************************************************//**
 
1057
/**************************************************************************
1193
1058
Removes a table object from the dictionary cache. */
1194
1059
UNIV_INTERN
1195
1060
void
1196
1061
dict_table_remove_from_cache(
1197
1062
/*=========================*/
1198
 
        dict_table_t*   table)  /*!< in, own: table */
 
1063
        dict_table_t*   table)  /* in, own: table */
1199
1064
{
1200
1065
        dict_foreign_t* foreign;
1201
1066
        dict_index_t*   index;
1242
1107
        HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1243
1108
                    ut_fold_string(table->name), table);
1244
1109
        HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1245
 
                    ut_fold_ull(table->id), table);
 
1110
                    ut_fold_dulint(table->id), table);
1246
1111
 
1247
1112
        /* Remove table from LRU list of tables */
1248
1113
        UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1249
1114
 
1250
 
        size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
 
1115
        size = mem_heap_get_size(table->heap);
1251
1116
 
1252
1117
        ut_ad(dict_sys->size >= size);
1253
1118
 
1256
1121
        dict_mem_table_free(table);
1257
1122
}
1258
1123
 
1259
 
/****************************************************************//**
 
1124
/********************************************************************
1260
1125
If the given column name is reserved for InnoDB system columns, return
1261
 
TRUE.
1262
 
@return TRUE if name is reserved */
 
1126
TRUE. */
1263
1127
UNIV_INTERN
1264
1128
ibool
1265
1129
dict_col_name_is_reserved(
1266
1130
/*======================*/
1267
 
        const char*     name)   /*!< in: column name */
 
1131
                                /* out: TRUE if name is reserved */
 
1132
        const char*     name)   /* in: column name */
1268
1133
{
1269
1134
        /* This check reminds that if a new system column is added to
1270
1135
        the program, it should be dealt with here. */
1279
1144
        ulint                   i;
1280
1145
 
1281
1146
        for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1282
 
                if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
 
1147
                if (strcmp(name, reserved_names[i]) == 0) {
1283
1148
 
1284
1149
                        return(TRUE);
1285
1150
                }
1288
1153
        return(FALSE);
1289
1154
}
1290
1155
 
1291
 
/****************************************************************//**
 
1156
/********************************************************************
1292
1157
If an undo log record for this table might not fit on a single page,
1293
 
return TRUE.
1294
 
@return TRUE if the undo log record could become too big */
 
1158
return TRUE. */
1295
1159
static
1296
1160
ibool
1297
1161
dict_index_too_big_for_undo(
1298
1162
/*========================*/
1299
 
        const dict_table_t*     table,          /*!< in: table */
1300
 
        const dict_index_t*     new_index)      /*!< in: index */
 
1163
                                                /* out: TRUE if the undo log
 
1164
                                                record could become too big */
 
1165
        const dict_table_t*     table,          /* in: table */
 
1166
        const dict_index_t*     new_index)      /* in: index */
1301
1167
{
1302
1168
        /* Make sure that all column prefixes will fit in the undo log record
1303
1169
        in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1309
1175
                = TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
1310
1176
                + 2 /* next record pointer */
1311
1177
                + 1 /* type_cmpl */
1312
 
                + 11 /* trx->undo_no */ + 11 /* table->id */
 
1178
                + 11 /* trx->undo_no */ - 11 /* table->id */
1313
1179
                + 1 /* rec_get_info_bits() */
1314
1180
                + 11 /* DB_TRX_ID */
1315
1181
                + 11 /* DB_ROLL_PTR */
1347
1213
                ulint                   max_size
1348
1214
                        = dict_col_get_max_size(col);
1349
1215
                ulint                   fixed_size
1350
 
                        = dict_col_get_fixed_size(col,
1351
 
                                                  dict_table_is_comp(table));
 
1216
                        = dict_col_get_fixed_size(col);
1352
1217
 
1353
1218
                if (fixed_size) {
1354
1219
                        /* Fixed-size columns are stored locally. */
1390
1255
        return(undo_page_len >= UNIV_PAGE_SIZE);
1391
1256
}
1392
1257
 
1393
 
/****************************************************************//**
 
1258
/********************************************************************
1394
1259
If a record of this index might not fit on a single B-tree page,
1395
 
return TRUE.
1396
 
@return TRUE if the index record could become too big */
 
1260
return TRUE. */
1397
1261
static
1398
1262
ibool
1399
1263
dict_index_too_big_for_tree(
1400
1264
/*========================*/
1401
 
        const dict_table_t*     table,          /*!< in: table */
1402
 
        const dict_index_t*     new_index)      /*!< in: index */
 
1265
                                                /* out: TRUE if the index
 
1266
                                                record could become too big */
 
1267
        const dict_table_t*     table,          /* in: table */
 
1268
        const dict_index_t*     new_index)      /* in: index */
1403
1269
{
1404
1270
        ulint   zip_size;
1405
1271
        ulint   comp;
1477
1343
                case in rec_get_converted_size_comp() for
1478
1344
                REC_STATUS_ORDINARY records. */
1479
1345
 
1480
 
                field_max_size = dict_col_get_fixed_size(col, comp);
 
1346
                field_max_size = dict_col_get_fixed_size(col);
1481
1347
                if (field_max_size) {
1482
1348
                        /* dict_index_add_col() should guarantee this */
1483
1349
                        ut_ad(!field->prefix_len
1539
1405
        return(FALSE);
1540
1406
}
1541
1407
 
1542
 
/**********************************************************************//**
1543
 
Adds an index to the dictionary cache.
1544
 
@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
 
1408
/**************************************************************************
 
1409
Adds an index to the dictionary cache. */
1545
1410
UNIV_INTERN
1546
1411
ulint
1547
1412
dict_index_add_to_cache(
1548
1413
/*====================*/
1549
 
        dict_table_t*   table,  /*!< in: table on which the index is */
1550
 
        dict_index_t*   index,  /*!< in, own: index; NOTE! The index memory
 
1414
                                /* out: DB_SUCCESS or DB_TOO_BIG_RECORD */
 
1415
        dict_table_t*   table,  /* in: table on which the index is */
 
1416
        dict_index_t*   index,  /* in, own: index; NOTE! The index memory
1551
1417
                                object is freed in this function! */
1552
 
        ulint           page_no,/*!< in: root page number of the index */
1553
 
        ibool           strict) /*!< in: TRUE=refuse to create the index
 
1418
        ulint           page_no,/* in: root page number of the index */
 
1419
        ibool           strict) /* in: TRUE=refuse to create the index
1554
1420
                                if records could be too big to fit in
1555
1421
                                an B-tree page */
1556
1422
{
1567
1433
        ut_a(!dict_index_is_clust(index)
1568
1434
             || UT_LIST_GET_LEN(table->indexes) == 0);
1569
1435
 
1570
 
        if (!dict_index_find_cols(table, index)) {
1571
 
 
1572
 
                dict_mem_index_free(index);
1573
 
                return(DB_CORRUPTION);
1574
 
        }
 
1436
        dict_index_find_cols(table, index);
1575
1437
 
1576
1438
        /* Build the cache internal representation of the index,
1577
1439
        containing also the added system fields */
1641
1503
 
1642
1504
                if (field->prefix_len /* prefix index */
1643
1505
                    && !col->ord_part /* not yet ordering column */
1644
 
                    && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
 
1506
                    && !dict_col_get_fixed_size(col) /* variable-length */
1645
1507
                    && dict_col_get_max_size(col)
1646
1508
                    > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
1647
1509
 
1676
1538
        new_index->stat_n_leaf_pages = 1;
1677
1539
 
1678
1540
        new_index->page = page_no;
1679
 
        rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
1680
 
                       SYNC_INDEX_TREE);
 
1541
        rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1681
1542
 
1682
1543
        if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1683
1544
 
1684
 
                new_index->stat_n_diff_key_vals = static_cast<ib_int64_t *>(mem_heap_alloc(
 
1545
                new_index->stat_n_diff_key_vals = mem_heap_alloc(
1685
1546
                        new_index->heap,
1686
1547
                        (1 + dict_index_get_n_unique(new_index))
1687
 
                        * sizeof(ib_int64_t)));
 
1548
                        * sizeof(ib_int64_t));
1688
1549
                /* Give some sensible values to stat_n_... in case we do
1689
1550
                not calculate statistics quickly enough */
1690
1551
 
1701
1562
        return(DB_SUCCESS);
1702
1563
}
1703
1564
 
1704
 
/**********************************************************************//**
 
1565
/**************************************************************************
1705
1566
Removes an index from the dictionary cache. */
1706
1567
UNIV_INTERN
1707
1568
void
1708
1569
dict_index_remove_from_cache(
1709
1570
/*=========================*/
1710
 
        dict_table_t*   table,  /*!< in/out: table */
1711
 
        dict_index_t*   index)  /*!< in, own: index */
 
1571
        dict_table_t*   table,  /* in/out: table */
 
1572
        dict_index_t*   index)  /* in, own: index */
1712
1573
{
1713
1574
        ulint           size;
1714
1575
        ulint           retries = 0;
1778
1639
        dict_mem_index_free(index);
1779
1640
}
1780
1641
 
1781
 
/*******************************************************************//**
 
1642
/***********************************************************************
1782
1643
Tries to find column names for the index and sets the col field of the
1783
 
index.
1784
 
@return TRUE if the column names were found */
 
1644
index. */
1785
1645
static
1786
 
ibool
 
1646
void
1787
1647
dict_index_find_cols(
1788
1648
/*=================*/
1789
 
        dict_table_t*   table,  /*!< in: table */
1790
 
        dict_index_t*   index)  /*!< in: index */
 
1649
        dict_table_t*   table,  /* in: table */
 
1650
        dict_index_t*   index)  /* in: index */
1791
1651
{
1792
1652
        ulint           i;
1793
1653
 
1808
1668
                        }
1809
1669
                }
1810
1670
 
1811
 
#ifdef UNIV_DEBUG
1812
1671
                /* It is an error not to find a matching column. */
1813
 
                fputs("InnoDB: Error: no matching column for ", stderr);
1814
 
                ut_print_name(stderr, NULL, FALSE, field->name);
1815
 
                fputs(" in ", stderr);
1816
 
                dict_index_name_print(stderr, NULL, index);
1817
 
                fputs("!\n", stderr);
1818
 
#endif /* UNIV_DEBUG */
1819
 
                return(FALSE);
 
1672
                ut_error;
1820
1673
 
1821
1674
found:
1822
1675
                ;
1823
1676
        }
1824
 
 
1825
 
        return(TRUE);
1826
1677
}
1827
 
#endif /* !UNIV_HOTBACKUP */
1828
1678
 
1829
 
/*******************************************************************//**
 
1679
/***********************************************************************
1830
1680
Adds a column to index. */
1831
1681
UNIV_INTERN
1832
1682
void
1833
1683
dict_index_add_col(
1834
1684
/*===============*/
1835
 
        dict_index_t*           index,          /*!< in/out: index */
1836
 
        const dict_table_t*     table,          /*!< in: table */
1837
 
        dict_col_t*             col,            /*!< in: column */
1838
 
        ulint                   prefix_len)     /*!< in: column prefix length */
 
1685
        dict_index_t*           index,          /* in/out: index */
 
1686
        const dict_table_t*     table,          /* in: table */
 
1687
        dict_col_t*             col,            /* in: column */
 
1688
        ulint                   prefix_len)     /* in: column prefix length */
1839
1689
{
1840
1690
        dict_field_t*   field;
1841
1691
        const char*     col_name;
1847
1697
        field = dict_index_get_nth_field(index, index->n_def - 1);
1848
1698
 
1849
1699
        field->col = col;
1850
 
        field->fixed_len = (unsigned int) dict_col_get_fixed_size(
1851
 
                col, dict_table_is_comp(table));
 
1700
        field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1852
1701
 
1853
1702
        if (prefix_len && field->fixed_len > prefix_len) {
1854
1703
                field->fixed_len = (unsigned int) prefix_len;
1861
1710
        if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1862
1711
                field->fixed_len = 0;
1863
1712
        }
1864
 
#if DICT_MAX_INDEX_COL_LEN != 1024
 
1713
#if DICT_MAX_INDEX_COL_LEN != 768
1865
1714
        /* The comparison limit above must be constant.  If it were
1866
1715
        changed, the disk format of some fixed-length columns would
1867
1716
        change, which would be a disaster. */
1868
 
# error "DICT_MAX_INDEX_COL_LEN != 1024"
 
1717
# error "DICT_MAX_INDEX_COL_LEN != 768"
1869
1718
#endif
1870
1719
 
1871
1720
        if (!(col->prtype & DATA_NOT_NULL)) {
1873
1722
        }
1874
1723
}
1875
1724
 
1876
 
#ifndef UNIV_HOTBACKUP
1877
 
/*******************************************************************//**
 
1725
/***********************************************************************
1878
1726
Copies fields contained in index2 to index1. */
1879
1727
static
1880
1728
void
1881
1729
dict_index_copy(
1882
1730
/*============*/
1883
 
        dict_index_t*           index1, /*!< in: index to copy to */
1884
 
        dict_index_t*           index2, /*!< in: index to copy from */
1885
 
        const dict_table_t*     table,  /*!< in: table */
1886
 
        ulint                   start,  /*!< in: first position to copy */
1887
 
        ulint                   end)    /*!< in: last position to copy */
 
1731
        dict_index_t*           index1, /* in: index to copy to */
 
1732
        dict_index_t*           index2, /* in: index to copy from */
 
1733
        const dict_table_t*     table,  /* in: table */
 
1734
        ulint                   start,  /* in: first position to copy */
 
1735
        ulint                   end)    /* in: last position to copy */
1888
1736
{
1889
1737
        dict_field_t*   field;
1890
1738
        ulint           i;
1899
1747
        }
1900
1748
}
1901
1749
 
1902
 
/*******************************************************************//**
 
1750
/***********************************************************************
1903
1751
Copies types of fields contained in index to tuple. */
1904
1752
UNIV_INTERN
1905
1753
void
1906
1754
dict_index_copy_types(
1907
1755
/*==================*/
1908
 
        dtuple_t*               tuple,          /*!< in/out: data tuple */
1909
 
        const dict_index_t*     index,          /*!< in: index */
1910
 
        ulint                   n_fields)       /*!< in: number of
 
1756
        dtuple_t*               tuple,          /* in/out: data tuple */
 
1757
        const dict_index_t*     index,          /* in: index */
 
1758
        ulint                   n_fields)       /* in: number of
1911
1759
                                                field types to copy */
1912
1760
{
1913
1761
        ulint           i;
1928
1776
        }
1929
1777
}
1930
1778
 
1931
 
/*******************************************************************//**
 
1779
/***********************************************************************
1932
1780
Copies types of columns contained in table to tuple and sets all
1933
1781
fields of the tuple to the SQL NULL value.  This function should
1934
1782
be called right after dtuple_create(). */
1936
1784
void
1937
1785
dict_table_copy_types(
1938
1786
/*==================*/
1939
 
        dtuple_t*               tuple,  /*!< in/out: data tuple */
1940
 
        const dict_table_t*     table)  /*!< in: table */
 
1787
        dtuple_t*               tuple,  /* in/out: data tuple */
 
1788
        const dict_table_t*     table)  /* in: table */
1941
1789
{
1942
1790
        ulint           i;
1943
1791
 
1951
1799
        }
1952
1800
}
1953
1801
 
1954
 
/*******************************************************************//**
 
1802
/***********************************************************************
1955
1803
Builds the internal dictionary cache representation for a clustered
1956
 
index, containing also system fields not defined by the user.
1957
 
@return own: the internal representation of the clustered index */
 
1804
index, containing also system fields not defined by the user. */
1958
1805
static
1959
1806
dict_index_t*
1960
1807
dict_index_build_internal_clust(
1961
1808
/*============================*/
1962
 
        const dict_table_t*     table,  /*!< in: table */
1963
 
        dict_index_t*           index)  /*!< in: user representation of
 
1809
                                        /* out, own: the internal
 
1810
                                        representation of the clustered
 
1811
                                        index */
 
1812
        const dict_table_t*     table,  /* in: table */
 
1813
        dict_index_t*           index)  /* in: user representation of
1964
1814
                                        a clustered index */
1965
1815
{
1966
1816
        dict_index_t*   new_index;
2043
1893
                for (i = 0; i < trx_id_pos; i++) {
2044
1894
 
2045
1895
                        fixed_size = dict_col_get_fixed_size(
2046
 
                                dict_index_get_nth_col(new_index, i),
2047
 
                                dict_table_is_comp(table));
 
1896
                                dict_index_get_nth_col(new_index, i));
2048
1897
 
2049
1898
                        if (fixed_size == 0) {
2050
1899
                                new_index->trx_id_offset = 0;
2065
1914
        }
2066
1915
 
2067
1916
        /* Remember the table columns already contained in new_index */
2068
 
        void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
2069
 
        indexed = static_cast<unsigned long *>(indexed_ptr);
 
1917
        indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2070
1918
 
2071
1919
        /* Mark the table columns already contained in new_index */
2072
1920
        for (i = 0; i < new_index->n_def; i++) {
2104
1952
        return(new_index);
2105
1953
}
2106
1954
 
2107
 
/*******************************************************************//**
 
1955
/***********************************************************************
2108
1956
Builds the internal dictionary cache representation for a non-clustered
2109
 
index, containing also system fields not defined by the user.
2110
 
@return own: the internal representation of the non-clustered index */
 
1957
index, containing also system fields not defined by the user. */
2111
1958
static
2112
1959
dict_index_t*
2113
1960
dict_index_build_internal_non_clust(
2114
1961
/*================================*/
2115
 
        const dict_table_t*     table,  /*!< in: table */
2116
 
        dict_index_t*           index)  /*!< in: user representation of
 
1962
                                        /* out, own: the internal
 
1963
                                        representation of the non-clustered
 
1964
                                        index */
 
1965
        const dict_table_t*     table,  /* in: table */
 
1966
        dict_index_t*           index)  /* in: user representation of
2117
1967
                                        a non-clustered index */
2118
1968
{
2119
1969
        dict_field_t*   field;
2150
2000
        dict_index_copy(new_index, index, table, 0, index->n_fields);
2151
2001
 
2152
2002
        /* Remember the table columns already contained in new_index */
2153
 
        void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
2154
 
        indexed = static_cast<unsigned long *>(indexed_ptr);
 
2003
        indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2155
2004
 
2156
2005
        /* Mark the table columns already contained in new_index */
2157
2006
        for (i = 0; i < new_index->n_def; i++) {
2200
2049
 
2201
2050
/*====================== FOREIGN KEY PROCESSING ========================*/
2202
2051
 
2203
 
/*********************************************************************//**
2204
 
Checks if a table is referenced by foreign keys.
2205
 
@return TRUE if table is referenced by a foreign key */
 
2052
/*************************************************************************
 
2053
Checks if a table is referenced by foreign keys. */
2206
2054
UNIV_INTERN
2207
2055
ibool
2208
2056
dict_table_is_referenced_by_foreign_key(
2209
2057
/*====================================*/
2210
 
        const dict_table_t*     table)  /*!< in: InnoDB table */
 
2058
                                        /* out: TRUE if table is referenced
 
2059
                                        by a foreign key */
 
2060
        const dict_table_t*     table)  /* in: InnoDB table */
2211
2061
{
2212
2062
        return(UT_LIST_GET_LEN(table->referenced_list) > 0);
2213
2063
}
2214
2064
 
2215
 
/*********************************************************************//**
 
2065
/*************************************************************************
2216
2066
Check if the index is referenced by a foreign key, if TRUE return foreign
2217
 
else return NULL
2218
 
@return pointer to foreign key struct if index is defined for foreign
2219
 
key, otherwise NULL */
 
2067
else return NULL */
2220
2068
UNIV_INTERN
2221
2069
dict_foreign_t*
2222
2070
dict_table_get_referenced_constraint(
2223
2071
/*=================================*/
2224
 
        dict_table_t*   table,  /*!< in: InnoDB table */
2225
 
        dict_index_t*   index)  /*!< in: InnoDB index */
 
2072
                                /* out: pointer to foreign key struct if index
 
2073
                                is defined for foreign key, otherwise NULL */
 
2074
        dict_table_t*   table,  /* in: InnoDB table */
 
2075
        dict_index_t*   index)  /* in: InnoDB index */
2226
2076
{
2227
2077
        dict_foreign_t* foreign;
2228
2078
 
2242
2092
        return(NULL);
2243
2093
}
2244
2094
 
2245
 
/*********************************************************************//**
 
2095
/*************************************************************************
2246
2096
Checks if a index is defined for a foreign key constraint. Index is a part
2247
2097
of a foreign key constraint if the index is referenced by foreign key
2248
 
or index is a foreign key index.
2249
 
@return pointer to foreign key struct if index is defined for foreign
2250
 
key, otherwise NULL */
 
2098
or index is a foreign key index. */
2251
2099
UNIV_INTERN
2252
2100
dict_foreign_t*
2253
2101
dict_table_get_foreign_constraint(
2254
2102
/*==============================*/
2255
 
        dict_table_t*   table,  /*!< in: InnoDB table */
2256
 
        dict_index_t*   index)  /*!< in: InnoDB index */
 
2103
                                /* out: pointer to foreign key struct if index
 
2104
                                is defined for foreign key, otherwise NULL */
 
2105
        dict_table_t*   table,  /* in: InnoDB table */
 
2106
        dict_index_t*   index)  /* in: InnoDB index */
2257
2107
{
2258
2108
        dict_foreign_t* foreign;
2259
2109
 
2274
2124
        return(NULL);
2275
2125
}
2276
2126
 
2277
 
/*********************************************************************//**
 
2127
/*************************************************************************
2278
2128
Frees a foreign key struct. */
2279
2129
static
2280
2130
void
2281
2131
dict_foreign_free(
2282
2132
/*==============*/
2283
 
        dict_foreign_t* foreign)        /*!< in, own: foreign key struct */
 
2133
        dict_foreign_t* foreign)        /* in, own: foreign key struct */
2284
2134
{
2285
2135
        mem_heap_free(foreign->heap);
2286
2136
}
2287
2137
 
2288
 
/**********************************************************************//**
 
2138
/**************************************************************************
2289
2139
Removes a foreign constraint struct from the dictionary cache. */
2290
2140
static
2291
2141
void
2292
2142
dict_foreign_remove_from_cache(
2293
2143
/*===========================*/
2294
 
        dict_foreign_t* foreign)        /*!< in, own: foreign constraint */
 
2144
        dict_foreign_t* foreign)        /* in, own: foreign constraint */
2295
2145
{
2296
2146
        ut_ad(mutex_own(&(dict_sys->mutex)));
2297
2147
        ut_a(foreign);
2311
2161
        dict_foreign_free(foreign);
2312
2162
}
2313
2163
 
2314
 
/**********************************************************************//**
 
2164
#ifndef UNIV_HOTBACKUP
 
2165
/**************************************************************************
2315
2166
Looks for the foreign constraint from the foreign and referenced lists
2316
 
of a table.
2317
 
@return foreign constraint */
 
2167
of a table. */
2318
2168
static
2319
2169
dict_foreign_t*
2320
2170
dict_foreign_find(
2321
2171
/*==============*/
2322
 
        dict_table_t*   table,  /*!< in: table object */
2323
 
        const char*     id)     /*!< in: foreign constraint id */
 
2172
                                /* out: foreign constraint */
 
2173
        dict_table_t*   table,  /* in: table object */
 
2174
        const char*     id)     /* in: foreign constraint id */
2324
2175
{
2325
2176
        dict_foreign_t* foreign;
2326
2177
 
2351
2202
        return(NULL);
2352
2203
}
2353
2204
 
2354
 
/*********************************************************************//**
 
2205
/*************************************************************************
2355
2206
Tries to find an index whose first fields are the columns in the array,
2356
2207
in the same order and is not marked for deletion and is not the same
2357
 
as types_idx.
2358
 
@return matching index, NULL if not found */
 
2208
as types_idx. */
2359
2209
static
2360
2210
dict_index_t*
2361
2211
dict_foreign_find_index(
2362
2212
/*====================*/
2363
 
        dict_table_t*   table,  /*!< in: table */
2364
 
        const char**    columns,/*!< in: array of column names */
2365
 
        ulint           n_cols, /*!< in: number of columns */
2366
 
        dict_index_t*   types_idx, /*!< in: NULL or an index to whose types the
 
2213
                                /* out: matching index, NULL if not found */
 
2214
        dict_table_t*   table,  /* in: table */
 
2215
        const char**    columns,/* in: array of column names */
 
2216
        ulint           n_cols, /* in: number of columns */
 
2217
        dict_index_t*   types_idx, /* in: NULL or an index to whose types the
2367
2218
                                   column types must match */
2368
2219
        ibool           check_charsets,
2369
 
                                /*!< in: whether to check charsets.
 
2220
                                /* in: whether to check charsets.
2370
2221
                                only has an effect if types_idx != NULL */
2371
2222
        ulint           check_null)
2372
 
                                /*!< in: nonzero if none of the columns must
 
2223
                                /* in: nonzero if none of the columns must
2373
2224
                                be declared NOT NULL */
2374
2225
{
2375
2226
        dict_index_t*   index;
2437
2288
        return(NULL);
2438
2289
}
2439
2290
 
2440
 
/**********************************************************************//**
 
2291
/**************************************************************************
2441
2292
Find an index that is equivalent to the one passed in and is not marked
2442
 
for deletion.
2443
 
@return index equivalent to foreign->foreign_index, or NULL */
 
2293
for deletion. */
2444
2294
UNIV_INTERN
2445
2295
dict_index_t*
2446
2296
dict_foreign_find_equiv_index(
2447
2297
/*==========================*/
2448
 
        dict_foreign_t* foreign)/*!< in: foreign key */
 
2298
                                /* out: index equivalent to
 
2299
                                foreign->foreign_index, or NULL */
 
2300
        dict_foreign_t* foreign)/* in: foreign key */
2449
2301
{
2450
2302
        ut_a(foreign != NULL);
2451
2303
 
2460
2312
                       FALSE/* allow columns to be NULL */));
2461
2313
}
2462
2314
 
2463
 
/**********************************************************************//**
 
2315
/**************************************************************************
2464
2316
Returns an index object by matching on the name and column names and
2465
 
if more than one index matches return the index with the max id
2466
 
@return matching index, NULL if not found */
 
2317
if more than one index matches return the index with the max id */
2467
2318
UNIV_INTERN
2468
2319
dict_index_t*
2469
2320
dict_table_get_index_by_max_id(
2470
2321
/*===========================*/
2471
 
        dict_table_t*   table,  /*!< in: table */
2472
 
        const char*     name,   /*!< in: the index name to find */
2473
 
        const char**    columns,/*!< in: array of column names */
2474
 
        ulint           n_cols) /*!< in: number of columns */
 
2322
                                /* out: matching index, NULL if not found */
 
2323
        dict_table_t*   table,  /* in: table */
 
2324
        const char*     name,   /* in: the index name to find */
 
2325
        const char**    columns,/* in: array of column names */
 
2326
        ulint           n_cols) /* in: number of columns */
2475
2327
{
2476
2328
        dict_index_t*   index;
2477
2329
        dict_index_t*   found;
2506
2358
                                /* We found a matching index, select
2507
2359
                                the index with the higher id*/
2508
2360
 
2509
 
                                if (!found || index->id > found->id) {
 
2361
                                if (!found
 
2362
                                    || ut_dulint_cmp(index->id, found->id) > 0) {
2510
2363
 
2511
2364
                                        found = index;
2512
2365
                                }
2519
2372
        return(found);
2520
2373
}
2521
2374
 
2522
 
/**********************************************************************//**
 
2375
/**************************************************************************
2523
2376
Report an error in a foreign key definition. */
2524
2377
static
2525
2378
void
2526
2379
dict_foreign_error_report_low(
2527
2380
/*==========================*/
2528
 
        FILE*           file,   /*!< in: output stream */
2529
 
        const char*     name)   /*!< in: table name */
 
2381
        FILE*           file,   /* in: output stream */
 
2382
        const char*     name)   /* in: table name */
2530
2383
{
2531
2384
        rewind(file);
2532
2385
        ut_print_timestamp(file);
2534
2387
                name);
2535
2388
}
2536
2389
 
2537
 
/**********************************************************************//**
 
2390
/**************************************************************************
2538
2391
Report an error in a foreign key definition. */
2539
2392
static
2540
2393
void
2541
2394
dict_foreign_error_report(
2542
2395
/*======================*/
2543
 
        FILE*           file,   /*!< in: output stream */
2544
 
        dict_foreign_t* fk,     /*!< in: foreign key constraint */
2545
 
        const char*     msg)    /*!< in: the error message */
 
2396
        FILE*           file,   /* in: output stream */
 
2397
        dict_foreign_t* fk,     /* in: foreign key constraint */
 
2398
        const char*     msg)    /* in: the error message */
2546
2399
{
2547
2400
        mutex_enter(&dict_foreign_err_mutex);
2548
2401
        dict_foreign_error_report_low(file, fk->foreign_table_name);
2554
2407
                fputs("The index in the foreign key in table is ", file);
2555
2408
                ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2556
2409
                fputs("\n"
2557
 
                      "See " REFMAN "innodb-foreign-key-constraints.html\n"
 
2410
                      "See http://dev.mysql.com/doc/refman/5.1/en/"
 
2411
                      "innodb-foreign-key-constraints.html\n"
2558
2412
                      "for correct foreign key definition.\n",
2559
2413
                      file);
2560
2414
        }
2561
2415
        mutex_exit(&dict_foreign_err_mutex);
2562
2416
}
2563
2417
 
2564
 
/**********************************************************************//**
 
2418
/**************************************************************************
2565
2419
Adds a foreign key constraint object to the dictionary cache. May free
2566
2420
the object if there already is an object with the same identifier in.
2567
2421
At least one of the foreign table and the referenced table must already
2568
 
be in the dictionary cache!
2569
 
@return DB_SUCCESS or error code */
 
2422
be in the dictionary cache! */
2570
2423
UNIV_INTERN
2571
2424
ulint
2572
2425
dict_foreign_add_to_cache(
2573
2426
/*======================*/
2574
 
        dict_foreign_t* foreign,        /*!< in, own: foreign key constraint */
2575
 
        ibool           check_charsets) /*!< in: TRUE=check charset
 
2427
                                        /* out: DB_SUCCESS or error code */
 
2428
        dict_foreign_t* foreign,        /* in, own: foreign key constraint */
 
2429
        ibool           check_charsets) /* in: TRUE=check charset
2576
2430
                                        compatibility */
2577
2431
{
2578
2432
        dict_table_t*   for_table;
2684
2538
        return(DB_SUCCESS);
2685
2539
}
2686
2540
 
2687
 
/*********************************************************************//**
 
2541
/*************************************************************************
2688
2542
Scans from pointer onwards. Stops if is at the start of a copy of
2689
2543
'string' where characters are compared without case sensitivity, and
2690
 
only outside `` or "" quotes. Stops also at NUL.
2691
 
@return scanned up to this */
 
2544
only outside `` or "" quotes. Stops also at '\0'. */
2692
2545
static
2693
2546
const char*
2694
2547
dict_scan_to(
2695
2548
/*=========*/
2696
 
        const char*     ptr,    /*!< in: scan from */
2697
 
        const char*     string) /*!< in: look for this */
 
2549
                                /* out: scanned up to this */
 
2550
        const char*     ptr,    /* in: scan from */
 
2551
        const char*     string) /* in: look for this */
2698
2552
{
2699
2553
        char    quote   = '\0';
2700
2554
 
2727
2581
        return(ptr);
2728
2582
}
2729
2583
 
2730
 
/*********************************************************************//**
2731
 
Accepts a specified string. Comparisons are case-insensitive.
2732
 
@return if string was accepted, the pointer is moved after that, else
2733
 
ptr is returned */
 
2584
/*************************************************************************
 
2585
Accepts a specified string. Comparisons are case-insensitive. */
2734
2586
static
2735
2587
const char*
2736
2588
dict_accept(
2737
2589
/*========*/
2738
 
        const void*     cs,/*!< in: the character set of ptr */
2739
 
        const char*     ptr,    /*!< in: scan from this */
2740
 
        const char*     string, /*!< in: accept only this string as the next
 
2590
                                /* out: if string was accepted, the pointer
 
2591
                                is moved after that, else ptr is returned */
 
2592
        struct charset_info_st* cs,/* in: the character set of ptr */
 
2593
        const char*     ptr,    /* in: scan from this */
 
2594
        const char*     string, /* in: accept only this string as the next
2741
2595
                                non-whitespace string */
2742
 
        ibool*          success)/*!< out: TRUE if accepted */
 
2596
        ibool*          success)/* out: TRUE if accepted */
2743
2597
{
2744
2598
        const char*     old_ptr = ptr;
2745
2599
        const char*     old_ptr2;
2746
2600
 
2747
2601
        *success = FALSE;
2748
2602
 
2749
 
        while (innobase_isspace(cs, *ptr)) {
 
2603
        while (my_isspace(cs, *ptr)) {
2750
2604
                ptr++;
2751
2605
        }
2752
2606
 
2763
2617
        return(ptr + ut_strlen(string));
2764
2618
}
2765
2619
 
2766
 
/*********************************************************************//**
 
2620
/*************************************************************************
2767
2621
Scans an id. For the lexical definition of an 'id', see the code below.
2768
 
Strips backquotes or double quotes from around the id.
2769
 
@return scanned to */
 
2622
Strips backquotes or double quotes from around the id. */
2770
2623
static
2771
2624
const char*
2772
2625
dict_scan_id(
2773
2626
/*=========*/
2774
 
        const void*     cs,/*!< in: the character set of ptr */
2775
 
        const char*     ptr,    /*!< in: scanned to */
2776
 
        mem_heap_t*     heap,   /*!< in: heap where to allocate the id
 
2627
                                /* out: scanned to */
 
2628
        struct charset_info_st* cs,/* in: the character set of ptr */
 
2629
        const char*     ptr,    /* in: scanned to */
 
2630
        mem_heap_t*     heap,   /* in: heap where to allocate the id
2777
2631
                                (NULL=id will not be allocated, but it
2778
2632
                                will point to string near ptr) */
2779
 
        const char**    id,     /*!< out,own: the id; NULL if no id was
 
2633
        const char**    id,     /* out,own: the id; NULL if no id was
2780
2634
                                scannable */
2781
 
        ibool           table_id,/*!< in: TRUE=convert the allocated id
 
2635
        ibool           table_id,/* in: TRUE=convert the allocated id
2782
2636
                                as a table name; FALSE=convert to UTF-8 */
2783
2637
        ibool           accept_also_dot)
2784
 
                                /*!< in: TRUE if also a dot can appear in a
 
2638
                                /* in: TRUE if also a dot can appear in a
2785
2639
                                non-quoted id; in a quoted id it can appear
2786
2640
                                always */
2787
2641
{
2793
2647
 
2794
2648
        *id = NULL;
2795
2649
 
2796
 
        while (innobase_isspace(cs, *ptr)) {
 
2650
        while (my_isspace(cs, *ptr)) {
2797
2651
                ptr++;
2798
2652
        }
2799
2653
 
2824
2678
                        len++;
2825
2679
                }
2826
2680
        } else {
2827
 
                while (!innobase_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
 
2681
                while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2828
2682
                       && (accept_also_dot || *ptr != '.')
2829
2683
                       && *ptr != ',' && *ptr != '\0') {
2830
2684
 
2842
2696
 
2843
2697
        if (quote) {
2844
2698
                char*   d;
2845
 
                str = d = static_cast<char *>(mem_heap_alloc(heap, len + 1));
 
2699
                str = d = mem_heap_alloc(heap, len + 1);
2846
2700
                while (len--) {
2847
2701
                        if ((*d++ = *s++) == quote) {
2848
2702
                                s++;
2861
2715
                /* Convert the identifier from connection character set
2862
2716
                to UTF-8. */
2863
2717
                len = 3 * len + 1;
2864
 
                *id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
 
2718
                *id = dst = mem_heap_alloc(heap, len);
2865
2719
 
2866
2720
                innobase_convert_from_id(cs, dst, str, len);
2867
 
        } else if (!strncmp(str, srv_mysql50_table_name_prefix.c_str(),
2868
 
                            srv_mysql50_table_name_prefix.size())) {
 
2721
        } else if (!strncmp(str, srv_mysql50_table_name_prefix,
 
2722
                            sizeof srv_mysql50_table_name_prefix)) {
2869
2723
                /* This is a pre-5.1 table name
2870
2724
                containing chars other than [A-Za-z0-9].
2871
2725
                Discard the prefix and use raw UTF-8 encoding. */
2872
 
                str += srv_mysql50_table_name_prefix.size();
2873
 
                len -= srv_mysql50_table_name_prefix.size();
 
2726
                str += sizeof srv_mysql50_table_name_prefix;
 
2727
                len -= sizeof srv_mysql50_table_name_prefix;
2874
2728
                goto convert_id;
2875
2729
        } else {
2876
2730
                /* Encode using filename-safe characters. */
2877
2731
                len = 5 * len + 1;
2878
 
                *id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
 
2732
                *id = dst = mem_heap_alloc(heap, len);
2879
2733
 
2880
2734
                innobase_convert_from_table_id(cs, dst, str, len);
2881
2735
        }
2883
2737
        return(ptr);
2884
2738
}
2885
2739
 
2886
 
/*********************************************************************//**
2887
 
Tries to scan a column name.
2888
 
@return scanned to */
 
2740
/*************************************************************************
 
2741
Tries to scan a column name. */
2889
2742
static
2890
2743
const char*
2891
2744
dict_scan_col(
2892
2745
/*==========*/
2893
 
        const void*     cs,     /*!< in: the character set of ptr */
2894
 
        const char*             ptr,    /*!< in: scanned to */
2895
 
        ibool*                  success,/*!< out: TRUE if success */
2896
 
        dict_table_t*           table,  /*!< in: table in which the column is */
2897
 
        const dict_col_t**      column, /*!< out: pointer to column if success */
2898
 
        mem_heap_t*             heap,   /*!< in: heap where to allocate */
2899
 
        const char**            name)   /*!< out,own: the column name;
 
2746
                                        /* out: scanned to */
 
2747
        struct charset_info_st* cs,     /* in: the character set of ptr */
 
2748
        const char*             ptr,    /* in: scanned to */
 
2749
        ibool*                  success,/* out: TRUE if success */
 
2750
        dict_table_t*           table,  /* in: table in which the column is */
 
2751
        const dict_col_t**      column, /* out: pointer to column if success */
 
2752
        mem_heap_t*             heap,   /* in: heap where to allocate */
 
2753
        const char**            name)   /* out,own: the column name;
2900
2754
                                        NULL if no name was scannable */
2901
2755
{
2902
2756
        ulint           i;
2934
2788
        return(ptr);
2935
2789
}
2936
2790
 
2937
 
/*********************************************************************//**
2938
 
Scans a table name from an SQL string.
2939
 
@return scanned to */
 
2791
/*************************************************************************
 
2792
Scans a table name from an SQL string. */
2940
2793
static
2941
2794
const char*
2942
2795
dict_scan_table_name(
2943
2796
/*=================*/
2944
 
        const void*     cs,/*!< in: the character set of ptr */
2945
 
        const char*     ptr,    /*!< in: scanned to */
2946
 
        dict_table_t**  table,  /*!< out: table object or NULL */
2947
 
        const char*     name,   /*!< in: foreign key table name */
2948
 
        ibool*          success,/*!< out: TRUE if ok name found */
2949
 
        mem_heap_t*     heap,   /*!< in: heap where to allocate the id */
2950
 
        const char**    ref_name)/*!< out,own: the table name;
 
2797
                                /* out: scanned to */
 
2798
        struct charset_info_st* cs,/* in: the character set of ptr */
 
2799
        const char*     ptr,    /* in: scanned to */
 
2800
        dict_table_t**  table,  /* out: table object or NULL */
 
2801
        const char*     name,   /* in: foreign key table name */
 
2802
        ibool*          success,/* out: TRUE if ok name found */
 
2803
        mem_heap_t*     heap,   /* in: heap where to allocate the id */
 
2804
        const char**    ref_name)/* out,own: the table name;
2951
2805
                                NULL if no name was scannable */
2952
2806
{
2953
2807
        const char*     database_name   = NULL;
3013
2867
        table_name_len = strlen(table_name);
3014
2868
 
3015
2869
        /* Copy database_name, '/', table_name, '\0' */
3016
 
        ref = static_cast<char *>(mem_heap_alloc(heap, database_name_len + table_name_len + 2));
 
2870
        ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
3017
2871
        memcpy(ref, database_name, database_name_len);
3018
2872
        ref[database_name_len] = '/';
3019
2873
        memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3033
2887
        return(ptr);
3034
2888
}
3035
2889
 
3036
 
/*********************************************************************//**
3037
 
Skips one id. The id is allowed to contain also '.'.
3038
 
@return scanned to */
 
2890
/*************************************************************************
 
2891
Skips one id. The id is allowed to contain also '.'. */
3039
2892
static
3040
2893
const char*
3041
2894
dict_skip_word(
3042
2895
/*===========*/
3043
 
        const void*     cs,/*!< in: the character set of ptr */
3044
 
        const char*     ptr,    /*!< in: scanned to */
3045
 
        ibool*          success)/*!< out: TRUE if success, FALSE if just spaces
 
2896
                                /* out: scanned to */
 
2897
        struct charset_info_st* cs,/* in: the character set of ptr */
 
2898
        const char*     ptr,    /* in: scanned to */
 
2899
        ibool*          success)/* out: TRUE if success, FALSE if just spaces
3046
2900
                                left in string or a syntax error */
3047
2901
{
3048
2902
        const char*     start;
3058
2912
        return(ptr);
3059
2913
}
3060
2914
 
3061
 
/*********************************************************************//**
 
2915
/*************************************************************************
3062
2916
Removes MySQL comments from an SQL string. A comment is either
3063
2917
(a) '#' to the end of the line,
3064
 
(b) '--[space]' to the end of the line, or
3065
 
(c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
3066
 
C comment syntax).
3067
 
@return own: SQL string stripped from comments; the caller must free
3068
 
this with mem_free()! */
 
2918
(b) '--<space>' to the end of the line, or
 
2919
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
 
2920
C comment syntax). */
3069
2921
static
3070
2922
char*
3071
2923
dict_strip_comments(
3072
2924
/*================*/
3073
 
        const char*     sql_string,     /*!< in: SQL string */
3074
 
        size_t          sql_length)     /*!< in: length of sql_string */
 
2925
                                        /* out, own: SQL string stripped from
 
2926
                                        comments; the caller must free this
 
2927
                                        with mem_free()! */
 
2928
        const char*     sql_string)     /* in: SQL string */
3075
2929
{
3076
2930
        char*           str;
3077
2931
        const char*     sptr;
3078
 
        const char*     eptr    = sql_string + sql_length;
3079
2932
        char*           ptr;
3080
2933
        /* unclosed quote character (0 if none) */
3081
2934
        char            quote   = 0;
3082
2935
 
3083
 
        str = static_cast<char *>(mem_alloc(sql_length + 1));
 
2936
        str = mem_alloc(strlen(sql_string) + 1);
3084
2937
 
3085
2938
        sptr = sql_string;
3086
2939
        ptr = str;
3087
2940
 
3088
2941
        for (;;) {
3089
2942
scan_more:
3090
 
                if (sptr >= eptr || *sptr == '\0') {
3091
 
end_of_string:
 
2943
                if (*sptr == '\0') {
3092
2944
                        *ptr = '\0';
3093
2945
 
3094
 
                        ut_a(ptr <= str + sql_length);
 
2946
                        ut_a(ptr <= str + strlen(sql_string));
3095
2947
 
3096
2948
                        return(str);
3097
2949
                }
3103
2955
                } else if (quote) {
3104
2956
                        /* Within quotes: do not look for
3105
2957
                        starting quotes or comments. */
3106
 
                } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
 
2958
                } else if (*sptr == '"' || *sptr == '`') {
3107
2959
                        /* Starting quote: remember the quote character. */
3108
2960
                        quote = *sptr;
3109
2961
                } else if (*sptr == '#'
3110
2962
                           || (sptr[0] == '-' && sptr[1] == '-'
3111
2963
                               && sptr[2] == ' ')) {
3112
2964
                        for (;;) {
3113
 
                                if (++sptr >= eptr) {
3114
 
                                        goto end_of_string;
3115
 
                                }
3116
 
 
3117
2965
                                /* In Unix a newline is 0x0A while in Windows
3118
2966
                                it is 0x0D followed by 0x0A */
3119
2967
 
3120
 
                                switch (*sptr) {
3121
 
                                case (char) 0X0A:
3122
 
                                case (char) 0x0D:
3123
 
                                case '\0':
 
2968
                                if (*sptr == (char)0x0A
 
2969
                                    || *sptr == (char)0x0D
 
2970
                                    || *sptr == '\0') {
 
2971
 
3124
2972
                                        goto scan_more;
3125
2973
                                }
 
2974
 
 
2975
                                sptr++;
3126
2976
                        }
3127
2977
                } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3128
 
                        sptr += 2;
3129
2978
                        for (;;) {
3130
 
                                if (sptr >= eptr) {
3131
 
                                        goto end_of_string;
 
2979
                                if (*sptr == '*' && *(sptr + 1) == '/') {
 
2980
 
 
2981
                                        sptr += 2;
 
2982
 
 
2983
                                        goto scan_more;
3132
2984
                                }
3133
2985
 
3134
 
                                switch (*sptr) {
3135
 
                                case '\0':
 
2986
                                if (*sptr == '\0') {
 
2987
 
3136
2988
                                        goto scan_more;
3137
 
                                case '*':
3138
 
                                        if (sptr[1] == '/') {
3139
 
                                                sptr += 2;
3140
 
                                                goto scan_more;
3141
 
                                        }
3142
2989
                                }
3143
2990
 
3144
2991
                                sptr++;
3152
2999
        }
3153
3000
}
3154
3001
 
3155
 
/*********************************************************************//**
3156
 
Finds the highest [number] for foreign key constraints of the table. Looks
 
3002
/*************************************************************************
 
3003
Finds the highest <number> for foreign key constraints of the table. Looks
3157
3004
only at the >= 4.0.18-format id's, which are of the form
3158
 
databasename/tablename_ibfk_[number].
3159
 
@return highest number, 0 if table has no new format foreign key constraints */
 
3005
databasename/tablename_ibfk_<number>. */
3160
3006
static
3161
3007
ulint
3162
3008
dict_table_get_highest_foreign_id(
3163
3009
/*==============================*/
3164
 
        dict_table_t*   table)  /*!< in: table in the dictionary memory cache */
 
3010
                                /* out: highest number, 0 if table has no new
 
3011
                                format foreign key constraints */
 
3012
        dict_table_t*   table)  /* in: table in the dictionary memory cache */
3165
3013
{
3166
3014
        dict_foreign_t* foreign;
3167
3015
        char*           endp;
3200
3048
        return(biggest_id);
3201
3049
}
3202
3050
 
3203
 
/*********************************************************************//**
 
3051
/*************************************************************************
3204
3052
Reports a simple foreign key create clause syntax error. */
3205
3053
static
3206
3054
void
3207
3055
dict_foreign_report_syntax_err(
3208
3056
/*===========================*/
3209
 
        const char*     name,           /*!< in: table name */
 
3057
        const char*     name,           /* in: table name */
3210
3058
        const char*     start_of_latest_foreign,
3211
 
                                        /*!< in: start of the foreign key clause
 
3059
                                        /* in: start of the foreign key clause
3212
3060
                                        in the SQL string */
3213
 
        const char*     ptr)            /*!< in: place of the syntax error */
 
3061
        const char*     ptr)            /* in: place of the syntax error */
3214
3062
{
3215
3063
        FILE*   ef = dict_foreign_err_file;
3216
3064
 
3221
3069
        mutex_exit(&dict_foreign_err_mutex);
3222
3070
}
3223
3071
 
3224
 
/*********************************************************************//**
 
3072
/*************************************************************************
3225
3073
Scans a table create SQL string and adds to the data dictionary the foreign
3226
3074
key constraints declared in the string. This function should be called after
3227
3075
the indexes for a table have been created. Each foreign key constraint must
3228
3076
be accompanied with indexes in both participating tables. The indexes are
3229
 
allowed to contain more fields than mentioned in the constraint.
3230
 
@return error code or DB_SUCCESS */
 
3077
allowed to contain more fields than mentioned in the constraint. */
3231
3078
static
3232
3079
ulint
3233
3080
dict_create_foreign_constraints_low(
3234
3081
/*================================*/
3235
 
        trx_t*          trx,    /*!< in: transaction */
3236
 
        mem_heap_t*     heap,   /*!< in: memory heap */
3237
 
        const void*     cs,/*!< in: the character set of sql_string */
 
3082
                                /* out: error code or DB_SUCCESS */
 
3083
        trx_t*          trx,    /* in: transaction */
 
3084
        mem_heap_t*     heap,   /* in: memory heap */
 
3085
        struct charset_info_st* cs,/* in: the character set of sql_string */
3238
3086
        const char*     sql_string,
3239
 
                                /*!< in: CREATE TABLE or ALTER TABLE statement
 
3087
                                /* in: CREATE TABLE or ALTER TABLE statement
3240
3088
                                where foreign keys are declared like:
3241
3089
                                FOREIGN KEY (a, b) REFERENCES table2(c, d),
3242
3090
                                table2 can be written also with the database
3243
3091
                                name before it: test.table2; the default
3244
3092
                                database is the database of parameter name */
3245
 
        const char*     name,   /*!< in: table full name in the normalized form
 
3093
        const char*     name,   /* in: table full name in the normalized form
3246
3094
                                database_name/table_name */
3247
3095
        ibool           reject_fks)
3248
 
                                /*!< in: if TRUE, fail with error code
 
3096
                                /* in: if TRUE, fail with error code
3249
3097
                                DB_CANNOT_ADD_CONSTRAINT if any foreign
3250
3098
                                keys are found. */
3251
3099
{
3319
3167
        }
3320
3168
 
3321
3169
        /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
3322
 
        format databasename/tablename_ibfk_[number], where [number] is local
3323
 
        to the table; look for the highest [number] for table_to_alter, so
 
3170
        format databasename/tablename_ibfk_<number>, where <number> is local
 
3171
        to the table; look for the highest <number> for table_to_alter, so
3324
3172
        that we can assign to new constraints higher numbers. */
3325
3173
 
3326
3174
        /* If we are altering a temporary table, the table name after ALTER
3353
3201
 
3354
3202
                ut_a(success);
3355
3203
 
3356
 
                if (!innobase_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
 
3204
                if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
3357
3205
                        goto loop;
3358
3206
                }
3359
3207
 
3360
 
                while (innobase_isspace(cs, *ptr)) {
 
3208
                while (my_isspace(cs, *ptr)) {
3361
3209
                        ptr++;
3362
3210
                }
3363
3211
 
3400
3248
                goto loop;
3401
3249
        }
3402
3250
 
3403
 
        if (!innobase_isspace(cs, *ptr)) {
 
3251
        if (!my_isspace(cs, *ptr)) {
3404
3252
                goto loop;
3405
3253
        }
3406
3254
 
3480
3328
                ut_print_name(ef, NULL, TRUE, name);
3481
3329
                fprintf(ef, " where the columns appear\n"
3482
3330
                        "as the first columns. Constraint:\n%s\n"
3483
 
                        "See " REFMAN "innodb-foreign-key-constraints.html\n"
 
3331
                        "See http://dev.mysql.com/doc/refman/5.1/en/"
 
3332
                        "innodb-foreign-key-constraints.html\n"
3484
3333
                        "for correct foreign key definition.\n",
3485
3334
                        start_of_latest_foreign);
3486
3335
                mutex_exit(&dict_foreign_err_mutex);
3487
3336
 
3488
 
                return(DB_CHILD_NO_INDEX);
 
3337
                return(DB_CANNOT_ADD_CONSTRAINT);
3489
3338
        }
3490
3339
        ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3491
3340
 
3492
 
        if (!success || !innobase_isspace(cs, *ptr)) {
 
3341
        if (!success || !my_isspace(cs, *ptr)) {
3493
3342
                dict_foreign_report_syntax_err(
3494
3343
                        name, start_of_latest_foreign, ptr);
3495
3344
                return(DB_CANNOT_ADD_CONSTRAINT);
3509
3358
 
3510
3359
                db_len = dict_get_db_name_len(table->name);
3511
3360
 
3512
 
                foreign->id = static_cast<char*>(mem_heap_alloc(
3513
 
                        foreign->heap, db_len + strlen(constraint_name) + 2));
 
3361
                foreign->id = mem_heap_alloc(
 
3362
                        foreign->heap, db_len + strlen(constraint_name) + 2);
3514
3363
 
3515
3364
                ut_memcpy(foreign->id, table->name, db_len);
3516
3365
                foreign->id[db_len] = '/';
3522
3371
                                                      table->name);
3523
3372
        foreign->foreign_index = index;
3524
3373
        foreign->n_fields = (unsigned int) i;
3525
 
        foreign->foreign_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
3526
 
                                                    i * sizeof(void*)));
 
3374
        foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
 
3375
                                                    i * sizeof(void*));
3527
3376
        for (i = 0; i < foreign->n_fields; i++) {
3528
3377
                foreign->foreign_col_names[i] = mem_heap_strdup(
3529
3378
                        foreign->heap,
3760
3609
                                " and such columns in old tables\n"
3761
3610
                                "cannot be referenced by such columns"
3762
3611
                                " in new tables.\n"
3763
 
                                "See " REFMAN
 
3612
                                "See http://dev.mysql.com/doc/refman/5.1/en/"
3764
3613
                                "innodb-foreign-key-constraints.html\n"
3765
3614
                                "for correct foreign key definition.\n",
3766
3615
                                start_of_latest_foreign);
3767
3616
                        mutex_exit(&dict_foreign_err_mutex);
3768
3617
 
3769
 
                        return(DB_PARENT_NO_INDEX);
 
3618
                        return(DB_CANNOT_ADD_CONSTRAINT);
3770
3619
                }
3771
3620
        } else {
3772
3621
                ut_a(trx->check_foreigns == FALSE);
3779
3628
        foreign->referenced_table_name
3780
3629
                = mem_heap_strdup(foreign->heap, referenced_table_name);
3781
3630
 
3782
 
        foreign->referenced_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
3783
 
                                                       i * sizeof(void*)));
 
3631
        foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
 
3632
                                                       i * sizeof(void*));
3784
3633
        for (i = 0; i < foreign->n_fields; i++) {
3785
3634
                foreign->referenced_col_names[i]
3786
3635
                        = mem_heap_strdup(foreign->heap, column_names[i]);
3799
3648
        goto loop;
3800
3649
}
3801
3650
 
3802
 
/*********************************************************************//**
 
3651
/*************************************************************************
3803
3652
Scans a table create SQL string and adds to the data dictionary the foreign
3804
3653
key constraints declared in the string. This function should be called after
3805
3654
the indexes for a table have been created. Each foreign key constraint must
3806
3655
be accompanied with indexes in both participating tables. The indexes are
3807
 
allowed to contain more fields than mentioned in the constraint.
3808
 
@return error code or DB_SUCCESS */
 
3656
allowed to contain more fields than mentioned in the constraint. */
3809
3657
UNIV_INTERN
3810
3658
ulint
3811
3659
dict_create_foreign_constraints(
3812
3660
/*============================*/
3813
 
        trx_t*          trx,            /*!< in: transaction */
3814
 
        const char*     sql_string,     /*!< in: table create statement where
 
3661
                                        /* out: error code or DB_SUCCESS */
 
3662
        trx_t*          trx,            /* in: transaction */
 
3663
        const char*     sql_string,     /* in: table create statement where
3815
3664
                                        foreign keys are declared like:
3816
3665
                                        FOREIGN KEY (a, b) REFERENCES
3817
3666
                                        table2(c, d), table2 can be written
3819
3668
                                        name before it: test.table2; the
3820
3669
                                        default database id the database of
3821
3670
                                        parameter name */
3822
 
        size_t          sql_length,     /*!< in: length of sql_string */
3823
 
        const char*     name,           /*!< in: table full name in the
 
3671
        const char*     name,           /* in: table full name in the
3824
3672
                                        normalized form
3825
3673
                                        database_name/table_name */
3826
 
        ibool           reject_fks)     /*!< in: if TRUE, fail with error
 
3674
        ibool           reject_fks)     /* in: if TRUE, fail with error
3827
3675
                                        code DB_CANNOT_ADD_CONSTRAINT if
3828
3676
                                        any foreign keys are found. */
3829
3677
{
3834
3682
        ut_a(trx);
3835
3683
        ut_a(trx->mysql_thd);
3836
3684
 
3837
 
        str = dict_strip_comments(sql_string, sql_length);
 
3685
        str = dict_strip_comments(sql_string);
3838
3686
        heap = mem_heap_create(10000);
3839
3687
 
3840
3688
        err = dict_create_foreign_constraints_low(
3841
 
                trx, heap, trx->session()->charset(), str, name,
 
3689
                trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3842
3690
                reject_fks);
3843
3691
 
3844
3692
        mem_heap_free(heap);
3847
3695
        return(err);
3848
3696
}
3849
3697
 
3850
 
/**********************************************************************//**
3851
 
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
3852
 
@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
3853
 
constraint id does not match */
 
3698
/**************************************************************************
 
3699
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3854
3700
UNIV_INTERN
3855
3701
ulint
3856
3702
dict_foreign_parse_drop_constraints(
3857
3703
/*================================*/
3858
 
        mem_heap_t*     heap,                   /*!< in: heap from which we can
 
3704
                                                /* out: DB_SUCCESS or
 
3705
                                                DB_CANNOT_DROP_CONSTRAINT if
 
3706
                                                syntax error or the constraint
 
3707
                                                id does not match */
 
3708
        mem_heap_t*     heap,                   /* in: heap from which we can
3859
3709
                                                allocate memory */
3860
 
        trx_t*          trx,                    /*!< in: transaction */
3861
 
        dict_table_t*   table,                  /*!< in: table */
3862
 
        ulint*          n,                      /*!< out: number of constraints
 
3710
        trx_t*          trx,                    /* in: transaction */
 
3711
        dict_table_t*   table,                  /* in: table */
 
3712
        ulint*          n,                      /* out: number of constraints
3863
3713
                                                to drop */
3864
 
        const char***   constraints_to_drop)    /*!< out: id's of the
 
3714
        const char***   constraints_to_drop)    /* out: id's of the
3865
3715
                                                constraints to drop */
3866
3716
{
3867
3717
        dict_foreign_t*         foreign;
3868
3718
        ibool                   success;
3869
3719
        char*                   str;
3870
 
        size_t                  len;
3871
3720
        const char*             ptr;
3872
3721
        const char*             id;
3873
3722
        FILE*                   ef      = dict_foreign_err_file;
3874
 
        const void*     cs;
 
3723
        struct charset_info_st* cs;
3875
3724
 
3876
3725
        ut_a(trx);
3877
3726
        ut_a(trx->mysql_thd);
3878
3727
 
3879
 
        cs = trx->session()->charset();
 
3728
        cs = innobase_get_charset(trx->mysql_thd);
3880
3729
 
3881
3730
        *n = 0;
3882
3731
 
3883
 
        *constraints_to_drop = static_cast<const char **>(mem_heap_alloc(heap, 1000 * sizeof(char*)));
3884
 
 
3885
 
        ptr= trx->session()->getQueryStringCopy(len);
3886
 
 
3887
 
        str = dict_strip_comments(ptr, len);
3888
 
 
 
3732
        *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
 
3733
 
 
3734
        str = dict_strip_comments(*(trx->mysql_query_str));
3889
3735
        ptr = str;
3890
3736
 
3891
3737
        ut_ad(mutex_own(&(dict_sys->mutex)));
3900
3746
 
3901
3747
        ptr = dict_accept(cs, ptr, "DROP", &success);
3902
3748
 
3903
 
        if (!innobase_isspace(cs, *ptr)) {
 
3749
        if (!my_isspace(cs, *ptr)) {
3904
3750
 
3905
3751
                goto loop;
3906
3752
        }
3907
3753
 
3908
3754
        ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3909
3755
 
3910
 
        if (!success || !innobase_isspace(cs, *ptr)) {
 
3756
        if (!success || !my_isspace(cs, *ptr)) {
3911
3757
 
3912
3758
                goto loop;
3913
3759
        }
3983
3829
 
3984
3830
        return(DB_CANNOT_DROP_CONSTRAINT);
3985
3831
}
 
3832
#endif /* UNIV_HOTBACKUP */
3986
3833
 
3987
3834
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3988
3835
 
3989
 
/**********************************************************************//**
 
3836
/**************************************************************************
3990
3837
Returns an index object if it is found in the dictionary cache.
3991
 
Assumes that dict_sys->mutex is already being held.
3992
 
@return index, NULL if not found */
 
3838
Assumes that dict_sys->mutex is already being held. */
3993
3839
UNIV_INTERN
3994
3840
dict_index_t*
3995
3841
dict_index_get_if_in_cache_low(
3996
3842
/*===========================*/
3997
 
        index_id_t      index_id)       /*!< in: index id */
 
3843
                                /* out: index, NULL if not found */
 
3844
        dulint  index_id)       /* in: index id */
3998
3845
{
3999
3846
        ut_ad(mutex_own(&(dict_sys->mutex)));
4000
3847
 
4002
3849
}
4003
3850
 
4004
3851
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
4005
 
/**********************************************************************//**
4006
 
Returns an index object if it is found in the dictionary cache.
4007
 
@return index, NULL if not found */
 
3852
/**************************************************************************
 
3853
Returns an index object if it is found in the dictionary cache. */
4008
3854
UNIV_INTERN
4009
3855
dict_index_t*
4010
3856
dict_index_get_if_in_cache(
4011
3857
/*=======================*/
4012
 
        index_id_t      index_id)       /*!< in: index id */
 
3858
                                /* out: index, NULL if not found */
 
3859
        dulint  index_id)       /* in: index id */
4013
3860
{
4014
3861
        dict_index_t*   index;
4015
3862
 
4028
3875
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
4029
3876
 
4030
3877
#ifdef UNIV_DEBUG
4031
 
/**********************************************************************//**
 
3878
/**************************************************************************
4032
3879
Checks that a tuple has n_fields_cmp value in a sensible range, so that
4033
 
no comparison can occur with the page number field in a node pointer.
4034
 
@return TRUE if ok */
 
3880
no comparison can occur with the page number field in a node pointer. */
4035
3881
UNIV_INTERN
4036
3882
ibool
4037
3883
dict_index_check_search_tuple(
4038
3884
/*==========================*/
4039
 
        const dict_index_t*     index,  /*!< in: index tree */
4040
 
        const dtuple_t*         tuple)  /*!< in: tuple used in a search */
 
3885
                                        /* out: TRUE if ok */
 
3886
        const dict_index_t*     index,  /* in: index tree */
 
3887
        const dtuple_t*         tuple)  /* in: tuple used in a search */
4041
3888
{
4042
3889
        ut_a(index);
4043
3890
        ut_a(dtuple_get_n_fields_cmp(tuple)
4046
3893
}
4047
3894
#endif /* UNIV_DEBUG */
4048
3895
 
4049
 
/**********************************************************************//**
4050
 
Builds a node pointer out of a physical record and a page number.
4051
 
@return own: node pointer */
 
3896
/**************************************************************************
 
3897
Builds a node pointer out of a physical record and a page number. */
4052
3898
UNIV_INTERN
4053
3899
dtuple_t*
4054
3900
dict_index_build_node_ptr(
4055
3901
/*======================*/
4056
 
        const dict_index_t*     index,  /*!< in: index */
4057
 
        const rec_t*            rec,    /*!< in: record for which to build node
4058
 
                                        pointer */
4059
 
        ulint                   page_no,/*!< in: page number to put in node
4060
 
                                        pointer */
4061
 
        mem_heap_t*             heap,   /*!< in: memory heap where pointer
 
3902
                                        /* out, own: node pointer */
 
3903
        const dict_index_t*     index,  /* in: index */
 
3904
        const rec_t*            rec,    /* in: record for which to build node
 
3905
                                        pointer */
 
3906
        ulint                   page_no,/* in: page number to put in node
 
3907
                                        pointer */
 
3908
        mem_heap_t*             heap,   /* in: memory heap where pointer
4062
3909
                                        created */
4063
 
        ulint                   level)  /*!< in: level of rec in tree:
 
3910
        ulint                   level)  /* in: level of rec in tree:
4064
3911
                                        0 means leaf level */
4065
3912
{
4066
3913
        dtuple_t*       tuple;
4097
3944
 
4098
3945
        dict_index_copy_types(tuple, index, n_unique);
4099
3946
 
4100
 
        buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
 
3947
        buf = mem_heap_alloc(heap, 4);
4101
3948
 
4102
3949
        mach_write_to_4(buf, page_no);
4103
3950
 
4115
3962
        return(tuple);
4116
3963
}
4117
3964
 
4118
 
/**********************************************************************//**
 
3965
/**************************************************************************
4119
3966
Copies an initial segment of a physical record, long enough to specify an
4120
 
index entry uniquely.
4121
 
@return pointer to the prefix record */
 
3967
index entry uniquely. */
4122
3968
UNIV_INTERN
4123
3969
rec_t*
4124
3970
dict_index_copy_rec_order_prefix(
4125
3971
/*=============================*/
4126
 
        const dict_index_t*     index,  /*!< in: index */
4127
 
        const rec_t*            rec,    /*!< in: record for which to
 
3972
                                        /* out: pointer to the prefix record */
 
3973
        const dict_index_t*     index,  /* in: index */
 
3974
        const rec_t*            rec,    /* in: record for which to
4128
3975
                                        copy prefix */
4129
 
        ulint*                  n_fields,/*!< out: number of fields copied */
4130
 
        byte**                  buf,    /*!< in/out: memory buffer for the
 
3976
        ulint*                  n_fields,/* out: number of fields copied */
 
3977
        byte**                  buf,    /* in/out: memory buffer for the
4131
3978
                                        copied prefix, or NULL */
4132
 
        ulint*                  buf_size)/*!< in/out: buffer size */
 
3979
        ulint*                  buf_size)/* in/out: buffer size */
4133
3980
{
4134
3981
        ulint           n;
4135
3982
 
4146
3993
        return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
4147
3994
}
4148
3995
 
4149
 
/**********************************************************************//**
4150
 
Builds a typed data tuple out of a physical record.
4151
 
@return own: data tuple */
 
3996
/**************************************************************************
 
3997
Builds a typed data tuple out of a physical record. */
4152
3998
UNIV_INTERN
4153
3999
dtuple_t*
4154
4000
dict_index_build_data_tuple(
4155
4001
/*========================*/
4156
 
        dict_index_t*   index,  /*!< in: index tree */
4157
 
        rec_t*          rec,    /*!< in: record for which to build data tuple */
4158
 
        ulint           n_fields,/*!< in: number of data fields */
4159
 
        mem_heap_t*     heap)   /*!< in: memory heap where tuple created */
 
4002
                                /* out, own: data tuple */
 
4003
        dict_index_t*   index,  /* in: index tree */
 
4004
        rec_t*          rec,    /* in: record for which to build data tuple */
 
4005
        ulint           n_fields,/* in: number of data fields */
 
4006
        mem_heap_t*     heap)   /* in: memory heap where tuple created */
4160
4007
{
4161
4008
        dtuple_t*       tuple;
4162
4009
 
4174
4021
        return(tuple);
4175
4022
}
4176
4023
 
4177
 
/*********************************************************************//**
 
4024
/*************************************************************************
4178
4025
Calculates the minimum record length in an index. */
4179
4026
UNIV_INTERN
4180
4027
ulint
4181
4028
dict_index_calc_min_rec_len(
4182
4029
/*========================*/
4183
 
        const dict_index_t*     index)  /*!< in: index */
 
4030
        const dict_index_t*     index)  /* in: index */
4184
4031
{
4185
4032
        ulint   sum     = 0;
4186
4033
        ulint   i;
4187
 
        ulint   comp    = dict_table_is_comp(index->table);
4188
4034
 
4189
 
        if (comp) {
 
4035
        if (dict_table_is_comp(index->table)) {
4190
4036
                ulint nullable = 0;
4191
4037
                sum = REC_N_NEW_EXTRA_BYTES;
4192
4038
                for (i = 0; i < dict_index_get_n_fields(index); i++) {
4193
4039
                        const dict_col_t*       col
4194
4040
                                = dict_index_get_nth_col(index, i);
4195
 
                        ulint   size = dict_col_get_fixed_size(col, comp);
 
4041
                        ulint   size = dict_col_get_fixed_size(col);
4196
4042
                        sum += size;
4197
4043
                        if (!size) {
4198
4044
                                size = col->len;
4211
4057
 
4212
4058
        for (i = 0; i < dict_index_get_n_fields(index); i++) {
4213
4059
                sum += dict_col_get_fixed_size(
4214
 
                        dict_index_get_nth_col(index, i), comp);
 
4060
                        dict_index_get_nth_col(index, i));
4215
4061
        }
4216
4062
 
4217
4063
        if (sum > 127) {
4225
4071
        return(sum);
4226
4072
}
4227
4073
 
4228
 
/*********************************************************************//**
 
4074
/*************************************************************************
4229
4075
Calculates new estimates for table and index statistics. The statistics
4230
4076
are used in query optimization. */
4231
4077
UNIV_INTERN
4232
4078
void
4233
 
dict_update_statistics(
4234
 
/*===================*/
4235
 
        dict_table_t*   table,          /*!< in/out: table */
4236
 
        ibool           only_calc_if_missing_stats)/*!< in: only
4237
 
                                        update/recalc the stats if they have
4238
 
                                        not been initialized yet, otherwise
4239
 
                                        do nothing */
 
4079
dict_update_statistics_low(
 
4080
/*=======================*/
 
4081
        dict_table_t*   table,          /* in/out: table */
 
4082
        ibool           has_dict_mutex __attribute__((unused)))
 
4083
                                        /* in: TRUE if the caller has the
 
4084
                                        dictionary mutex */
4240
4085
{
4241
4086
        dict_index_t*   index;
 
4087
        ulint           size;
4242
4088
        ulint           sum_of_index_sizes      = 0;
4243
4089
 
4244
4090
        if (table->ibd_file_missing) {
4247
4093
                        "  InnoDB: cannot calculate statistics for table %s\n"
4248
4094
                        "InnoDB: because the .ibd file is missing.  For help,"
4249
4095
                        " please refer to\n"
4250
 
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
 
4096
                        "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
 
4097
                        "innodb-troubleshooting.html\n",
4251
4098
                        table->name);
4252
4099
 
4253
4100
                return;
4254
4101
        }
4255
4102
 
 
4103
        /* If we have set a high innodb_force_recovery level, do not calculate
 
4104
        statistics, as a badly corrupted index can cause a crash in it. */
 
4105
 
 
4106
        if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
 
4107
 
 
4108
                return;
 
4109
        }
 
4110
 
4256
4111
        /* Find out the sizes of the indexes and how many different values
4257
4112
        for the key they approximately have */
4258
4113
 
4264
4119
                return;
4265
4120
        }
4266
4121
 
4267
 
        dict_table_stats_lock(table, RW_X_LATCH);
4268
 
 
4269
 
        if (only_calc_if_missing_stats && table->stat_initialized) {
4270
 
                dict_table_stats_unlock(table, RW_X_LATCH);
4271
 
                return;
4272
 
        }
4273
 
 
4274
 
        do {
4275
 
                if (UNIV_LIKELY
4276
 
                    (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
4277
 
                     || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
4278
 
                         && dict_index_is_clust(index)))) {
4279
 
                        ulint   size;
4280
 
                        size = btr_get_size(index, BTR_TOTAL_SIZE);
4281
 
 
4282
 
                        index->stat_index_size = size;
4283
 
 
4284
 
                        sum_of_index_sizes += size;
4285
 
 
4286
 
                        size = btr_get_size(index, BTR_N_LEAF_PAGES);
4287
 
 
4288
 
                        if (size == 0) {
4289
 
                                /* The root node of the tree is a leaf */
4290
 
                                size = 1;
4291
 
                        }
4292
 
 
4293
 
                        index->stat_n_leaf_pages = size;
4294
 
 
4295
 
                        btr_estimate_number_of_different_key_vals(index);
4296
 
                } else {
4297
 
                        /* If we have set a high innodb_force_recovery
4298
 
                        level, do not calculate statistics, as a badly
4299
 
                        corrupted index can cause a crash in it.
4300
 
                        Initialize some bogus index cardinality
4301
 
                        statistics, so that the data can be queried in
4302
 
                        various means, also via secondary indexes. */
4303
 
                        ulint   i;
4304
 
 
4305
 
                        sum_of_index_sizes++;
4306
 
                        index->stat_index_size = index->stat_n_leaf_pages = 1;
4307
 
 
4308
 
                        for (i = dict_index_get_n_unique(index); i; ) {
4309
 
                                index->stat_n_diff_key_vals[i--] = 1;
4310
 
                        }
 
4122
        while (index) {
 
4123
                size = btr_get_size(index, BTR_TOTAL_SIZE);
 
4124
 
 
4125
                index->stat_index_size = size;
 
4126
 
 
4127
                sum_of_index_sizes += size;
 
4128
 
 
4129
                size = btr_get_size(index, BTR_N_LEAF_PAGES);
 
4130
 
 
4131
                if (size == 0) {
 
4132
                        /* The root node of the tree is a leaf */
 
4133
                        size = 1;
4311
4134
                }
4312
4135
 
 
4136
                index->stat_n_leaf_pages = size;
 
4137
 
 
4138
                btr_estimate_number_of_different_key_vals(index);
 
4139
 
4313
4140
                index = dict_table_get_next_index(index);
4314
 
        } while (index);
 
4141
        }
4315
4142
 
4316
4143
        index = dict_table_get_first_index(table);
4317
4144
 
4326
4153
        table->stat_initialized = TRUE;
4327
4154
 
4328
4155
        table->stat_modified_counter = 0;
4329
 
 
4330
 
        dict_table_stats_unlock(table, RW_X_LATCH);
4331
 
}
4332
 
 
4333
 
/**********************************************************************//**
 
4156
}
 
4157
 
 
4158
/*************************************************************************
 
4159
Calculates new estimates for table and index statistics. The statistics
 
4160
are used in query optimization. */
 
4161
UNIV_INTERN
 
4162
void
 
4163
dict_update_statistics(
 
4164
/*===================*/
 
4165
        dict_table_t*   table)  /* in/out: table */
 
4166
{
 
4167
        dict_update_statistics_low(table, FALSE);
 
4168
}
 
4169
 
 
4170
/**************************************************************************
4334
4171
Prints info of a foreign key constraint. */
4335
4172
static
4336
4173
void
4337
4174
dict_foreign_print_low(
4338
4175
/*===================*/
4339
 
        dict_foreign_t* foreign)        /*!< in: foreign key constraint */
 
4176
        dict_foreign_t* foreign)        /* in: foreign key constraint */
4340
4177
{
4341
4178
        ulint   i;
4342
4179
 
4360
4197
        fputs(" )\n", stderr);
4361
4198
}
4362
4199
 
4363
 
/**********************************************************************//**
 
4200
/**************************************************************************
4364
4201
Prints a table data. */
4365
4202
UNIV_INTERN
4366
4203
void
4367
4204
dict_table_print(
4368
4205
/*=============*/
4369
 
        dict_table_t*   table)  /*!< in: table */
 
4206
        dict_table_t*   table)  /* in: table */
4370
4207
{
4371
4208
        mutex_enter(&(dict_sys->mutex));
4372
4209
        dict_table_print_low(table);
4373
4210
        mutex_exit(&(dict_sys->mutex));
4374
4211
}
4375
4212
 
4376
 
/**********************************************************************//**
 
4213
/**************************************************************************
4377
4214
Prints a table data when we know the table name. */
4378
4215
UNIV_INTERN
4379
4216
void
4380
4217
dict_table_print_by_name(
4381
4218
/*=====================*/
4382
 
        const char*     name)   /*!< in: table name */
 
4219
        const char*     name)
4383
4220
{
4384
4221
        dict_table_t*   table;
4385
4222
 
4393
4230
        mutex_exit(&(dict_sys->mutex));
4394
4231
}
4395
4232
 
4396
 
/**********************************************************************//**
 
4233
/**************************************************************************
4397
4234
Prints a table data. */
4398
4235
UNIV_INTERN
4399
4236
void
4400
4237
dict_table_print_low(
4401
4238
/*=================*/
4402
 
        dict_table_t*   table)  /*!< in: table */
 
4239
        dict_table_t*   table)  /* in: table */
4403
4240
{
4404
4241
        dict_index_t*   index;
4405
4242
        dict_foreign_t* foreign;
4407
4244
 
4408
4245
        ut_ad(mutex_own(&(dict_sys->mutex)));
4409
4246
 
4410
 
        dict_update_statistics(table, FALSE /* update even if initialized */);
4411
 
 
4412
 
        dict_table_stats_lock(table, RW_S_LATCH);
 
4247
        dict_update_statistics_low(table, TRUE);
4413
4248
 
4414
4249
        fprintf(stderr,
4415
4250
                "--------------------------------------\n"
4416
 
                "TABLE: name %s, id %llu, flags %lx, columns %lu,"
 
4251
                "TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
4417
4252
                " indexes %lu, appr.rows %lu\n"
4418
4253
                "  COLUMNS: ",
4419
4254
                table->name,
4420
 
                (ullint) table->id,
 
4255
                (ulong) ut_dulint_get_high(table->id),
 
4256
                (ulong) ut_dulint_get_low(table->id),
4421
4257
                (ulong) table->flags,
4422
4258
                (ulong) table->n_cols,
4423
4259
                (ulong) UT_LIST_GET_LEN(table->indexes),
4424
4260
                (ulong) table->stat_n_rows);
4425
4261
 
4426
 
        for (i = 0; i < (ulint) table->n_cols; i++) {
 
4262
        for (i = 0; i + 1 < (ulint) table->n_cols; i++) {
4427
4263
                dict_col_print_low(table, dict_table_get_nth_col(table, i));
4428
4264
                fputs("; ", stderr);
4429
4265
        }
4437
4273
                index = UT_LIST_GET_NEXT(indexes, index);
4438
4274
        }
4439
4275
 
4440
 
        dict_table_stats_unlock(table, RW_S_LATCH);
4441
 
 
4442
4276
        foreign = UT_LIST_GET_FIRST(table->foreign_list);
4443
4277
 
4444
4278
        while (foreign != NULL) {
4454
4288
        }
4455
4289
}
4456
4290
 
4457
 
/**********************************************************************//**
 
4291
/**************************************************************************
4458
4292
Prints a column data. */
4459
4293
static
4460
4294
void
4461
4295
dict_col_print_low(
4462
4296
/*===============*/
4463
 
        const dict_table_t*     table,  /*!< in: table */
4464
 
        const dict_col_t*       col)    /*!< in: column */
 
4297
        const dict_table_t*     table,  /* in: table */
 
4298
        const dict_col_t*       col)    /* in: column */
4465
4299
{
4466
4300
        dtype_t type;
4467
4301
 
4474
4308
        dtype_print(&type);
4475
4309
}
4476
4310
 
4477
 
/**********************************************************************//**
 
4311
/**************************************************************************
4478
4312
Prints an index data. */
4479
4313
static
4480
4314
void
4481
4315
dict_index_print_low(
4482
4316
/*=================*/
4483
 
        dict_index_t*   index)  /*!< in: index */
 
4317
        dict_index_t*   index)  /* in: index */
4484
4318
{
4485
4319
        ib_int64_t      n_vals;
4486
4320
        ulint           i;
 
4321
        const char*     type_string;
4487
4322
 
4488
4323
        ut_ad(mutex_own(&(dict_sys->mutex)));
4489
4324
 
4494
4329
                n_vals = index->stat_n_diff_key_vals[1];
4495
4330
        }
4496
4331
 
 
4332
        if (dict_index_is_clust(index)) {
 
4333
                type_string = "clustered index";
 
4334
        } else if (dict_index_is_unique(index)) {
 
4335
                type_string = "unique index";
 
4336
        } else {
 
4337
                type_string = "secondary index";
 
4338
        }
 
4339
 
4497
4340
        fprintf(stderr,
4498
 
                "  INDEX: name %s, id %llu, fields %lu/%lu,"
 
4341
                "  INDEX: name %s, id %lu %lu, fields %lu/%lu,"
4499
4342
                " uniq %lu, type %lu\n"
4500
4343
                "   root page %lu, appr.key vals %lu,"
4501
4344
                " leaf pages %lu, size pages %lu\n"
4502
4345
                "   FIELDS: ",
4503
4346
                index->name,
4504
 
                (ullint) index->id,
 
4347
                (ulong) ut_dulint_get_high(index->id),
 
4348
                (ulong) ut_dulint_get_low(index->id),
4505
4349
                (ulong) index->n_user_defined_cols,
4506
4350
                (ulong) index->n_fields,
4507
4351
                (ulong) index->n_uniq,
4524
4368
#endif /* UNIV_BTR_PRINT */
4525
4369
}
4526
4370
 
4527
 
/**********************************************************************//**
 
4371
/**************************************************************************
4528
4372
Prints a field data. */
4529
4373
static
4530
4374
void
4531
4375
dict_field_print_low(
4532
4376
/*=================*/
4533
 
        const dict_field_t*     field)  /*!< in: field */
 
4377
        dict_field_t*   field)  /* in: field */
4534
4378
{
4535
4379
        ut_ad(mutex_own(&(dict_sys->mutex)));
4536
4380
 
4541
4385
        }
4542
4386
}
4543
4387
 
4544
 
/**********************************************************************//**
 
4388
/**************************************************************************
4545
4389
Outputs info on a foreign key of a table in a format suitable for
4546
4390
CREATE TABLE. */
4547
4391
UNIV_INTERN
4548
4392
void
4549
4393
dict_print_info_on_foreign_key_in_create_format(
4550
4394
/*============================================*/
4551
 
        FILE*           file,           /*!< in: file where to print */
4552
 
        trx_t*          trx,            /*!< in: transaction */
4553
 
        dict_foreign_t* foreign,        /*!< in: foreign key constraint */
4554
 
        ibool           add_newline)    /*!< in: whether to add a newline */
 
4395
        FILE*           file,           /* in: file where to print */
 
4396
        trx_t*          trx,            /* in: transaction */
 
4397
        dict_foreign_t* foreign,        /* in: foreign key constraint */
 
4398
        ibool           add_newline)    /* in: whether to add a newline */
4555
4399
{
4556
4400
        const char*     stripped_id;
4557
4401
        ulint   i;
4639
4483
        }
4640
4484
}
4641
4485
 
4642
 
/**********************************************************************//**
 
4486
/**************************************************************************
4643
4487
Outputs info on foreign keys of a table. */
4644
4488
UNIV_INTERN
4645
4489
void
4646
4490
dict_print_info_on_foreign_keys(
4647
4491
/*============================*/
4648
 
        ibool           create_table_format, /*!< in: if TRUE then print in
 
4492
        ibool           create_table_format, /* in: if TRUE then print in
4649
4493
                                a format suitable to be inserted into
4650
4494
                                a CREATE TABLE, otherwise in the format
4651
4495
                                of SHOW TABLE STATUS */
4652
 
        FILE*           file,   /*!< in: file where to print */
4653
 
        trx_t*          trx,    /*!< in: transaction */
4654
 
        dict_table_t*   table)  /*!< in: table */
 
4496
        FILE*           file,   /* in: file where to print */
 
4497
        trx_t*          trx,    /* in: transaction */
 
4498
        dict_table_t*   table)  /* in: table */
4655
4499
{
4656
4500
        dict_foreign_t* foreign;
4657
4501
 
4729
4573
        mutex_exit(&(dict_sys->mutex));
4730
4574
}
4731
4575
 
4732
 
/********************************************************************//**
 
4576
/************************************************************************
4733
4577
Displays the names of the index and the table. */
4734
4578
UNIV_INTERN
4735
4579
void
4736
4580
dict_index_name_print(
4737
4581
/*==================*/
4738
 
        FILE*                   file,   /*!< in: output stream */
4739
 
        trx_t*                  trx,    /*!< in: transaction */
4740
 
        const dict_index_t*     index)  /*!< in: index to print */
 
4582
        FILE*                   file,   /* in: output stream */
 
4583
        trx_t*                  trx,    /* in: transaction */
 
4584
        const dict_index_t*     index)  /* in: index to print */
4741
4585
{
4742
4586
        fputs("index ", file);
4743
4587
        ut_print_name(file, trx, FALSE, index->name);
4744
4588
        fputs(" of table ", file);
4745
4589
        ut_print_name(file, trx, TRUE, index->table_name);
4746
4590
}
4747
 
#endif /* !UNIV_HOTBACKUP */
4748
 
 
4749
 
/**********************************************************************//**
4750
 
Inits dict_ind_redundant and dict_ind_compact. */
4751
 
UNIV_INTERN
4752
 
void
4753
 
dict_ind_init(void)
4754
 
/*===============*/
4755
 
{
4756
 
        dict_table_t*           table;
4757
 
 
4758
 
        /* create dummy table and index for REDUNDANT infimum and supremum */
4759
 
        table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
4760
 
        dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
4761
 
                               DATA_ENGLISH | DATA_NOT_NULL, 8);
4762
 
 
4763
 
        dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
4764
 
                                                   DICT_HDR_SPACE, 0, 1);
4765
 
        dict_index_add_col(dict_ind_redundant, table,
4766
 
                           dict_table_get_nth_col(table, 0), 0);
4767
 
        dict_ind_redundant->table = table;
4768
 
        /* create dummy table and index for COMPACT infimum and supremum */
4769
 
        table = dict_mem_table_create("SYS_DUMMY2",
4770
 
                                      DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
4771
 
        dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
4772
 
                               DATA_ENGLISH | DATA_NOT_NULL, 8);
4773
 
        dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
4774
 
                                                 DICT_HDR_SPACE, 0, 1);
4775
 
        dict_index_add_col(dict_ind_compact, table,
4776
 
                           dict_table_get_nth_col(table, 0), 0);
4777
 
        dict_ind_compact->table = table;
4778
 
 
4779
 
        /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
4780
 
        dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
4781
 
}
4782
 
 
4783
 
/**********************************************************************//**
4784
 
Frees dict_ind_redundant and dict_ind_compact. */
4785
 
static
4786
 
void
4787
 
dict_ind_free(void)
4788
 
/*===============*/
4789
 
{
4790
 
        dict_table_t*   table;
4791
 
 
4792
 
        table = dict_ind_compact->table;
4793
 
        dict_mem_index_free(dict_ind_compact);
4794
 
        dict_ind_compact = NULL;
4795
 
        dict_mem_table_free(table);
4796
 
 
4797
 
        table = dict_ind_redundant->table;
4798
 
        dict_mem_index_free(dict_ind_redundant);
4799
 
        dict_ind_redundant = NULL;
4800
 
        dict_mem_table_free(table);
4801
 
}
4802
 
 
4803
 
#ifndef UNIV_HOTBACKUP
4804
 
/**********************************************************************//**
4805
 
Get index by name
4806
 
@return index, NULL if does not exist */
 
4591
 
 
4592
/**************************************************************************
 
4593
Get index by name */
4807
4594
UNIV_INTERN
4808
4595
dict_index_t*
4809
4596
dict_table_get_index_on_name(
4810
4597
/*=========================*/
4811
 
        dict_table_t*   table,  /*!< in: table */
4812
 
        const char*     name)   /*!< in: name of the index to find */
 
4598
                                /* out: index, NULL if does not exist */
 
4599
        dict_table_t*   table,  /* in: table */
 
4600
        const char*     name)   /* in: name of the index to find */
4813
4601
{
4814
4602
        dict_index_t*   index;
4815
4603
 
4828
4616
 
4829
4617
}
4830
4618
 
4831
 
/**********************************************************************//**
 
4619
/**************************************************************************
4832
4620
Replace the index passed in with another equivalent index in the tables
4833
4621
foreign key list. */
4834
4622
UNIV_INTERN
4835
4623
void
4836
4624
dict_table_replace_index_in_foreign_list(
4837
4625
/*=====================================*/
4838
 
        dict_table_t*   table,  /*!< in/out: table */
4839
 
        dict_index_t*   index,  /*!< in: index to be replaced */
4840
 
        const trx_t*    trx)    /*!< in: transaction handle */
 
4626
        dict_table_t*   table,  /* in/out: table */
 
4627
        dict_index_t*   index)  /* in: index to be replaced */
4841
4628
{
4842
4629
        dict_foreign_t* foreign;
4843
4630
 
4848
4635
                if (foreign->foreign_index == index) {
4849
4636
                        dict_index_t*   new_index
4850
4637
                                = dict_foreign_find_equiv_index(foreign);
4851
 
 
4852
 
                        /* There must exist an alternative index if
4853
 
                        check_foreigns (FOREIGN_KEY_CHECKS) is on, 
4854
 
                        since ha_innobase::prepare_drop_index had done
4855
 
                        the check before we reach here. */
4856
 
 
4857
 
                        ut_a(new_index || !trx->check_foreigns);
 
4638
                        ut_a(new_index);
4858
4639
 
4859
4640
                        foreign->foreign_index = new_index;
4860
4641
                }
4861
4642
        }
4862
4643
}
4863
4644
 
4864
 
/**********************************************************************//**
 
4645
/**************************************************************************
4865
4646
In case there is more than one index with the same name return the index
4866
 
with the min(id).
4867
 
@return index, NULL if does not exist */
 
4647
with the min(id). */
4868
4648
UNIV_INTERN
4869
4649
dict_index_t*
4870
4650
dict_table_get_index_on_name_and_min_id(
4871
4651
/*=====================================*/
4872
 
        dict_table_t*   table,  /*!< in: table */
4873
 
        const char*     name)   /*!< in: name of the index to find */
 
4652
                                /* out: index, NULL if does not exist */
 
4653
        dict_table_t*   table,  /* in: table */
 
4654
        const char*     name)   /* in: name of the index to find */
4874
4655
{
4875
4656
        dict_index_t*   index;
4876
4657
        dict_index_t*   min_index; /* Index with matching name and min(id) */
4880
4661
 
4881
4662
        while (index != NULL) {
4882
4663
                if (ut_strcmp(index->name, name) == 0) {
4883
 
                        if (!min_index || index->id < min_index->id) {
 
4664
                        if (!min_index
 
4665
                            || ut_dulint_cmp(index->id, min_index->id) < 0) {
4884
4666
 
4885
4667
                                min_index = index;
4886
4668
                        }
4894
4676
}
4895
4677
 
4896
4678
#ifdef UNIV_DEBUG
4897
 
/**********************************************************************//**
 
4679
/**************************************************************************
4898
4680
Check for duplicate index entries in a table [using the index name] */
4899
4681
UNIV_INTERN
4900
4682
void
4901
4683
dict_table_check_for_dup_indexes(
4902
4684
/*=============================*/
4903
 
        const dict_table_t*     table,  /*!< in: Check for dup indexes
 
4685
        const dict_table_t*     table)  /* in: Check for dup indexes
4904
4686
                                        in this table */
4905
 
        ibool                   tmp_ok) /*!< in: TRUE=allow temporary
4906
 
                                        index names */
4907
4687
{
4908
4688
        /* Check for duplicates, ignoring indexes that are marked
4909
4689
        as to be dropped */
4911
4691
        const dict_index_t*     index1;
4912
4692
        const dict_index_t*     index2;
4913
4693
 
4914
 
        ut_ad(mutex_own(&dict_sys->mutex));
4915
 
 
4916
4694
        /* The primary index _must_ exist */
4917
4695
        ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
4918
4696
 
4919
4697
        index1 = UT_LIST_GET_FIRST(table->indexes);
4920
 
 
4921
 
        do {
4922
 
                ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);
4923
 
 
4924
 
                index2 = UT_LIST_GET_NEXT(indexes, index1);
 
4698
        index2 = UT_LIST_GET_NEXT(indexes, index1);
 
4699
 
 
4700
        while (index1 && index2) {
4925
4701
 
4926
4702
                while (index2) {
4927
4703
 
4933
4709
                }
4934
4710
 
4935
4711
                index1 = UT_LIST_GET_NEXT(indexes, index1);
4936
 
        } while (index1);
 
4712
                index2 = UT_LIST_GET_NEXT(indexes, index1);
 
4713
        }
4937
4714
}
4938
4715
#endif /* UNIV_DEBUG */
4939
 
 
4940
 
/**************************************************************************
4941
 
Closes the data dictionary module. */
4942
 
UNIV_INTERN
4943
 
void
4944
 
dict_close(void)
4945
 
/*============*/
4946
 
{
4947
 
        ulint   i;
4948
 
 
4949
 
        /* Free the hash elements. We don't remove them from the table
4950
 
        because we are going to destroy the table anyway. */
4951
 
        for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
4952
 
                dict_table_t*   table;
4953
 
 
4954
 
                table = static_cast<dict_table_t *>(HASH_GET_FIRST(dict_sys->table_hash, i));
4955
 
 
4956
 
                while (table) {
4957
 
                        dict_table_t*   prev_table = table;
4958
 
 
4959
 
                        table = static_cast<dict_table_t *>(HASH_GET_NEXT(name_hash, prev_table));
4960
 
#ifdef UNIV_DEBUG
4961
 
                        ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
4962
 
#endif
4963
 
                        /* Acquire only because it's a pre-condition. */
4964
 
                        mutex_enter(&dict_sys->mutex);
4965
 
 
4966
 
                        dict_table_remove_from_cache(prev_table);
4967
 
 
4968
 
                        mutex_exit(&dict_sys->mutex);
4969
 
                }
4970
 
        }
4971
 
 
4972
 
        hash_table_free(dict_sys->table_hash);
4973
 
 
4974
 
        /* The elements are the same instance as in dict_sys->table_hash,
4975
 
        therefore we don't delete the individual elements. */
4976
 
        hash_table_free(dict_sys->table_id_hash);
4977
 
 
4978
 
        dict_ind_free();
4979
 
 
4980
 
        mutex_free(&dict_sys->mutex);
4981
 
 
4982
 
        rw_lock_free(&dict_operation_lock);
4983
 
        memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
4984
 
 
4985
 
        mutex_free(&dict_foreign_err_mutex);
4986
 
 
4987
 
        mem_free(dict_sys);
4988
 
        dict_sys = NULL;
4989
 
 
4990
 
        for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
4991
 
                rw_lock_free(&dict_table_stats_latches[i]);
4992
 
        }
4993
 
}
4994
 
#endif /* !UNIV_HOTBACKUP */