~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Tags: innodb-plugin-1.0.1
Imported 1.0.1 with clean - with no changes.

Show diffs side-by-side

added added

removed removed

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