~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Renamed more stuff to drizzle.

Show diffs side-by-side

added added

removed removed

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