~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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