~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2009-08-29 19:30:29 UTC
  • mto: (1126.5.1 captain-20090914-03)
  • mto: This revision was merged to the branch mainline in revision 1129.
  • Revision ID: mordred@inaugust.com-20090829193029-i12fw4pg91dm8nu9
Fixed a buffer overrun that was causing some translated message output to suck.

Honestly guys, declaring a char[80] and then doing an sprintf into it with
no length checking? sigh

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
 
}