~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Rename of handler to Cursor.  You would not believe how long I have wanted
to do that.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (C) 2000, 2010, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 2000, 2009, Innobase Oy. All Rights Reserved.
4
4
 
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
11
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
12
 
13
13
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
 
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
15
Place, Suite 330, Boston, MA 02111-1307 USA
16
16
 
17
17
*****************************************************************************/
18
18
 
52
52
#include "fil0fil.h"
53
53
#include "ibuf0ibuf.h"
54
54
 
55
 
#include <errno.h>
56
 
 
57
55
/** Provide optional 4.x backwards compatibility for 5.0 and above */
58
56
UNIV_INTERN ibool       row_rollback_on_timeout = FALSE;
59
57
 
95
93
        ((str1_len) == sizeof(str2_onstack) \
96
94
         && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
97
95
 
 
96
/*******************************************************************//**
 
97
Determine if the given name is a name reserved for MySQL system tables.
 
98
@return TRUE if name is a MySQL system table name */
 
99
static
 
100
ibool
 
101
row_mysql_is_system_table(
 
102
/*======================*/
 
103
        const char*     name)
 
104
{
 
105
        if (strncmp(name, "mysql/", 6) != 0) {
 
106
 
 
107
                return(FALSE);
 
108
        }
 
109
 
 
110
        return(0 == strcmp(name + 6, "host")
 
111
               || 0 == strcmp(name + 6, "user")
 
112
               || 0 == strcmp(name + 6, "db"));
 
113
}
 
114
 
98
115
/*********************************************************************//**
99
116
If a table is not yet in the drop list, adds the table to the list of tables
100
117
which the master thread drops in background. We need this on Unix because in
249
266
}
250
267
 
251
268
/**************************************************************//**
252
 
Pad a column with spaces. */
253
 
UNIV_INTERN
254
 
void
255
 
row_mysql_pad_col(
256
 
/*==============*/
257
 
        ulint   mbminlen,       /*!< in: minimum size of a character,
258
 
                                in bytes */
259
 
        byte*   pad,            /*!< out: padded buffer */
260
 
        ulint   len)            /*!< in: number of bytes to pad */
261
 
{
262
 
        const byte*     pad_end;
263
 
 
264
 
        switch (UNIV_EXPECT(mbminlen, 1)) {
265
 
        default:
266
 
                ut_error;
267
 
        case 1:
268
 
                /* space=0x20 */
269
 
                memset(pad, 0x20, len);
270
 
                break;
271
 
        case 2:
272
 
                /* space=0x0020 */
273
 
                pad_end = pad + len;
274
 
                ut_a(!(len % 2));
275
 
                do {
276
 
                        *pad++ = 0x00;
277
 
                        *pad++ = 0x20;
278
 
                } while (pad < pad_end);
279
 
                break;
280
 
        case 4:
281
 
                /* space=0x00000020 */
282
 
                pad_end = pad + len;
283
 
                ut_a(!(len % 4));
284
 
                do {
285
 
                        *pad++ = 0x00;
286
 
                        *pad++ = 0x00;
287
 
                        *pad++ = 0x00;
288
 
                        *pad++ = 0x20;
289
 
                } while (pad < pad_end);
290
 
                break;
291
 
        }
292
 
}
293
 
 
294
 
/**************************************************************//**
295
269
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
296
270
The counterpart of this function is row_sel_field_store_in_mysql_format() in
297
271
row0sel.c.
383
357
                        /* Remove trailing spaces from old style VARCHAR
384
358
                        columns. */
385
359
 
386
 
                        /* Handle Unicode strings differently. */
 
360
                        /* Handle UCS2 strings differently. */
387
361
                        ulint   mbminlen        = dtype_get_mbminlen(dtype);
388
362
 
389
363
                        ptr = mysql_data;
390
364
 
391
 
                        switch (mbminlen) {
392
 
                        default:
393
 
                                ut_error;
394
 
                        case 4:
395
 
                                /* space=0x00000020 */
396
 
                                /* Trim "half-chars", just in case. */
397
 
                                col_len &= ~3;
398
 
 
399
 
                                while (col_len >= 4
400
 
                                       && ptr[col_len - 4] == 0x00
401
 
                                       && ptr[col_len - 3] == 0x00
402
 
                                       && ptr[col_len - 2] == 0x00
403
 
                                       && ptr[col_len - 1] == 0x20) {
404
 
                                        col_len -= 4;
405
 
                                }
406
 
                                break;
407
 
                        case 2:
 
365
                        if (mbminlen == 2) {
408
366
                                /* space=0x0020 */
409
367
                                /* Trim "half-chars", just in case. */
410
368
                                col_len &= ~1;
413
371
                                       && ptr[col_len - 1] == 0x20) {
414
372
                                        col_len -= 2;
415
373
                                }
416
 
                                break;
417
 
                        case 1:
 
374
                        } else {
 
375
                                ut_a(mbminlen == 1);
418
376
                                /* space=0x20 */
419
377
                                while (col_len > 0
420
378
                                       && ptr[col_len - 1] == 0x20) {
486
444
                                        row is used, as row may contain
487
445
                                        pointers to this record! */
488
446
{
489
 
        const mysql_row_templ_t*templ;
 
447
        mysql_row_templ_t*      templ;
490
448
        dfield_t*               dfield;
491
449
        ulint                   i;
492
450
 
527
485
/****************************************************************//**
528
486
Handles user errors and lock waits detected by the database engine.
529
487
@return TRUE if it was a lock wait and we should continue running the
530
 
query thread and in that case the thr is ALREADY in the running state. */
 
488
query thread */
531
489
UNIV_INTERN
532
490
ibool
533
491
row_mysql_handle_errors(
552
510
        switch (err) {
553
511
        case DB_LOCK_WAIT_TIMEOUT:
554
512
                if (row_rollback_on_timeout) {
555
 
                        trx_general_rollback_for_mysql(trx, NULL);
 
513
                        trx_general_rollback_for_mysql(trx, FALSE, NULL);
556
514
                        break;
557
515
                }
558
516
                /* fall through */
564
522
        case DB_CANNOT_ADD_CONSTRAINT:
565
523
        case DB_TOO_MANY_CONCURRENT_TRXS:
566
524
        case DB_OUT_OF_FILE_SPACE:
567
 
        case DB_INTERRUPTED:
568
525
                if (savept) {
569
526
                        /* Roll back the latest, possibly incomplete
570
527
                        insertion or update */
571
528
 
572
 
                        trx_general_rollback_for_mysql(trx, savept);
 
529
                        trx_general_rollback_for_mysql(trx, TRUE, savept);
573
530
                }
574
531
                /* MySQL will roll back the latest SQL statement */
575
532
                break;
591
548
                /* Roll back the whole transaction; this resolution was added
592
549
                to version 3.23.43 */
593
550
 
594
 
                trx_general_rollback_for_mysql(trx, NULL);
 
551
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
595
552
                break;
596
553
 
597
554
        case DB_MUST_GET_MORE_FILE_SPACE:
618
575
                      "InnoDB: " REFMAN "forcing-recovery.html"
619
576
                      " for help.\n", stderr);
620
577
                break;
621
 
        case DB_FOREIGN_EXCEED_MAX_CASCADE:
622
 
                fprintf(stderr, "InnoDB: Cannot delete/update rows with"
623
 
                        " cascading foreign key constraints that exceed max"
624
 
                        " depth of %lu\n"
625
 
                        "Please drop excessive foreign constraints"
626
 
                        " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
627
 
                break;
628
578
        default:
629
579
                fprintf(stderr, "InnoDB: unknown error code %lu\n",
630
580
                        (ulong) err);
659
609
 
660
610
        heap = mem_heap_create(sizeof *prebuilt + 128);
661
611
 
662
 
        prebuilt = static_cast<row_prebuilt_t *>(mem_heap_zalloc(heap, sizeof *prebuilt));
 
612
        prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt);
663
613
 
664
614
        prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
665
615
        prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
674
624
 
675
625
        prebuilt->select_lock_type = LOCK_NONE;
676
626
        prebuilt->stored_select_lock_type = 99999999;
677
 
        UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
678
 
                         sizeof prebuilt->stored_select_lock_type);
679
627
 
680
628
        prebuilt->search_tuple = dtuple_create(
681
629
                heap, 2 * dict_table_get_n_cols(table));
840
788
        }
841
789
}
842
790
 
843
 
dtuple_t* row_get_prebuilt_insert_row(row_prebuilt_t*   prebuilt);
844
 
 
845
791
/*********************************************************************//**
846
792
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
847
793
has not yet been built in the prebuilt struct, then this function first
848
794
builds it.
849
795
@return prebuilt dtuple; the column type information is also set in it */
 
796
static
850
797
dtuple_t*
851
798
row_get_prebuilt_insert_row(
852
799
/*========================*/
869
816
                prebuilt->ins_node = node;
870
817
 
871
818
                if (prebuilt->ins_upd_rec_buff == NULL) {
872
 
                        prebuilt->ins_upd_rec_buff = static_cast<byte *>(mem_heap_alloc(
873
 
                                prebuilt->heap, prebuilt->mysql_row_len));
 
819
                        prebuilt->ins_upd_rec_buff = mem_heap_alloc(
 
820
                                prebuilt->heap, prebuilt->mysql_row_len);
874
821
                }
875
822
 
876
823
                row = dtuple_create(prebuilt->heap,
880
827
 
881
828
                ins_node_set_new_row(node, row);
882
829
 
883
 
                prebuilt->ins_graph = static_cast<que_fork_t *>(que_node_get_parent(
 
830
                prebuilt->ins_graph = que_node_get_parent(
884
831
                        pars_complete_graph_for_exec(node,
885
832
                                                     prebuilt->trx,
886
 
                                                     prebuilt->heap)));
 
833
                                                     prebuilt->heap));
887
834
                prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
888
835
        }
889
836
 
914
861
        if (counter > 2000000000
915
862
            || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
916
863
 
917
 
                dict_update_statistics(table, FALSE /* update even if stats
918
 
                                                    are initialized */);
 
864
                dict_update_statistics(table);
919
865
        }
920
866
}
921
867
 
922
868
/*********************************************************************//**
923
 
Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
924
 
function should be called at the the end of an SQL statement, by the
925
 
connection thread that owns the transaction (trx->mysql_thd). */
 
869
Unlocks AUTO_INC type locks that were possibly reserved by a trx. */
926
870
UNIV_INTERN
927
871
void
928
872
row_unlock_table_autoinc_for_mysql(
929
873
/*===============================*/
930
874
        trx_t*  trx)    /*!< in/out: transaction */
931
875
{
932
 
        if (lock_trx_holds_autoinc_locks(trx)) {
933
 
                mutex_enter(&kernel_mutex);
934
 
 
935
 
                lock_release_autoinc_locks(trx);
936
 
 
937
 
                mutex_exit(&kernel_mutex);
938
 
        }
 
876
        mutex_enter(&kernel_mutex);
 
877
 
 
878
        lock_release_autoinc_locks(trx);
 
879
 
 
880
        mutex_exit(&kernel_mutex);
939
881
}
940
882
 
941
883
/*********************************************************************//**
1066
1008
        trx_start_if_not_started(trx);
1067
1009
 
1068
1010
        if (table) {
1069
 
                err = lock_table(0, table, static_cast<lock_mode>(mode), thr);
 
1011
                err = lock_table(0, table, mode, thr);
1070
1012
        } else {
1071
1013
                err = lock_table(0, prebuilt->table,
1072
 
                                 static_cast<lock_mode>(prebuilt->select_lock_type), thr);
 
1014
                                 prebuilt->select_lock_type, thr);
1073
1015
        }
1074
1016
 
1075
1017
        trx->error_state = err;
1244
1186
 
1245
1187
                node = sel_node_create(prebuilt->heap);
1246
1188
 
1247
 
                prebuilt->sel_graph = static_cast<que_fork_t *>(que_node_get_parent(
 
1189
                prebuilt->sel_graph = que_node_get_parent(
1248
1190
                        pars_complete_graph_for_exec(node,
1249
1191
                                                     prebuilt->trx,
1250
 
                                                     prebuilt->heap)));
 
1192
                                                     prebuilt->heap));
1251
1193
 
1252
1194
                prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1253
1195
        }
1315
1257
 
1316
1258
                prebuilt->upd_node = node;
1317
1259
 
1318
 
                prebuilt->upd_graph = static_cast<que_fork_t *>(que_node_get_parent(
 
1260
                prebuilt->upd_graph = que_node_get_parent(
1319
1261
                        pars_complete_graph_for_exec(node,
1320
1262
                                                     prebuilt->trx,
1321
 
                                                     prebuilt->heap)));
 
1263
                                                     prebuilt->heap));
1322
1264
                prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1323
1265
        }
1324
1266
 
1432
1374
run_again:
1433
1375
        thr->run_node = node;
1434
1376
        thr->prev_node = node;
1435
 
        thr->fk_cascade_depth = 0;
1436
1377
 
1437
1378
        row_upd_step(thr);
1438
1379
 
1439
 
        /* The recursive call for cascading update/delete happens
1440
 
        in above row_upd_step(), reset the counter once we come
1441
 
        out of the recursive call, so it does not accumulate for
1442
 
        different row deletes */
1443
 
        thr->fk_cascade_depth = 0;
1444
 
 
1445
1380
        err = trx->error_state;
1446
1381
 
1447
 
        /* Reset fk_cascade_depth back to 0 */
1448
 
        thr->fk_cascade_depth = 0;
1449
 
 
1450
1382
        if (err != DB_SUCCESS) {
1451
1383
                que_thr_stop_for_mysql(thr);
1452
1384
 
1483
1415
                srv_n_rows_updated++;
1484
1416
        }
1485
1417
 
1486
 
        /* We update table statistics only if it is a DELETE or UPDATE
1487
 
        that changes indexed columns, UPDATEs that change only non-indexed
1488
 
        columns would not affect statistics. */
1489
 
        if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1490
 
                row_update_statistics_if_needed(prebuilt->table);
1491
 
        }
 
1418
        row_update_statistics_if_needed(prebuilt->table);
1492
1419
 
1493
1420
        trx->op_info = "";
1494
1421
 
1496
1423
}
1497
1424
 
1498
1425
/*********************************************************************//**
1499
 
This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
1500
 
session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
1501
 
Before calling this function row_search_for_mysql() must have
1502
 
initialized prebuilt->new_rec_locks to store the information which new
1503
 
record locks really were set. This function removes a newly set
1504
 
clustered index record lock under prebuilt->pcur or
1505
 
prebuilt->clust_pcur.  Thus, this implements a 'mini-rollback' that
1506
 
releases the latest clustered index record lock we set.
1507
 
@return error code or DB_SUCCESS */
 
1426
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
 
1427
this session is using a READ COMMITTED isolation level. Before
 
1428
calling this function we must use trx_reset_new_rec_lock_info() and
 
1429
trx_register_new_rec_lock() to store the information which new record locks
 
1430
really were set. This function removes a newly set lock under prebuilt->pcur,
 
1431
and also under prebuilt->clust_pcur. Currently, this is only used and tested
 
1432
in the case of an UPDATE or a DELETE statement, where the row lock is of the
 
1433
LOCK_X type.
 
1434
Thus, this implements a 'mini-rollback' that releases the latest record
 
1435
locks we set.
 
1436
@return error code or DB_SUCCESS */
1508
1437
UNIV_INTERN
1509
1438
int
1510
1439
row_unlock_for_mysql(
1511
1440
/*=================*/
1512
 
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct in MySQL
 
1441
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct in MySQL
1513
1442
                                        handle */
1514
 
        ibool           has_latches_on_recs)/*!< in: TRUE if called so
1515
 
                                        that we have the latches on
1516
 
                                        the records under pcur and
1517
 
                                        clust_pcur, and we do not need
1518
 
                                        to reposition the cursors. */
 
1443
        ibool           has_latches_on_recs)/*!< TRUE if called so that we have
 
1444
                                        the latches on the records under pcur
 
1445
                                        and clust_pcur, and we do not need to
 
1446
                                        reposition the cursors. */
1519
1447
{
1520
1448
        btr_pcur_t*     pcur            = prebuilt->pcur;
1521
1449
        btr_pcur_t*     clust_pcur      = prebuilt->clust_pcur;
1526
1454
 
1527
1455
        if (UNIV_UNLIKELY
1528
1456
            (!srv_locks_unsafe_for_binlog
1529
 
             && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
 
1457
             && trx->isolation_level != TRX_ISO_READ_COMMITTED)) {
1530
1458
 
1531
1459
                fprintf(stderr,
1532
1460
                        "InnoDB: Error: calling row_unlock_for_mysql though\n"
1598
1526
                        }
1599
1527
                }
1600
1528
 
1601
 
                if (rec_trx_id != trx->id) {
 
1529
                if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) {
1602
1530
                        /* We did not update the record: unlock it */
1603
1531
 
1604
1532
                        rec = btr_pcur_get_rec(pcur);
1605
1533
                        index = btr_pcur_get_btr_cur(pcur)->index;
1606
1534
 
1607
1535
                        lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1608
 
                                        rec, static_cast<lock_mode>(prebuilt->select_lock_type));
 
1536
                                        rec, prebuilt->select_lock_type);
1609
1537
 
1610
1538
                        if (prebuilt->new_rec_locks >= 2) {
1611
1539
                                rec = btr_pcur_get_rec(clust_pcur);
1614
1542
                                lock_rec_unlock(trx,
1615
1543
                                                btr_pcur_get_block(clust_pcur),
1616
1544
                                                rec,
1617
 
                                                static_cast<lock_mode>(prebuilt->select_lock_type));
 
1545
                                                prebuilt->select_lock_type);
1618
1546
                        }
1619
1547
                }
1620
1548
no_unlock:
1642
1570
        trx_t*  trx;
1643
1571
 
1644
1572
        trx = thr_get_trx(thr);
1645
 
 
1646
 
        /* Increment fk_cascade_depth to record the recursive call depth on
1647
 
        a single update/delete that affects multiple tables chained
1648
 
        together with foreign key relations. */
1649
 
        thr->fk_cascade_depth++;
1650
 
 
1651
 
        if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1652
 
                return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1653
 
        }
1654
1573
run_again:
1655
1574
        thr->run_node = node;
1656
1575
        thr->prev_node = node;
1657
1576
 
1658
1577
        row_upd_step(thr);
1659
1578
 
1660
 
        /* The recursive call for cascading update/delete happens
1661
 
        in above row_upd_step(), reset the counter once we come
1662
 
        out of the recursive call, so it does not accumulate for
1663
 
        different row deletes */
1664
 
        thr->fk_cascade_depth = 0;
1665
 
 
1666
1579
        err = trx->error_state;
1667
1580
 
1668
1581
        /* Note that the cascade node is a subnode of another InnoDB
1728
1641
}
1729
1642
 
1730
1643
/*********************************************************************//**
 
1644
Calculates the key number used inside MySQL for an Innobase index. We have
 
1645
to take into account if we generated a default clustered index for the table
 
1646
@return the key number used inside MySQL */
 
1647
UNIV_INTERN
 
1648
ulint
 
1649
row_get_mysql_key_number_for_index(
 
1650
/*===============================*/
 
1651
        const dict_index_t*     index)  /*!< in: index */
 
1652
{
 
1653
        const dict_index_t*     ind;
 
1654
        ulint                   i;
 
1655
 
 
1656
        ut_a(index);
 
1657
 
 
1658
        i = 0;
 
1659
        ind = dict_table_get_first_index(index->table);
 
1660
 
 
1661
        while (index != ind) {
 
1662
                ind = dict_table_get_next_index(ind);
 
1663
                i++;
 
1664
        }
 
1665
 
 
1666
        if (row_table_got_default_clust_index(index->table)) {
 
1667
                ut_a(i > 0);
 
1668
                i--;
 
1669
        }
 
1670
 
 
1671
        return(i);
 
1672
}
 
1673
 
 
1674
/*********************************************************************//**
1731
1675
Locks the data dictionary in shared mode from modifications, for performing
1732
1676
foreign key check, rollback, or other operation invisible to MySQL. */
1733
1677
UNIV_INTERN
1823
1767
        const char*     table_name;
1824
1768
        ulint           table_name_len;
1825
1769
        ulint           err;
 
1770
        ulint           i;
1826
1771
 
1827
1772
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1828
1773
#ifdef UNIV_SYNC_DEBUG
1837
1782
                      " by the user.\n"
1838
1783
                      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1839
1784
                      " is replaced with raw.\n", stderr);
 
1785
err_exit:
1840
1786
                dict_mem_table_free(table);
1841
1787
                trx_commit_for_mysql(trx);
1842
1788
 
1845
1791
 
1846
1792
        trx->op_info = "creating table";
1847
1793
 
 
1794
        if (row_mysql_is_system_table(table->name)) {
 
1795
 
 
1796
                fprintf(stderr,
 
1797
                        "InnoDB: Error: trying to create a MySQL system"
 
1798
                        " table %s of type InnoDB.\n"
 
1799
                        "InnoDB: MySQL system tables must be"
 
1800
                        " of the MyISAM type!\n",
 
1801
                        table->name);
 
1802
                goto err_exit;
 
1803
        }
 
1804
 
 
1805
        /* Check that no reserved column names are used. */
 
1806
        for (i = 0; i < dict_table_get_n_user_cols(table); i++) {
 
1807
                if (dict_col_name_is_reserved(
 
1808
                            dict_table_get_col_name(table, i))) {
 
1809
 
 
1810
                        goto err_exit;
 
1811
                }
 
1812
        }
 
1813
 
1848
1814
        trx_start_if_not_started(trx);
1849
1815
 
1850
1816
        /* The table name is prefixed with the database name and a '/'.
1912
1878
 
1913
1879
        thr = pars_complete_graph_for_exec(node, trx, heap);
1914
1880
 
1915
 
        ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
 
1881
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1916
1882
        que_run_threads(thr);
1917
1883
 
1918
1884
        err = trx->error_state;
1919
1885
 
 
1886
        if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
 
1887
                trx->error_state = DB_SUCCESS;
 
1888
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
 
1889
        }
 
1890
 
1920
1891
        switch (err) {
1921
 
        case DB_SUCCESS:
1922
 
                break;
1923
1892
        case DB_OUT_OF_FILE_SPACE:
1924
 
                trx->error_state = DB_SUCCESS;
1925
 
                trx_general_rollback_for_mysql(trx, NULL);
1926
 
 
1927
1893
                ut_print_timestamp(stderr);
1928
1894
                fputs("  InnoDB: Warning: cannot create table ",
1929
1895
                      stderr);
1938
1904
                break;
1939
1905
 
1940
1906
        case DB_DUPLICATE_KEY:
1941
 
        default:
 
1907
                ut_print_timestamp(stderr);
 
1908
                fputs("  InnoDB: Error: table ", stderr);
 
1909
                ut_print_name(stderr, trx, TRUE, table->name);
 
1910
                fputs(" already exists in InnoDB internal\n"
 
1911
                      "InnoDB: data dictionary. Have you deleted"
 
1912
                      " the .frm file\n"
 
1913
                      "InnoDB: and not used DROP TABLE?"
 
1914
                      " Have you used DROP DATABASE\n"
 
1915
                      "InnoDB: for InnoDB tables in"
 
1916
                      " MySQL version <= 3.23.43?\n"
 
1917
                      "InnoDB: See the Restrictions section"
 
1918
                      " of the InnoDB manual.\n"
 
1919
                      "InnoDB: You can drop the orphaned table"
 
1920
                      " inside InnoDB by\n"
 
1921
                      "InnoDB: creating an InnoDB table with"
 
1922
                      " the same name in another\n"
 
1923
                      "InnoDB: database and copying the .frm file"
 
1924
                      " to the current database.\n"
 
1925
                      "InnoDB: Then MySQL thinks the table exists,"
 
1926
                      " and DROP TABLE will\n"
 
1927
                      "InnoDB: succeed.\n"
 
1928
                      "InnoDB: You can look for further help from\n"
 
1929
                      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
 
1930
                      stderr);
 
1931
 
1942
1932
                /* We may also get err == DB_ERROR if the .ibd file for the
1943
1933
                table already exists */
1944
1934
 
1945
 
                trx->error_state = DB_SUCCESS;
1946
 
                trx_general_rollback_for_mysql(trx, NULL);
1947
 
                dict_mem_table_free(table);
1948
1935
                break;
1949
1936
        }
1950
1937
 
2053
2040
 
2054
2041
        thr = pars_complete_graph_for_exec(node, trx, heap);
2055
2042
 
2056
 
        ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
 
2043
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2057
2044
        que_run_threads(thr);
2058
2045
 
2059
2046
        err = trx->error_state;
2066
2053
 
2067
2054
                trx->error_state = DB_SUCCESS;
2068
2055
 
2069
 
                trx_general_rollback_for_mysql(trx, NULL);
 
2056
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
2070
2057
 
2071
2058
                row_drop_table_for_mysql(table_name, trx, FALSE);
2072
2059
 
2087
2074
the foreign key constraints declared in the string. This function
2088
2075
should be called after the indexes for a table have been created.
2089
2076
Each foreign key constraint must be accompanied with indexes in
2090
 
both participating tables. The indexes are allowed to contain more
 
2077
bot participating tables. The indexes are allowed to contain more
2091
2078
fields than mentioned in the constraint. Check also that foreign key
2092
2079
constraints which reference this table are ok.
2093
2080
@return error code or DB_SUCCESS */
2101
2088
                                FOREIGN KEY (a, b) REFERENCES table2(c, d),
2102
2089
                                        table2 can be written also with the
2103
2090
                                        database name before it: test.table2 */
2104
 
        size_t          sql_length,     /*!< in: length of sql_string */
2105
2091
        const char*     name,           /*!< in: table full name in the
2106
2092
                                        normalized form
2107
2093
                                        database_name/table_name */
2123
2109
 
2124
2110
        trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2125
2111
 
2126
 
        err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2127
 
                                              name, reject_fks);
 
2112
        err = dict_create_foreign_constraints(trx, sql_string, name,
 
2113
                                              reject_fks);
2128
2114
        if (err == DB_SUCCESS) {
2129
2115
                /* Check that also referencing constraints are ok */
2130
 
                err = dict_load_foreigns(name, FALSE, TRUE);
 
2116
                err = dict_load_foreigns(name, TRUE);
2131
2117
        }
2132
2118
 
2133
2119
        if (err != DB_SUCCESS) {
2135
2121
 
2136
2122
                trx->error_state = DB_SUCCESS;
2137
2123
 
2138
 
                trx_general_rollback_for_mysql(trx, NULL);
 
2124
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
2139
2125
 
2140
2126
                row_drop_table_for_mysql(name, trx, FALSE);
2141
2127
 
2326
2312
                drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2327
2313
        }
2328
2314
 
2329
 
        drop = static_cast<row_mysql_drop_t *>(mem_alloc(sizeof(row_mysql_drop_t)));
 
2315
        drop = mem_alloc(sizeof(row_mysql_drop_t));
2330
2316
 
2331
2317
        drop->table_name = mem_strdup(name);
2332
2318
 
2354
2340
        trx_t*          trx)    /*!< in: transaction handle */
2355
2341
{
2356
2342
        dict_foreign_t* foreign;
2357
 
        table_id_t      new_id;
 
2343
        dulint          new_id;
2358
2344
        dict_table_t*   table;
2359
2345
        ibool           success;
2360
2346
        ulint           err;
2468
2454
                goto funct_exit;
2469
2455
        }
2470
2456
 
2471
 
        dict_hdr_get_new_id(&new_id, NULL, NULL);
 
2457
        new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2472
2458
 
2473
2459
        /* Remove all locks except the table-level S and X locks. */
2474
2460
        lock_remove_all_on_table(table, FALSE);
2476
2462
        info = pars_info_create();
2477
2463
 
2478
2464
        pars_info_add_str_literal(info, "table_name", name);
2479
 
        pars_info_add_ull_literal(info, "new_id", new_id);
 
2465
        pars_info_add_dulint_literal(info, "new_id", new_id);
2480
2466
 
2481
2467
        err = que_eval_sql(info,
2482
2468
                           "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2502
2488
 
2503
2489
        if (err != DB_SUCCESS) {
2504
2490
                trx->error_state = DB_SUCCESS;
2505
 
                trx_general_rollback_for_mysql(trx, NULL);
 
2491
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
2506
2492
                trx->error_state = DB_SUCCESS;
2507
2493
        } else {
2508
2494
                dict_table_change_id_in_cache(table, new_id);
2511
2497
 
2512
2498
                if (!success) {
2513
2499
                        trx->error_state = DB_SUCCESS;
2514
 
                        trx_general_rollback_for_mysql(trx, NULL);
 
2500
                        trx_general_rollback_for_mysql(trx, FALSE, NULL);
2515
2501
                        trx->error_state = DB_SUCCESS;
2516
2502
 
2517
2503
                        err = DB_ERROR;
2690
2676
        dict_index_t*   sys_index;
2691
2677
        btr_pcur_t      pcur;
2692
2678
        mtr_t           mtr;
2693
 
        table_id_t      new_id;
 
2679
        dulint          new_id;
2694
2680
        ulint           recreate_space = 0;
2695
2681
        pars_info_t*    info = NULL;
2696
2682
 
2830
2816
 
2831
2817
                        dict_index_t*   index;
2832
2818
 
2833
 
                        dict_hdr_get_new_id(NULL, NULL, &space);
2834
 
 
2835
 
                        /* Lock all index trees for this table. We must
2836
 
                        do so after dict_hdr_get_new_id() to preserve
2837
 
                        the latch order */
2838
 
                        dict_table_x_lock_indexes(table);
2839
 
 
2840
 
                        if (space == ULINT_UNDEFINED
2841
 
                            || fil_create_new_single_table_tablespace(
2842
 
                                    space, table->name, FALSE, flags,
 
2819
                        space = 0;
 
2820
 
 
2821
                        if (fil_create_new_single_table_tablespace(
 
2822
                                    &space, table->name, FALSE, flags,
2843
2823
                                    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2844
 
                                dict_table_x_unlock_indexes(table);
2845
2824
                                ut_print_timestamp(stderr);
2846
2825
                                fprintf(stderr,
2847
2826
                                        "  InnoDB: TRUNCATE TABLE %s failed to"
2870
2849
                                        FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2871
2850
                        mtr_commit(&mtr);
2872
2851
                }
2873
 
        } else {
2874
 
                /* Lock all index trees for this table, as we will
2875
 
                truncate the table/index and possibly change their metadata.
2876
 
                All DML/DDL are blocked by table level lock, with
2877
 
                a few exceptions such as queries into information schema
2878
 
                about the table, MySQL could try to access index stats
2879
 
                for this kind of query, we need to use index locks to
2880
 
                sync up */
2881
 
                dict_table_x_lock_indexes(table);
2882
2852
        }
2883
2853
 
2884
2854
        /* scan SYS_INDEXES for all indexes of the table */
2887
2857
        tuple = dtuple_create(heap, 1);
2888
2858
        dfield = dtuple_get_nth_field(tuple, 0);
2889
2859
 
2890
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
 
2860
        buf = mem_heap_alloc(heap, 8);
2891
2861
        mach_write_to_8(buf, table->id);
2892
2862
 
2893
2863
        dfield_set_data(dfield, buf, 8);
2954
2924
 
2955
2925
        mem_heap_free(heap);
2956
2926
 
2957
 
        /* Done with index truncation, release index tree locks,
2958
 
        subsequent work relates to table level metadata change */
2959
 
        dict_table_x_unlock_indexes(table);
2960
 
 
2961
 
        dict_hdr_get_new_id(&new_id, NULL, NULL);
 
2927
        new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2962
2928
 
2963
2929
        info = pars_info_create();
2964
2930
 
2965
2931
        pars_info_add_int4_literal(info, "space", (lint) table->space);
2966
 
        pars_info_add_ull_literal(info, "old_id", table->id);
2967
 
        pars_info_add_ull_literal(info, "new_id", new_id);
 
2932
        pars_info_add_dulint_literal(info, "old_id", table->id);
 
2933
        pars_info_add_dulint_literal(info, "new_id", new_id);
2968
2934
 
2969
2935
        err = que_eval_sql(info,
2970
2936
                           "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2983
2949
 
2984
2950
        if (err != DB_SUCCESS) {
2985
2951
                trx->error_state = DB_SUCCESS;
2986
 
                trx_general_rollback_for_mysql(trx, NULL);
 
2952
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
2987
2953
                trx->error_state = DB_SUCCESS;
2988
2954
                ut_print_timestamp(stderr);
2989
2955
                fputs("  InnoDB: Unable to assign a new identifier to table ",
2997
2963
                dict_table_change_id_in_cache(table, new_id);
2998
2964
        }
2999
2965
 
3000
 
        /* 
3001
 
          MySQL calls ha_innobase::reset_auto_increment() which does
3002
 
          the same thing. 
3003
 
        */
 
2966
        /* MySQL calls ha_innobase::reset_auto_increment() which does
 
2967
        the same thing. */
3004
2968
        dict_table_autoinc_lock(table);
3005
2969
        dict_table_autoinc_initialize(table, 1);
3006
2970
        dict_table_autoinc_unlock(table);
3007
 
        dict_update_statistics(table, FALSE /* update even if stats are
3008
 
                                            initialized */);
 
2971
        dict_update_statistics(table);
3009
2972
 
3010
2973
        trx_commit_for_mysql(trx);
3011
2974
 
3213
3176
 
3214
3177
        if (table->n_foreign_key_checks_running > 0) {
3215
3178
 
3216
 
                const char*     i_table_name = table->name;
 
3179
                const char*     table_name = table->name;
3217
3180
                ibool           added;
3218
3181
 
3219
 
                added = row_add_table_to_background_drop_list(i_table_name);
 
3182
                added = row_add_table_to_background_drop_list(table_name);
3220
3183
 
3221
3184
                if (added) {
3222
3185
                        ut_print_timestamp(stderr);
3223
3186
                        fputs("  InnoDB: You are trying to drop table ",
3224
3187
                              stderr);
3225
 
                        ut_print_name(stderr, trx, TRUE, i_table_name);
 
3188
                        ut_print_name(stderr, trx, TRUE, table_name);
3226
3189
                        fputs("\n"
3227
3190
                              "InnoDB: though there is a"
3228
3191
                              " foreign key check running on it.\n"
3325
3288
                           "END;\n"
3326
3289
                           , FALSE, trx);
3327
3290
 
3328
 
        switch (err) {
3329
 
                ibool           is_temp;
 
3291
        if (err != DB_SUCCESS) {
 
3292
                ut_a(err == DB_OUT_OF_FILE_SPACE);
 
3293
 
 
3294
                err = DB_MUST_GET_MORE_FILE_SPACE;
 
3295
 
 
3296
                row_mysql_handle_errors(&err, trx, NULL, NULL);
 
3297
 
 
3298
                ut_error;
 
3299
        } else {
 
3300
                ibool           is_path;
3330
3301
                const char*     name_or_path;
3331
3302
                mem_heap_t*     heap;
3332
3303
 
3333
 
        case DB_SUCCESS:
3334
 
 
3335
3304
                heap = mem_heap_create(200);
3336
3305
 
3337
3306
                /* Clone the name, in case it has been allocated
3341
3310
                space_id = table->space;
3342
3311
 
3343
3312
                if (table->dir_path_of_temp_table != NULL) {
 
3313
                        is_path = TRUE;
3344
3314
                        name_or_path = mem_heap_strdup(
3345
3315
                                heap, table->dir_path_of_temp_table);
3346
 
                        is_temp = TRUE;
3347
3316
                } else {
 
3317
                        is_path = FALSE;
3348
3318
                        name_or_path = name;
3349
 
                        is_temp = (table->flags >> DICT_TF2_SHIFT)
3350
 
                                & DICT_TF2_TEMPORARY;
3351
3319
                }
3352
3320
 
3353
3321
                dict_table_remove_from_cache(table);
3354
3322
 
3355
 
                if (dict_load_table(name, TRUE) != NULL) {
 
3323
                if (dict_load_table(name) != NULL) {
3356
3324
                        ut_print_timestamp(stderr);
3357
3325
                        fputs("  InnoDB: Error: not able to remove table ",
3358
3326
                              stderr);
3367
3335
                if (err == DB_SUCCESS && space_id > 0) {
3368
3336
                        if (!fil_space_for_table_exists_in_mem(space_id,
3369
3337
                                                               name_or_path,
3370
 
                                                               is_temp, FALSE,
3371
 
                                                               !is_temp)) {
 
3338
                                                               is_path,
 
3339
                                                               FALSE, TRUE)) {
3372
3340
                                err = DB_SUCCESS;
3373
3341
 
3374
3342
                                fprintf(stderr,
3397
3365
                }
3398
3366
 
3399
3367
                mem_heap_free(heap);
3400
 
                break;
3401
 
 
3402
 
        case DB_TOO_MANY_CONCURRENT_TRXS:
3403
 
                /* Cannot even find a free slot for the
3404
 
                the undo log. We can directly exit here
3405
 
                and return the DB_TOO_MANY_CONCURRENT_TRXS
3406
 
                error. */
3407
 
                break;
3408
 
 
3409
 
        case DB_OUT_OF_FILE_SPACE:
3410
 
                err = DB_MUST_GET_MORE_FILE_SPACE;
3411
 
 
3412
 
                row_mysql_handle_errors(&err, trx, NULL, NULL);
3413
 
 
3414
 
                /* Fall through to raise error */
3415
 
 
3416
 
        default:
3417
 
                /* No other possible error returns */
3418
 
                ut_error;
3419
3368
        }
3420
 
 
3421
3369
funct_exit:
3422
3370
 
3423
3371
        if (locked_dictionary) {
3433
3381
        return((int) err);
3434
3382
}
3435
3383
 
3436
 
/*********************************************************************//**
3437
 
Drop all temporary tables during crash recovery. */
3438
 
UNIV_INTERN
3439
 
void
3440
 
row_mysql_drop_temp_tables(void)
3441
 
/*============================*/
3442
 
{
3443
 
        trx_t*          trx;
3444
 
        btr_pcur_t      pcur;
3445
 
        mtr_t           mtr;
3446
 
        mem_heap_t*     heap;
3447
 
 
3448
 
        trx = trx_allocate_for_background();
3449
 
        trx->op_info = "dropping temporary tables";
3450
 
        row_mysql_lock_data_dictionary(trx);
3451
 
 
3452
 
        heap = mem_heap_create(200);
3453
 
 
3454
 
        mtr_start(&mtr);
3455
 
 
3456
 
        btr_pcur_open_at_index_side(
3457
 
                TRUE,
3458
 
                dict_table_get_first_index(dict_sys->sys_tables),
3459
 
                BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3460
 
 
3461
 
        for (;;) {
3462
 
                const rec_t*    rec;
3463
 
                const byte*     field;
3464
 
                ulint           len;
3465
 
                const char*     table_name;
3466
 
                dict_table_t*   table;
3467
 
 
3468
 
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3469
 
 
3470
 
                if (!btr_pcur_is_on_user_rec(&pcur)) {
3471
 
                        break;
3472
 
                }
3473
 
 
3474
 
                rec = btr_pcur_get_rec(&pcur);
3475
 
                field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
3476
 
                if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
3477
 
                        continue;
3478
 
                }
3479
 
 
3480
 
                /* Because this is not a ROW_FORMAT=REDUNDANT table,
3481
 
                the is_temp flag is valid.  Examine it. */
3482
 
 
3483
 
                field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
3484
 
                if (len != 4
3485
 
                    || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
3486
 
                        continue;
3487
 
                }
3488
 
 
3489
 
                /* This is a temporary table. */
3490
 
                field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
3491
 
                if (len == UNIV_SQL_NULL || len == 0) {
3492
 
                        /* Corrupted SYS_TABLES.NAME */
3493
 
                        continue;
3494
 
                }
3495
 
 
3496
 
                table_name = mem_heap_strdupl(heap, (const char*) field, len);
3497
 
 
3498
 
                btr_pcur_store_position(&pcur, &mtr);
3499
 
                btr_pcur_commit_specify_mtr(&pcur, &mtr);
3500
 
 
3501
 
                table = dict_load_table(table_name, TRUE);
3502
 
 
3503
 
                if (table) {
3504
 
                        row_drop_table_for_mysql(table_name, trx, FALSE);
3505
 
                        trx_commit_for_mysql(trx);
3506
 
                }
3507
 
 
3508
 
                mtr_start(&mtr);
3509
 
                btr_pcur_restore_position(BTR_SEARCH_LEAF,
3510
 
                                          &pcur, &mtr);
3511
 
        }
3512
 
 
3513
 
        btr_pcur_close(&pcur);
3514
 
        mtr_commit(&mtr);
3515
 
        mem_heap_free(heap);
3516
 
        row_mysql_unlock_data_dictionary(trx);
3517
 
        trx_free_for_background(trx);
3518
 
}
3519
 
 
3520
3384
/*******************************************************************//**
3521
3385
Drop all foreign keys in a database, see Bug#18942.
3522
3386
Called at the end of row_drop_database_for_mysql().
3605
3469
        while ((table_name = dict_get_first_table_name_in_db(name))) {
3606
3470
                ut_a(memcmp(table_name, name, namelen) == 0);
3607
3471
 
3608
 
                // For the time being I would like to see how often we see
3609
 
                // lost temporary tables. --Brian
3610
 
                fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
3611
 
 
3612
3472
                table = dict_table_get_low(table_name);
3613
3473
 
3614
3474
                ut_a(table);
3780
3640
                      stderr);
3781
3641
 
3782
3642
                goto funct_exit;
 
3643
        } else if (row_mysql_is_system_table(new_name)) {
 
3644
 
 
3645
                fprintf(stderr,
 
3646
                        "InnoDB: Error: trying to create a MySQL"
 
3647
                        " system table %s of type InnoDB.\n"
 
3648
                        "InnoDB: MySQL system tables must be"
 
3649
                        " of the MyISAM type!\n",
 
3650
                        new_name);
 
3651
 
 
3652
                goto funct_exit;
3783
3653
        }
3784
3654
 
3785
3655
        trx->op_info = "renaming table";
3992
3862
                              "InnoDB: succeed.\n", stderr);
3993
3863
                }
3994
3864
                trx->error_state = DB_SUCCESS;
3995
 
                trx_general_rollback_for_mysql(trx, NULL);
 
3865
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
3996
3866
                trx->error_state = DB_SUCCESS;
3997
3867
        } else {
3998
3868
                /* The following call will also rename the .ibd data file if
4001
3871
                if (!dict_table_rename_in_cache(table, new_name,
4002
3872
                                                !new_is_tmp)) {
4003
3873
                        trx->error_state = DB_SUCCESS;
4004
 
                        trx_general_rollback_for_mysql(trx, NULL);
 
3874
                        trx_general_rollback_for_mysql(trx, FALSE, NULL);
4005
3875
                        trx->error_state = DB_SUCCESS;
4006
3876
                        goto funct_exit;
4007
3877
                }
4010
3880
                an ALTER, not in a RENAME. */
4011
3881
 
4012
3882
                err = dict_load_foreigns(
4013
 
                        new_name, FALSE, !old_is_tmp || trx->check_foreigns);
 
3883
                        new_name, !old_is_tmp || trx->check_foreigns);
4014
3884
 
4015
3885
                if (err != DB_SUCCESS) {
4016
3886
                        ut_print_timestamp(stderr);
4041
3911
                        ut_a(dict_table_rename_in_cache(table,
4042
3912
                                                        old_name, FALSE));
4043
3913
                        trx->error_state = DB_SUCCESS;
4044
 
                        trx_general_rollback_for_mysql(trx, NULL);
 
3914
                        trx_general_rollback_for_mysql(trx, FALSE, NULL);
4045
3915
                        trx->error_state = DB_SUCCESS;
4046
3916
                }
4047
3917
        }
4066
3936
constraint is not broken, and calculates the number of index entries
4067
3937
in the read view of the current transaction.
4068
3938
@return TRUE if ok */
4069
 
UNIV_INTERN
 
3939
static
4070
3940
ibool
4071
 
row_check_index_for_mysql(
4072
 
/*======================*/
4073
 
        row_prebuilt_t*         prebuilt,       /*!< in: prebuilt struct
4074
 
                                                in MySQL handle */
4075
 
        const dict_index_t*     index,          /*!< in: index */
4076
 
        ulint*                  n_rows)         /*!< out: number of entries
4077
 
                                                seen in the consistent read */
 
3941
row_scan_and_check_index(
 
3942
/*=====================*/
 
3943
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct in MySQL */
 
3944
        dict_index_t*   index,          /*!< in: index */
 
3945
        ulint*          n_rows)         /*!< out: number of entries seen in the
 
3946
                                        current consistent read */
4078
3947
{
4079
3948
        dtuple_t*       prev_entry      = NULL;
4080
3949
        ulint           matched_fields;
4095
3964
 
4096
3965
        *n_rows = 0;
4097
3966
 
4098
 
        buf = static_cast<byte *>(mem_alloc(UNIV_PAGE_SIZE));
 
3967
        if (!row_merge_is_index_usable(prebuilt->trx, index)) {
 
3968
                /* A newly created index may lack some delete-marked
 
3969
                records that may exist in the read view of
 
3970
                prebuilt->trx.  Thus, such indexes must not be
 
3971
                accessed by consistent read. */
 
3972
                return(is_ok);
 
3973
        }
 
3974
 
 
3975
        buf = mem_alloc(UNIV_PAGE_SIZE);
4099
3976
        heap = mem_heap_create(100);
4100
3977
 
 
3978
        /* Make a dummy template in prebuilt, which we will use
 
3979
        in scanning the index entries */
 
3980
 
 
3981
        prebuilt->index = index;
 
3982
        /* row_merge_is_index_usable() was already checked above. */
 
3983
        prebuilt->index_usable = TRUE;
 
3984
        prebuilt->sql_stat_start = TRUE;
 
3985
        prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
 
3986
        prebuilt->n_template = 0;
 
3987
        prebuilt->need_to_access_clustered = FALSE;
 
3988
 
 
3989
        dtuple_set_n_fields(prebuilt->search_tuple, 0);
 
3990
 
 
3991
        prebuilt->select_lock_type = LOCK_NONE;
4101
3992
        cnt = 1000;
4102
3993
 
4103
3994
        ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4196
4087
                                * sizeof *offsets;
4197
4088
 
4198
4089
                        tmp_heap = mem_heap_create(size);
4199
 
                        offsets = static_cast<ulint *>(mem_heap_dup(tmp_heap, offsets, size));
 
4090
                        offsets = mem_heap_dup(tmp_heap, offsets, size);
4200
4091
                }
4201
4092
 
4202
4093
                mem_heap_empty(heap);
4216
4107
}
4217
4108
 
4218
4109
/*********************************************************************//**
 
4110
Checks a table for corruption.
 
4111
@return DB_ERROR or DB_SUCCESS */
 
4112
UNIV_INTERN
 
4113
ulint
 
4114
row_check_table_for_mysql(
 
4115
/*======================*/
 
4116
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct in MySQL
 
4117
                                        handle */
 
4118
{
 
4119
        dict_table_t*   table           = prebuilt->table;
 
4120
        dict_index_t*   index;
 
4121
        ulint           n_rows;
 
4122
        ulint           n_rows_in_table = ULINT_UNDEFINED;
 
4123
        ulint           ret             = DB_SUCCESS;
 
4124
        ulint           old_isolation_level;
 
4125
 
 
4126
        if (table->ibd_file_missing) {
 
4127
                ut_print_timestamp(stderr);
 
4128
                fprintf(stderr, "  InnoDB: Error:\n"
 
4129
                        "InnoDB: MySQL is trying to use a table handle"
 
4130
                        " but the .ibd file for\n"
 
4131
                        "InnoDB: table %s does not exist.\n"
 
4132
                        "InnoDB: Have you deleted the .ibd file"
 
4133
                        " from the database directory under\n"
 
4134
                        "InnoDB: the MySQL datadir, or have you"
 
4135
                        " used DISCARD TABLESPACE?\n"
 
4136
                        "InnoDB: Look from\n"
 
4137
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
 
4138
                        "InnoDB: how you can resolve the problem.\n",
 
4139
                        table->name);
 
4140
                return(DB_ERROR);
 
4141
        }
 
4142
 
 
4143
        prebuilt->trx->op_info = "checking table";
 
4144
 
 
4145
        old_isolation_level = prebuilt->trx->isolation_level;
 
4146
 
 
4147
        /* We must run the index record counts at an isolation level
 
4148
        >= READ COMMITTED, because a dirty read can see a wrong number
 
4149
        of records in some index; to play safe, we use always
 
4150
        REPEATABLE READ here */
 
4151
 
 
4152
        prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
 
4153
 
 
4154
        /* Enlarge the fatal lock wait timeout during CHECK TABLE. */
 
4155
        mutex_enter(&kernel_mutex);
 
4156
        srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
 
4157
        mutex_exit(&kernel_mutex);
 
4158
 
 
4159
        index = dict_table_get_first_index(table);
 
4160
 
 
4161
        while (index != NULL) {
 
4162
                /* fputs("Validating index ", stderr);
 
4163
                ut_print_name(stderr, trx, FALSE, index->name);
 
4164
                putc('\n', stderr); */
 
4165
 
 
4166
                if (!btr_validate_index(index, prebuilt->trx)) {
 
4167
                        ret = DB_ERROR;
 
4168
                } else {
 
4169
                        if (!row_scan_and_check_index(prebuilt,index, &n_rows)){
 
4170
                                ret = DB_ERROR;
 
4171
                        }
 
4172
 
 
4173
                        if (trx_is_interrupted(prebuilt->trx)) {
 
4174
                                break;
 
4175
                        }
 
4176
 
 
4177
                        /* fprintf(stderr, "%lu entries in index %s\n", n_rows,
 
4178
                        index->name); */
 
4179
 
 
4180
                        if (index == dict_table_get_first_index(table)) {
 
4181
                                n_rows_in_table = n_rows;
 
4182
                        } else if (n_rows != n_rows_in_table) {
 
4183
 
 
4184
                                ret = DB_ERROR;
 
4185
 
 
4186
                                fputs("Error: ", stderr);
 
4187
                                dict_index_name_print(stderr,
 
4188
                                                      prebuilt->trx, index);
 
4189
                                fprintf(stderr,
 
4190
                                        " contains %lu entries,"
 
4191
                                        " should be %lu\n",
 
4192
                                        (ulong) n_rows,
 
4193
                                        (ulong) n_rows_in_table);
 
4194
                        }
 
4195
                }
 
4196
 
 
4197
                index = dict_table_get_next_index(index);
 
4198
        }
 
4199
 
 
4200
        /* Restore the original isolation level */
 
4201
        prebuilt->trx->isolation_level = old_isolation_level;
 
4202
 
 
4203
        /* We validate also the whole adaptive hash index for all tables
 
4204
        at every CHECK TABLE */
 
4205
 
 
4206
        if (!btr_search_validate()) {
 
4207
 
 
4208
                ret = DB_ERROR;
 
4209
        }
 
4210
 
 
4211
        /* Restore the fatal lock wait timeout after CHECK TABLE. */
 
4212
        mutex_enter(&kernel_mutex);
 
4213
        srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
 
4214
        mutex_exit(&kernel_mutex);
 
4215
 
 
4216
        prebuilt->trx->op_info = "";
 
4217
 
 
4218
        return(ret);
 
4219
}
 
4220
 
 
4221
/*********************************************************************//**
4219
4222
Determines if a table is a magic monitor table.
4220
4223
@return TRUE if monitor table */
4221
4224
UNIV_INTERN