~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/row/row0mysql.cc

  • Committer: Monty Taylor
  • Date: 2008-11-07 00:15:51 UTC
  • mto: This revision was merged to the branch mainline in revision 579.
  • Revision ID: monty@inaugust.com-20081107001551-8vxb6sf1ti0i5p09
Cleaned up some headers for PCH.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 2000, 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 row/row0mysql.c
21
 
Interface between Innobase row operations and MySQL.
22
 
Contains also create table and other data dictionary operations.
23
 
 
24
 
Created 9/17/2000 Heikki Tuuri
25
 
*******************************************************/
26
 
 
27
 
#include "row0mysql.h"
28
 
 
29
 
#ifdef UNIV_NONINL
30
 
#include "row0mysql.ic"
31
 
#endif
32
 
 
33
 
#include "row0ins.h"
34
 
#include "row0merge.h"
35
 
#include "row0sel.h"
36
 
#include "row0upd.h"
37
 
#include "row0row.h"
38
 
#include "que0que.h"
39
 
#include "pars0pars.h"
40
 
#include "dict0dict.h"
41
 
#include "dict0crea.h"
42
 
#include "dict0load.h"
43
 
#include "dict0boot.h"
44
 
#include "trx0roll.h"
45
 
#include "trx0purge.h"
46
 
#include "trx0rec.h"
47
 
#include "trx0undo.h"
48
 
#include "lock0lock.h"
49
 
#include "rem0cmp.h"
50
 
#include "log0log.h"
51
 
#include "btr0sea.h"
52
 
#include "fil0fil.h"
53
 
#include "ibuf0ibuf.h"
54
 
 
55
 
#include <errno.h>
56
 
 
57
 
/** Provide optional 4.x backwards compatibility for 5.0 and above */
58
 
UNIV_INTERN ibool       row_rollback_on_timeout = FALSE;
59
 
 
60
 
/** Chain node of the list of tables to drop in the background. */
61
 
typedef struct row_mysql_drop_struct    row_mysql_drop_t;
62
 
 
63
 
/** Chain node of the list of tables to drop in the background. */
64
 
struct row_mysql_drop_struct{
65
 
        char*                           table_name;     /*!< table name */
66
 
        UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
67
 
                                                        /*!< list chain node */
68
 
};
69
 
 
70
 
/** @brief List of tables we should drop in background.
71
 
 
72
 
ALTER TABLE in MySQL requires that the table handler can drop the
73
 
table in background when there are no queries to it any
74
 
more.  Protected by kernel_mutex. */
75
 
static UT_LIST_BASE_NODE_T(row_mysql_drop_t)    row_mysql_drop_list;
76
 
/** Flag: has row_mysql_drop_list been initialized? */
77
 
static ibool    row_mysql_drop_list_inited      = FALSE;
78
 
 
79
 
/** Magic table names for invoking various monitor threads */
80
 
/* @{ */
81
 
static const char S_innodb_monitor[] = "innodb_monitor";
82
 
static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
83
 
static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
84
 
static const char S_innodb_table_monitor[] = "innodb_table_monitor";
85
 
static const char S_innodb_mem_validate[] = "innodb_mem_validate";
86
 
/* @} */
87
 
 
88
 
/** Evaluates to true if str1 equals str2_onstack, used for comparing
89
 
the magic table names.
90
 
@param str1             in: string to compare
91
 
@param str1_len         in: length of str1, in bytes, including terminating NUL
92
 
@param str2_onstack     in: char[] array containing a NUL terminated string
93
 
@return                 TRUE if str1 equals str2_onstack */
94
 
#define STR_EQ(str1, str1_len, str2_onstack) \
95
 
        ((str1_len) == sizeof(str2_onstack) \
96
 
         && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
97
 
 
98
 
/*********************************************************************//**
99
 
If a table is not yet in the drop list, adds the table to the list of tables
100
 
which the master thread drops in background. We need this on Unix because in
101
 
ALTER TABLE MySQL may call drop table even if the table has running queries on
102
 
it. Also, if there are running foreign key checks on the table, we drop the
103
 
table lazily.
104
 
@return TRUE if the table was not yet in the drop list, and was added there */
105
 
static
106
 
ibool
107
 
row_add_table_to_background_drop_list(
108
 
/*==================================*/
109
 
        const char*     name);  /*!< in: table name */
110
 
 
111
 
/*******************************************************************//**
112
 
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
113
 
static
114
 
void
115
 
row_mysql_delay_if_needed(void)
116
 
/*===========================*/
117
 
{
118
 
        if (srv_dml_needed_delay) {
119
 
                os_thread_sleep(srv_dml_needed_delay);
120
 
        }
121
 
}
122
 
 
123
 
/*******************************************************************//**
124
 
Frees the blob heap in prebuilt when no longer needed. */
125
 
UNIV_INTERN
126
 
void
127
 
row_mysql_prebuilt_free_blob_heap(
128
 
/*==============================*/
129
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct of a
130
 
                                        ha_innobase:: table handle */
131
 
{
132
 
        mem_heap_free(prebuilt->blob_heap);
133
 
        prebuilt->blob_heap = NULL;
134
 
}
135
 
 
136
 
/*******************************************************************//**
137
 
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
138
 
format.
139
 
@return pointer to the data, we skip the 1 or 2 bytes at the start
140
 
that are used to store the len */
141
 
UNIV_INTERN
142
 
byte*
143
 
row_mysql_store_true_var_len(
144
 
/*=========================*/
145
 
        byte*   dest,   /*!< in: where to store */
146
 
        ulint   len,    /*!< in: length, must fit in two bytes */
147
 
        ulint   lenlen) /*!< in: storage length of len: either 1 or 2 bytes */
148
 
{
149
 
        if (lenlen == 2) {
150
 
                ut_a(len < 256 * 256);
151
 
 
152
 
                mach_write_to_2_little_endian(dest, len);
153
 
 
154
 
                return(dest + 2);
155
 
        }
156
 
 
157
 
        ut_a(lenlen == 1);
158
 
        ut_a(len < 256);
159
 
 
160
 
        mach_write_to_1(dest, len);
161
 
 
162
 
        return(dest + 1);
163
 
}
164
 
 
165
 
/*******************************************************************//**
166
 
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
167
 
returns a pointer to the data.
168
 
@return pointer to the data, we skip the 1 or 2 bytes at the start
169
 
that are used to store the len */
170
 
UNIV_INTERN
171
 
const byte*
172
 
row_mysql_read_true_varchar(
173
 
/*========================*/
174
 
        ulint*          len,    /*!< out: variable-length field length */
175
 
        const byte*     field,  /*!< in: field in the MySQL format */
176
 
        ulint           lenlen) /*!< in: storage length of len: either 1
177
 
                                or 2 bytes */
178
 
{
179
 
        if (lenlen == 2) {
180
 
                *len = mach_read_from_2_little_endian(field);
181
 
 
182
 
                return(field + 2);
183
 
        }
184
 
 
185
 
        ut_a(lenlen == 1);
186
 
 
187
 
        *len = mach_read_from_1(field);
188
 
 
189
 
        return(field + 1);
190
 
}
191
 
 
192
 
/*******************************************************************//**
193
 
Stores a reference to a BLOB in the MySQL format. */
194
 
UNIV_INTERN
195
 
void
196
 
row_mysql_store_blob_ref(
197
 
/*=====================*/
198
 
        byte*           dest,   /*!< in: where to store */
199
 
        ulint           col_len,/*!< in: dest buffer size: determines into
200
 
                                how many bytes the BLOB length is stored,
201
 
                                the space for the length may vary from 1
202
 
                                to 4 bytes */
203
 
        const void*     data,   /*!< in: BLOB data; if the value to store
204
 
                                is SQL NULL this should be NULL pointer */
205
 
        ulint           len)    /*!< in: BLOB length; if the value to store
206
 
                                is SQL NULL this should be 0; remember
207
 
                                also to set the NULL bit in the MySQL record
208
 
                                header! */
209
 
{
210
 
        /* MySQL might assume the field is set to zero except the length and
211
 
        the pointer fields */
212
 
 
213
 
        memset(dest, '\0', col_len);
214
 
 
215
 
        /* In dest there are 1 - 4 bytes reserved for the BLOB length,
216
 
        and after that 8 bytes reserved for the pointer to the data.
217
 
        In 32-bit architectures we only use the first 4 bytes of the pointer
218
 
        slot. */
219
 
 
220
 
        ut_a(col_len - 8 > 1 || len < 256);
221
 
        ut_a(col_len - 8 > 2 || len < 256 * 256);
222
 
        ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
223
 
 
224
 
        mach_write_to_n_little_endian(dest, col_len - 8, len);
225
 
 
226
 
        memcpy(dest + col_len - 8, &data, sizeof data);
227
 
}
228
 
 
229
 
/*******************************************************************//**
230
 
Reads a reference to a BLOB in the MySQL format.
231
 
@return pointer to BLOB data */
232
 
UNIV_INTERN
233
 
const byte*
234
 
row_mysql_read_blob_ref(
235
 
/*====================*/
236
 
        ulint*          len,            /*!< out: BLOB length */
237
 
        const byte*     ref,            /*!< in: BLOB reference in the
238
 
                                        MySQL format */
239
 
        ulint           col_len)        /*!< in: BLOB reference length
240
 
                                        (not BLOB length) */
241
 
{
242
 
        byte*   data;
243
 
 
244
 
        *len = mach_read_from_n_little_endian(ref, col_len - 8);
245
 
 
246
 
        memcpy(&data, ref + col_len - 8, sizeof data);
247
 
 
248
 
        return(data);
249
 
}
250
 
 
251
 
/**************************************************************//**
252
 
Pad a column with spaces. */
253
 
UNIV_INTERN
254
 
void
255
 
row_mysql_pad_col(
256
 
/*==============*/
257
 
        ulint   mbminlen,       /*!< in: minimum size of a character,
258
 
                                in bytes */
259
 
        byte*   pad,            /*!< out: padded buffer */
260
 
        ulint   len)            /*!< in: number of bytes to pad */
261
 
{
262
 
        const byte*     pad_end;
263
 
 
264
 
        switch (UNIV_EXPECT(mbminlen, 1)) {
265
 
        default:
266
 
                ut_error;
267
 
        case 1:
268
 
                /* space=0x20 */
269
 
                memset(pad, 0x20, len);
270
 
                break;
271
 
        case 2:
272
 
                /* space=0x0020 */
273
 
                pad_end = pad + len;
274
 
                ut_a(!(len % 2));
275
 
                do {
276
 
                        *pad++ = 0x00;
277
 
                        *pad++ = 0x20;
278
 
                } while (pad < pad_end);
279
 
                break;
280
 
        case 4:
281
 
                /* space=0x00000020 */
282
 
                pad_end = pad + len;
283
 
                ut_a(!(len % 4));
284
 
                do {
285
 
                        *pad++ = 0x00;
286
 
                        *pad++ = 0x00;
287
 
                        *pad++ = 0x00;
288
 
                        *pad++ = 0x20;
289
 
                } while (pad < pad_end);
290
 
                break;
291
 
        }
292
 
}
293
 
 
294
 
/**************************************************************//**
295
 
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
296
 
The counterpart of this function is row_sel_field_store_in_mysql_format() in
297
 
row0sel.c.
298
 
@return up to which byte we used buf in the conversion */
299
 
UNIV_INTERN
300
 
byte*
301
 
row_mysql_store_col_in_innobase_format(
302
 
/*===================================*/
303
 
        dfield_t*       dfield,         /*!< in/out: dfield where dtype
304
 
                                        information must be already set when
305
 
                                        this function is called! */
306
 
        byte*           buf,            /*!< in/out: buffer for a converted
307
 
                                        integer value; this must be at least
308
 
                                        col_len long then! */
309
 
        ibool           row_format_col, /*!< TRUE if the mysql_data is from
310
 
                                        a MySQL row, FALSE if from a MySQL
311
 
                                        key value;
312
 
                                        in MySQL, a true VARCHAR storage
313
 
                                        format differs in a row and in a
314
 
                                        key value: in a key value the length
315
 
                                        is always stored in 2 bytes! */
316
 
        const byte*     mysql_data,     /*!< in: MySQL column value, not
317
 
                                        SQL NULL; NOTE that dfield may also
318
 
                                        get a pointer to mysql_data,
319
 
                                        therefore do not discard this as long
320
 
                                        as dfield is used! */
321
 
        ulint           col_len,        /*!< in: MySQL column length; NOTE that
322
 
                                        this is the storage length of the
323
 
                                        column in the MySQL format row, not
324
 
                                        necessarily the length of the actual
325
 
                                        payload data; if the column is a true
326
 
                                        VARCHAR then this is irrelevant */
327
 
        ulint           comp)           /*!< in: nonzero=compact format */
328
 
{
329
 
        const byte*     ptr     = mysql_data;
330
 
        const dtype_t*  dtype;
331
 
        ulint           type;
332
 
        ulint           lenlen;
333
 
 
334
 
        dtype = dfield_get_type(dfield);
335
 
 
336
 
        type = dtype->mtype;
337
 
 
338
 
        if (type == DATA_INT) {
339
 
                /* Store integer data in Innobase in a big-endian format,
340
 
                sign bit negated if the data is a signed integer. In MySQL,
341
 
                integers are stored in a little-endian format. */
342
 
 
343
 
                byte*   p = buf + col_len;
344
 
 
345
 
                for (;;) {
346
 
                        p--;
347
 
                        *p = *mysql_data;
348
 
                        if (p == buf) {
349
 
                                break;
350
 
                        }
351
 
                        mysql_data++;
352
 
                }
353
 
 
354
 
                if (!(dtype->prtype & DATA_UNSIGNED)) {
355
 
 
356
 
                        *buf ^= 128;
357
 
                }
358
 
 
359
 
                ptr = buf;
360
 
                buf += col_len;
361
 
        } else if ((type == DATA_VARCHAR
362
 
                    || type == DATA_VARMYSQL
363
 
                    || type == DATA_BINARY)) {
364
 
 
365
 
                if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
366
 
                        /* The length of the actual data is stored to 1 or 2
367
 
                        bytes at the start of the field */
368
 
 
369
 
                        if (row_format_col) {
370
 
                                if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
371
 
                                        lenlen = 2;
372
 
                                } else {
373
 
                                        lenlen = 1;
374
 
                                }
375
 
                        } else {
376
 
                                /* In a MySQL key value, lenlen is always 2 */
377
 
                                lenlen = 2;
378
 
                        }
379
 
 
380
 
                        ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
381
 
                                                          lenlen);
382
 
                } else {
383
 
                        /* Remove trailing spaces from old style VARCHAR
384
 
                        columns. */
385
 
 
386
 
                        /* Handle Unicode strings differently. */
387
 
                        ulint   mbminlen        = dtype_get_mbminlen(dtype);
388
 
 
389
 
                        ptr = mysql_data;
390
 
 
391
 
                        switch (mbminlen) {
392
 
                        default:
393
 
                                ut_error;
394
 
                        case 4:
395
 
                                /* space=0x00000020 */
396
 
                                /* Trim "half-chars", just in case. */
397
 
                                col_len &= ~3;
398
 
 
399
 
                                while (col_len >= 4
400
 
                                       && ptr[col_len - 4] == 0x00
401
 
                                       && ptr[col_len - 3] == 0x00
402
 
                                       && ptr[col_len - 2] == 0x00
403
 
                                       && ptr[col_len - 1] == 0x20) {
404
 
                                        col_len -= 4;
405
 
                                }
406
 
                                break;
407
 
                        case 2:
408
 
                                /* space=0x0020 */
409
 
                                /* Trim "half-chars", just in case. */
410
 
                                col_len &= ~1;
411
 
 
412
 
                                while (col_len >= 2 && ptr[col_len - 2] == 0x00
413
 
                                       && ptr[col_len - 1] == 0x20) {
414
 
                                        col_len -= 2;
415
 
                                }
416
 
                                break;
417
 
                        case 1:
418
 
                                /* space=0x20 */
419
 
                                while (col_len > 0
420
 
                                       && ptr[col_len - 1] == 0x20) {
421
 
                                        col_len--;
422
 
                                }
423
 
                        }
424
 
                }
425
 
        } else if (comp && type == DATA_MYSQL
426
 
                   && dtype_get_mbminlen(dtype) == 1
427
 
                   && dtype_get_mbmaxlen(dtype) > 1) {
428
 
                /* In some cases we strip trailing spaces from UTF-8 and other
429
 
                multibyte charsets, from FIXED-length CHAR columns, to save
430
 
                space. UTF-8 would otherwise normally use 3 * the string length
431
 
                bytes to store an ASCII string! */
432
 
 
433
 
                /* We assume that this CHAR field is encoded in a
434
 
                variable-length character set where spaces have
435
 
                1:1 correspondence to 0x20 bytes, such as UTF-8.
436
 
 
437
 
                Consider a CHAR(n) field, a field of n characters.
438
 
                It will contain between n * mbminlen and n * mbmaxlen bytes.
439
 
                We will try to truncate it to n bytes by stripping
440
 
                space padding.  If the field contains single-byte
441
 
                characters only, it will be truncated to n characters.
442
 
                Consider a CHAR(5) field containing the string ".a   "
443
 
                where "." denotes a 3-byte character represented by
444
 
                the bytes "$%&".  After our stripping, the string will
445
 
                be stored as "$%&a " (5 bytes).  The string ".abc "
446
 
                will be stored as "$%&abc" (6 bytes).
447
 
 
448
 
                The space padding will be restored in row0sel.c, function
449
 
                row_sel_field_store_in_mysql_format(). */
450
 
 
451
 
                ulint           n_chars;
452
 
 
453
 
                ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
454
 
 
455
 
                n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
456
 
 
457
 
                /* Strip space padding. */
458
 
                while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
459
 
                        col_len--;
460
 
                }
461
 
        } else if (type == DATA_BLOB && row_format_col) {
462
 
 
463
 
                ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
464
 
        }
465
 
 
466
 
        dfield_set_data(dfield, ptr, col_len);
467
 
 
468
 
        return(buf);
469
 
}
470
 
 
471
 
/**************************************************************//**
472
 
Convert a row in the MySQL format to a row in the Innobase format. Note that
473
 
the function to convert a MySQL format key value to an InnoDB dtuple is
474
 
row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
475
 
static
476
 
void
477
 
row_mysql_convert_row_to_innobase(
478
 
/*==============================*/
479
 
        dtuple_t*       row,            /*!< in/out: Innobase row where the
480
 
                                        field type information is already
481
 
                                        copied there! */
482
 
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct where template
483
 
                                        must be of type ROW_MYSQL_WHOLE_ROW */
484
 
        byte*           mysql_rec)      /*!< in: row in the MySQL format;
485
 
                                        NOTE: do not discard as long as
486
 
                                        row is used, as row may contain
487
 
                                        pointers to this record! */
488
 
{
489
 
        const mysql_row_templ_t*templ;
490
 
        dfield_t*               dfield;
491
 
        ulint                   i;
492
 
 
493
 
        ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
494
 
        ut_ad(prebuilt->mysql_template);
495
 
 
496
 
        for (i = 0; i < prebuilt->n_template; i++) {
497
 
 
498
 
                templ = prebuilt->mysql_template + i;
499
 
                dfield = dtuple_get_nth_field(row, i);
500
 
 
501
 
                if (templ->mysql_null_bit_mask != 0) {
502
 
                        /* Column may be SQL NULL */
503
 
 
504
 
                        if (mysql_rec[templ->mysql_null_byte_offset]
505
 
                            & (byte) (templ->mysql_null_bit_mask)) {
506
 
 
507
 
                                /* It is SQL NULL */
508
 
 
509
 
                                dfield_set_null(dfield);
510
 
 
511
 
                                goto next_column;
512
 
                        }
513
 
                }
514
 
 
515
 
                row_mysql_store_col_in_innobase_format(
516
 
                        dfield,
517
 
                        prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
518
 
                        TRUE, /* MySQL row format data */
519
 
                        mysql_rec + templ->mysql_col_offset,
520
 
                        templ->mysql_col_len,
521
 
                        dict_table_is_comp(prebuilt->table));
522
 
next_column:
523
 
                ;
524
 
        }
525
 
}
526
 
 
527
 
/****************************************************************//**
528
 
Handles user errors and lock waits detected by the database engine.
529
 
@return TRUE if it was a lock wait and we should continue running the
530
 
query thread and in that case the thr is ALREADY in the running state. */
531
 
UNIV_INTERN
532
 
ibool
533
 
row_mysql_handle_errors(
534
 
/*====================*/
535
 
        ulint*          new_err,/*!< out: possible new error encountered in
536
 
                                lock wait, or if no new error, the value
537
 
                                of trx->error_state at the entry of this
538
 
                                function */
539
 
        trx_t*          trx,    /*!< in: transaction */
540
 
        que_thr_t*      thr,    /*!< in: query thread */
541
 
        trx_savept_t*   savept) /*!< in: savepoint or NULL */
542
 
{
543
 
        ulint   err;
544
 
 
545
 
handle_new_error:
546
 
        err = trx->error_state;
547
 
 
548
 
        ut_a(err != DB_SUCCESS);
549
 
 
550
 
        trx->error_state = DB_SUCCESS;
551
 
 
552
 
        switch (err) {
553
 
        case DB_LOCK_WAIT_TIMEOUT:
554
 
                if (row_rollback_on_timeout) {
555
 
                        trx_general_rollback_for_mysql(trx, NULL);
556
 
                        break;
557
 
                }
558
 
                /* fall through */
559
 
        case DB_DUPLICATE_KEY:
560
 
        case DB_FOREIGN_DUPLICATE_KEY:
561
 
        case DB_TOO_BIG_RECORD:
562
 
        case DB_ROW_IS_REFERENCED:
563
 
        case DB_NO_REFERENCED_ROW:
564
 
        case DB_CANNOT_ADD_CONSTRAINT:
565
 
        case DB_TOO_MANY_CONCURRENT_TRXS:
566
 
        case DB_OUT_OF_FILE_SPACE:
567
 
        case DB_INTERRUPTED:
568
 
                if (savept) {
569
 
                        /* Roll back the latest, possibly incomplete
570
 
                        insertion or update */
571
 
 
572
 
                        trx_general_rollback_for_mysql(trx, savept);
573
 
                }
574
 
                /* MySQL will roll back the latest SQL statement */
575
 
                break;
576
 
        case DB_LOCK_WAIT:
577
 
                srv_suspend_mysql_thread(thr);
578
 
 
579
 
                if (trx->error_state != DB_SUCCESS) {
580
 
                        que_thr_stop_for_mysql(thr);
581
 
 
582
 
                        goto handle_new_error;
583
 
                }
584
 
 
585
 
                *new_err = err;
586
 
 
587
 
                return(TRUE);
588
 
 
589
 
        case DB_DEADLOCK:
590
 
        case DB_LOCK_TABLE_FULL:
591
 
                /* Roll back the whole transaction; this resolution was added
592
 
                to version 3.23.43 */
593
 
 
594
 
                trx_general_rollback_for_mysql(trx, NULL);
595
 
                break;
596
 
 
597
 
        case DB_MUST_GET_MORE_FILE_SPACE:
598
 
                fputs("InnoDB: The database cannot continue"
599
 
                      " operation because of\n"
600
 
                      "InnoDB: lack of space. You must add"
601
 
                      " a new data file to\n"
602
 
                      "InnoDB: my.cnf and restart the database.\n", stderr);
603
 
 
604
 
                exit(1);
605
 
 
606
 
        case DB_CORRUPTION:
607
 
                fputs("InnoDB: We detected index corruption"
608
 
                      " in an InnoDB type table.\n"
609
 
                      "InnoDB: You have to dump + drop + reimport"
610
 
                      " the table or, in\n"
611
 
                      "InnoDB: a case of widespread corruption,"
612
 
                      " dump all InnoDB\n"
613
 
                      "InnoDB: tables and recreate the"
614
 
                      " whole InnoDB tablespace.\n"
615
 
                      "InnoDB: If the mysqld server crashes"
616
 
                      " after the startup or when\n"
617
 
                      "InnoDB: you dump the tables, look at\n"
618
 
                      "InnoDB: " REFMAN "forcing-recovery.html"
619
 
                      " for help.\n", stderr);
620
 
                break;
621
 
        case DB_FOREIGN_EXCEED_MAX_CASCADE:
622
 
                fprintf(stderr, "InnoDB: Cannot delete/update rows with"
623
 
                        " cascading foreign key constraints that exceed max"
624
 
                        " depth of %lu\n"
625
 
                        "Please drop excessive foreign constraints"
626
 
                        " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
627
 
                break;
628
 
        default:
629
 
                fprintf(stderr, "InnoDB: unknown error code %lu\n",
630
 
                        (ulong) err);
631
 
                ut_error;
632
 
        }
633
 
 
634
 
        if (trx->error_state != DB_SUCCESS) {
635
 
                *new_err = trx->error_state;
636
 
        } else {
637
 
                *new_err = err;
638
 
        }
639
 
 
640
 
        trx->error_state = DB_SUCCESS;
641
 
 
642
 
        return(FALSE);
643
 
}
644
 
 
645
 
/********************************************************************//**
646
 
Create a prebuilt struct for a MySQL table handle.
647
 
@return own: a prebuilt struct */
648
 
UNIV_INTERN
649
 
row_prebuilt_t*
650
 
row_create_prebuilt(
651
 
/*================*/
652
 
        dict_table_t*   table)  /*!< in: Innobase table handle */
653
 
{
654
 
        row_prebuilt_t* prebuilt;
655
 
        mem_heap_t*     heap;
656
 
        dict_index_t*   clust_index;
657
 
        dtuple_t*       ref;
658
 
        ulint           ref_len;
659
 
 
660
 
        heap = mem_heap_create(sizeof *prebuilt + 128);
661
 
 
662
 
        prebuilt = static_cast<row_prebuilt_t *>(mem_heap_zalloc(heap, sizeof *prebuilt));
663
 
 
664
 
        prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
665
 
        prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
666
 
 
667
 
        prebuilt->table = table;
668
 
 
669
 
        prebuilt->sql_stat_start = TRUE;
670
 
        prebuilt->heap = heap;
671
 
 
672
 
        prebuilt->pcur = btr_pcur_create_for_mysql();
673
 
        prebuilt->clust_pcur = btr_pcur_create_for_mysql();
674
 
 
675
 
        prebuilt->select_lock_type = LOCK_NONE;
676
 
        prebuilt->stored_select_lock_type = 99999999;
677
 
        UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
678
 
                         sizeof prebuilt->stored_select_lock_type);
679
 
 
680
 
        prebuilt->search_tuple = dtuple_create(
681
 
                heap, 2 * dict_table_get_n_cols(table));
682
 
 
683
 
        clust_index = dict_table_get_first_index(table);
684
 
 
685
 
        /* Make sure that search_tuple is long enough for clustered index */
686
 
        ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
687
 
 
688
 
        ref_len = dict_index_get_n_unique(clust_index);
689
 
 
690
 
        ref = dtuple_create(heap, ref_len);
691
 
 
692
 
        dict_index_copy_types(ref, clust_index, ref_len);
693
 
 
694
 
        prebuilt->clust_ref = ref;
695
 
 
696
 
        prebuilt->autoinc_error = 0;
697
 
        prebuilt->autoinc_offset = 0;
698
 
 
699
 
        /* Default to 1, we will set the actual value later in 
700
 
        ha_innobase::get_auto_increment(). */
701
 
        prebuilt->autoinc_increment = 1;
702
 
 
703
 
        prebuilt->autoinc_last_value = 0;
704
 
 
705
 
        return(prebuilt);
706
 
}
707
 
 
708
 
/********************************************************************//**
709
 
Free a prebuilt struct for a MySQL table handle. */
710
 
UNIV_INTERN
711
 
void
712
 
row_prebuilt_free(
713
 
/*==============*/
714
 
        row_prebuilt_t* prebuilt,       /*!< in, own: prebuilt struct */
715
 
        ibool           dict_locked)    /*!< in: TRUE=data dictionary locked */
716
 
{
717
 
        ulint   i;
718
 
 
719
 
        if (UNIV_UNLIKELY
720
 
            (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
721
 
             || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
722
 
 
723
 
                fprintf(stderr,
724
 
                        "InnoDB: Error: trying to free a corrupt\n"
725
 
                        "InnoDB: table handle. Magic n %lu,"
726
 
                        " magic n2 %lu, table name ",
727
 
                        (ulong) prebuilt->magic_n,
728
 
                        (ulong) prebuilt->magic_n2);
729
 
                ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
730
 
                putc('\n', stderr);
731
 
 
732
 
                mem_analyze_corruption(prebuilt);
733
 
 
734
 
                ut_error;
735
 
        }
736
 
 
737
 
        prebuilt->magic_n = ROW_PREBUILT_FREED;
738
 
        prebuilt->magic_n2 = ROW_PREBUILT_FREED;
739
 
 
740
 
        btr_pcur_free_for_mysql(prebuilt->pcur);
741
 
        btr_pcur_free_for_mysql(prebuilt->clust_pcur);
742
 
 
743
 
        if (prebuilt->mysql_template) {
744
 
                mem_free(prebuilt->mysql_template);
745
 
        }
746
 
 
747
 
        if (prebuilt->ins_graph) {
748
 
                que_graph_free_recursive(prebuilt->ins_graph);
749
 
        }
750
 
 
751
 
        if (prebuilt->sel_graph) {
752
 
                que_graph_free_recursive(prebuilt->sel_graph);
753
 
        }
754
 
 
755
 
        if (prebuilt->upd_graph) {
756
 
                que_graph_free_recursive(prebuilt->upd_graph);
757
 
        }
758
 
 
759
 
        if (prebuilt->blob_heap) {
760
 
                mem_heap_free(prebuilt->blob_heap);
761
 
        }
762
 
 
763
 
        if (prebuilt->old_vers_heap) {
764
 
                mem_heap_free(prebuilt->old_vers_heap);
765
 
        }
766
 
 
767
 
        for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
768
 
                if (prebuilt->fetch_cache[i] != NULL) {
769
 
 
770
 
                        if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
771
 
                                     (prebuilt->fetch_cache[i]) - 4))
772
 
                            || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
773
 
                                        (prebuilt->fetch_cache[i])
774
 
                                        + prebuilt->mysql_row_len))) {
775
 
                                fputs("InnoDB: Error: trying to free"
776
 
                                      " a corrupt fetch buffer.\n", stderr);
777
 
 
778
 
                                mem_analyze_corruption(
779
 
                                        prebuilt->fetch_cache[i]);
780
 
 
781
 
                                ut_error;
782
 
                        }
783
 
 
784
 
                        mem_free((prebuilt->fetch_cache[i]) - 4);
785
 
                }
786
 
        }
787
 
 
788
 
        dict_table_decrement_handle_count(prebuilt->table, dict_locked);
789
 
 
790
 
        mem_heap_free(prebuilt->heap);
791
 
}
792
 
 
793
 
/*********************************************************************//**
794
 
Updates the transaction pointers in query graphs stored in the prebuilt
795
 
struct. */
796
 
UNIV_INTERN
797
 
void
798
 
row_update_prebuilt_trx(
799
 
/*====================*/
800
 
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct
801
 
                                        in MySQL handle */
802
 
        trx_t*          trx)            /*!< in: transaction handle */
803
 
{
804
 
        if (trx->magic_n != TRX_MAGIC_N) {
805
 
                fprintf(stderr,
806
 
                        "InnoDB: Error: trying to use a corrupt\n"
807
 
                        "InnoDB: trx handle. Magic n %lu\n",
808
 
                        (ulong) trx->magic_n);
809
 
 
810
 
                mem_analyze_corruption(trx);
811
 
 
812
 
                ut_error;
813
 
        }
814
 
 
815
 
        if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
816
 
                fprintf(stderr,
817
 
                        "InnoDB: Error: trying to use a corrupt\n"
818
 
                        "InnoDB: table handle. Magic n %lu, table name ",
819
 
                        (ulong) prebuilt->magic_n);
820
 
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
821
 
                putc('\n', stderr);
822
 
 
823
 
                mem_analyze_corruption(prebuilt);
824
 
 
825
 
                ut_error;
826
 
        }
827
 
 
828
 
        prebuilt->trx = trx;
829
 
 
830
 
        if (prebuilt->ins_graph) {
831
 
                prebuilt->ins_graph->trx = trx;
832
 
        }
833
 
 
834
 
        if (prebuilt->upd_graph) {
835
 
                prebuilt->upd_graph->trx = trx;
836
 
        }
837
 
 
838
 
        if (prebuilt->sel_graph) {
839
 
                prebuilt->sel_graph->trx = trx;
840
 
        }
841
 
}
842
 
 
843
 
dtuple_t* row_get_prebuilt_insert_row(row_prebuilt_t*   prebuilt);
844
 
 
845
 
/*********************************************************************//**
846
 
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
847
 
has not yet been built in the prebuilt struct, then this function first
848
 
builds it.
849
 
@return prebuilt dtuple; the column type information is also set in it */
850
 
dtuple_t*
851
 
row_get_prebuilt_insert_row(
852
 
/*========================*/
853
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
854
 
                                        handle */
855
 
{
856
 
        ins_node_t*     node;
857
 
        dtuple_t*       row;
858
 
        dict_table_t*   table   = prebuilt->table;
859
 
 
860
 
        ut_ad(prebuilt && table && prebuilt->trx);
861
 
 
862
 
        if (prebuilt->ins_node == NULL) {
863
 
 
864
 
                /* Not called before for this handle: create an insert node
865
 
                and query graph to the prebuilt struct */
866
 
 
867
 
                node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
868
 
 
869
 
                prebuilt->ins_node = node;
870
 
 
871
 
                if (prebuilt->ins_upd_rec_buff == NULL) {
872
 
                        prebuilt->ins_upd_rec_buff = static_cast<byte *>(mem_heap_alloc(
873
 
                                prebuilt->heap, prebuilt->mysql_row_len));
874
 
                }
875
 
 
876
 
                row = dtuple_create(prebuilt->heap,
877
 
                                    dict_table_get_n_cols(table));
878
 
 
879
 
                dict_table_copy_types(row, table);
880
 
 
881
 
                ins_node_set_new_row(node, row);
882
 
 
883
 
                prebuilt->ins_graph = static_cast<que_fork_t *>(que_node_get_parent(
884
 
                        pars_complete_graph_for_exec(node,
885
 
                                                     prebuilt->trx,
886
 
                                                     prebuilt->heap)));
887
 
                prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
888
 
        }
889
 
 
890
 
        return(prebuilt->ins_node->row);
891
 
}
892
 
 
893
 
/*********************************************************************//**
894
 
Updates the table modification counter and calculates new estimates
895
 
for table and index statistics if necessary. */
896
 
UNIV_INLINE
897
 
void
898
 
row_update_statistics_if_needed(
899
 
/*============================*/
900
 
        dict_table_t*   table)  /*!< in: table */
901
 
{
902
 
        ulint   counter;
903
 
 
904
 
        counter = table->stat_modified_counter;
905
 
 
906
 
        table->stat_modified_counter = counter + 1;
907
 
 
908
 
        /* Calculate new statistics if 1 / 16 of table has been modified
909
 
        since the last time a statistics batch was run, or if
910
 
        stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
911
 
        We calculate statistics at most every 16th round, since we may have
912
 
        a counter table which is very small and updated very often. */
913
 
 
914
 
        if (counter > 2000000000
915
 
            || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
916
 
 
917
 
                dict_update_statistics(table, FALSE /* update even if stats
918
 
                                                    are initialized */);
919
 
        }
920
 
}
921
 
 
922
 
/*********************************************************************//**
923
 
Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
924
 
function should be called at the the end of an SQL statement, by the
925
 
connection thread that owns the transaction (trx->mysql_thd). */
926
 
UNIV_INTERN
927
 
void
928
 
row_unlock_table_autoinc_for_mysql(
929
 
/*===============================*/
930
 
        trx_t*  trx)    /*!< in/out: transaction */
931
 
{
932
 
        if (lock_trx_holds_autoinc_locks(trx)) {
933
 
                mutex_enter(&kernel_mutex);
934
 
 
935
 
                lock_release_autoinc_locks(trx);
936
 
 
937
 
                mutex_exit(&kernel_mutex);
938
 
        }
939
 
}
940
 
 
941
 
/*********************************************************************//**
942
 
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
943
 
AUTO_INC lock gives exclusive access to the auto-inc counter of the
944
 
table. The lock is reserved only for the duration of an SQL statement.
945
 
It is not compatible with another AUTO_INC or exclusive lock on the
946
 
table.
947
 
@return error code or DB_SUCCESS */
948
 
UNIV_INTERN
949
 
int
950
 
row_lock_table_autoinc_for_mysql(
951
 
/*=============================*/
952
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in the MySQL
953
 
                                        table handle */
954
 
{
955
 
        trx_t*                  trx     = prebuilt->trx;
956
 
        ins_node_t*             node    = prebuilt->ins_node;
957
 
        const dict_table_t*     table   = prebuilt->table;
958
 
        que_thr_t*              thr;
959
 
        ulint                   err;
960
 
        ibool                   was_lock_wait;
961
 
 
962
 
        ut_ad(trx);
963
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
964
 
 
965
 
        /* If we already hold an AUTOINC lock on the table then do nothing.
966
 
        Note: We peek at the value of the current owner without acquiring
967
 
        the kernel mutex. **/
968
 
        if (trx == table->autoinc_trx) {
969
 
 
970
 
                return(DB_SUCCESS);
971
 
        }
972
 
 
973
 
        trx->op_info = "setting auto-inc lock";
974
 
 
975
 
        if (node == NULL) {
976
 
                row_get_prebuilt_insert_row(prebuilt);
977
 
                node = prebuilt->ins_node;
978
 
        }
979
 
 
980
 
        /* We use the insert query graph as the dummy graph needed
981
 
        in the lock module call */
982
 
 
983
 
        thr = que_fork_get_first_thr(prebuilt->ins_graph);
984
 
 
985
 
        que_thr_move_to_run_state_for_mysql(thr, trx);
986
 
 
987
 
run_again:
988
 
        thr->run_node = node;
989
 
        thr->prev_node = node;
990
 
 
991
 
        /* It may be that the current session has not yet started
992
 
        its transaction, or it has been committed: */
993
 
 
994
 
        trx_start_if_not_started(trx);
995
 
 
996
 
        err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
997
 
 
998
 
        trx->error_state = err;
999
 
 
1000
 
        if (err != DB_SUCCESS) {
1001
 
                que_thr_stop_for_mysql(thr);
1002
 
 
1003
 
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1004
 
 
1005
 
                if (was_lock_wait) {
1006
 
                        goto run_again;
1007
 
                }
1008
 
 
1009
 
                trx->op_info = "";
1010
 
 
1011
 
                return((int) err);
1012
 
        }
1013
 
 
1014
 
        que_thr_stop_for_mysql_no_error(thr, trx);
1015
 
 
1016
 
        trx->op_info = "";
1017
 
 
1018
 
        return((int) err);
1019
 
}
1020
 
 
1021
 
/*********************************************************************//**
1022
 
Sets a table lock on the table mentioned in prebuilt.
1023
 
@return error code or DB_SUCCESS */
1024
 
UNIV_INTERN
1025
 
int
1026
 
row_lock_table_for_mysql(
1027
 
/*=====================*/
1028
 
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct in the MySQL
1029
 
                                        table handle */
1030
 
        dict_table_t*   table,          /*!< in: table to lock, or NULL
1031
 
                                        if prebuilt->table should be
1032
 
                                        locked as
1033
 
                                        prebuilt->select_lock_type */
1034
 
        ulint           mode)           /*!< in: lock mode of table
1035
 
                                        (ignored if table==NULL) */
1036
 
{
1037
 
        trx_t*          trx             = prebuilt->trx;
1038
 
        que_thr_t*      thr;
1039
 
        ulint           err;
1040
 
        ibool           was_lock_wait;
1041
 
 
1042
 
        ut_ad(trx);
1043
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1044
 
 
1045
 
        trx->op_info = "setting table lock";
1046
 
 
1047
 
        if (prebuilt->sel_graph == NULL) {
1048
 
                /* Build a dummy select query graph */
1049
 
                row_prebuild_sel_graph(prebuilt);
1050
 
        }
1051
 
 
1052
 
        /* We use the select query graph as the dummy graph needed
1053
 
        in the lock module call */
1054
 
 
1055
 
        thr = que_fork_get_first_thr(prebuilt->sel_graph);
1056
 
 
1057
 
        que_thr_move_to_run_state_for_mysql(thr, trx);
1058
 
 
1059
 
run_again:
1060
 
        thr->run_node = thr;
1061
 
        thr->prev_node = thr->common.parent;
1062
 
 
1063
 
        /* It may be that the current session has not yet started
1064
 
        its transaction, or it has been committed: */
1065
 
 
1066
 
        trx_start_if_not_started(trx);
1067
 
 
1068
 
        if (table) {
1069
 
                err = lock_table(0, table, static_cast<lock_mode>(mode), thr);
1070
 
        } else {
1071
 
                err = lock_table(0, prebuilt->table,
1072
 
                                 static_cast<lock_mode>(prebuilt->select_lock_type), thr);
1073
 
        }
1074
 
 
1075
 
        trx->error_state = err;
1076
 
 
1077
 
        if (err != DB_SUCCESS) {
1078
 
                que_thr_stop_for_mysql(thr);
1079
 
 
1080
 
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1081
 
 
1082
 
                if (was_lock_wait) {
1083
 
                        goto run_again;
1084
 
                }
1085
 
 
1086
 
                trx->op_info = "";
1087
 
 
1088
 
                return((int) err);
1089
 
        }
1090
 
 
1091
 
        que_thr_stop_for_mysql_no_error(thr, trx);
1092
 
 
1093
 
        trx->op_info = "";
1094
 
 
1095
 
        return((int) err);
1096
 
}
1097
 
 
1098
 
/*********************************************************************//**
1099
 
Does an insert for MySQL.
1100
 
@return error code or DB_SUCCESS */
1101
 
UNIV_INTERN
1102
 
int
1103
 
row_insert_for_mysql(
1104
 
/*=================*/
1105
 
        byte*           mysql_rec,      /*!< in: row in the MySQL format */
1106
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
1107
 
                                        handle */
1108
 
{
1109
 
        trx_savept_t    savept;
1110
 
        que_thr_t*      thr;
1111
 
        ulint           err;
1112
 
        ibool           was_lock_wait;
1113
 
        trx_t*          trx             = prebuilt->trx;
1114
 
        ins_node_t*     node            = prebuilt->ins_node;
1115
 
 
1116
 
        ut_ad(trx);
1117
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1118
 
 
1119
 
        if (prebuilt->table->ibd_file_missing) {
1120
 
                ut_print_timestamp(stderr);
1121
 
                fprintf(stderr, "  InnoDB: Error:\n"
1122
 
                        "InnoDB: MySQL is trying to use a table handle"
1123
 
                        " but the .ibd file for\n"
1124
 
                        "InnoDB: table %s does not exist.\n"
1125
 
                        "InnoDB: Have you deleted the .ibd file"
1126
 
                        " from the database directory under\n"
1127
 
                        "InnoDB: the MySQL datadir, or have you"
1128
 
                        " used DISCARD TABLESPACE?\n"
1129
 
                        "InnoDB: Look from\n"
1130
 
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1131
 
                        "InnoDB: how you can resolve the problem.\n",
1132
 
                        prebuilt->table->name);
1133
 
                return(DB_ERROR);
1134
 
        }
1135
 
 
1136
 
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1137
 
                fprintf(stderr,
1138
 
                        "InnoDB: Error: trying to free a corrupt\n"
1139
 
                        "InnoDB: table handle. Magic n %lu, table name ",
1140
 
                        (ulong) prebuilt->magic_n);
1141
 
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1142
 
                putc('\n', stderr);
1143
 
 
1144
 
                mem_analyze_corruption(prebuilt);
1145
 
 
1146
 
                ut_error;
1147
 
        }
1148
 
 
1149
 
        if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1150
 
                fputs("InnoDB: A new raw disk partition was initialized or\n"
1151
 
                      "InnoDB: innodb_force_recovery is on: we do not allow\n"
1152
 
                      "InnoDB: database modifications by the user. Shut down\n"
1153
 
                      "InnoDB: mysqld and edit my.cnf so that"
1154
 
                      " newraw is replaced\n"
1155
 
                      "InnoDB: with raw, and innodb_force_... is removed.\n",
1156
 
                      stderr);
1157
 
 
1158
 
                return(DB_ERROR);
1159
 
        }
1160
 
 
1161
 
        trx->op_info = "inserting";
1162
 
 
1163
 
        row_mysql_delay_if_needed();
1164
 
 
1165
 
        trx_start_if_not_started(trx);
1166
 
 
1167
 
        if (node == NULL) {
1168
 
                row_get_prebuilt_insert_row(prebuilt);
1169
 
                node = prebuilt->ins_node;
1170
 
        }
1171
 
 
1172
 
        row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1173
 
 
1174
 
        savept = trx_savept_take(trx);
1175
 
 
1176
 
        thr = que_fork_get_first_thr(prebuilt->ins_graph);
1177
 
 
1178
 
        if (prebuilt->sql_stat_start) {
1179
 
                node->state = INS_NODE_SET_IX_LOCK;
1180
 
                prebuilt->sql_stat_start = FALSE;
1181
 
        } else {
1182
 
                node->state = INS_NODE_ALLOC_ROW_ID;
1183
 
        }
1184
 
 
1185
 
        que_thr_move_to_run_state_for_mysql(thr, trx);
1186
 
 
1187
 
run_again:
1188
 
        thr->run_node = node;
1189
 
        thr->prev_node = node;
1190
 
 
1191
 
        row_ins_step(thr);
1192
 
 
1193
 
        err = trx->error_state;
1194
 
 
1195
 
        if (err != DB_SUCCESS) {
1196
 
                que_thr_stop_for_mysql(thr);
1197
 
 
1198
 
                /* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1199
 
 
1200
 
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1201
 
                                                        &savept);
1202
 
                thr->lock_state= QUE_THR_LOCK_NOLOCK;
1203
 
 
1204
 
                if (was_lock_wait) {
1205
 
                        goto run_again;
1206
 
                }
1207
 
 
1208
 
                trx->op_info = "";
1209
 
 
1210
 
                return((int) err);
1211
 
        }
1212
 
 
1213
 
        que_thr_stop_for_mysql_no_error(thr, trx);
1214
 
 
1215
 
        prebuilt->table->stat_n_rows++;
1216
 
 
1217
 
        srv_n_rows_inserted++;
1218
 
 
1219
 
        if (prebuilt->table->stat_n_rows == 0) {
1220
 
                /* Avoid wrap-over */
1221
 
                prebuilt->table->stat_n_rows--;
1222
 
        }
1223
 
 
1224
 
        row_update_statistics_if_needed(prebuilt->table);
1225
 
        trx->op_info = "";
1226
 
 
1227
 
        return((int) err);
1228
 
}
1229
 
 
1230
 
/*********************************************************************//**
1231
 
Builds a dummy query graph used in selects. */
1232
 
UNIV_INTERN
1233
 
void
1234
 
row_prebuild_sel_graph(
1235
 
/*===================*/
1236
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
1237
 
                                        handle */
1238
 
{
1239
 
        sel_node_t*     node;
1240
 
 
1241
 
        ut_ad(prebuilt && prebuilt->trx);
1242
 
 
1243
 
        if (prebuilt->sel_graph == NULL) {
1244
 
 
1245
 
                node = sel_node_create(prebuilt->heap);
1246
 
 
1247
 
                prebuilt->sel_graph = static_cast<que_fork_t *>(que_node_get_parent(
1248
 
                        pars_complete_graph_for_exec(node,
1249
 
                                                     prebuilt->trx,
1250
 
                                                     prebuilt->heap)));
1251
 
 
1252
 
                prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1253
 
        }
1254
 
}
1255
 
 
1256
 
/*********************************************************************//**
1257
 
Creates an query graph node of 'update' type to be used in the MySQL
1258
 
interface.
1259
 
@return own: update node */
1260
 
UNIV_INTERN
1261
 
upd_node_t*
1262
 
row_create_update_node_for_mysql(
1263
 
/*=============================*/
1264
 
        dict_table_t*   table,  /*!< in: table to update */
1265
 
        mem_heap_t*     heap)   /*!< in: mem heap from which allocated */
1266
 
{
1267
 
        upd_node_t*     node;
1268
 
 
1269
 
        node = upd_node_create(heap);
1270
 
 
1271
 
        node->in_mysql_interface = TRUE;
1272
 
        node->is_delete = FALSE;
1273
 
        node->searched_update = FALSE;
1274
 
        node->select = NULL;
1275
 
        node->pcur = btr_pcur_create_for_mysql();
1276
 
        node->table = table;
1277
 
 
1278
 
        node->update = upd_create(dict_table_get_n_cols(table), heap);
1279
 
 
1280
 
        node->update_n_fields = dict_table_get_n_cols(table);
1281
 
 
1282
 
        UT_LIST_INIT(node->columns);
1283
 
        node->has_clust_rec_x_lock = TRUE;
1284
 
        node->cmpl_info = 0;
1285
 
 
1286
 
        node->table_sym = NULL;
1287
 
        node->col_assign_list = NULL;
1288
 
 
1289
 
        return(node);
1290
 
}
1291
 
 
1292
 
/*********************************************************************//**
1293
 
Gets pointer to a prebuilt update vector used in updates. If the update
1294
 
graph has not yet been built in the prebuilt struct, then this function
1295
 
first builds it.
1296
 
@return prebuilt update vector */
1297
 
UNIV_INTERN
1298
 
upd_t*
1299
 
row_get_prebuilt_update_vector(
1300
 
/*===========================*/
1301
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
1302
 
                                        handle */
1303
 
{
1304
 
        dict_table_t*   table   = prebuilt->table;
1305
 
        upd_node_t*     node;
1306
 
 
1307
 
        ut_ad(prebuilt && table && prebuilt->trx);
1308
 
 
1309
 
        if (prebuilt->upd_node == NULL) {
1310
 
 
1311
 
                /* Not called before for this handle: create an update node
1312
 
                and query graph to the prebuilt struct */
1313
 
 
1314
 
                node = row_create_update_node_for_mysql(table, prebuilt->heap);
1315
 
 
1316
 
                prebuilt->upd_node = node;
1317
 
 
1318
 
                prebuilt->upd_graph = static_cast<que_fork_t *>(que_node_get_parent(
1319
 
                        pars_complete_graph_for_exec(node,
1320
 
                                                     prebuilt->trx,
1321
 
                                                     prebuilt->heap)));
1322
 
                prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1323
 
        }
1324
 
 
1325
 
        return(prebuilt->upd_node->update);
1326
 
}
1327
 
 
1328
 
/*********************************************************************//**
1329
 
Does an update or delete of a row for MySQL.
1330
 
@return error code or DB_SUCCESS */
1331
 
UNIV_INTERN
1332
 
int
1333
 
row_update_for_mysql(
1334
 
/*=================*/
1335
 
        byte*           mysql_rec,      /*!< in: the row to be updated, in
1336
 
                                        the MySQL format */
1337
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
1338
 
                                        handle */
1339
 
{
1340
 
        trx_savept_t    savept;
1341
 
        ulint           err;
1342
 
        que_thr_t*      thr;
1343
 
        ibool           was_lock_wait;
1344
 
        dict_index_t*   clust_index;
1345
 
        /*      ulint           ref_len; */
1346
 
        upd_node_t*     node;
1347
 
        dict_table_t*   table           = prebuilt->table;
1348
 
        trx_t*          trx             = prebuilt->trx;
1349
 
 
1350
 
        ut_ad(prebuilt && trx);
1351
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1352
 
        UT_NOT_USED(mysql_rec);
1353
 
 
1354
 
        if (prebuilt->table->ibd_file_missing) {
1355
 
                ut_print_timestamp(stderr);
1356
 
                fprintf(stderr, "  InnoDB: Error:\n"
1357
 
                        "InnoDB: MySQL is trying to use a table handle"
1358
 
                        " but the .ibd file for\n"
1359
 
                        "InnoDB: table %s does not exist.\n"
1360
 
                        "InnoDB: Have you deleted the .ibd file"
1361
 
                        " from the database directory under\n"
1362
 
                        "InnoDB: the MySQL datadir, or have you"
1363
 
                        " used DISCARD TABLESPACE?\n"
1364
 
                        "InnoDB: Look from\n"
1365
 
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1366
 
                        "InnoDB: how you can resolve the problem.\n",
1367
 
                        prebuilt->table->name);
1368
 
                return(DB_ERROR);
1369
 
        }
1370
 
 
1371
 
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1372
 
                fprintf(stderr,
1373
 
                        "InnoDB: Error: trying to free a corrupt\n"
1374
 
                        "InnoDB: table handle. Magic n %lu, table name ",
1375
 
                        (ulong) prebuilt->magic_n);
1376
 
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1377
 
                putc('\n', stderr);
1378
 
 
1379
 
                mem_analyze_corruption(prebuilt);
1380
 
 
1381
 
                ut_error;
1382
 
        }
1383
 
 
1384
 
        if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1385
 
                fputs("InnoDB: A new raw disk partition was initialized or\n"
1386
 
                      "InnoDB: innodb_force_recovery is on: we do not allow\n"
1387
 
                      "InnoDB: database modifications by the user. Shut down\n"
1388
 
                      "InnoDB: mysqld and edit my.cnf so that newraw"
1389
 
                      " is replaced\n"
1390
 
                      "InnoDB: with raw, and innodb_force_... is removed.\n",
1391
 
                      stderr);
1392
 
 
1393
 
                return(DB_ERROR);
1394
 
        }
1395
 
 
1396
 
        trx->op_info = "updating or deleting";
1397
 
 
1398
 
        row_mysql_delay_if_needed();
1399
 
 
1400
 
        trx_start_if_not_started(trx);
1401
 
 
1402
 
        node = prebuilt->upd_node;
1403
 
 
1404
 
        clust_index = dict_table_get_first_index(table);
1405
 
 
1406
 
        if (prebuilt->pcur->btr_cur.index == clust_index) {
1407
 
                btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1408
 
        } else {
1409
 
                btr_pcur_copy_stored_position(node->pcur,
1410
 
                                              prebuilt->clust_pcur);
1411
 
        }
1412
 
 
1413
 
        ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1414
 
 
1415
 
        /* MySQL seems to call rnd_pos before updating each row it
1416
 
        has cached: we can get the correct cursor position from
1417
 
        prebuilt->pcur; NOTE that we cannot build the row reference
1418
 
        from mysql_rec if the clustered index was automatically
1419
 
        generated for the table: MySQL does not know anything about
1420
 
        the row id used as the clustered index key */
1421
 
 
1422
 
        savept = trx_savept_take(trx);
1423
 
 
1424
 
        thr = que_fork_get_first_thr(prebuilt->upd_graph);
1425
 
 
1426
 
        node->state = UPD_NODE_UPDATE_CLUSTERED;
1427
 
 
1428
 
        ut_ad(!prebuilt->sql_stat_start);
1429
 
 
1430
 
        que_thr_move_to_run_state_for_mysql(thr, trx);
1431
 
 
1432
 
run_again:
1433
 
        thr->run_node = node;
1434
 
        thr->prev_node = node;
1435
 
        thr->fk_cascade_depth = 0;
1436
 
 
1437
 
        row_upd_step(thr);
1438
 
 
1439
 
        /* The recursive call for cascading update/delete happens
1440
 
        in above row_upd_step(), reset the counter once we come
1441
 
        out of the recursive call, so it does not accumulate for
1442
 
        different row deletes */
1443
 
        thr->fk_cascade_depth = 0;
1444
 
 
1445
 
        err = trx->error_state;
1446
 
 
1447
 
        /* Reset fk_cascade_depth back to 0 */
1448
 
        thr->fk_cascade_depth = 0;
1449
 
 
1450
 
        if (err != DB_SUCCESS) {
1451
 
                que_thr_stop_for_mysql(thr);
1452
 
 
1453
 
                if (err == DB_RECORD_NOT_FOUND) {
1454
 
                        trx->error_state = DB_SUCCESS;
1455
 
                        trx->op_info = "";
1456
 
 
1457
 
                        return((int) err);
1458
 
                }
1459
 
 
1460
 
                thr->lock_state= QUE_THR_LOCK_ROW;
1461
 
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1462
 
                                                        &savept);
1463
 
                thr->lock_state= QUE_THR_LOCK_NOLOCK;
1464
 
 
1465
 
                if (was_lock_wait) {
1466
 
                        goto run_again;
1467
 
                }
1468
 
 
1469
 
                trx->op_info = "";
1470
 
 
1471
 
                return((int) err);
1472
 
        }
1473
 
 
1474
 
        que_thr_stop_for_mysql_no_error(thr, trx);
1475
 
 
1476
 
        if (node->is_delete) {
1477
 
                if (prebuilt->table->stat_n_rows > 0) {
1478
 
                        prebuilt->table->stat_n_rows--;
1479
 
                }
1480
 
 
1481
 
                srv_n_rows_deleted++;
1482
 
        } else {
1483
 
                srv_n_rows_updated++;
1484
 
        }
1485
 
 
1486
 
        /* We update table statistics only if it is a DELETE or UPDATE
1487
 
        that changes indexed columns, UPDATEs that change only non-indexed
1488
 
        columns would not affect statistics. */
1489
 
        if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1490
 
                row_update_statistics_if_needed(prebuilt->table);
1491
 
        }
1492
 
 
1493
 
        trx->op_info = "";
1494
 
 
1495
 
        return((int) err);
1496
 
}
1497
 
 
1498
 
/*********************************************************************//**
1499
 
This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
1500
 
session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
1501
 
Before calling this function row_search_for_mysql() must have
1502
 
initialized prebuilt->new_rec_locks to store the information which new
1503
 
record locks really were set. This function removes a newly set
1504
 
clustered index record lock under prebuilt->pcur or
1505
 
prebuilt->clust_pcur.  Thus, this implements a 'mini-rollback' that
1506
 
releases the latest clustered index record lock we set.
1507
 
@return error code or DB_SUCCESS */
1508
 
UNIV_INTERN
1509
 
int
1510
 
row_unlock_for_mysql(
1511
 
/*=================*/
1512
 
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct in MySQL
1513
 
                                        handle */
1514
 
        ibool           has_latches_on_recs)/*!< in: TRUE if called so
1515
 
                                        that we have the latches on
1516
 
                                        the records under pcur and
1517
 
                                        clust_pcur, and we do not need
1518
 
                                        to reposition the cursors. */
1519
 
{
1520
 
        btr_pcur_t*     pcur            = prebuilt->pcur;
1521
 
        btr_pcur_t*     clust_pcur      = prebuilt->clust_pcur;
1522
 
        trx_t*          trx             = prebuilt->trx;
1523
 
 
1524
 
        ut_ad(prebuilt && trx);
1525
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1526
 
 
1527
 
        if (UNIV_UNLIKELY
1528
 
            (!srv_locks_unsafe_for_binlog
1529
 
             && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
1530
 
 
1531
 
                fprintf(stderr,
1532
 
                        "InnoDB: Error: calling row_unlock_for_mysql though\n"
1533
 
                        "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1534
 
                        "InnoDB: this session is not using"
1535
 
                        " READ COMMITTED isolation level.\n");
1536
 
 
1537
 
                return(DB_SUCCESS);
1538
 
        }
1539
 
 
1540
 
        trx->op_info = "unlock_row";
1541
 
 
1542
 
        if (prebuilt->new_rec_locks >= 1) {
1543
 
 
1544
 
                const rec_t*    rec;
1545
 
                dict_index_t*   index;
1546
 
                trx_id_t        rec_trx_id;
1547
 
                mtr_t           mtr;
1548
 
 
1549
 
                mtr_start(&mtr);
1550
 
 
1551
 
                /* Restore the cursor position and find the record */
1552
 
 
1553
 
                if (!has_latches_on_recs) {
1554
 
                        btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1555
 
                }
1556
 
 
1557
 
                rec = btr_pcur_get_rec(pcur);
1558
 
                index = btr_pcur_get_btr_cur(pcur)->index;
1559
 
 
1560
 
                if (prebuilt->new_rec_locks >= 2) {
1561
 
                        /* Restore the cursor position and find the record
1562
 
                        in the clustered index. */
1563
 
 
1564
 
                        if (!has_latches_on_recs) {
1565
 
                                btr_pcur_restore_position(BTR_SEARCH_LEAF,
1566
 
                                                          clust_pcur, &mtr);
1567
 
                        }
1568
 
 
1569
 
                        rec = btr_pcur_get_rec(clust_pcur);
1570
 
                        index = btr_pcur_get_btr_cur(clust_pcur)->index;
1571
 
                }
1572
 
 
1573
 
                if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1574
 
                        /* This is not a clustered index record.  We
1575
 
                        do not know how to unlock the record. */
1576
 
                        goto no_unlock;
1577
 
                }
1578
 
 
1579
 
                /* If the record has been modified by this
1580
 
                transaction, do not unlock it. */
1581
 
 
1582
 
                if (index->trx_id_offset) {
1583
 
                        rec_trx_id = trx_read_trx_id(rec
1584
 
                                                     + index->trx_id_offset);
1585
 
                } else {
1586
 
                        mem_heap_t*     heap                    = NULL;
1587
 
                        ulint   offsets_[REC_OFFS_NORMAL_SIZE];
1588
 
                        ulint*  offsets                         = offsets_;
1589
 
 
1590
 
                        rec_offs_init(offsets_);
1591
 
                        offsets = rec_get_offsets(rec, index, offsets,
1592
 
                                                  ULINT_UNDEFINED, &heap);
1593
 
 
1594
 
                        rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1595
 
 
1596
 
                        if (UNIV_LIKELY_NULL(heap)) {
1597
 
                                mem_heap_free(heap);
1598
 
                        }
1599
 
                }
1600
 
 
1601
 
                if (rec_trx_id != trx->id) {
1602
 
                        /* We did not update the record: unlock it */
1603
 
 
1604
 
                        rec = btr_pcur_get_rec(pcur);
1605
 
                        index = btr_pcur_get_btr_cur(pcur)->index;
1606
 
 
1607
 
                        lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1608
 
                                        rec, static_cast<lock_mode>(prebuilt->select_lock_type));
1609
 
 
1610
 
                        if (prebuilt->new_rec_locks >= 2) {
1611
 
                                rec = btr_pcur_get_rec(clust_pcur);
1612
 
                                index = btr_pcur_get_btr_cur(clust_pcur)->index;
1613
 
 
1614
 
                                lock_rec_unlock(trx,
1615
 
                                                btr_pcur_get_block(clust_pcur),
1616
 
                                                rec,
1617
 
                                                static_cast<lock_mode>(prebuilt->select_lock_type));
1618
 
                        }
1619
 
                }
1620
 
no_unlock:
1621
 
                mtr_commit(&mtr);
1622
 
        }
1623
 
 
1624
 
        trx->op_info = "";
1625
 
 
1626
 
        return(DB_SUCCESS);
1627
 
}
1628
 
 
1629
 
/**********************************************************************//**
1630
 
Does a cascaded delete or set null in a foreign key operation.
1631
 
@return error code or DB_SUCCESS */
1632
 
UNIV_INTERN
1633
 
ulint
1634
 
row_update_cascade_for_mysql(
1635
 
/*=========================*/
1636
 
        que_thr_t*      thr,    /*!< in: query thread */
1637
 
        upd_node_t*     node,   /*!< in: update node used in the cascade
1638
 
                                or set null operation */
1639
 
        dict_table_t*   table)  /*!< in: table where we do the operation */
1640
 
{
1641
 
        ulint   err;
1642
 
        trx_t*  trx;
1643
 
 
1644
 
        trx = thr_get_trx(thr);
1645
 
 
1646
 
        /* Increment fk_cascade_depth to record the recursive call depth on
1647
 
        a single update/delete that affects multiple tables chained
1648
 
        together with foreign key relations. */
1649
 
        thr->fk_cascade_depth++;
1650
 
 
1651
 
        if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1652
 
                return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1653
 
        }
1654
 
run_again:
1655
 
        thr->run_node = node;
1656
 
        thr->prev_node = node;
1657
 
 
1658
 
        row_upd_step(thr);
1659
 
 
1660
 
        /* The recursive call for cascading update/delete happens
1661
 
        in above row_upd_step(), reset the counter once we come
1662
 
        out of the recursive call, so it does not accumulate for
1663
 
        different row deletes */
1664
 
        thr->fk_cascade_depth = 0;
1665
 
 
1666
 
        err = trx->error_state;
1667
 
 
1668
 
        /* Note that the cascade node is a subnode of another InnoDB
1669
 
        query graph node. We do a normal lock wait in this node, but
1670
 
        all errors are handled by the parent node. */
1671
 
 
1672
 
        if (err == DB_LOCK_WAIT) {
1673
 
                /* Handle lock wait here */
1674
 
 
1675
 
                que_thr_stop_for_mysql(thr);
1676
 
 
1677
 
                srv_suspend_mysql_thread(thr);
1678
 
 
1679
 
                /* Note that a lock wait may also end in a lock wait timeout,
1680
 
                or this transaction is picked as a victim in selective
1681
 
                deadlock resolution */
1682
 
 
1683
 
                if (trx->error_state != DB_SUCCESS) {
1684
 
 
1685
 
                        return(trx->error_state);
1686
 
                }
1687
 
 
1688
 
                /* Retry operation after a normal lock wait */
1689
 
 
1690
 
                goto run_again;
1691
 
        }
1692
 
 
1693
 
        if (err != DB_SUCCESS) {
1694
 
 
1695
 
                return(err);
1696
 
        }
1697
 
 
1698
 
        if (node->is_delete) {
1699
 
                if (table->stat_n_rows > 0) {
1700
 
                        table->stat_n_rows--;
1701
 
                }
1702
 
 
1703
 
                srv_n_rows_deleted++;
1704
 
        } else {
1705
 
                srv_n_rows_updated++;
1706
 
        }
1707
 
 
1708
 
        row_update_statistics_if_needed(table);
1709
 
 
1710
 
        return(err);
1711
 
}
1712
 
 
1713
 
/*********************************************************************//**
1714
 
Checks if a table is such that we automatically created a clustered
1715
 
index on it (on row id).
1716
 
@return TRUE if the clustered index was generated automatically */
1717
 
UNIV_INTERN
1718
 
ibool
1719
 
row_table_got_default_clust_index(
1720
 
/*==============================*/
1721
 
        const dict_table_t*     table)  /*!< in: table */
1722
 
{
1723
 
        const dict_index_t*     clust_index;
1724
 
 
1725
 
        clust_index = dict_table_get_first_index(table);
1726
 
 
1727
 
        return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1728
 
}
1729
 
 
1730
 
/*********************************************************************//**
1731
 
Locks the data dictionary in shared mode from modifications, for performing
1732
 
foreign key check, rollback, or other operation invisible to MySQL. */
1733
 
UNIV_INTERN
1734
 
void
1735
 
row_mysql_freeze_data_dictionary_func(
1736
 
/*==================================*/
1737
 
        trx_t*          trx,    /*!< in/out: transaction */
1738
 
        const char*     file,   /*!< in: file name */
1739
 
        ulint           line)   /*!< in: line number */
1740
 
{
1741
 
        ut_a(trx->dict_operation_lock_mode == 0);
1742
 
 
1743
 
        rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
1744
 
 
1745
 
        trx->dict_operation_lock_mode = RW_S_LATCH;
1746
 
}
1747
 
 
1748
 
/*********************************************************************//**
1749
 
Unlocks the data dictionary shared lock. */
1750
 
UNIV_INTERN
1751
 
void
1752
 
row_mysql_unfreeze_data_dictionary(
1753
 
/*===============================*/
1754
 
        trx_t*  trx)    /*!< in/out: transaction */
1755
 
{
1756
 
        ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1757
 
 
1758
 
        rw_lock_s_unlock(&dict_operation_lock);
1759
 
 
1760
 
        trx->dict_operation_lock_mode = 0;
1761
 
}
1762
 
 
1763
 
/*********************************************************************//**
1764
 
Locks the data dictionary exclusively for performing a table create or other
1765
 
data dictionary modification operation. */
1766
 
UNIV_INTERN
1767
 
void
1768
 
row_mysql_lock_data_dictionary_func(
1769
 
/*================================*/
1770
 
        trx_t*          trx,    /*!< in/out: transaction */
1771
 
        const char*     file,   /*!< in: file name */
1772
 
        ulint           line)   /*!< in: line number */
1773
 
{
1774
 
        ut_a(trx->dict_operation_lock_mode == 0
1775
 
             || trx->dict_operation_lock_mode == RW_X_LATCH);
1776
 
 
1777
 
        /* Serialize data dictionary operations with dictionary mutex:
1778
 
        no deadlocks or lock waits can occur then in these operations */
1779
 
 
1780
 
        rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
1781
 
        trx->dict_operation_lock_mode = RW_X_LATCH;
1782
 
 
1783
 
        mutex_enter(&(dict_sys->mutex));
1784
 
}
1785
 
 
1786
 
/*********************************************************************//**
1787
 
Unlocks the data dictionary exclusive lock. */
1788
 
UNIV_INTERN
1789
 
void
1790
 
row_mysql_unlock_data_dictionary(
1791
 
/*=============================*/
1792
 
        trx_t*  trx)    /*!< in/out: transaction */
1793
 
{
1794
 
        ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1795
 
 
1796
 
        /* Serialize data dictionary operations with dictionary mutex:
1797
 
        no deadlocks can occur then in these operations */
1798
 
 
1799
 
        mutex_exit(&(dict_sys->mutex));
1800
 
        rw_lock_x_unlock(&dict_operation_lock);
1801
 
 
1802
 
        trx->dict_operation_lock_mode = 0;
1803
 
}
1804
 
 
1805
 
/*********************************************************************//**
1806
 
Creates a table for MySQL. If the name of the table ends in
1807
 
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1808
 
"innodb_table_monitor", then this will also start the printing of monitor
1809
 
output by the master thread. If the table name ends in "innodb_mem_validate",
1810
 
InnoDB will try to invoke mem_validate().
1811
 
@return error code or DB_SUCCESS */
1812
 
UNIV_INTERN
1813
 
int
1814
 
row_create_table_for_mysql(
1815
 
/*=======================*/
1816
 
        dict_table_t*   table,  /*!< in, own: table definition
1817
 
                                (will be freed) */
1818
 
        trx_t*          trx)    /*!< in: transaction handle */
1819
 
{
1820
 
        tab_node_t*     node;
1821
 
        mem_heap_t*     heap;
1822
 
        que_thr_t*      thr;
1823
 
        const char*     table_name;
1824
 
        ulint           table_name_len;
1825
 
        ulint           err;
1826
 
 
1827
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1828
 
#ifdef UNIV_SYNC_DEBUG
1829
 
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1830
 
#endif /* UNIV_SYNC_DEBUG */
1831
 
        ut_ad(mutex_own(&(dict_sys->mutex)));
1832
 
        ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1833
 
 
1834
 
        if (srv_created_new_raw) {
1835
 
                fputs("InnoDB: A new raw disk partition was initialized:\n"
1836
 
                      "InnoDB: we do not allow database modifications"
1837
 
                      " by the user.\n"
1838
 
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1839
 
                      " is replaced with raw.\n", stderr);
1840
 
                dict_mem_table_free(table);
1841
 
                trx_commit_for_mysql(trx);
1842
 
 
1843
 
                return(DB_ERROR);
1844
 
        }
1845
 
 
1846
 
        trx->op_info = "creating table";
1847
 
 
1848
 
        trx_start_if_not_started(trx);
1849
 
 
1850
 
        /* The table name is prefixed with the database name and a '/'.
1851
 
        Certain table names starting with 'innodb_' have their special
1852
 
        meaning regardless of the database name.  Thus, we need to
1853
 
        ignore the database name prefix in the comparisons. */
1854
 
        table_name = strchr(table->name, '/');
1855
 
        ut_a(table_name);
1856
 
        table_name++;
1857
 
        table_name_len = strlen(table_name) + 1;
1858
 
 
1859
 
        if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1860
 
 
1861
 
                /* Table equals "innodb_monitor":
1862
 
                start monitor prints */
1863
 
 
1864
 
                srv_print_innodb_monitor = TRUE;
1865
 
 
1866
 
                /* The lock timeout monitor thread also takes care
1867
 
                of InnoDB monitor prints */
1868
 
 
1869
 
                os_event_set(srv_lock_timeout_thread_event);
1870
 
        } else if (STR_EQ(table_name, table_name_len,
1871
 
                          S_innodb_lock_monitor)) {
1872
 
 
1873
 
                srv_print_innodb_monitor = TRUE;
1874
 
                srv_print_innodb_lock_monitor = TRUE;
1875
 
                os_event_set(srv_lock_timeout_thread_event);
1876
 
        } else if (STR_EQ(table_name, table_name_len,
1877
 
                          S_innodb_tablespace_monitor)) {
1878
 
 
1879
 
                srv_print_innodb_tablespace_monitor = TRUE;
1880
 
                os_event_set(srv_lock_timeout_thread_event);
1881
 
        } else if (STR_EQ(table_name, table_name_len,
1882
 
                          S_innodb_table_monitor)) {
1883
 
 
1884
 
                srv_print_innodb_table_monitor = TRUE;
1885
 
                os_event_set(srv_lock_timeout_thread_event);
1886
 
        } else if (STR_EQ(table_name, table_name_len,
1887
 
                          S_innodb_mem_validate)) {
1888
 
                /* We define here a debugging feature intended for
1889
 
                developers */
1890
 
 
1891
 
                fputs("Validating InnoDB memory:\n"
1892
 
                      "to use this feature you must compile InnoDB with\n"
1893
 
                      "UNIV_MEM_DEBUG defined in univ.i and"
1894
 
                      " the server must be\n"
1895
 
                      "quiet because allocation from a mem heap"
1896
 
                      " is not protected\n"
1897
 
                      "by any semaphore.\n", stderr);
1898
 
#ifdef UNIV_MEM_DEBUG
1899
 
                ut_a(mem_validate());
1900
 
                fputs("Memory validated\n", stderr);
1901
 
#else /* UNIV_MEM_DEBUG */
1902
 
                fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1903
 
                      stderr);
1904
 
#endif /* UNIV_MEM_DEBUG */
1905
 
        }
1906
 
 
1907
 
        heap = mem_heap_create(512);
1908
 
 
1909
 
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1910
 
 
1911
 
        node = tab_create_graph_create(table, heap);
1912
 
 
1913
 
        thr = pars_complete_graph_for_exec(node, trx, heap);
1914
 
 
1915
 
        ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
1916
 
        que_run_threads(thr);
1917
 
 
1918
 
        err = trx->error_state;
1919
 
 
1920
 
        switch (err) {
1921
 
        case DB_SUCCESS:
1922
 
                break;
1923
 
        case DB_OUT_OF_FILE_SPACE:
1924
 
                trx->error_state = DB_SUCCESS;
1925
 
                trx_general_rollback_for_mysql(trx, NULL);
1926
 
 
1927
 
                ut_print_timestamp(stderr);
1928
 
                fputs("  InnoDB: Warning: cannot create table ",
1929
 
                      stderr);
1930
 
                ut_print_name(stderr, trx, TRUE, table->name);
1931
 
                fputs(" because tablespace full\n", stderr);
1932
 
 
1933
 
                if (dict_table_get_low(table->name)) {
1934
 
 
1935
 
                        row_drop_table_for_mysql(table->name, trx, FALSE);
1936
 
                        trx_commit_for_mysql(trx);
1937
 
                }
1938
 
                break;
1939
 
 
1940
 
        case DB_DUPLICATE_KEY:
1941
 
        default:
1942
 
                /* We may also get err == DB_ERROR if the .ibd file for the
1943
 
                table already exists */
1944
 
 
1945
 
                trx->error_state = DB_SUCCESS;
1946
 
                trx_general_rollback_for_mysql(trx, NULL);
1947
 
                dict_mem_table_free(table);
1948
 
                break;
1949
 
        }
1950
 
 
1951
 
        que_graph_free((que_t*) que_node_get_parent(thr));
1952
 
 
1953
 
        trx->op_info = "";
1954
 
 
1955
 
        return((int) err);
1956
 
}
1957
 
 
1958
 
/*********************************************************************//**
1959
 
Does an index creation operation for MySQL. TODO: currently failure
1960
 
to create an index results in dropping the whole table! This is no problem
1961
 
currently as all indexes must be created at the same time as the table.
1962
 
@return error number or DB_SUCCESS */
1963
 
UNIV_INTERN
1964
 
int
1965
 
row_create_index_for_mysql(
1966
 
/*=======================*/
1967
 
        dict_index_t*   index,          /*!< in, own: index definition
1968
 
                                        (will be freed) */
1969
 
        trx_t*          trx,            /*!< in: transaction handle */
1970
 
        const ulint*    field_lengths)  /*!< in: if not NULL, must contain
1971
 
                                        dict_index_get_n_fields(index)
1972
 
                                        actual field lengths for the
1973
 
                                        index columns, which are
1974
 
                                        then checked for not being too
1975
 
                                        large. */
1976
 
{
1977
 
        ind_node_t*     node;
1978
 
        mem_heap_t*     heap;
1979
 
        que_thr_t*      thr;
1980
 
        ulint           err;
1981
 
        ulint           i;
1982
 
        ulint           len;
1983
 
        char*           table_name;
1984
 
 
1985
 
#ifdef UNIV_SYNC_DEBUG
1986
 
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1987
 
#endif /* UNIV_SYNC_DEBUG */
1988
 
        ut_ad(mutex_own(&(dict_sys->mutex)));
1989
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1990
 
 
1991
 
        trx->op_info = "creating index";
1992
 
 
1993
 
        /* Copy the table name because we may want to drop the
1994
 
        table later, after the index object is freed (inside
1995
 
        que_run_threads()) and thus index->table_name is not available. */
1996
 
        table_name = mem_strdup(index->table_name);
1997
 
 
1998
 
        trx_start_if_not_started(trx);
1999
 
 
2000
 
        /* Check that the same column does not appear twice in the index.
2001
 
        Starting from 4.0.14, InnoDB should be able to cope with that, but
2002
 
        safer not to allow them. */
2003
 
 
2004
 
        for (i = 0; i < dict_index_get_n_fields(index); i++) {
2005
 
                ulint           j;
2006
 
 
2007
 
                for (j = 0; j < i; j++) {
2008
 
                        if (0 == ut_strcmp(
2009
 
                                    dict_index_get_nth_field(index, j)->name,
2010
 
                                    dict_index_get_nth_field(index, i)->name)) {
2011
 
                                ut_print_timestamp(stderr);
2012
 
 
2013
 
                                fputs("  InnoDB: Error: column ", stderr);
2014
 
                                ut_print_name(stderr, trx, FALSE,
2015
 
                                              dict_index_get_nth_field(
2016
 
                                                      index, i)->name);
2017
 
                                fputs(" appears twice in ", stderr);
2018
 
                                dict_index_name_print(stderr, trx, index);
2019
 
                                fputs("\n"
2020
 
                                      "InnoDB: This is not allowed"
2021
 
                                      " in InnoDB.\n", stderr);
2022
 
 
2023
 
                                err = DB_COL_APPEARS_TWICE_IN_INDEX;
2024
 
 
2025
 
                                goto error_handling;
2026
 
                        }
2027
 
                }
2028
 
 
2029
 
                /* Check also that prefix_len and actual length
2030
 
                < DICT_MAX_INDEX_COL_LEN */
2031
 
 
2032
 
                len = dict_index_get_nth_field(index, i)->prefix_len;
2033
 
 
2034
 
                if (field_lengths) {
2035
 
                        len = ut_max(len, field_lengths[i]);
2036
 
                }
2037
 
 
2038
 
                if (len >= DICT_MAX_INDEX_COL_LEN) {
2039
 
                        err = DB_TOO_BIG_RECORD;
2040
 
 
2041
 
                        goto error_handling;
2042
 
                }
2043
 
        }
2044
 
 
2045
 
        heap = mem_heap_create(512);
2046
 
 
2047
 
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2048
 
 
2049
 
        /* Note that the space id where we store the index is inherited from
2050
 
        the table in dict_build_index_def_step() in dict0crea.c. */
2051
 
 
2052
 
        node = ind_create_graph_create(index, heap);
2053
 
 
2054
 
        thr = pars_complete_graph_for_exec(node, trx, heap);
2055
 
 
2056
 
        ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
2057
 
        que_run_threads(thr);
2058
 
 
2059
 
        err = trx->error_state;
2060
 
 
2061
 
        que_graph_free((que_t*) que_node_get_parent(thr));
2062
 
 
2063
 
error_handling:
2064
 
        if (err != DB_SUCCESS) {
2065
 
                /* We have special error handling here */
2066
 
 
2067
 
                trx->error_state = DB_SUCCESS;
2068
 
 
2069
 
                trx_general_rollback_for_mysql(trx, NULL);
2070
 
 
2071
 
                row_drop_table_for_mysql(table_name, trx, FALSE);
2072
 
 
2073
 
                trx_commit_for_mysql(trx);
2074
 
 
2075
 
                trx->error_state = DB_SUCCESS;
2076
 
        }
2077
 
 
2078
 
        trx->op_info = "";
2079
 
 
2080
 
        mem_free(table_name);
2081
 
 
2082
 
        return((int) err);
2083
 
}
2084
 
 
2085
 
/*********************************************************************//**
2086
 
Scans a table create SQL string and adds to the data dictionary
2087
 
the foreign key constraints declared in the string. This function
2088
 
should be called after the indexes for a table have been created.
2089
 
Each foreign key constraint must be accompanied with indexes in
2090
 
both participating tables. The indexes are allowed to contain more
2091
 
fields than mentioned in the constraint. Check also that foreign key
2092
 
constraints which reference this table are ok.
2093
 
@return error code or DB_SUCCESS */
2094
 
UNIV_INTERN
2095
 
int
2096
 
row_table_add_foreign_constraints(
2097
 
/*==============================*/
2098
 
        trx_t*          trx,            /*!< in: transaction */
2099
 
        const char*     sql_string,     /*!< in: table create statement where
2100
 
                                        foreign keys are declared like:
2101
 
                                FOREIGN KEY (a, b) REFERENCES table2(c, d),
2102
 
                                        table2 can be written also with the
2103
 
                                        database name before it: test.table2 */
2104
 
        size_t          sql_length,     /*!< in: length of sql_string */
2105
 
        const char*     name,           /*!< in: table full name in the
2106
 
                                        normalized form
2107
 
                                        database_name/table_name */
2108
 
        ibool           reject_fks)     /*!< in: if TRUE, fail with error
2109
 
                                        code DB_CANNOT_ADD_CONSTRAINT if
2110
 
                                        any foreign keys are found. */
2111
 
{
2112
 
        ulint   err;
2113
 
 
2114
 
        ut_ad(mutex_own(&(dict_sys->mutex)));
2115
 
#ifdef UNIV_SYNC_DEBUG
2116
 
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2117
 
#endif /* UNIV_SYNC_DEBUG */
2118
 
        ut_a(sql_string);
2119
 
 
2120
 
        trx->op_info = "adding foreign keys";
2121
 
 
2122
 
        trx_start_if_not_started(trx);
2123
 
 
2124
 
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2125
 
 
2126
 
        err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2127
 
                                              name, reject_fks);
2128
 
        if (err == DB_SUCCESS) {
2129
 
                /* Check that also referencing constraints are ok */
2130
 
                err = dict_load_foreigns(name, FALSE, TRUE);
2131
 
        }
2132
 
 
2133
 
        if (err != DB_SUCCESS) {
2134
 
                /* We have special error handling here */
2135
 
 
2136
 
                trx->error_state = DB_SUCCESS;
2137
 
 
2138
 
                trx_general_rollback_for_mysql(trx, NULL);
2139
 
 
2140
 
                row_drop_table_for_mysql(name, trx, FALSE);
2141
 
 
2142
 
                trx_commit_for_mysql(trx);
2143
 
 
2144
 
                trx->error_state = DB_SUCCESS;
2145
 
        }
2146
 
 
2147
 
        return((int) err);
2148
 
}
2149
 
 
2150
 
/*********************************************************************//**
2151
 
Drops a table for MySQL as a background operation. MySQL relies on Unix
2152
 
in ALTER TABLE to the fact that the table handler does not remove the
2153
 
table before all handles to it has been removed. Furhermore, the MySQL's
2154
 
call to drop table must be non-blocking. Therefore we do the drop table
2155
 
as a background operation, which is taken care of by the master thread
2156
 
in srv0srv.c.
2157
 
@return error code or DB_SUCCESS */
2158
 
static
2159
 
int
2160
 
row_drop_table_for_mysql_in_background(
2161
 
/*===================================*/
2162
 
        const char*     name)   /*!< in: table name */
2163
 
{
2164
 
        ulint   error;
2165
 
        trx_t*  trx;
2166
 
 
2167
 
        trx = trx_allocate_for_background();
2168
 
 
2169
 
        /* If the original transaction was dropping a table referenced by
2170
 
        foreign keys, we must set the following to be able to drop the
2171
 
        table: */
2172
 
 
2173
 
        trx->check_foreigns = FALSE;
2174
 
 
2175
 
        /*      fputs("InnoDB: Error: Dropping table ", stderr);
2176
 
        ut_print_name(stderr, trx, TRUE, name);
2177
 
        fputs(" in background drop list\n", stderr); */
2178
 
 
2179
 
        /* Try to drop the table in InnoDB */
2180
 
 
2181
 
        error = row_drop_table_for_mysql(name, trx, FALSE);
2182
 
 
2183
 
        /* Flush the log to reduce probability that the .frm files and
2184
 
        the InnoDB data dictionary get out-of-sync if the user runs
2185
 
        with innodb_flush_log_at_trx_commit = 0 */
2186
 
 
2187
 
        log_buffer_flush_to_disk();
2188
 
 
2189
 
        trx_commit_for_mysql(trx);
2190
 
 
2191
 
        trx_free_for_background(trx);
2192
 
 
2193
 
        return((int) error);
2194
 
}
2195
 
 
2196
 
/*********************************************************************//**
2197
 
The master thread in srv0srv.c calls this regularly to drop tables which
2198
 
we must drop in background after queries to them have ended. Such lazy
2199
 
dropping of tables is needed in ALTER TABLE on Unix.
2200
 
@return how many tables dropped + remaining tables in list */
2201
 
UNIV_INTERN
2202
 
ulint
2203
 
row_drop_tables_for_mysql_in_background(void)
2204
 
/*=========================================*/
2205
 
{
2206
 
        row_mysql_drop_t*       drop;
2207
 
        dict_table_t*           table;
2208
 
        ulint                   n_tables;
2209
 
        ulint                   n_tables_dropped = 0;
2210
 
loop:
2211
 
        mutex_enter(&kernel_mutex);
2212
 
 
2213
 
        if (!row_mysql_drop_list_inited) {
2214
 
 
2215
 
                UT_LIST_INIT(row_mysql_drop_list);
2216
 
                row_mysql_drop_list_inited = TRUE;
2217
 
        }
2218
 
 
2219
 
        drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2220
 
 
2221
 
        n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2222
 
 
2223
 
        mutex_exit(&kernel_mutex);
2224
 
 
2225
 
        if (drop == NULL) {
2226
 
                /* All tables dropped */
2227
 
 
2228
 
                return(n_tables + n_tables_dropped);
2229
 
        }
2230
 
 
2231
 
        mutex_enter(&(dict_sys->mutex));
2232
 
        table = dict_table_get_low(drop->table_name);
2233
 
        mutex_exit(&(dict_sys->mutex));
2234
 
 
2235
 
        if (table == NULL) {
2236
 
                /* If for some reason the table has already been dropped
2237
 
                through some other mechanism, do not try to drop it */
2238
 
 
2239
 
                goto already_dropped;
2240
 
        }
2241
 
 
2242
 
        if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2243
 
                    drop->table_name)) {
2244
 
                /* If the DROP fails for some table, we return, and let the
2245
 
                main thread retry later */
2246
 
 
2247
 
                return(n_tables + n_tables_dropped);
2248
 
        }
2249
 
 
2250
 
        n_tables_dropped++;
2251
 
 
2252
 
already_dropped:
2253
 
        mutex_enter(&kernel_mutex);
2254
 
 
2255
 
        UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2256
 
 
2257
 
        ut_print_timestamp(stderr);
2258
 
        fputs("  InnoDB: Dropped table ", stderr);
2259
 
        ut_print_name(stderr, NULL, TRUE, drop->table_name);
2260
 
        fputs(" in background drop queue.\n", stderr);
2261
 
 
2262
 
        mem_free(drop->table_name);
2263
 
 
2264
 
        mem_free(drop);
2265
 
 
2266
 
        mutex_exit(&kernel_mutex);
2267
 
 
2268
 
        goto loop;
2269
 
}
2270
 
 
2271
 
/*********************************************************************//**
2272
 
Get the background drop list length. NOTE: the caller must own the kernel
2273
 
mutex!
2274
 
@return how many tables in list */
2275
 
UNIV_INTERN
2276
 
ulint
2277
 
row_get_background_drop_list_len_low(void)
2278
 
/*======================================*/
2279
 
{
2280
 
        ut_ad(mutex_own(&kernel_mutex));
2281
 
 
2282
 
        if (!row_mysql_drop_list_inited) {
2283
 
 
2284
 
                UT_LIST_INIT(row_mysql_drop_list);
2285
 
                row_mysql_drop_list_inited = TRUE;
2286
 
        }
2287
 
 
2288
 
        return(UT_LIST_GET_LEN(row_mysql_drop_list));
2289
 
}
2290
 
 
2291
 
/*********************************************************************//**
2292
 
If a table is not yet in the drop list, adds the table to the list of tables
2293
 
which the master thread drops in background. We need this on Unix because in
2294
 
ALTER TABLE MySQL may call drop table even if the table has running queries on
2295
 
it. Also, if there are running foreign key checks on the table, we drop the
2296
 
table lazily.
2297
 
@return TRUE if the table was not yet in the drop list, and was added there */
2298
 
static
2299
 
ibool
2300
 
row_add_table_to_background_drop_list(
2301
 
/*==================================*/
2302
 
        const char*     name)   /*!< in: table name */
2303
 
{
2304
 
        row_mysql_drop_t*       drop;
2305
 
 
2306
 
        mutex_enter(&kernel_mutex);
2307
 
 
2308
 
        if (!row_mysql_drop_list_inited) {
2309
 
 
2310
 
                UT_LIST_INIT(row_mysql_drop_list);
2311
 
                row_mysql_drop_list_inited = TRUE;
2312
 
        }
2313
 
 
2314
 
        /* Look if the table already is in the drop list */
2315
 
        drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2316
 
 
2317
 
        while (drop != NULL) {
2318
 
                if (strcmp(drop->table_name, name) == 0) {
2319
 
                        /* Already in the list */
2320
 
 
2321
 
                        mutex_exit(&kernel_mutex);
2322
 
 
2323
 
                        return(FALSE);
2324
 
                }
2325
 
 
2326
 
                drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2327
 
        }
2328
 
 
2329
 
        drop = static_cast<row_mysql_drop_t *>(mem_alloc(sizeof(row_mysql_drop_t)));
2330
 
 
2331
 
        drop->table_name = mem_strdup(name);
2332
 
 
2333
 
        UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2334
 
 
2335
 
        /*      fputs("InnoDB: Adding table ", stderr);
2336
 
        ut_print_name(stderr, trx, TRUE, drop->table_name);
2337
 
        fputs(" to background drop list\n", stderr); */
2338
 
 
2339
 
        mutex_exit(&kernel_mutex);
2340
 
 
2341
 
        return(TRUE);
2342
 
}
2343
 
 
2344
 
/*********************************************************************//**
2345
 
Discards the tablespace of a table which stored in an .ibd file. Discarding
2346
 
means that this function deletes the .ibd file and assigns a new table id for
2347
 
the table. Also the flag table->ibd_file_missing is set TRUE.
2348
 
@return error code or DB_SUCCESS */
2349
 
UNIV_INTERN
2350
 
int
2351
 
row_discard_tablespace_for_mysql(
2352
 
/*=============================*/
2353
 
        const char*     name,   /*!< in: table name */
2354
 
        trx_t*          trx)    /*!< in: transaction handle */
2355
 
{
2356
 
        dict_foreign_t* foreign;
2357
 
        table_id_t      new_id;
2358
 
        dict_table_t*   table;
2359
 
        ibool           success;
2360
 
        ulint           err;
2361
 
        pars_info_t*    info = NULL;
2362
 
 
2363
 
        /* How do we prevent crashes caused by ongoing operations on
2364
 
        the table? Old operations could try to access non-existent
2365
 
        pages.
2366
 
 
2367
 
        1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2368
 
        MySQL table lock on the table before we can do DISCARD
2369
 
        TABLESPACE. Then there are no running queries on the table.
2370
 
 
2371
 
        2) Purge and rollback: we assign a new table id for the
2372
 
        table. Since purge and rollback look for the table based on
2373
 
        the table id, they see the table as 'dropped' and discard
2374
 
        their operations.
2375
 
 
2376
 
        3) Insert buffer: we remove all entries for the tablespace in
2377
 
        the insert buffer tree; as long as the tablespace mem object
2378
 
        does not exist, ongoing insert buffer page merges are
2379
 
        discarded in buf0rea.c. If we recreate the tablespace mem
2380
 
        object with IMPORT TABLESPACE later, then the tablespace will
2381
 
        have the same id, but the tablespace_version field in the mem
2382
 
        object is different, and ongoing old insert buffer page merges
2383
 
        get discarded.
2384
 
 
2385
 
        4) Linear readahead and random readahead: we use the same
2386
 
        method as in 3) to discard ongoing operations.
2387
 
 
2388
 
        5) FOREIGN KEY operations: if
2389
 
        table->n_foreign_key_checks_running > 0, we do not allow the
2390
 
        discard. We also reserve the data dictionary latch. */
2391
 
 
2392
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2393
 
 
2394
 
        trx->op_info = "discarding tablespace";
2395
 
        trx_start_if_not_started(trx);
2396
 
 
2397
 
        /* Serialize data dictionary operations with dictionary mutex:
2398
 
        no deadlocks can occur then in these operations */
2399
 
 
2400
 
        row_mysql_lock_data_dictionary(trx);
2401
 
 
2402
 
        table = dict_table_get_low(name);
2403
 
 
2404
 
        if (!table) {
2405
 
                err = DB_TABLE_NOT_FOUND;
2406
 
 
2407
 
                goto funct_exit;
2408
 
        }
2409
 
 
2410
 
        if (table->space == 0) {
2411
 
                ut_print_timestamp(stderr);
2412
 
                fputs("  InnoDB: Error: table ", stderr);
2413
 
                ut_print_name(stderr, trx, TRUE, name);
2414
 
                fputs("\n"
2415
 
                      "InnoDB: is in the system tablespace 0"
2416
 
                      " which cannot be discarded\n", stderr);
2417
 
                err = DB_ERROR;
2418
 
 
2419
 
                goto funct_exit;
2420
 
        }
2421
 
 
2422
 
        if (table->n_foreign_key_checks_running > 0) {
2423
 
 
2424
 
                ut_print_timestamp(stderr);
2425
 
                fputs("  InnoDB: You are trying to DISCARD table ", stderr);
2426
 
                ut_print_name(stderr, trx, TRUE, table->name);
2427
 
                fputs("\n"
2428
 
                      "InnoDB: though there is a foreign key check"
2429
 
                      " running on it.\n"
2430
 
                      "InnoDB: Cannot discard the table.\n",
2431
 
                      stderr);
2432
 
 
2433
 
                err = DB_ERROR;
2434
 
 
2435
 
                goto funct_exit;
2436
 
        }
2437
 
 
2438
 
        /* Check if the table is referenced by foreign key constraints from
2439
 
        some other table (not the table itself) */
2440
 
 
2441
 
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
2442
 
 
2443
 
        while (foreign && foreign->foreign_table == table) {
2444
 
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2445
 
        }
2446
 
 
2447
 
        if (foreign && trx->check_foreigns) {
2448
 
 
2449
 
                FILE*   ef      = dict_foreign_err_file;
2450
 
 
2451
 
                /* We only allow discarding a referenced table if
2452
 
                FOREIGN_KEY_CHECKS is set to 0 */
2453
 
 
2454
 
                err = DB_CANNOT_DROP_CONSTRAINT;
2455
 
 
2456
 
                mutex_enter(&dict_foreign_err_mutex);
2457
 
                rewind(ef);
2458
 
                ut_print_timestamp(ef);
2459
 
 
2460
 
                fputs("  Cannot DISCARD table ", ef);
2461
 
                ut_print_name(stderr, trx, TRUE, name);
2462
 
                fputs("\n"
2463
 
                      "because it is referenced by ", ef);
2464
 
                ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2465
 
                putc('\n', ef);
2466
 
                mutex_exit(&dict_foreign_err_mutex);
2467
 
 
2468
 
                goto funct_exit;
2469
 
        }
2470
 
 
2471
 
        dict_hdr_get_new_id(&new_id, NULL, NULL);
2472
 
 
2473
 
        /* Remove all locks except the table-level S and X locks. */
2474
 
        lock_remove_all_on_table(table, FALSE);
2475
 
 
2476
 
        info = pars_info_create();
2477
 
 
2478
 
        pars_info_add_str_literal(info, "table_name", name);
2479
 
        pars_info_add_ull_literal(info, "new_id", new_id);
2480
 
 
2481
 
        err = que_eval_sql(info,
2482
 
                           "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2483
 
                           "old_id CHAR;\n"
2484
 
                           "BEGIN\n"
2485
 
                           "SELECT ID INTO old_id\n"
2486
 
                           "FROM SYS_TABLES\n"
2487
 
                           "WHERE NAME = :table_name\n"
2488
 
                           "LOCK IN SHARE MODE;\n"
2489
 
                           "IF (SQL % NOTFOUND) THEN\n"
2490
 
                           "       COMMIT WORK;\n"
2491
 
                           "       RETURN;\n"
2492
 
                           "END IF;\n"
2493
 
                           "UPDATE SYS_TABLES SET ID = :new_id\n"
2494
 
                           " WHERE ID = old_id;\n"
2495
 
                           "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2496
 
                           " WHERE TABLE_ID = old_id;\n"
2497
 
                           "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2498
 
                           " WHERE TABLE_ID = old_id;\n"
2499
 
                           "COMMIT WORK;\n"
2500
 
                           "END;\n"
2501
 
                           , FALSE, trx);
2502
 
 
2503
 
        if (err != DB_SUCCESS) {
2504
 
                trx->error_state = DB_SUCCESS;
2505
 
                trx_general_rollback_for_mysql(trx, NULL);
2506
 
                trx->error_state = DB_SUCCESS;
2507
 
        } else {
2508
 
                dict_table_change_id_in_cache(table, new_id);
2509
 
 
2510
 
                success = fil_discard_tablespace(table->space);
2511
 
 
2512
 
                if (!success) {
2513
 
                        trx->error_state = DB_SUCCESS;
2514
 
                        trx_general_rollback_for_mysql(trx, NULL);
2515
 
                        trx->error_state = DB_SUCCESS;
2516
 
 
2517
 
                        err = DB_ERROR;
2518
 
                } else {
2519
 
                        /* Set the flag which tells that now it is legal to
2520
 
                        IMPORT a tablespace for this table */
2521
 
                        table->tablespace_discarded = TRUE;
2522
 
                        table->ibd_file_missing = TRUE;
2523
 
                }
2524
 
        }
2525
 
 
2526
 
funct_exit:
2527
 
        trx_commit_for_mysql(trx);
2528
 
 
2529
 
        row_mysql_unlock_data_dictionary(trx);
2530
 
 
2531
 
        trx->op_info = "";
2532
 
 
2533
 
        return((int) err);
2534
 
}
2535
 
 
2536
 
/*****************************************************************//**
2537
 
Imports a tablespace. The space id in the .ibd file must match the space id
2538
 
of the table in the data dictionary.
2539
 
@return error code or DB_SUCCESS */
2540
 
UNIV_INTERN
2541
 
int
2542
 
row_import_tablespace_for_mysql(
2543
 
/*============================*/
2544
 
        const char*     name,   /*!< in: table name */
2545
 
        trx_t*          trx)    /*!< in: transaction handle */
2546
 
{
2547
 
        dict_table_t*   table;
2548
 
        ibool           success;
2549
 
        ib_uint64_t     current_lsn;
2550
 
        ulint           err             = DB_SUCCESS;
2551
 
 
2552
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2553
 
 
2554
 
        trx_start_if_not_started(trx);
2555
 
 
2556
 
        trx->op_info = "importing tablespace";
2557
 
 
2558
 
        current_lsn = log_get_lsn();
2559
 
 
2560
 
        /* It is possible, though very improbable, that the lsn's in the
2561
 
        tablespace to be imported have risen above the current system lsn, if
2562
 
        a lengthy purge, ibuf merge, or rollback was performed on a backup
2563
 
        taken with ibbackup. If that is the case, reset page lsn's in the
2564
 
        file. We assume that mysqld was shut down after it performed these
2565
 
        cleanup operations on the .ibd file, so that it stamped the latest lsn
2566
 
        to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2567
 
 
2568
 
        TODO: reset also the trx id's in clustered index records and write
2569
 
        a new space id to each data page. That would allow us to import clean
2570
 
        .ibd files from another MySQL installation. */
2571
 
 
2572
 
        success = fil_reset_too_high_lsns(name, current_lsn);
2573
 
 
2574
 
        if (!success) {
2575
 
                ut_print_timestamp(stderr);
2576
 
                fputs("  InnoDB: Error: cannot reset lsn's in table ", stderr);
2577
 
                ut_print_name(stderr, trx, TRUE, name);
2578
 
                fputs("\n"
2579
 
                      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2580
 
                      stderr);
2581
 
 
2582
 
                err = DB_ERROR;
2583
 
 
2584
 
                row_mysql_lock_data_dictionary(trx);
2585
 
 
2586
 
                goto funct_exit;
2587
 
        }
2588
 
 
2589
 
        /* Serialize data dictionary operations with dictionary mutex:
2590
 
        no deadlocks can occur then in these operations */
2591
 
 
2592
 
        row_mysql_lock_data_dictionary(trx);
2593
 
 
2594
 
        table = dict_table_get_low(name);
2595
 
 
2596
 
        if (!table) {
2597
 
                ut_print_timestamp(stderr);
2598
 
                fputs("  InnoDB: table ", stderr);
2599
 
                ut_print_name(stderr, trx, TRUE, name);
2600
 
                fputs("\n"
2601
 
                      "InnoDB: does not exist in the InnoDB data dictionary\n"
2602
 
                      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2603
 
                      stderr);
2604
 
 
2605
 
                err = DB_TABLE_NOT_FOUND;
2606
 
 
2607
 
                goto funct_exit;
2608
 
        }
2609
 
 
2610
 
        if (table->space == 0) {
2611
 
                ut_print_timestamp(stderr);
2612
 
                fputs("  InnoDB: Error: table ", stderr);
2613
 
                ut_print_name(stderr, trx, TRUE, name);
2614
 
                fputs("\n"
2615
 
                      "InnoDB: is in the system tablespace 0"
2616
 
                      " which cannot be imported\n", stderr);
2617
 
                err = DB_ERROR;
2618
 
 
2619
 
                goto funct_exit;
2620
 
        }
2621
 
 
2622
 
        if (!table->tablespace_discarded) {
2623
 
                ut_print_timestamp(stderr);
2624
 
                fputs("  InnoDB: Error: you are trying to"
2625
 
                      " IMPORT a tablespace\n"
2626
 
                      "InnoDB: ", stderr);
2627
 
                ut_print_name(stderr, trx, TRUE, name);
2628
 
                fputs(", though you have not called DISCARD on it yet\n"
2629
 
                      "InnoDB: during the lifetime of the mysqld process!\n",
2630
 
                      stderr);
2631
 
 
2632
 
                err = DB_ERROR;
2633
 
 
2634
 
                goto funct_exit;
2635
 
        }
2636
 
 
2637
 
        /* Play safe and remove all insert buffer entries, though we should
2638
 
        have removed them already when DISCARD TABLESPACE was called */
2639
 
 
2640
 
        ibuf_delete_for_discarded_space(table->space);
2641
 
 
2642
 
        success = fil_open_single_table_tablespace(
2643
 
                TRUE, table->space,
2644
 
                table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2645
 
                table->name);
2646
 
        if (success) {
2647
 
                table->ibd_file_missing = FALSE;
2648
 
                table->tablespace_discarded = FALSE;
2649
 
        } else {
2650
 
                if (table->ibd_file_missing) {
2651
 
                        ut_print_timestamp(stderr);
2652
 
                        fputs("  InnoDB: cannot find or open in the"
2653
 
                              " database directory the .ibd file of\n"
2654
 
                              "InnoDB: table ", stderr);
2655
 
                        ut_print_name(stderr, trx, TRUE, name);
2656
 
                        fputs("\n"
2657
 
                              "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2658
 
                              stderr);
2659
 
                }
2660
 
 
2661
 
                err = DB_ERROR;
2662
 
        }
2663
 
 
2664
 
funct_exit:
2665
 
        trx_commit_for_mysql(trx);
2666
 
 
2667
 
        row_mysql_unlock_data_dictionary(trx);
2668
 
 
2669
 
        trx->op_info = "";
2670
 
 
2671
 
        return((int) err);
2672
 
}
2673
 
 
2674
 
/*********************************************************************//**
2675
 
Truncates a table for MySQL.
2676
 
@return error code or DB_SUCCESS */
2677
 
UNIV_INTERN
2678
 
int
2679
 
row_truncate_table_for_mysql(
2680
 
/*=========================*/
2681
 
        dict_table_t*   table,  /*!< in: table handle */
2682
 
        trx_t*          trx)    /*!< in: transaction handle */
2683
 
{
2684
 
        dict_foreign_t* foreign;
2685
 
        ulint           err;
2686
 
        mem_heap_t*     heap;
2687
 
        byte*           buf;
2688
 
        dtuple_t*       tuple;
2689
 
        dfield_t*       dfield;
2690
 
        dict_index_t*   sys_index;
2691
 
        btr_pcur_t      pcur;
2692
 
        mtr_t           mtr;
2693
 
        table_id_t      new_id;
2694
 
        ulint           recreate_space = 0;
2695
 
        pars_info_t*    info = NULL;
2696
 
 
2697
 
        /* How do we prevent crashes caused by ongoing operations on
2698
 
        the table? Old operations could try to access non-existent
2699
 
        pages.
2700
 
 
2701
 
        1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2702
 
        MySQL table lock on the table before we can do TRUNCATE
2703
 
        TABLE. Then there are no running queries on the table. This is
2704
 
        guaranteed, because in ha_innobase::store_lock(), we do not
2705
 
        weaken the TL_WRITE lock requested by MySQL when executing
2706
 
        SQLCOM_TRUNCATE.
2707
 
 
2708
 
        2) Purge and rollback: we assign a new table id for the
2709
 
        table. Since purge and rollback look for the table based on
2710
 
        the table id, they see the table as 'dropped' and discard
2711
 
        their operations.
2712
 
 
2713
 
        3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2714
 
        so we do not have to remove insert buffer records, as the
2715
 
        insert buffer works at a low level. If a freed page is later
2716
 
        reallocated, the allocator will remove the ibuf entries for
2717
 
        it.
2718
 
 
2719
 
        When we truncate *.ibd files by recreating them (analogous to
2720
 
        DISCARD TABLESPACE), we remove all entries for the table in the
2721
 
        insert buffer tree.  This is not strictly necessary, because
2722
 
        in 6) we will assign a new tablespace identifier, but we can
2723
 
        free up some space in the system tablespace.
2724
 
 
2725
 
        4) Linear readahead and random readahead: we use the same
2726
 
        method as in 3) to discard ongoing operations. (This is only
2727
 
        relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2728
 
 
2729
 
        5) FOREIGN KEY operations: if
2730
 
        table->n_foreign_key_checks_running > 0, we do not allow the
2731
 
        TRUNCATE. We also reserve the data dictionary latch.
2732
 
 
2733
 
        6) Crash recovery: To prevent the application of pre-truncation
2734
 
        redo log records on the truncated tablespace, we will assign
2735
 
        a new tablespace identifier to the truncated tablespace. */
2736
 
 
2737
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2738
 
        ut_ad(table);
2739
 
 
2740
 
        if (srv_created_new_raw) {
2741
 
                fputs("InnoDB: A new raw disk partition was initialized:\n"
2742
 
                      "InnoDB: we do not allow database modifications"
2743
 
                      " by the user.\n"
2744
 
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2745
 
                      " is replaced with raw.\n", stderr);
2746
 
 
2747
 
                return(DB_ERROR);
2748
 
        }
2749
 
 
2750
 
        trx->op_info = "truncating table";
2751
 
 
2752
 
        trx_start_if_not_started(trx);
2753
 
 
2754
 
        /* Serialize data dictionary operations with dictionary mutex:
2755
 
        no deadlocks can occur then in these operations */
2756
 
 
2757
 
        ut_a(trx->dict_operation_lock_mode == 0);
2758
 
        /* Prevent foreign key checks etc. while we are truncating the
2759
 
        table */
2760
 
 
2761
 
        row_mysql_lock_data_dictionary(trx);
2762
 
 
2763
 
        ut_ad(mutex_own(&(dict_sys->mutex)));
2764
 
#ifdef UNIV_SYNC_DEBUG
2765
 
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2766
 
#endif /* UNIV_SYNC_DEBUG */
2767
 
 
2768
 
        /* Check if the table is referenced by foreign key constraints from
2769
 
        some other table (not the table itself) */
2770
 
 
2771
 
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
2772
 
 
2773
 
        while (foreign && foreign->foreign_table == table) {
2774
 
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2775
 
        }
2776
 
 
2777
 
        if (foreign && trx->check_foreigns) {
2778
 
                FILE*   ef      = dict_foreign_err_file;
2779
 
 
2780
 
                /* We only allow truncating a referenced table if
2781
 
                FOREIGN_KEY_CHECKS is set to 0 */
2782
 
 
2783
 
                mutex_enter(&dict_foreign_err_mutex);
2784
 
                rewind(ef);
2785
 
                ut_print_timestamp(ef);
2786
 
 
2787
 
                fputs("  Cannot truncate table ", ef);
2788
 
                ut_print_name(ef, trx, TRUE, table->name);
2789
 
                fputs(" by DROP+CREATE\n"
2790
 
                      "InnoDB: because it is referenced by ", ef);
2791
 
                ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2792
 
                putc('\n', ef);
2793
 
                mutex_exit(&dict_foreign_err_mutex);
2794
 
 
2795
 
                err = DB_ERROR;
2796
 
                goto funct_exit;
2797
 
        }
2798
 
 
2799
 
        /* TODO: could we replace the counter n_foreign_key_checks_running
2800
 
        with lock checks on the table? Acquire here an exclusive lock on the
2801
 
        table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2802
 
        they can cope with the table having been truncated here? Foreign key
2803
 
        checks take an IS or IX lock on the table. */
2804
 
 
2805
 
        if (table->n_foreign_key_checks_running > 0) {
2806
 
                ut_print_timestamp(stderr);
2807
 
                fputs("  InnoDB: Cannot truncate table ", stderr);
2808
 
                ut_print_name(stderr, trx, TRUE, table->name);
2809
 
                fputs(" by DROP+CREATE\n"
2810
 
                      "InnoDB: because there is a foreign key check"
2811
 
                      " running on it.\n",
2812
 
                      stderr);
2813
 
                err = DB_ERROR;
2814
 
 
2815
 
                goto funct_exit;
2816
 
        }
2817
 
 
2818
 
        /* Remove all locks except the table-level S and X locks. */
2819
 
        lock_remove_all_on_table(table, FALSE);
2820
 
 
2821
 
        trx->table_id = table->id;
2822
 
 
2823
 
        if (table->space && !table->dir_path_of_temp_table) {
2824
 
                /* Discard and create the single-table tablespace. */
2825
 
                ulint   space   = table->space;
2826
 
                ulint   flags   = fil_space_get_flags(space);
2827
 
 
2828
 
                if (flags != ULINT_UNDEFINED
2829
 
                    && fil_discard_tablespace(space)) {
2830
 
 
2831
 
                        dict_index_t*   index;
2832
 
 
2833
 
                        dict_hdr_get_new_id(NULL, NULL, &space);
2834
 
 
2835
 
                        /* Lock all index trees for this table. We must
2836
 
                        do so after dict_hdr_get_new_id() to preserve
2837
 
                        the latch order */
2838
 
                        dict_table_x_lock_indexes(table);
2839
 
 
2840
 
                        if (space == ULINT_UNDEFINED
2841
 
                            || fil_create_new_single_table_tablespace(
2842
 
                                    space, table->name, FALSE, flags,
2843
 
                                    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2844
 
                                dict_table_x_unlock_indexes(table);
2845
 
                                ut_print_timestamp(stderr);
2846
 
                                fprintf(stderr,
2847
 
                                        "  InnoDB: TRUNCATE TABLE %s failed to"
2848
 
                                        " create a new tablespace\n",
2849
 
                                        table->name);
2850
 
                                table->ibd_file_missing = 1;
2851
 
                                err = DB_ERROR;
2852
 
                                goto funct_exit;
2853
 
                        }
2854
 
 
2855
 
                        recreate_space = space;
2856
 
 
2857
 
                        /* Replace the space_id in the data dictionary cache.
2858
 
                        The persisent data dictionary (SYS_TABLES.SPACE
2859
 
                        and SYS_INDEXES.SPACE) are updated later in this
2860
 
                        function. */
2861
 
                        table->space = space;
2862
 
                        index = dict_table_get_first_index(table);
2863
 
                        do {
2864
 
                                index->space = space;
2865
 
                                index = dict_table_get_next_index(index);
2866
 
                        } while (index);
2867
 
 
2868
 
                        mtr_start(&mtr);
2869
 
                        fsp_header_init(space,
2870
 
                                        FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2871
 
                        mtr_commit(&mtr);
2872
 
                }
2873
 
        } else {
2874
 
                /* Lock all index trees for this table, as we will
2875
 
                truncate the table/index and possibly change their metadata.
2876
 
                All DML/DDL are blocked by table level lock, with
2877
 
                a few exceptions such as queries into information schema
2878
 
                about the table, MySQL could try to access index stats
2879
 
                for this kind of query, we need to use index locks to
2880
 
                sync up */
2881
 
                dict_table_x_lock_indexes(table);
2882
 
        }
2883
 
 
2884
 
        /* scan SYS_INDEXES for all indexes of the table */
2885
 
        heap = mem_heap_create(800);
2886
 
 
2887
 
        tuple = dtuple_create(heap, 1);
2888
 
        dfield = dtuple_get_nth_field(tuple, 0);
2889
 
 
2890
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
2891
 
        mach_write_to_8(buf, table->id);
2892
 
 
2893
 
        dfield_set_data(dfield, buf, 8);
2894
 
        sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2895
 
        dict_index_copy_types(tuple, sys_index, 1);
2896
 
 
2897
 
        mtr_start(&mtr);
2898
 
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2899
 
                                  BTR_MODIFY_LEAF, &pcur, &mtr);
2900
 
        for (;;) {
2901
 
                rec_t*          rec;
2902
 
                const byte*     field;
2903
 
                ulint           len;
2904
 
                ulint           root_page_no;
2905
 
 
2906
 
                if (!btr_pcur_is_on_user_rec(&pcur)) {
2907
 
                        /* The end of SYS_INDEXES has been reached. */
2908
 
                        break;
2909
 
                }
2910
 
 
2911
 
                rec = btr_pcur_get_rec(&pcur);
2912
 
 
2913
 
                field = rec_get_nth_field_old(rec, 0, &len);
2914
 
                ut_ad(len == 8);
2915
 
 
2916
 
                if (memcmp(buf, field, len) != 0) {
2917
 
                        /* End of indexes for the table (TABLE_ID mismatch). */
2918
 
                        break;
2919
 
                }
2920
 
 
2921
 
                if (rec_get_deleted_flag(rec, FALSE)) {
2922
 
                        /* The index has been dropped. */
2923
 
                        goto next_rec;
2924
 
                }
2925
 
 
2926
 
                /* This call may commit and restart mtr
2927
 
                and reposition pcur. */
2928
 
                root_page_no = dict_truncate_index_tree(table, recreate_space,
2929
 
                                                        &pcur, &mtr);
2930
 
 
2931
 
                rec = btr_pcur_get_rec(&pcur);
2932
 
 
2933
 
                if (root_page_no != FIL_NULL) {
2934
 
                        page_rec_write_index_page_no(
2935
 
                                rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2936
 
                                root_page_no, &mtr);
2937
 
                        /* We will need to commit and restart the
2938
 
                        mini-transaction in order to avoid deadlocks.
2939
 
                        The dict_truncate_index_tree() call has allocated
2940
 
                        a page in this mini-transaction, and the rest of
2941
 
                        this loop could latch another index page. */
2942
 
                        mtr_commit(&mtr);
2943
 
                        mtr_start(&mtr);
2944
 
                        btr_pcur_restore_position(BTR_MODIFY_LEAF,
2945
 
                                                  &pcur, &mtr);
2946
 
                }
2947
 
 
2948
 
next_rec:
2949
 
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2950
 
        }
2951
 
 
2952
 
        btr_pcur_close(&pcur);
2953
 
        mtr_commit(&mtr);
2954
 
 
2955
 
        mem_heap_free(heap);
2956
 
 
2957
 
        /* Done with index truncation, release index tree locks,
2958
 
        subsequent work relates to table level metadata change */
2959
 
        dict_table_x_unlock_indexes(table);
2960
 
 
2961
 
        dict_hdr_get_new_id(&new_id, NULL, NULL);
2962
 
 
2963
 
        info = pars_info_create();
2964
 
 
2965
 
        pars_info_add_int4_literal(info, "space", (lint) table->space);
2966
 
        pars_info_add_ull_literal(info, "old_id", table->id);
2967
 
        pars_info_add_ull_literal(info, "new_id", new_id);
2968
 
 
2969
 
        err = que_eval_sql(info,
2970
 
                           "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2971
 
                           "BEGIN\n"
2972
 
                           "UPDATE SYS_TABLES"
2973
 
                           " SET ID = :new_id, SPACE = :space\n"
2974
 
                           " WHERE ID = :old_id;\n"
2975
 
                           "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2976
 
                           " WHERE TABLE_ID = :old_id;\n"
2977
 
                           "UPDATE SYS_INDEXES"
2978
 
                           " SET TABLE_ID = :new_id, SPACE = :space\n"
2979
 
                           " WHERE TABLE_ID = :old_id;\n"
2980
 
                           "COMMIT WORK;\n"
2981
 
                           "END;\n"
2982
 
                           , FALSE, trx);
2983
 
 
2984
 
        if (err != DB_SUCCESS) {
2985
 
                trx->error_state = DB_SUCCESS;
2986
 
                trx_general_rollback_for_mysql(trx, NULL);
2987
 
                trx->error_state = DB_SUCCESS;
2988
 
                ut_print_timestamp(stderr);
2989
 
                fputs("  InnoDB: Unable to assign a new identifier to table ",
2990
 
                      stderr);
2991
 
                ut_print_name(stderr, trx, TRUE, table->name);
2992
 
                fputs("\n"
2993
 
                      "InnoDB: after truncating it.  Background processes"
2994
 
                      " may corrupt the table!\n", stderr);
2995
 
                err = DB_ERROR;
2996
 
        } else {
2997
 
                dict_table_change_id_in_cache(table, new_id);
2998
 
        }
2999
 
 
3000
 
        /* 
3001
 
          MySQL calls ha_innobase::reset_auto_increment() which does
3002
 
          the same thing. 
3003
 
        */
3004
 
        dict_table_autoinc_lock(table);
3005
 
        dict_table_autoinc_initialize(table, 1);
3006
 
        dict_table_autoinc_unlock(table);
3007
 
        dict_update_statistics(table, FALSE /* update even if stats are
3008
 
                                            initialized */);
3009
 
 
3010
 
        trx_commit_for_mysql(trx);
3011
 
 
3012
 
funct_exit:
3013
 
 
3014
 
        row_mysql_unlock_data_dictionary(trx);
3015
 
 
3016
 
        trx->op_info = "";
3017
 
 
3018
 
        srv_wake_master_thread();
3019
 
 
3020
 
        return((int) err);
3021
 
}
3022
 
 
3023
 
/*********************************************************************//**
3024
 
Drops a table for MySQL.  If the name of the dropped table ends in
3025
 
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
3026
 
"innodb_table_monitor", then this will also stop the printing of monitor
3027
 
output by the master thread.  If the data dictionary was not already locked
3028
 
by the transaction, the transaction will be committed.  Otherwise, the
3029
 
data dictionary will remain locked.
3030
 
@return error code or DB_SUCCESS */
3031
 
UNIV_INTERN
3032
 
int
3033
 
row_drop_table_for_mysql(
3034
 
/*=====================*/
3035
 
        const char*     name,   /*!< in: table name */
3036
 
        trx_t*          trx,    /*!< in: transaction handle */
3037
 
        ibool           drop_db)/*!< in: TRUE=dropping whole database */
3038
 
{
3039
 
        dict_foreign_t* foreign;
3040
 
        dict_table_t*   table;
3041
 
        ulint           space_id;
3042
 
        ulint           err;
3043
 
        const char*     table_name;
3044
 
        ulint           namelen;
3045
 
        ibool           locked_dictionary       = FALSE;
3046
 
        pars_info_t*    info                    = NULL;
3047
 
 
3048
 
        ut_a(name != NULL);
3049
 
 
3050
 
        if (srv_created_new_raw) {
3051
 
                fputs("InnoDB: A new raw disk partition was initialized:\n"
3052
 
                      "InnoDB: we do not allow database modifications"
3053
 
                      " by the user.\n"
3054
 
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3055
 
                      " is replaced with raw.\n", stderr);
3056
 
 
3057
 
                return(DB_ERROR);
3058
 
        }
3059
 
 
3060
 
        trx->op_info = "dropping table";
3061
 
 
3062
 
        trx_start_if_not_started(trx);
3063
 
 
3064
 
        /* The table name is prefixed with the database name and a '/'.
3065
 
        Certain table names starting with 'innodb_' have their special
3066
 
        meaning regardless of the database name.  Thus, we need to
3067
 
        ignore the database name prefix in the comparisons. */
3068
 
        table_name = strchr(name, '/');
3069
 
        ut_a(table_name);
3070
 
        table_name++;
3071
 
        namelen = strlen(table_name) + 1;
3072
 
 
3073
 
        if (namelen == sizeof S_innodb_monitor
3074
 
            && !memcmp(table_name, S_innodb_monitor,
3075
 
                       sizeof S_innodb_monitor)) {
3076
 
 
3077
 
                /* Table name equals "innodb_monitor":
3078
 
                stop monitor prints */
3079
 
 
3080
 
                srv_print_innodb_monitor = FALSE;
3081
 
                srv_print_innodb_lock_monitor = FALSE;
3082
 
        } else if (namelen == sizeof S_innodb_lock_monitor
3083
 
                   && !memcmp(table_name, S_innodb_lock_monitor,
3084
 
                              sizeof S_innodb_lock_monitor)) {
3085
 
                srv_print_innodb_monitor = FALSE;
3086
 
                srv_print_innodb_lock_monitor = FALSE;
3087
 
        } else if (namelen == sizeof S_innodb_tablespace_monitor
3088
 
                   && !memcmp(table_name, S_innodb_tablespace_monitor,
3089
 
                              sizeof S_innodb_tablespace_monitor)) {
3090
 
 
3091
 
                srv_print_innodb_tablespace_monitor = FALSE;
3092
 
        } else if (namelen == sizeof S_innodb_table_monitor
3093
 
                   && !memcmp(table_name, S_innodb_table_monitor,
3094
 
                              sizeof S_innodb_table_monitor)) {
3095
 
 
3096
 
                srv_print_innodb_table_monitor = FALSE;
3097
 
        }
3098
 
 
3099
 
        /* Serialize data dictionary operations with dictionary mutex:
3100
 
        no deadlocks can occur then in these operations */
3101
 
 
3102
 
        if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3103
 
                /* Prevent foreign key checks etc. while we are dropping the
3104
 
                table */
3105
 
 
3106
 
                row_mysql_lock_data_dictionary(trx);
3107
 
 
3108
 
                locked_dictionary = TRUE;
3109
 
        }
3110
 
 
3111
 
        ut_ad(mutex_own(&(dict_sys->mutex)));
3112
 
#ifdef UNIV_SYNC_DEBUG
3113
 
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3114
 
#endif /* UNIV_SYNC_DEBUG */
3115
 
 
3116
 
        table = dict_table_get_low(name);
3117
 
 
3118
 
        if (!table) {
3119
 
#if defined(BUILD_DRIZZLE)
3120
 
                err = ENOENT;
3121
 
#else
3122
 
                err = DB_TABLE_NOT_FOUND;
3123
 
                ut_print_timestamp(stderr);
3124
 
 
3125
 
                fputs("  InnoDB: Error: table ", stderr);
3126
 
                ut_print_name(stderr, trx, TRUE, name);
3127
 
                fputs(" does not exist in the InnoDB internal\n"
3128
 
                      "InnoDB: data dictionary though MySQL is"
3129
 
                      " trying to drop it.\n"
3130
 
                      "InnoDB: Have you copied the .frm file"
3131
 
                      " of the table to the\n"
3132
 
                      "InnoDB: MySQL database directory"
3133
 
                      " from another database?\n"
3134
 
                      "InnoDB: You can look for further help from\n"
3135
 
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3136
 
                      stderr);
3137
 
#endif /* BUILD_DRIZZLE */
3138
 
                goto funct_exit;
3139
 
        }
3140
 
 
3141
 
        /* Check if the table is referenced by foreign key constraints from
3142
 
        some other table (not the table itself) */
3143
 
 
3144
 
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
3145
 
 
3146
 
        while (foreign && foreign->foreign_table == table) {
3147
 
check_next_foreign:
3148
 
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3149
 
        }
3150
 
 
3151
 
        if (foreign && trx->check_foreigns
3152
 
            && !(drop_db && dict_tables_have_same_db(
3153
 
                         name, foreign->foreign_table_name))) {
3154
 
                FILE*   ef      = dict_foreign_err_file;
3155
 
 
3156
 
                /* We only allow dropping a referenced table if
3157
 
                FOREIGN_KEY_CHECKS is set to 0 */
3158
 
 
3159
 
                err = DB_CANNOT_DROP_CONSTRAINT;
3160
 
 
3161
 
                mutex_enter(&dict_foreign_err_mutex);
3162
 
                rewind(ef);
3163
 
                ut_print_timestamp(ef);
3164
 
 
3165
 
                fputs("  Cannot drop table ", ef);
3166
 
                ut_print_name(ef, trx, TRUE, name);
3167
 
                fputs("\n"
3168
 
                      "because it is referenced by ", ef);
3169
 
                ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3170
 
                putc('\n', ef);
3171
 
                mutex_exit(&dict_foreign_err_mutex);
3172
 
 
3173
 
                goto funct_exit;
3174
 
        }
3175
 
 
3176
 
        if (foreign && trx->check_foreigns) {
3177
 
                goto check_next_foreign;
3178
 
        }
3179
 
 
3180
 
        if (table->n_mysql_handles_opened > 0) {
3181
 
                ibool   added;
3182
 
 
3183
 
                added = row_add_table_to_background_drop_list(table->name);
3184
 
 
3185
 
                if (added) {
3186
 
                        ut_print_timestamp(stderr);
3187
 
                        fputs("  InnoDB: Warning: MySQL is"
3188
 
                              " trying to drop table ", stderr);
3189
 
                        ut_print_name(stderr, trx, TRUE, table->name);
3190
 
                        fputs("\n"
3191
 
                              "InnoDB: though there are still"
3192
 
                              " open handles to it.\n"
3193
 
                              "InnoDB: Adding the table to the"
3194
 
                              " background drop queue.\n",
3195
 
                              stderr);
3196
 
 
3197
 
                        /* We return DB_SUCCESS to MySQL though the drop will
3198
 
                        happen lazily later */
3199
 
                        err = DB_SUCCESS;
3200
 
                } else {
3201
 
                        /* The table is already in the background drop list */
3202
 
                        err = DB_ERROR;
3203
 
                }
3204
 
 
3205
 
                goto funct_exit;
3206
 
        }
3207
 
 
3208
 
        /* TODO: could we replace the counter n_foreign_key_checks_running
3209
 
        with lock checks on the table? Acquire here an exclusive lock on the
3210
 
        table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3211
 
        they can cope with the table having been dropped here? Foreign key
3212
 
        checks take an IS or IX lock on the table. */
3213
 
 
3214
 
        if (table->n_foreign_key_checks_running > 0) {
3215
 
 
3216
 
                const char*     i_table_name = table->name;
3217
 
                ibool           added;
3218
 
 
3219
 
                added = row_add_table_to_background_drop_list(i_table_name);
3220
 
 
3221
 
                if (added) {
3222
 
                        ut_print_timestamp(stderr);
3223
 
                        fputs("  InnoDB: You are trying to drop table ",
3224
 
                              stderr);
3225
 
                        ut_print_name(stderr, trx, TRUE, i_table_name);
3226
 
                        fputs("\n"
3227
 
                              "InnoDB: though there is a"
3228
 
                              " foreign key check running on it.\n"
3229
 
                              "InnoDB: Adding the table to"
3230
 
                              " the background drop queue.\n",
3231
 
                              stderr);
3232
 
 
3233
 
                        /* We return DB_SUCCESS to MySQL though the drop will
3234
 
                        happen lazily later */
3235
 
 
3236
 
                        err = DB_SUCCESS;
3237
 
                } else {
3238
 
                        /* The table is already in the background drop list */
3239
 
                        err = DB_ERROR;
3240
 
                }
3241
 
 
3242
 
                goto funct_exit;
3243
 
        }
3244
 
 
3245
 
        /* Remove all locks there are on the table or its records */
3246
 
        lock_remove_all_on_table(table, TRUE);
3247
 
 
3248
 
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
3249
 
        trx->table_id = table->id;
3250
 
 
3251
 
        /* We use the private SQL parser of Innobase to generate the
3252
 
        query graphs needed in deleting the dictionary data from system
3253
 
        tables in Innobase. Deleting a row from SYS_INDEXES table also
3254
 
        frees the file segments of the B-tree associated with the index. */
3255
 
 
3256
 
        info = pars_info_create();
3257
 
 
3258
 
        pars_info_add_str_literal(info, "table_name", name);
3259
 
 
3260
 
        err = que_eval_sql(info,
3261
 
                           "PROCEDURE DROP_TABLE_PROC () IS\n"
3262
 
                           "sys_foreign_id CHAR;\n"
3263
 
                           "table_id CHAR;\n"
3264
 
                           "index_id CHAR;\n"
3265
 
                           "foreign_id CHAR;\n"
3266
 
                           "found INT;\n"
3267
 
                           "BEGIN\n"
3268
 
                           "SELECT ID INTO table_id\n"
3269
 
                           "FROM SYS_TABLES\n"
3270
 
                           "WHERE NAME = :table_name\n"
3271
 
                           "LOCK IN SHARE MODE;\n"
3272
 
                           "IF (SQL % NOTFOUND) THEN\n"
3273
 
                           "       RETURN;\n"
3274
 
                           "END IF;\n"
3275
 
                           "found := 1;\n"
3276
 
                           "SELECT ID INTO sys_foreign_id\n"
3277
 
                           "FROM SYS_TABLES\n"
3278
 
                           "WHERE NAME = 'SYS_FOREIGN'\n"
3279
 
                           "LOCK IN SHARE MODE;\n"
3280
 
                           "IF (SQL % NOTFOUND) THEN\n"
3281
 
                           "       found := 0;\n"
3282
 
                           "END IF;\n"
3283
 
                           "IF (:table_name = 'SYS_FOREIGN') THEN\n"
3284
 
                           "       found := 0;\n"
3285
 
                           "END IF;\n"
3286
 
                           "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3287
 
                           "       found := 0;\n"
3288
 
                           "END IF;\n"
3289
 
                           "WHILE found = 1 LOOP\n"
3290
 
                           "       SELECT ID INTO foreign_id\n"
3291
 
                           "       FROM SYS_FOREIGN\n"
3292
 
                           "       WHERE FOR_NAME = :table_name\n"
3293
 
                           "               AND TO_BINARY(FOR_NAME)\n"
3294
 
                           "                 = TO_BINARY(:table_name)\n"
3295
 
                           "               LOCK IN SHARE MODE;\n"
3296
 
                           "       IF (SQL % NOTFOUND) THEN\n"
3297
 
                           "               found := 0;\n"
3298
 
                           "       ELSE\n"
3299
 
                           "               DELETE FROM SYS_FOREIGN_COLS\n"
3300
 
                           "               WHERE ID = foreign_id;\n"
3301
 
                           "               DELETE FROM SYS_FOREIGN\n"
3302
 
                           "               WHERE ID = foreign_id;\n"
3303
 
                           "       END IF;\n"
3304
 
                           "END LOOP;\n"
3305
 
                           "found := 1;\n"
3306
 
                           "WHILE found = 1 LOOP\n"
3307
 
                           "       SELECT ID INTO index_id\n"
3308
 
                           "       FROM SYS_INDEXES\n"
3309
 
                           "       WHERE TABLE_ID = table_id\n"
3310
 
                           "       LOCK IN SHARE MODE;\n"
3311
 
                           "       IF (SQL % NOTFOUND) THEN\n"
3312
 
                           "               found := 0;\n"
3313
 
                           "       ELSE\n"
3314
 
                           "               DELETE FROM SYS_FIELDS\n"
3315
 
                           "               WHERE INDEX_ID = index_id;\n"
3316
 
                           "               DELETE FROM SYS_INDEXES\n"
3317
 
                           "               WHERE ID = index_id\n"
3318
 
                           "               AND TABLE_ID = table_id;\n"
3319
 
                           "       END IF;\n"
3320
 
                           "END LOOP;\n"
3321
 
                           "DELETE FROM SYS_COLUMNS\n"
3322
 
                           "WHERE TABLE_ID = table_id;\n"
3323
 
                           "DELETE FROM SYS_TABLES\n"
3324
 
                           "WHERE ID = table_id;\n"
3325
 
                           "END;\n"
3326
 
                           , FALSE, trx);
3327
 
 
3328
 
        switch (err) {
3329
 
                ibool           is_temp;
3330
 
                const char*     name_or_path;
3331
 
                mem_heap_t*     heap;
3332
 
 
3333
 
        case DB_SUCCESS:
3334
 
 
3335
 
                heap = mem_heap_create(200);
3336
 
 
3337
 
                /* Clone the name, in case it has been allocated
3338
 
                from table->heap, which will be freed by
3339
 
                dict_table_remove_from_cache(table) below. */
3340
 
                name = mem_heap_strdup(heap, name);
3341
 
                space_id = table->space;
3342
 
 
3343
 
                if (table->dir_path_of_temp_table != NULL) {
3344
 
                        name_or_path = mem_heap_strdup(
3345
 
                                heap, table->dir_path_of_temp_table);
3346
 
                        is_temp = TRUE;
3347
 
                } else {
3348
 
                        name_or_path = name;
3349
 
                        is_temp = (table->flags >> DICT_TF2_SHIFT)
3350
 
                                & DICT_TF2_TEMPORARY;
3351
 
                }
3352
 
 
3353
 
                dict_table_remove_from_cache(table);
3354
 
 
3355
 
                if (dict_load_table(name, TRUE) != NULL) {
3356
 
                        ut_print_timestamp(stderr);
3357
 
                        fputs("  InnoDB: Error: not able to remove table ",
3358
 
                              stderr);
3359
 
                        ut_print_name(stderr, trx, TRUE, name);
3360
 
                        fputs(" from the dictionary cache!\n", stderr);
3361
 
                        err = DB_ERROR;
3362
 
                }
3363
 
 
3364
 
                /* Do not drop possible .ibd tablespace if something went
3365
 
                wrong: we do not want to delete valuable data of the user */
3366
 
 
3367
 
                if (err == DB_SUCCESS && space_id > 0) {
3368
 
                        if (!fil_space_for_table_exists_in_mem(space_id,
3369
 
                                                               name_or_path,
3370
 
                                                               is_temp, FALSE,
3371
 
                                                               !is_temp)) {
3372
 
                                err = DB_SUCCESS;
3373
 
 
3374
 
                                fprintf(stderr,
3375
 
                                        "InnoDB: We removed now the InnoDB"
3376
 
                                        " internal data dictionary entry\n"
3377
 
                                        "InnoDB: of table ");
3378
 
                                ut_print_name(stderr, trx, TRUE, name);
3379
 
                                fprintf(stderr, ".\n");
3380
 
                        } else if (!fil_delete_tablespace(space_id)) {
3381
 
                                fprintf(stderr,
3382
 
                                        "InnoDB: We removed now the InnoDB"
3383
 
                                        " internal data dictionary entry\n"
3384
 
                                        "InnoDB: of table ");
3385
 
                                ut_print_name(stderr, trx, TRUE, name);
3386
 
                                fprintf(stderr, ".\n");
3387
 
 
3388
 
                                ut_print_timestamp(stderr);
3389
 
                                fprintf(stderr,
3390
 
                                        "  InnoDB: Error: not able to"
3391
 
                                        " delete tablespace %lu of table ",
3392
 
                                        (ulong) space_id);
3393
 
                                ut_print_name(stderr, trx, TRUE, name);
3394
 
                                fputs("!\n", stderr);
3395
 
                                err = DB_ERROR;
3396
 
                        }
3397
 
                }
3398
 
 
3399
 
                mem_heap_free(heap);
3400
 
                break;
3401
 
 
3402
 
        case DB_TOO_MANY_CONCURRENT_TRXS:
3403
 
                /* Cannot even find a free slot for the
3404
 
                the undo log. We can directly exit here
3405
 
                and return the DB_TOO_MANY_CONCURRENT_TRXS
3406
 
                error. */
3407
 
                break;
3408
 
 
3409
 
        case DB_OUT_OF_FILE_SPACE:
3410
 
                err = DB_MUST_GET_MORE_FILE_SPACE;
3411
 
 
3412
 
                row_mysql_handle_errors(&err, trx, NULL, NULL);
3413
 
 
3414
 
                /* Fall through to raise error */
3415
 
 
3416
 
        default:
3417
 
                /* No other possible error returns */
3418
 
                ut_error;
3419
 
        }
3420
 
 
3421
 
funct_exit:
3422
 
 
3423
 
        if (locked_dictionary) {
3424
 
                trx_commit_for_mysql(trx);
3425
 
 
3426
 
                row_mysql_unlock_data_dictionary(trx);
3427
 
        }
3428
 
 
3429
 
        trx->op_info = "";
3430
 
 
3431
 
        srv_wake_master_thread();
3432
 
 
3433
 
        return((int) err);
3434
 
}
3435
 
 
3436
 
/*********************************************************************//**
3437
 
Drop all temporary tables during crash recovery. */
3438
 
UNIV_INTERN
3439
 
void
3440
 
row_mysql_drop_temp_tables(void)
3441
 
/*============================*/
3442
 
{
3443
 
        trx_t*          trx;
3444
 
        btr_pcur_t      pcur;
3445
 
        mtr_t           mtr;
3446
 
        mem_heap_t*     heap;
3447
 
 
3448
 
        trx = trx_allocate_for_background();
3449
 
        trx->op_info = "dropping temporary tables";
3450
 
        row_mysql_lock_data_dictionary(trx);
3451
 
 
3452
 
        heap = mem_heap_create(200);
3453
 
 
3454
 
        mtr_start(&mtr);
3455
 
 
3456
 
        btr_pcur_open_at_index_side(
3457
 
                TRUE,
3458
 
                dict_table_get_first_index(dict_sys->sys_tables),
3459
 
                BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3460
 
 
3461
 
        for (;;) {
3462
 
                const rec_t*    rec;
3463
 
                const byte*     field;
3464
 
                ulint           len;
3465
 
                const char*     table_name;
3466
 
                dict_table_t*   table;
3467
 
 
3468
 
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3469
 
 
3470
 
                if (!btr_pcur_is_on_user_rec(&pcur)) {
3471
 
                        break;
3472
 
                }
3473
 
 
3474
 
                rec = btr_pcur_get_rec(&pcur);
3475
 
                field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
3476
 
                if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
3477
 
                        continue;
3478
 
                }
3479
 
 
3480
 
                /* Because this is not a ROW_FORMAT=REDUNDANT table,
3481
 
                the is_temp flag is valid.  Examine it. */
3482
 
 
3483
 
                field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
3484
 
                if (len != 4
3485
 
                    || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
3486
 
                        continue;
3487
 
                }
3488
 
 
3489
 
                /* This is a temporary table. */
3490
 
                field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
3491
 
                if (len == UNIV_SQL_NULL || len == 0) {
3492
 
                        /* Corrupted SYS_TABLES.NAME */
3493
 
                        continue;
3494
 
                }
3495
 
 
3496
 
                table_name = mem_heap_strdupl(heap, (const char*) field, len);
3497
 
 
3498
 
                btr_pcur_store_position(&pcur, &mtr);
3499
 
                btr_pcur_commit_specify_mtr(&pcur, &mtr);
3500
 
 
3501
 
                table = dict_load_table(table_name, TRUE);
3502
 
 
3503
 
                if (table) {
3504
 
                        row_drop_table_for_mysql(table_name, trx, FALSE);
3505
 
                        trx_commit_for_mysql(trx);
3506
 
                }
3507
 
 
3508
 
                mtr_start(&mtr);
3509
 
                btr_pcur_restore_position(BTR_SEARCH_LEAF,
3510
 
                                          &pcur, &mtr);
3511
 
        }
3512
 
 
3513
 
        btr_pcur_close(&pcur);
3514
 
        mtr_commit(&mtr);
3515
 
        mem_heap_free(heap);
3516
 
        row_mysql_unlock_data_dictionary(trx);
3517
 
        trx_free_for_background(trx);
3518
 
}
3519
 
 
3520
 
/*******************************************************************//**
3521
 
Drop all foreign keys in a database, see Bug#18942.
3522
 
Called at the end of row_drop_database_for_mysql().
3523
 
@return error code or DB_SUCCESS */
3524
 
static
3525
 
ulint
3526
 
drop_all_foreign_keys_in_db(
3527
 
/*========================*/
3528
 
        const char*     name,   /*!< in: database name which ends to '/' */
3529
 
        trx_t*          trx)    /*!< in: transaction handle */
3530
 
{
3531
 
        pars_info_t*    pinfo;
3532
 
        ulint           err;
3533
 
 
3534
 
        ut_a(name[strlen(name) - 1] == '/');
3535
 
 
3536
 
        pinfo = pars_info_create();
3537
 
 
3538
 
        pars_info_add_str_literal(pinfo, "dbname", name);
3539
 
 
3540
 
/** true if for_name is not prefixed with dbname */
3541
 
#define TABLE_NOT_IN_THIS_DB \
3542
 
"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3543
 
 
3544
 
        err = que_eval_sql(pinfo,
3545
 
                           "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3546
 
                           "foreign_id CHAR;\n"
3547
 
                           "for_name CHAR;\n"
3548
 
                           "found INT;\n"
3549
 
                           "DECLARE CURSOR cur IS\n"
3550
 
                           "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3551
 
                           "WHERE FOR_NAME >= :dbname\n"
3552
 
                           "LOCK IN SHARE MODE\n"
3553
 
                           "ORDER BY FOR_NAME;\n"
3554
 
                           "BEGIN\n"
3555
 
                           "found := 1;\n"
3556
 
                           "OPEN cur;\n"
3557
 
                           "WHILE found = 1 LOOP\n"
3558
 
                           "        FETCH cur INTO foreign_id, for_name;\n"
3559
 
                           "        IF (SQL % NOTFOUND) THEN\n"
3560
 
                           "                found := 0;\n"
3561
 
                           "        ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3562
 
                           "                found := 0;\n"
3563
 
                           "        ELSIF (1=1) THEN\n"
3564
 
                           "                DELETE FROM SYS_FOREIGN_COLS\n"
3565
 
                           "                WHERE ID = foreign_id;\n"
3566
 
                           "                DELETE FROM SYS_FOREIGN\n"
3567
 
                           "                WHERE ID = foreign_id;\n"
3568
 
                           "        END IF;\n"
3569
 
                           "END LOOP;\n"
3570
 
                           "CLOSE cur;\n"
3571
 
                           "COMMIT WORK;\n"
3572
 
                           "END;\n",
3573
 
                           FALSE, /* do not reserve dict mutex,
3574
 
                                  we are already holding it */
3575
 
                           trx);
3576
 
 
3577
 
        return(err);
3578
 
}
3579
 
 
3580
 
/*********************************************************************//**
3581
 
Drops a database for MySQL.
3582
 
@return error code or DB_SUCCESS */
3583
 
UNIV_INTERN
3584
 
int
3585
 
row_drop_database_for_mysql(
3586
 
/*========================*/
3587
 
        const char*     name,   /*!< in: database name which ends to '/' */
3588
 
        trx_t*          trx)    /*!< in: transaction handle */
3589
 
{
3590
 
        dict_table_t* table;
3591
 
        char*   table_name;
3592
 
        int     err     = DB_SUCCESS;
3593
 
        ulint   namelen = strlen(name);
3594
 
 
3595
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3596
 
        ut_a(name != NULL);
3597
 
        ut_a(name[namelen - 1] == '/');
3598
 
 
3599
 
        trx->op_info = "dropping database";
3600
 
 
3601
 
        trx_start_if_not_started(trx);
3602
 
loop:
3603
 
        row_mysql_lock_data_dictionary(trx);
3604
 
 
3605
 
        while ((table_name = dict_get_first_table_name_in_db(name))) {
3606
 
                ut_a(memcmp(table_name, name, namelen) == 0);
3607
 
 
3608
 
                // For the time being I would like to see how often we see
3609
 
                // lost temporary tables. --Brian
3610
 
                fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
3611
 
 
3612
 
                table = dict_table_get_low(table_name);
3613
 
 
3614
 
                ut_a(table);
3615
 
 
3616
 
                /* Wait until MySQL does not have any queries running on
3617
 
                the table */
3618
 
 
3619
 
                if (table->n_mysql_handles_opened > 0) {
3620
 
                        row_mysql_unlock_data_dictionary(trx);
3621
 
 
3622
 
                        ut_print_timestamp(stderr);
3623
 
                        fputs("  InnoDB: Warning: MySQL is trying to"
3624
 
                              " drop database ", stderr);
3625
 
                        ut_print_name(stderr, trx, TRUE, name);
3626
 
                        fputs("\n"
3627
 
                              "InnoDB: though there are still"
3628
 
                              " open handles to table ", stderr);
3629
 
                        ut_print_name(stderr, trx, TRUE, table_name);
3630
 
                        fputs(".\n", stderr);
3631
 
 
3632
 
                        os_thread_sleep(1000000);
3633
 
 
3634
 
                        mem_free(table_name);
3635
 
 
3636
 
                        goto loop;
3637
 
                }
3638
 
 
3639
 
                err = row_drop_table_for_mysql(table_name, trx, TRUE);
3640
 
                trx_commit_for_mysql(trx);
3641
 
 
3642
 
                if (err != DB_SUCCESS) {
3643
 
                        fputs("InnoDB: DROP DATABASE ", stderr);
3644
 
                        ut_print_name(stderr, trx, TRUE, name);
3645
 
                        fprintf(stderr, " failed with error %lu for table ",
3646
 
                                (ulint) err);
3647
 
                        ut_print_name(stderr, trx, TRUE, table_name);
3648
 
                        putc('\n', stderr);
3649
 
                        mem_free(table_name);
3650
 
                        break;
3651
 
                }
3652
 
 
3653
 
                mem_free(table_name);
3654
 
        }
3655
 
 
3656
 
        if (err == DB_SUCCESS) {
3657
 
                /* after dropping all tables try to drop all leftover
3658
 
                foreign keys in case orphaned ones exist */
3659
 
                err = (int) drop_all_foreign_keys_in_db(name, trx);
3660
 
 
3661
 
                if (err != DB_SUCCESS) {
3662
 
                        fputs("InnoDB: DROP DATABASE ", stderr);
3663
 
                        ut_print_name(stderr, trx, TRUE, name);
3664
 
                        fprintf(stderr, " failed with error %d while "
3665
 
                                "dropping all foreign keys", err);
3666
 
                }
3667
 
        }
3668
 
 
3669
 
        trx_commit_for_mysql(trx);
3670
 
 
3671
 
        row_mysql_unlock_data_dictionary(trx);
3672
 
 
3673
 
        trx->op_info = "";
3674
 
 
3675
 
        return(err);
3676
 
}
3677
 
 
3678
 
/*********************************************************************//**
3679
 
Checks if a table name contains the string "/#sql" which denotes temporary
3680
 
tables in MySQL.
3681
 
@return TRUE if temporary table */
3682
 
static
3683
 
ibool
3684
 
row_is_mysql_tmp_table_name(
3685
 
/*========================*/
3686
 
        const char*     name)   /*!< in: table name in the form
3687
 
                                'database/tablename' */
3688
 
{
3689
 
        return(strstr(name, "/#sql") != NULL);
3690
 
        /* return(strstr(name, "/@0023sql") != NULL); */
3691
 
}
3692
 
 
3693
 
/****************************************************************//**
3694
 
Delete a single constraint.
3695
 
@return error code or DB_SUCCESS */
3696
 
static
3697
 
int
3698
 
row_delete_constraint_low(
3699
 
/*======================*/
3700
 
        const char*     id,             /*!< in: constraint id */
3701
 
        trx_t*          trx)            /*!< in: transaction handle */
3702
 
{
3703
 
        pars_info_t*    info = pars_info_create();
3704
 
 
3705
 
        pars_info_add_str_literal(info, "id", id);
3706
 
 
3707
 
        return((int) que_eval_sql(info,
3708
 
                            "PROCEDURE DELETE_CONSTRAINT () IS\n"
3709
 
                            "BEGIN\n"
3710
 
                            "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3711
 
                            "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3712
 
                            "END;\n"
3713
 
                            , FALSE, trx));
3714
 
}
3715
 
 
3716
 
/****************************************************************//**
3717
 
Delete a single constraint.
3718
 
@return error code or DB_SUCCESS */
3719
 
static
3720
 
int
3721
 
row_delete_constraint(
3722
 
/*==================*/
3723
 
        const char*     id,             /*!< in: constraint id */
3724
 
        const char*     database_name,  /*!< in: database name, with the
3725
 
                                        trailing '/' */
3726
 
        mem_heap_t*     heap,           /*!< in: memory heap */
3727
 
        trx_t*          trx)            /*!< in: transaction handle */
3728
 
{
3729
 
        ulint           err;
3730
 
 
3731
 
        /* New format constraints have ids <databasename>/<constraintname>. */
3732
 
        err = row_delete_constraint_low(
3733
 
                mem_heap_strcat(heap, database_name, id), trx);
3734
 
 
3735
 
        if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3736
 
                /* Old format < 4.0.18 constraints have constraint ids
3737
 
                <number>_<number>. We only try deleting them if the
3738
 
                constraint name does not contain a '/' character, otherwise
3739
 
                deleting a new format constraint named 'foo/bar' from
3740
 
                database 'baz' would remove constraint 'bar' from database
3741
 
                'foo', if it existed. */
3742
 
 
3743
 
                err = row_delete_constraint_low(id, trx);
3744
 
        }
3745
 
 
3746
 
        return((int) err);
3747
 
}
3748
 
 
3749
 
/*********************************************************************//**
3750
 
Renames a table for MySQL.
3751
 
@return error code or DB_SUCCESS */
3752
 
UNIV_INTERN
3753
 
ulint
3754
 
row_rename_table_for_mysql(
3755
 
/*=======================*/
3756
 
        const char*     old_name,       /*!< in: old table name */
3757
 
        const char*     new_name,       /*!< in: new table name */
3758
 
        trx_t*          trx,            /*!< in: transaction handle */
3759
 
        ibool           commit)         /*!< in: if TRUE then commit trx */
3760
 
{
3761
 
        dict_table_t*   table;
3762
 
        ulint           err                     = DB_ERROR;
3763
 
        mem_heap_t*     heap                    = NULL;
3764
 
        const char**    constraints_to_drop     = NULL;
3765
 
        ulint           n_constraints_to_drop   = 0;
3766
 
        ibool           old_is_tmp, new_is_tmp;
3767
 
        pars_info_t*    info                    = NULL;
3768
 
 
3769
 
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3770
 
        ut_a(old_name != NULL);
3771
 
        ut_a(new_name != NULL);
3772
 
 
3773
 
        if (srv_created_new_raw || srv_force_recovery) {
3774
 
                fputs("InnoDB: A new raw disk partition was initialized or\n"
3775
 
                      "InnoDB: innodb_force_recovery is on: we do not allow\n"
3776
 
                      "InnoDB: database modifications by the user. Shut down\n"
3777
 
                      "InnoDB: mysqld and edit my.cnf so that newraw"
3778
 
                      " is replaced\n"
3779
 
                      "InnoDB: with raw, and innodb_force_... is removed.\n",
3780
 
                      stderr);
3781
 
 
3782
 
                goto funct_exit;
3783
 
        }
3784
 
 
3785
 
        trx->op_info = "renaming table";
3786
 
        trx_start_if_not_started(trx);
3787
 
 
3788
 
        old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3789
 
        new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3790
 
 
3791
 
        table = dict_table_get_low(old_name);
3792
 
 
3793
 
        if (!table) {
3794
 
#if defined(BUILD_DRIZZLE)
3795
 
                err = ENOENT;
3796
 
#else
3797
 
                err = DB_TABLE_NOT_FOUND;
3798
 
                ut_print_timestamp(stderr);
3799
 
 
3800
 
                fputs("  InnoDB: Error: table ", stderr);
3801
 
                ut_print_name(stderr, trx, TRUE, old_name);
3802
 
                fputs(" does not exist in the InnoDB internal\n"
3803
 
                      "InnoDB: data dictionary though MySQL is"
3804
 
                      " trying to rename the table.\n"
3805
 
                      "InnoDB: Have you copied the .frm file"
3806
 
                      " of the table to the\n"
3807
 
                      "InnoDB: MySQL database directory"
3808
 
                      " from another database?\n"
3809
 
                      "InnoDB: You can look for further help from\n"
3810
 
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3811
 
                      stderr);
3812
 
#endif /* BUILD_DRIZZLE */
3813
 
                goto funct_exit;
3814
 
        } else if (table->ibd_file_missing) {
3815
 
                err = DB_TABLE_NOT_FOUND;
3816
 
                ut_print_timestamp(stderr);
3817
 
 
3818
 
                fputs("  InnoDB: Error: table ", stderr);
3819
 
                ut_print_name(stderr, trx, TRUE, old_name);
3820
 
                fputs(" does not have an .ibd file"
3821
 
                      " in the database directory.\n"
3822
 
                      "InnoDB: You can look for further help from\n"
3823
 
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3824
 
                      stderr);
3825
 
                goto funct_exit;
3826
 
        } else if (new_is_tmp) {
3827
 
                /* MySQL is doing an ALTER TABLE command and it renames the
3828
 
                original table to a temporary table name. We want to preserve
3829
 
                the original foreign key constraint definitions despite the
3830
 
                name change. An exception is those constraints for which
3831
 
                the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3832
 
 
3833
 
                heap = mem_heap_create(100);
3834
 
 
3835
 
                err = dict_foreign_parse_drop_constraints(
3836
 
                        heap, trx, table, &n_constraints_to_drop,
3837
 
                        &constraints_to_drop);
3838
 
 
3839
 
                if (err != DB_SUCCESS) {
3840
 
 
3841
 
                        goto funct_exit;
3842
 
                }
3843
 
        }
3844
 
 
3845
 
        /* We use the private SQL parser of Innobase to generate the query
3846
 
        graphs needed in updating the dictionary data from system tables. */
3847
 
 
3848
 
        info = pars_info_create();
3849
 
 
3850
 
        pars_info_add_str_literal(info, "new_table_name", new_name);
3851
 
        pars_info_add_str_literal(info, "old_table_name", old_name);
3852
 
 
3853
 
        err = que_eval_sql(info,
3854
 
                           "PROCEDURE RENAME_TABLE () IS\n"
3855
 
                           "BEGIN\n"
3856
 
                           "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3857
 
                           " WHERE NAME = :old_table_name;\n"
3858
 
                           "END;\n"
3859
 
                           , FALSE, trx);
3860
 
 
3861
 
        if (err != DB_SUCCESS) {
3862
 
 
3863
 
                goto end;
3864
 
        } else if (!new_is_tmp) {
3865
 
                /* Rename all constraints. */
3866
 
 
3867
 
                info = pars_info_create();
3868
 
 
3869
 
                pars_info_add_str_literal(info, "new_table_name", new_name);
3870
 
                pars_info_add_str_literal(info, "old_table_name", old_name);
3871
 
 
3872
 
                err = que_eval_sql(
3873
 
                        info,
3874
 
                        "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3875
 
                        "gen_constr_prefix CHAR;\n"
3876
 
                        "new_db_name CHAR;\n"
3877
 
                        "foreign_id CHAR;\n"
3878
 
                        "new_foreign_id CHAR;\n"
3879
 
                        "old_db_name_len INT;\n"
3880
 
                        "old_t_name_len INT;\n"
3881
 
                        "new_db_name_len INT;\n"
3882
 
                        "id_len INT;\n"
3883
 
                        "found INT;\n"
3884
 
                        "BEGIN\n"
3885
 
                        "found := 1;\n"
3886
 
                        "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3887
 
                        "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3888
 
                        "new_db_name := SUBSTR(:new_table_name, 0,\n"
3889
 
                        "                      new_db_name_len);\n"
3890
 
                        "old_t_name_len := LENGTH(:old_table_name);\n"
3891
 
                        "gen_constr_prefix := CONCAT(:old_table_name,\n"
3892
 
                        "                            '_ibfk_');\n"
3893
 
                        "WHILE found = 1 LOOP\n"
3894
 
                        "       SELECT ID INTO foreign_id\n"
3895
 
                        "        FROM SYS_FOREIGN\n"
3896
 
                        "        WHERE FOR_NAME = :old_table_name\n"
3897
 
                        "         AND TO_BINARY(FOR_NAME)\n"
3898
 
                        "           = TO_BINARY(:old_table_name)\n"
3899
 
                        "         LOCK IN SHARE MODE;\n"
3900
 
                        "       IF (SQL % NOTFOUND) THEN\n"
3901
 
                        "        found := 0;\n"
3902
 
                        "       ELSE\n"
3903
 
                        "        UPDATE SYS_FOREIGN\n"
3904
 
                        "        SET FOR_NAME = :new_table_name\n"
3905
 
                        "         WHERE ID = foreign_id;\n"
3906
 
                        "        id_len := LENGTH(foreign_id);\n"
3907
 
                        "        IF (INSTR(foreign_id, '/') > 0) THEN\n"
3908
 
                        "               IF (INSTR(foreign_id,\n"
3909
 
                        "                         gen_constr_prefix) > 0)\n"
3910
 
                        "               THEN\n"
3911
 
                        "                new_foreign_id :=\n"
3912
 
                        "                CONCAT(:new_table_name,\n"
3913
 
                        "                SUBSTR(foreign_id, old_t_name_len,\n"
3914
 
                        "                       id_len - old_t_name_len));\n"
3915
 
                        "               ELSE\n"
3916
 
                        "                new_foreign_id :=\n"
3917
 
                        "                CONCAT(new_db_name,\n"
3918
 
                        "                SUBSTR(foreign_id,\n"
3919
 
                        "                       old_db_name_len,\n"
3920
 
                        "                       id_len - old_db_name_len));\n"
3921
 
                        "               END IF;\n"
3922
 
                        "               UPDATE SYS_FOREIGN\n"
3923
 
                        "                SET ID = new_foreign_id\n"
3924
 
                        "                WHERE ID = foreign_id;\n"
3925
 
                        "               UPDATE SYS_FOREIGN_COLS\n"
3926
 
                        "                SET ID = new_foreign_id\n"
3927
 
                        "                WHERE ID = foreign_id;\n"
3928
 
                        "        END IF;\n"
3929
 
                        "       END IF;\n"
3930
 
                        "END LOOP;\n"
3931
 
                        "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3932
 
                        "WHERE REF_NAME = :old_table_name\n"
3933
 
                        "  AND TO_BINARY(REF_NAME)\n"
3934
 
                        "    = TO_BINARY(:old_table_name);\n"
3935
 
                        "END;\n"
3936
 
                        , FALSE, trx);
3937
 
 
3938
 
        } else if (n_constraints_to_drop > 0) {
3939
 
                /* Drop some constraints of tmp tables. */
3940
 
 
3941
 
                ulint   db_name_len = dict_get_db_name_len(old_name) + 1;
3942
 
                char*   db_name = mem_heap_strdupl(heap, old_name,
3943
 
                                                   db_name_len);
3944
 
                ulint   i;
3945
 
 
3946
 
                for (i = 0; i < n_constraints_to_drop; i++) {
3947
 
                        err = row_delete_constraint(constraints_to_drop[i],
3948
 
                                                    db_name, heap, trx);
3949
 
 
3950
 
                        if (err != DB_SUCCESS) {
3951
 
                                break;
3952
 
                        }
3953
 
                }
3954
 
        }
3955
 
 
3956
 
end:
3957
 
        if (err != DB_SUCCESS) {
3958
 
                if (err == DB_DUPLICATE_KEY) {
3959
 
                        ut_print_timestamp(stderr);
3960
 
                        fputs("  InnoDB: Error; possible reasons:\n"
3961
 
                              "InnoDB: 1) Table rename would cause"
3962
 
                              " two FOREIGN KEY constraints\n"
3963
 
                              "InnoDB: to have the same internal name"
3964
 
                              " in case-insensitive comparison.\n"
3965
 
                              "InnoDB: 2) table ", stderr);
3966
 
                        ut_print_name(stderr, trx, TRUE, new_name);
3967
 
                        fputs(" exists in the InnoDB internal data\n"
3968
 
                              "InnoDB: dictionary though MySQL is"
3969
 
                              " trying to rename table ", stderr);
3970
 
                        ut_print_name(stderr, trx, TRUE, old_name);
3971
 
                        fputs(" to it.\n"
3972
 
                              "InnoDB: Have you deleted the .frm file"
3973
 
                              " and not used DROP TABLE?\n"
3974
 
                              "InnoDB: You can look for further help from\n"
3975
 
                              "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
3976
 
                              "InnoDB: If table ", stderr);
3977
 
                        ut_print_name(stderr, trx, TRUE, new_name);
3978
 
                        fputs(" is a temporary table #sql..., then"
3979
 
                              " it can be that\n"
3980
 
                              "InnoDB: there are still queries running"
3981
 
                              " on the table, and it will be\n"
3982
 
                              "InnoDB: dropped automatically when"
3983
 
                              " the queries end.\n"
3984
 
                              "InnoDB: You can drop the orphaned table"
3985
 
                              " inside InnoDB by\n"
3986
 
                              "InnoDB: creating an InnoDB table with"
3987
 
                              " the same name in another\n"
3988
 
                              "InnoDB: database and copying the .frm file"
3989
 
                              " to the current database.\n"
3990
 
                              "InnoDB: Then MySQL thinks the table exists,"
3991
 
                              " and DROP TABLE will\n"
3992
 
                              "InnoDB: succeed.\n", stderr);
3993
 
                }
3994
 
                trx->error_state = DB_SUCCESS;
3995
 
                trx_general_rollback_for_mysql(trx, NULL);
3996
 
                trx->error_state = DB_SUCCESS;
3997
 
        } else {
3998
 
                /* The following call will also rename the .ibd data file if
3999
 
                the table is stored in a single-table tablespace */
4000
 
 
4001
 
                if (!dict_table_rename_in_cache(table, new_name,
4002
 
                                                !new_is_tmp)) {
4003
 
                        trx->error_state = DB_SUCCESS;
4004
 
                        trx_general_rollback_for_mysql(trx, NULL);
4005
 
                        trx->error_state = DB_SUCCESS;
4006
 
                        goto funct_exit;
4007
 
                }
4008
 
 
4009
 
                /* We only want to switch off some of the type checking in
4010
 
                an ALTER, not in a RENAME. */
4011
 
 
4012
 
                err = dict_load_foreigns(
4013
 
                        new_name, FALSE, !old_is_tmp || trx->check_foreigns);
4014
 
 
4015
 
                if (err != DB_SUCCESS) {
4016
 
                        ut_print_timestamp(stderr);
4017
 
 
4018
 
                        if (old_is_tmp) {
4019
 
                                fputs("  InnoDB: Error: in ALTER TABLE ",
4020
 
                                      stderr);
4021
 
                                ut_print_name(stderr, trx, TRUE, new_name);
4022
 
                                fputs("\n"
4023
 
                                      "InnoDB: has or is referenced"
4024
 
                                      " in foreign key constraints\n"
4025
 
                                      "InnoDB: which are not compatible"
4026
 
                                      " with the new table definition.\n",
4027
 
                                      stderr);
4028
 
                        } else {
4029
 
                                fputs("  InnoDB: Error: in RENAME TABLE"
4030
 
                                      " table ",
4031
 
                                      stderr);
4032
 
                                ut_print_name(stderr, trx, TRUE, new_name);
4033
 
                                fputs("\n"
4034
 
                                      "InnoDB: is referenced in"
4035
 
                                      " foreign key constraints\n"
4036
 
                                      "InnoDB: which are not compatible"
4037
 
                                      " with the new table definition.\n",
4038
 
                                      stderr);
4039
 
                        }
4040
 
 
4041
 
                        ut_a(dict_table_rename_in_cache(table,
4042
 
                                                        old_name, FALSE));
4043
 
                        trx->error_state = DB_SUCCESS;
4044
 
                        trx_general_rollback_for_mysql(trx, NULL);
4045
 
                        trx->error_state = DB_SUCCESS;
4046
 
                }
4047
 
        }
4048
 
 
4049
 
funct_exit:
4050
 
 
4051
 
        if (commit) {
4052
 
                trx_commit_for_mysql(trx);
4053
 
        }
4054
 
 
4055
 
        if (UNIV_LIKELY_NULL(heap)) {
4056
 
                mem_heap_free(heap);
4057
 
        }
4058
 
 
4059
 
        trx->op_info = "";
4060
 
 
4061
 
        return(err);
4062
 
}
4063
 
 
4064
 
/*********************************************************************//**
4065
 
Checks that the index contains entries in an ascending order, unique
4066
 
constraint is not broken, and calculates the number of index entries
4067
 
in the read view of the current transaction.
4068
 
@return TRUE if ok */
4069
 
UNIV_INTERN
4070
 
ibool
4071
 
row_check_index_for_mysql(
4072
 
/*======================*/
4073
 
        row_prebuilt_t*         prebuilt,       /*!< in: prebuilt struct
4074
 
                                                in MySQL handle */
4075
 
        const dict_index_t*     index,          /*!< in: index */
4076
 
        ulint*                  n_rows)         /*!< out: number of entries
4077
 
                                                seen in the consistent read */
4078
 
{
4079
 
        dtuple_t*       prev_entry      = NULL;
4080
 
        ulint           matched_fields;
4081
 
        ulint           matched_bytes;
4082
 
        byte*           buf;
4083
 
        ulint           ret;
4084
 
        rec_t*          rec;
4085
 
        ibool           is_ok           = TRUE;
4086
 
        int             cmp;
4087
 
        ibool           contains_null;
4088
 
        ulint           i;
4089
 
        ulint           cnt;
4090
 
        mem_heap_t*     heap            = NULL;
4091
 
        ulint           n_ext;
4092
 
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
4093
 
        ulint*          offsets;
4094
 
        rec_offs_init(offsets_);
4095
 
 
4096
 
        *n_rows = 0;
4097
 
 
4098
 
        buf = static_cast<byte *>(mem_alloc(UNIV_PAGE_SIZE));
4099
 
        heap = mem_heap_create(100);
4100
 
 
4101
 
        cnt = 1000;
4102
 
 
4103
 
        ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4104
 
loop:
4105
 
        /* Check thd->killed every 1,000 scanned rows */
4106
 
        if (--cnt == 0) {
4107
 
                if (trx_is_interrupted(prebuilt->trx)) {
4108
 
                        goto func_exit;
4109
 
                }
4110
 
                cnt = 1000;
4111
 
        }
4112
 
 
4113
 
        switch (ret) {
4114
 
        case DB_SUCCESS:
4115
 
                break;
4116
 
        default:
4117
 
                ut_print_timestamp(stderr);
4118
 
                fputs("  InnoDB: Warning: CHECK TABLE on ", stderr);
4119
 
                dict_index_name_print(stderr, prebuilt->trx, index);
4120
 
                fprintf(stderr, " returned %lu\n", ret);
4121
 
                /* fall through (this error is ignored by CHECK TABLE) */
4122
 
        case DB_END_OF_INDEX:
4123
 
func_exit:
4124
 
                mem_free(buf);
4125
 
                mem_heap_free(heap);
4126
 
 
4127
 
                return(is_ok);
4128
 
        }
4129
 
 
4130
 
        *n_rows = *n_rows + 1;
4131
 
 
4132
 
        /* row_search... returns the index record in buf, record origin offset
4133
 
        within buf stored in the first 4 bytes, because we have built a dummy
4134
 
        template */
4135
 
 
4136
 
        rec = buf + mach_read_from_4(buf);
4137
 
 
4138
 
        offsets = rec_get_offsets(rec, index, offsets_,
4139
 
                                  ULINT_UNDEFINED, &heap);
4140
 
 
4141
 
        if (prev_entry != NULL) {
4142
 
                matched_fields = 0;
4143
 
                matched_bytes = 0;
4144
 
 
4145
 
                cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4146
 
                                                &matched_fields,
4147
 
                                                &matched_bytes);
4148
 
                contains_null = FALSE;
4149
 
 
4150
 
                /* In a unique secondary index we allow equal key values if
4151
 
                they contain SQL NULLs */
4152
 
 
4153
 
                for (i = 0;
4154
 
                     i < dict_index_get_n_ordering_defined_by_user(index);
4155
 
                     i++) {
4156
 
                        if (UNIV_SQL_NULL == dfield_get_len(
4157
 
                                    dtuple_get_nth_field(prev_entry, i))) {
4158
 
 
4159
 
                                contains_null = TRUE;
4160
 
                        }
4161
 
                }
4162
 
 
4163
 
                if (cmp > 0) {
4164
 
                        fputs("InnoDB: index records in a wrong order in ",
4165
 
                              stderr);
4166
 
not_ok:
4167
 
                        dict_index_name_print(stderr,
4168
 
                                              prebuilt->trx, index);
4169
 
                        fputs("\n"
4170
 
                              "InnoDB: prev record ", stderr);
4171
 
                        dtuple_print(stderr, prev_entry);
4172
 
                        fputs("\n"
4173
 
                              "InnoDB: record ", stderr);
4174
 
                        rec_print_new(stderr, rec, offsets);
4175
 
                        putc('\n', stderr);
4176
 
                        is_ok = FALSE;
4177
 
                } else if (dict_index_is_unique(index)
4178
 
                           && !contains_null
4179
 
                           && matched_fields
4180
 
                           >= dict_index_get_n_ordering_defined_by_user(
4181
 
                                   index)) {
4182
 
 
4183
 
                        fputs("InnoDB: duplicate key in ", stderr);
4184
 
                        goto not_ok;
4185
 
                }
4186
 
        }
4187
 
 
4188
 
        {
4189
 
                mem_heap_t*     tmp_heap = NULL;
4190
 
 
4191
 
                /* Empty the heap on each round.  But preserve offsets[]
4192
 
                for the row_rec_to_index_entry() call, by copying them
4193
 
                into a separate memory heap when needed. */
4194
 
                if (UNIV_UNLIKELY(offsets != offsets_)) {
4195
 
                        ulint   size = rec_offs_get_n_alloc(offsets)
4196
 
                                * sizeof *offsets;
4197
 
 
4198
 
                        tmp_heap = mem_heap_create(size);
4199
 
                        offsets = static_cast<ulint *>(mem_heap_dup(tmp_heap, offsets, size));
4200
 
                }
4201
 
 
4202
 
                mem_heap_empty(heap);
4203
 
 
4204
 
                prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4205
 
                                                    index, offsets,
4206
 
                                                    &n_ext, heap);
4207
 
 
4208
 
                if (UNIV_LIKELY_NULL(tmp_heap)) {
4209
 
                        mem_heap_free(tmp_heap);
4210
 
                }
4211
 
        }
4212
 
 
4213
 
        ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4214
 
 
4215
 
        goto loop;
4216
 
}
4217
 
 
4218
 
/*********************************************************************//**
4219
 
Determines if a table is a magic monitor table.
4220
 
@return TRUE if monitor table */
4221
 
UNIV_INTERN
4222
 
ibool
4223
 
row_is_magic_monitor_table(
4224
 
/*=======================*/
4225
 
        const char*     table_name)     /*!< in: name of the table, in the
4226
 
                                        form database/table_name */
4227
 
{
4228
 
        const char*     name; /* table_name without database/ */
4229
 
        ulint           len;
4230
 
 
4231
 
        name = strchr(table_name, '/');
4232
 
        ut_a(name != NULL);
4233
 
        name++;
4234
 
        len = strlen(name) + 1;
4235
 
 
4236
 
        if (STR_EQ(name, len, S_innodb_monitor)
4237
 
            || STR_EQ(name, len, S_innodb_lock_monitor)
4238
 
            || STR_EQ(name, len, S_innodb_tablespace_monitor)
4239
 
            || STR_EQ(name, len, S_innodb_table_monitor)
4240
 
            || STR_EQ(name, len, S_innodb_mem_validate)) {
4241
 
 
4242
 
                return(TRUE);
4243
 
        }
4244
 
 
4245
 
        return(FALSE);
4246
 
}