~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-12-08 22:35:56 UTC
  • mfrom: (1819.9.158 update-innobase)
  • Revision ID: brian@tangent.org-20101208223556-37mi4omqg7lkjzf3
Merge in Stewart's changes, 1.3 changes.

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
        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 = 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 = 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 = 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);
 
918
        }
 
919
}
 
920
 
 
921
/*********************************************************************//**
 
922
Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
 
923
function should be called at the the end of an SQL statement, by the
 
924
connection thread that owns the transaction (trx->mysql_thd). */
 
925
UNIV_INTERN
 
926
void
 
927
row_unlock_table_autoinc_for_mysql(
 
928
/*===============================*/
 
929
        trx_t*  trx)    /*!< in/out: transaction */
 
930
{
 
931
        if (lock_trx_holds_autoinc_locks(trx)) {
 
932
                mutex_enter(&kernel_mutex);
 
933
 
 
934
                lock_release_autoinc_locks(trx);
 
935
 
 
936
                mutex_exit(&kernel_mutex);
 
937
        }
 
938
}
 
939
 
 
940
/*********************************************************************//**
 
941
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
 
942
AUTO_INC lock gives exclusive access to the auto-inc counter of the
 
943
table. The lock is reserved only for the duration of an SQL statement.
 
944
It is not compatible with another AUTO_INC or exclusive lock on the
 
945
table.
 
946
@return error code or DB_SUCCESS */
 
947
UNIV_INTERN
 
948
int
 
949
row_lock_table_autoinc_for_mysql(
 
950
/*=============================*/
 
951
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in the MySQL
 
952
                                        table handle */
 
953
{
 
954
        trx_t*                  trx     = prebuilt->trx;
 
955
        ins_node_t*             node    = prebuilt->ins_node;
 
956
        const dict_table_t*     table   = prebuilt->table;
 
957
        que_thr_t*              thr;
 
958
        ulint                   err;
 
959
        ibool                   was_lock_wait;
 
960
 
 
961
        ut_ad(trx);
 
962
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
963
 
 
964
        /* If we already hold an AUTOINC lock on the table then do nothing.
 
965
        Note: We peek at the value of the current owner without acquiring
 
966
        the kernel mutex. **/
 
967
        if (trx == table->autoinc_trx) {
 
968
 
 
969
                return(DB_SUCCESS);
 
970
        }
 
971
 
 
972
        trx->op_info = "setting auto-inc lock";
 
973
 
 
974
        if (node == NULL) {
 
975
                row_get_prebuilt_insert_row(prebuilt);
 
976
                node = prebuilt->ins_node;
 
977
        }
 
978
 
 
979
        /* We use the insert query graph as the dummy graph needed
 
980
        in the lock module call */
 
981
 
 
982
        thr = que_fork_get_first_thr(prebuilt->ins_graph);
 
983
 
 
984
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
985
 
 
986
run_again:
 
987
        thr->run_node = node;
 
988
        thr->prev_node = node;
 
989
 
 
990
        /* It may be that the current session has not yet started
 
991
        its transaction, or it has been committed: */
 
992
 
 
993
        trx_start_if_not_started(trx);
 
994
 
 
995
        err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
 
996
 
 
997
        trx->error_state = err;
 
998
 
 
999
        if (err != DB_SUCCESS) {
 
1000
                que_thr_stop_for_mysql(thr);
 
1001
 
 
1002
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
 
1003
 
 
1004
                if (was_lock_wait) {
 
1005
                        goto run_again;
 
1006
                }
 
1007
 
 
1008
                trx->op_info = "";
 
1009
 
 
1010
                return((int) err);
 
1011
        }
 
1012
 
 
1013
        que_thr_stop_for_mysql_no_error(thr, trx);
 
1014
 
 
1015
        trx->op_info = "";
 
1016
 
 
1017
        return((int) err);
 
1018
}
 
1019
 
 
1020
/*********************************************************************//**
 
1021
Sets a table lock on the table mentioned in prebuilt.
 
1022
@return error code or DB_SUCCESS */
 
1023
UNIV_INTERN
 
1024
int
 
1025
row_lock_table_for_mysql(
 
1026
/*=====================*/
 
1027
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct in the MySQL
 
1028
                                        table handle */
 
1029
        dict_table_t*   table,          /*!< in: table to lock, or NULL
 
1030
                                        if prebuilt->table should be
 
1031
                                        locked as
 
1032
                                        prebuilt->select_lock_type */
 
1033
        ulint           mode)           /*!< in: lock mode of table
 
1034
                                        (ignored if table==NULL) */
 
1035
{
 
1036
        trx_t*          trx             = prebuilt->trx;
 
1037
        que_thr_t*      thr;
 
1038
        ulint           err;
 
1039
        ibool           was_lock_wait;
 
1040
 
 
1041
        ut_ad(trx);
 
1042
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1043
 
 
1044
        trx->op_info = "setting table lock";
 
1045
 
 
1046
        if (prebuilt->sel_graph == NULL) {
 
1047
                /* Build a dummy select query graph */
 
1048
                row_prebuild_sel_graph(prebuilt);
 
1049
        }
 
1050
 
 
1051
        /* We use the select query graph as the dummy graph needed
 
1052
        in the lock module call */
 
1053
 
 
1054
        thr = que_fork_get_first_thr(prebuilt->sel_graph);
 
1055
 
 
1056
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
1057
 
 
1058
run_again:
 
1059
        thr->run_node = thr;
 
1060
        thr->prev_node = thr->common.parent;
 
1061
 
 
1062
        /* It may be that the current session has not yet started
 
1063
        its transaction, or it has been committed: */
 
1064
 
 
1065
        trx_start_if_not_started(trx);
 
1066
 
 
1067
        if (table) {
 
1068
                err = lock_table(0, table, mode, thr);
 
1069
        } else {
 
1070
                err = lock_table(0, prebuilt->table,
 
1071
                                 prebuilt->select_lock_type, thr);
 
1072
        }
 
1073
 
 
1074
        trx->error_state = err;
 
1075
 
 
1076
        if (err != DB_SUCCESS) {
 
1077
                que_thr_stop_for_mysql(thr);
 
1078
 
 
1079
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
 
1080
 
 
1081
                if (was_lock_wait) {
 
1082
                        goto run_again;
 
1083
                }
 
1084
 
 
1085
                trx->op_info = "";
 
1086
 
 
1087
                return((int) err);
 
1088
        }
 
1089
 
 
1090
        que_thr_stop_for_mysql_no_error(thr, trx);
 
1091
 
 
1092
        trx->op_info = "";
 
1093
 
 
1094
        return((int) err);
 
1095
}
 
1096
 
 
1097
/*********************************************************************//**
 
1098
Does an insert for MySQL.
 
1099
@return error code or DB_SUCCESS */
 
1100
UNIV_INTERN
 
1101
int
 
1102
row_insert_for_mysql(
 
1103
/*=================*/
 
1104
        byte*           mysql_rec,      /*!< in: row in the MySQL format */
 
1105
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
 
1106
                                        handle */
 
1107
{
 
1108
        trx_savept_t    savept;
 
1109
        que_thr_t*      thr;
 
1110
        ulint           err;
 
1111
        ibool           was_lock_wait;
 
1112
        trx_t*          trx             = prebuilt->trx;
 
1113
        ins_node_t*     node            = prebuilt->ins_node;
 
1114
 
 
1115
        ut_ad(trx);
 
1116
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1117
 
 
1118
        if (prebuilt->table->ibd_file_missing) {
 
1119
                ut_print_timestamp(stderr);
 
1120
                fprintf(stderr, "  InnoDB: Error:\n"
 
1121
                        "InnoDB: MySQL is trying to use a table handle"
 
1122
                        " but the .ibd file for\n"
 
1123
                        "InnoDB: table %s does not exist.\n"
 
1124
                        "InnoDB: Have you deleted the .ibd file"
 
1125
                        " from the database directory under\n"
 
1126
                        "InnoDB: the MySQL datadir, or have you"
 
1127
                        " used DISCARD TABLESPACE?\n"
 
1128
                        "InnoDB: Look from\n"
 
1129
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
 
1130
                        "InnoDB: how you can resolve the problem.\n",
 
1131
                        prebuilt->table->name);
 
1132
                return(DB_ERROR);
 
1133
        }
 
1134
 
 
1135
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
 
1136
                fprintf(stderr,
 
1137
                        "InnoDB: Error: trying to free a corrupt\n"
 
1138
                        "InnoDB: table handle. Magic n %lu, table name ",
 
1139
                        (ulong) prebuilt->magic_n);
 
1140
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
 
1141
                putc('\n', stderr);
 
1142
 
 
1143
                mem_analyze_corruption(prebuilt);
 
1144
 
 
1145
                ut_error;
 
1146
        }
 
1147
 
 
1148
        if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
 
1149
                fputs("InnoDB: A new raw disk partition was initialized or\n"
 
1150
                      "InnoDB: innodb_force_recovery is on: we do not allow\n"
 
1151
                      "InnoDB: database modifications by the user. Shut down\n"
 
1152
                      "InnoDB: mysqld and edit my.cnf so that"
 
1153
                      " newraw is replaced\n"
 
1154
                      "InnoDB: with raw, and innodb_force_... is removed.\n",
 
1155
                      stderr);
 
1156
 
 
1157
                return(DB_ERROR);
 
1158
        }
 
1159
 
 
1160
        trx->op_info = "inserting";
 
1161
 
 
1162
        row_mysql_delay_if_needed();
 
1163
 
 
1164
        trx_start_if_not_started(trx);
 
1165
 
 
1166
        if (node == NULL) {
 
1167
                row_get_prebuilt_insert_row(prebuilt);
 
1168
                node = prebuilt->ins_node;
 
1169
        }
 
1170
 
 
1171
        row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
 
1172
 
 
1173
        savept = trx_savept_take(trx);
 
1174
 
 
1175
        thr = que_fork_get_first_thr(prebuilt->ins_graph);
 
1176
 
 
1177
        if (prebuilt->sql_stat_start) {
 
1178
                node->state = INS_NODE_SET_IX_LOCK;
 
1179
                prebuilt->sql_stat_start = FALSE;
 
1180
        } else {
 
1181
                node->state = INS_NODE_ALLOC_ROW_ID;
 
1182
        }
 
1183
 
 
1184
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
1185
 
 
1186
run_again:
 
1187
        thr->run_node = node;
 
1188
        thr->prev_node = node;
 
1189
 
 
1190
        row_ins_step(thr);
 
1191
 
 
1192
        err = trx->error_state;
 
1193
 
 
1194
        if (err != DB_SUCCESS) {
 
1195
                que_thr_stop_for_mysql(thr);
 
1196
 
 
1197
                /* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
 
1198
 
 
1199
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
 
1200
                                                        &savept);
 
1201
                thr->lock_state= QUE_THR_LOCK_NOLOCK;
 
1202
 
 
1203
                if (was_lock_wait) {
 
1204
                        goto run_again;
 
1205
                }
 
1206
 
 
1207
                trx->op_info = "";
 
1208
 
 
1209
                return((int) err);
 
1210
        }
 
1211
 
 
1212
        que_thr_stop_for_mysql_no_error(thr, trx);
 
1213
 
 
1214
        prebuilt->table->stat_n_rows++;
 
1215
 
 
1216
        srv_n_rows_inserted++;
 
1217
 
 
1218
        if (prebuilt->table->stat_n_rows == 0) {
 
1219
                /* Avoid wrap-over */
 
1220
                prebuilt->table->stat_n_rows--;
 
1221
        }
 
1222
 
 
1223
        row_update_statistics_if_needed(prebuilt->table);
 
1224
        trx->op_info = "";
 
1225
 
 
1226
        return((int) err);
 
1227
}
 
1228
 
 
1229
/*********************************************************************//**
 
1230
Builds a dummy query graph used in selects. */
 
1231
UNIV_INTERN
 
1232
void
 
1233
row_prebuild_sel_graph(
 
1234
/*===================*/
 
1235
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
 
1236
                                        handle */
 
1237
{
 
1238
        sel_node_t*     node;
 
1239
 
 
1240
        ut_ad(prebuilt && prebuilt->trx);
 
1241
 
 
1242
        if (prebuilt->sel_graph == NULL) {
 
1243
 
 
1244
                node = sel_node_create(prebuilt->heap);
 
1245
 
 
1246
                prebuilt->sel_graph = que_node_get_parent(
 
1247
                        pars_complete_graph_for_exec(node,
 
1248
                                                     prebuilt->trx,
 
1249
                                                     prebuilt->heap));
 
1250
 
 
1251
                prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
 
1252
        }
 
1253
}
 
1254
 
 
1255
/*********************************************************************//**
 
1256
Creates an query graph node of 'update' type to be used in the MySQL
 
1257
interface.
 
1258
@return own: update node */
 
1259
UNIV_INTERN
 
1260
upd_node_t*
 
1261
row_create_update_node_for_mysql(
 
1262
/*=============================*/
 
1263
        dict_table_t*   table,  /*!< in: table to update */
 
1264
        mem_heap_t*     heap)   /*!< in: mem heap from which allocated */
 
1265
{
 
1266
        upd_node_t*     node;
 
1267
 
 
1268
        node = upd_node_create(heap);
 
1269
 
 
1270
        node->in_mysql_interface = TRUE;
 
1271
        node->is_delete = FALSE;
 
1272
        node->searched_update = FALSE;
 
1273
        node->select = NULL;
 
1274
        node->pcur = btr_pcur_create_for_mysql();
 
1275
        node->table = table;
 
1276
 
 
1277
        node->update = upd_create(dict_table_get_n_cols(table), heap);
 
1278
 
 
1279
        node->update_n_fields = dict_table_get_n_cols(table);
 
1280
 
 
1281
        UT_LIST_INIT(node->columns);
 
1282
        node->has_clust_rec_x_lock = TRUE;
 
1283
        node->cmpl_info = 0;
 
1284
 
 
1285
        node->table_sym = NULL;
 
1286
        node->col_assign_list = NULL;
 
1287
 
 
1288
        return(node);
 
1289
}
 
1290
 
 
1291
/*********************************************************************//**
 
1292
Gets pointer to a prebuilt update vector used in updates. If the update
 
1293
graph has not yet been built in the prebuilt struct, then this function
 
1294
first builds it.
 
1295
@return prebuilt update vector */
 
1296
UNIV_INTERN
 
1297
upd_t*
 
1298
row_get_prebuilt_update_vector(
 
1299
/*===========================*/
 
1300
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
 
1301
                                        handle */
 
1302
{
 
1303
        dict_table_t*   table   = prebuilt->table;
 
1304
        upd_node_t*     node;
 
1305
 
 
1306
        ut_ad(prebuilt && table && prebuilt->trx);
 
1307
 
 
1308
        if (prebuilt->upd_node == NULL) {
 
1309
 
 
1310
                /* Not called before for this handle: create an update node
 
1311
                and query graph to the prebuilt struct */
 
1312
 
 
1313
                node = row_create_update_node_for_mysql(table, prebuilt->heap);
 
1314
 
 
1315
                prebuilt->upd_node = node;
 
1316
 
 
1317
                prebuilt->upd_graph = que_node_get_parent(
 
1318
                        pars_complete_graph_for_exec(node,
 
1319
                                                     prebuilt->trx,
 
1320
                                                     prebuilt->heap));
 
1321
                prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
 
1322
        }
 
1323
 
 
1324
        return(prebuilt->upd_node->update);
 
1325
}
 
1326
 
 
1327
/*********************************************************************//**
 
1328
Does an update or delete of a row for MySQL.
 
1329
@return error code or DB_SUCCESS */
 
1330
UNIV_INTERN
 
1331
int
 
1332
row_update_for_mysql(
 
1333
/*=================*/
 
1334
        byte*           mysql_rec,      /*!< in: the row to be updated, in
 
1335
                                        the MySQL format */
 
1336
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
 
1337
                                        handle */
 
1338
{
 
1339
        trx_savept_t    savept;
 
1340
        ulint           err;
 
1341
        que_thr_t*      thr;
 
1342
        ibool           was_lock_wait;
 
1343
        dict_index_t*   clust_index;
 
1344
        /*      ulint           ref_len; */
 
1345
        upd_node_t*     node;
 
1346
        dict_table_t*   table           = prebuilt->table;
 
1347
        trx_t*          trx             = prebuilt->trx;
 
1348
 
 
1349
        ut_ad(prebuilt && trx);
 
1350
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1351
        UT_NOT_USED(mysql_rec);
 
1352
 
 
1353
        if (prebuilt->table->ibd_file_missing) {
 
1354
                ut_print_timestamp(stderr);
 
1355
                fprintf(stderr, "  InnoDB: Error:\n"
 
1356
                        "InnoDB: MySQL is trying to use a table handle"
 
1357
                        " but the .ibd file for\n"
 
1358
                        "InnoDB: table %s does not exist.\n"
 
1359
                        "InnoDB: Have you deleted the .ibd file"
 
1360
                        " from the database directory under\n"
 
1361
                        "InnoDB: the MySQL datadir, or have you"
 
1362
                        " used DISCARD TABLESPACE?\n"
 
1363
                        "InnoDB: Look from\n"
 
1364
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
 
1365
                        "InnoDB: how you can resolve the problem.\n",
 
1366
                        prebuilt->table->name);
 
1367
                return(DB_ERROR);
 
1368
        }
 
1369
 
 
1370
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
 
1371
                fprintf(stderr,
 
1372
                        "InnoDB: Error: trying to free a corrupt\n"
 
1373
                        "InnoDB: table handle. Magic n %lu, table name ",
 
1374
                        (ulong) prebuilt->magic_n);
 
1375
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
 
1376
                putc('\n', stderr);
 
1377
 
 
1378
                mem_analyze_corruption(prebuilt);
 
1379
 
 
1380
                ut_error;
 
1381
        }
 
1382
 
 
1383
        if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
 
1384
                fputs("InnoDB: A new raw disk partition was initialized or\n"
 
1385
                      "InnoDB: innodb_force_recovery is on: we do not allow\n"
 
1386
                      "InnoDB: database modifications by the user. Shut down\n"
 
1387
                      "InnoDB: mysqld and edit my.cnf so that newraw"
 
1388
                      " is replaced\n"
 
1389
                      "InnoDB: with raw, and innodb_force_... is removed.\n",
 
1390
                      stderr);
 
1391
 
 
1392
                return(DB_ERROR);
 
1393
        }
 
1394
 
 
1395
        trx->op_info = "updating or deleting";
 
1396
 
 
1397
        row_mysql_delay_if_needed();
 
1398
 
 
1399
        trx_start_if_not_started(trx);
 
1400
 
 
1401
        node = prebuilt->upd_node;
 
1402
 
 
1403
        clust_index = dict_table_get_first_index(table);
 
1404
 
 
1405
        if (prebuilt->pcur->btr_cur.index == clust_index) {
 
1406
                btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
 
1407
        } else {
 
1408
                btr_pcur_copy_stored_position(node->pcur,
 
1409
                                              prebuilt->clust_pcur);
 
1410
        }
 
1411
 
 
1412
        ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
 
1413
 
 
1414
        /* MySQL seems to call rnd_pos before updating each row it
 
1415
        has cached: we can get the correct cursor position from
 
1416
        prebuilt->pcur; NOTE that we cannot build the row reference
 
1417
        from mysql_rec if the clustered index was automatically
 
1418
        generated for the table: MySQL does not know anything about
 
1419
        the row id used as the clustered index key */
 
1420
 
 
1421
        savept = trx_savept_take(trx);
 
1422
 
 
1423
        thr = que_fork_get_first_thr(prebuilt->upd_graph);
 
1424
 
 
1425
        node->state = UPD_NODE_UPDATE_CLUSTERED;
 
1426
 
 
1427
        ut_ad(!prebuilt->sql_stat_start);
 
1428
 
 
1429
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
1430
 
 
1431
run_again:
 
1432
        thr->run_node = node;
 
1433
        thr->prev_node = node;
 
1434
        thr->fk_cascade_depth = 0;
 
1435
 
 
1436
        row_upd_step(thr);
 
1437
 
 
1438
        /* The recursive call for cascading update/delete happens
 
1439
        in above row_upd_step(), reset the counter once we come
 
1440
        out of the recursive call, so it does not accumulate for
 
1441
        different row deletes */
 
1442
        thr->fk_cascade_depth = 0;
 
1443
 
 
1444
        err = trx->error_state;
 
1445
 
 
1446
        /* Reset fk_cascade_depth back to 0 */
 
1447
        thr->fk_cascade_depth = 0;
 
1448
 
 
1449
        if (err != DB_SUCCESS) {
 
1450
                que_thr_stop_for_mysql(thr);
 
1451
 
 
1452
                if (err == DB_RECORD_NOT_FOUND) {
 
1453
                        trx->error_state = DB_SUCCESS;
 
1454
                        trx->op_info = "";
 
1455
 
 
1456
                        return((int) err);
 
1457
                }
 
1458
 
 
1459
                thr->lock_state= QUE_THR_LOCK_ROW;
 
1460
                was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
 
1461
                                                        &savept);
 
1462
                thr->lock_state= QUE_THR_LOCK_NOLOCK;
 
1463
 
 
1464
                if (was_lock_wait) {
 
1465
                        goto run_again;
 
1466
                }
 
1467
 
 
1468
                trx->op_info = "";
 
1469
 
 
1470
                return((int) err);
 
1471
        }
 
1472
 
 
1473
        que_thr_stop_for_mysql_no_error(thr, trx);
 
1474
 
 
1475
        if (node->is_delete) {
 
1476
                if (prebuilt->table->stat_n_rows > 0) {
 
1477
                        prebuilt->table->stat_n_rows--;
 
1478
                }
 
1479
 
 
1480
                srv_n_rows_deleted++;
 
1481
        } else {
 
1482
                srv_n_rows_updated++;
 
1483
        }
 
1484
 
 
1485
        /* We update table statistics only if it is a DELETE or UPDATE
 
1486
        that changes indexed columns, UPDATEs that change only non-indexed
 
1487
        columns would not affect statistics. */
 
1488
        if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
 
1489
                row_update_statistics_if_needed(prebuilt->table);
 
1490
        }
 
1491
 
 
1492
        trx->op_info = "";
 
1493
 
 
1494
        return((int) err);
 
1495
}
 
1496
 
 
1497
/*********************************************************************//**
 
1498
This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
 
1499
session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
 
1500
Before calling this function row_search_for_mysql() must have
 
1501
initialized prebuilt->new_rec_locks to store the information which new
 
1502
record locks really were set. This function removes a newly set
 
1503
clustered index record lock under prebuilt->pcur or
 
1504
prebuilt->clust_pcur.  Thus, this implements a 'mini-rollback' that
 
1505
releases the latest clustered index record lock we set.
 
1506
@return error code or DB_SUCCESS */
 
1507
UNIV_INTERN
 
1508
int
 
1509
row_unlock_for_mysql(
 
1510
/*=================*/
 
1511
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct in MySQL
 
1512
                                        handle */
 
1513
        ibool           has_latches_on_recs)/*!< in: TRUE if called so
 
1514
                                        that we have the latches on
 
1515
                                        the records under pcur and
 
1516
                                        clust_pcur, and we do not need
 
1517
                                        to reposition the cursors. */
 
1518
{
 
1519
        btr_pcur_t*     pcur            = prebuilt->pcur;
 
1520
        btr_pcur_t*     clust_pcur      = prebuilt->clust_pcur;
 
1521
        trx_t*          trx             = prebuilt->trx;
 
1522
 
 
1523
        ut_ad(prebuilt && trx);
 
1524
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1525
 
 
1526
        if (UNIV_UNLIKELY
 
1527
            (!srv_locks_unsafe_for_binlog
 
1528
             && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
 
1529
 
 
1530
                fprintf(stderr,
 
1531
                        "InnoDB: Error: calling row_unlock_for_mysql though\n"
 
1532
                        "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
 
1533
                        "InnoDB: this session is not using"
 
1534
                        " READ COMMITTED isolation level.\n");
 
1535
 
 
1536
                return(DB_SUCCESS);
 
1537
        }
 
1538
 
 
1539
        trx->op_info = "unlock_row";
 
1540
 
 
1541
        if (prebuilt->new_rec_locks >= 1) {
 
1542
 
 
1543
                const rec_t*    rec;
 
1544
                dict_index_t*   index;
 
1545
                trx_id_t        rec_trx_id;
 
1546
                mtr_t           mtr;
 
1547
 
 
1548
                mtr_start(&mtr);
 
1549
 
 
1550
                /* Restore the cursor position and find the record */
 
1551
 
 
1552
                if (!has_latches_on_recs) {
 
1553
                        btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
 
1554
                }
 
1555
 
 
1556
                rec = btr_pcur_get_rec(pcur);
 
1557
                index = btr_pcur_get_btr_cur(pcur)->index;
 
1558
 
 
1559
                if (prebuilt->new_rec_locks >= 2) {
 
1560
                        /* Restore the cursor position and find the record
 
1561
                        in the clustered index. */
 
1562
 
 
1563
                        if (!has_latches_on_recs) {
 
1564
                                btr_pcur_restore_position(BTR_SEARCH_LEAF,
 
1565
                                                          clust_pcur, &mtr);
 
1566
                        }
 
1567
 
 
1568
                        rec = btr_pcur_get_rec(clust_pcur);
 
1569
                        index = btr_pcur_get_btr_cur(clust_pcur)->index;
 
1570
                }
 
1571
 
 
1572
                if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
 
1573
                        /* This is not a clustered index record.  We
 
1574
                        do not know how to unlock the record. */
 
1575
                        goto no_unlock;
 
1576
                }
 
1577
 
 
1578
                /* If the record has been modified by this
 
1579
                transaction, do not unlock it. */
 
1580
 
 
1581
                if (index->trx_id_offset) {
 
1582
                        rec_trx_id = trx_read_trx_id(rec
 
1583
                                                     + index->trx_id_offset);
 
1584
                } else {
 
1585
                        mem_heap_t*     heap                    = NULL;
 
1586
                        ulint   offsets_[REC_OFFS_NORMAL_SIZE];
 
1587
                        ulint*  offsets                         = offsets_;
 
1588
 
 
1589
                        rec_offs_init(offsets_);
 
1590
                        offsets = rec_get_offsets(rec, index, offsets,
 
1591
                                                  ULINT_UNDEFINED, &heap);
 
1592
 
 
1593
                        rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
 
1594
 
 
1595
                        if (UNIV_LIKELY_NULL(heap)) {
 
1596
                                mem_heap_free(heap);
 
1597
                        }
 
1598
                }
 
1599
 
 
1600
                if (rec_trx_id != trx->id) {
 
1601
                        /* We did not update the record: unlock it */
 
1602
 
 
1603
                        rec = btr_pcur_get_rec(pcur);
 
1604
                        index = btr_pcur_get_btr_cur(pcur)->index;
 
1605
 
 
1606
                        lock_rec_unlock(trx, btr_pcur_get_block(pcur),
 
1607
                                        rec, prebuilt->select_lock_type);
 
1608
 
 
1609
                        if (prebuilt->new_rec_locks >= 2) {
 
1610
                                rec = btr_pcur_get_rec(clust_pcur);
 
1611
                                index = btr_pcur_get_btr_cur(clust_pcur)->index;
 
1612
 
 
1613
                                lock_rec_unlock(trx,
 
1614
                                                btr_pcur_get_block(clust_pcur),
 
1615
                                                rec,
 
1616
                                                prebuilt->select_lock_type);
 
1617
                        }
 
1618
                }
 
1619
no_unlock:
 
1620
                mtr_commit(&mtr);
 
1621
        }
 
1622
 
 
1623
        trx->op_info = "";
 
1624
 
 
1625
        return(DB_SUCCESS);
 
1626
}
 
1627
 
 
1628
/**********************************************************************//**
 
1629
Does a cascaded delete or set null in a foreign key operation.
 
1630
@return error code or DB_SUCCESS */
 
1631
UNIV_INTERN
 
1632
ulint
 
1633
row_update_cascade_for_mysql(
 
1634
/*=========================*/
 
1635
        que_thr_t*      thr,    /*!< in: query thread */
 
1636
        upd_node_t*     node,   /*!< in: update node used in the cascade
 
1637
                                or set null operation */
 
1638
        dict_table_t*   table)  /*!< in: table where we do the operation */
 
1639
{
 
1640
        ulint   err;
 
1641
        trx_t*  trx;
 
1642
 
 
1643
        trx = thr_get_trx(thr);
 
1644
 
 
1645
        /* Increment fk_cascade_depth to record the recursive call depth on
 
1646
        a single update/delete that affects multiple tables chained
 
1647
        together with foreign key relations. */
 
1648
        thr->fk_cascade_depth++;
 
1649
 
 
1650
        if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
 
1651
                return (DB_FOREIGN_EXCEED_MAX_CASCADE);
 
1652
        }
 
1653
run_again:
 
1654
        thr->run_node = node;
 
1655
        thr->prev_node = node;
 
1656
 
 
1657
        row_upd_step(thr);
 
1658
 
 
1659
        /* The recursive call for cascading update/delete happens
 
1660
        in above row_upd_step(), reset the counter once we come
 
1661
        out of the recursive call, so it does not accumulate for
 
1662
        different row deletes */
 
1663
        thr->fk_cascade_depth = 0;
 
1664
 
 
1665
        err = trx->error_state;
 
1666
 
 
1667
        /* Note that the cascade node is a subnode of another InnoDB
 
1668
        query graph node. We do a normal lock wait in this node, but
 
1669
        all errors are handled by the parent node. */
 
1670
 
 
1671
        if (err == DB_LOCK_WAIT) {
 
1672
                /* Handle lock wait here */
 
1673
 
 
1674
                que_thr_stop_for_mysql(thr);
 
1675
 
 
1676
                srv_suspend_mysql_thread(thr);
 
1677
 
 
1678
                /* Note that a lock wait may also end in a lock wait timeout,
 
1679
                or this transaction is picked as a victim in selective
 
1680
                deadlock resolution */
 
1681
 
 
1682
                if (trx->error_state != DB_SUCCESS) {
 
1683
 
 
1684
                        return(trx->error_state);
 
1685
                }
 
1686
 
 
1687
                /* Retry operation after a normal lock wait */
 
1688
 
 
1689
                goto run_again;
 
1690
        }
 
1691
 
 
1692
        if (err != DB_SUCCESS) {
 
1693
 
 
1694
                return(err);
 
1695
        }
 
1696
 
 
1697
        if (node->is_delete) {
 
1698
                if (table->stat_n_rows > 0) {
 
1699
                        table->stat_n_rows--;
 
1700
                }
 
1701
 
 
1702
                srv_n_rows_deleted++;
 
1703
        } else {
 
1704
                srv_n_rows_updated++;
 
1705
        }
 
1706
 
 
1707
        row_update_statistics_if_needed(table);
 
1708
 
 
1709
        return(err);
 
1710
}
 
1711
 
 
1712
/*********************************************************************//**
 
1713
Checks if a table is such that we automatically created a clustered
 
1714
index on it (on row id).
 
1715
@return TRUE if the clustered index was generated automatically */
 
1716
UNIV_INTERN
 
1717
ibool
 
1718
row_table_got_default_clust_index(
 
1719
/*==============================*/
 
1720
        const dict_table_t*     table)  /*!< in: table */
 
1721
{
 
1722
        const dict_index_t*     clust_index;
 
1723
 
 
1724
        clust_index = dict_table_get_first_index(table);
 
1725
 
 
1726
        return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
 
1727
}
 
1728
 
 
1729
/*********************************************************************//**
 
1730
Locks the data dictionary in shared mode from modifications, for performing
 
1731
foreign key check, rollback, or other operation invisible to MySQL. */
 
1732
UNIV_INTERN
 
1733
void
 
1734
row_mysql_freeze_data_dictionary_func(
 
1735
/*==================================*/
 
1736
        trx_t*          trx,    /*!< in/out: transaction */
 
1737
        const char*     file,   /*!< in: file name */
 
1738
        ulint           line)   /*!< in: line number */
 
1739
{
 
1740
        ut_a(trx->dict_operation_lock_mode == 0);
 
1741
 
 
1742
        rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
 
1743
 
 
1744
        trx->dict_operation_lock_mode = RW_S_LATCH;
 
1745
}
 
1746
 
 
1747
/*********************************************************************//**
 
1748
Unlocks the data dictionary shared lock. */
 
1749
UNIV_INTERN
 
1750
void
 
1751
row_mysql_unfreeze_data_dictionary(
 
1752
/*===============================*/
 
1753
        trx_t*  trx)    /*!< in/out: transaction */
 
1754
{
 
1755
        ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
 
1756
 
 
1757
        rw_lock_s_unlock(&dict_operation_lock);
 
1758
 
 
1759
        trx->dict_operation_lock_mode = 0;
 
1760
}
 
1761
 
 
1762
/*********************************************************************//**
 
1763
Locks the data dictionary exclusively for performing a table create or other
 
1764
data dictionary modification operation. */
 
1765
UNIV_INTERN
 
1766
void
 
1767
row_mysql_lock_data_dictionary_func(
 
1768
/*================================*/
 
1769
        trx_t*          trx,    /*!< in/out: transaction */
 
1770
        const char*     file,   /*!< in: file name */
 
1771
        ulint           line)   /*!< in: line number */
 
1772
{
 
1773
        ut_a(trx->dict_operation_lock_mode == 0
 
1774
             || trx->dict_operation_lock_mode == RW_X_LATCH);
 
1775
 
 
1776
        /* Serialize data dictionary operations with dictionary mutex:
 
1777
        no deadlocks or lock waits can occur then in these operations */
 
1778
 
 
1779
        rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
 
1780
        trx->dict_operation_lock_mode = RW_X_LATCH;
 
1781
 
 
1782
        mutex_enter(&(dict_sys->mutex));
 
1783
}
 
1784
 
 
1785
/*********************************************************************//**
 
1786
Unlocks the data dictionary exclusive lock. */
 
1787
UNIV_INTERN
 
1788
void
 
1789
row_mysql_unlock_data_dictionary(
 
1790
/*=============================*/
 
1791
        trx_t*  trx)    /*!< in/out: transaction */
 
1792
{
 
1793
        ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
 
1794
 
 
1795
        /* Serialize data dictionary operations with dictionary mutex:
 
1796
        no deadlocks can occur then in these operations */
 
1797
 
 
1798
        mutex_exit(&(dict_sys->mutex));
 
1799
        rw_lock_x_unlock(&dict_operation_lock);
 
1800
 
 
1801
        trx->dict_operation_lock_mode = 0;
 
1802
}
 
1803
 
 
1804
/*********************************************************************//**
 
1805
Creates a table for MySQL. If the name of the table ends in
 
1806
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
 
1807
"innodb_table_monitor", then this will also start the printing of monitor
 
1808
output by the master thread. If the table name ends in "innodb_mem_validate",
 
1809
InnoDB will try to invoke mem_validate().
 
1810
@return error code or DB_SUCCESS */
 
1811
UNIV_INTERN
 
1812
int
 
1813
row_create_table_for_mysql(
 
1814
/*=======================*/
 
1815
        dict_table_t*   table,  /*!< in, own: table definition
 
1816
                                (will be freed) */
 
1817
        trx_t*          trx)    /*!< in: transaction handle */
 
1818
{
 
1819
        tab_node_t*     node;
 
1820
        mem_heap_t*     heap;
 
1821
        que_thr_t*      thr;
 
1822
        const char*     table_name;
 
1823
        ulint           table_name_len;
 
1824
        ulint           err;
 
1825
 
 
1826
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1827
#ifdef UNIV_SYNC_DEBUG
 
1828
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 
1829
#endif /* UNIV_SYNC_DEBUG */
 
1830
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1831
        ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
 
1832
 
 
1833
        if (srv_created_new_raw) {
 
1834
                fputs("InnoDB: A new raw disk partition was initialized:\n"
 
1835
                      "InnoDB: we do not allow database modifications"
 
1836
                      " by the user.\n"
 
1837
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
 
1838
                      " is replaced with raw.\n", stderr);
 
1839
                dict_mem_table_free(table);
 
1840
                trx_commit_for_mysql(trx);
 
1841
 
 
1842
                return(DB_ERROR);
 
1843
        }
 
1844
 
 
1845
        trx->op_info = "creating table";
 
1846
 
 
1847
        trx_start_if_not_started(trx);
 
1848
 
 
1849
        /* The table name is prefixed with the database name and a '/'.
 
1850
        Certain table names starting with 'innodb_' have their special
 
1851
        meaning regardless of the database name.  Thus, we need to
 
1852
        ignore the database name prefix in the comparisons. */
 
1853
        table_name = strchr(table->name, '/');
 
1854
        ut_a(table_name);
 
1855
        table_name++;
 
1856
        table_name_len = strlen(table_name) + 1;
 
1857
 
 
1858
        if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
 
1859
 
 
1860
                /* Table equals "innodb_monitor":
 
1861
                start monitor prints */
 
1862
 
 
1863
                srv_print_innodb_monitor = TRUE;
 
1864
 
 
1865
                /* The lock timeout monitor thread also takes care
 
1866
                of InnoDB monitor prints */
 
1867
 
 
1868
                os_event_set(srv_lock_timeout_thread_event);
 
1869
        } else if (STR_EQ(table_name, table_name_len,
 
1870
                          S_innodb_lock_monitor)) {
 
1871
 
 
1872
                srv_print_innodb_monitor = TRUE;
 
1873
                srv_print_innodb_lock_monitor = TRUE;
 
1874
                os_event_set(srv_lock_timeout_thread_event);
 
1875
        } else if (STR_EQ(table_name, table_name_len,
 
1876
                          S_innodb_tablespace_monitor)) {
 
1877
 
 
1878
                srv_print_innodb_tablespace_monitor = TRUE;
 
1879
                os_event_set(srv_lock_timeout_thread_event);
 
1880
        } else if (STR_EQ(table_name, table_name_len,
 
1881
                          S_innodb_table_monitor)) {
 
1882
 
 
1883
                srv_print_innodb_table_monitor = TRUE;
 
1884
                os_event_set(srv_lock_timeout_thread_event);
 
1885
        } else if (STR_EQ(table_name, table_name_len,
 
1886
                          S_innodb_mem_validate)) {
 
1887
                /* We define here a debugging feature intended for
 
1888
                developers */
 
1889
 
 
1890
                fputs("Validating InnoDB memory:\n"
 
1891
                      "to use this feature you must compile InnoDB with\n"
 
1892
                      "UNIV_MEM_DEBUG defined in univ.i and"
 
1893
                      " the server must be\n"
 
1894
                      "quiet because allocation from a mem heap"
 
1895
                      " is not protected\n"
 
1896
                      "by any semaphore.\n", stderr);
 
1897
#ifdef UNIV_MEM_DEBUG
 
1898
                ut_a(mem_validate());
 
1899
                fputs("Memory validated\n", stderr);
 
1900
#else /* UNIV_MEM_DEBUG */
 
1901
                fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
 
1902
                      stderr);
 
1903
#endif /* UNIV_MEM_DEBUG */
 
1904
        }
 
1905
 
 
1906
        heap = mem_heap_create(512);
 
1907
 
 
1908
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
 
1909
 
 
1910
        node = tab_create_graph_create(table, heap);
 
1911
 
 
1912
        thr = pars_complete_graph_for_exec(node, trx, heap);
 
1913
 
 
1914
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
 
1915
        que_run_threads(thr);
 
1916
 
 
1917
        err = trx->error_state;
 
1918
 
 
1919
        if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
 
1920
                trx->error_state = DB_SUCCESS;
 
1921
                trx_general_rollback_for_mysql(trx, NULL);
 
1922
                /* TO DO: free table?  The code below will dereference
 
1923
                table->name, though. */
 
1924
        }
 
1925
 
 
1926
        switch (err) {
 
1927
        case DB_OUT_OF_FILE_SPACE:
 
1928
                ut_print_timestamp(stderr);
 
1929
                fputs("  InnoDB: Warning: cannot create table ",
 
1930
                      stderr);
 
1931
                ut_print_name(stderr, trx, TRUE, table->name);
 
1932
                fputs(" because tablespace full\n", stderr);
 
1933
 
 
1934
                if (dict_table_get_low(table->name)) {
 
1935
 
 
1936
                        row_drop_table_for_mysql(table->name, trx, FALSE);
 
1937
                        trx_commit_for_mysql(trx);
 
1938
                }
 
1939
                break;
 
1940
 
 
1941
        case DB_DUPLICATE_KEY:
 
1942
                /* We may also get err == DB_ERROR if the .ibd file for the
 
1943
                table already exists */
 
1944
 
 
1945
                break;
 
1946
        }
 
1947
 
 
1948
        que_graph_free((que_t*) que_node_get_parent(thr));
 
1949
 
 
1950
        trx->op_info = "";
 
1951
 
 
1952
        return((int) err);
 
1953
}
 
1954
 
 
1955
/*********************************************************************//**
 
1956
Does an index creation operation for MySQL. TODO: currently failure
 
1957
to create an index results in dropping the whole table! This is no problem
 
1958
currently as all indexes must be created at the same time as the table.
 
1959
@return error number or DB_SUCCESS */
 
1960
UNIV_INTERN
 
1961
int
 
1962
row_create_index_for_mysql(
 
1963
/*=======================*/
 
1964
        dict_index_t*   index,          /*!< in, own: index definition
 
1965
                                        (will be freed) */
 
1966
        trx_t*          trx,            /*!< in: transaction handle */
 
1967
        const ulint*    field_lengths)  /*!< in: if not NULL, must contain
 
1968
                                        dict_index_get_n_fields(index)
 
1969
                                        actual field lengths for the
 
1970
                                        index columns, which are
 
1971
                                        then checked for not being too
 
1972
                                        large. */
 
1973
{
 
1974
        ind_node_t*     node;
 
1975
        mem_heap_t*     heap;
 
1976
        que_thr_t*      thr;
 
1977
        ulint           err;
 
1978
        ulint           i;
 
1979
        ulint           len;
 
1980
        char*           table_name;
 
1981
 
 
1982
#ifdef UNIV_SYNC_DEBUG
 
1983
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 
1984
#endif /* UNIV_SYNC_DEBUG */
 
1985
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1986
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
1987
 
 
1988
        trx->op_info = "creating index";
 
1989
 
 
1990
        /* Copy the table name because we may want to drop the
 
1991
        table later, after the index object is freed (inside
 
1992
        que_run_threads()) and thus index->table_name is not available. */
 
1993
        table_name = mem_strdup(index->table_name);
 
1994
 
 
1995
        trx_start_if_not_started(trx);
 
1996
 
 
1997
        /* Check that the same column does not appear twice in the index.
 
1998
        Starting from 4.0.14, InnoDB should be able to cope with that, but
 
1999
        safer not to allow them. */
 
2000
 
 
2001
        for (i = 0; i < dict_index_get_n_fields(index); i++) {
 
2002
                ulint           j;
 
2003
 
 
2004
                for (j = 0; j < i; j++) {
 
2005
                        if (0 == ut_strcmp(
 
2006
                                    dict_index_get_nth_field(index, j)->name,
 
2007
                                    dict_index_get_nth_field(index, i)->name)) {
 
2008
                                ut_print_timestamp(stderr);
 
2009
 
 
2010
                                fputs("  InnoDB: Error: column ", stderr);
 
2011
                                ut_print_name(stderr, trx, FALSE,
 
2012
                                              dict_index_get_nth_field(
 
2013
                                                      index, i)->name);
 
2014
                                fputs(" appears twice in ", stderr);
 
2015
                                dict_index_name_print(stderr, trx, index);
 
2016
                                fputs("\n"
 
2017
                                      "InnoDB: This is not allowed"
 
2018
                                      " in InnoDB.\n", stderr);
 
2019
 
 
2020
                                err = DB_COL_APPEARS_TWICE_IN_INDEX;
 
2021
 
 
2022
                                goto error_handling;
 
2023
                        }
 
2024
                }
 
2025
 
 
2026
                /* Check also that prefix_len and actual length
 
2027
                < DICT_MAX_INDEX_COL_LEN */
 
2028
 
 
2029
                len = dict_index_get_nth_field(index, i)->prefix_len;
 
2030
 
 
2031
                if (field_lengths) {
 
2032
                        len = ut_max(len, field_lengths[i]);
 
2033
                }
 
2034
 
 
2035
                if (len >= DICT_MAX_INDEX_COL_LEN) {
 
2036
                        err = DB_TOO_BIG_RECORD;
 
2037
 
 
2038
                        goto error_handling;
 
2039
                }
 
2040
        }
 
2041
 
 
2042
        heap = mem_heap_create(512);
 
2043
 
 
2044
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
 
2045
 
 
2046
        /* Note that the space id where we store the index is inherited from
 
2047
        the table in dict_build_index_def_step() in dict0crea.c. */
 
2048
 
 
2049
        node = ind_create_graph_create(index, heap);
 
2050
 
 
2051
        thr = pars_complete_graph_for_exec(node, trx, heap);
 
2052
 
 
2053
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
 
2054
        que_run_threads(thr);
 
2055
 
 
2056
        err = trx->error_state;
 
2057
 
 
2058
        que_graph_free((que_t*) que_node_get_parent(thr));
 
2059
 
 
2060
error_handling:
 
2061
        if (err != DB_SUCCESS) {
 
2062
                /* We have special error handling here */
 
2063
 
 
2064
                trx->error_state = DB_SUCCESS;
 
2065
 
 
2066
                trx_general_rollback_for_mysql(trx, NULL);
 
2067
 
 
2068
                row_drop_table_for_mysql(table_name, trx, FALSE);
 
2069
 
 
2070
                trx_commit_for_mysql(trx);
 
2071
 
 
2072
                trx->error_state = DB_SUCCESS;
 
2073
        }
 
2074
 
 
2075
        trx->op_info = "";
 
2076
 
 
2077
        mem_free(table_name);
 
2078
 
 
2079
        return((int) err);
 
2080
}
 
2081
 
 
2082
/*********************************************************************//**
 
2083
Scans a table create SQL string and adds to the data dictionary
 
2084
the foreign key constraints declared in the string. This function
 
2085
should be called after the indexes for a table have been created.
 
2086
Each foreign key constraint must be accompanied with indexes in
 
2087
both participating tables. The indexes are allowed to contain more
 
2088
fields than mentioned in the constraint. Check also that foreign key
 
2089
constraints which reference this table are ok.
 
2090
@return error code or DB_SUCCESS */
 
2091
UNIV_INTERN
 
2092
int
 
2093
row_table_add_foreign_constraints(
 
2094
/*==============================*/
 
2095
        trx_t*          trx,            /*!< in: transaction */
 
2096
        const char*     sql_string,     /*!< in: table create statement where
 
2097
                                        foreign keys are declared like:
 
2098
                                FOREIGN KEY (a, b) REFERENCES table2(c, d),
 
2099
                                        table2 can be written also with the
 
2100
                                        database name before it: test.table2 */
 
2101
        size_t          sql_length,     /*!< in: length of sql_string */
 
2102
        const char*     name,           /*!< in: table full name in the
 
2103
                                        normalized form
 
2104
                                        database_name/table_name */
 
2105
        ibool           reject_fks)     /*!< in: if TRUE, fail with error
 
2106
                                        code DB_CANNOT_ADD_CONSTRAINT if
 
2107
                                        any foreign keys are found. */
 
2108
{
 
2109
        ulint   err;
 
2110
 
 
2111
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
2112
#ifdef UNIV_SYNC_DEBUG
 
2113
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 
2114
#endif /* UNIV_SYNC_DEBUG */
 
2115
        ut_a(sql_string);
 
2116
 
 
2117
        trx->op_info = "adding foreign keys";
 
2118
 
 
2119
        trx_start_if_not_started(trx);
 
2120
 
 
2121
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
 
2122
 
 
2123
        err = dict_create_foreign_constraints(trx, sql_string, sql_length,
 
2124
                                              name, reject_fks);
 
2125
        if (err == DB_SUCCESS) {
 
2126
                /* Check that also referencing constraints are ok */
 
2127
                err = dict_load_foreigns(name, FALSE, TRUE);
 
2128
        }
 
2129
 
 
2130
        if (err != DB_SUCCESS) {
 
2131
                /* We have special error handling here */
 
2132
 
 
2133
                trx->error_state = DB_SUCCESS;
 
2134
 
 
2135
                trx_general_rollback_for_mysql(trx, NULL);
 
2136
 
 
2137
                row_drop_table_for_mysql(name, trx, FALSE);
 
2138
 
 
2139
                trx_commit_for_mysql(trx);
 
2140
 
 
2141
                trx->error_state = DB_SUCCESS;
 
2142
        }
 
2143
 
 
2144
        return((int) err);
 
2145
}
 
2146
 
 
2147
/*********************************************************************//**
 
2148
Drops a table for MySQL as a background operation. MySQL relies on Unix
 
2149
in ALTER TABLE to the fact that the table handler does not remove the
 
2150
table before all handles to it has been removed. Furhermore, the MySQL's
 
2151
call to drop table must be non-blocking. Therefore we do the drop table
 
2152
as a background operation, which is taken care of by the master thread
 
2153
in srv0srv.c.
 
2154
@return error code or DB_SUCCESS */
 
2155
static
 
2156
int
 
2157
row_drop_table_for_mysql_in_background(
 
2158
/*===================================*/
 
2159
        const char*     name)   /*!< in: table name */
 
2160
{
 
2161
        ulint   error;
 
2162
        trx_t*  trx;
 
2163
 
 
2164
        trx = trx_allocate_for_background();
 
2165
 
 
2166
        /* If the original transaction was dropping a table referenced by
 
2167
        foreign keys, we must set the following to be able to drop the
 
2168
        table: */
 
2169
 
 
2170
        trx->check_foreigns = FALSE;
 
2171
 
 
2172
        /*      fputs("InnoDB: Error: Dropping table ", stderr);
 
2173
        ut_print_name(stderr, trx, TRUE, name);
 
2174
        fputs(" in background drop list\n", stderr); */
 
2175
 
 
2176
        /* Try to drop the table in InnoDB */
 
2177
 
 
2178
        error = row_drop_table_for_mysql(name, trx, FALSE);
 
2179
 
 
2180
        /* Flush the log to reduce probability that the .frm files and
 
2181
        the InnoDB data dictionary get out-of-sync if the user runs
 
2182
        with innodb_flush_log_at_trx_commit = 0 */
 
2183
 
 
2184
        log_buffer_flush_to_disk();
 
2185
 
 
2186
        trx_commit_for_mysql(trx);
 
2187
 
 
2188
        trx_free_for_background(trx);
 
2189
 
 
2190
        return((int) error);
 
2191
}
 
2192
 
 
2193
/*********************************************************************//**
 
2194
The master thread in srv0srv.c calls this regularly to drop tables which
 
2195
we must drop in background after queries to them have ended. Such lazy
 
2196
dropping of tables is needed in ALTER TABLE on Unix.
 
2197
@return how many tables dropped + remaining tables in list */
 
2198
UNIV_INTERN
 
2199
ulint
 
2200
row_drop_tables_for_mysql_in_background(void)
 
2201
/*=========================================*/
 
2202
{
 
2203
        row_mysql_drop_t*       drop;
 
2204
        dict_table_t*           table;
 
2205
        ulint                   n_tables;
 
2206
        ulint                   n_tables_dropped = 0;
 
2207
loop:
 
2208
        mutex_enter(&kernel_mutex);
 
2209
 
 
2210
        if (!row_mysql_drop_list_inited) {
 
2211
 
 
2212
                UT_LIST_INIT(row_mysql_drop_list);
 
2213
                row_mysql_drop_list_inited = TRUE;
 
2214
        }
 
2215
 
 
2216
        drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
 
2217
 
 
2218
        n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
 
2219
 
 
2220
        mutex_exit(&kernel_mutex);
 
2221
 
 
2222
        if (drop == NULL) {
 
2223
                /* All tables dropped */
 
2224
 
 
2225
                return(n_tables + n_tables_dropped);
 
2226
        }
 
2227
 
 
2228
        mutex_enter(&(dict_sys->mutex));
 
2229
        table = dict_table_get_low(drop->table_name);
 
2230
        mutex_exit(&(dict_sys->mutex));
 
2231
 
 
2232
        if (table == NULL) {
 
2233
                /* If for some reason the table has already been dropped
 
2234
                through some other mechanism, do not try to drop it */
 
2235
 
 
2236
                goto already_dropped;
 
2237
        }
 
2238
 
 
2239
        if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
 
2240
                    drop->table_name)) {
 
2241
                /* If the DROP fails for some table, we return, and let the
 
2242
                main thread retry later */
 
2243
 
 
2244
                return(n_tables + n_tables_dropped);
 
2245
        }
 
2246
 
 
2247
        n_tables_dropped++;
 
2248
 
 
2249
already_dropped:
 
2250
        mutex_enter(&kernel_mutex);
 
2251
 
 
2252
        UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
 
2253
 
 
2254
        ut_print_timestamp(stderr);
 
2255
        fputs("  InnoDB: Dropped table ", stderr);
 
2256
        ut_print_name(stderr, NULL, TRUE, drop->table_name);
 
2257
        fputs(" in background drop queue.\n", stderr);
 
2258
 
 
2259
        mem_free(drop->table_name);
 
2260
 
 
2261
        mem_free(drop);
 
2262
 
 
2263
        mutex_exit(&kernel_mutex);
 
2264
 
 
2265
        goto loop;
 
2266
}
 
2267
 
 
2268
/*********************************************************************//**
 
2269
Get the background drop list length. NOTE: the caller must own the kernel
 
2270
mutex!
 
2271
@return how many tables in list */
 
2272
UNIV_INTERN
 
2273
ulint
 
2274
row_get_background_drop_list_len_low(void)
 
2275
/*======================================*/
 
2276
{
 
2277
        ut_ad(mutex_own(&kernel_mutex));
 
2278
 
 
2279
        if (!row_mysql_drop_list_inited) {
 
2280
 
 
2281
                UT_LIST_INIT(row_mysql_drop_list);
 
2282
                row_mysql_drop_list_inited = TRUE;
 
2283
        }
 
2284
 
 
2285
        return(UT_LIST_GET_LEN(row_mysql_drop_list));
 
2286
}
 
2287
 
 
2288
/*********************************************************************//**
 
2289
If a table is not yet in the drop list, adds the table to the list of tables
 
2290
which the master thread drops in background. We need this on Unix because in
 
2291
ALTER TABLE MySQL may call drop table even if the table has running queries on
 
2292
it. Also, if there are running foreign key checks on the table, we drop the
 
2293
table lazily.
 
2294
@return TRUE if the table was not yet in the drop list, and was added there */
 
2295
static
 
2296
ibool
 
2297
row_add_table_to_background_drop_list(
 
2298
/*==================================*/
 
2299
        const char*     name)   /*!< in: table name */
 
2300
{
 
2301
        row_mysql_drop_t*       drop;
 
2302
 
 
2303
        mutex_enter(&kernel_mutex);
 
2304
 
 
2305
        if (!row_mysql_drop_list_inited) {
 
2306
 
 
2307
                UT_LIST_INIT(row_mysql_drop_list);
 
2308
                row_mysql_drop_list_inited = TRUE;
 
2309
        }
 
2310
 
 
2311
        /* Look if the table already is in the drop list */
 
2312
        drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
 
2313
 
 
2314
        while (drop != NULL) {
 
2315
                if (strcmp(drop->table_name, name) == 0) {
 
2316
                        /* Already in the list */
 
2317
 
 
2318
                        mutex_exit(&kernel_mutex);
 
2319
 
 
2320
                        return(FALSE);
 
2321
                }
 
2322
 
 
2323
                drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
 
2324
        }
 
2325
 
 
2326
        drop = mem_alloc(sizeof(row_mysql_drop_t));
 
2327
 
 
2328
        drop->table_name = mem_strdup(name);
 
2329
 
 
2330
        UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
 
2331
 
 
2332
        /*      fputs("InnoDB: Adding table ", stderr);
 
2333
        ut_print_name(stderr, trx, TRUE, drop->table_name);
 
2334
        fputs(" to background drop list\n", stderr); */
 
2335
 
 
2336
        mutex_exit(&kernel_mutex);
 
2337
 
 
2338
        return(TRUE);
 
2339
}
 
2340
 
 
2341
/*********************************************************************//**
 
2342
Discards the tablespace of a table which stored in an .ibd file. Discarding
 
2343
means that this function deletes the .ibd file and assigns a new table id for
 
2344
the table. Also the flag table->ibd_file_missing is set TRUE.
 
2345
@return error code or DB_SUCCESS */
 
2346
UNIV_INTERN
 
2347
int
 
2348
row_discard_tablespace_for_mysql(
 
2349
/*=============================*/
 
2350
        const char*     name,   /*!< in: table name */
 
2351
        trx_t*          trx)    /*!< in: transaction handle */
 
2352
{
 
2353
        dict_foreign_t* foreign;
 
2354
        table_id_t      new_id;
 
2355
        dict_table_t*   table;
 
2356
        ibool           success;
 
2357
        ulint           err;
 
2358
        pars_info_t*    info = NULL;
 
2359
 
 
2360
        /* How do we prevent crashes caused by ongoing operations on
 
2361
        the table? Old operations could try to access non-existent
 
2362
        pages.
 
2363
 
 
2364
        1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
 
2365
        MySQL table lock on the table before we can do DISCARD
 
2366
        TABLESPACE. Then there are no running queries on the table.
 
2367
 
 
2368
        2) Purge and rollback: we assign a new table id for the
 
2369
        table. Since purge and rollback look for the table based on
 
2370
        the table id, they see the table as 'dropped' and discard
 
2371
        their operations.
 
2372
 
 
2373
        3) Insert buffer: we remove all entries for the tablespace in
 
2374
        the insert buffer tree; as long as the tablespace mem object
 
2375
        does not exist, ongoing insert buffer page merges are
 
2376
        discarded in buf0rea.c. If we recreate the tablespace mem
 
2377
        object with IMPORT TABLESPACE later, then the tablespace will
 
2378
        have the same id, but the tablespace_version field in the mem
 
2379
        object is different, and ongoing old insert buffer page merges
 
2380
        get discarded.
 
2381
 
 
2382
        4) Linear readahead and random readahead: we use the same
 
2383
        method as in 3) to discard ongoing operations.
 
2384
 
 
2385
        5) FOREIGN KEY operations: if
 
2386
        table->n_foreign_key_checks_running > 0, we do not allow the
 
2387
        discard. We also reserve the data dictionary latch. */
 
2388
 
 
2389
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
2390
 
 
2391
        trx->op_info = "discarding tablespace";
 
2392
        trx_start_if_not_started(trx);
 
2393
 
 
2394
        /* Serialize data dictionary operations with dictionary mutex:
 
2395
        no deadlocks can occur then in these operations */
 
2396
 
 
2397
        row_mysql_lock_data_dictionary(trx);
 
2398
 
 
2399
        table = dict_table_get_low(name);
 
2400
 
 
2401
        if (!table) {
 
2402
                err = DB_TABLE_NOT_FOUND;
 
2403
 
 
2404
                goto funct_exit;
 
2405
        }
 
2406
 
 
2407
        if (table->space == 0) {
 
2408
                ut_print_timestamp(stderr);
 
2409
                fputs("  InnoDB: Error: table ", stderr);
 
2410
                ut_print_name(stderr, trx, TRUE, name);
 
2411
                fputs("\n"
 
2412
                      "InnoDB: is in the system tablespace 0"
 
2413
                      " which cannot be discarded\n", stderr);
 
2414
                err = DB_ERROR;
 
2415
 
 
2416
                goto funct_exit;
 
2417
        }
 
2418
 
 
2419
        if (table->n_foreign_key_checks_running > 0) {
 
2420
 
 
2421
                ut_print_timestamp(stderr);
 
2422
                fputs("  InnoDB: You are trying to DISCARD table ", stderr);
 
2423
                ut_print_name(stderr, trx, TRUE, table->name);
 
2424
                fputs("\n"
 
2425
                      "InnoDB: though there is a foreign key check"
 
2426
                      " running on it.\n"
 
2427
                      "InnoDB: Cannot discard the table.\n",
 
2428
                      stderr);
 
2429
 
 
2430
                err = DB_ERROR;
 
2431
 
 
2432
                goto funct_exit;
 
2433
        }
 
2434
 
 
2435
        /* Check if the table is referenced by foreign key constraints from
 
2436
        some other table (not the table itself) */
 
2437
 
 
2438
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
2439
 
 
2440
        while (foreign && foreign->foreign_table == table) {
 
2441
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
2442
        }
 
2443
 
 
2444
        if (foreign && trx->check_foreigns) {
 
2445
 
 
2446
                FILE*   ef      = dict_foreign_err_file;
 
2447
 
 
2448
                /* We only allow discarding a referenced table if
 
2449
                FOREIGN_KEY_CHECKS is set to 0 */
 
2450
 
 
2451
                err = DB_CANNOT_DROP_CONSTRAINT;
 
2452
 
 
2453
                mutex_enter(&dict_foreign_err_mutex);
 
2454
                rewind(ef);
 
2455
                ut_print_timestamp(ef);
 
2456
 
 
2457
                fputs("  Cannot DISCARD table ", ef);
 
2458
                ut_print_name(stderr, trx, TRUE, name);
 
2459
                fputs("\n"
 
2460
                      "because it is referenced by ", ef);
 
2461
                ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
 
2462
                putc('\n', ef);
 
2463
                mutex_exit(&dict_foreign_err_mutex);
 
2464
 
 
2465
                goto funct_exit;
 
2466
        }
 
2467
 
 
2468
        dict_hdr_get_new_id(&new_id, NULL, NULL);
 
2469
 
 
2470
        /* Remove all locks except the table-level S and X locks. */
 
2471
        lock_remove_all_on_table(table, FALSE);
 
2472
 
 
2473
        info = pars_info_create();
 
2474
 
 
2475
        pars_info_add_str_literal(info, "table_name", name);
 
2476
        pars_info_add_ull_literal(info, "new_id", new_id);
 
2477
 
 
2478
        err = que_eval_sql(info,
 
2479
                           "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
 
2480
                           "old_id CHAR;\n"
 
2481
                           "BEGIN\n"
 
2482
                           "SELECT ID INTO old_id\n"
 
2483
                           "FROM SYS_TABLES\n"
 
2484
                           "WHERE NAME = :table_name\n"
 
2485
                           "LOCK IN SHARE MODE;\n"
 
2486
                           "IF (SQL % NOTFOUND) THEN\n"
 
2487
                           "       COMMIT WORK;\n"
 
2488
                           "       RETURN;\n"
 
2489
                           "END IF;\n"
 
2490
                           "UPDATE SYS_TABLES SET ID = :new_id\n"
 
2491
                           " WHERE ID = old_id;\n"
 
2492
                           "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
 
2493
                           " WHERE TABLE_ID = old_id;\n"
 
2494
                           "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
 
2495
                           " WHERE TABLE_ID = old_id;\n"
 
2496
                           "COMMIT WORK;\n"
 
2497
                           "END;\n"
 
2498
                           , FALSE, trx);
 
2499
 
 
2500
        if (err != DB_SUCCESS) {
 
2501
                trx->error_state = DB_SUCCESS;
 
2502
                trx_general_rollback_for_mysql(trx, NULL);
 
2503
                trx->error_state = DB_SUCCESS;
 
2504
        } else {
 
2505
                dict_table_change_id_in_cache(table, new_id);
 
2506
 
 
2507
                success = fil_discard_tablespace(table->space);
 
2508
 
 
2509
                if (!success) {
 
2510
                        trx->error_state = DB_SUCCESS;
 
2511
                        trx_general_rollback_for_mysql(trx, NULL);
 
2512
                        trx->error_state = DB_SUCCESS;
 
2513
 
 
2514
                        err = DB_ERROR;
 
2515
                } else {
 
2516
                        /* Set the flag which tells that now it is legal to
 
2517
                        IMPORT a tablespace for this table */
 
2518
                        table->tablespace_discarded = TRUE;
 
2519
                        table->ibd_file_missing = TRUE;
 
2520
                }
 
2521
        }
 
2522
 
 
2523
funct_exit:
 
2524
        trx_commit_for_mysql(trx);
 
2525
 
 
2526
        row_mysql_unlock_data_dictionary(trx);
 
2527
 
 
2528
        trx->op_info = "";
 
2529
 
 
2530
        return((int) err);
 
2531
}
 
2532
 
 
2533
/*****************************************************************//**
 
2534
Imports a tablespace. The space id in the .ibd file must match the space id
 
2535
of the table in the data dictionary.
 
2536
@return error code or DB_SUCCESS */
 
2537
UNIV_INTERN
 
2538
int
 
2539
row_import_tablespace_for_mysql(
 
2540
/*============================*/
 
2541
        const char*     name,   /*!< in: table name */
 
2542
        trx_t*          trx)    /*!< in: transaction handle */
 
2543
{
 
2544
        dict_table_t*   table;
 
2545
        ibool           success;
 
2546
        ib_uint64_t     current_lsn;
 
2547
        ulint           err             = DB_SUCCESS;
 
2548
 
 
2549
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
2550
 
 
2551
        trx_start_if_not_started(trx);
 
2552
 
 
2553
        trx->op_info = "importing tablespace";
 
2554
 
 
2555
        current_lsn = log_get_lsn();
 
2556
 
 
2557
        /* It is possible, though very improbable, that the lsn's in the
 
2558
        tablespace to be imported have risen above the current system lsn, if
 
2559
        a lengthy purge, ibuf merge, or rollback was performed on a backup
 
2560
        taken with ibbackup. If that is the case, reset page lsn's in the
 
2561
        file. We assume that mysqld was shut down after it performed these
 
2562
        cleanup operations on the .ibd file, so that it stamped the latest lsn
 
2563
        to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
 
2564
 
 
2565
        TODO: reset also the trx id's in clustered index records and write
 
2566
        a new space id to each data page. That would allow us to import clean
 
2567
        .ibd files from another MySQL installation. */
 
2568
 
 
2569
        success = fil_reset_too_high_lsns(name, current_lsn);
 
2570
 
 
2571
        if (!success) {
 
2572
                ut_print_timestamp(stderr);
 
2573
                fputs("  InnoDB: Error: cannot reset lsn's in table ", stderr);
 
2574
                ut_print_name(stderr, trx, TRUE, name);
 
2575
                fputs("\n"
 
2576
                      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
 
2577
                      stderr);
 
2578
 
 
2579
                err = DB_ERROR;
 
2580
 
 
2581
                row_mysql_lock_data_dictionary(trx);
 
2582
 
 
2583
                goto funct_exit;
 
2584
        }
 
2585
 
 
2586
        /* Serialize data dictionary operations with dictionary mutex:
 
2587
        no deadlocks can occur then in these operations */
 
2588
 
 
2589
        row_mysql_lock_data_dictionary(trx);
 
2590
 
 
2591
        table = dict_table_get_low(name);
 
2592
 
 
2593
        if (!table) {
 
2594
                ut_print_timestamp(stderr);
 
2595
                fputs("  InnoDB: table ", stderr);
 
2596
                ut_print_name(stderr, trx, TRUE, name);
 
2597
                fputs("\n"
 
2598
                      "InnoDB: does not exist in the InnoDB data dictionary\n"
 
2599
                      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
 
2600
                      stderr);
 
2601
 
 
2602
                err = DB_TABLE_NOT_FOUND;
 
2603
 
 
2604
                goto funct_exit;
 
2605
        }
 
2606
 
 
2607
        if (table->space == 0) {
 
2608
                ut_print_timestamp(stderr);
 
2609
                fputs("  InnoDB: Error: table ", stderr);
 
2610
                ut_print_name(stderr, trx, TRUE, name);
 
2611
                fputs("\n"
 
2612
                      "InnoDB: is in the system tablespace 0"
 
2613
                      " which cannot be imported\n", stderr);
 
2614
                err = DB_ERROR;
 
2615
 
 
2616
                goto funct_exit;
 
2617
        }
 
2618
 
 
2619
        if (!table->tablespace_discarded) {
 
2620
                ut_print_timestamp(stderr);
 
2621
                fputs("  InnoDB: Error: you are trying to"
 
2622
                      " IMPORT a tablespace\n"
 
2623
                      "InnoDB: ", stderr);
 
2624
                ut_print_name(stderr, trx, TRUE, name);
 
2625
                fputs(", though you have not called DISCARD on it yet\n"
 
2626
                      "InnoDB: during the lifetime of the mysqld process!\n",
 
2627
                      stderr);
 
2628
 
 
2629
                err = DB_ERROR;
 
2630
 
 
2631
                goto funct_exit;
 
2632
        }
 
2633
 
 
2634
        /* Play safe and remove all insert buffer entries, though we should
 
2635
        have removed them already when DISCARD TABLESPACE was called */
 
2636
 
 
2637
        ibuf_delete_for_discarded_space(table->space);
 
2638
 
 
2639
        success = fil_open_single_table_tablespace(
 
2640
                TRUE, table->space,
 
2641
                table->flags == DICT_TF_COMPACT ? 0 : table->flags,
 
2642
                table->name);
 
2643
        if (success) {
 
2644
                table->ibd_file_missing = FALSE;
 
2645
                table->tablespace_discarded = FALSE;
 
2646
        } else {
 
2647
                if (table->ibd_file_missing) {
 
2648
                        ut_print_timestamp(stderr);
 
2649
                        fputs("  InnoDB: cannot find or open in the"
 
2650
                              " database directory the .ibd file of\n"
 
2651
                              "InnoDB: table ", stderr);
 
2652
                        ut_print_name(stderr, trx, TRUE, name);
 
2653
                        fputs("\n"
 
2654
                              "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
 
2655
                              stderr);
 
2656
                }
 
2657
 
 
2658
                err = DB_ERROR;
 
2659
        }
 
2660
 
 
2661
funct_exit:
 
2662
        trx_commit_for_mysql(trx);
 
2663
 
 
2664
        row_mysql_unlock_data_dictionary(trx);
 
2665
 
 
2666
        trx->op_info = "";
 
2667
 
 
2668
        return((int) err);
 
2669
}
 
2670
 
 
2671
/*********************************************************************//**
 
2672
Truncates a table for MySQL.
 
2673
@return error code or DB_SUCCESS */
 
2674
UNIV_INTERN
 
2675
int
 
2676
row_truncate_table_for_mysql(
 
2677
/*=========================*/
 
2678
        dict_table_t*   table,  /*!< in: table handle */
 
2679
        trx_t*          trx)    /*!< in: transaction handle */
 
2680
{
 
2681
        dict_foreign_t* foreign;
 
2682
        ulint           err;
 
2683
        mem_heap_t*     heap;
 
2684
        byte*           buf;
 
2685
        dtuple_t*       tuple;
 
2686
        dfield_t*       dfield;
 
2687
        dict_index_t*   sys_index;
 
2688
        btr_pcur_t      pcur;
 
2689
        mtr_t           mtr;
 
2690
        table_id_t      new_id;
 
2691
        ulint           recreate_space = 0;
 
2692
        pars_info_t*    info = NULL;
 
2693
 
 
2694
        /* How do we prevent crashes caused by ongoing operations on
 
2695
        the table? Old operations could try to access non-existent
 
2696
        pages.
 
2697
 
 
2698
        1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
 
2699
        MySQL table lock on the table before we can do TRUNCATE
 
2700
        TABLE. Then there are no running queries on the table. This is
 
2701
        guaranteed, because in ha_innobase::store_lock(), we do not
 
2702
        weaken the TL_WRITE lock requested by MySQL when executing
 
2703
        SQLCOM_TRUNCATE.
 
2704
 
 
2705
        2) Purge and rollback: we assign a new table id for the
 
2706
        table. Since purge and rollback look for the table based on
 
2707
        the table id, they see the table as 'dropped' and discard
 
2708
        their operations.
 
2709
 
 
2710
        3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
 
2711
        so we do not have to remove insert buffer records, as the
 
2712
        insert buffer works at a low level. If a freed page is later
 
2713
        reallocated, the allocator will remove the ibuf entries for
 
2714
        it.
 
2715
 
 
2716
        When we truncate *.ibd files by recreating them (analogous to
 
2717
        DISCARD TABLESPACE), we remove all entries for the table in the
 
2718
        insert buffer tree.  This is not strictly necessary, because
 
2719
        in 6) we will assign a new tablespace identifier, but we can
 
2720
        free up some space in the system tablespace.
 
2721
 
 
2722
        4) Linear readahead and random readahead: we use the same
 
2723
        method as in 3) to discard ongoing operations. (This is only
 
2724
        relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
 
2725
 
 
2726
        5) FOREIGN KEY operations: if
 
2727
        table->n_foreign_key_checks_running > 0, we do not allow the
 
2728
        TRUNCATE. We also reserve the data dictionary latch.
 
2729
 
 
2730
        6) Crash recovery: To prevent the application of pre-truncation
 
2731
        redo log records on the truncated tablespace, we will assign
 
2732
        a new tablespace identifier to the truncated tablespace. */
 
2733
 
 
2734
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
2735
        ut_ad(table);
 
2736
 
 
2737
        if (srv_created_new_raw) {
 
2738
                fputs("InnoDB: A new raw disk partition was initialized:\n"
 
2739
                      "InnoDB: we do not allow database modifications"
 
2740
                      " by the user.\n"
 
2741
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
 
2742
                      " is replaced with raw.\n", stderr);
 
2743
 
 
2744
                return(DB_ERROR);
 
2745
        }
 
2746
 
 
2747
        trx->op_info = "truncating table";
 
2748
 
 
2749
        trx_start_if_not_started(trx);
 
2750
 
 
2751
        /* Serialize data dictionary operations with dictionary mutex:
 
2752
        no deadlocks can occur then in these operations */
 
2753
 
 
2754
        ut_a(trx->dict_operation_lock_mode == 0);
 
2755
        /* Prevent foreign key checks etc. while we are truncating the
 
2756
        table */
 
2757
 
 
2758
        row_mysql_lock_data_dictionary(trx);
 
2759
 
 
2760
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
2761
#ifdef UNIV_SYNC_DEBUG
 
2762
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 
2763
#endif /* UNIV_SYNC_DEBUG */
 
2764
 
 
2765
        /* Check if the table is referenced by foreign key constraints from
 
2766
        some other table (not the table itself) */
 
2767
 
 
2768
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
2769
 
 
2770
        while (foreign && foreign->foreign_table == table) {
 
2771
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
2772
        }
 
2773
 
 
2774
        if (foreign && trx->check_foreigns) {
 
2775
                FILE*   ef      = dict_foreign_err_file;
 
2776
 
 
2777
                /* We only allow truncating a referenced table if
 
2778
                FOREIGN_KEY_CHECKS is set to 0 */
 
2779
 
 
2780
                mutex_enter(&dict_foreign_err_mutex);
 
2781
                rewind(ef);
 
2782
                ut_print_timestamp(ef);
 
2783
 
 
2784
                fputs("  Cannot truncate table ", ef);
 
2785
                ut_print_name(ef, trx, TRUE, table->name);
 
2786
                fputs(" by DROP+CREATE\n"
 
2787
                      "InnoDB: because it is referenced by ", ef);
 
2788
                ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
 
2789
                putc('\n', ef);
 
2790
                mutex_exit(&dict_foreign_err_mutex);
 
2791
 
 
2792
                err = DB_ERROR;
 
2793
                goto funct_exit;
 
2794
        }
 
2795
 
 
2796
        /* TODO: could we replace the counter n_foreign_key_checks_running
 
2797
        with lock checks on the table? Acquire here an exclusive lock on the
 
2798
        table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
 
2799
        they can cope with the table having been truncated here? Foreign key
 
2800
        checks take an IS or IX lock on the table. */
 
2801
 
 
2802
        if (table->n_foreign_key_checks_running > 0) {
 
2803
                ut_print_timestamp(stderr);
 
2804
                fputs("  InnoDB: Cannot truncate table ", stderr);
 
2805
                ut_print_name(stderr, trx, TRUE, table->name);
 
2806
                fputs(" by DROP+CREATE\n"
 
2807
                      "InnoDB: because there is a foreign key check"
 
2808
                      " running on it.\n",
 
2809
                      stderr);
 
2810
                err = DB_ERROR;
 
2811
 
 
2812
                goto funct_exit;
 
2813
        }
 
2814
 
 
2815
        /* Remove all locks except the table-level S and X locks. */
 
2816
        lock_remove_all_on_table(table, FALSE);
 
2817
 
 
2818
        trx->table_id = table->id;
 
2819
 
 
2820
        /* Lock all index trees for this table, as we will
 
2821
        truncate the table/index and possibly change their metadata.
 
2822
        All DML/DDL are blocked by table level lock, with
 
2823
        a few exceptions such as queries into information schema
 
2824
        about the table, MySQL could try to access index stats
 
2825
        for this kind of query, we need to use index locks to
 
2826
        sync up */
 
2827
        dict_table_x_lock_indexes(table);
 
2828
 
 
2829
        if (table->space && !table->dir_path_of_temp_table) {
 
2830
                /* Discard and create the single-table tablespace. */
 
2831
                ulint   space   = table->space;
 
2832
                ulint   flags   = fil_space_get_flags(space);
 
2833
 
 
2834
                if (flags != ULINT_UNDEFINED
 
2835
                    && fil_discard_tablespace(space)) {
 
2836
 
 
2837
                        dict_index_t*   index;
 
2838
 
 
2839
                        dict_hdr_get_new_id(NULL, NULL, &space);
 
2840
 
 
2841
                        if (space == ULINT_UNDEFINED
 
2842
                            || fil_create_new_single_table_tablespace(
 
2843
                                    space, table->name, FALSE, flags,
 
2844
                                    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
 
2845
                                dict_table_x_unlock_indexes(table);
 
2846
                                ut_print_timestamp(stderr);
 
2847
                                fprintf(stderr,
 
2848
                                        "  InnoDB: TRUNCATE TABLE %s failed to"
 
2849
                                        " create a new tablespace\n",
 
2850
                                        table->name);
 
2851
                                table->ibd_file_missing = 1;
 
2852
                                err = DB_ERROR;
 
2853
                                goto funct_exit;
 
2854
                        }
 
2855
 
 
2856
                        recreate_space = space;
 
2857
 
 
2858
                        /* Replace the space_id in the data dictionary cache.
 
2859
                        The persisent data dictionary (SYS_TABLES.SPACE
 
2860
                        and SYS_INDEXES.SPACE) are updated later in this
 
2861
                        function. */
 
2862
                        table->space = space;
 
2863
                        index = dict_table_get_first_index(table);
 
2864
                        do {
 
2865
                                index->space = space;
 
2866
                                index = dict_table_get_next_index(index);
 
2867
                        } while (index);
 
2868
 
 
2869
                        mtr_start(&mtr);
 
2870
                        fsp_header_init(space,
 
2871
                                        FIL_IBD_FILE_INITIAL_SIZE, &mtr);
 
2872
                        mtr_commit(&mtr);
 
2873
                }
 
2874
        }
 
2875
 
 
2876
        /* scan SYS_INDEXES for all indexes of the table */
 
2877
        heap = mem_heap_create(800);
 
2878
 
 
2879
        tuple = dtuple_create(heap, 1);
 
2880
        dfield = dtuple_get_nth_field(tuple, 0);
 
2881
 
 
2882
        buf = mem_heap_alloc(heap, 8);
 
2883
        mach_write_to_8(buf, table->id);
 
2884
 
 
2885
        dfield_set_data(dfield, buf, 8);
 
2886
        sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
 
2887
        dict_index_copy_types(tuple, sys_index, 1);
 
2888
 
 
2889
        mtr_start(&mtr);
 
2890
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
2891
                                  BTR_MODIFY_LEAF, &pcur, &mtr);
 
2892
        for (;;) {
 
2893
                rec_t*          rec;
 
2894
                const byte*     field;
 
2895
                ulint           len;
 
2896
                ulint           root_page_no;
 
2897
 
 
2898
                if (!btr_pcur_is_on_user_rec(&pcur)) {
 
2899
                        /* The end of SYS_INDEXES has been reached. */
 
2900
                        break;
 
2901
                }
 
2902
 
 
2903
                rec = btr_pcur_get_rec(&pcur);
 
2904
 
 
2905
                field = rec_get_nth_field_old(rec, 0, &len);
 
2906
                ut_ad(len == 8);
 
2907
 
 
2908
                if (memcmp(buf, field, len) != 0) {
 
2909
                        /* End of indexes for the table (TABLE_ID mismatch). */
 
2910
                        break;
 
2911
                }
 
2912
 
 
2913
                if (rec_get_deleted_flag(rec, FALSE)) {
 
2914
                        /* The index has been dropped. */
 
2915
                        goto next_rec;
 
2916
                }
 
2917
 
 
2918
                /* This call may commit and restart mtr
 
2919
                and reposition pcur. */
 
2920
                root_page_no = dict_truncate_index_tree(table, recreate_space,
 
2921
                                                        &pcur, &mtr);
 
2922
 
 
2923
                rec = btr_pcur_get_rec(&pcur);
 
2924
 
 
2925
                if (root_page_no != FIL_NULL) {
 
2926
                        page_rec_write_index_page_no(
 
2927
                                rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
 
2928
                                root_page_no, &mtr);
 
2929
                        /* We will need to commit and restart the
 
2930
                        mini-transaction in order to avoid deadlocks.
 
2931
                        The dict_truncate_index_tree() call has allocated
 
2932
                        a page in this mini-transaction, and the rest of
 
2933
                        this loop could latch another index page. */
 
2934
                        mtr_commit(&mtr);
 
2935
                        mtr_start(&mtr);
 
2936
                        btr_pcur_restore_position(BTR_MODIFY_LEAF,
 
2937
                                                  &pcur, &mtr);
 
2938
                }
 
2939
 
 
2940
next_rec:
 
2941
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
2942
        }
 
2943
 
 
2944
        btr_pcur_close(&pcur);
 
2945
        mtr_commit(&mtr);
 
2946
 
 
2947
        mem_heap_free(heap);
 
2948
 
 
2949
        /* Done with index truncation, release index tree locks,
 
2950
        subsequent work relates to table level metadata change */
 
2951
        dict_table_x_unlock_indexes(table);
 
2952
 
 
2953
        dict_hdr_get_new_id(&new_id, NULL, NULL);
 
2954
 
 
2955
        info = pars_info_create();
 
2956
 
 
2957
        pars_info_add_int4_literal(info, "space", (lint) table->space);
 
2958
        pars_info_add_ull_literal(info, "old_id", table->id);
 
2959
        pars_info_add_ull_literal(info, "new_id", new_id);
 
2960
 
 
2961
        err = que_eval_sql(info,
 
2962
                           "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
 
2963
                           "BEGIN\n"
 
2964
                           "UPDATE SYS_TABLES"
 
2965
                           " SET ID = :new_id, SPACE = :space\n"
 
2966
                           " WHERE ID = :old_id;\n"
 
2967
                           "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
 
2968
                           " WHERE TABLE_ID = :old_id;\n"
 
2969
                           "UPDATE SYS_INDEXES"
 
2970
                           " SET TABLE_ID = :new_id, SPACE = :space\n"
 
2971
                           " WHERE TABLE_ID = :old_id;\n"
 
2972
                           "COMMIT WORK;\n"
 
2973
                           "END;\n"
 
2974
                           , FALSE, trx);
 
2975
 
 
2976
        if (err != DB_SUCCESS) {
 
2977
                trx->error_state = DB_SUCCESS;
 
2978
                trx_general_rollback_for_mysql(trx, NULL);
 
2979
                trx->error_state = DB_SUCCESS;
 
2980
                ut_print_timestamp(stderr);
 
2981
                fputs("  InnoDB: Unable to assign a new identifier to table ",
 
2982
                      stderr);
 
2983
                ut_print_name(stderr, trx, TRUE, table->name);
 
2984
                fputs("\n"
 
2985
                      "InnoDB: after truncating it.  Background processes"
 
2986
                      " may corrupt the table!\n", stderr);
 
2987
                err = DB_ERROR;
 
2988
        } else {
 
2989
                dict_table_change_id_in_cache(table, new_id);
 
2990
        }
 
2991
 
 
2992
        /* 
 
2993
          MySQL calls ha_innobase::reset_auto_increment() which does
 
2994
          the same thing. 
 
2995
        */
 
2996
        dict_table_autoinc_lock(table);
 
2997
        dict_table_autoinc_initialize(table, 1);
 
2998
        dict_table_autoinc_unlock(table);
 
2999
        dict_update_statistics(table);
 
3000
 
 
3001
        trx_commit_for_mysql(trx);
 
3002
 
 
3003
funct_exit:
 
3004
 
 
3005
        row_mysql_unlock_data_dictionary(trx);
 
3006
 
 
3007
        trx->op_info = "";
 
3008
 
 
3009
        srv_wake_master_thread();
 
3010
 
 
3011
        return((int) err);
 
3012
}
 
3013
 
 
3014
/*********************************************************************//**
 
3015
Drops a table for MySQL.  If the name of the dropped table ends in
 
3016
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
 
3017
"innodb_table_monitor", then this will also stop the printing of monitor
 
3018
output by the master thread.  If the data dictionary was not already locked
 
3019
by the transaction, the transaction will be committed.  Otherwise, the
 
3020
data dictionary will remain locked.
 
3021
@return error code or DB_SUCCESS */
 
3022
UNIV_INTERN
 
3023
int
 
3024
row_drop_table_for_mysql(
 
3025
/*=====================*/
 
3026
        const char*     name,   /*!< in: table name */
 
3027
        trx_t*          trx,    /*!< in: transaction handle */
 
3028
        ibool           drop_db)/*!< in: TRUE=dropping whole database */
 
3029
{
 
3030
        dict_foreign_t* foreign;
 
3031
        dict_table_t*   table;
 
3032
        ulint           space_id;
 
3033
        ulint           err;
 
3034
        const char*     table_name;
 
3035
        ulint           namelen;
 
3036
        ibool           locked_dictionary       = FALSE;
 
3037
        pars_info_t*    info                    = NULL;
 
3038
 
 
3039
        ut_a(name != NULL);
 
3040
 
 
3041
        if (srv_created_new_raw) {
 
3042
                fputs("InnoDB: A new raw disk partition was initialized:\n"
 
3043
                      "InnoDB: we do not allow database modifications"
 
3044
                      " by the user.\n"
 
3045
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
 
3046
                      " is replaced with raw.\n", stderr);
 
3047
 
 
3048
                return(DB_ERROR);
 
3049
        }
 
3050
 
 
3051
        trx->op_info = "dropping table";
 
3052
 
 
3053
        trx_start_if_not_started(trx);
 
3054
 
 
3055
        /* The table name is prefixed with the database name and a '/'.
 
3056
        Certain table names starting with 'innodb_' have their special
 
3057
        meaning regardless of the database name.  Thus, we need to
 
3058
        ignore the database name prefix in the comparisons. */
 
3059
        table_name = strchr(name, '/');
 
3060
        ut_a(table_name);
 
3061
        table_name++;
 
3062
        namelen = strlen(table_name) + 1;
 
3063
 
 
3064
        if (namelen == sizeof S_innodb_monitor
 
3065
            && !memcmp(table_name, S_innodb_monitor,
 
3066
                       sizeof S_innodb_monitor)) {
 
3067
 
 
3068
                /* Table name equals "innodb_monitor":
 
3069
                stop monitor prints */
 
3070
 
 
3071
                srv_print_innodb_monitor = FALSE;
 
3072
                srv_print_innodb_lock_monitor = FALSE;
 
3073
        } else if (namelen == sizeof S_innodb_lock_monitor
 
3074
                   && !memcmp(table_name, S_innodb_lock_monitor,
 
3075
                              sizeof S_innodb_lock_monitor)) {
 
3076
                srv_print_innodb_monitor = FALSE;
 
3077
                srv_print_innodb_lock_monitor = FALSE;
 
3078
        } else if (namelen == sizeof S_innodb_tablespace_monitor
 
3079
                   && !memcmp(table_name, S_innodb_tablespace_monitor,
 
3080
                              sizeof S_innodb_tablespace_monitor)) {
 
3081
 
 
3082
                srv_print_innodb_tablespace_monitor = FALSE;
 
3083
        } else if (namelen == sizeof S_innodb_table_monitor
 
3084
                   && !memcmp(table_name, S_innodb_table_monitor,
 
3085
                              sizeof S_innodb_table_monitor)) {
 
3086
 
 
3087
                srv_print_innodb_table_monitor = FALSE;
 
3088
        }
 
3089
 
 
3090
        /* Serialize data dictionary operations with dictionary mutex:
 
3091
        no deadlocks can occur then in these operations */
 
3092
 
 
3093
        if (trx->dict_operation_lock_mode != RW_X_LATCH) {
 
3094
                /* Prevent foreign key checks etc. while we are dropping the
 
3095
                table */
 
3096
 
 
3097
                row_mysql_lock_data_dictionary(trx);
 
3098
 
 
3099
                locked_dictionary = TRUE;
 
3100
        }
 
3101
 
 
3102
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
3103
#ifdef UNIV_SYNC_DEBUG
 
3104
        ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 
3105
#endif /* UNIV_SYNC_DEBUG */
 
3106
 
 
3107
        table = dict_table_get_low(name);
 
3108
 
 
3109
        if (!table) {
 
3110
#if defined(BUILD_DRIZZLE)
 
3111
                err = ENOENT;
 
3112
#else
 
3113
                err = DB_TABLE_NOT_FOUND;
 
3114
                ut_print_timestamp(stderr);
 
3115
 
 
3116
                fputs("  InnoDB: Error: table ", stderr);
 
3117
                ut_print_name(stderr, trx, TRUE, name);
 
3118
                fputs(" does not exist in the InnoDB internal\n"
 
3119
                      "InnoDB: data dictionary though MySQL is"
 
3120
                      " trying to drop it.\n"
 
3121
                      "InnoDB: Have you copied the .frm file"
 
3122
                      " of the table to the\n"
 
3123
                      "InnoDB: MySQL database directory"
 
3124
                      " from another database?\n"
 
3125
                      "InnoDB: You can look for further help from\n"
 
3126
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
 
3127
                      stderr);
 
3128
#endif /* BUILD_DRIZZLE */
 
3129
                goto funct_exit;
 
3130
        }
 
3131
 
 
3132
        /* Check if the table is referenced by foreign key constraints from
 
3133
        some other table (not the table itself) */
 
3134
 
 
3135
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
3136
 
 
3137
        while (foreign && foreign->foreign_table == table) {
 
3138
check_next_foreign:
 
3139
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 
3140
        }
 
3141
 
 
3142
        if (foreign && trx->check_foreigns
 
3143
            && !(drop_db && dict_tables_have_same_db(
 
3144
                         name, foreign->foreign_table_name))) {
 
3145
                FILE*   ef      = dict_foreign_err_file;
 
3146
 
 
3147
                /* We only allow dropping a referenced table if
 
3148
                FOREIGN_KEY_CHECKS is set to 0 */
 
3149
 
 
3150
                err = DB_CANNOT_DROP_CONSTRAINT;
 
3151
 
 
3152
                mutex_enter(&dict_foreign_err_mutex);
 
3153
                rewind(ef);
 
3154
                ut_print_timestamp(ef);
 
3155
 
 
3156
                fputs("  Cannot drop table ", ef);
 
3157
                ut_print_name(ef, trx, TRUE, name);
 
3158
                fputs("\n"
 
3159
                      "because it is referenced by ", ef);
 
3160
                ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
 
3161
                putc('\n', ef);
 
3162
                mutex_exit(&dict_foreign_err_mutex);
 
3163
 
 
3164
                goto funct_exit;
 
3165
        }
 
3166
 
 
3167
        if (foreign && trx->check_foreigns) {
 
3168
                goto check_next_foreign;
 
3169
        }
 
3170
 
 
3171
        if (table->n_mysql_handles_opened > 0) {
 
3172
                ibool   added;
 
3173
 
 
3174
                added = row_add_table_to_background_drop_list(table->name);
 
3175
 
 
3176
                if (added) {
 
3177
                        ut_print_timestamp(stderr);
 
3178
                        fputs("  InnoDB: Warning: MySQL is"
 
3179
                              " trying to drop table ", stderr);
 
3180
                        ut_print_name(stderr, trx, TRUE, table->name);
 
3181
                        fputs("\n"
 
3182
                              "InnoDB: though there are still"
 
3183
                              " open handles to it.\n"
 
3184
                              "InnoDB: Adding the table to the"
 
3185
                              " background drop queue.\n",
 
3186
                              stderr);
 
3187
 
 
3188
                        /* We return DB_SUCCESS to MySQL though the drop will
 
3189
                        happen lazily later */
 
3190
                        err = DB_SUCCESS;
 
3191
                } else {
 
3192
                        /* The table is already in the background drop list */
 
3193
                        err = DB_ERROR;
 
3194
                }
 
3195
 
 
3196
                goto funct_exit;
 
3197
        }
 
3198
 
 
3199
        /* TODO: could we replace the counter n_foreign_key_checks_running
 
3200
        with lock checks on the table? Acquire here an exclusive lock on the
 
3201
        table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
 
3202
        they can cope with the table having been dropped here? Foreign key
 
3203
        checks take an IS or IX lock on the table. */
 
3204
 
 
3205
        if (table->n_foreign_key_checks_running > 0) {
 
3206
 
 
3207
                const char*     table_name = table->name;
 
3208
                ibool           added;
 
3209
 
 
3210
                added = row_add_table_to_background_drop_list(table_name);
 
3211
 
 
3212
                if (added) {
 
3213
                        ut_print_timestamp(stderr);
 
3214
                        fputs("  InnoDB: You are trying to drop table ",
 
3215
                              stderr);
 
3216
                        ut_print_name(stderr, trx, TRUE, table_name);
 
3217
                        fputs("\n"
 
3218
                              "InnoDB: though there is a"
 
3219
                              " foreign key check running on it.\n"
 
3220
                              "InnoDB: Adding the table to"
 
3221
                              " the background drop queue.\n",
 
3222
                              stderr);
 
3223
 
 
3224
                        /* We return DB_SUCCESS to MySQL though the drop will
 
3225
                        happen lazily later */
 
3226
 
 
3227
                        err = DB_SUCCESS;
 
3228
                } else {
 
3229
                        /* The table is already in the background drop list */
 
3230
                        err = DB_ERROR;
 
3231
                }
 
3232
 
 
3233
                goto funct_exit;
 
3234
        }
 
3235
 
 
3236
        /* Remove all locks there are on the table or its records */
 
3237
        lock_remove_all_on_table(table, TRUE);
 
3238
 
 
3239
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
 
3240
        trx->table_id = table->id;
 
3241
 
 
3242
        /* We use the private SQL parser of Innobase to generate the
 
3243
        query graphs needed in deleting the dictionary data from system
 
3244
        tables in Innobase. Deleting a row from SYS_INDEXES table also
 
3245
        frees the file segments of the B-tree associated with the index. */
 
3246
 
 
3247
        info = pars_info_create();
 
3248
 
 
3249
        pars_info_add_str_literal(info, "table_name", name);
 
3250
 
 
3251
        err = que_eval_sql(info,
 
3252
                           "PROCEDURE DROP_TABLE_PROC () IS\n"
 
3253
                           "sys_foreign_id CHAR;\n"
 
3254
                           "table_id CHAR;\n"
 
3255
                           "index_id CHAR;\n"
 
3256
                           "foreign_id CHAR;\n"
 
3257
                           "found INT;\n"
 
3258
                           "BEGIN\n"
 
3259
                           "SELECT ID INTO table_id\n"
 
3260
                           "FROM SYS_TABLES\n"
 
3261
                           "WHERE NAME = :table_name\n"
 
3262
                           "LOCK IN SHARE MODE;\n"
 
3263
                           "IF (SQL % NOTFOUND) THEN\n"
 
3264
                           "       RETURN;\n"
 
3265
                           "END IF;\n"
 
3266
                           "found := 1;\n"
 
3267
                           "SELECT ID INTO sys_foreign_id\n"
 
3268
                           "FROM SYS_TABLES\n"
 
3269
                           "WHERE NAME = 'SYS_FOREIGN'\n"
 
3270
                           "LOCK IN SHARE MODE;\n"
 
3271
                           "IF (SQL % NOTFOUND) THEN\n"
 
3272
                           "       found := 0;\n"
 
3273
                           "END IF;\n"
 
3274
                           "IF (:table_name = 'SYS_FOREIGN') THEN\n"
 
3275
                           "       found := 0;\n"
 
3276
                           "END IF;\n"
 
3277
                           "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
 
3278
                           "       found := 0;\n"
 
3279
                           "END IF;\n"
 
3280
                           "WHILE found = 1 LOOP\n"
 
3281
                           "       SELECT ID INTO foreign_id\n"
 
3282
                           "       FROM SYS_FOREIGN\n"
 
3283
                           "       WHERE FOR_NAME = :table_name\n"
 
3284
                           "               AND TO_BINARY(FOR_NAME)\n"
 
3285
                           "                 = TO_BINARY(:table_name)\n"
 
3286
                           "               LOCK IN SHARE MODE;\n"
 
3287
                           "       IF (SQL % NOTFOUND) THEN\n"
 
3288
                           "               found := 0;\n"
 
3289
                           "       ELSE\n"
 
3290
                           "               DELETE FROM SYS_FOREIGN_COLS\n"
 
3291
                           "               WHERE ID = foreign_id;\n"
 
3292
                           "               DELETE FROM SYS_FOREIGN\n"
 
3293
                           "               WHERE ID = foreign_id;\n"
 
3294
                           "       END IF;\n"
 
3295
                           "END LOOP;\n"
 
3296
                           "found := 1;\n"
 
3297
                           "WHILE found = 1 LOOP\n"
 
3298
                           "       SELECT ID INTO index_id\n"
 
3299
                           "       FROM SYS_INDEXES\n"
 
3300
                           "       WHERE TABLE_ID = table_id\n"
 
3301
                           "       LOCK IN SHARE MODE;\n"
 
3302
                           "       IF (SQL % NOTFOUND) THEN\n"
 
3303
                           "               found := 0;\n"
 
3304
                           "       ELSE\n"
 
3305
                           "               DELETE FROM SYS_FIELDS\n"
 
3306
                           "               WHERE INDEX_ID = index_id;\n"
 
3307
                           "               DELETE FROM SYS_INDEXES\n"
 
3308
                           "               WHERE ID = index_id\n"
 
3309
                           "               AND TABLE_ID = table_id;\n"
 
3310
                           "       END IF;\n"
 
3311
                           "END LOOP;\n"
 
3312
                           "DELETE FROM SYS_COLUMNS\n"
 
3313
                           "WHERE TABLE_ID = table_id;\n"
 
3314
                           "DELETE FROM SYS_TABLES\n"
 
3315
                           "WHERE ID = table_id;\n"
 
3316
                           "END;\n"
 
3317
                           , FALSE, trx);
 
3318
 
 
3319
        switch (err) {
 
3320
                ibool           is_temp;
 
3321
                const char*     name_or_path;
 
3322
                mem_heap_t*     heap;
 
3323
 
 
3324
        case DB_SUCCESS:
 
3325
 
 
3326
                heap = mem_heap_create(200);
 
3327
 
 
3328
                /* Clone the name, in case it has been allocated
 
3329
                from table->heap, which will be freed by
 
3330
                dict_table_remove_from_cache(table) below. */
 
3331
                name = mem_heap_strdup(heap, name);
 
3332
                space_id = table->space;
 
3333
 
 
3334
                if (table->dir_path_of_temp_table != NULL) {
 
3335
                        name_or_path = mem_heap_strdup(
 
3336
                                heap, table->dir_path_of_temp_table);
 
3337
                        is_temp = TRUE;
 
3338
                } else {
 
3339
                        name_or_path = name;
 
3340
                        is_temp = (table->flags >> DICT_TF2_SHIFT)
 
3341
                                & DICT_TF2_TEMPORARY;
 
3342
                }
 
3343
 
 
3344
                dict_table_remove_from_cache(table);
 
3345
 
 
3346
                if (dict_load_table(name, TRUE) != NULL) {
 
3347
                        ut_print_timestamp(stderr);
 
3348
                        fputs("  InnoDB: Error: not able to remove table ",
 
3349
                              stderr);
 
3350
                        ut_print_name(stderr, trx, TRUE, name);
 
3351
                        fputs(" from the dictionary cache!\n", stderr);
 
3352
                        err = DB_ERROR;
 
3353
                }
 
3354
 
 
3355
                /* Do not drop possible .ibd tablespace if something went
 
3356
                wrong: we do not want to delete valuable data of the user */
 
3357
 
 
3358
                if (err == DB_SUCCESS && space_id > 0) {
 
3359
                        if (!fil_space_for_table_exists_in_mem(space_id,
 
3360
                                                               name_or_path,
 
3361
                                                               is_temp, FALSE,
 
3362
                                                               !is_temp)) {
 
3363
                                err = DB_SUCCESS;
 
3364
 
 
3365
                                fprintf(stderr,
 
3366
                                        "InnoDB: We removed now the InnoDB"
 
3367
                                        " internal data dictionary entry\n"
 
3368
                                        "InnoDB: of table ");
 
3369
                                ut_print_name(stderr, trx, TRUE, name);
 
3370
                                fprintf(stderr, ".\n");
 
3371
                        } else if (!fil_delete_tablespace(space_id)) {
 
3372
                                fprintf(stderr,
 
3373
                                        "InnoDB: We removed now the InnoDB"
 
3374
                                        " internal data dictionary entry\n"
 
3375
                                        "InnoDB: of table ");
 
3376
                                ut_print_name(stderr, trx, TRUE, name);
 
3377
                                fprintf(stderr, ".\n");
 
3378
 
 
3379
                                ut_print_timestamp(stderr);
 
3380
                                fprintf(stderr,
 
3381
                                        "  InnoDB: Error: not able to"
 
3382
                                        " delete tablespace %lu of table ",
 
3383
                                        (ulong) space_id);
 
3384
                                ut_print_name(stderr, trx, TRUE, name);
 
3385
                                fputs("!\n", stderr);
 
3386
                                err = DB_ERROR;
 
3387
                        }
 
3388
                }
 
3389
 
 
3390
                mem_heap_free(heap);
 
3391
                break;
 
3392
 
 
3393
        case DB_TOO_MANY_CONCURRENT_TRXS:
 
3394
                /* Cannot even find a free slot for the
 
3395
                the undo log. We can directly exit here
 
3396
                and return the DB_TOO_MANY_CONCURRENT_TRXS
 
3397
                error. */
 
3398
                break;
 
3399
 
 
3400
        case DB_OUT_OF_FILE_SPACE:
 
3401
                err = DB_MUST_GET_MORE_FILE_SPACE;
 
3402
 
 
3403
                row_mysql_handle_errors(&err, trx, NULL, NULL);
 
3404
 
 
3405
                /* Fall through to raise error */
 
3406
 
 
3407
        default:
 
3408
                /* No other possible error returns */
 
3409
                ut_error;
 
3410
        }
 
3411
 
 
3412
funct_exit:
 
3413
 
 
3414
        if (locked_dictionary) {
 
3415
                trx_commit_for_mysql(trx);
 
3416
 
 
3417
                row_mysql_unlock_data_dictionary(trx);
 
3418
        }
 
3419
 
 
3420
        trx->op_info = "";
 
3421
 
 
3422
        srv_wake_master_thread();
 
3423
 
 
3424
        return((int) err);
 
3425
}
 
3426
 
 
3427
/*********************************************************************//**
 
3428
Drop all temporary tables during crash recovery. */
 
3429
UNIV_INTERN
 
3430
void
 
3431
row_mysql_drop_temp_tables(void)
 
3432
/*============================*/
 
3433
{
 
3434
        trx_t*          trx;
 
3435
        btr_pcur_t      pcur;
 
3436
        mtr_t           mtr;
 
3437
        mem_heap_t*     heap;
 
3438
 
 
3439
        trx = trx_allocate_for_background();
 
3440
        trx->op_info = "dropping temporary tables";
 
3441
        row_mysql_lock_data_dictionary(trx);
 
3442
 
 
3443
        heap = mem_heap_create(200);
 
3444
 
 
3445
        mtr_start(&mtr);
 
3446
 
 
3447
        btr_pcur_open_at_index_side(
 
3448
                TRUE,
 
3449
                dict_table_get_first_index(dict_sys->sys_tables),
 
3450
                BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
 
3451
 
 
3452
        for (;;) {
 
3453
                const rec_t*    rec;
 
3454
                const byte*     field;
 
3455
                ulint           len;
 
3456
                const char*     table_name;
 
3457
                dict_table_t*   table;
 
3458
 
 
3459
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
3460
 
 
3461
                if (!btr_pcur_is_on_user_rec(&pcur)) {
 
3462
                        break;
 
3463
                }
 
3464
 
 
3465
                rec = btr_pcur_get_rec(&pcur);
 
3466
                field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
 
3467
                if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
 
3468
                        continue;
 
3469
                }
 
3470
 
 
3471
                /* Because this is not a ROW_FORMAT=REDUNDANT table,
 
3472
                the is_temp flag is valid.  Examine it. */
 
3473
 
 
3474
                field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
 
3475
                if (len != 4
 
3476
                    || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
 
3477
                        continue;
 
3478
                }
 
3479
 
 
3480
                /* This is a temporary table. */
 
3481
                field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
 
3482
                if (len == UNIV_SQL_NULL || len == 0) {
 
3483
                        /* Corrupted SYS_TABLES.NAME */
 
3484
                        continue;
 
3485
                }
 
3486
 
 
3487
                table_name = mem_heap_strdupl(heap, (const char*) field, len);
 
3488
 
 
3489
                btr_pcur_store_position(&pcur, &mtr);
 
3490
                btr_pcur_commit_specify_mtr(&pcur, &mtr);
 
3491
 
 
3492
                table = dict_load_table(table_name, TRUE);
 
3493
 
 
3494
                if (table) {
 
3495
                        row_drop_table_for_mysql(table_name, trx, FALSE);
 
3496
                        trx_commit_for_mysql(trx);
 
3497
                }
 
3498
 
 
3499
                mtr_start(&mtr);
 
3500
                btr_pcur_restore_position(BTR_SEARCH_LEAF,
 
3501
                                          &pcur, &mtr);
 
3502
        }
 
3503
 
 
3504
        btr_pcur_close(&pcur);
 
3505
        mtr_commit(&mtr);
 
3506
        mem_heap_free(heap);
 
3507
        row_mysql_unlock_data_dictionary(trx);
 
3508
        trx_free_for_background(trx);
 
3509
}
 
3510
 
 
3511
/*******************************************************************//**
 
3512
Drop all foreign keys in a database, see Bug#18942.
 
3513
Called at the end of row_drop_database_for_mysql().
 
3514
@return error code or DB_SUCCESS */
 
3515
static
 
3516
ulint
 
3517
drop_all_foreign_keys_in_db(
 
3518
/*========================*/
 
3519
        const char*     name,   /*!< in: database name which ends to '/' */
 
3520
        trx_t*          trx)    /*!< in: transaction handle */
 
3521
{
 
3522
        pars_info_t*    pinfo;
 
3523
        ulint           err;
 
3524
 
 
3525
        ut_a(name[strlen(name) - 1] == '/');
 
3526
 
 
3527
        pinfo = pars_info_create();
 
3528
 
 
3529
        pars_info_add_str_literal(pinfo, "dbname", name);
 
3530
 
 
3531
/** true if for_name is not prefixed with dbname */
 
3532
#define TABLE_NOT_IN_THIS_DB \
 
3533
"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
 
3534
 
 
3535
        err = que_eval_sql(pinfo,
 
3536
                           "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
 
3537
                           "foreign_id CHAR;\n"
 
3538
                           "for_name CHAR;\n"
 
3539
                           "found INT;\n"
 
3540
                           "DECLARE CURSOR cur IS\n"
 
3541
                           "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
 
3542
                           "WHERE FOR_NAME >= :dbname\n"
 
3543
                           "LOCK IN SHARE MODE\n"
 
3544
                           "ORDER BY FOR_NAME;\n"
 
3545
                           "BEGIN\n"
 
3546
                           "found := 1;\n"
 
3547
                           "OPEN cur;\n"
 
3548
                           "WHILE found = 1 LOOP\n"
 
3549
                           "        FETCH cur INTO foreign_id, for_name;\n"
 
3550
                           "        IF (SQL % NOTFOUND) THEN\n"
 
3551
                           "                found := 0;\n"
 
3552
                           "        ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
 
3553
                           "                found := 0;\n"
 
3554
                           "        ELSIF (1=1) THEN\n"
 
3555
                           "                DELETE FROM SYS_FOREIGN_COLS\n"
 
3556
                           "                WHERE ID = foreign_id;\n"
 
3557
                           "                DELETE FROM SYS_FOREIGN\n"
 
3558
                           "                WHERE ID = foreign_id;\n"
 
3559
                           "        END IF;\n"
 
3560
                           "END LOOP;\n"
 
3561
                           "CLOSE cur;\n"
 
3562
                           "COMMIT WORK;\n"
 
3563
                           "END;\n",
 
3564
                           FALSE, /* do not reserve dict mutex,
 
3565
                                  we are already holding it */
 
3566
                           trx);
 
3567
 
 
3568
        return(err);
 
3569
}
 
3570
 
 
3571
/*********************************************************************//**
 
3572
Drops a database for MySQL.
 
3573
@return error code or DB_SUCCESS */
 
3574
UNIV_INTERN
 
3575
int
 
3576
row_drop_database_for_mysql(
 
3577
/*========================*/
 
3578
        const char*     name,   /*!< in: database name which ends to '/' */
 
3579
        trx_t*          trx)    /*!< in: transaction handle */
 
3580
{
 
3581
        dict_table_t* table;
 
3582
        char*   table_name;
 
3583
        int     err     = DB_SUCCESS;
 
3584
        ulint   namelen = strlen(name);
 
3585
 
 
3586
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
3587
        ut_a(name != NULL);
 
3588
        ut_a(name[namelen - 1] == '/');
 
3589
 
 
3590
        trx->op_info = "dropping database";
 
3591
 
 
3592
        trx_start_if_not_started(trx);
 
3593
loop:
 
3594
        row_mysql_lock_data_dictionary(trx);
 
3595
 
 
3596
        while ((table_name = dict_get_first_table_name_in_db(name))) {
 
3597
                ut_a(memcmp(table_name, name, namelen) == 0);
 
3598
 
 
3599
                // For the time being I would like to see how often we see
 
3600
                // lost temporary tables. --Brian
 
3601
                fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
 
3602
 
 
3603
                table = dict_table_get_low(table_name);
 
3604
 
 
3605
                ut_a(table);
 
3606
 
 
3607
                /* Wait until MySQL does not have any queries running on
 
3608
                the table */
 
3609
 
 
3610
                if (table->n_mysql_handles_opened > 0) {
 
3611
                        row_mysql_unlock_data_dictionary(trx);
 
3612
 
 
3613
                        ut_print_timestamp(stderr);
 
3614
                        fputs("  InnoDB: Warning: MySQL is trying to"
 
3615
                              " drop database ", stderr);
 
3616
                        ut_print_name(stderr, trx, TRUE, name);
 
3617
                        fputs("\n"
 
3618
                              "InnoDB: though there are still"
 
3619
                              " open handles to table ", stderr);
 
3620
                        ut_print_name(stderr, trx, TRUE, table_name);
 
3621
                        fputs(".\n", stderr);
 
3622
 
 
3623
                        os_thread_sleep(1000000);
 
3624
 
 
3625
                        mem_free(table_name);
 
3626
 
 
3627
                        goto loop;
 
3628
                }
 
3629
 
 
3630
                err = row_drop_table_for_mysql(table_name, trx, TRUE);
 
3631
                trx_commit_for_mysql(trx);
 
3632
 
 
3633
                if (err != DB_SUCCESS) {
 
3634
                        fputs("InnoDB: DROP DATABASE ", stderr);
 
3635
                        ut_print_name(stderr, trx, TRUE, name);
 
3636
                        fprintf(stderr, " failed with error %lu for table ",
 
3637
                                (ulint) err);
 
3638
                        ut_print_name(stderr, trx, TRUE, table_name);
 
3639
                        putc('\n', stderr);
 
3640
                        mem_free(table_name);
 
3641
                        break;
 
3642
                }
 
3643
 
 
3644
                mem_free(table_name);
 
3645
        }
 
3646
 
 
3647
        if (err == DB_SUCCESS) {
 
3648
                /* after dropping all tables try to drop all leftover
 
3649
                foreign keys in case orphaned ones exist */
 
3650
                err = (int) drop_all_foreign_keys_in_db(name, trx);
 
3651
 
 
3652
                if (err != DB_SUCCESS) {
 
3653
                        fputs("InnoDB: DROP DATABASE ", stderr);
 
3654
                        ut_print_name(stderr, trx, TRUE, name);
 
3655
                        fprintf(stderr, " failed with error %d while "
 
3656
                                "dropping all foreign keys", err);
 
3657
                }
 
3658
        }
 
3659
 
 
3660
        trx_commit_for_mysql(trx);
 
3661
 
 
3662
        row_mysql_unlock_data_dictionary(trx);
 
3663
 
 
3664
        trx->op_info = "";
 
3665
 
 
3666
        return(err);
 
3667
}
 
3668
 
 
3669
/*********************************************************************//**
 
3670
Checks if a table name contains the string "/#sql" which denotes temporary
 
3671
tables in MySQL.
 
3672
@return TRUE if temporary table */
 
3673
static
 
3674
ibool
 
3675
row_is_mysql_tmp_table_name(
 
3676
/*========================*/
 
3677
        const char*     name)   /*!< in: table name in the form
 
3678
                                'database/tablename' */
 
3679
{
 
3680
        return(strstr(name, "/#sql") != NULL);
 
3681
        /* return(strstr(name, "/@0023sql") != NULL); */
 
3682
}
 
3683
 
 
3684
/****************************************************************//**
 
3685
Delete a single constraint.
 
3686
@return error code or DB_SUCCESS */
 
3687
static
 
3688
int
 
3689
row_delete_constraint_low(
 
3690
/*======================*/
 
3691
        const char*     id,             /*!< in: constraint id */
 
3692
        trx_t*          trx)            /*!< in: transaction handle */
 
3693
{
 
3694
        pars_info_t*    info = pars_info_create();
 
3695
 
 
3696
        pars_info_add_str_literal(info, "id", id);
 
3697
 
 
3698
        return((int) que_eval_sql(info,
 
3699
                            "PROCEDURE DELETE_CONSTRAINT () IS\n"
 
3700
                            "BEGIN\n"
 
3701
                            "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
 
3702
                            "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
 
3703
                            "END;\n"
 
3704
                            , FALSE, trx));
 
3705
}
 
3706
 
 
3707
/****************************************************************//**
 
3708
Delete a single constraint.
 
3709
@return error code or DB_SUCCESS */
 
3710
static
 
3711
int
 
3712
row_delete_constraint(
 
3713
/*==================*/
 
3714
        const char*     id,             /*!< in: constraint id */
 
3715
        const char*     database_name,  /*!< in: database name, with the
 
3716
                                        trailing '/' */
 
3717
        mem_heap_t*     heap,           /*!< in: memory heap */
 
3718
        trx_t*          trx)            /*!< in: transaction handle */
 
3719
{
 
3720
        ulint           err;
 
3721
 
 
3722
        /* New format constraints have ids <databasename>/<constraintname>. */
 
3723
        err = row_delete_constraint_low(
 
3724
                mem_heap_strcat(heap, database_name, id), trx);
 
3725
 
 
3726
        if ((err == DB_SUCCESS) && !strchr(id, '/')) {
 
3727
                /* Old format < 4.0.18 constraints have constraint ids
 
3728
                <number>_<number>. We only try deleting them if the
 
3729
                constraint name does not contain a '/' character, otherwise
 
3730
                deleting a new format constraint named 'foo/bar' from
 
3731
                database 'baz' would remove constraint 'bar' from database
 
3732
                'foo', if it existed. */
 
3733
 
 
3734
                err = row_delete_constraint_low(id, trx);
 
3735
        }
 
3736
 
 
3737
        return((int) err);
 
3738
}
 
3739
 
 
3740
/*********************************************************************//**
 
3741
Renames a table for MySQL.
 
3742
@return error code or DB_SUCCESS */
 
3743
UNIV_INTERN
 
3744
ulint
 
3745
row_rename_table_for_mysql(
 
3746
/*=======================*/
 
3747
        const char*     old_name,       /*!< in: old table name */
 
3748
        const char*     new_name,       /*!< in: new table name */
 
3749
        trx_t*          trx,            /*!< in: transaction handle */
 
3750
        ibool           commit)         /*!< in: if TRUE then commit trx */
 
3751
{
 
3752
        dict_table_t*   table;
 
3753
        ulint           err                     = DB_ERROR;
 
3754
        mem_heap_t*     heap                    = NULL;
 
3755
        const char**    constraints_to_drop     = NULL;
 
3756
        ulint           n_constraints_to_drop   = 0;
 
3757
        ibool           old_is_tmp, new_is_tmp;
 
3758
        pars_info_t*    info                    = NULL;
 
3759
 
 
3760
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
3761
        ut_a(old_name != NULL);
 
3762
        ut_a(new_name != NULL);
 
3763
 
 
3764
        if (srv_created_new_raw || srv_force_recovery) {
 
3765
                fputs("InnoDB: A new raw disk partition was initialized or\n"
 
3766
                      "InnoDB: innodb_force_recovery is on: we do not allow\n"
 
3767
                      "InnoDB: database modifications by the user. Shut down\n"
 
3768
                      "InnoDB: mysqld and edit my.cnf so that newraw"
 
3769
                      " is replaced\n"
 
3770
                      "InnoDB: with raw, and innodb_force_... is removed.\n",
 
3771
                      stderr);
 
3772
 
 
3773
                goto funct_exit;
 
3774
        }
 
3775
 
 
3776
        trx->op_info = "renaming table";
 
3777
        trx_start_if_not_started(trx);
 
3778
 
 
3779
        old_is_tmp = row_is_mysql_tmp_table_name(old_name);
 
3780
        new_is_tmp = row_is_mysql_tmp_table_name(new_name);
 
3781
 
 
3782
        table = dict_table_get_low(old_name);
 
3783
 
 
3784
        if (!table) {
 
3785
#if defined(BUILD_DRIZZLE)
 
3786
                err = ENOENT;
 
3787
#else
 
3788
                err = DB_TABLE_NOT_FOUND;
 
3789
                ut_print_timestamp(stderr);
 
3790
 
 
3791
                fputs("  InnoDB: Error: table ", stderr);
 
3792
                ut_print_name(stderr, trx, TRUE, old_name);
 
3793
                fputs(" does not exist in the InnoDB internal\n"
 
3794
                      "InnoDB: data dictionary though MySQL is"
 
3795
                      " trying to rename the table.\n"
 
3796
                      "InnoDB: Have you copied the .frm file"
 
3797
                      " of the table to the\n"
 
3798
                      "InnoDB: MySQL database directory"
 
3799
                      " from another database?\n"
 
3800
                      "InnoDB: You can look for further help from\n"
 
3801
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
 
3802
                      stderr);
 
3803
#endif /* BUILD_DRIZZLE */
 
3804
                goto funct_exit;
 
3805
        } else if (table->ibd_file_missing) {
 
3806
                err = DB_TABLE_NOT_FOUND;
 
3807
                ut_print_timestamp(stderr);
 
3808
 
 
3809
                fputs("  InnoDB: Error: table ", stderr);
 
3810
                ut_print_name(stderr, trx, TRUE, old_name);
 
3811
                fputs(" does not have an .ibd file"
 
3812
                      " in the database directory.\n"
 
3813
                      "InnoDB: You can look for further help from\n"
 
3814
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
 
3815
                      stderr);
 
3816
                goto funct_exit;
 
3817
        } else if (new_is_tmp) {
 
3818
                /* MySQL is doing an ALTER TABLE command and it renames the
 
3819
                original table to a temporary table name. We want to preserve
 
3820
                the original foreign key constraint definitions despite the
 
3821
                name change. An exception is those constraints for which
 
3822
                the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
 
3823
 
 
3824
                heap = mem_heap_create(100);
 
3825
 
 
3826
                err = dict_foreign_parse_drop_constraints(
 
3827
                        heap, trx, table, &n_constraints_to_drop,
 
3828
                        &constraints_to_drop);
 
3829
 
 
3830
                if (err != DB_SUCCESS) {
 
3831
 
 
3832
                        goto funct_exit;
 
3833
                }
 
3834
        }
 
3835
 
 
3836
        /* We use the private SQL parser of Innobase to generate the query
 
3837
        graphs needed in updating the dictionary data from system tables. */
 
3838
 
 
3839
        info = pars_info_create();
 
3840
 
 
3841
        pars_info_add_str_literal(info, "new_table_name", new_name);
 
3842
        pars_info_add_str_literal(info, "old_table_name", old_name);
 
3843
 
 
3844
        err = que_eval_sql(info,
 
3845
                           "PROCEDURE RENAME_TABLE () IS\n"
 
3846
                           "BEGIN\n"
 
3847
                           "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
 
3848
                           " WHERE NAME = :old_table_name;\n"
 
3849
                           "END;\n"
 
3850
                           , FALSE, trx);
 
3851
 
 
3852
        if (err != DB_SUCCESS) {
 
3853
 
 
3854
                goto end;
 
3855
        } else if (!new_is_tmp) {
 
3856
                /* Rename all constraints. */
 
3857
 
 
3858
                info = pars_info_create();
 
3859
 
 
3860
                pars_info_add_str_literal(info, "new_table_name", new_name);
 
3861
                pars_info_add_str_literal(info, "old_table_name", old_name);
 
3862
 
 
3863
                err = que_eval_sql(
 
3864
                        info,
 
3865
                        "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
 
3866
                        "gen_constr_prefix CHAR;\n"
 
3867
                        "new_db_name CHAR;\n"
 
3868
                        "foreign_id CHAR;\n"
 
3869
                        "new_foreign_id CHAR;\n"
 
3870
                        "old_db_name_len INT;\n"
 
3871
                        "old_t_name_len INT;\n"
 
3872
                        "new_db_name_len INT;\n"
 
3873
                        "id_len INT;\n"
 
3874
                        "found INT;\n"
 
3875
                        "BEGIN\n"
 
3876
                        "found := 1;\n"
 
3877
                        "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
 
3878
                        "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
 
3879
                        "new_db_name := SUBSTR(:new_table_name, 0,\n"
 
3880
                        "                      new_db_name_len);\n"
 
3881
                        "old_t_name_len := LENGTH(:old_table_name);\n"
 
3882
                        "gen_constr_prefix := CONCAT(:old_table_name,\n"
 
3883
                        "                            '_ibfk_');\n"
 
3884
                        "WHILE found = 1 LOOP\n"
 
3885
                        "       SELECT ID INTO foreign_id\n"
 
3886
                        "        FROM SYS_FOREIGN\n"
 
3887
                        "        WHERE FOR_NAME = :old_table_name\n"
 
3888
                        "         AND TO_BINARY(FOR_NAME)\n"
 
3889
                        "           = TO_BINARY(:old_table_name)\n"
 
3890
                        "         LOCK IN SHARE MODE;\n"
 
3891
                        "       IF (SQL % NOTFOUND) THEN\n"
 
3892
                        "        found := 0;\n"
 
3893
                        "       ELSE\n"
 
3894
                        "        UPDATE SYS_FOREIGN\n"
 
3895
                        "        SET FOR_NAME = :new_table_name\n"
 
3896
                        "         WHERE ID = foreign_id;\n"
 
3897
                        "        id_len := LENGTH(foreign_id);\n"
 
3898
                        "        IF (INSTR(foreign_id, '/') > 0) THEN\n"
 
3899
                        "               IF (INSTR(foreign_id,\n"
 
3900
                        "                         gen_constr_prefix) > 0)\n"
 
3901
                        "               THEN\n"
 
3902
                        "                new_foreign_id :=\n"
 
3903
                        "                CONCAT(:new_table_name,\n"
 
3904
                        "                SUBSTR(foreign_id, old_t_name_len,\n"
 
3905
                        "                       id_len - old_t_name_len));\n"
 
3906
                        "               ELSE\n"
 
3907
                        "                new_foreign_id :=\n"
 
3908
                        "                CONCAT(new_db_name,\n"
 
3909
                        "                SUBSTR(foreign_id,\n"
 
3910
                        "                       old_db_name_len,\n"
 
3911
                        "                       id_len - old_db_name_len));\n"
 
3912
                        "               END IF;\n"
 
3913
                        "               UPDATE SYS_FOREIGN\n"
 
3914
                        "                SET ID = new_foreign_id\n"
 
3915
                        "                WHERE ID = foreign_id;\n"
 
3916
                        "               UPDATE SYS_FOREIGN_COLS\n"
 
3917
                        "                SET ID = new_foreign_id\n"
 
3918
                        "                WHERE ID = foreign_id;\n"
 
3919
                        "        END IF;\n"
 
3920
                        "       END IF;\n"
 
3921
                        "END LOOP;\n"
 
3922
                        "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
 
3923
                        "WHERE REF_NAME = :old_table_name\n"
 
3924
                        "  AND TO_BINARY(REF_NAME)\n"
 
3925
                        "    = TO_BINARY(:old_table_name);\n"
 
3926
                        "END;\n"
 
3927
                        , FALSE, trx);
 
3928
 
 
3929
        } else if (n_constraints_to_drop > 0) {
 
3930
                /* Drop some constraints of tmp tables. */
 
3931
 
 
3932
                ulint   db_name_len = dict_get_db_name_len(old_name) + 1;
 
3933
                char*   db_name = mem_heap_strdupl(heap, old_name,
 
3934
                                                   db_name_len);
 
3935
                ulint   i;
 
3936
 
 
3937
                for (i = 0; i < n_constraints_to_drop; i++) {
 
3938
                        err = row_delete_constraint(constraints_to_drop[i],
 
3939
                                                    db_name, heap, trx);
 
3940
 
 
3941
                        if (err != DB_SUCCESS) {
 
3942
                                break;
 
3943
                        }
 
3944
                }
 
3945
        }
 
3946
 
 
3947
end:
 
3948
        if (err != DB_SUCCESS) {
 
3949
                if (err == DB_DUPLICATE_KEY) {
 
3950
                        ut_print_timestamp(stderr);
 
3951
                        fputs("  InnoDB: Error; possible reasons:\n"
 
3952
                              "InnoDB: 1) Table rename would cause"
 
3953
                              " two FOREIGN KEY constraints\n"
 
3954
                              "InnoDB: to have the same internal name"
 
3955
                              " in case-insensitive comparison.\n"
 
3956
                              "InnoDB: 2) table ", stderr);
 
3957
                        ut_print_name(stderr, trx, TRUE, new_name);
 
3958
                        fputs(" exists in the InnoDB internal data\n"
 
3959
                              "InnoDB: dictionary though MySQL is"
 
3960
                              " trying to rename table ", stderr);
 
3961
                        ut_print_name(stderr, trx, TRUE, old_name);
 
3962
                        fputs(" to it.\n"
 
3963
                              "InnoDB: Have you deleted the .frm file"
 
3964
                              " and not used DROP TABLE?\n"
 
3965
                              "InnoDB: You can look for further help from\n"
 
3966
                              "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
 
3967
                              "InnoDB: If table ", stderr);
 
3968
                        ut_print_name(stderr, trx, TRUE, new_name);
 
3969
                        fputs(" is a temporary table #sql..., then"
 
3970
                              " it can be that\n"
 
3971
                              "InnoDB: there are still queries running"
 
3972
                              " on the table, and it will be\n"
 
3973
                              "InnoDB: dropped automatically when"
 
3974
                              " the queries end.\n"
 
3975
                              "InnoDB: You can drop the orphaned table"
 
3976
                              " inside InnoDB by\n"
 
3977
                              "InnoDB: creating an InnoDB table with"
 
3978
                              " the same name in another\n"
 
3979
                              "InnoDB: database and copying the .frm file"
 
3980
                              " to the current database.\n"
 
3981
                              "InnoDB: Then MySQL thinks the table exists,"
 
3982
                              " and DROP TABLE will\n"
 
3983
                              "InnoDB: succeed.\n", stderr);
 
3984
                }
 
3985
                trx->error_state = DB_SUCCESS;
 
3986
                trx_general_rollback_for_mysql(trx, NULL);
 
3987
                trx->error_state = DB_SUCCESS;
 
3988
        } else {
 
3989
                /* The following call will also rename the .ibd data file if
 
3990
                the table is stored in a single-table tablespace */
 
3991
 
 
3992
                if (!dict_table_rename_in_cache(table, new_name,
 
3993
                                                !new_is_tmp)) {
 
3994
                        trx->error_state = DB_SUCCESS;
 
3995
                        trx_general_rollback_for_mysql(trx, NULL);
 
3996
                        trx->error_state = DB_SUCCESS;
 
3997
                        goto funct_exit;
 
3998
                }
 
3999
 
 
4000
                /* We only want to switch off some of the type checking in
 
4001
                an ALTER, not in a RENAME. */
 
4002
 
 
4003
                err = dict_load_foreigns(
 
4004
                        new_name, FALSE, !old_is_tmp || trx->check_foreigns);
 
4005
 
 
4006
                if (err != DB_SUCCESS) {
 
4007
                        ut_print_timestamp(stderr);
 
4008
 
 
4009
                        if (old_is_tmp) {
 
4010
                                fputs("  InnoDB: Error: in ALTER TABLE ",
 
4011
                                      stderr);
 
4012
                                ut_print_name(stderr, trx, TRUE, new_name);
 
4013
                                fputs("\n"
 
4014
                                      "InnoDB: has or is referenced"
 
4015
                                      " in foreign key constraints\n"
 
4016
                                      "InnoDB: which are not compatible"
 
4017
                                      " with the new table definition.\n",
 
4018
                                      stderr);
 
4019
                        } else {
 
4020
                                fputs("  InnoDB: Error: in RENAME TABLE"
 
4021
                                      " table ",
 
4022
                                      stderr);
 
4023
                                ut_print_name(stderr, trx, TRUE, new_name);
 
4024
                                fputs("\n"
 
4025
                                      "InnoDB: is referenced in"
 
4026
                                      " foreign key constraints\n"
 
4027
                                      "InnoDB: which are not compatible"
 
4028
                                      " with the new table definition.\n",
 
4029
                                      stderr);
 
4030
                        }
 
4031
 
 
4032
                        ut_a(dict_table_rename_in_cache(table,
 
4033
                                                        old_name, FALSE));
 
4034
                        trx->error_state = DB_SUCCESS;
 
4035
                        trx_general_rollback_for_mysql(trx, NULL);
 
4036
                        trx->error_state = DB_SUCCESS;
 
4037
                }
 
4038
        }
 
4039
 
 
4040
funct_exit:
 
4041
 
 
4042
        if (commit) {
 
4043
                trx_commit_for_mysql(trx);
 
4044
        }
 
4045
 
 
4046
        if (UNIV_LIKELY_NULL(heap)) {
 
4047
                mem_heap_free(heap);
 
4048
        }
 
4049
 
 
4050
        trx->op_info = "";
 
4051
 
 
4052
        return(err);
 
4053
}
 
4054
 
 
4055
/*********************************************************************//**
 
4056
Checks that the index contains entries in an ascending order, unique
 
4057
constraint is not broken, and calculates the number of index entries
 
4058
in the read view of the current transaction.
 
4059
@return TRUE if ok */
 
4060
UNIV_INTERN
 
4061
ibool
 
4062
row_check_index_for_mysql(
 
4063
/*======================*/
 
4064
        row_prebuilt_t*         prebuilt,       /*!< in: prebuilt struct
 
4065
                                                in MySQL handle */
 
4066
        const dict_index_t*     index,          /*!< in: index */
 
4067
        ulint*                  n_rows)         /*!< out: number of entries
 
4068
                                                seen in the consistent read */
 
4069
{
 
4070
        dtuple_t*       prev_entry      = NULL;
 
4071
        ulint           matched_fields;
 
4072
        ulint           matched_bytes;
 
4073
        byte*           buf;
 
4074
        ulint           ret;
 
4075
        rec_t*          rec;
 
4076
        ibool           is_ok           = TRUE;
 
4077
        int             cmp;
 
4078
        ibool           contains_null;
 
4079
        ulint           i;
 
4080
        ulint           cnt;
 
4081
        mem_heap_t*     heap            = NULL;
 
4082
        ulint           n_ext;
 
4083
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
4084
        ulint*          offsets;
 
4085
        rec_offs_init(offsets_);
 
4086
 
 
4087
        *n_rows = 0;
 
4088
 
 
4089
        buf = mem_alloc(UNIV_PAGE_SIZE);
 
4090
        heap = mem_heap_create(100);
 
4091
 
 
4092
        cnt = 1000;
 
4093
 
 
4094
        ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
 
4095
loop:
 
4096
        /* Check thd->killed every 1,000 scanned rows */
 
4097
        if (--cnt == 0) {
 
4098
                if (trx_is_interrupted(prebuilt->trx)) {
 
4099
                        goto func_exit;
 
4100
                }
 
4101
                cnt = 1000;
 
4102
        }
 
4103
 
 
4104
        switch (ret) {
 
4105
        case DB_SUCCESS:
 
4106
                break;
 
4107
        default:
 
4108
                ut_print_timestamp(stderr);
 
4109
                fputs("  InnoDB: Warning: CHECK TABLE on ", stderr);
 
4110
                dict_index_name_print(stderr, prebuilt->trx, index);
 
4111
                fprintf(stderr, " returned %lu\n", ret);
 
4112
                /* fall through (this error is ignored by CHECK TABLE) */
 
4113
        case DB_END_OF_INDEX:
 
4114
func_exit:
 
4115
                mem_free(buf);
 
4116
                mem_heap_free(heap);
 
4117
 
 
4118
                return(is_ok);
 
4119
        }
 
4120
 
 
4121
        *n_rows = *n_rows + 1;
 
4122
 
 
4123
        /* row_search... returns the index record in buf, record origin offset
 
4124
        within buf stored in the first 4 bytes, because we have built a dummy
 
4125
        template */
 
4126
 
 
4127
        rec = buf + mach_read_from_4(buf);
 
4128
 
 
4129
        offsets = rec_get_offsets(rec, index, offsets_,
 
4130
                                  ULINT_UNDEFINED, &heap);
 
4131
 
 
4132
        if (prev_entry != NULL) {
 
4133
                matched_fields = 0;
 
4134
                matched_bytes = 0;
 
4135
 
 
4136
                cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
 
4137
                                                &matched_fields,
 
4138
                                                &matched_bytes);
 
4139
                contains_null = FALSE;
 
4140
 
 
4141
                /* In a unique secondary index we allow equal key values if
 
4142
                they contain SQL NULLs */
 
4143
 
 
4144
                for (i = 0;
 
4145
                     i < dict_index_get_n_ordering_defined_by_user(index);
 
4146
                     i++) {
 
4147
                        if (UNIV_SQL_NULL == dfield_get_len(
 
4148
                                    dtuple_get_nth_field(prev_entry, i))) {
 
4149
 
 
4150
                                contains_null = TRUE;
 
4151
                        }
 
4152
                }
 
4153
 
 
4154
                if (cmp > 0) {
 
4155
                        fputs("InnoDB: index records in a wrong order in ",
 
4156
                              stderr);
 
4157
not_ok:
 
4158
                        dict_index_name_print(stderr,
 
4159
                                              prebuilt->trx, index);
 
4160
                        fputs("\n"
 
4161
                              "InnoDB: prev record ", stderr);
 
4162
                        dtuple_print(stderr, prev_entry);
 
4163
                        fputs("\n"
 
4164
                              "InnoDB: record ", stderr);
 
4165
                        rec_print_new(stderr, rec, offsets);
 
4166
                        putc('\n', stderr);
 
4167
                        is_ok = FALSE;
 
4168
                } else if (dict_index_is_unique(index)
 
4169
                           && !contains_null
 
4170
                           && matched_fields
 
4171
                           >= dict_index_get_n_ordering_defined_by_user(
 
4172
                                   index)) {
 
4173
 
 
4174
                        fputs("InnoDB: duplicate key in ", stderr);
 
4175
                        goto not_ok;
 
4176
                }
 
4177
        }
 
4178
 
 
4179
        {
 
4180
                mem_heap_t*     tmp_heap = NULL;
 
4181
 
 
4182
                /* Empty the heap on each round.  But preserve offsets[]
 
4183
                for the row_rec_to_index_entry() call, by copying them
 
4184
                into a separate memory heap when needed. */
 
4185
                if (UNIV_UNLIKELY(offsets != offsets_)) {
 
4186
                        ulint   size = rec_offs_get_n_alloc(offsets)
 
4187
                                * sizeof *offsets;
 
4188
 
 
4189
                        tmp_heap = mem_heap_create(size);
 
4190
                        offsets = mem_heap_dup(tmp_heap, offsets, size);
 
4191
                }
 
4192
 
 
4193
                mem_heap_empty(heap);
 
4194
 
 
4195
                prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
 
4196
                                                    index, offsets,
 
4197
                                                    &n_ext, heap);
 
4198
 
 
4199
                if (UNIV_LIKELY_NULL(tmp_heap)) {
 
4200
                        mem_heap_free(tmp_heap);
 
4201
                }
 
4202
        }
 
4203
 
 
4204
        ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
 
4205
 
 
4206
        goto loop;
 
4207
}
 
4208
 
 
4209
/*********************************************************************//**
 
4210
Determines if a table is a magic monitor table.
 
4211
@return TRUE if monitor table */
 
4212
UNIV_INTERN
 
4213
ibool
 
4214
row_is_magic_monitor_table(
 
4215
/*=======================*/
 
4216
        const char*     table_name)     /*!< in: name of the table, in the
 
4217
                                        form database/table_name */
 
4218
{
 
4219
        const char*     name; /* table_name without database/ */
 
4220
        ulint           len;
 
4221
 
 
4222
        name = strchr(table_name, '/');
 
4223
        ut_a(name != NULL);
 
4224
        name++;
 
4225
        len = strlen(name) + 1;
 
4226
 
 
4227
        if (STR_EQ(name, len, S_innodb_monitor)
 
4228
            || STR_EQ(name, len, S_innodb_lock_monitor)
 
4229
            || STR_EQ(name, len, S_innodb_tablespace_monitor)
 
4230
            || STR_EQ(name, len, S_innodb_table_monitor)
 
4231
            || STR_EQ(name, len, S_innodb_mem_validate)) {
 
4232
 
 
4233
                return(TRUE);
 
4234
        }
 
4235
 
 
4236
        return(FALSE);
 
4237
}