00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00027 #include "row0mysql.h"
00028
00029 #ifdef UNIV_NONINL
00030 #include "row0mysql.ic"
00031 #endif
00032
00033 #include "row0ins.h"
00034 #include "row0merge.h"
00035 #include "row0sel.h"
00036 #include "row0upd.h"
00037 #include "row0row.h"
00038 #include "que0que.h"
00039 #include "pars0pars.h"
00040 #include "dict0dict.h"
00041 #include "dict0crea.h"
00042 #include "dict0load.h"
00043 #include "dict0boot.h"
00044 #include "trx0roll.h"
00045 #include "trx0purge.h"
00046 #include "trx0rec.h"
00047 #include "trx0undo.h"
00048 #include "lock0lock.h"
00049 #include "rem0cmp.h"
00050 #include "log0log.h"
00051 #include "btr0sea.h"
00052 #include "fil0fil.h"
00053 #include "ibuf0ibuf.h"
00054
00055 #include <errno.h>
00056
00058 UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
00059
00061 typedef struct row_mysql_drop_struct row_mysql_drop_t;
00062
00064 struct row_mysql_drop_struct{
00065 char* table_name;
00066 UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
00068 };
00069
00075 static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
00077 static ibool row_mysql_drop_list_inited = FALSE;
00078
00080
00081 static const char S_innodb_monitor[] = "innodb_monitor";
00082 static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
00083 static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
00084 static const char S_innodb_table_monitor[] = "innodb_table_monitor";
00085 static const char S_innodb_mem_validate[] = "innodb_mem_validate";
00086
00087
00094 #define STR_EQ(str1, str1_len, str2_onstack) \
00095 ((str1_len) == sizeof(str2_onstack) \
00096 && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
00097
00098
00105 static
00106 ibool
00107 row_add_table_to_background_drop_list(
00108
00109 const char* name);
00111
00113 static
00114 void
00115 row_mysql_delay_if_needed(void)
00116
00117 {
00118 if (srv_dml_needed_delay) {
00119 os_thread_sleep(srv_dml_needed_delay);
00120 }
00121 }
00122
00123
00125 UNIV_INTERN
00126 void
00127 row_mysql_prebuilt_free_blob_heap(
00128
00129 row_prebuilt_t* prebuilt)
00131 {
00132 mem_heap_free(prebuilt->blob_heap);
00133 prebuilt->blob_heap = NULL;
00134 }
00135
00136
00141 UNIV_INTERN
00142 byte*
00143 row_mysql_store_true_var_len(
00144
00145 byte* dest,
00146 ulint len,
00147 ulint lenlen)
00148 {
00149 if (lenlen == 2) {
00150 ut_a(len < 256 * 256);
00151
00152 mach_write_to_2_little_endian(dest, len);
00153
00154 return(dest + 2);
00155 }
00156
00157 ut_a(lenlen == 1);
00158 ut_a(len < 256);
00159
00160 mach_write_to_1(dest, len);
00161
00162 return(dest + 1);
00163 }
00164
00165
00170 UNIV_INTERN
00171 const byte*
00172 row_mysql_read_true_varchar(
00173
00174 ulint* len,
00175 const byte* field,
00176 ulint lenlen)
00178 {
00179 if (lenlen == 2) {
00180 *len = mach_read_from_2_little_endian(field);
00181
00182 return(field + 2);
00183 }
00184
00185 ut_a(lenlen == 1);
00186
00187 *len = mach_read_from_1(field);
00188
00189 return(field + 1);
00190 }
00191
00192
00194 UNIV_INTERN
00195 void
00196 row_mysql_store_blob_ref(
00197
00198 byte* dest,
00199 ulint col_len,
00203 const void* data,
00205 ulint len)
00209 {
00210
00211
00212
00213 memset(dest, '\0', col_len);
00214
00215
00216
00217
00218
00219
00220 ut_a(col_len - 8 > 1 || len < 256);
00221 ut_a(col_len - 8 > 2 || len < 256 * 256);
00222 ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
00223
00224 mach_write_to_n_little_endian(dest, col_len - 8, len);
00225
00226 memcpy(dest + col_len - 8, &data, sizeof data);
00227 }
00228
00229
00232 UNIV_INTERN
00233 const byte*
00234 row_mysql_read_blob_ref(
00235
00236 ulint* len,
00237 const byte* ref,
00239 ulint col_len)
00241 {
00242 byte* data;
00243
00244 *len = mach_read_from_n_little_endian(ref, col_len - 8);
00245
00246 memcpy(&data, ref + col_len - 8, sizeof data);
00247
00248 return(data);
00249 }
00250
00251
00253 UNIV_INTERN
00254 void
00255 row_mysql_pad_col(
00256
00257 ulint mbminlen,
00259 byte* pad,
00260 ulint len)
00261 {
00262 const byte* pad_end;
00263
00264 switch (UNIV_EXPECT(mbminlen, 1)) {
00265 default:
00266 ut_error;
00267 case 1:
00268
00269 memset(pad, 0x20, len);
00270 break;
00271 case 2:
00272
00273 pad_end = pad + len;
00274 ut_a(!(len % 2));
00275 do {
00276 *pad++ = 0x00;
00277 *pad++ = 0x20;
00278 } while (pad < pad_end);
00279 break;
00280 case 4:
00281
00282 pad_end = pad + len;
00283 ut_a(!(len % 4));
00284 do {
00285 *pad++ = 0x00;
00286 *pad++ = 0x00;
00287 *pad++ = 0x00;
00288 *pad++ = 0x20;
00289 } while (pad < pad_end);
00290 break;
00291 }
00292 }
00293
00294
00299 UNIV_INTERN
00300 byte*
00301 row_mysql_store_col_in_innobase_format(
00302
00303 dfield_t* dfield,
00306 byte* buf,
00309 ibool row_format_col,
00316 const byte* mysql_data,
00321 ulint col_len,
00327 ulint comp)
00328 {
00329 const byte* ptr = mysql_data;
00330 const dtype_t* dtype;
00331 ulint type;
00332 ulint lenlen;
00333
00334 dtype = dfield_get_type(dfield);
00335
00336 type = dtype->mtype;
00337
00338 if (type == DATA_INT) {
00339
00340
00341
00342
00343 byte* p = buf + col_len;
00344
00345 for (;;) {
00346 p--;
00347 *p = *mysql_data;
00348 if (p == buf) {
00349 break;
00350 }
00351 mysql_data++;
00352 }
00353
00354 if (!(dtype->prtype & DATA_UNSIGNED)) {
00355
00356 *buf ^= 128;
00357 }
00358
00359 ptr = buf;
00360 buf += col_len;
00361 } else if ((type == DATA_VARCHAR
00362 || type == DATA_VARMYSQL
00363 || type == DATA_BINARY)) {
00364
00365 if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
00366
00367
00368
00369 if (row_format_col) {
00370 if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
00371 lenlen = 2;
00372 } else {
00373 lenlen = 1;
00374 }
00375 } else {
00376
00377 lenlen = 2;
00378 }
00379
00380 ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
00381 lenlen);
00382 } else {
00383
00384
00385
00386
00387 ulint mbminlen = dtype_get_mbminlen(dtype);
00388
00389 ptr = mysql_data;
00390
00391 switch (mbminlen) {
00392 default:
00393 ut_error;
00394 case 4:
00395
00396
00397 col_len &= ~3;
00398
00399 while (col_len >= 4
00400 && ptr[col_len - 4] == 0x00
00401 && ptr[col_len - 3] == 0x00
00402 && ptr[col_len - 2] == 0x00
00403 && ptr[col_len - 1] == 0x20) {
00404 col_len -= 4;
00405 }
00406 break;
00407 case 2:
00408
00409
00410 col_len &= ~1;
00411
00412 while (col_len >= 2 && ptr[col_len - 2] == 0x00
00413 && ptr[col_len - 1] == 0x20) {
00414 col_len -= 2;
00415 }
00416 break;
00417 case 1:
00418
00419 while (col_len > 0
00420 && ptr[col_len - 1] == 0x20) {
00421 col_len--;
00422 }
00423 }
00424 }
00425 } else if (comp && type == DATA_MYSQL
00426 && dtype_get_mbminlen(dtype) == 1
00427 && dtype_get_mbmaxlen(dtype) > 1) {
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 ulint n_chars;
00452
00453 ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
00454
00455 n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
00456
00457
00458 while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
00459 col_len--;
00460 }
00461 } else if (type == DATA_BLOB && row_format_col) {
00462
00463 ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
00464 }
00465
00466 dfield_set_data(dfield, ptr, col_len);
00467
00468 return(buf);
00469 }
00470
00471
00475 static
00476 void
00477 row_mysql_convert_row_to_innobase(
00478
00479 dtuple_t* row,
00482 row_prebuilt_t* prebuilt,
00484 byte* mysql_rec)
00488 {
00489 const mysql_row_templ_t*templ;
00490 dfield_t* dfield;
00491 ulint i;
00492
00493 ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
00494 ut_ad(prebuilt->mysql_template);
00495
00496 for (i = 0; i < prebuilt->n_template; i++) {
00497
00498 templ = prebuilt->mysql_template + i;
00499 dfield = dtuple_get_nth_field(row, i);
00500
00501 if (templ->mysql_null_bit_mask != 0) {
00502
00503
00504 if (mysql_rec[templ->mysql_null_byte_offset]
00505 & (byte) (templ->mysql_null_bit_mask)) {
00506
00507
00508
00509 dfield_set_null(dfield);
00510
00511 goto next_column;
00512 }
00513 }
00514
00515 row_mysql_store_col_in_innobase_format(
00516 dfield,
00517 prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
00518 TRUE,
00519 mysql_rec + templ->mysql_col_offset,
00520 templ->mysql_col_len,
00521 dict_table_is_comp(prebuilt->table));
00522 next_column:
00523 ;
00524 }
00525 }
00526
00527
00531 UNIV_INTERN
00532 ibool
00533 row_mysql_handle_errors(
00534
00535 ulint* new_err,
00539 trx_t* trx,
00540 que_thr_t* thr,
00541 trx_savept_t* savept)
00542 {
00543 ulint err;
00544
00545 handle_new_error:
00546 err = trx->error_state;
00547
00548 ut_a(err != DB_SUCCESS);
00549
00550 trx->error_state = DB_SUCCESS;
00551
00552 switch (err) {
00553 case DB_LOCK_WAIT_TIMEOUT:
00554 if (row_rollback_on_timeout) {
00555 trx_general_rollback_for_mysql(trx, NULL);
00556 break;
00557 }
00558
00559 case DB_DUPLICATE_KEY:
00560 case DB_FOREIGN_DUPLICATE_KEY:
00561 case DB_TOO_BIG_RECORD:
00562 case DB_ROW_IS_REFERENCED:
00563 case DB_NO_REFERENCED_ROW:
00564 case DB_CANNOT_ADD_CONSTRAINT:
00565 case DB_TOO_MANY_CONCURRENT_TRXS:
00566 case DB_OUT_OF_FILE_SPACE:
00567 case DB_INTERRUPTED:
00568 if (savept) {
00569
00570
00571
00572 trx_general_rollback_for_mysql(trx, savept);
00573 }
00574
00575 break;
00576 case DB_LOCK_WAIT:
00577 srv_suspend_mysql_thread(thr);
00578
00579 if (trx->error_state != DB_SUCCESS) {
00580 que_thr_stop_for_mysql(thr);
00581
00582 goto handle_new_error;
00583 }
00584
00585 *new_err = err;
00586
00587 return(TRUE);
00588
00589 case DB_DEADLOCK:
00590 case DB_LOCK_TABLE_FULL:
00591
00592
00593
00594 trx_general_rollback_for_mysql(trx, NULL);
00595 break;
00596
00597 case DB_MUST_GET_MORE_FILE_SPACE:
00598 fputs("InnoDB: The database cannot continue"
00599 " operation because of\n"
00600 "InnoDB: lack of space. You must add"
00601 " a new data file to\n"
00602 "InnoDB: my.cnf and restart the database.\n", stderr);
00603
00604 exit(1);
00605
00606 case DB_CORRUPTION:
00607 fputs("InnoDB: We detected index corruption"
00608 " in an InnoDB type table.\n"
00609 "InnoDB: You have to dump + drop + reimport"
00610 " the table or, in\n"
00611 "InnoDB: a case of widespread corruption,"
00612 " dump all InnoDB\n"
00613 "InnoDB: tables and recreate the"
00614 " whole InnoDB tablespace.\n"
00615 "InnoDB: If the mysqld server crashes"
00616 " after the startup or when\n"
00617 "InnoDB: you dump the tables, look at\n"
00618 "InnoDB: " REFMAN "forcing-recovery.html"
00619 " for help.\n", stderr);
00620 break;
00621 case DB_FOREIGN_EXCEED_MAX_CASCADE:
00622 fprintf(stderr, "InnoDB: Cannot delete/update rows with"
00623 " cascading foreign key constraints that exceed max"
00624 " depth of %lu\n"
00625 "Please drop excessive foreign constraints"
00626 " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
00627 break;
00628 default:
00629 fprintf(stderr, "InnoDB: unknown error code %lu\n",
00630 (ulong) err);
00631 ut_error;
00632 }
00633
00634 if (trx->error_state != DB_SUCCESS) {
00635 *new_err = trx->error_state;
00636 } else {
00637 *new_err = err;
00638 }
00639
00640 trx->error_state = DB_SUCCESS;
00641
00642 return(FALSE);
00643 }
00644
00645
00648 UNIV_INTERN
00649 row_prebuilt_t*
00650 row_create_prebuilt(
00651
00652 dict_table_t* table)
00653 {
00654 row_prebuilt_t* prebuilt;
00655 mem_heap_t* heap;
00656 dict_index_t* clust_index;
00657 dtuple_t* ref;
00658 ulint ref_len;
00659
00660 heap = mem_heap_create(sizeof *prebuilt + 128);
00661
00662 prebuilt = static_cast<row_prebuilt_t *>(mem_heap_zalloc(heap, sizeof *prebuilt));
00663
00664 prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
00665 prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
00666
00667 prebuilt->table = table;
00668
00669 prebuilt->sql_stat_start = TRUE;
00670 prebuilt->heap = heap;
00671
00672 prebuilt->pcur = btr_pcur_create_for_mysql();
00673 prebuilt->clust_pcur = btr_pcur_create_for_mysql();
00674
00675 prebuilt->select_lock_type = LOCK_NONE;
00676 prebuilt->stored_select_lock_type = 99999999;
00677 UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
00678 sizeof prebuilt->stored_select_lock_type);
00679
00680 prebuilt->search_tuple = dtuple_create(
00681 heap, 2 * dict_table_get_n_cols(table));
00682
00683 clust_index = dict_table_get_first_index(table);
00684
00685
00686 ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
00687
00688 ref_len = dict_index_get_n_unique(clust_index);
00689
00690 ref = dtuple_create(heap, ref_len);
00691
00692 dict_index_copy_types(ref, clust_index, ref_len);
00693
00694 prebuilt->clust_ref = ref;
00695
00696 prebuilt->autoinc_error = 0;
00697 prebuilt->autoinc_offset = 0;
00698
00699
00700
00701 prebuilt->autoinc_increment = 1;
00702
00703 prebuilt->autoinc_last_value = 0;
00704
00705 return(prebuilt);
00706 }
00707
00708
00710 UNIV_INTERN
00711 void
00712 row_prebuilt_free(
00713
00714 row_prebuilt_t* prebuilt,
00715 ibool dict_locked)
00716 {
00717 ulint i;
00718
00719 if (UNIV_UNLIKELY
00720 (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
00721 || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
00722
00723 fprintf(stderr,
00724 "InnoDB: Error: trying to free a corrupt\n"
00725 "InnoDB: table handle. Magic n %lu,"
00726 " magic n2 %lu, table name ",
00727 (ulong) prebuilt->magic_n,
00728 (ulong) prebuilt->magic_n2);
00729 ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
00730 putc('\n', stderr);
00731
00732 mem_analyze_corruption(prebuilt);
00733
00734 ut_error;
00735 }
00736
00737 prebuilt->magic_n = ROW_PREBUILT_FREED;
00738 prebuilt->magic_n2 = ROW_PREBUILT_FREED;
00739
00740 btr_pcur_free_for_mysql(prebuilt->pcur);
00741 btr_pcur_free_for_mysql(prebuilt->clust_pcur);
00742
00743 if (prebuilt->mysql_template) {
00744 mem_free(prebuilt->mysql_template);
00745 }
00746
00747 if (prebuilt->ins_graph) {
00748 que_graph_free_recursive(prebuilt->ins_graph);
00749 }
00750
00751 if (prebuilt->sel_graph) {
00752 que_graph_free_recursive(prebuilt->sel_graph);
00753 }
00754
00755 if (prebuilt->upd_graph) {
00756 que_graph_free_recursive(prebuilt->upd_graph);
00757 }
00758
00759 if (prebuilt->blob_heap) {
00760 mem_heap_free(prebuilt->blob_heap);
00761 }
00762
00763 if (prebuilt->old_vers_heap) {
00764 mem_heap_free(prebuilt->old_vers_heap);
00765 }
00766
00767 for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
00768 if (prebuilt->fetch_cache[i] != NULL) {
00769
00770 if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
00771 (prebuilt->fetch_cache[i]) - 4))
00772 || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
00773 (prebuilt->fetch_cache[i])
00774 + prebuilt->mysql_row_len))) {
00775 fputs("InnoDB: Error: trying to free"
00776 " a corrupt fetch buffer.\n", stderr);
00777
00778 mem_analyze_corruption(
00779 prebuilt->fetch_cache[i]);
00780
00781 ut_error;
00782 }
00783
00784 mem_free((prebuilt->fetch_cache[i]) - 4);
00785 }
00786 }
00787
00788 dict_table_decrement_handle_count(prebuilt->table, dict_locked);
00789
00790 mem_heap_free(prebuilt->heap);
00791 }
00792
00793
00796 UNIV_INTERN
00797 void
00798 row_update_prebuilt_trx(
00799
00800 row_prebuilt_t* prebuilt,
00802 trx_t* trx)
00803 {
00804 if (trx->magic_n != TRX_MAGIC_N) {
00805 fprintf(stderr,
00806 "InnoDB: Error: trying to use a corrupt\n"
00807 "InnoDB: trx handle. Magic n %lu\n",
00808 (ulong) trx->magic_n);
00809
00810 mem_analyze_corruption(trx);
00811
00812 ut_error;
00813 }
00814
00815 if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
00816 fprintf(stderr,
00817 "InnoDB: Error: trying to use a corrupt\n"
00818 "InnoDB: table handle. Magic n %lu, table name ",
00819 (ulong) prebuilt->magic_n);
00820 ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
00821 putc('\n', stderr);
00822
00823 mem_analyze_corruption(prebuilt);
00824
00825 ut_error;
00826 }
00827
00828 prebuilt->trx = trx;
00829
00830 if (prebuilt->ins_graph) {
00831 prebuilt->ins_graph->trx = trx;
00832 }
00833
00834 if (prebuilt->upd_graph) {
00835 prebuilt->upd_graph->trx = trx;
00836 }
00837
00838 if (prebuilt->sel_graph) {
00839 prebuilt->sel_graph->trx = trx;
00840 }
00841 }
00842
00843 dtuple_t* row_get_prebuilt_insert_row(row_prebuilt_t* prebuilt);
00844
00845
00850 dtuple_t*
00851 row_get_prebuilt_insert_row(
00852
00853 row_prebuilt_t* prebuilt)
00855 {
00856 ins_node_t* node;
00857 dtuple_t* row;
00858 dict_table_t* table = prebuilt->table;
00859
00860 ut_ad(prebuilt && table && prebuilt->trx);
00861
00862 if (prebuilt->ins_node == NULL) {
00863
00864
00865
00866
00867 node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
00868
00869 prebuilt->ins_node = node;
00870
00871 if (prebuilt->ins_upd_rec_buff == NULL) {
00872 prebuilt->ins_upd_rec_buff = static_cast<byte *>(mem_heap_alloc(
00873 prebuilt->heap, prebuilt->mysql_row_len));
00874 }
00875
00876 row = dtuple_create(prebuilt->heap,
00877 dict_table_get_n_cols(table));
00878
00879 dict_table_copy_types(row, table);
00880
00881 ins_node_set_new_row(node, row);
00882
00883 prebuilt->ins_graph = static_cast<que_fork_t *>(que_node_get_parent(
00884 pars_complete_graph_for_exec(node,
00885 prebuilt->trx,
00886 prebuilt->heap)));
00887 prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
00888 }
00889
00890 return(prebuilt->ins_node->row);
00891 }
00892
00893
00896 UNIV_INLINE
00897 void
00898 row_update_statistics_if_needed(
00899
00900 dict_table_t* table)
00901 {
00902 ulint counter;
00903
00904 counter = table->stat_modified_counter;
00905
00906 table->stat_modified_counter = counter + 1;
00907
00908
00909
00910
00911
00912
00913
00914 if (counter > 2000000000
00915 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
00916
00917 dict_update_statistics(table, FALSE
00918 );
00919 }
00920 }
00921
00922
00926 UNIV_INTERN
00927 void
00928 row_unlock_table_autoinc_for_mysql(
00929
00930 trx_t* trx)
00931 {
00932 if (lock_trx_holds_autoinc_locks(trx)) {
00933 mutex_enter(&kernel_mutex);
00934
00935 lock_release_autoinc_locks(trx);
00936
00937 mutex_exit(&kernel_mutex);
00938 }
00939 }
00940
00941
00948 UNIV_INTERN
00949 int
00950 row_lock_table_autoinc_for_mysql(
00951
00952 row_prebuilt_t* prebuilt)
00954 {
00955 trx_t* trx = prebuilt->trx;
00956 ins_node_t* node = prebuilt->ins_node;
00957 const dict_table_t* table = prebuilt->table;
00958 que_thr_t* thr;
00959 ulint err;
00960 ibool was_lock_wait;
00961
00962 ut_ad(trx);
00963 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
00964
00965
00966
00967
00968 if (trx == table->autoinc_trx) {
00969
00970 return(DB_SUCCESS);
00971 }
00972
00973 trx->op_info = "setting auto-inc lock";
00974
00975 if (node == NULL) {
00976 row_get_prebuilt_insert_row(prebuilt);
00977 node = prebuilt->ins_node;
00978 }
00979
00980
00981
00982
00983 thr = que_fork_get_first_thr(prebuilt->ins_graph);
00984
00985 que_thr_move_to_run_state_for_mysql(thr, trx);
00986
00987 run_again:
00988 thr->run_node = node;
00989 thr->prev_node = node;
00990
00991
00992
00993
00994 trx_start_if_not_started(trx);
00995
00996 err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
00997
00998 trx->error_state = err;
00999
01000 if (err != DB_SUCCESS) {
01001 que_thr_stop_for_mysql(thr);
01002
01003 was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
01004
01005 if (was_lock_wait) {
01006 goto run_again;
01007 }
01008
01009 trx->op_info = "";
01010
01011 return((int) err);
01012 }
01013
01014 que_thr_stop_for_mysql_no_error(thr, trx);
01015
01016 trx->op_info = "";
01017
01018 return((int) err);
01019 }
01020
01021
01024 UNIV_INTERN
01025 int
01026 row_lock_table_for_mysql(
01027
01028 row_prebuilt_t* prebuilt,
01030 dict_table_t* table,
01034 ulint mode)
01036 {
01037 trx_t* trx = prebuilt->trx;
01038 que_thr_t* thr;
01039 ulint err;
01040 ibool was_lock_wait;
01041
01042 ut_ad(trx);
01043 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
01044
01045 trx->op_info = "setting table lock";
01046
01047 if (prebuilt->sel_graph == NULL) {
01048
01049 row_prebuild_sel_graph(prebuilt);
01050 }
01051
01052
01053
01054
01055 thr = que_fork_get_first_thr(prebuilt->sel_graph);
01056
01057 que_thr_move_to_run_state_for_mysql(thr, trx);
01058
01059 run_again:
01060 thr->run_node = thr;
01061 thr->prev_node = thr->common.parent;
01062
01063
01064
01065
01066 trx_start_if_not_started(trx);
01067
01068 if (table) {
01069 err = lock_table(0, table, static_cast<lock_mode>(mode), thr);
01070 } else {
01071 err = lock_table(0, prebuilt->table,
01072 static_cast<lock_mode>(prebuilt->select_lock_type), thr);
01073 }
01074
01075 trx->error_state = err;
01076
01077 if (err != DB_SUCCESS) {
01078 que_thr_stop_for_mysql(thr);
01079
01080 was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
01081
01082 if (was_lock_wait) {
01083 goto run_again;
01084 }
01085
01086 trx->op_info = "";
01087
01088 return((int) err);
01089 }
01090
01091 que_thr_stop_for_mysql_no_error(thr, trx);
01092
01093 trx->op_info = "";
01094
01095 return((int) err);
01096 }
01097
01098
01101 UNIV_INTERN
01102 int
01103 row_insert_for_mysql(
01104
01105 byte* mysql_rec,
01106 row_prebuilt_t* prebuilt)
01108 {
01109 trx_savept_t savept;
01110 que_thr_t* thr;
01111 ulint err;
01112 ibool was_lock_wait;
01113 trx_t* trx = prebuilt->trx;
01114 ins_node_t* node = prebuilt->ins_node;
01115
01116 ut_ad(trx);
01117 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
01118
01119 if (prebuilt->table->ibd_file_missing) {
01120 ut_print_timestamp(stderr);
01121 fprintf(stderr, " InnoDB: Error:\n"
01122 "InnoDB: MySQL is trying to use a table handle"
01123 " but the .ibd file for\n"
01124 "InnoDB: table %s does not exist.\n"
01125 "InnoDB: Have you deleted the .ibd file"
01126 " from the database directory under\n"
01127 "InnoDB: the MySQL datadir, or have you"
01128 " used DISCARD TABLESPACE?\n"
01129 "InnoDB: Look from\n"
01130 "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
01131 "InnoDB: how you can resolve the problem.\n",
01132 prebuilt->table->name);
01133 return(DB_ERROR);
01134 }
01135
01136 if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
01137 fprintf(stderr,
01138 "InnoDB: Error: trying to free a corrupt\n"
01139 "InnoDB: table handle. Magic n %lu, table name ",
01140 (ulong) prebuilt->magic_n);
01141 ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
01142 putc('\n', stderr);
01143
01144 mem_analyze_corruption(prebuilt);
01145
01146 ut_error;
01147 }
01148
01149 if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
01150 fputs("InnoDB: A new raw disk partition was initialized or\n"
01151 "InnoDB: innodb_force_recovery is on: we do not allow\n"
01152 "InnoDB: database modifications by the user. Shut down\n"
01153 "InnoDB: mysqld and edit my.cnf so that"
01154 " newraw is replaced\n"
01155 "InnoDB: with raw, and innodb_force_... is removed.\n",
01156 stderr);
01157
01158 return(DB_ERROR);
01159 }
01160
01161 trx->op_info = "inserting";
01162
01163 row_mysql_delay_if_needed();
01164
01165 trx_start_if_not_started(trx);
01166
01167 if (node == NULL) {
01168 row_get_prebuilt_insert_row(prebuilt);
01169 node = prebuilt->ins_node;
01170 }
01171
01172 row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
01173
01174 savept = trx_savept_take(trx);
01175
01176 thr = que_fork_get_first_thr(prebuilt->ins_graph);
01177
01178 if (prebuilt->sql_stat_start) {
01179 node->state = INS_NODE_SET_IX_LOCK;
01180 prebuilt->sql_stat_start = FALSE;
01181 } else {
01182 node->state = INS_NODE_ALLOC_ROW_ID;
01183 }
01184
01185 que_thr_move_to_run_state_for_mysql(thr, trx);
01186
01187 run_again:
01188 thr->run_node = node;
01189 thr->prev_node = node;
01190
01191 row_ins_step(thr);
01192
01193 err = trx->error_state;
01194
01195 if (err != DB_SUCCESS) {
01196 que_thr_stop_for_mysql(thr);
01197
01198 thr->lock_state= QUE_THR_LOCK_ROW;
01199
01200 was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
01201 &savept);
01202 thr->lock_state= QUE_THR_LOCK_NOLOCK;
01203
01204 if (was_lock_wait) {
01205 goto run_again;
01206 }
01207
01208 trx->op_info = "";
01209
01210 return((int) err);
01211 }
01212
01213 que_thr_stop_for_mysql_no_error(thr, trx);
01214
01215 prebuilt->table->stat_n_rows++;
01216
01217 srv_n_rows_inserted++;
01218
01219 if (prebuilt->table->stat_n_rows == 0) {
01220
01221 prebuilt->table->stat_n_rows--;
01222 }
01223
01224 row_update_statistics_if_needed(prebuilt->table);
01225 trx->op_info = "";
01226
01227 return((int) err);
01228 }
01229
01230
01232 UNIV_INTERN
01233 void
01234 row_prebuild_sel_graph(
01235
01236 row_prebuilt_t* prebuilt)
01238 {
01239 sel_node_t* node;
01240
01241 ut_ad(prebuilt && prebuilt->trx);
01242
01243 if (prebuilt->sel_graph == NULL) {
01244
01245 node = sel_node_create(prebuilt->heap);
01246
01247 prebuilt->sel_graph = static_cast<que_fork_t *>(que_node_get_parent(
01248 pars_complete_graph_for_exec(node,
01249 prebuilt->trx,
01250 prebuilt->heap)));
01251
01252 prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
01253 }
01254 }
01255
01256
01260 UNIV_INTERN
01261 upd_node_t*
01262 row_create_update_node_for_mysql(
01263
01264 dict_table_t* table,
01265 mem_heap_t* heap)
01266 {
01267 upd_node_t* node;
01268
01269 node = upd_node_create(heap);
01270
01271 node->in_mysql_interface = TRUE;
01272 node->is_delete = FALSE;
01273 node->searched_update = FALSE;
01274 node->select = NULL;
01275 node->pcur = btr_pcur_create_for_mysql();
01276 node->table = table;
01277
01278 node->update = upd_create(dict_table_get_n_cols(table), heap);
01279
01280 node->update_n_fields = dict_table_get_n_cols(table);
01281
01282 UT_LIST_INIT(node->columns);
01283 node->has_clust_rec_x_lock = TRUE;
01284 node->cmpl_info = 0;
01285
01286 node->table_sym = NULL;
01287 node->col_assign_list = NULL;
01288
01289 return(node);
01290 }
01291
01292
01297 UNIV_INTERN
01298 upd_t*
01299 row_get_prebuilt_update_vector(
01300
01301 row_prebuilt_t* prebuilt)
01303 {
01304 dict_table_t* table = prebuilt->table;
01305 upd_node_t* node;
01306
01307 ut_ad(prebuilt && table && prebuilt->trx);
01308
01309 if (prebuilt->upd_node == NULL) {
01310
01311
01312
01313
01314 node = row_create_update_node_for_mysql(table, prebuilt->heap);
01315
01316 prebuilt->upd_node = node;
01317
01318 prebuilt->upd_graph = static_cast<que_fork_t *>(que_node_get_parent(
01319 pars_complete_graph_for_exec(node,
01320 prebuilt->trx,
01321 prebuilt->heap)));
01322 prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
01323 }
01324
01325 return(prebuilt->upd_node->update);
01326 }
01327
01328
01331 UNIV_INTERN
01332 int
01333 row_update_for_mysql(
01334
01335 byte* mysql_rec,
01337 row_prebuilt_t* prebuilt)
01339 {
01340 trx_savept_t savept;
01341 ulint err;
01342 que_thr_t* thr;
01343 ibool was_lock_wait;
01344 dict_index_t* clust_index;
01345
01346 upd_node_t* node;
01347 dict_table_t* table = prebuilt->table;
01348 trx_t* trx = prebuilt->trx;
01349
01350 ut_ad(prebuilt && trx);
01351 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
01352 UT_NOT_USED(mysql_rec);
01353
01354 if (prebuilt->table->ibd_file_missing) {
01355 ut_print_timestamp(stderr);
01356 fprintf(stderr, " InnoDB: Error:\n"
01357 "InnoDB: MySQL is trying to use a table handle"
01358 " but the .ibd file for\n"
01359 "InnoDB: table %s does not exist.\n"
01360 "InnoDB: Have you deleted the .ibd file"
01361 " from the database directory under\n"
01362 "InnoDB: the MySQL datadir, or have you"
01363 " used DISCARD TABLESPACE?\n"
01364 "InnoDB: Look from\n"
01365 "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
01366 "InnoDB: how you can resolve the problem.\n",
01367 prebuilt->table->name);
01368 return(DB_ERROR);
01369 }
01370
01371 if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
01372 fprintf(stderr,
01373 "InnoDB: Error: trying to free a corrupt\n"
01374 "InnoDB: table handle. Magic n %lu, table name ",
01375 (ulong) prebuilt->magic_n);
01376 ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
01377 putc('\n', stderr);
01378
01379 mem_analyze_corruption(prebuilt);
01380
01381 ut_error;
01382 }
01383
01384 if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
01385 fputs("InnoDB: A new raw disk partition was initialized or\n"
01386 "InnoDB: innodb_force_recovery is on: we do not allow\n"
01387 "InnoDB: database modifications by the user. Shut down\n"
01388 "InnoDB: mysqld and edit my.cnf so that newraw"
01389 " is replaced\n"
01390 "InnoDB: with raw, and innodb_force_... is removed.\n",
01391 stderr);
01392
01393 return(DB_ERROR);
01394 }
01395
01396 trx->op_info = "updating or deleting";
01397
01398 row_mysql_delay_if_needed();
01399
01400 trx_start_if_not_started(trx);
01401
01402 node = prebuilt->upd_node;
01403
01404 clust_index = dict_table_get_first_index(table);
01405
01406 if (prebuilt->pcur->btr_cur.index == clust_index) {
01407 btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
01408 } else {
01409 btr_pcur_copy_stored_position(node->pcur,
01410 prebuilt->clust_pcur);
01411 }
01412
01413 ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
01414
01415
01416
01417
01418
01419
01420
01421
01422 savept = trx_savept_take(trx);
01423
01424 thr = que_fork_get_first_thr(prebuilt->upd_graph);
01425
01426 node->state = UPD_NODE_UPDATE_CLUSTERED;
01427
01428 ut_ad(!prebuilt->sql_stat_start);
01429
01430 que_thr_move_to_run_state_for_mysql(thr, trx);
01431
01432 run_again:
01433 thr->run_node = node;
01434 thr->prev_node = node;
01435 thr->fk_cascade_depth = 0;
01436
01437 row_upd_step(thr);
01438
01439
01440
01441
01442
01443 thr->fk_cascade_depth = 0;
01444
01445 err = trx->error_state;
01446
01447
01448 thr->fk_cascade_depth = 0;
01449
01450 if (err != DB_SUCCESS) {
01451 que_thr_stop_for_mysql(thr);
01452
01453 if (err == DB_RECORD_NOT_FOUND) {
01454 trx->error_state = DB_SUCCESS;
01455 trx->op_info = "";
01456
01457 return((int) err);
01458 }
01459
01460 thr->lock_state= QUE_THR_LOCK_ROW;
01461 was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
01462 &savept);
01463 thr->lock_state= QUE_THR_LOCK_NOLOCK;
01464
01465 if (was_lock_wait) {
01466 goto run_again;
01467 }
01468
01469 trx->op_info = "";
01470
01471 return((int) err);
01472 }
01473
01474 que_thr_stop_for_mysql_no_error(thr, trx);
01475
01476 if (node->is_delete) {
01477 if (prebuilt->table->stat_n_rows > 0) {
01478 prebuilt->table->stat_n_rows--;
01479 }
01480
01481 srv_n_rows_deleted++;
01482 } else {
01483 srv_n_rows_updated++;
01484 }
01485
01486
01487
01488
01489 if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
01490 row_update_statistics_if_needed(prebuilt->table);
01491 }
01492
01493 trx->op_info = "";
01494
01495 return((int) err);
01496 }
01497
01498
01508 UNIV_INTERN
01509 int
01510 row_unlock_for_mysql(
01511
01512 row_prebuilt_t* prebuilt,
01514 ibool has_latches_on_recs)
01519 {
01520 btr_pcur_t* pcur = prebuilt->pcur;
01521 btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
01522 trx_t* trx = prebuilt->trx;
01523
01524 ut_ad(prebuilt && trx);
01525 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
01526
01527 if (UNIV_UNLIKELY
01528 (!srv_locks_unsafe_for_binlog
01529 && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
01530
01531 fprintf(stderr,
01532 "InnoDB: Error: calling row_unlock_for_mysql though\n"
01533 "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
01534 "InnoDB: this session is not using"
01535 " READ COMMITTED isolation level.\n");
01536
01537 return(DB_SUCCESS);
01538 }
01539
01540 trx->op_info = "unlock_row";
01541
01542 if (prebuilt->new_rec_locks >= 1) {
01543
01544 const rec_t* rec;
01545 dict_index_t* index;
01546 trx_id_t rec_trx_id;
01547 mtr_t mtr;
01548
01549 mtr_start(&mtr);
01550
01551
01552
01553 if (!has_latches_on_recs) {
01554 btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
01555 }
01556
01557 rec = btr_pcur_get_rec(pcur);
01558 index = btr_pcur_get_btr_cur(pcur)->index;
01559
01560 if (prebuilt->new_rec_locks >= 2) {
01561
01562
01563
01564 if (!has_latches_on_recs) {
01565 btr_pcur_restore_position(BTR_SEARCH_LEAF,
01566 clust_pcur, &mtr);
01567 }
01568
01569 rec = btr_pcur_get_rec(clust_pcur);
01570 index = btr_pcur_get_btr_cur(clust_pcur)->index;
01571 }
01572
01573 if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
01574
01575
01576 goto no_unlock;
01577 }
01578
01579
01580
01581
01582 if (index->trx_id_offset) {
01583 rec_trx_id = trx_read_trx_id(rec
01584 + index->trx_id_offset);
01585 } else {
01586 mem_heap_t* heap = NULL;
01587 ulint offsets_[REC_OFFS_NORMAL_SIZE];
01588 ulint* offsets = offsets_;
01589
01590 rec_offs_init(offsets_);
01591 offsets = rec_get_offsets(rec, index, offsets,
01592 ULINT_UNDEFINED, &heap);
01593
01594 rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
01595
01596 if (UNIV_LIKELY_NULL(heap)) {
01597 mem_heap_free(heap);
01598 }
01599 }
01600
01601 if (rec_trx_id != trx->id) {
01602
01603
01604 rec = btr_pcur_get_rec(pcur);
01605 index = btr_pcur_get_btr_cur(pcur)->index;
01606
01607 lock_rec_unlock(trx, btr_pcur_get_block(pcur),
01608 rec, static_cast<lock_mode>(prebuilt->select_lock_type));
01609
01610 if (prebuilt->new_rec_locks >= 2) {
01611 rec = btr_pcur_get_rec(clust_pcur);
01612 index = btr_pcur_get_btr_cur(clust_pcur)->index;
01613
01614 lock_rec_unlock(trx,
01615 btr_pcur_get_block(clust_pcur),
01616 rec,
01617 static_cast<lock_mode>(prebuilt->select_lock_type));
01618 }
01619 }
01620 no_unlock:
01621 mtr_commit(&mtr);
01622 }
01623
01624 trx->op_info = "";
01625
01626 return(DB_SUCCESS);
01627 }
01628
01629
01632 UNIV_INTERN
01633 ulint
01634 row_update_cascade_for_mysql(
01635
01636 que_thr_t* thr,
01637 upd_node_t* node,
01639 dict_table_t* table)
01640 {
01641 ulint err;
01642 trx_t* trx;
01643
01644 trx = thr_get_trx(thr);
01645
01646
01647
01648
01649 thr->fk_cascade_depth++;
01650
01651 if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
01652 return (DB_FOREIGN_EXCEED_MAX_CASCADE);
01653 }
01654 run_again:
01655 thr->run_node = node;
01656 thr->prev_node = node;
01657
01658 row_upd_step(thr);
01659
01660
01661
01662
01663
01664 thr->fk_cascade_depth = 0;
01665
01666 err = trx->error_state;
01667
01668
01669
01670
01671
01672 if (err == DB_LOCK_WAIT) {
01673
01674
01675 que_thr_stop_for_mysql(thr);
01676
01677 srv_suspend_mysql_thread(thr);
01678
01679
01680
01681
01682
01683 if (trx->error_state != DB_SUCCESS) {
01684
01685 return(trx->error_state);
01686 }
01687
01688
01689
01690 goto run_again;
01691 }
01692
01693 if (err != DB_SUCCESS) {
01694
01695 return(err);
01696 }
01697
01698 if (node->is_delete) {
01699 if (table->stat_n_rows > 0) {
01700 table->stat_n_rows--;
01701 }
01702
01703 srv_n_rows_deleted++;
01704 } else {
01705 srv_n_rows_updated++;
01706 }
01707
01708 row_update_statistics_if_needed(table);
01709
01710 return(err);
01711 }
01712
01713
01717 UNIV_INTERN
01718 ibool
01719 row_table_got_default_clust_index(
01720
01721 const dict_table_t* table)
01722 {
01723 const dict_index_t* clust_index;
01724
01725 clust_index = dict_table_get_first_index(table);
01726
01727 return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
01728 }
01729
01730
01733 UNIV_INTERN
01734 void
01735 row_mysql_freeze_data_dictionary_func(
01736
01737 trx_t* trx,
01738 const char* file,
01739 ulint line)
01740 {
01741 ut_a(trx->dict_operation_lock_mode == 0);
01742
01743 rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
01744
01745 trx->dict_operation_lock_mode = RW_S_LATCH;
01746 }
01747
01748
01750 UNIV_INTERN
01751 void
01752 row_mysql_unfreeze_data_dictionary(
01753
01754 trx_t* trx)
01755 {
01756 ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
01757
01758 rw_lock_s_unlock(&dict_operation_lock);
01759
01760 trx->dict_operation_lock_mode = 0;
01761 }
01762
01763
01766 UNIV_INTERN
01767 void
01768 row_mysql_lock_data_dictionary_func(
01769
01770 trx_t* trx,
01771 const char* file,
01772 ulint line)
01773 {
01774 ut_a(trx->dict_operation_lock_mode == 0
01775 || trx->dict_operation_lock_mode == RW_X_LATCH);
01776
01777
01778
01779
01780 rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
01781 trx->dict_operation_lock_mode = RW_X_LATCH;
01782
01783 mutex_enter(&(dict_sys->mutex));
01784 }
01785
01786
01788 UNIV_INTERN
01789 void
01790 row_mysql_unlock_data_dictionary(
01791
01792 trx_t* trx)
01793 {
01794 ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
01795
01796
01797
01798
01799 mutex_exit(&(dict_sys->mutex));
01800 rw_lock_x_unlock(&dict_operation_lock);
01801
01802 trx->dict_operation_lock_mode = 0;
01803 }
01804
01805
01812 UNIV_INTERN
01813 int
01814 row_create_table_for_mysql(
01815
01816 dict_table_t* table,
01818 trx_t* trx)
01819 {
01820 tab_node_t* node;
01821 mem_heap_t* heap;
01822 que_thr_t* thr;
01823 const char* table_name;
01824 ulint table_name_len;
01825 ulint err;
01826
01827 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
01828 #ifdef UNIV_SYNC_DEBUG
01829 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
01830 #endif
01831 ut_ad(mutex_own(&(dict_sys->mutex)));
01832 ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
01833
01834 if (srv_created_new_raw) {
01835 fputs("InnoDB: A new raw disk partition was initialized:\n"
01836 "InnoDB: we do not allow database modifications"
01837 " by the user.\n"
01838 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
01839 " is replaced with raw.\n", stderr);
01840 dict_mem_table_free(table);
01841 trx_commit_for_mysql(trx);
01842
01843 return(DB_ERROR);
01844 }
01845
01846 trx->op_info = "creating table";
01847
01848 trx_start_if_not_started(trx);
01849
01850
01851
01852
01853
01854 table_name = strchr(table->name, '/');
01855 ut_a(table_name);
01856 table_name++;
01857 table_name_len = strlen(table_name) + 1;
01858
01859 if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
01860
01861
01862
01863
01864 srv_print_innodb_monitor = TRUE;
01865
01866
01867
01868
01869 os_event_set(srv_lock_timeout_thread_event);
01870 } else if (STR_EQ(table_name, table_name_len,
01871 S_innodb_lock_monitor)) {
01872
01873 srv_print_innodb_monitor = TRUE;
01874 srv_print_innodb_lock_monitor = TRUE;
01875 os_event_set(srv_lock_timeout_thread_event);
01876 } else if (STR_EQ(table_name, table_name_len,
01877 S_innodb_tablespace_monitor)) {
01878
01879 srv_print_innodb_tablespace_monitor = TRUE;
01880 os_event_set(srv_lock_timeout_thread_event);
01881 } else if (STR_EQ(table_name, table_name_len,
01882 S_innodb_table_monitor)) {
01883
01884 srv_print_innodb_table_monitor = TRUE;
01885 os_event_set(srv_lock_timeout_thread_event);
01886 } else if (STR_EQ(table_name, table_name_len,
01887 S_innodb_mem_validate)) {
01888
01889
01890
01891 fputs("Validating InnoDB memory:\n"
01892 "to use this feature you must compile InnoDB with\n"
01893 "UNIV_MEM_DEBUG defined in univ.i and"
01894 " the server must be\n"
01895 "quiet because allocation from a mem heap"
01896 " is not protected\n"
01897 "by any semaphore.\n", stderr);
01898 #ifdef UNIV_MEM_DEBUG
01899 ut_a(mem_validate());
01900 fputs("Memory validated\n", stderr);
01901 #else
01902 fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
01903 stderr);
01904 #endif
01905 }
01906
01907 heap = mem_heap_create(512);
01908
01909 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
01910
01911 node = tab_create_graph_create(table, heap);
01912
01913 thr = pars_complete_graph_for_exec(node, trx, heap);
01914
01915 ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
01916 que_run_threads(thr);
01917
01918 err = trx->error_state;
01919
01920 switch (err) {
01921 case DB_SUCCESS:
01922 break;
01923 case DB_OUT_OF_FILE_SPACE:
01924 trx->error_state = DB_SUCCESS;
01925 trx_general_rollback_for_mysql(trx, NULL);
01926
01927 ut_print_timestamp(stderr);
01928 fputs(" InnoDB: Warning: cannot create table ",
01929 stderr);
01930 ut_print_name(stderr, trx, TRUE, table->name);
01931 fputs(" because tablespace full\n", stderr);
01932
01933 if (dict_table_get_low(table->name)) {
01934
01935 row_drop_table_for_mysql(table->name, trx, FALSE);
01936 trx_commit_for_mysql(trx);
01937 }
01938 break;
01939
01940 case DB_DUPLICATE_KEY:
01941 default:
01942
01943
01944
01945 trx->error_state = DB_SUCCESS;
01946 trx_general_rollback_for_mysql(trx, NULL);
01947 dict_mem_table_free(table);
01948 break;
01949 }
01950
01951 que_graph_free((que_t*) que_node_get_parent(thr));
01952
01953 trx->op_info = "";
01954
01955 return((int) err);
01956 }
01957
01958
01963 UNIV_INTERN
01964 int
01965 row_create_index_for_mysql(
01966
01967 dict_index_t* index,
01969 trx_t* trx,
01970 const ulint* field_lengths)
01976 {
01977 ind_node_t* node;
01978 mem_heap_t* heap;
01979 que_thr_t* thr;
01980 ulint err;
01981 ulint i;
01982 ulint len;
01983 char* table_name;
01984
01985 #ifdef UNIV_SYNC_DEBUG
01986 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
01987 #endif
01988 ut_ad(mutex_own(&(dict_sys->mutex)));
01989 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
01990
01991 trx->op_info = "creating index";
01992
01993
01994
01995
01996 table_name = mem_strdup(index->table_name);
01997
01998 trx_start_if_not_started(trx);
01999
02000
02001
02002
02003
02004 for (i = 0; i < dict_index_get_n_fields(index); i++) {
02005 ulint j;
02006
02007 for (j = 0; j < i; j++) {
02008 if (0 == ut_strcmp(
02009 dict_index_get_nth_field(index, j)->name,
02010 dict_index_get_nth_field(index, i)->name)) {
02011 ut_print_timestamp(stderr);
02012
02013 fputs(" InnoDB: Error: column ", stderr);
02014 ut_print_name(stderr, trx, FALSE,
02015 dict_index_get_nth_field(
02016 index, i)->name);
02017 fputs(" appears twice in ", stderr);
02018 dict_index_name_print(stderr, trx, index);
02019 fputs("\n"
02020 "InnoDB: This is not allowed"
02021 " in InnoDB.\n", stderr);
02022
02023 err = DB_COL_APPEARS_TWICE_IN_INDEX;
02024
02025 goto error_handling;
02026 }
02027 }
02028
02029
02030
02031
02032 len = dict_index_get_nth_field(index, i)->prefix_len;
02033
02034 if (field_lengths) {
02035 len = ut_max(len, field_lengths[i]);
02036 }
02037
02038 if (len >= DICT_MAX_INDEX_COL_LEN) {
02039 err = DB_TOO_BIG_RECORD;
02040
02041 goto error_handling;
02042 }
02043 }
02044
02045 heap = mem_heap_create(512);
02046
02047 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
02048
02049
02050
02051
02052 node = ind_create_graph_create(index, heap);
02053
02054 thr = pars_complete_graph_for_exec(node, trx, heap);
02055
02056 ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
02057 que_run_threads(thr);
02058
02059 err = trx->error_state;
02060
02061 que_graph_free((que_t*) que_node_get_parent(thr));
02062
02063 error_handling:
02064 if (err != DB_SUCCESS) {
02065
02066
02067 trx->error_state = DB_SUCCESS;
02068
02069 trx_general_rollback_for_mysql(trx, NULL);
02070
02071 row_drop_table_for_mysql(table_name, trx, FALSE);
02072
02073 trx_commit_for_mysql(trx);
02074
02075 trx->error_state = DB_SUCCESS;
02076 }
02077
02078 trx->op_info = "";
02079
02080 mem_free(table_name);
02081
02082 return((int) err);
02083 }
02084
02085
02094 UNIV_INTERN
02095 int
02096 row_table_add_foreign_constraints(
02097
02098 trx_t* trx,
02099 const char* sql_string,
02104 size_t sql_length,
02105 const char* name,
02108 ibool reject_fks)
02111 {
02112 ulint err;
02113
02114 ut_ad(mutex_own(&(dict_sys->mutex)));
02115 #ifdef UNIV_SYNC_DEBUG
02116 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
02117 #endif
02118 ut_a(sql_string);
02119
02120 trx->op_info = "adding foreign keys";
02121
02122 trx_start_if_not_started(trx);
02123
02124 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
02125
02126 err = dict_create_foreign_constraints(trx, sql_string, sql_length,
02127 name, reject_fks);
02128 if (err == DB_SUCCESS) {
02129
02130 err = dict_load_foreigns(name, FALSE, TRUE);
02131 }
02132
02133 if (err != DB_SUCCESS) {
02134
02135
02136 trx->error_state = DB_SUCCESS;
02137
02138 trx_general_rollback_for_mysql(trx, NULL);
02139
02140 row_drop_table_for_mysql(name, trx, FALSE);
02141
02142 trx_commit_for_mysql(trx);
02143
02144 trx->error_state = DB_SUCCESS;
02145 }
02146
02147 return((int) err);
02148 }
02149
02150
02158 static
02159 int
02160 row_drop_table_for_mysql_in_background(
02161
02162 const char* name)
02163 {
02164 ulint error;
02165 trx_t* trx;
02166
02167 trx = trx_allocate_for_background();
02168
02169
02170
02171
02172
02173 trx->check_foreigns = FALSE;
02174
02175
02176
02177
02178
02179
02180
02181 error = row_drop_table_for_mysql(name, trx, FALSE);
02182
02183
02184
02185
02186
02187 log_buffer_flush_to_disk();
02188
02189 trx_commit_for_mysql(trx);
02190
02191 trx_free_for_background(trx);
02192
02193 return((int) error);
02194 }
02195
02196
02201 UNIV_INTERN
02202 ulint
02203 row_drop_tables_for_mysql_in_background(void)
02204
02205 {
02206 row_mysql_drop_t* drop;
02207 dict_table_t* table;
02208 ulint n_tables;
02209 ulint n_tables_dropped = 0;
02210 loop:
02211 mutex_enter(&kernel_mutex);
02212
02213 if (!row_mysql_drop_list_inited) {
02214
02215 UT_LIST_INIT(row_mysql_drop_list);
02216 row_mysql_drop_list_inited = TRUE;
02217 }
02218
02219 drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
02220
02221 n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
02222
02223 mutex_exit(&kernel_mutex);
02224
02225 if (drop == NULL) {
02226
02227
02228 return(n_tables + n_tables_dropped);
02229 }
02230
02231 mutex_enter(&(dict_sys->mutex));
02232 table = dict_table_get_low(drop->table_name);
02233 mutex_exit(&(dict_sys->mutex));
02234
02235 if (table == NULL) {
02236
02237
02238
02239 goto already_dropped;
02240 }
02241
02242 if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
02243 drop->table_name)) {
02244
02245
02246
02247 return(n_tables + n_tables_dropped);
02248 }
02249
02250 n_tables_dropped++;
02251
02252 already_dropped:
02253 mutex_enter(&kernel_mutex);
02254
02255 UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
02256
02257 ut_print_timestamp(stderr);
02258 fputs(" InnoDB: Dropped table ", stderr);
02259 ut_print_name(stderr, NULL, TRUE, drop->table_name);
02260 fputs(" in background drop queue.\n", stderr);
02261
02262 mem_free(drop->table_name);
02263
02264 mem_free(drop);
02265
02266 mutex_exit(&kernel_mutex);
02267
02268 goto loop;
02269 }
02270
02271
02275 UNIV_INTERN
02276 ulint
02277 row_get_background_drop_list_len_low(void)
02278
02279 {
02280 ut_ad(mutex_own(&kernel_mutex));
02281
02282 if (!row_mysql_drop_list_inited) {
02283
02284 UT_LIST_INIT(row_mysql_drop_list);
02285 row_mysql_drop_list_inited = TRUE;
02286 }
02287
02288 return(UT_LIST_GET_LEN(row_mysql_drop_list));
02289 }
02290
02291
02298 static
02299 ibool
02300 row_add_table_to_background_drop_list(
02301
02302 const char* name)
02303 {
02304 row_mysql_drop_t* drop;
02305
02306 mutex_enter(&kernel_mutex);
02307
02308 if (!row_mysql_drop_list_inited) {
02309
02310 UT_LIST_INIT(row_mysql_drop_list);
02311 row_mysql_drop_list_inited = TRUE;
02312 }
02313
02314
02315 drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
02316
02317 while (drop != NULL) {
02318 if (strcmp(drop->table_name, name) == 0) {
02319
02320
02321 mutex_exit(&kernel_mutex);
02322
02323 return(FALSE);
02324 }
02325
02326 drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
02327 }
02328
02329 drop = static_cast<row_mysql_drop_t *>(mem_alloc(sizeof(row_mysql_drop_t)));
02330
02331 drop->table_name = mem_strdup(name);
02332
02333 UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
02334
02335
02336
02337
02338
02339 mutex_exit(&kernel_mutex);
02340
02341 return(TRUE);
02342 }
02343
02344
02349 UNIV_INTERN
02350 int
02351 row_discard_tablespace_for_mysql(
02352
02353 const char* name,
02354 trx_t* trx)
02355 {
02356 dict_foreign_t* foreign;
02357 table_id_t new_id;
02358 dict_table_t* table;
02359 ibool success;
02360 ulint err;
02361 pars_info_t* info = NULL;
02362
02363
02364
02365
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
02393
02394 trx->op_info = "discarding tablespace";
02395 trx_start_if_not_started(trx);
02396
02397
02398
02399
02400 row_mysql_lock_data_dictionary(trx);
02401
02402 table = dict_table_get_low(name);
02403
02404 if (!table) {
02405 err = DB_TABLE_NOT_FOUND;
02406
02407 goto funct_exit;
02408 }
02409
02410 if (table->space == 0) {
02411 ut_print_timestamp(stderr);
02412 fputs(" InnoDB: Error: table ", stderr);
02413 ut_print_name(stderr, trx, TRUE, name);
02414 fputs("\n"
02415 "InnoDB: is in the system tablespace 0"
02416 " which cannot be discarded\n", stderr);
02417 err = DB_ERROR;
02418
02419 goto funct_exit;
02420 }
02421
02422 if (table->n_foreign_key_checks_running > 0) {
02423
02424 ut_print_timestamp(stderr);
02425 fputs(" InnoDB: You are trying to DISCARD table ", stderr);
02426 ut_print_name(stderr, trx, TRUE, table->name);
02427 fputs("\n"
02428 "InnoDB: though there is a foreign key check"
02429 " running on it.\n"
02430 "InnoDB: Cannot discard the table.\n",
02431 stderr);
02432
02433 err = DB_ERROR;
02434
02435 goto funct_exit;
02436 }
02437
02438
02439
02440
02441 foreign = UT_LIST_GET_FIRST(table->referenced_list);
02442
02443 while (foreign && foreign->foreign_table == table) {
02444 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
02445 }
02446
02447 if (foreign && trx->check_foreigns) {
02448
02449 FILE* ef = dict_foreign_err_file;
02450
02451
02452
02453
02454 err = DB_CANNOT_DROP_CONSTRAINT;
02455
02456 mutex_enter(&dict_foreign_err_mutex);
02457 rewind(ef);
02458 ut_print_timestamp(ef);
02459
02460 fputs(" Cannot DISCARD table ", ef);
02461 ut_print_name(stderr, trx, TRUE, name);
02462 fputs("\n"
02463 "because it is referenced by ", ef);
02464 ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
02465 putc('\n', ef);
02466 mutex_exit(&dict_foreign_err_mutex);
02467
02468 goto funct_exit;
02469 }
02470
02471 dict_hdr_get_new_id(&new_id, NULL, NULL);
02472
02473
02474 lock_remove_all_on_table(table, FALSE);
02475
02476 info = pars_info_create();
02477
02478 pars_info_add_str_literal(info, "table_name", name);
02479 pars_info_add_ull_literal(info, "new_id", new_id);
02480
02481 err = que_eval_sql(info,
02482 "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
02483 "old_id CHAR;\n"
02484 "BEGIN\n"
02485 "SELECT ID INTO old_id\n"
02486 "FROM SYS_TABLES\n"
02487 "WHERE NAME = :table_name\n"
02488 "LOCK IN SHARE MODE;\n"
02489 "IF (SQL % NOTFOUND) THEN\n"
02490 " COMMIT WORK;\n"
02491 " RETURN;\n"
02492 "END IF;\n"
02493 "UPDATE SYS_TABLES SET ID = :new_id\n"
02494 " WHERE ID = old_id;\n"
02495 "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
02496 " WHERE TABLE_ID = old_id;\n"
02497 "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
02498 " WHERE TABLE_ID = old_id;\n"
02499 "COMMIT WORK;\n"
02500 "END;\n"
02501 , FALSE, trx);
02502
02503 if (err != DB_SUCCESS) {
02504 trx->error_state = DB_SUCCESS;
02505 trx_general_rollback_for_mysql(trx, NULL);
02506 trx->error_state = DB_SUCCESS;
02507 } else {
02508 dict_table_change_id_in_cache(table, new_id);
02509
02510 success = fil_discard_tablespace(table->space);
02511
02512 if (!success) {
02513 trx->error_state = DB_SUCCESS;
02514 trx_general_rollback_for_mysql(trx, NULL);
02515 trx->error_state = DB_SUCCESS;
02516
02517 err = DB_ERROR;
02518 } else {
02519
02520
02521 table->tablespace_discarded = TRUE;
02522 table->ibd_file_missing = TRUE;
02523 }
02524 }
02525
02526 funct_exit:
02527 trx_commit_for_mysql(trx);
02528
02529 row_mysql_unlock_data_dictionary(trx);
02530
02531 trx->op_info = "";
02532
02533 return((int) err);
02534 }
02535
02536
02540 UNIV_INTERN
02541 int
02542 row_import_tablespace_for_mysql(
02543
02544 const char* name,
02545 trx_t* trx)
02546 {
02547 dict_table_t* table;
02548 ibool success;
02549 ib_uint64_t current_lsn;
02550 ulint err = DB_SUCCESS;
02551
02552 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
02553
02554 trx_start_if_not_started(trx);
02555
02556 trx->op_info = "importing tablespace";
02557
02558 current_lsn = log_get_lsn();
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570
02571
02572 success = fil_reset_too_high_lsns(name, current_lsn);
02573
02574 if (!success) {
02575 ut_print_timestamp(stderr);
02576 fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
02577 ut_print_name(stderr, trx, TRUE, name);
02578 fputs("\n"
02579 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
02580 stderr);
02581
02582 err = DB_ERROR;
02583
02584 row_mysql_lock_data_dictionary(trx);
02585
02586 goto funct_exit;
02587 }
02588
02589
02590
02591
02592 row_mysql_lock_data_dictionary(trx);
02593
02594 table = dict_table_get_low(name);
02595
02596 if (!table) {
02597 ut_print_timestamp(stderr);
02598 fputs(" InnoDB: table ", stderr);
02599 ut_print_name(stderr, trx, TRUE, name);
02600 fputs("\n"
02601 "InnoDB: does not exist in the InnoDB data dictionary\n"
02602 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
02603 stderr);
02604
02605 err = DB_TABLE_NOT_FOUND;
02606
02607 goto funct_exit;
02608 }
02609
02610 if (table->space == 0) {
02611 ut_print_timestamp(stderr);
02612 fputs(" InnoDB: Error: table ", stderr);
02613 ut_print_name(stderr, trx, TRUE, name);
02614 fputs("\n"
02615 "InnoDB: is in the system tablespace 0"
02616 " which cannot be imported\n", stderr);
02617 err = DB_ERROR;
02618
02619 goto funct_exit;
02620 }
02621
02622 if (!table->tablespace_discarded) {
02623 ut_print_timestamp(stderr);
02624 fputs(" InnoDB: Error: you are trying to"
02625 " IMPORT a tablespace\n"
02626 "InnoDB: ", stderr);
02627 ut_print_name(stderr, trx, TRUE, name);
02628 fputs(", though you have not called DISCARD on it yet\n"
02629 "InnoDB: during the lifetime of the mysqld process!\n",
02630 stderr);
02631
02632 err = DB_ERROR;
02633
02634 goto funct_exit;
02635 }
02636
02637
02638
02639
02640 ibuf_delete_for_discarded_space(table->space);
02641
02642 success = fil_open_single_table_tablespace(
02643 TRUE, table->space,
02644 table->flags == DICT_TF_COMPACT ? 0 : table->flags,
02645 table->name);
02646 if (success) {
02647 table->ibd_file_missing = FALSE;
02648 table->tablespace_discarded = FALSE;
02649 } else {
02650 if (table->ibd_file_missing) {
02651 ut_print_timestamp(stderr);
02652 fputs(" InnoDB: cannot find or open in the"
02653 " database directory the .ibd file of\n"
02654 "InnoDB: table ", stderr);
02655 ut_print_name(stderr, trx, TRUE, name);
02656 fputs("\n"
02657 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
02658 stderr);
02659 }
02660
02661 err = DB_ERROR;
02662 }
02663
02664 funct_exit:
02665 trx_commit_for_mysql(trx);
02666
02667 row_mysql_unlock_data_dictionary(trx);
02668
02669 trx->op_info = "";
02670
02671 return((int) err);
02672 }
02673
02674
02677 UNIV_INTERN
02678 int
02679 row_truncate_table_for_mysql(
02680
02681 dict_table_t* table,
02682 trx_t* trx)
02683 {
02684 dict_foreign_t* foreign;
02685 ulint err;
02686 mem_heap_t* heap;
02687 byte* buf;
02688 dtuple_t* tuple;
02689 dfield_t* dfield;
02690 dict_index_t* sys_index;
02691 btr_pcur_t pcur;
02692 mtr_t mtr;
02693 table_id_t new_id;
02694 ulint recreate_space = 0;
02695 pars_info_t* info = NULL;
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
02738 ut_ad(table);
02739
02740 if (srv_created_new_raw) {
02741 fputs("InnoDB: A new raw disk partition was initialized:\n"
02742 "InnoDB: we do not allow database modifications"
02743 " by the user.\n"
02744 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
02745 " is replaced with raw.\n", stderr);
02746
02747 return(DB_ERROR);
02748 }
02749
02750 trx->op_info = "truncating table";
02751
02752 trx_start_if_not_started(trx);
02753
02754
02755
02756
02757 ut_a(trx->dict_operation_lock_mode == 0);
02758
02759
02760
02761 row_mysql_lock_data_dictionary(trx);
02762
02763 ut_ad(mutex_own(&(dict_sys->mutex)));
02764 #ifdef UNIV_SYNC_DEBUG
02765 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
02766 #endif
02767
02768
02769
02770
02771 foreign = UT_LIST_GET_FIRST(table->referenced_list);
02772
02773 while (foreign && foreign->foreign_table == table) {
02774 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
02775 }
02776
02777 if (foreign && trx->check_foreigns) {
02778 FILE* ef = dict_foreign_err_file;
02779
02780
02781
02782
02783 mutex_enter(&dict_foreign_err_mutex);
02784 rewind(ef);
02785 ut_print_timestamp(ef);
02786
02787 fputs(" Cannot truncate table ", ef);
02788 ut_print_name(ef, trx, TRUE, table->name);
02789 fputs(" by DROP+CREATE\n"
02790 "InnoDB: because it is referenced by ", ef);
02791 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
02792 putc('\n', ef);
02793 mutex_exit(&dict_foreign_err_mutex);
02794
02795 err = DB_ERROR;
02796 goto funct_exit;
02797 }
02798
02799
02800
02801
02802
02803
02804
02805 if (table->n_foreign_key_checks_running > 0) {
02806 ut_print_timestamp(stderr);
02807 fputs(" InnoDB: Cannot truncate table ", stderr);
02808 ut_print_name(stderr, trx, TRUE, table->name);
02809 fputs(" by DROP+CREATE\n"
02810 "InnoDB: because there is a foreign key check"
02811 " running on it.\n",
02812 stderr);
02813 err = DB_ERROR;
02814
02815 goto funct_exit;
02816 }
02817
02818
02819 lock_remove_all_on_table(table, FALSE);
02820
02821 trx->table_id = table->id;
02822
02823 if (table->space && !table->dir_path_of_temp_table) {
02824
02825 ulint space = table->space;
02826 ulint flags = fil_space_get_flags(space);
02827
02828 if (flags != ULINT_UNDEFINED
02829 && fil_discard_tablespace(space)) {
02830
02831 dict_index_t* index;
02832
02833 dict_hdr_get_new_id(NULL, NULL, &space);
02834
02835
02836
02837
02838 dict_table_x_lock_indexes(table);
02839
02840 if (space == ULINT_UNDEFINED
02841 || fil_create_new_single_table_tablespace(
02842 space, table->name, FALSE, flags,
02843 FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
02844 dict_table_x_unlock_indexes(table);
02845 ut_print_timestamp(stderr);
02846 fprintf(stderr,
02847 " InnoDB: TRUNCATE TABLE %s failed to"
02848 " create a new tablespace\n",
02849 table->name);
02850 table->ibd_file_missing = 1;
02851 err = DB_ERROR;
02852 goto funct_exit;
02853 }
02854
02855 recreate_space = space;
02856
02857
02858
02859
02860
02861 table->space = space;
02862 index = dict_table_get_first_index(table);
02863 do {
02864 index->space = space;
02865 index = dict_table_get_next_index(index);
02866 } while (index);
02867
02868 mtr_start(&mtr);
02869 fsp_header_init(space,
02870 FIL_IBD_FILE_INITIAL_SIZE, &mtr);
02871 mtr_commit(&mtr);
02872 }
02873 } else {
02874
02875
02876
02877
02878
02879
02880
02881 dict_table_x_lock_indexes(table);
02882 }
02883
02884
02885 heap = mem_heap_create(800);
02886
02887 tuple = dtuple_create(heap, 1);
02888 dfield = dtuple_get_nth_field(tuple, 0);
02889
02890 buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
02891 mach_write_to_8(buf, table->id);
02892
02893 dfield_set_data(dfield, buf, 8);
02894 sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
02895 dict_index_copy_types(tuple, sys_index, 1);
02896
02897 mtr_start(&mtr);
02898 btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
02899 BTR_MODIFY_LEAF, &pcur, &mtr);
02900 for (;;) {
02901 rec_t* rec;
02902 const byte* field;
02903 ulint len;
02904 ulint root_page_no;
02905
02906 if (!btr_pcur_is_on_user_rec(&pcur)) {
02907
02908 break;
02909 }
02910
02911 rec = btr_pcur_get_rec(&pcur);
02912
02913 field = rec_get_nth_field_old(rec, 0, &len);
02914 ut_ad(len == 8);
02915
02916 if (memcmp(buf, field, len) != 0) {
02917
02918 break;
02919 }
02920
02921 if (rec_get_deleted_flag(rec, FALSE)) {
02922
02923 goto next_rec;
02924 }
02925
02926
02927
02928 root_page_no = dict_truncate_index_tree(table, recreate_space,
02929 &pcur, &mtr);
02930
02931 rec = btr_pcur_get_rec(&pcur);
02932
02933 if (root_page_no != FIL_NULL) {
02934 page_rec_write_index_page_no(
02935 rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
02936 root_page_no, &mtr);
02937
02938
02939
02940
02941
02942 mtr_commit(&mtr);
02943 mtr_start(&mtr);
02944 btr_pcur_restore_position(BTR_MODIFY_LEAF,
02945 &pcur, &mtr);
02946 }
02947
02948 next_rec:
02949 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
02950 }
02951
02952 btr_pcur_close(&pcur);
02953 mtr_commit(&mtr);
02954
02955 mem_heap_free(heap);
02956
02957
02958
02959 dict_table_x_unlock_indexes(table);
02960
02961 dict_hdr_get_new_id(&new_id, NULL, NULL);
02962
02963 info = pars_info_create();
02964
02965 pars_info_add_int4_literal(info, "space", (lint) table->space);
02966 pars_info_add_ull_literal(info, "old_id", table->id);
02967 pars_info_add_ull_literal(info, "new_id", new_id);
02968
02969 err = que_eval_sql(info,
02970 "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
02971 "BEGIN\n"
02972 "UPDATE SYS_TABLES"
02973 " SET ID = :new_id, SPACE = :space\n"
02974 " WHERE ID = :old_id;\n"
02975 "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
02976 " WHERE TABLE_ID = :old_id;\n"
02977 "UPDATE SYS_INDEXES"
02978 " SET TABLE_ID = :new_id, SPACE = :space\n"
02979 " WHERE TABLE_ID = :old_id;\n"
02980 "COMMIT WORK;\n"
02981 "END;\n"
02982 , FALSE, trx);
02983
02984 if (err != DB_SUCCESS) {
02985 trx->error_state = DB_SUCCESS;
02986 trx_general_rollback_for_mysql(trx, NULL);
02987 trx->error_state = DB_SUCCESS;
02988 ut_print_timestamp(stderr);
02989 fputs(" InnoDB: Unable to assign a new identifier to table ",
02990 stderr);
02991 ut_print_name(stderr, trx, TRUE, table->name);
02992 fputs("\n"
02993 "InnoDB: after truncating it. Background processes"
02994 " may corrupt the table!\n", stderr);
02995 err = DB_ERROR;
02996 } else {
02997 dict_table_change_id_in_cache(table, new_id);
02998 }
02999
03000
03001
03002
03003
03004 dict_table_autoinc_lock(table);
03005 dict_table_autoinc_initialize(table, 1);
03006 dict_table_autoinc_unlock(table);
03007 dict_update_statistics(table, FALSE
03008 );
03009
03010 trx_commit_for_mysql(trx);
03011
03012 funct_exit:
03013
03014 row_mysql_unlock_data_dictionary(trx);
03015
03016 trx->op_info = "";
03017
03018 srv_wake_master_thread();
03019
03020 return((int) err);
03021 }
03022
03023
03031 UNIV_INTERN
03032 int
03033 row_drop_table_for_mysql(
03034
03035 const char* name,
03036 trx_t* trx,
03037 ibool drop_db)
03038 {
03039 dict_foreign_t* foreign;
03040 dict_table_t* table;
03041 ulint space_id;
03042 ulint err;
03043 const char* table_name;
03044 ulint namelen;
03045 ibool locked_dictionary = FALSE;
03046 pars_info_t* info = NULL;
03047
03048 ut_a(name != NULL);
03049
03050 if (srv_created_new_raw) {
03051 fputs("InnoDB: A new raw disk partition was initialized:\n"
03052 "InnoDB: we do not allow database modifications"
03053 " by the user.\n"
03054 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
03055 " is replaced with raw.\n", stderr);
03056
03057 return(DB_ERROR);
03058 }
03059
03060 trx->op_info = "dropping table";
03061
03062 trx_start_if_not_started(trx);
03063
03064
03065
03066
03067
03068 table_name = strchr(name, '/');
03069 ut_a(table_name);
03070 table_name++;
03071 namelen = strlen(table_name) + 1;
03072
03073 if (namelen == sizeof S_innodb_monitor
03074 && !memcmp(table_name, S_innodb_monitor,
03075 sizeof S_innodb_monitor)) {
03076
03077
03078
03079
03080 srv_print_innodb_monitor = FALSE;
03081 srv_print_innodb_lock_monitor = FALSE;
03082 } else if (namelen == sizeof S_innodb_lock_monitor
03083 && !memcmp(table_name, S_innodb_lock_monitor,
03084 sizeof S_innodb_lock_monitor)) {
03085 srv_print_innodb_monitor = FALSE;
03086 srv_print_innodb_lock_monitor = FALSE;
03087 } else if (namelen == sizeof S_innodb_tablespace_monitor
03088 && !memcmp(table_name, S_innodb_tablespace_monitor,
03089 sizeof S_innodb_tablespace_monitor)) {
03090
03091 srv_print_innodb_tablespace_monitor = FALSE;
03092 } else if (namelen == sizeof S_innodb_table_monitor
03093 && !memcmp(table_name, S_innodb_table_monitor,
03094 sizeof S_innodb_table_monitor)) {
03095
03096 srv_print_innodb_table_monitor = FALSE;
03097 }
03098
03099
03100
03101
03102 if (trx->dict_operation_lock_mode != RW_X_LATCH) {
03103
03104
03105
03106 row_mysql_lock_data_dictionary(trx);
03107
03108 locked_dictionary = TRUE;
03109 }
03110
03111 ut_ad(mutex_own(&(dict_sys->mutex)));
03112 #ifdef UNIV_SYNC_DEBUG
03113 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
03114 #endif
03115
03116 table = dict_table_get_low(name);
03117
03118 if (!table) {
03119 #if defined(BUILD_DRIZZLE)
03120 err = ENOENT;
03121 #else
03122 err = DB_TABLE_NOT_FOUND;
03123 ut_print_timestamp(stderr);
03124
03125 fputs(" InnoDB: Error: table ", stderr);
03126 ut_print_name(stderr, trx, TRUE, name);
03127 fputs(" does not exist in the InnoDB internal\n"
03128 "InnoDB: data dictionary though MySQL is"
03129 " trying to drop it.\n"
03130 "InnoDB: Have you copied the .frm file"
03131 " of the table to the\n"
03132 "InnoDB: MySQL database directory"
03133 " from another database?\n"
03134 "InnoDB: You can look for further help from\n"
03135 "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
03136 stderr);
03137 #endif
03138 goto funct_exit;
03139 }
03140
03141
03142
03143
03144 foreign = UT_LIST_GET_FIRST(table->referenced_list);
03145
03146 while (foreign && foreign->foreign_table == table) {
03147 check_next_foreign:
03148 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
03149 }
03150
03151 if (foreign && trx->check_foreigns
03152 && !(drop_db && dict_tables_have_same_db(
03153 name, foreign->foreign_table_name))) {
03154 FILE* ef = dict_foreign_err_file;
03155
03156
03157
03158
03159 err = DB_CANNOT_DROP_CONSTRAINT;
03160
03161 mutex_enter(&dict_foreign_err_mutex);
03162 rewind(ef);
03163 ut_print_timestamp(ef);
03164
03165 fputs(" Cannot drop table ", ef);
03166 ut_print_name(ef, trx, TRUE, name);
03167 fputs("\n"
03168 "because it is referenced by ", ef);
03169 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
03170 putc('\n', ef);
03171 mutex_exit(&dict_foreign_err_mutex);
03172
03173 goto funct_exit;
03174 }
03175
03176 if (foreign && trx->check_foreigns) {
03177 goto check_next_foreign;
03178 }
03179
03180 if (table->n_mysql_handles_opened > 0) {
03181 ibool added;
03182
03183 added = row_add_table_to_background_drop_list(table->name);
03184
03185 if (added) {
03186 ut_print_timestamp(stderr);
03187 fputs(" InnoDB: Warning: MySQL is"
03188 " trying to drop table ", stderr);
03189 ut_print_name(stderr, trx, TRUE, table->name);
03190 fputs("\n"
03191 "InnoDB: though there are still"
03192 " open handles to it.\n"
03193 "InnoDB: Adding the table to the"
03194 " background drop queue.\n",
03195 stderr);
03196
03197
03198
03199 err = DB_SUCCESS;
03200 } else {
03201
03202 err = DB_ERROR;
03203 }
03204
03205 goto funct_exit;
03206 }
03207
03208
03209
03210
03211
03212
03213
03214 if (table->n_foreign_key_checks_running > 0) {
03215
03216 const char* i_table_name = table->name;
03217 ibool added;
03218
03219 added = row_add_table_to_background_drop_list(i_table_name);
03220
03221 if (added) {
03222 ut_print_timestamp(stderr);
03223 fputs(" InnoDB: You are trying to drop table ",
03224 stderr);
03225 ut_print_name(stderr, trx, TRUE, i_table_name);
03226 fputs("\n"
03227 "InnoDB: though there is a"
03228 " foreign key check running on it.\n"
03229 "InnoDB: Adding the table to"
03230 " the background drop queue.\n",
03231 stderr);
03232
03233
03234
03235
03236 err = DB_SUCCESS;
03237 } else {
03238
03239 err = DB_ERROR;
03240 }
03241
03242 goto funct_exit;
03243 }
03244
03245
03246 lock_remove_all_on_table(table, TRUE);
03247
03248 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
03249 trx->table_id = table->id;
03250
03251
03252
03253
03254
03255
03256 info = pars_info_create();
03257
03258 pars_info_add_str_literal(info, "table_name", name);
03259
03260 err = que_eval_sql(info,
03261 "PROCEDURE DROP_TABLE_PROC () IS\n"
03262 "sys_foreign_id CHAR;\n"
03263 "table_id CHAR;\n"
03264 "index_id CHAR;\n"
03265 "foreign_id CHAR;\n"
03266 "found INT;\n"
03267 "BEGIN\n"
03268 "SELECT ID INTO table_id\n"
03269 "FROM SYS_TABLES\n"
03270 "WHERE NAME = :table_name\n"
03271 "LOCK IN SHARE MODE;\n"
03272 "IF (SQL % NOTFOUND) THEN\n"
03273 " RETURN;\n"
03274 "END IF;\n"
03275 "found := 1;\n"
03276 "SELECT ID INTO sys_foreign_id\n"
03277 "FROM SYS_TABLES\n"
03278 "WHERE NAME = 'SYS_FOREIGN'\n"
03279 "LOCK IN SHARE MODE;\n"
03280 "IF (SQL % NOTFOUND) THEN\n"
03281 " found := 0;\n"
03282 "END IF;\n"
03283 "IF (:table_name = 'SYS_FOREIGN') THEN\n"
03284 " found := 0;\n"
03285 "END IF;\n"
03286 "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
03287 " found := 0;\n"
03288 "END IF;\n"
03289 "WHILE found = 1 LOOP\n"
03290 " SELECT ID INTO foreign_id\n"
03291 " FROM SYS_FOREIGN\n"
03292 " WHERE FOR_NAME = :table_name\n"
03293 " AND TO_BINARY(FOR_NAME)\n"
03294 " = TO_BINARY(:table_name)\n"
03295 " LOCK IN SHARE MODE;\n"
03296 " IF (SQL % NOTFOUND) THEN\n"
03297 " found := 0;\n"
03298 " ELSE\n"
03299 " DELETE FROM SYS_FOREIGN_COLS\n"
03300 " WHERE ID = foreign_id;\n"
03301 " DELETE FROM SYS_FOREIGN\n"
03302 " WHERE ID = foreign_id;\n"
03303 " END IF;\n"
03304 "END LOOP;\n"
03305 "found := 1;\n"
03306 "WHILE found = 1 LOOP\n"
03307 " SELECT ID INTO index_id\n"
03308 " FROM SYS_INDEXES\n"
03309 " WHERE TABLE_ID = table_id\n"
03310 " LOCK IN SHARE MODE;\n"
03311 " IF (SQL % NOTFOUND) THEN\n"
03312 " found := 0;\n"
03313 " ELSE\n"
03314 " DELETE FROM SYS_FIELDS\n"
03315 " WHERE INDEX_ID = index_id;\n"
03316 " DELETE FROM SYS_INDEXES\n"
03317 " WHERE ID = index_id\n"
03318 " AND TABLE_ID = table_id;\n"
03319 " END IF;\n"
03320 "END LOOP;\n"
03321 "DELETE FROM SYS_COLUMNS\n"
03322 "WHERE TABLE_ID = table_id;\n"
03323 "DELETE FROM SYS_TABLES\n"
03324 "WHERE ID = table_id;\n"
03325 "END;\n"
03326 , FALSE, trx);
03327
03328 switch (err) {
03329 ibool is_temp;
03330 const char* name_or_path;
03331 mem_heap_t* heap;
03332
03333 case DB_SUCCESS:
03334
03335 heap = mem_heap_create(200);
03336
03337
03338
03339
03340 name = mem_heap_strdup(heap, name);
03341 space_id = table->space;
03342
03343 if (table->dir_path_of_temp_table != NULL) {
03344 name_or_path = mem_heap_strdup(
03345 heap, table->dir_path_of_temp_table);
03346 is_temp = TRUE;
03347 } else {
03348 name_or_path = name;
03349 is_temp = (table->flags >> DICT_TF2_SHIFT)
03350 & DICT_TF2_TEMPORARY;
03351 }
03352
03353 dict_table_remove_from_cache(table);
03354
03355 if (dict_load_table(name, TRUE) != NULL) {
03356 ut_print_timestamp(stderr);
03357 fputs(" InnoDB: Error: not able to remove table ",
03358 stderr);
03359 ut_print_name(stderr, trx, TRUE, name);
03360 fputs(" from the dictionary cache!\n", stderr);
03361 err = DB_ERROR;
03362 }
03363
03364
03365
03366
03367 if (err == DB_SUCCESS && space_id > 0) {
03368 if (!fil_space_for_table_exists_in_mem(space_id,
03369 name_or_path,
03370 is_temp, FALSE,
03371 !is_temp)) {
03372 err = DB_SUCCESS;
03373
03374 fprintf(stderr,
03375 "InnoDB: We removed now the InnoDB"
03376 " internal data dictionary entry\n"
03377 "InnoDB: of table ");
03378 ut_print_name(stderr, trx, TRUE, name);
03379 fprintf(stderr, ".\n");
03380 } else if (!fil_delete_tablespace(space_id)) {
03381 fprintf(stderr,
03382 "InnoDB: We removed now the InnoDB"
03383 " internal data dictionary entry\n"
03384 "InnoDB: of table ");
03385 ut_print_name(stderr, trx, TRUE, name);
03386 fprintf(stderr, ".\n");
03387
03388 ut_print_timestamp(stderr);
03389 fprintf(stderr,
03390 " InnoDB: Error: not able to"
03391 " delete tablespace %lu of table ",
03392 (ulong) space_id);
03393 ut_print_name(stderr, trx, TRUE, name);
03394 fputs("!\n", stderr);
03395 err = DB_ERROR;
03396 }
03397 }
03398
03399 mem_heap_free(heap);
03400 break;
03401
03402 case DB_TOO_MANY_CONCURRENT_TRXS:
03403
03404
03405
03406
03407 break;
03408
03409 case DB_OUT_OF_FILE_SPACE:
03410 err = DB_MUST_GET_MORE_FILE_SPACE;
03411
03412 row_mysql_handle_errors(&err, trx, NULL, NULL);
03413
03414
03415
03416 default:
03417
03418 ut_error;
03419 }
03420
03421 funct_exit:
03422
03423 if (locked_dictionary) {
03424 trx_commit_for_mysql(trx);
03425
03426 row_mysql_unlock_data_dictionary(trx);
03427 }
03428
03429 trx->op_info = "";
03430
03431 srv_wake_master_thread();
03432
03433 return((int) err);
03434 }
03435
03436
03438 UNIV_INTERN
03439 void
03440 row_mysql_drop_temp_tables(void)
03441
03442 {
03443 trx_t* trx;
03444 btr_pcur_t pcur;
03445 mtr_t mtr;
03446 mem_heap_t* heap;
03447
03448 trx = trx_allocate_for_background();
03449 trx->op_info = "dropping temporary tables";
03450 row_mysql_lock_data_dictionary(trx);
03451
03452 heap = mem_heap_create(200);
03453
03454 mtr_start(&mtr);
03455
03456 btr_pcur_open_at_index_side(
03457 TRUE,
03458 dict_table_get_first_index(dict_sys->sys_tables),
03459 BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
03460
03461 for (;;) {
03462 const rec_t* rec;
03463 const byte* field;
03464 ulint len;
03465 const char* table_name;
03466 dict_table_t* table;
03467
03468 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
03469
03470 if (!btr_pcur_is_on_user_rec(&pcur)) {
03471 break;
03472 }
03473
03474 rec = btr_pcur_get_rec(&pcur);
03475 field = rec_get_nth_field_old(rec, 4, &len);
03476 if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
03477 continue;
03478 }
03479
03480
03481
03482
03483 field = rec_get_nth_field_old(rec, 7, &len);
03484 if (len != 4
03485 || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
03486 continue;
03487 }
03488
03489
03490 field = rec_get_nth_field_old(rec, 0, &len);
03491 if (len == UNIV_SQL_NULL || len == 0) {
03492
03493 continue;
03494 }
03495
03496 table_name = mem_heap_strdupl(heap, (const char*) field, len);
03497
03498 btr_pcur_store_position(&pcur, &mtr);
03499 btr_pcur_commit_specify_mtr(&pcur, &mtr);
03500
03501 table = dict_load_table(table_name, TRUE);
03502
03503 if (table) {
03504 row_drop_table_for_mysql(table_name, trx, FALSE);
03505 trx_commit_for_mysql(trx);
03506 }
03507
03508 mtr_start(&mtr);
03509 btr_pcur_restore_position(BTR_SEARCH_LEAF,
03510 &pcur, &mtr);
03511 }
03512
03513 btr_pcur_close(&pcur);
03514 mtr_commit(&mtr);
03515 mem_heap_free(heap);
03516 row_mysql_unlock_data_dictionary(trx);
03517 trx_free_for_background(trx);
03518 }
03519
03520
03524 static
03525 ulint
03526 drop_all_foreign_keys_in_db(
03527
03528 const char* name,
03529 trx_t* trx)
03530 {
03531 pars_info_t* pinfo;
03532 ulint err;
03533
03534 ut_a(name[strlen(name) - 1] == '/');
03535
03536 pinfo = pars_info_create();
03537
03538 pars_info_add_str_literal(pinfo, "dbname", name);
03539
03541 #define TABLE_NOT_IN_THIS_DB \
03542 "SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
03543
03544 err = que_eval_sql(pinfo,
03545 "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
03546 "foreign_id CHAR;\n"
03547 "for_name CHAR;\n"
03548 "found INT;\n"
03549 "DECLARE CURSOR cur IS\n"
03550 "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
03551 "WHERE FOR_NAME >= :dbname\n"
03552 "LOCK IN SHARE MODE\n"
03553 "ORDER BY FOR_NAME;\n"
03554 "BEGIN\n"
03555 "found := 1;\n"
03556 "OPEN cur;\n"
03557 "WHILE found = 1 LOOP\n"
03558 " FETCH cur INTO foreign_id, for_name;\n"
03559 " IF (SQL % NOTFOUND) THEN\n"
03560 " found := 0;\n"
03561 " ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
03562 " found := 0;\n"
03563 " ELSIF (1=1) THEN\n"
03564 " DELETE FROM SYS_FOREIGN_COLS\n"
03565 " WHERE ID = foreign_id;\n"
03566 " DELETE FROM SYS_FOREIGN\n"
03567 " WHERE ID = foreign_id;\n"
03568 " END IF;\n"
03569 "END LOOP;\n"
03570 "CLOSE cur;\n"
03571 "COMMIT WORK;\n"
03572 "END;\n",
03573 FALSE,
03574
03575 trx);
03576
03577 return(err);
03578 }
03579
03580
03583 UNIV_INTERN
03584 int
03585 row_drop_database_for_mysql(
03586
03587 const char* name,
03588 trx_t* trx)
03589 {
03590 dict_table_t* table;
03591 char* table_name;
03592 int err = DB_SUCCESS;
03593 ulint namelen = strlen(name);
03594
03595 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
03596 ut_a(name != NULL);
03597 ut_a(name[namelen - 1] == '/');
03598
03599 trx->op_info = "dropping database";
03600
03601 trx_start_if_not_started(trx);
03602 loop:
03603 row_mysql_lock_data_dictionary(trx);
03604
03605 while ((table_name = dict_get_first_table_name_in_db(name))) {
03606 ut_a(memcmp(table_name, name, namelen) == 0);
03607
03608
03609
03610 fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
03611
03612 table = dict_table_get_low(table_name);
03613
03614 ut_a(table);
03615
03616
03617
03618
03619 if (table->n_mysql_handles_opened > 0) {
03620 row_mysql_unlock_data_dictionary(trx);
03621
03622 ut_print_timestamp(stderr);
03623 fputs(" InnoDB: Warning: MySQL is trying to"
03624 " drop database ", stderr);
03625 ut_print_name(stderr, trx, TRUE, name);
03626 fputs("\n"
03627 "InnoDB: though there are still"
03628 " open handles to table ", stderr);
03629 ut_print_name(stderr, trx, TRUE, table_name);
03630 fputs(".\n", stderr);
03631
03632 os_thread_sleep(1000000);
03633
03634 mem_free(table_name);
03635
03636 goto loop;
03637 }
03638
03639 err = row_drop_table_for_mysql(table_name, trx, TRUE);
03640 trx_commit_for_mysql(trx);
03641
03642 if (err != DB_SUCCESS) {
03643 fputs("InnoDB: DROP DATABASE ", stderr);
03644 ut_print_name(stderr, trx, TRUE, name);
03645 fprintf(stderr, " failed with error %lu for table ",
03646 (ulint) err);
03647 ut_print_name(stderr, trx, TRUE, table_name);
03648 putc('\n', stderr);
03649 mem_free(table_name);
03650 break;
03651 }
03652
03653 mem_free(table_name);
03654 }
03655
03656 if (err == DB_SUCCESS) {
03657
03658
03659 err = (int) drop_all_foreign_keys_in_db(name, trx);
03660
03661 if (err != DB_SUCCESS) {
03662 fputs("InnoDB: DROP DATABASE ", stderr);
03663 ut_print_name(stderr, trx, TRUE, name);
03664 fprintf(stderr, " failed with error %d while "
03665 "dropping all foreign keys", err);
03666 }
03667 }
03668
03669 trx_commit_for_mysql(trx);
03670
03671 row_mysql_unlock_data_dictionary(trx);
03672
03673 trx->op_info = "";
03674
03675 return(err);
03676 }
03677
03678
03682 static
03683 ibool
03684 row_is_mysql_tmp_table_name(
03685
03686 const char* name)
03688 {
03689 return(strstr(name, "/#sql") != NULL);
03690
03691 }
03692
03693
03696 static
03697 int
03698 row_delete_constraint_low(
03699
03700 const char* id,
03701 trx_t* trx)
03702 {
03703 pars_info_t* info = pars_info_create();
03704
03705 pars_info_add_str_literal(info, "id", id);
03706
03707 return((int) que_eval_sql(info,
03708 "PROCEDURE DELETE_CONSTRAINT () IS\n"
03709 "BEGIN\n"
03710 "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
03711 "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
03712 "END;\n"
03713 , FALSE, trx));
03714 }
03715
03716
03719 static
03720 int
03721 row_delete_constraint(
03722
03723 const char* id,
03724 const char* database_name,
03726 mem_heap_t* heap,
03727 trx_t* trx)
03728 {
03729 ulint err;
03730
03731
03732 err = row_delete_constraint_low(
03733 mem_heap_strcat(heap, database_name, id), trx);
03734
03735 if ((err == DB_SUCCESS) && !strchr(id, '/')) {
03736
03737
03738
03739
03740
03741
03742
03743 err = row_delete_constraint_low(id, trx);
03744 }
03745
03746 return((int) err);
03747 }
03748
03749
03752 UNIV_INTERN
03753 ulint
03754 row_rename_table_for_mysql(
03755
03756 const char* old_name,
03757 const char* new_name,
03758 trx_t* trx,
03759 ibool commit)
03760 {
03761 dict_table_t* table;
03762 ulint err = DB_ERROR;
03763 mem_heap_t* heap = NULL;
03764 const char** constraints_to_drop = NULL;
03765 ulint n_constraints_to_drop = 0;
03766 ibool old_is_tmp, new_is_tmp;
03767 pars_info_t* info = NULL;
03768
03769 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
03770 ut_a(old_name != NULL);
03771 ut_a(new_name != NULL);
03772
03773 if (srv_created_new_raw || srv_force_recovery) {
03774 fputs("InnoDB: A new raw disk partition was initialized or\n"
03775 "InnoDB: innodb_force_recovery is on: we do not allow\n"
03776 "InnoDB: database modifications by the user. Shut down\n"
03777 "InnoDB: mysqld and edit my.cnf so that newraw"
03778 " is replaced\n"
03779 "InnoDB: with raw, and innodb_force_... is removed.\n",
03780 stderr);
03781
03782 goto funct_exit;
03783 }
03784
03785 trx->op_info = "renaming table";
03786 trx_start_if_not_started(trx);
03787
03788 old_is_tmp = row_is_mysql_tmp_table_name(old_name);
03789 new_is_tmp = row_is_mysql_tmp_table_name(new_name);
03790
03791 table = dict_table_get_low(old_name);
03792
03793 if (!table) {
03794 #if defined(BUILD_DRIZZLE)
03795 err = ENOENT;
03796 #else
03797 err = DB_TABLE_NOT_FOUND;
03798 ut_print_timestamp(stderr);
03799
03800 fputs(" InnoDB: Error: table ", stderr);
03801 ut_print_name(stderr, trx, TRUE, old_name);
03802 fputs(" does not exist in the InnoDB internal\n"
03803 "InnoDB: data dictionary though MySQL is"
03804 " trying to rename the table.\n"
03805 "InnoDB: Have you copied the .frm file"
03806 " of the table to the\n"
03807 "InnoDB: MySQL database directory"
03808 " from another database?\n"
03809 "InnoDB: You can look for further help from\n"
03810 "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
03811 stderr);
03812 #endif
03813 goto funct_exit;
03814 } else if (table->ibd_file_missing) {
03815 err = DB_TABLE_NOT_FOUND;
03816 ut_print_timestamp(stderr);
03817
03818 fputs(" InnoDB: Error: table ", stderr);
03819 ut_print_name(stderr, trx, TRUE, old_name);
03820 fputs(" does not have an .ibd file"
03821 " in the database directory.\n"
03822 "InnoDB: You can look for further help from\n"
03823 "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
03824 stderr);
03825 goto funct_exit;
03826 } else if (new_is_tmp) {
03827
03828
03829
03830
03831
03832
03833 heap = mem_heap_create(100);
03834
03835 err = dict_foreign_parse_drop_constraints(
03836 heap, trx, table, &n_constraints_to_drop,
03837 &constraints_to_drop);
03838
03839 if (err != DB_SUCCESS) {
03840
03841 goto funct_exit;
03842 }
03843 }
03844
03845
03846
03847
03848 info = pars_info_create();
03849
03850 pars_info_add_str_literal(info, "new_table_name", new_name);
03851 pars_info_add_str_literal(info, "old_table_name", old_name);
03852
03853 err = que_eval_sql(info,
03854 "PROCEDURE RENAME_TABLE () IS\n"
03855 "BEGIN\n"
03856 "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
03857 " WHERE NAME = :old_table_name;\n"
03858 "END;\n"
03859 , FALSE, trx);
03860
03861 if (err != DB_SUCCESS) {
03862
03863 goto end;
03864 } else if (!new_is_tmp) {
03865
03866
03867 info = pars_info_create();
03868
03869 pars_info_add_str_literal(info, "new_table_name", new_name);
03870 pars_info_add_str_literal(info, "old_table_name", old_name);
03871
03872 err = que_eval_sql(
03873 info,
03874 "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
03875 "gen_constr_prefix CHAR;\n"
03876 "new_db_name CHAR;\n"
03877 "foreign_id CHAR;\n"
03878 "new_foreign_id CHAR;\n"
03879 "old_db_name_len INT;\n"
03880 "old_t_name_len INT;\n"
03881 "new_db_name_len INT;\n"
03882 "id_len INT;\n"
03883 "found INT;\n"
03884 "BEGIN\n"
03885 "found := 1;\n"
03886 "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
03887 "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
03888 "new_db_name := SUBSTR(:new_table_name, 0,\n"
03889 " new_db_name_len);\n"
03890 "old_t_name_len := LENGTH(:old_table_name);\n"
03891 "gen_constr_prefix := CONCAT(:old_table_name,\n"
03892 " '_ibfk_');\n"
03893 "WHILE found = 1 LOOP\n"
03894 " SELECT ID INTO foreign_id\n"
03895 " FROM SYS_FOREIGN\n"
03896 " WHERE FOR_NAME = :old_table_name\n"
03897 " AND TO_BINARY(FOR_NAME)\n"
03898 " = TO_BINARY(:old_table_name)\n"
03899 " LOCK IN SHARE MODE;\n"
03900 " IF (SQL % NOTFOUND) THEN\n"
03901 " found := 0;\n"
03902 " ELSE\n"
03903 " UPDATE SYS_FOREIGN\n"
03904 " SET FOR_NAME = :new_table_name\n"
03905 " WHERE ID = foreign_id;\n"
03906 " id_len := LENGTH(foreign_id);\n"
03907 " IF (INSTR(foreign_id, '/') > 0) THEN\n"
03908 " IF (INSTR(foreign_id,\n"
03909 " gen_constr_prefix) > 0)\n"
03910 " THEN\n"
03911 " new_foreign_id :=\n"
03912 " CONCAT(:new_table_name,\n"
03913 " SUBSTR(foreign_id, old_t_name_len,\n"
03914 " id_len - old_t_name_len));\n"
03915 " ELSE\n"
03916 " new_foreign_id :=\n"
03917 " CONCAT(new_db_name,\n"
03918 " SUBSTR(foreign_id,\n"
03919 " old_db_name_len,\n"
03920 " id_len - old_db_name_len));\n"
03921 " END IF;\n"
03922 " UPDATE SYS_FOREIGN\n"
03923 " SET ID = new_foreign_id\n"
03924 " WHERE ID = foreign_id;\n"
03925 " UPDATE SYS_FOREIGN_COLS\n"
03926 " SET ID = new_foreign_id\n"
03927 " WHERE ID = foreign_id;\n"
03928 " END IF;\n"
03929 " END IF;\n"
03930 "END LOOP;\n"
03931 "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
03932 "WHERE REF_NAME = :old_table_name\n"
03933 " AND TO_BINARY(REF_NAME)\n"
03934 " = TO_BINARY(:old_table_name);\n"
03935 "END;\n"
03936 , FALSE, trx);
03937
03938 } else if (n_constraints_to_drop > 0) {
03939
03940
03941 ulint db_name_len = dict_get_db_name_len(old_name) + 1;
03942 char* db_name = mem_heap_strdupl(heap, old_name,
03943 db_name_len);
03944 ulint i;
03945
03946 for (i = 0; i < n_constraints_to_drop; i++) {
03947 err = row_delete_constraint(constraints_to_drop[i],
03948 db_name, heap, trx);
03949
03950 if (err != DB_SUCCESS) {
03951 break;
03952 }
03953 }
03954 }
03955
03956 end:
03957 if (err != DB_SUCCESS) {
03958 if (err == DB_DUPLICATE_KEY) {
03959 ut_print_timestamp(stderr);
03960 fputs(" InnoDB: Error; possible reasons:\n"
03961 "InnoDB: 1) Table rename would cause"
03962 " two FOREIGN KEY constraints\n"
03963 "InnoDB: to have the same internal name"
03964 " in case-insensitive comparison.\n"
03965 "InnoDB: 2) table ", stderr);
03966 ut_print_name(stderr, trx, TRUE, new_name);
03967 fputs(" exists in the InnoDB internal data\n"
03968 "InnoDB: dictionary though MySQL is"
03969 " trying to rename table ", stderr);
03970 ut_print_name(stderr, trx, TRUE, old_name);
03971 fputs(" to it.\n"
03972 "InnoDB: Have you deleted the .frm file"
03973 " and not used DROP TABLE?\n"
03974 "InnoDB: You can look for further help from\n"
03975 "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
03976 "InnoDB: If table ", stderr);
03977 ut_print_name(stderr, trx, TRUE, new_name);
03978 fputs(" is a temporary table #sql..., then"
03979 " it can be that\n"
03980 "InnoDB: there are still queries running"
03981 " on the table, and it will be\n"
03982 "InnoDB: dropped automatically when"
03983 " the queries end.\n"
03984 "InnoDB: You can drop the orphaned table"
03985 " inside InnoDB by\n"
03986 "InnoDB: creating an InnoDB table with"
03987 " the same name in another\n"
03988 "InnoDB: database and copying the .frm file"
03989 " to the current database.\n"
03990 "InnoDB: Then MySQL thinks the table exists,"
03991 " and DROP TABLE will\n"
03992 "InnoDB: succeed.\n", stderr);
03993 }
03994 trx->error_state = DB_SUCCESS;
03995 trx_general_rollback_for_mysql(trx, NULL);
03996 trx->error_state = DB_SUCCESS;
03997 } else {
03998
03999
04000
04001 if (!dict_table_rename_in_cache(table, new_name,
04002 !new_is_tmp)) {
04003 trx->error_state = DB_SUCCESS;
04004 trx_general_rollback_for_mysql(trx, NULL);
04005 trx->error_state = DB_SUCCESS;
04006 goto funct_exit;
04007 }
04008
04009
04010
04011
04012 err = dict_load_foreigns(
04013 new_name, FALSE, !old_is_tmp || trx->check_foreigns);
04014
04015 if (err != DB_SUCCESS) {
04016 ut_print_timestamp(stderr);
04017
04018 if (old_is_tmp) {
04019 fputs(" InnoDB: Error: in ALTER TABLE ",
04020 stderr);
04021 ut_print_name(stderr, trx, TRUE, new_name);
04022 fputs("\n"
04023 "InnoDB: has or is referenced"
04024 " in foreign key constraints\n"
04025 "InnoDB: which are not compatible"
04026 " with the new table definition.\n",
04027 stderr);
04028 } else {
04029 fputs(" InnoDB: Error: in RENAME TABLE"
04030 " table ",
04031 stderr);
04032 ut_print_name(stderr, trx, TRUE, new_name);
04033 fputs("\n"
04034 "InnoDB: is referenced in"
04035 " foreign key constraints\n"
04036 "InnoDB: which are not compatible"
04037 " with the new table definition.\n",
04038 stderr);
04039 }
04040
04041 ut_a(dict_table_rename_in_cache(table,
04042 old_name, FALSE));
04043 trx->error_state = DB_SUCCESS;
04044 trx_general_rollback_for_mysql(trx, NULL);
04045 trx->error_state = DB_SUCCESS;
04046 }
04047 }
04048
04049 funct_exit:
04050
04051 if (commit) {
04052 trx_commit_for_mysql(trx);
04053 }
04054
04055 if (UNIV_LIKELY_NULL(heap)) {
04056 mem_heap_free(heap);
04057 }
04058
04059 trx->op_info = "";
04060
04061 return(err);
04062 }
04063
04064
04069 UNIV_INTERN
04070 ibool
04071 row_check_index_for_mysql(
04072
04073 row_prebuilt_t* prebuilt,
04075 const dict_index_t* index,
04076 ulint* n_rows)
04078 {
04079 dtuple_t* prev_entry = NULL;
04080 ulint matched_fields;
04081 ulint matched_bytes;
04082 byte* buf;
04083 ulint ret;
04084 rec_t* rec;
04085 ibool is_ok = TRUE;
04086 int cmp;
04087 ibool contains_null;
04088 ulint i;
04089 ulint cnt;
04090 mem_heap_t* heap = NULL;
04091 ulint n_ext;
04092 ulint offsets_[REC_OFFS_NORMAL_SIZE];
04093 ulint* offsets;
04094 rec_offs_init(offsets_);
04095
04096 *n_rows = 0;
04097
04098 buf = static_cast<byte *>(mem_alloc(UNIV_PAGE_SIZE));
04099 heap = mem_heap_create(100);
04100
04101 cnt = 1000;
04102
04103 ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
04104 loop:
04105
04106 if (--cnt == 0) {
04107 if (trx_is_interrupted(prebuilt->trx)) {
04108 goto func_exit;
04109 }
04110 cnt = 1000;
04111 }
04112
04113 switch (ret) {
04114 case DB_SUCCESS:
04115 break;
04116 default:
04117 ut_print_timestamp(stderr);
04118 fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
04119 dict_index_name_print(stderr, prebuilt->trx, index);
04120 fprintf(stderr, " returned %lu\n", ret);
04121
04122 case DB_END_OF_INDEX:
04123 func_exit:
04124 mem_free(buf);
04125 mem_heap_free(heap);
04126
04127 return(is_ok);
04128 }
04129
04130 *n_rows = *n_rows + 1;
04131
04132
04133
04134
04135
04136 rec = buf + mach_read_from_4(buf);
04137
04138 offsets = rec_get_offsets(rec, index, offsets_,
04139 ULINT_UNDEFINED, &heap);
04140
04141 if (prev_entry != NULL) {
04142 matched_fields = 0;
04143 matched_bytes = 0;
04144
04145 cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
04146 &matched_fields,
04147 &matched_bytes);
04148 contains_null = FALSE;
04149
04150
04151
04152
04153 for (i = 0;
04154 i < dict_index_get_n_ordering_defined_by_user(index);
04155 i++) {
04156 if (UNIV_SQL_NULL == dfield_get_len(
04157 dtuple_get_nth_field(prev_entry, i))) {
04158
04159 contains_null = TRUE;
04160 }
04161 }
04162
04163 if (cmp > 0) {
04164 fputs("InnoDB: index records in a wrong order in ",
04165 stderr);
04166 not_ok:
04167 dict_index_name_print(stderr,
04168 prebuilt->trx, index);
04169 fputs("\n"
04170 "InnoDB: prev record ", stderr);
04171 dtuple_print(stderr, prev_entry);
04172 fputs("\n"
04173 "InnoDB: record ", stderr);
04174 rec_print_new(stderr, rec, offsets);
04175 putc('\n', stderr);
04176 is_ok = FALSE;
04177 } else if (dict_index_is_unique(index)
04178 && !contains_null
04179 && matched_fields
04180 >= dict_index_get_n_ordering_defined_by_user(
04181 index)) {
04182
04183 fputs("InnoDB: duplicate key in ", stderr);
04184 goto not_ok;
04185 }
04186 }
04187
04188 {
04189 mem_heap_t* tmp_heap = NULL;
04190
04191
04192
04193
04194 if (UNIV_UNLIKELY(offsets != offsets_)) {
04195 ulint size = rec_offs_get_n_alloc(offsets)
04196 * sizeof *offsets;
04197
04198 tmp_heap = mem_heap_create(size);
04199 offsets = static_cast<ulint *>(mem_heap_dup(tmp_heap, offsets, size));
04200 }
04201
04202 mem_heap_empty(heap);
04203
04204 prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
04205 index, offsets,
04206 &n_ext, heap);
04207
04208 if (UNIV_LIKELY_NULL(tmp_heap)) {
04209 mem_heap_free(tmp_heap);
04210 }
04211 }
04212
04213 ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
04214
04215 goto loop;
04216 }
04217
04218
04221 UNIV_INTERN
04222 ibool
04223 row_is_magic_monitor_table(
04224
04225 const char* table_name)
04227 {
04228 const char* name;
04229 ulint len;
04230
04231 name = strchr(table_name, '/');
04232 ut_a(name != NULL);
04233 name++;
04234 len = strlen(name) + 1;
04235
04236 if (STR_EQ(name, len, S_innodb_monitor)
04237 || STR_EQ(name, len, S_innodb_lock_monitor)
04238 || STR_EQ(name, len, S_innodb_tablespace_monitor)
04239 || STR_EQ(name, len, S_innodb_table_monitor)
04240 || STR_EQ(name, len, S_innodb_mem_validate)) {
04241
04242 return(TRUE);
04243 }
04244
04245 return(FALSE);
04246 }