~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/innodb_plugin/row/row0mysql.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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