row0mysql.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:93k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. Interface between Innobase row operations and MySQL.
  3. Contains also create table and other data dictionary operations.
  4. (c) 2000 Innobase Oy
  5. Created 9/17/2000 Heikki Tuuri
  6. *******************************************************/
  7. #include "row0mysql.h"
  8. #ifdef UNIV_NONINL
  9. #include "row0mysql.ic"
  10. #endif
  11. #include "row0ins.h"
  12. #include "row0sel.h"
  13. #include "row0upd.h"
  14. #include "row0row.h"
  15. #include "que0que.h"
  16. #include "pars0pars.h"
  17. #include "dict0dict.h"
  18. #include "dict0crea.h"
  19. #include "dict0load.h"
  20. #include "dict0boot.h"
  21. #include "trx0roll.h"
  22. #include "trx0purge.h"
  23. #include "lock0lock.h"
  24. #include "rem0cmp.h"
  25. #include "log0log.h"
  26. #include "btr0sea.h"
  27. #include "fil0fil.h"
  28. #include "ibuf0ibuf.h"
  29. /* A dummy variable used to fool the compiler */
  30. ibool row_mysql_identically_false = FALSE;
  31. /* List of tables we should drop in background. ALTER TABLE in MySQL requires
  32. that the table handler can drop the table in background when there are no
  33. queries to it any more. Protected by the kernel mutex. */
  34. typedef struct row_mysql_drop_struct row_mysql_drop_t;
  35. struct row_mysql_drop_struct{
  36. char* table_name;
  37. UT_LIST_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
  38. };
  39. UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
  40. ibool row_mysql_drop_list_inited  = FALSE;
  41. /* Magic table names for invoking various monitor threads */
  42. static const char S_innodb_monitor[] = "innodb_monitor";
  43. static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
  44. static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
  45. static const char S_innodb_table_monitor[] = "innodb_table_monitor";
  46. static const char S_innodb_mem_validate[] = "innodb_mem_validate";
  47. /* Name suffix for recovered orphaned temporary tables */
  48. static const char S_recover_innodb_tmp_table[] = "_recover_innodb_tmp_table";
  49. /***********************************************************************
  50. Determine if the given name ends in the suffix reserved for recovered
  51. orphaned temporary tables. */
  52. static
  53. ibool
  54. row_mysql_is_recovered_tmp_table(
  55. /*=============================*/
  56.  /* out: TRUE if table name ends in
  57.  the reserved suffix */
  58. const char* name)
  59. {
  60. ulint namelen = strlen(name) + 1;
  61. return(namelen >= sizeof S_recover_innodb_tmp_table
  62. && !memcmp(name + namelen -
  63. sizeof S_recover_innodb_tmp_table,
  64. S_recover_innodb_tmp_table,
  65. sizeof S_recover_innodb_tmp_table));
  66. }
  67. /***********************************************************************
  68. Determine if the given name is a name reserved for MySQL system tables. */
  69. static
  70. ibool
  71. row_mysql_is_system_table(
  72. /*======================*/
  73.  /* out: TRUE if name is a MySQL
  74.  system table name */
  75. const char* name)
  76. {
  77. if (memcmp(name, "mysql/", 6)) {
  78. return(FALSE);
  79. }
  80. return(0 == strcmp(name + 6, "host")
  81.     || 0 == strcmp(name + 6, "user")
  82.     || 0 == strcmp(name + 6, "db"));
  83. }
  84. /***********************************************************************
  85. Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
  86. static
  87. void
  88. row_mysql_delay_if_needed(void)
  89. /*===========================*/
  90. {
  91. if (srv_dml_needed_delay) {
  92. os_thread_sleep(srv_dml_needed_delay);
  93. }
  94. }
  95. /***********************************************************************
  96. Reads a MySQL format variable-length field (like VARCHAR) length and
  97. returns pointer to the field data. */
  98. byte*
  99. row_mysql_read_var_ref_noninline(
  100. /*=============================*/
  101. /* out: field + 2 */
  102. ulint* len, /* out: variable-length field length */
  103. byte* field) /* in: field */
  104. {
  105. return(row_mysql_read_var_ref(len, field));
  106. }
  107. /***********************************************************************
  108. Frees the blob heap in prebuilt when no longer needed. */
  109. void
  110. row_mysql_prebuilt_free_blob_heap(
  111. /*==============================*/
  112. row_prebuilt_t* prebuilt) /* in: prebuilt struct of a
  113. ha_innobase:: table handle */
  114. {
  115. mem_heap_free(prebuilt->blob_heap);
  116. prebuilt->blob_heap = NULL;
  117. }
  118. /***********************************************************************
  119. Stores a reference to a BLOB in the MySQL format. */
  120. void
  121. row_mysql_store_blob_ref(
  122. /*=====================*/
  123. byte* dest, /* in: where to store */
  124. ulint col_len, /* in: dest buffer size: determines into
  125. how many bytes the BLOB length is stored,
  126. the space for the length may vary from 1
  127. to 4 bytes */
  128. byte* data, /* in: BLOB data; if the value to store
  129. is SQL NULL this should be NULL pointer */
  130. ulint len) /* in: BLOB length; if the value to store
  131. is SQL NULL this should be 0; remember
  132. also to set the NULL bit in the MySQL record
  133. header! */
  134. {
  135. /* MySQL might assume the field is set to zero except the length and
  136. the pointer fields */
  137. memset(dest, '', col_len);
  138. /* In dest there are 1 - 4 bytes reserved for the BLOB length,
  139. and after that 8 bytes reserved for the pointer to the data.
  140. In 32-bit architectures we only use the first 4 bytes of the pointer
  141. slot. */
  142. ut_a(col_len - 8 > 1 || len < 256);
  143. ut_a(col_len - 8 > 2 || len < 256 * 256);
  144. ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
  145. mach_write_to_n_little_endian(dest, col_len - 8, len);
  146. ut_memcpy(dest + col_len - 8, (byte*)&data, sizeof(byte*));
  147. }
  148. /***********************************************************************
  149. Reads a reference to a BLOB in the MySQL format. */
  150. byte*
  151. row_mysql_read_blob_ref(
  152. /*====================*/
  153. /* out: pointer to BLOB data */
  154. ulint* len, /* out: BLOB length */
  155. byte* ref, /* in: BLOB reference in the MySQL format */
  156. ulint col_len) /* in: BLOB reference length (not BLOB
  157. length) */
  158. {
  159. byte* data;
  160. *len = mach_read_from_n_little_endian(ref, col_len - 8);
  161. ut_memcpy((byte*)&data, ref + col_len - 8, sizeof(byte*));
  162. return(data);
  163. }
  164. /******************************************************************
  165. Convert a row in the MySQL format to a row in the Innobase format. */
  166. static
  167. void
  168. row_mysql_convert_row_to_innobase(
  169. /*==============================*/
  170. dtuple_t* row, /* in/out: Innobase row where the
  171. field type information is already
  172. copied there, or will be copied
  173. later */
  174. row_prebuilt_t* prebuilt, /* in: prebuilt struct where template
  175. must be of type ROW_MYSQL_WHOLE_ROW */
  176. byte* mysql_rec) /* in: row in the MySQL format;
  177. NOTE: do not discard as long as
  178. row is used, as row may contain
  179. pointers to this record! */
  180. {
  181. mysql_row_templ_t* templ;
  182. dfield_t* dfield;
  183. ulint i;
  184. ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
  185. ut_ad(prebuilt->mysql_template);
  186. for (i = 0; i < prebuilt->n_template; i++) {
  187. templ = prebuilt->mysql_template + i;
  188. dfield = dtuple_get_nth_field(row, i);
  189. if (templ->mysql_null_bit_mask != 0) {
  190. /* Column may be SQL NULL */
  191. if (mysql_rec[templ->mysql_null_byte_offset] &
  192.   (byte) (templ->mysql_null_bit_mask)) {
  193. /* It is SQL NULL */
  194. dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
  195. goto next_column;
  196. }
  197. }
  198. row_mysql_store_col_in_innobase_format(dfield,
  199. prebuilt->ins_upd_rec_buff
  200. + templ->mysql_col_offset,
  201. mysql_rec + templ->mysql_col_offset,
  202. templ->mysql_col_len,
  203. templ->type, templ->is_unsigned);
  204. next_column:
  205. ;
  206. }
  207. /********************************************************************
  208. Handles user errors and lock waits detected by the database engine. */
  209. ibool
  210. row_mysql_handle_errors(
  211. /*====================*/
  212. /* out: TRUE if it was a lock wait and
  213. we should continue running the query thread */
  214. ulint* new_err,/* out: possible new error encountered in
  215. lock wait, or if no new error, the value
  216. of trx->error_state at the entry of this
  217. function */
  218. trx_t* trx, /* in: transaction */
  219. que_thr_t* thr, /* in: query thread */
  220. trx_savept_t* savept) /* in: savepoint or NULL */
  221. {
  222. ulint err;
  223. handle_new_error:
  224. err = trx->error_state;
  225. ut_a(err != DB_SUCCESS);
  226. trx->error_state = DB_SUCCESS;
  227. if (err == DB_DUPLICATE_KEY) {
  228.             if (savept) {
  229. /* Roll back the latest, possibly incomplete
  230. insertion or update */
  231. trx_general_rollback_for_mysql(trx, TRUE, savept);
  232. }
  233. } else if (err == DB_TOO_BIG_RECORD) {
  234.             if (savept) {
  235. /* Roll back the latest, possibly incomplete
  236. insertion or update */
  237. trx_general_rollback_for_mysql(trx, TRUE, savept);
  238. }
  239. /* MySQL will roll back the latest SQL statement */
  240. } else if (err == DB_ROW_IS_REFERENCED
  241.    || err == DB_NO_REFERENCED_ROW
  242.    || err == DB_CANNOT_ADD_CONSTRAINT) {
  243.             if (savept) {
  244. /* Roll back the latest, possibly incomplete
  245. insertion or update */
  246. trx_general_rollback_for_mysql(trx, TRUE, savept);
  247. }
  248. /* MySQL will roll back the latest SQL statement */
  249. } else if (err == DB_LOCK_WAIT) {
  250. srv_suspend_mysql_thread(thr);
  251. if (trx->error_state != DB_SUCCESS) {
  252. que_thr_stop_for_mysql(thr);
  253. goto handle_new_error;
  254. }
  255. *new_err = err;
  256. return(TRUE);
  257. } else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT
  258.    || err == DB_LOCK_TABLE_FULL) {
  259. /* Roll back the whole transaction; this resolution was added
  260. to version 3.23.43 */
  261. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  262. } else if (err == DB_OUT_OF_FILE_SPACE) {
  263.             if (savept) {
  264. /* Roll back the latest, possibly incomplete
  265. insertion or update */
  266. trx_general_rollback_for_mysql(trx, TRUE, savept);
  267. }
  268. /* MySQL will roll back the latest SQL statement */
  269. } else if (err == DB_MUST_GET_MORE_FILE_SPACE) {
  270. fputs(
  271. "InnoDB: The database cannot continue operation because ofn"
  272. "InnoDB: lack of space. You must add a new data file ton"
  273. "InnoDB: my.cnf and restart the database.n", stderr);
  274. exit(1);
  275. } else if (err == DB_CORRUPTION) {
  276.        fputs(
  277.     "InnoDB: We detected index corruption in an InnoDB type table.n"
  278.     "InnoDB: You have to dump + drop + reimport the table or, inn"
  279.     "InnoDB: a case of widespread corruption, dump all InnoDBn"
  280.     "InnoDB: tables and recreate the whole InnoDB tablespace.n"
  281.     "InnoDB: If the mysqld server crashes after the startup or whenn"
  282.     "InnoDB: you dump the tables, look atn"
  283.     "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html"
  284.     " for help.n", stderr);
  285. } else {
  286. fprintf(stderr, "InnoDB: unknown error code %lun",
  287. (ulong) err);
  288. ut_error;
  289. }
  290. if (trx->error_state != DB_SUCCESS) {
  291. *new_err = trx->error_state;
  292. } else {
  293. *new_err = err;
  294. }
  295. trx->error_state = DB_SUCCESS;
  296. return(FALSE);
  297. }
  298. /************************************************************************
  299. Create a prebuilt struct for a MySQL table handle. */
  300. row_prebuilt_t*
  301. row_create_prebuilt(
  302. /*================*/
  303. /* out, own: a prebuilt struct */
  304. dict_table_t* table) /* in: Innobase table handle */
  305. {
  306. row_prebuilt_t* prebuilt;
  307. mem_heap_t* heap;
  308. dict_index_t* clust_index;
  309. dtuple_t* ref;
  310. ulint ref_len;
  311. ulint i;
  312. heap = mem_heap_create(128);
  313. prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
  314. prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
  315. prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
  316. prebuilt->table = table;
  317. prebuilt->trx = NULL;
  318. prebuilt->sql_stat_start = TRUE;
  319. prebuilt->mysql_has_locked = FALSE;
  320. prebuilt->index = NULL;
  321. prebuilt->used_in_HANDLER = FALSE;
  322. prebuilt->n_template = 0;
  323. prebuilt->mysql_template = NULL;
  324. prebuilt->heap = heap;
  325. prebuilt->ins_node = NULL;
  326. prebuilt->ins_upd_rec_buff = NULL;
  327. prebuilt->upd_node = NULL;
  328. prebuilt->ins_graph = NULL;
  329. prebuilt->upd_graph = NULL;
  330.    prebuilt->pcur = btr_pcur_create_for_mysql();
  331.    prebuilt->clust_pcur = btr_pcur_create_for_mysql();
  332. prebuilt->select_lock_type = LOCK_NONE;
  333. prebuilt->stored_select_lock_type = 99999999;
  334. prebuilt->sel_graph = NULL;
  335. prebuilt->search_tuple = dtuple_create(heap,
  336. 2 * dict_table_get_n_cols(table));
  337. clust_index = dict_table_get_first_index(table);
  338. ref_len = dict_index_get_n_unique(clust_index);
  339. ref = dtuple_create(heap, ref_len);
  340. dict_index_copy_types(ref, clust_index, ref_len);
  341. prebuilt->clust_ref = ref;
  342. for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
  343. prebuilt->fetch_cache[i] = NULL;
  344. }
  345. prebuilt->n_fetch_cached = 0;
  346. prebuilt->blob_heap = NULL;
  347. prebuilt->old_vers_heap = NULL;
  348. return(prebuilt);
  349. }
  350. /************************************************************************
  351. Free a prebuilt struct for a MySQL table handle. */
  352. void
  353. row_prebuilt_free(
  354. /*==============*/
  355. row_prebuilt_t* prebuilt) /* in, own: prebuilt struct */
  356. {
  357. ulint i;
  358. if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
  359.     || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
  360. fprintf(stderr,
  361. "InnoDB: Error: trying to free a corruptn"
  362. "InnoDB: table handle. Magic n %lu, magic n2 %lu, table name",
  363. (ulong) prebuilt->magic_n,
  364. (ulong) prebuilt->magic_n2);
  365. ut_print_name(stderr, NULL, prebuilt->table->name);
  366. putc('n', stderr);
  367. mem_analyze_corruption((byte*)prebuilt);
  368. ut_error;
  369. }
  370. prebuilt->magic_n = ROW_PREBUILT_FREED;
  371. prebuilt->magic_n2 = ROW_PREBUILT_FREED;
  372. btr_pcur_free_for_mysql(prebuilt->pcur);
  373. btr_pcur_free_for_mysql(prebuilt->clust_pcur);
  374. if (prebuilt->mysql_template) {
  375. mem_free(prebuilt->mysql_template);
  376. }
  377. if (prebuilt->ins_graph) {
  378. que_graph_free_recursive(prebuilt->ins_graph);
  379. }
  380. if (prebuilt->sel_graph) {
  381. que_graph_free_recursive(prebuilt->sel_graph);
  382. }
  383. if (prebuilt->upd_graph) {
  384. que_graph_free_recursive(prebuilt->upd_graph);
  385. }
  386. if (prebuilt->blob_heap) {
  387. mem_heap_free(prebuilt->blob_heap);
  388. }
  389. if (prebuilt->old_vers_heap) {
  390. mem_heap_free(prebuilt->old_vers_heap);
  391. }
  392. for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
  393. if (prebuilt->fetch_cache[i] != NULL) {
  394. if ((ROW_PREBUILT_FETCH_MAGIC_N !=
  395.     mach_read_from_4((prebuilt->fetch_cache[i]) - 4))
  396.     || (ROW_PREBUILT_FETCH_MAGIC_N !=
  397.     mach_read_from_4((prebuilt->fetch_cache[i])
  398.      + prebuilt->mysql_row_len))) {
  399. fputs(
  400. "InnoDB: Error: trying to free a corruptn"
  401. "InnoDB: fetch buffer.n", stderr);
  402. mem_analyze_corruption(
  403. prebuilt->fetch_cache[i]);
  404. ut_error;
  405. }
  406. mem_free((prebuilt->fetch_cache[i]) - 4);
  407. }
  408. }
  409. dict_table_decrement_handle_count(prebuilt->table);
  410. mem_heap_free(prebuilt->heap);
  411. }
  412. /*************************************************************************
  413. Updates the transaction pointers in query graphs stored in the prebuilt
  414. struct. */
  415. void
  416. row_update_prebuilt_trx(
  417. /*====================*/
  418. /* out: prebuilt dtuple */
  419. row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
  420. handle */
  421. trx_t* trx) /* in: transaction handle */
  422. {
  423. if (trx->magic_n != TRX_MAGIC_N) {
  424. fprintf(stderr,
  425. "InnoDB: Error: trying to use a corruptn"
  426. "InnoDB: trx handle. Magic n %lun",
  427. (ulong) trx->magic_n);
  428. mem_analyze_corruption((byte*)trx);
  429. ut_error;
  430. }
  431. if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
  432. fprintf(stderr,
  433. "InnoDB: Error: trying to use a corruptn"
  434. "InnoDB: table handle. Magic n %lu, table name",
  435. (ulong) prebuilt->magic_n);
  436. ut_print_name(stderr, NULL, prebuilt->table->name);
  437. putc('n', stderr);
  438. mem_analyze_corruption((byte*)prebuilt);
  439. ut_error;
  440. }
  441. prebuilt->trx = trx;
  442. if (prebuilt->ins_graph) {
  443. prebuilt->ins_graph->trx = trx;
  444. }
  445. if (prebuilt->upd_graph) {
  446. prebuilt->upd_graph->trx = trx;
  447. }
  448. if (prebuilt->sel_graph) {
  449. prebuilt->sel_graph->trx = trx;
  450. }
  451. }
  452. /*************************************************************************
  453. Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
  454. has not yet been built in the prebuilt struct, then this function first
  455. builds it. */
  456. static
  457. dtuple_t*
  458. row_get_prebuilt_insert_row(
  459. /*========================*/
  460. /* out: prebuilt dtuple */
  461. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  462. handle */
  463. {
  464. ins_node_t* node;
  465. dtuple_t* row;
  466. dict_table_t* table = prebuilt->table;
  467. ulint i;
  468. ut_ad(prebuilt && table && prebuilt->trx);
  469. if (prebuilt->ins_node == NULL) {
  470. /* Not called before for this handle: create an insert node
  471. and query graph to the prebuilt struct */
  472. node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
  473. prebuilt->ins_node = node;
  474. if (prebuilt->ins_upd_rec_buff == NULL) {
  475. prebuilt->ins_upd_rec_buff = mem_heap_alloc(
  476. prebuilt->heap,
  477. prebuilt->mysql_row_len);
  478. }
  479. row = dtuple_create(prebuilt->heap,
  480. dict_table_get_n_cols(table));
  481. dict_table_copy_types(row, table);
  482. /* We init the value of every field to the SQL NULL to avoid
  483. a debug assertion from failing */
  484. for (i = 0; i < dtuple_get_n_fields(row); i++) {
  485.     
  486.         dtuple_get_nth_field(row, i)->len = UNIV_SQL_NULL;
  487. }
  488. ins_node_set_new_row(node, row);
  489. prebuilt->ins_graph =
  490. que_node_get_parent(
  491. pars_complete_graph_for_exec(node,
  492. prebuilt->trx,
  493. prebuilt->heap));
  494. prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
  495. }
  496. return(prebuilt->ins_node->row);
  497. }
  498. /*************************************************************************
  499. Updates the table modification counter and calculates new estimates
  500. for table and index statistics if necessary. */
  501. UNIV_INLINE
  502. void
  503. row_update_statistics_if_needed(
  504. /*============================*/
  505. dict_table_t* table) /* in: table */
  506. {
  507. ulint counter;
  508. counter = table->stat_modified_counter;
  509. table->stat_modified_counter = counter + 1;
  510. /* Calculate new statistics if 1 / 16 of table has been modified
  511. since the last time a statistics batch was run, or if
  512. stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
  513. We calculate statistics at most every 16th round, since we may have
  514. a counter table which is very small and updated very often. */
  515. if (counter > 2000000000
  516.     || ((ib_longlong)counter > 16 + table->stat_n_rows / 16)) {
  517. dict_update_statistics(table);
  518. }
  519. }
  520.   
  521. /*************************************************************************
  522. Unlocks an AUTO_INC type lock possibly reserved by trx. */
  523. void   
  524. row_unlock_table_autoinc_for_mysql(
  525. /*===============================*/
  526. trx_t* trx) /* in: transaction */
  527. {
  528. if (!trx->auto_inc_lock) {
  529. return;
  530. }
  531. lock_table_unlock_auto_inc(trx);
  532. }
  533. /*************************************************************************
  534. Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
  535. AUTO_INC lock gives exclusive access to the auto-inc counter of the
  536. table. The lock is reserved only for the duration of an SQL statement.
  537. It is not compatible with another AUTO_INC or exclusive lock on the
  538. table. */
  539. int
  540. row_lock_table_autoinc_for_mysql(
  541. /*=============================*/
  542. /* out: error code or DB_SUCCESS */
  543. row_prebuilt_t* prebuilt) /* in: prebuilt struct in the MySQL
  544. table handle */
  545. {
  546. trx_t* trx  = prebuilt->trx;
  547. ins_node_t* node = prebuilt->ins_node;
  548. que_thr_t* thr;
  549. ulint err;
  550. ibool was_lock_wait;
  551. ut_ad(trx);
  552. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  553. if (trx->auto_inc_lock) {
  554. return(DB_SUCCESS);
  555. }
  556. trx->op_info = "setting auto-inc lock";
  557. if (node == NULL) {
  558. row_get_prebuilt_insert_row(prebuilt);
  559. node = prebuilt->ins_node;
  560. }
  561. /* We use the insert query graph as the dummy graph needed
  562. in the lock module call */
  563. thr = que_fork_get_first_thr(prebuilt->ins_graph);
  564. que_thr_move_to_run_state_for_mysql(thr, trx);
  565. run_again:
  566. thr->run_node = node;
  567. thr->prev_node = node;
  568. /* It may be that the current session has not yet started
  569. its transaction, or it has been committed: */
  570. trx_start_if_not_started(trx);
  571. err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
  572. trx->error_state = err;
  573. if (err != DB_SUCCESS) {
  574. que_thr_stop_for_mysql(thr);
  575. was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
  576. if (was_lock_wait) {
  577. goto run_again;
  578. }
  579. trx->op_info = "";
  580. return((int) err);
  581. }
  582. que_thr_stop_for_mysql_no_error(thr, trx);
  583. trx->op_info = "";
  584. return((int) err);
  585. }
  586. /*************************************************************************
  587. Unlocks all table locks explicitly requested by trx (with LOCK TABLES,
  588. lock type LOCK_TABLE_EXP). */
  589. void   
  590. row_unlock_tables_for_mysql(
  591. /*========================*/
  592. trx_t* trx) /* in: transaction */
  593. {
  594. if (!trx->n_lock_table_exp) {
  595. return;
  596. }
  597. mutex_enter(&kernel_mutex);
  598. lock_release_tables_off_kernel(trx);
  599. mutex_exit(&kernel_mutex);
  600. }
  601. /*************************************************************************
  602. Sets a table lock on the table mentioned in prebuilt. */
  603. int
  604. row_lock_table_for_mysql(
  605. /*=====================*/
  606. /* out: error code or DB_SUCCESS */
  607. row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL
  608. table handle */
  609. dict_table_t* table, /* in: table to lock, or NULL
  610. if prebuilt->table should be
  611. locked as LOCK_TABLE_EXP |
  612. prebuilt->select_lock_type */
  613. ulint mode) /* in: lock mode of table */
  614. {
  615. trx_t* trx  = prebuilt->trx;
  616. que_thr_t* thr;
  617. ulint err;
  618. ibool was_lock_wait;
  619. ut_ad(trx);
  620. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  621. trx->op_info = "setting table lock";
  622. if (prebuilt->sel_graph == NULL) {
  623. /* Build a dummy select query graph */
  624. row_prebuild_sel_graph(prebuilt);
  625. }
  626. /* We use the select query graph as the dummy graph needed
  627. in the lock module call */
  628. thr = que_fork_get_first_thr(prebuilt->sel_graph);
  629. que_thr_move_to_run_state_for_mysql(thr, trx);
  630. run_again:
  631. thr->run_node = thr;
  632. thr->prev_node = thr->common.parent;
  633. /* It may be that the current session has not yet started
  634. its transaction, or it has been committed: */
  635. trx_start_if_not_started(trx);
  636. if (table) {
  637. err = lock_table(0, table, mode, thr);
  638. } else {
  639. err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
  640. prebuilt->select_lock_type, thr);
  641. }
  642. trx->error_state = err;
  643. if (err != DB_SUCCESS) {
  644. que_thr_stop_for_mysql(thr);
  645. was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
  646. if (was_lock_wait) {
  647. goto run_again;
  648. }
  649. trx->op_info = "";
  650. return((int) err);
  651. }
  652. que_thr_stop_for_mysql_no_error(thr, trx);
  653. trx->op_info = "";
  654. return((int) err);
  655. }
  656. /*************************************************************************
  657. Does an insert for MySQL. */
  658. int
  659. row_insert_for_mysql(
  660. /*=================*/
  661. /* out: error code or DB_SUCCESS */
  662. byte* mysql_rec, /* in: row in the MySQL format */
  663. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  664. handle */
  665. {
  666. trx_savept_t savept;
  667. que_thr_t* thr;
  668. ulint err;
  669. ibool was_lock_wait;
  670. trx_t* trx  = prebuilt->trx;
  671. ins_node_t* node = prebuilt->ins_node;
  672. ut_ad(trx);
  673. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  674. if (prebuilt->table->ibd_file_missing) {
  675.         ut_print_timestamp(stderr);
  676.         fprintf(stderr, "  InnoDB: Error:n"
  677. "InnoDB: MySQL is trying to use a table handle but the .ibd file forn"
  678. "InnoDB: table %s does not exist.n"
  679. "InnoDB: Have you deleted the .ibd file from the database directory undern"
  680. "InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?n"
  681. "InnoDB: Look fromn"
  682. "http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.htmln"
  683. "InnoDB: how you can resolve the problem.n",
  684. prebuilt->table->name);
  685. return(DB_ERROR);
  686. }
  687. if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
  688. fprintf(stderr,
  689. "InnoDB: Error: trying to free a corruptn"
  690. "InnoDB: table handle. Magic n %lu, table name",
  691. (ulong) prebuilt->magic_n);
  692. ut_print_name(stderr, prebuilt->trx, prebuilt->table->name);
  693. putc('n', stderr);
  694. mem_analyze_corruption((byte*)prebuilt);
  695. ut_error;
  696. }
  697. if (srv_created_new_raw || srv_force_recovery) {
  698. fputs(
  699. "InnoDB: A new raw disk partition was initialized orn"
  700. "InnoDB: innodb_force_recovery is on: we do not allown"
  701. "InnoDB: database modifications by the user. Shut downn"
  702. "InnoDB: mysqld and edit my.cnf so that newraw is replacedn"
  703. "InnoDB: with raw, and innodb_force_... is removed.n",
  704. stderr);
  705. return(DB_ERROR);
  706. }
  707. trx->op_info = "inserting";
  708. row_mysql_delay_if_needed();
  709. trx_start_if_not_started(trx);
  710. if (node == NULL) {
  711. row_get_prebuilt_insert_row(prebuilt);
  712. node = prebuilt->ins_node;
  713. }
  714. row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
  715. savept = trx_savept_take(trx);
  716. thr = que_fork_get_first_thr(prebuilt->ins_graph);
  717. if (prebuilt->sql_stat_start) {
  718. node->state = INS_NODE_SET_IX_LOCK;
  719. prebuilt->sql_stat_start = FALSE;
  720. } else {
  721. node->state = INS_NODE_ALLOC_ROW_ID;
  722. }
  723. que_thr_move_to_run_state_for_mysql(thr, trx);
  724. run_again:
  725. thr->run_node = node;
  726. thr->prev_node = node;
  727. row_ins_step(thr);
  728. err = trx->error_state;
  729. if (err != DB_SUCCESS) {
  730. que_thr_stop_for_mysql(thr);
  731. was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
  732. &savept);
  733. if (was_lock_wait) {
  734. goto run_again;
  735. }
  736. trx->op_info = "";
  737. return((int) err);
  738. }
  739. que_thr_stop_for_mysql_no_error(thr, trx);
  740. prebuilt->table->stat_n_rows++;
  741. srv_n_rows_inserted++;
  742. if (prebuilt->table->stat_n_rows == 0) {
  743. /* Avoid wrap-over */
  744. prebuilt->table->stat_n_rows--;
  745. }
  746. row_update_statistics_if_needed(prebuilt->table);
  747. trx->op_info = "";
  748. return((int) err);
  749. }
  750. /*************************************************************************
  751. Builds a dummy query graph used in selects. */
  752. void
  753. row_prebuild_sel_graph(
  754. /*===================*/
  755. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  756. handle */
  757. {
  758. sel_node_t* node;
  759. ut_ad(prebuilt && prebuilt->trx);
  760. if (prebuilt->sel_graph == NULL) {
  761. node = sel_node_create(prebuilt->heap);
  762. prebuilt->sel_graph =
  763. que_node_get_parent(
  764. pars_complete_graph_for_exec(node,
  765. prebuilt->trx,
  766. prebuilt->heap));
  767. prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
  768. }
  769. }
  770. /*************************************************************************
  771. Creates an query graph node of 'update' type to be used in the MySQL
  772. interface. */
  773. upd_node_t*
  774. row_create_update_node_for_mysql(
  775. /*=============================*/
  776. /* out, own: update node */
  777. dict_table_t* table, /* in: table to update */
  778. mem_heap_t* heap) /* in: mem heap from which allocated */
  779. {
  780. upd_node_t* node;
  781. node = upd_node_create(heap);
  782. node->in_mysql_interface = TRUE;
  783. node->is_delete = FALSE;
  784. node->searched_update = FALSE;
  785. node->select_will_do_update = FALSE;
  786. node->select = NULL;
  787. node->pcur = btr_pcur_create_for_mysql();
  788. node->table = table;
  789. node->update = upd_create(dict_table_get_n_cols(table), heap);
  790. node->update_n_fields = dict_table_get_n_cols(table);
  791. UT_LIST_INIT(node->columns);
  792. node->has_clust_rec_x_lock = TRUE;
  793. node->cmpl_info = 0;
  794. node->table_sym = NULL;
  795. node->col_assign_list = NULL;
  796. return(node);
  797. }
  798. /*************************************************************************
  799. Gets pointer to a prebuilt update vector used in updates. If the update
  800. graph has not yet been built in the prebuilt struct, then this function
  801. first builds it. */
  802. upd_t*
  803. row_get_prebuilt_update_vector(
  804. /*===========================*/
  805. /* out: prebuilt update vector */
  806. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  807. handle */
  808. {
  809. dict_table_t* table = prebuilt->table;
  810. upd_node_t* node;
  811. ut_ad(prebuilt && table && prebuilt->trx);
  812. if (prebuilt->upd_node == NULL) {
  813. /* Not called before for this handle: create an update node
  814. and query graph to the prebuilt struct */
  815. node = row_create_update_node_for_mysql(table, prebuilt->heap);
  816. prebuilt->upd_node = node;
  817. prebuilt->upd_graph =
  818. que_node_get_parent(
  819. pars_complete_graph_for_exec(node,
  820. prebuilt->trx,
  821. prebuilt->heap));
  822. prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
  823. }
  824. return(prebuilt->upd_node->update);
  825. }
  826. /*************************************************************************
  827. Does an update or delete of a row for MySQL. */
  828. int
  829. row_update_for_mysql(
  830. /*=================*/
  831. /* out: error code or DB_SUCCESS */
  832. byte* mysql_rec, /* in: the row to be updated, in
  833. the MySQL format */
  834. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  835. handle */
  836. {
  837. trx_savept_t savept;
  838. ulint err;
  839. que_thr_t* thr;
  840. ibool was_lock_wait;
  841. dict_index_t* clust_index; 
  842. /* ulint ref_len; */
  843. upd_node_t* node;
  844. dict_table_t* table = prebuilt->table;
  845. trx_t* trx = prebuilt->trx;
  846. ut_ad(prebuilt && trx);
  847. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  848. UT_NOT_USED(mysql_rec);
  849. if (prebuilt->table->ibd_file_missing) {
  850.         ut_print_timestamp(stderr);
  851.         fprintf(stderr, "  InnoDB: Error:n"
  852. "InnoDB: MySQL is trying to use a table handle but the .ibd file forn"
  853. "InnoDB: table %s does not exist.n"
  854. "InnoDB: Have you deleted the .ibd file from the database directory undern"
  855. "InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?n"
  856. "InnoDB: Look fromn"
  857. "http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.htmln"
  858. "InnoDB: how you can resolve the problem.n",
  859. prebuilt->table->name);
  860. return(DB_ERROR);
  861. }
  862. if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
  863. fprintf(stderr,
  864. "InnoDB: Error: trying to free a corruptn"
  865. "InnoDB: table handle. Magic n %lu, table name",
  866. (ulong) prebuilt->magic_n);
  867. ut_print_name(stderr, prebuilt->trx, prebuilt->table->name);
  868. putc('n', stderr);
  869. mem_analyze_corruption((byte*)prebuilt);
  870. ut_error;
  871. }
  872. if (srv_created_new_raw || srv_force_recovery) {
  873. fputs(
  874. "InnoDB: A new raw disk partition was initialized orn"
  875. "InnoDB: innodb_force_recovery is on: we do not allown"
  876. "InnoDB: database modifications by the user. Shut downn"
  877. "InnoDB: mysqld and edit my.cnf so that newraw is replacedn"
  878. "InnoDB: with raw, and innodb_force_... is removed.n",
  879. stderr);
  880. return(DB_ERROR);
  881. }
  882. trx->op_info = "updating or deleting";
  883. row_mysql_delay_if_needed();
  884. trx_start_if_not_started(trx);
  885. node = prebuilt->upd_node;
  886. clust_index = dict_table_get_first_index(table);
  887. if (prebuilt->pcur->btr_cur.index == clust_index) {
  888. btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
  889. } else {
  890. btr_pcur_copy_stored_position(node->pcur,
  891. prebuilt->clust_pcur);
  892. }
  893. ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
  894.  
  895. /* MySQL seems to call rnd_pos before updating each row it
  896. has cached: we can get the correct cursor position from
  897. prebuilt->pcur; NOTE that we cannot build the row reference
  898. from mysql_rec if the clustered index was automatically
  899. generated for the table: MySQL does not know anything about
  900. the row id used as the clustered index key */
  901. savept = trx_savept_take(trx);
  902. thr = que_fork_get_first_thr(prebuilt->upd_graph);
  903. node->state = UPD_NODE_UPDATE_CLUSTERED;
  904. ut_ad(!prebuilt->sql_stat_start);
  905. que_thr_move_to_run_state_for_mysql(thr, trx);
  906. run_again:
  907. thr->run_node = node;
  908. thr->prev_node = node;
  909. row_upd_step(thr);
  910. err = trx->error_state;
  911. if (err != DB_SUCCESS) {
  912. que_thr_stop_for_mysql(thr);
  913. if (err == DB_RECORD_NOT_FOUND) {
  914. trx->error_state = DB_SUCCESS;
  915. trx->op_info = "";
  916. return((int) err);
  917. }
  918. was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
  919. &savept);
  920. if (was_lock_wait) {
  921. goto run_again;
  922. }
  923. trx->op_info = "";
  924. return((int) err);
  925. }
  926. que_thr_stop_for_mysql_no_error(thr, trx);
  927. if (node->is_delete) {
  928. if (prebuilt->table->stat_n_rows > 0) {
  929. prebuilt->table->stat_n_rows--;
  930. }
  931. srv_n_rows_deleted++;
  932. } else {
  933. srv_n_rows_updated++;
  934. }
  935. row_update_statistics_if_needed(prebuilt->table);
  936. trx->op_info = "";
  937. return((int) err);
  938. }
  939. /**************************************************************************
  940. Does a cascaded delete or set null in a foreign key operation. */
  941. ulint
  942. row_update_cascade_for_mysql(
  943. /*=========================*/
  944. /* out: error code or DB_SUCCESS */
  945. que_thr_t* thr, /* in: query thread */
  946. upd_node_t* node, /* in: update node used in the cascade
  947. or set null operation */
  948. dict_table_t* table) /* in: table where we do the operation */
  949. {
  950. ulint err;
  951. trx_t* trx;
  952. trx = thr_get_trx(thr);
  953. run_again:
  954. thr->run_node = node;
  955. thr->prev_node = node;
  956. row_upd_step(thr);
  957. err = trx->error_state;
  958. /* Note that the cascade node is a subnode of another InnoDB
  959. query graph node. We do a normal lock wait in this node, but
  960. all errors are handled by the parent node. */
  961. if (err == DB_LOCK_WAIT) {
  962. /* Handle lock wait here */
  963. que_thr_stop_for_mysql(thr);
  964. srv_suspend_mysql_thread(thr);
  965. /* Note that a lock wait may also end in a lock wait timeout,
  966. or this transaction is picked as a victim in selective
  967. deadlock resolution */
  968. if (trx->error_state != DB_SUCCESS) {
  969. return(trx->error_state);
  970. }
  971. /* Retry operation after a normal lock wait */
  972. goto run_again;
  973. }
  974. if (err != DB_SUCCESS) {
  975. return(err);
  976. }
  977. if (node->is_delete) {
  978. if (table->stat_n_rows > 0) {
  979. table->stat_n_rows--;
  980. }
  981. srv_n_rows_deleted++;
  982. } else {
  983. srv_n_rows_updated++;
  984. }
  985. row_update_statistics_if_needed(table);
  986. return(err);
  987. }
  988. /*************************************************************************
  989. Checks if a table is such that we automatically created a clustered
  990. index on it (on row id). */
  991. ibool
  992. row_table_got_default_clust_index(
  993. /*==============================*/
  994. dict_table_t* table)
  995. {
  996. dict_index_t* clust_index;
  997. clust_index = dict_table_get_first_index(table);
  998. if (dtype_get_mtype(dict_index_get_nth_type(clust_index, 0))
  999.   == DATA_SYS) {
  1000.   return(TRUE);
  1001. }
  1002. return(FALSE);
  1003. }
  1004. /*************************************************************************
  1005. Calculates the key number used inside MySQL for an Innobase index. We have
  1006. to take into account if we generated a default clustered index for the table */
  1007. ulint
  1008. row_get_mysql_key_number_for_index(
  1009. /*===============================*/
  1010. dict_index_t* index)
  1011. {
  1012. dict_index_t* ind;
  1013. ulint i;
  1014. ut_a(index);
  1015. i = 0;
  1016. ind = dict_table_get_first_index(index->table);
  1017. while (index != ind) {
  1018. ind = dict_table_get_next_index(ind);
  1019. i++;
  1020. }
  1021. if (row_table_got_default_clust_index(index->table)) {
  1022. ut_a(i > 0);
  1023. i--;
  1024. }
  1025. return(i);
  1026. }
  1027. /*************************************************************************
  1028. Recovers an orphaned tmp table inside InnoDB by renaming it. In the table
  1029. name #sql becomes rsql, and "_recover_innodb_tmp_table" is catenated to
  1030. the end of name. table->name should be of the form
  1031. "dbname/rsql..._recover_innodb_tmp_table". This renames a table whose
  1032. name is "#sql..." */
  1033. static
  1034. int
  1035. row_mysql_recover_tmp_table(
  1036. /*========================*/
  1037. /* out: error code or DB_SUCCESS */
  1038. dict_table_t* table, /* in: table definition */
  1039. trx_t* trx) /* in: transaction handle */
  1040. {
  1041. const char* ptr = strstr(table->name, "/rsql");
  1042. if (!ptr) {
  1043. /* table name does not begin with "/rsql" */
  1044. trx_commit_for_mysql(trx);
  1045. return(DB_ERROR);
  1046. }
  1047. else {
  1048. int status;
  1049. int namelen = (int) strlen(table->name);
  1050. char* old_name = mem_strdupl(table->name, namelen);
  1051. /* replace "rsql" with "#sql" */
  1052. old_name[ptr - table->name + 1] = '#';
  1053. /* remove "_recover_innodb_tmp_table" suffix */
  1054. ut_ad(namelen > (int) sizeof S_recover_innodb_tmp_table);
  1055. ut_ad(!strcmp(old_name + namelen + 1 -
  1056. sizeof S_recover_innodb_tmp_table,
  1057. S_recover_innodb_tmp_table));
  1058. old_name[namelen + 1 - sizeof S_recover_innodb_tmp_table] = 0;
  1059. status = row_rename_table_for_mysql(old_name,
  1060. table->name, trx);
  1061. mem_free(old_name);
  1062. return(status);
  1063. }
  1064. }
  1065. /*************************************************************************
  1066. Locks the data dictionary in shared mode from modifications, for performing
  1067. foreign key check, rollback, or other operation invisible to MySQL. */
  1068. void
  1069. row_mysql_freeze_data_dictionary(
  1070. /*=============================*/
  1071. trx_t* trx) /* in: transaction */
  1072. {
  1073. ut_a(trx->dict_operation_lock_mode == 0);
  1074. rw_lock_s_lock(&dict_operation_lock);
  1075. trx->dict_operation_lock_mode = RW_S_LATCH;
  1076. }
  1077. /*************************************************************************
  1078. Unlocks the data dictionary shared lock. */
  1079. void
  1080. row_mysql_unfreeze_data_dictionary(
  1081. /*===============================*/
  1082. trx_t* trx) /* in: transaction */
  1083. {
  1084. ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
  1085. rw_lock_s_unlock(&dict_operation_lock);
  1086. trx->dict_operation_lock_mode = 0;
  1087. }
  1088. /*************************************************************************
  1089. Locks the data dictionary exclusively for performing a table create or other
  1090. data dictionary modification operation. */
  1091. void
  1092. row_mysql_lock_data_dictionary(
  1093. /*===========================*/
  1094. trx_t* trx) /* in: transaction */
  1095. {
  1096. ut_a(trx->dict_operation_lock_mode == 0
  1097.      || trx->dict_operation_lock_mode == RW_X_LATCH);
  1098. /* Serialize data dictionary operations with dictionary mutex:
  1099. no deadlocks or lock waits can occur then in these operations */
  1100. rw_lock_x_lock(&dict_operation_lock);
  1101. trx->dict_operation_lock_mode = RW_X_LATCH;
  1102. mutex_enter(&(dict_sys->mutex));
  1103. }
  1104. /*************************************************************************
  1105. Unlocks the data dictionary exclusive lock. */
  1106. void
  1107. row_mysql_unlock_data_dictionary(
  1108. /*=============================*/
  1109. trx_t* trx) /* in: transaction */
  1110. {
  1111. ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
  1112. /* Serialize data dictionary operations with dictionary mutex:
  1113. no deadlocks can occur then in these operations */
  1114. mutex_exit(&(dict_sys->mutex));
  1115. rw_lock_x_unlock(&dict_operation_lock);
  1116. trx->dict_operation_lock_mode = 0;
  1117. }
  1118. /*************************************************************************
  1119. Does a table creation operation for MySQL.  If the name of the table
  1120. to be created is equal with one of the predefined magic table names,
  1121. then this also starts printing the corresponding monitor output by
  1122. the master thread. */
  1123. int
  1124. row_create_table_for_mysql(
  1125. /*=======================*/
  1126. /* out: error code or DB_SUCCESS */
  1127. dict_table_t* table, /* in: table definition */
  1128. trx_t* trx) /* in: transaction handle */
  1129. {
  1130. tab_node_t* node;
  1131. mem_heap_t* heap;
  1132. que_thr_t* thr;
  1133. const char* table_name;
  1134. ulint table_name_len;
  1135. ulint err;
  1136. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  1137. #ifdef UNIV_SYNC_DEBUG
  1138. ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
  1139. ut_ad(mutex_own(&(dict_sys->mutex)));
  1140. #endif /* UNIV_SYNC_DEBUG */
  1141. ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
  1142. if (srv_created_new_raw) {
  1143. fputs(
  1144. "InnoDB: A new raw disk partition was initialized orn"
  1145. "InnoDB: innodb_force_recovery is on: we do not allown"
  1146. "InnoDB: database modifications by the user. Shut downn"
  1147. "InnoDB: mysqld and edit my.cnf so that newraw is replacedn"
  1148. "InnoDB: with raw, and innodb_force_... is removed.n",
  1149. stderr);
  1150. trx_commit_for_mysql(trx);
  1151. return(DB_ERROR);
  1152. }
  1153. trx->op_info = "creating table";
  1154. if (row_mysql_is_system_table(table->name)) {
  1155. fprintf(stderr,
  1156.     "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.n"
  1157.     "InnoDB: MySQL system tables must be of the MyISAM type!n",
  1158. table->name);
  1159. trx_commit_for_mysql(trx);
  1160. return(DB_ERROR);
  1161. }
  1162. trx_start_if_not_started(trx);
  1163. if (row_mysql_is_recovered_tmp_table(table->name)) {
  1164. /* MySQL prevents accessing of tables whose name begins
  1165. with #sql, that is temporary tables. If mysqld crashes in
  1166. the middle of an ALTER TABLE, we may get an orphaned
  1167. #sql-table in the tablespace. We have here a special
  1168. mechanism to recover such tables by renaming them to
  1169. rsql... */
  1170.  
  1171. return(row_mysql_recover_tmp_table(table, trx));
  1172. }
  1173. /* The table name is prefixed with the database name and a '/'.
  1174. Certain table names starting with 'innodb_' have their special
  1175. meaning regardless of the database name.  Thus, we need to
  1176. ignore the database name prefix in the comparisons. */
  1177. table_name = strchr(table->name, '/');
  1178. ut_a(table_name);
  1179. table_name++;
  1180. table_name_len = strlen(table_name) + 1;
  1181. if (table_name_len == sizeof S_innodb_monitor
  1182. && !memcmp(table_name, S_innodb_monitor,
  1183. sizeof S_innodb_monitor)) {
  1184. /* Table equals "innodb_monitor":
  1185. start monitor prints */
  1186.  
  1187. srv_print_innodb_monitor = TRUE;
  1188. /* The lock timeout monitor thread also takes care
  1189. of InnoDB monitor prints */
  1190. os_event_set(srv_lock_timeout_thread_event);
  1191. } else if (table_name_len == sizeof S_innodb_lock_monitor
  1192. && !memcmp(table_name, S_innodb_lock_monitor,
  1193. sizeof S_innodb_lock_monitor)) {
  1194. srv_print_innodb_monitor = TRUE;
  1195. srv_print_innodb_lock_monitor = TRUE;
  1196. os_event_set(srv_lock_timeout_thread_event);
  1197. } else if (table_name_len == sizeof S_innodb_tablespace_monitor
  1198. && !memcmp(table_name, S_innodb_tablespace_monitor,
  1199. sizeof S_innodb_tablespace_monitor)) {
  1200. srv_print_innodb_tablespace_monitor = TRUE;
  1201. os_event_set(srv_lock_timeout_thread_event);
  1202. } else if (table_name_len == sizeof S_innodb_table_monitor
  1203. && !memcmp(table_name, S_innodb_table_monitor,
  1204. sizeof S_innodb_table_monitor)) {
  1205. srv_print_innodb_table_monitor = TRUE;
  1206. os_event_set(srv_lock_timeout_thread_event);
  1207. } else if (table_name_len == sizeof S_innodb_mem_validate
  1208. && !memcmp(table_name, S_innodb_mem_validate,
  1209. sizeof S_innodb_mem_validate)) {
  1210.         /* We define here a debugging feature intended for
  1211. developers */
  1212. fputs("Validating InnoDB memory:n"
  1213.  "to use this feature you must compile InnoDB withn"
  1214.  "UNIV_MEM_DEBUG defined in univ.i and the server must ben"
  1215.  "quiet because allocation from a mem heap is not protectedn"
  1216. "by any semaphore.n", stderr);
  1217. #ifdef UNIV_MEM_DEBUG
  1218. ut_a(mem_validate());
  1219. fputs("Memory validatedn", stderr);
  1220. #else /* UNIV_MEM_DEBUG */
  1221. fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)n",
  1222. stderr);
  1223. #endif /* UNIV_MEM_DEBUG */
  1224. }
  1225. heap = mem_heap_create(512);
  1226. trx->dict_operation = TRUE;
  1227. node = tab_create_graph_create(table, heap);
  1228. thr = pars_complete_graph_for_exec(node, trx, heap);
  1229. ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
  1230. que_run_threads(thr);
  1231. err = trx->error_state;
  1232. if (err != DB_SUCCESS) {
  1233. /* We have special error handling here */
  1234. trx->error_state = DB_SUCCESS;
  1235. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  1236. if (err == DB_OUT_OF_FILE_SPACE) {
  1237.      ut_print_timestamp(stderr);
  1238. fputs("  InnoDB: Warning: cannot create table ", 
  1239. stderr);
  1240. ut_print_name(stderr, trx, table->name);
  1241. fputs(" because tablespace fulln", stderr);
  1242. if (dict_table_get_low(table->name)) {
  1243.       row_drop_table_for_mysql(table->name, trx,
  1244. FALSE);
  1245. }
  1246. } else if (err == DB_DUPLICATE_KEY) {
  1247.      ut_print_timestamp(stderr);
  1248. fputs("  InnoDB: Error: table ", stderr);
  1249. ut_print_name(stderr, trx, table->name);
  1250. fputs(" already exists in InnoDB internaln"
  1251.      "InnoDB: data dictionary. Have you deleted the .frm filen"
  1252.      "InnoDB: and not used DROP TABLE? Have you used DROP DATABASEn"
  1253.      "InnoDB: for InnoDB tables in MySQL version <= 3.23.43?n"
  1254.      "InnoDB: See the Restrictions section of the InnoDB manual.n"
  1255.      "InnoDB: You can drop the orphaned table inside InnoDB byn"
  1256.      "InnoDB: creating an InnoDB table with the same name in anothern"
  1257.      "InnoDB: database and copying the .frm file to the current database.n"
  1258.      "InnoDB: Then MySQL thinks the table exists, and DROP TABLE willn"
  1259.      "InnoDB: succeed.n"
  1260.      "InnoDB: You can look for further help fromn"
  1261.      "InnoDB: http://dev.mysql.com/doc/mysql/en/"
  1262.      "InnoDB_troubleshooting_datadict.htmln", stderr);
  1263. }
  1264. /* We may also get err == DB_ERROR if the .ibd file for the
  1265. table already exists */
  1266. trx->error_state = DB_SUCCESS;
  1267. }
  1268. que_graph_free((que_t*) que_node_get_parent(thr));
  1269. trx->op_info = "";
  1270. return((int) err);
  1271. }
  1272. /*************************************************************************
  1273. Does an index creation operation for MySQL. TODO: currently failure
  1274. to create an index results in dropping the whole table! This is no problem
  1275. currently as all indexes must be created at the same time as the table. */
  1276. int
  1277. row_create_index_for_mysql(
  1278. /*=======================*/
  1279. /* out: error number or DB_SUCCESS */
  1280. dict_index_t* index, /* in: index definition */
  1281. trx_t* trx) /* in: transaction handle */
  1282. {
  1283. ind_node_t* node;
  1284. mem_heap_t* heap;
  1285. que_thr_t* thr;
  1286. ulint err;
  1287. ulint i, j;
  1288. #ifdef UNIV_SYNC_DEBUG
  1289. ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
  1290. ut_ad(mutex_own(&(dict_sys->mutex)));
  1291. #endif /* UNIV_SYNC_DEBUG */
  1292. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  1293. trx->op_info = "creating index";
  1294. trx_start_if_not_started(trx);
  1295. /* Check that the same column does not appear twice in the index.
  1296. Starting from 4.0.14, InnoDB should be able to cope with that, but
  1297. safer not to allow them. */
  1298. for (i = 0; i < dict_index_get_n_fields(index); i++) {
  1299. for (j = 0; j < i; j++) {
  1300. if (0 == ut_strcmp(
  1301.       dict_index_get_nth_field(index, j)->name,
  1302.       dict_index_get_nth_field(index, i)->name)) {
  1303. ut_print_timestamp(stderr);
  1304. fputs("  InnoDB: Error: column ", stderr);
  1305. ut_print_name(stderr, trx,
  1306. dict_index_get_nth_field(index, i)->name);
  1307. fputs(" appears twice in ", stderr);
  1308. dict_index_name_print(stderr, trx, index);
  1309. fputs("n"
  1310. "InnoDB: This is not allowed in InnoDB.n",
  1311. stderr);
  1312. err = DB_COL_APPEARS_TWICE_IN_INDEX;
  1313. goto error_handling;
  1314. }
  1315. }
  1316. /* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */
  1317. if (dict_index_get_nth_field(index, i)->prefix_len
  1318. >= DICT_MAX_COL_PREFIX_LEN) {
  1319. err = DB_TOO_BIG_RECORD;
  1320. goto error_handling;
  1321. }
  1322. }
  1323. if (row_mysql_is_recovered_tmp_table(index->table_name)) {
  1324. return(DB_SUCCESS);
  1325. }
  1326. heap = mem_heap_create(512);
  1327. trx->dict_operation = TRUE;
  1328. /* Note that the space id where we store the index is inherited from
  1329. the table in dict_build_index_def_step() in dict0crea.c. */
  1330. node = ind_create_graph_create(index, heap);
  1331. thr = pars_complete_graph_for_exec(node, trx, heap);
  1332. ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
  1333. que_run_threads(thr);
  1334.   err = trx->error_state;
  1335. que_graph_free((que_t*) que_node_get_parent(thr));
  1336. error_handling:
  1337. if (err != DB_SUCCESS) {
  1338. /* We have special error handling here */
  1339. trx->error_state = DB_SUCCESS;
  1340. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  1341. row_drop_table_for_mysql(index->table_name, trx, FALSE);
  1342. trx->error_state = DB_SUCCESS;
  1343. }
  1344. trx->op_info = "";
  1345. return((int) err);
  1346. }
  1347. /*************************************************************************
  1348. Scans a table create SQL string and adds to the data dictionary
  1349. the foreign key constraints declared in the string. This function
  1350. should be called after the indexes for a table have been created.
  1351. Each foreign key constraint must be accompanied with indexes in
  1352. bot participating tables. The indexes are allowed to contain more
  1353. fields than mentioned in the constraint. Check also that foreign key
  1354. constraints which reference this table are ok. */
  1355. int
  1356. row_table_add_foreign_constraints(
  1357. /*==============================*/
  1358. /* out: error code or DB_SUCCESS */
  1359. trx_t* trx, /* in: transaction */
  1360. const char* sql_string, /* in: table create statement where
  1361. foreign keys are declared like:
  1362. FOREIGN KEY (a, b) REFERENCES table2(c, d),
  1363. table2 can be written also with the
  1364. database name before it: test.table2 */
  1365. const char* name) /* in: table full name in the
  1366. normalized form
  1367. database_name/table_name */
  1368. {
  1369. ulint err;
  1370. #ifdef UNIV_SYNC_DEBUG
  1371. ut_ad(mutex_own(&(dict_sys->mutex)));
  1372. ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
  1373. #endif /* UNIV_SYNC_DEBUG */
  1374. ut_a(sql_string);
  1375. trx->op_info = "adding foreign keys";
  1376. trx_start_if_not_started(trx);
  1377. if (row_mysql_is_recovered_tmp_table(name)) {
  1378. return(DB_SUCCESS);
  1379. }
  1380. trx->dict_operation = TRUE;
  1381. err = dict_create_foreign_constraints(trx, sql_string, name);
  1382. if (err == DB_SUCCESS) {
  1383. /* Check that also referencing constraints are ok */
  1384. err = dict_load_foreigns(name, trx->check_foreigns);
  1385. }
  1386. if (err != DB_SUCCESS) {
  1387. /* We have special error handling here */
  1388. trx->error_state = DB_SUCCESS;
  1389. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  1390. row_drop_table_for_mysql(name, trx, FALSE);
  1391. trx->error_state = DB_SUCCESS;
  1392. }
  1393. return((int) err);
  1394. }
  1395. /*************************************************************************
  1396. Drops a table for MySQL as a background operation. MySQL relies on Unix
  1397. in ALTER TABLE to the fact that the table handler does not remove the
  1398. table before all handles to it has been removed. Furhermore, the MySQL's
  1399. call to drop table must be non-blocking. Therefore we do the drop table
  1400. as a background operation, which is taken care of by the master thread
  1401. in srv0srv.c. */
  1402. static
  1403. int
  1404. row_drop_table_for_mysql_in_background(
  1405. /*===================================*/
  1406. /* out: error code or DB_SUCCESS */
  1407. const char* name) /* in: table name */
  1408. {
  1409. ulint error;
  1410. trx_t* trx;
  1411. trx = trx_allocate_for_background();
  1412. /* If the original transaction was dropping a table referenced by
  1413. foreign keys, we must set the following to be able to drop the
  1414. table: */
  1415. trx->check_foreigns = FALSE;
  1416. /* fputs("InnoDB: Error: Dropping table ", stderr);
  1417. ut_print_name(stderr, name);
  1418. fputs(" in background drop listn", stderr); */
  1419.    /* Try to drop the table in InnoDB */
  1420.    error = row_drop_table_for_mysql(name, trx, FALSE);
  1421.   
  1422. /* Flush the log to reduce probability that the .frm files and
  1423. the InnoDB data dictionary get out-of-sync if the user runs
  1424. with innodb_flush_log_at_trx_commit = 0 */
  1425. log_buffer_flush_to_disk();
  1426.    trx_commit_for_mysql(trx);
  1427.    trx_free_for_background(trx);
  1428. return((int) error);
  1429. }
  1430. /*************************************************************************
  1431. The master thread in srv0srv.c calls this regularly to drop tables which
  1432. we must drop in background after queries to them have ended. Such lazy
  1433. dropping of tables is needed in ALTER TABLE on Unix. */
  1434. ulint
  1435. row_drop_tables_for_mysql_in_background(void)
  1436. /*=========================================*/
  1437. /* out: how many tables dropped
  1438. + remaining tables in list */
  1439. {
  1440. row_mysql_drop_t* drop;
  1441. dict_table_t* table;
  1442. ulint n_tables;
  1443. ulint n_tables_dropped = 0;
  1444. loop:
  1445. mutex_enter(&kernel_mutex);
  1446. if (!row_mysql_drop_list_inited) {
  1447. UT_LIST_INIT(row_mysql_drop_list);
  1448. row_mysql_drop_list_inited = TRUE;
  1449. }
  1450. drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
  1451. n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
  1452. mutex_exit(&kernel_mutex);
  1453. if (drop == NULL) {
  1454. /* All tables dropped */
  1455. return(n_tables + n_tables_dropped);
  1456. }
  1457. mutex_enter(&(dict_sys->mutex));
  1458. table = dict_table_get_low(drop->table_name);
  1459. mutex_exit(&(dict_sys->mutex));
  1460. if (table == NULL) {
  1461.         /* If for some reason the table has already been dropped
  1462. through some other mechanism, do not try to drop it */
  1463.         goto already_dropped;
  1464. }
  1465. if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
  1466. drop->table_name)) {
  1467. /* If the DROP fails for some table, we return, and let the
  1468. main thread retry later */
  1469. return(n_tables + n_tables_dropped);
  1470. }
  1471. n_tables_dropped++;
  1472. already_dropped:
  1473. mutex_enter(&kernel_mutex);
  1474. UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
  1475.         ut_print_timestamp(stderr);
  1476. fprintf(stderr,
  1477. "  InnoDB: Dropped table %s in background drop queue.n",
  1478. drop->table_name);
  1479. mem_free(drop->table_name);
  1480. mem_free(drop);
  1481. mutex_exit(&kernel_mutex);
  1482. goto loop;
  1483. }
  1484. /*************************************************************************
  1485. Get the background drop list length. NOTE: the caller must own the kernel
  1486. mutex! */
  1487. ulint
  1488. row_get_background_drop_list_len_low(void)
  1489. /*======================================*/
  1490. /* out: how many tables in list */
  1491. {
  1492. #ifdef UNIV_SYNC_DEBUG
  1493. ut_ad(mutex_own(&kernel_mutex));
  1494. #endif /* UNIV_SYNC_DEBUG */
  1495. if (!row_mysql_drop_list_inited) {
  1496. UT_LIST_INIT(row_mysql_drop_list);
  1497. row_mysql_drop_list_inited = TRUE;
  1498. }
  1499. return(UT_LIST_GET_LEN(row_mysql_drop_list));
  1500. }
  1501. /*************************************************************************
  1502. If a table is not yet in the drop list, adds the table to the list of tables
  1503. which the master thread drops in background. We need this on Unix because in
  1504. ALTER TABLE MySQL may call drop table even if the table has running queries on
  1505. it. Also, if there are running foreign key checks on the table, we drop the
  1506. table lazily. */
  1507. static
  1508. ibool
  1509. row_add_table_to_background_drop_list(
  1510. /*==================================*/
  1511. /* out: TRUE if the table was not yet in the
  1512. drop list, and was added there */
  1513. dict_table_t* table) /* in: table */
  1514. {
  1515. row_mysql_drop_t* drop;
  1516. mutex_enter(&kernel_mutex);
  1517. if (!row_mysql_drop_list_inited) {
  1518. UT_LIST_INIT(row_mysql_drop_list);
  1519. row_mysql_drop_list_inited = TRUE;
  1520. }
  1521. /* Look if the table already is in the drop list */
  1522. drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
  1523. while (drop != NULL) {
  1524. if (strcmp(drop->table_name, table->name) == 0) {
  1525. /* Already in the list */
  1526. mutex_exit(&kernel_mutex);
  1527. return(FALSE);
  1528. }
  1529. drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
  1530. }
  1531. drop = mem_alloc(sizeof(row_mysql_drop_t));
  1532. drop->table_name = mem_strdup(table->name);
  1533.  
  1534. UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
  1535. /* fputs("InnoDB: Adding table ", stderr);
  1536. ut_print_name(stderr, drop->table_name);
  1537. fputs(" to background drop listn", stderr); */
  1538. mutex_exit(&kernel_mutex);
  1539. return(TRUE);
  1540. }
  1541. /*************************************************************************
  1542. Discards the tablespace of a table which stored in an .ibd file. Discarding
  1543. means that this function deletes the .ibd file and assigns a new table id for
  1544. the table. Also the flag table->ibd_file_missing is set TRUE. */
  1545. int
  1546. row_discard_tablespace_for_mysql(
  1547. /*=============================*/
  1548. /* out: error code or DB_SUCCESS */
  1549. const char* name, /* in: table name */
  1550. trx_t* trx) /* in: transaction handle */
  1551. {
  1552. dict_foreign_t* foreign;
  1553. dulint new_id;
  1554. dict_table_t* table;
  1555. que_thr_t* thr;
  1556. que_t* graph = NULL;
  1557. ibool success;
  1558. ulint err;
  1559. char* buf;
  1560. /* How do we prevent crashes caused by ongoing operations on the table? Old
  1561. operations could try to access non-existent pages.
  1562. 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock
  1563. on the table before we can do DISCARD TABLESPACE. Then there are no running
  1564. queries on the table.
  1565. 2) Purge and rollback: we assign a new table id for the table. Since purge and
  1566. rollback look for the table based on the table id, they see the table as
  1567. 'dropped' and discard their operations.
  1568. 3) Insert buffer: we remove all entries for the tablespace in the insert
  1569. buffer tree; as long as the tablespace mem object does not exist, ongoing
  1570. insert buffer page merges are discarded in buf0rea.c. If we recreate the
  1571. tablespace mem object with IMPORT TABLESPACE later, then the tablespace will
  1572. have the same id, but the tablespace_version field in the mem object is
  1573. different, and ongoing old insert buffer page merges get discarded.
  1574. 4) Linear readahead and random readahead: we use the same method as in 3) to
  1575. discard ongoing operations.
  1576. 5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we
  1577. do not allow the discard. We also reserve the data dictionary latch. */
  1578. static const char discard_tablespace_proc1[] =
  1579. "PROCEDURE DISCARD_TABLESPACE_PROC () ISn"
  1580. "old_id CHAR;n"
  1581. "new_id CHAR;n"
  1582. "new_id_low INT;n"
  1583. "new_id_high INT;n"
  1584. "table_name CHAR;n"
  1585. "BEGINn"
  1586. "table_name := '";
  1587. static const char discard_tablespace_proc2[] =
  1588. "';n"
  1589. "new_id_high := %lu;n"
  1590. "new_id_low := %lu;n"
  1591.    "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));n"
  1592. "SELECT ID INTO old_idn"
  1593. "FROM SYS_TABLESn"
  1594. "WHERE NAME = table_name;n"
  1595. "IF (SQL %% NOTFOUND) THENn"
  1596. " COMMIT WORK;n"
  1597. " RETURN;n"
  1598. "END IF;n"
  1599. "UPDATE SYS_TABLES SET ID = new_idn"
  1600. "WHERE ID = old_id;n"
  1601. "UPDATE SYS_COLUMNS SET TABLE_ID = new_idn"
  1602. "WHERE TABLE_ID = old_id;n"
  1603. "UPDATE SYS_INDEXES SET TABLE_ID = new_idn"
  1604. "WHERE TABLE_ID = old_id;n"
  1605. "COMMIT WORK;n"
  1606. "END;n";
  1607. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  1608. trx->op_info = "discarding tablespace";
  1609. trx_start_if_not_started(trx);
  1610. /* Serialize data dictionary operations with dictionary mutex:
  1611. no deadlocks can occur then in these operations */
  1612. row_mysql_lock_data_dictionary(trx);
  1613. table = dict_table_get_low(name);
  1614. if (!table) {
  1615. err = DB_TABLE_NOT_FOUND;
  1616. goto funct_exit;
  1617. }
  1618. if (table->space == 0) {
  1619. ut_print_timestamp(stderr);
  1620. fputs("  InnoDB: Error: table ", stderr);
  1621. ut_print_name(stderr, trx, name);
  1622. fputs("n"
  1623. "InnoDB: is in the system tablespace 0 which cannot be discardedn", stderr);
  1624. err = DB_ERROR;
  1625. goto funct_exit;
  1626. }
  1627. if (table->n_foreign_key_checks_running > 0) {
  1628.         ut_print_timestamp(stderr);
  1629. fputs("  InnoDB: You are trying to DISCARD table ", stderr);
  1630. ut_print_name(stderr, trx, table->name);
  1631. fputs("n"
  1632.  "InnoDB: though there is a foreign key check running on it.n"
  1633.  "InnoDB: Cannot discard the table.n",
  1634. stderr);
  1635. err = DB_ERROR;
  1636. goto funct_exit;
  1637. }
  1638. /* Check if the table is referenced by foreign key constraints from
  1639. some other table (not the table itself) */
  1640. foreign = UT_LIST_GET_FIRST(table->referenced_list);
  1641. while (foreign && foreign->foreign_table == table) {
  1642. foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
  1643. }
  1644. if (foreign && trx->check_foreigns) {
  1645. FILE* ef = dict_foreign_err_file;
  1646. /* We only allow discarding a referenced table if
  1647. FOREIGN_KEY_CHECKS is set to 0 */
  1648. err = DB_CANNOT_DROP_CONSTRAINT;
  1649. mutex_enter(&dict_foreign_err_mutex);
  1650. rewind(ef);
  1651. ut_print_timestamp(ef);
  1652. fputs("  Cannot DISCARD table ", ef);
  1653. ut_print_name(ef, trx, name);
  1654. fputs("n"
  1655. "because it is referenced by ", ef);
  1656. ut_print_name(ef, trx, foreign->foreign_table_name);
  1657. putc('n', ef);
  1658. mutex_exit(&dict_foreign_err_mutex);
  1659. goto funct_exit;
  1660. }
  1661. new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
  1662. buf = mem_alloc((sizeof discard_tablespace_proc1) +
  1663. (sizeof discard_tablespace_proc2) +
  1664. 20 + ut_strlenq(name, '''));
  1665. memcpy(buf, discard_tablespace_proc1, sizeof discard_tablespace_proc1);
  1666. sprintf(ut_strcpyq(buf + (sizeof discard_tablespace_proc1 - 1),
  1667. ''', name),
  1668. discard_tablespace_proc2,
  1669. (ulong) ut_dulint_get_high(new_id),
  1670. (ulong) ut_dulint_get_low(new_id));
  1671. graph = pars_sql(buf);
  1672. ut_a(graph);
  1673. /* Remove any locks there are on the table or its records */
  1674. lock_reset_all_on_table(table);
  1675. graph->trx = trx;
  1676. trx->graph = NULL;
  1677. graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
  1678. ut_a(thr = que_fork_start_command(graph));
  1679. que_run_threads(thr);
  1680. err = trx->error_state;
  1681. if (err != DB_SUCCESS) {
  1682. trx->error_state = DB_SUCCESS;
  1683. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  1684. trx->error_state = DB_SUCCESS;
  1685. } else {
  1686. dict_table_change_id_in_cache(table, new_id);
  1687. success = fil_discard_tablespace(table->space);
  1688. if (!success) {
  1689. trx->error_state = DB_SUCCESS;
  1690. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  1691. trx->error_state = DB_SUCCESS;
  1692. err = DB_ERROR;
  1693. } else {
  1694. /* Set the flag which tells that now it is legal to
  1695. IMPORT a tablespace for this table */
  1696. table->tablespace_discarded = TRUE;
  1697. table->ibd_file_missing = TRUE;
  1698. }
  1699. }
  1700. funct_exit:
  1701. row_mysql_unlock_data_dictionary(trx);
  1702. if (graph) {
  1703. que_graph_free(graph);
  1704. }
  1705.    trx_commit_for_mysql(trx);
  1706. trx->op_info = "";
  1707. return((int) err);
  1708. }
  1709. /*********************************************************************
  1710. Imports a tablespace. The space id in the .ibd file must match the space id
  1711. of the table in the data dictionary. */
  1712. int
  1713. row_import_tablespace_for_mysql(
  1714. /*============================*/
  1715. /* out: error code or DB_SUCCESS */
  1716. const char* name, /* in: table name */
  1717. trx_t* trx) /* in: transaction handle */
  1718. {
  1719. dict_table_t* table;
  1720. ibool success;
  1721. dulint current_lsn;
  1722. ulint err = DB_SUCCESS;
  1723. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  1724. trx_start_if_not_started(trx);
  1725. trx->op_info = "importing tablespace";
  1726. current_lsn = log_get_lsn();
  1727. /* It is possible, though very improbable, that the lsn's in the
  1728. tablespace to be imported have risen above the current system lsn, if
  1729. a lengthy purge, ibuf merge, or rollback was performed on a backup
  1730. taken with ibbackup. If that is the case, reset page lsn's in the
  1731. file. We assume that mysqld was shut down after it performed these
  1732. cleanup operations on the .ibd file, so that it stamped the latest lsn
  1733. to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
  1734. TODO: reset also the trx id's in clustered index records and write
  1735. a new space id to each data page. That would allow us to import clean
  1736. .ibd files from another MySQL installation. */
  1737. success = fil_reset_too_high_lsns(name, current_lsn);
  1738. if (!success) {
  1739. ut_print_timestamp(stderr);
  1740. fputs("  InnoDB: Error: cannot reset lsn's in table ", stderr);
  1741. ut_print_name(stderr, trx, name);
  1742. fputs("n"
  1743. "InnoDB: in ALTER TABLE ... IMPORT TABLESPACEn", stderr);
  1744. err = DB_ERROR;
  1745. row_mysql_lock_data_dictionary(trx);
  1746. goto funct_exit;
  1747. }
  1748. /* Serialize data dictionary operations with dictionary mutex:
  1749. no deadlocks can occur then in these operations */
  1750. row_mysql_lock_data_dictionary(trx);
  1751. table = dict_table_get_low(name);
  1752. if (!table) {
  1753. ut_print_timestamp(stderr);
  1754. fputs("  InnoDB: table ", stderr);
  1755. ut_print_name(stderr, trx, name);
  1756. fputs("n"
  1757. "InnoDB: does not exist in the InnoDB data dictionaryn"
  1758. "InnoDB: in ALTER TABLE ... IMPORT TABLESPACEn",
  1759. stderr);
  1760. err = DB_TABLE_NOT_FOUND;
  1761. goto funct_exit;
  1762. }
  1763. if (table->space == 0) {
  1764. ut_print_timestamp(stderr);
  1765. fputs("  InnoDB: Error: table ", stderr);
  1766. ut_print_name(stderr, trx, name);
  1767. fputs("n"
  1768. "InnoDB: is in the system tablespace 0 which cannot be importedn", stderr);
  1769. err = DB_ERROR;
  1770. goto funct_exit;
  1771. }
  1772. if (!table->tablespace_discarded) {
  1773. ut_print_timestamp(stderr);
  1774. fputs(
  1775. "  InnoDB: Error: you are trying to IMPORT a tablespacen"
  1776. "InnoDB: ", stderr);
  1777. ut_print_name(stderr, trx, name);
  1778. fputs(", though you have not called DISCARD on it yetn"
  1779. "InnoDB: during the lifetime of the mysqld process!n", stderr);
  1780. err = DB_ERROR;
  1781. goto funct_exit;
  1782. }
  1783. /* Play safe and remove all insert buffer entries, though we should
  1784. have removed them already when DISCARD TABLESPACE was called */
  1785. ibuf_delete_for_discarded_space(table->space);
  1786. success = fil_open_single_table_tablespace(TRUE, table->space,
  1787. table->name);
  1788. if (success) {
  1789. table->ibd_file_missing = FALSE;
  1790. table->tablespace_discarded = FALSE;
  1791. } else {
  1792. if (table->ibd_file_missing) {
  1793. ut_print_timestamp(stderr);
  1794. fputs(
  1795. "  InnoDB: cannot find or open in the database directory the .ibd file ofn"
  1796. "InnoDB: table ", stderr);
  1797. ut_print_name(stderr, trx, name);
  1798. fputs("n"
  1799. "InnoDB: in ALTER TABLE ... IMPORT TABLESPACEn",
  1800. stderr);
  1801. }
  1802. err = DB_ERROR;
  1803. }
  1804. funct_exit:
  1805. row_mysql_unlock_data_dictionary(trx);
  1806.    trx_commit_for_mysql(trx);
  1807. trx->op_info = "";
  1808. return((int) err);
  1809. }
  1810. /*************************************************************************
  1811. Drops a table for MySQL. If the name of the table to be dropped is equal
  1812. with one of the predefined magic table names, then this also stops printing
  1813. the corresponding monitor output by the master thread. */
  1814. int
  1815. row_drop_table_for_mysql(
  1816. /*=====================*/
  1817. /* out: error code or DB_SUCCESS */
  1818. const char* name, /* in: table name */
  1819. trx_t* trx, /* in: transaction handle */
  1820. ibool drop_db)/* in: TRUE=dropping whole database */
  1821. {
  1822. dict_foreign_t* foreign;
  1823. dict_table_t* table;
  1824. ulint space_id;
  1825. que_thr_t* thr;
  1826. que_t* graph;
  1827. ulint err;
  1828. const char* table_name;
  1829. ulint namelen;
  1830. char* dir_path_of_temp_table = NULL;
  1831. ibool success;
  1832. ibool locked_dictionary = FALSE;
  1833. char* quoted_name;
  1834. char* sql;
  1835. /* We use the private SQL parser of Innobase to generate the
  1836. query graphs needed in deleting the dictionary data from system
  1837. tables in Innobase. Deleting a row from SYS_INDEXES table also
  1838. frees the file segments of the B-tree associated with the index. */
  1839. static const char str1[] =
  1840. "PROCEDURE DROP_TABLE_PROC () ISn"
  1841. "table_name CHAR;n"
  1842. "sys_foreign_id CHAR;n"
  1843. "table_id CHAR;n"
  1844. "index_id CHAR;n"
  1845. "foreign_id CHAR;n"
  1846. "found INT;n"
  1847. "BEGINn"
  1848. "table_name := ";
  1849. static const char str2[] =
  1850. ";n"
  1851. "SELECT ID INTO table_idn"
  1852. "FROM SYS_TABLESn"
  1853. "WHERE NAME = table_name;n"
  1854. "IF (SQL % NOTFOUND) THENn"
  1855. " COMMIT WORK;n"
  1856. " RETURN;n"
  1857. "END IF;n"
  1858. "found := 1;n"
  1859. "SELECT ID INTO sys_foreign_idn"
  1860. "FROM SYS_TABLESn"
  1861. "WHERE NAME = 'SYS_FOREIGN';n"
  1862. "IF (SQL % NOTFOUND) THENn"
  1863. " found := 0;n"
  1864. "END IF;n"
  1865. "IF (table_name = 'SYS_FOREIGN') THENn"
  1866. " found := 0;n"
  1867. "END IF;n"
  1868. "IF (table_name = 'SYS_FOREIGN_COLS') THENn"
  1869. " found := 0;n"
  1870. "END IF;n"
  1871. "WHILE found = 1 LOOPn"
  1872. " SELECT ID INTO foreign_idn"
  1873. " FROM SYS_FOREIGNn"
  1874. " WHERE FOR_NAME = table_namen"
  1875.         "             AND TO_BINARY(FOR_NAME) = TO_BINARY(table_name);n"
  1876. " IF (SQL % NOTFOUND) THENn"
  1877. " found := 0;n"
  1878. " ELSE"
  1879. " DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;n"
  1880. " DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;n"
  1881. " END IF;n"
  1882. "END LOOP;n"
  1883. "found := 1;n"
  1884. "WHILE found = 1 LOOPn"
  1885. " SELECT ID INTO index_idn"
  1886. " FROM SYS_INDEXESn"
  1887. " WHERE TABLE_ID = table_id;n"
  1888. " IF (SQL % NOTFOUND) THENn"
  1889. " found := 0;n"
  1890. " ELSE"
  1891. " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;n"
  1892. " DELETE FROM SYS_INDEXES WHERE ID = index_idn"
  1893. "  AND TABLE_ID = table_id;n"
  1894. " END IF;n"
  1895. "END LOOP;n"
  1896. "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;n"
  1897. "DELETE FROM SYS_TABLES WHERE ID = table_id;n"
  1898. "COMMIT WORK;n"
  1899. "END;n";
  1900. ut_a(name != NULL);
  1901. if (srv_created_new_raw) {
  1902. fputs(
  1903. "InnoDB: A new raw disk partition was initialized orn"
  1904. "InnoDB: innodb_force_recovery is on: we do not allown"
  1905. "InnoDB: database modifications by the user. Shut downn"
  1906. "InnoDB: mysqld and edit my.cnf so that newraw is replacedn"
  1907. "InnoDB: with raw, and innodb_force_... is removed.n",
  1908.                 stderr);
  1909. return(DB_ERROR);
  1910. }
  1911. trx->op_info = "dropping table";
  1912. trx_start_if_not_started(trx);
  1913. /* The table name is prefixed with the database name and a '/'.
  1914. Certain table names starting with 'innodb_' have their special
  1915. meaning regardless of the database name.  Thus, we need to
  1916. ignore the database name prefix in the comparisons. */
  1917. table_name = strchr(name, '/');
  1918. ut_a(table_name);
  1919. table_name++;
  1920. namelen = strlen(table_name) + 1;
  1921. if (namelen == sizeof S_innodb_monitor
  1922. && !memcmp(table_name, S_innodb_monitor,
  1923. sizeof S_innodb_monitor)) {
  1924. /* Table name equals "innodb_monitor":
  1925. stop monitor prints */
  1926.  
  1927. srv_print_innodb_monitor = FALSE;
  1928. srv_print_innodb_lock_monitor = FALSE;
  1929. } else if (namelen == sizeof S_innodb_lock_monitor
  1930. && !memcmp(table_name, S_innodb_lock_monitor,
  1931. sizeof S_innodb_lock_monitor)) {
  1932. srv_print_innodb_monitor = FALSE;
  1933. srv_print_innodb_lock_monitor = FALSE;
  1934. } else if (namelen == sizeof S_innodb_tablespace_monitor
  1935. && !memcmp(table_name, S_innodb_tablespace_monitor,
  1936. sizeof S_innodb_tablespace_monitor)) {
  1937. srv_print_innodb_tablespace_monitor = FALSE;
  1938. } else if (namelen == sizeof S_innodb_table_monitor
  1939. && !memcmp(table_name, S_innodb_table_monitor,
  1940. sizeof S_innodb_table_monitor)) {
  1941. srv_print_innodb_table_monitor = FALSE;
  1942. }
  1943. quoted_name = mem_strdupq(name, ''');
  1944. namelen = strlen(quoted_name);
  1945. sql = mem_alloc((sizeof str1) + (sizeof str2) - 2 + 1 + namelen);
  1946. memcpy(sql, str1, (sizeof str1) - 1);
  1947. memcpy(sql + (sizeof str1) - 1, quoted_name, namelen);
  1948. memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2);
  1949. mem_free(quoted_name);
  1950. /* Serialize data dictionary operations with dictionary mutex:
  1951. no deadlocks can occur then in these operations */
  1952. if (trx->dict_operation_lock_mode != RW_X_LATCH) {
  1953. /* Prevent foreign key checks etc. while we are dropping the
  1954. table */
  1955. row_mysql_lock_data_dictionary(trx);
  1956. locked_dictionary = TRUE;
  1957. }
  1958. #ifdef UNIV_SYNC_DEBUG
  1959. ut_ad(mutex_own(&(dict_sys->mutex)));
  1960. ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
  1961. #endif /* UNIV_SYNC_DEBUG */
  1962. graph = pars_sql(sql);
  1963. ut_a(graph);
  1964. mem_free(sql);
  1965. graph->trx = trx;
  1966. trx->graph = NULL;
  1967. graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
  1968. table = dict_table_get_low(name);
  1969. if (!table) {
  1970. err = DB_TABLE_NOT_FOUND;
  1971.      ut_print_timestamp(stderr);
  1972. fputs("  InnoDB: Error: table ", stderr);
  1973. ut_print_name(stderr, trx, name);
  1974. fputs(" does not exist in the InnoDB internaln"
  1975.       "InnoDB: data dictionary though MySQL is trying to drop it.n"
  1976.       "InnoDB: Have you copied the .frm file of the table to then"
  1977. "InnoDB: MySQL database directory from another database?n"
  1978. "InnoDB: You can look for further help fromn"
  1979. "InnoDB: http://dev.mysql.com/doc/mysql/en/"
  1980. "InnoDB_troubleshooting_datadict.htmln", stderr);
  1981. goto funct_exit;
  1982. }
  1983. /* Check if the table is referenced by foreign key constraints from
  1984. some other table (not the table itself) */
  1985. foreign = UT_LIST_GET_FIRST(table->referenced_list);
  1986. while (foreign && foreign->foreign_table == table) {
  1987. check_next_foreign:
  1988. foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
  1989. }
  1990. if (foreign && trx->check_foreigns &&
  1991. !(drop_db && dict_tables_have_same_db(
  1992. name, foreign->foreign_table_name))) {
  1993. FILE* ef = dict_foreign_err_file;
  1994. /* We only allow dropping a referenced table if
  1995. FOREIGN_KEY_CHECKS is set to 0 */
  1996. err = DB_CANNOT_DROP_CONSTRAINT;
  1997. mutex_enter(&dict_foreign_err_mutex);
  1998. rewind(ef);
  1999. ut_print_timestamp(ef);
  2000. fputs("  Cannot drop table ", ef);
  2001. ut_print_name(ef, trx, name);
  2002. fputs("n"
  2003. "because it is referenced by ", ef);
  2004. ut_print_name(ef, trx, foreign->foreign_table_name);
  2005. putc('n', ef);
  2006. mutex_exit(&dict_foreign_err_mutex);
  2007. goto funct_exit;
  2008. }
  2009. if (foreign && trx->check_foreigns) {
  2010. goto check_next_foreign;
  2011. }
  2012. if (table->n_mysql_handles_opened > 0) {
  2013. ibool added;
  2014. added = row_add_table_to_background_drop_list(table);
  2015.         if (added) {
  2016. ut_print_timestamp(stderr);
  2017. fputs("  InnoDB: Warning: MySQL is trying to drop table ", stderr);
  2018. ut_print_name(stderr, trx, table->name);
  2019. fputs("n"
  2020. "InnoDB: though there are still open handles to it.n"
  2021. "InnoDB: Adding the table to the background drop queue.n",
  2022. stderr);
  2023. /* We return DB_SUCCESS to MySQL though the drop will
  2024. happen lazily later */
  2025. err = DB_SUCCESS;
  2026. } else {
  2027. /* The table is already in the background drop list */
  2028. err = DB_ERROR;
  2029. }
  2030. goto funct_exit;
  2031. }
  2032. /* TODO: could we replace the counter n_foreign_key_checks_running
  2033. with lock checks on the table? Acquire here an exclusive lock on the
  2034. table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
  2035. they can cope with the table having been dropped here? Foreign key
  2036. checks take an IS or IX lock on the table. */
  2037. if (table->n_foreign_key_checks_running > 0) {
  2038. ibool added;
  2039. added = row_add_table_to_background_drop_list(table);
  2040. if (added) {
  2041.          ut_print_timestamp(stderr);
  2042. fputs("  InnoDB: You are trying to drop table ", stderr);
  2043. ut_print_name(stderr, trx, table->name);
  2044. fputs("n"
  2045. "InnoDB: though there is a foreign key check running on it.n"
  2046. "InnoDB: Adding the table to the background drop queue.n",
  2047. stderr);
  2048. /* We return DB_SUCCESS to MySQL though the drop will
  2049. happen lazily later */
  2050. err = DB_SUCCESS;
  2051. } else {
  2052. /* The table is already in the background drop list */
  2053. err = DB_ERROR;
  2054. }
  2055. goto funct_exit;
  2056. }
  2057. /* Remove any locks there are on the table or its records */
  2058. lock_reset_all_on_table(table);
  2059. trx->dict_operation = TRUE;
  2060. trx->table_id = table->id;
  2061. ut_a(thr = que_fork_start_command(graph));
  2062. que_run_threads(thr);
  2063. err = trx->error_state;
  2064. if (err != DB_SUCCESS) {
  2065. ut_a(err == DB_OUT_OF_FILE_SPACE);
  2066. err = DB_MUST_GET_MORE_FILE_SPACE;
  2067. row_mysql_handle_errors(&err, trx, thr, NULL);
  2068. ut_error;
  2069. } else {
  2070. ibool is_path;
  2071. const char* name_or_path;
  2072. space_id = table->space;
  2073. if (table->dir_path_of_temp_table != NULL) {
  2074. dir_path_of_temp_table =
  2075. mem_strdup(table->dir_path_of_temp_table);
  2076. is_path = TRUE;
  2077. name_or_path = dir_path_of_temp_table;
  2078. } else {
  2079. is_path = FALSE;
  2080. name_or_path = name;
  2081. }
  2082. dict_table_remove_from_cache(table);
  2083. if (dict_load_table(name) != NULL) {
  2084. ut_print_timestamp(stderr);
  2085. fputs("  InnoDB: Error: not able to remove table ",
  2086. stderr);
  2087. ut_print_name(stderr, trx, name);
  2088. fputs(" from the dictionary cache!n", stderr);
  2089. err = DB_ERROR;
  2090. }
  2091. /* Do not drop possible .ibd tablespace if something went
  2092. wrong: we do not want to delete valuable data of the user */
  2093. if (err == DB_SUCCESS && space_id > 0) {
  2094. if (!fil_space_for_table_exists_in_mem(space_id,
  2095. name_or_path,
  2096. is_path,
  2097. FALSE, TRUE)) {
  2098. err = DB_SUCCESS;
  2099. fprintf(stderr,
  2100. "InnoDB: We removed now the InnoDB internal data dictionary entryn"
  2101. "InnoDB: of table ");
  2102. ut_print_name(stderr, trx, name);
  2103. fprintf(stderr, ".n");
  2104. goto funct_exit;
  2105. }
  2106. success = fil_delete_tablespace(space_id);
  2107. if (!success) {
  2108. fprintf(stderr,
  2109. "InnoDB: We removed now the InnoDB internal data dictionary entryn"
  2110. "InnoDB: of table ");
  2111. ut_print_name(stderr, trx, name);
  2112. fprintf(stderr, ".n");
  2113. ut_print_timestamp(stderr);
  2114. fprintf(stderr,
  2115. "  InnoDB: Error: not able to delete tablespace %lu of table ",
  2116. (ulong) space_id);
  2117. ut_print_name(stderr, trx, name);
  2118. fputs("!n", stderr);
  2119. err = DB_ERROR;
  2120. }
  2121. }
  2122. }
  2123. funct_exit:
  2124. if (locked_dictionary) {
  2125. row_mysql_unlock_data_dictionary(trx);
  2126. }
  2127. if (dir_path_of_temp_table) {
  2128. mem_free(dir_path_of_temp_table);
  2129. }
  2130. que_graph_free(graph);
  2131.    trx_commit_for_mysql(trx);
  2132. trx->op_info = "";
  2133. srv_wake_master_thread();
  2134. return((int) err);
  2135. }
  2136. /*************************************************************************
  2137. Drops a database for MySQL. */
  2138. int
  2139. row_drop_database_for_mysql(
  2140. /*========================*/
  2141. /* out: error code or DB_SUCCESS */
  2142. const char* name, /* in: database name which ends to '/' */
  2143. trx_t* trx) /* in: transaction handle */
  2144. {
  2145.         dict_table_t* table;
  2146. char* table_name;
  2147. int err = DB_SUCCESS;
  2148. ulint namelen = strlen(name);
  2149. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  2150. ut_a(name != NULL);
  2151. ut_a(name[namelen - 1] == '/');
  2152. trx->op_info = "dropping database";
  2153. trx_start_if_not_started(trx);
  2154. loop:
  2155. row_mysql_lock_data_dictionary(trx);
  2156. while ((table_name = dict_get_first_table_name_in_db(name))) {
  2157. ut_a(memcmp(table_name, name, namelen) == 0);
  2158. table = dict_table_get_low(table_name);
  2159. ut_a(table);
  2160. /* Wait until MySQL does not have any queries running on
  2161. the table */
  2162. if (table->n_mysql_handles_opened > 0) {
  2163. row_mysql_unlock_data_dictionary(trx);
  2164. ut_print_timestamp(stderr);
  2165. fputs(
  2166. "  InnoDB: Warning: MySQL is trying to drop database ", stderr);
  2167. ut_print_name(stderr, trx, name);
  2168. fputs("n"
  2169. "InnoDB: though there are still open handles to table ", stderr);
  2170. ut_print_name(stderr, trx, table_name);
  2171. fputs(".n", stderr);
  2172.         os_thread_sleep(1000000);
  2173.         mem_free(table_name);
  2174.         goto loop;
  2175. }
  2176. err = row_drop_table_for_mysql(table_name, trx, TRUE);
  2177. mem_free(table_name);
  2178. if (err != DB_SUCCESS) {
  2179. fputs("InnoDB: DROP DATABASE ", stderr);
  2180. ut_print_name(stderr, trx, name);
  2181. fprintf(stderr, " failed with error %lu for table ",
  2182. (ulint) err);
  2183. ut_print_name(stderr, trx, table_name);
  2184. putc('n', stderr);
  2185. break;
  2186. }
  2187. }
  2188. row_mysql_unlock_data_dictionary(trx);
  2189. trx_commit_for_mysql(trx);
  2190. trx->op_info = "";
  2191. return(err);
  2192. }
  2193. /*************************************************************************
  2194. Checks if a table name contains the string "/#sql" which denotes temporary
  2195. tables in MySQL. */
  2196. static
  2197. ibool
  2198. row_is_mysql_tmp_table_name(
  2199. /*========================*/
  2200. /* out: TRUE if temporary table */
  2201. const char* name) /* in: table name in the form
  2202. 'database/tablename' */
  2203. {
  2204. return(strstr(name, "/#sql") != NULL);
  2205. }
  2206. /*************************************************************************
  2207. Renames a table for MySQL. */
  2208. int
  2209. row_rename_table_for_mysql(
  2210. /*=======================*/
  2211. /* out: error code or DB_SUCCESS */
  2212. const char* old_name, /* in: old table name */
  2213. const char* new_name, /* in: new table name */
  2214. trx_t* trx) /* in: transaction handle */
  2215. {
  2216. dict_table_t* table;
  2217. que_thr_t* thr;
  2218. que_t* graph = NULL;
  2219. ulint err;
  2220. /* We use the private SQL parser of Innobase to generate the
  2221. query graphs needed in deleting the dictionary data from system
  2222. tables in Innobase. Deleting a row from SYS_INDEXES table also
  2223. frees the file segments of the B-tree associated with the index. */
  2224. static const char str1[] =
  2225. "PROCEDURE RENAME_TABLE_PROC () ISn"
  2226. "new_table_name CHAR;n"
  2227. "old_table_name CHAR;n"
  2228. "gen_constr_prefix CHAR;n"
  2229. "new_db_name CHAR;n"
  2230. "foreign_id CHAR;n"
  2231. "new_foreign_id CHAR;n"
  2232. "old_db_name_len INT;n"
  2233. "old_t_name_len INT;n"
  2234. "new_db_name_len INT;n"
  2235. "id_len INT;n"
  2236. "found INT;n"
  2237. "BEGINn"
  2238. "new_table_name := '";
  2239. static const char str2[] =
  2240. "';nold_table_name := '";
  2241. static const char str3[] =
  2242. "';n"
  2243. "UPDATE SYS_TABLES SET NAME = new_table_namen"
  2244. "WHERE NAME = old_table_name;n";
  2245. static const char str4a1[] = /* drop some constraints of tmp tables */
  2246. "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '";
  2247. static const char str4a2[] = "';n"
  2248. "DELETE FROM SYS_FOREIGN WHERE ID = '";
  2249. static const char str4a3[] = "';n";
  2250. static const char str4b[] = /* rename all constraints */
  2251. "found := 1;n"
  2252. "old_db_name_len := INSTR(old_table_name, '/') - 1;n"
  2253. "new_db_name_len := INSTR(new_table_name, '/') - 1;n"
  2254. "new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);n"
  2255. "old_t_name_len := LENGTH(old_table_name);n"
  2256. "gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');n"
  2257. "WHILE found = 1 LOOPn"
  2258. " SELECT ID INTO foreign_idn"
  2259. " FROM SYS_FOREIGNn"
  2260. " WHERE FOR_NAME = old_table_namen"
  2261. "       AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);n"
  2262. " IF (SQL % NOTFOUND) THENn"
  2263. "  found := 0;n"
  2264. " ELSEn"
  2265. "  UPDATE SYS_FOREIGNn"
  2266. "  SET FOR_NAME = new_table_namen"
  2267. "  WHERE ID = foreign_id;n"
  2268. "  id_len := LENGTH(foreign_id);n"
  2269. "  IF (INSTR(foreign_id, '/') > 0) THENn"
  2270. "   IF (INSTR(foreign_id,n"
  2271. " gen_constr_prefix) > 0)n"
  2272. " THENn"
  2273. "   new_foreign_id :=n"
  2274. "     CONCAT(new_table_name,n"
  2275. " SUBSTR(foreign_id, old_t_name_len,n"
  2276. "         id_len - old_t_name_len));n"
  2277. " ELSEn"
  2278. "   new_foreign_id :=n"
  2279. "     CONCAT(new_db_name,n"
  2280. " SUBSTR(foreign_id,n"
  2281. " old_db_name_len,n"
  2282. "  id_len - old_db_name_len));n"
  2283. " END IF;n"
  2284. " UPDATE SYS_FOREIGNn"
  2285. " SET ID = new_foreign_idn"
  2286. " WHERE ID = foreign_id;n"
  2287. " UPDATE SYS_FOREIGN_COLSn"
  2288. " SET ID = new_foreign_idn"
  2289. " WHERE ID = foreign_id;n"
  2290. "  END IF;n"
  2291. " END IF;n"
  2292. "END LOOP;n"
  2293. "UPDATE SYS_FOREIGN SET REF_NAME = new_table_namen"
  2294. "WHERE REF_NAME = old_table_namen"
  2295. "      AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);n";
  2296. static const char str5[] =
  2297. "END;n";
  2298. mem_heap_t* heap = NULL;
  2299. const char** constraints_to_drop = NULL;
  2300. ulint n_constraints_to_drop = 0;
  2301.         ibool           recovering_temp_table   = FALSE;
  2302. ulint len;
  2303. ulint i;
  2304.         ibool success;
  2305. /* length of database name; 0 if not renaming to a temporary table */
  2306. ulint db_name_len;
  2307. char* sql;
  2308. char* sqlend;
  2309. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  2310. ut_a(old_name != NULL);
  2311. ut_a(new_name != NULL);
  2312. if (srv_created_new_raw || srv_force_recovery) {
  2313. fputs(
  2314. "InnoDB: A new raw disk partition was initialized orn"
  2315. "InnoDB: innodb_force_recovery is on: we do not allown"
  2316. "InnoDB: database modifications by the user. Shut downn"
  2317. "InnoDB: mysqld and edit my.cnf so that newraw is replacedn"
  2318. "InnoDB: with raw, and innodb_force_... is removed.n",
  2319. stderr);
  2320.    trx_commit_for_mysql(trx);
  2321. return(DB_ERROR);
  2322. }
  2323. if (row_mysql_is_system_table(new_name)) {
  2324.     
  2325. fprintf(stderr,
  2326.     "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.n"
  2327.     "InnoDB: MySQL system tables must be of the MyISAM type!n",
  2328. new_name);
  2329.    trx_commit_for_mysql(trx);
  2330. return(DB_ERROR);
  2331. }
  2332. trx->op_info = "renaming table";
  2333. trx_start_if_not_started(trx);
  2334. if (row_mysql_is_recovered_tmp_table(new_name)) {
  2335.                 recovering_temp_table = TRUE;
  2336.         } else {
  2337. /* Serialize data dictionary operations with dictionary mutex:
  2338. no deadlocks can occur then in these operations */
  2339. row_mysql_lock_data_dictionary(trx);
  2340. }
  2341. table = dict_table_get_low(old_name);
  2342. if (!table) {
  2343. err = DB_TABLE_NOT_FOUND;
  2344.      ut_print_timestamp(stderr);
  2345.                 fputs("  InnoDB: Error: table ", stderr);
  2346.                 ut_print_name(stderr, trx, old_name);
  2347.                 fputs(" does not exist in the InnoDB internaln"
  2348.       "InnoDB: data dictionary though MySQL is trying to rename the table.n"
  2349.       "InnoDB: Have you copied the .frm file of the table to then"
  2350. "InnoDB: MySQL database directory from another database?n"
  2351. "InnoDB: You can look for further help from section 15.1 ofn"
  2352.         "InnoDB: http://www.innodb.com/ibman.phpn", stderr);
  2353. goto funct_exit;
  2354. }
  2355. if (table->ibd_file_missing) {
  2356. err = DB_TABLE_NOT_FOUND;
  2357.      ut_print_timestamp(stderr);
  2358.                 fputs("  InnoDB: Error: table ", stderr);
  2359.                 ut_print_name(stderr, trx, old_name);
  2360.                 fputs(
  2361. " does not have an .ibd file in the database directory.n"
  2362. "InnoDB: You can look for further help from section 15.1 ofn"
  2363.         "InnoDB: http://www.innodb.com/ibman.phpn", stderr);
  2364. goto funct_exit;
  2365. }
  2366. /* calculate the length of the SQL string */
  2367. len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4
  2368. + ut_strlenq(new_name, ''') + ut_strlenq(old_name, ''');
  2369. if (row_is_mysql_tmp_table_name(new_name)) {
  2370. db_name_len = dict_get_db_name_len(old_name) + 1;
  2371. /* MySQL is doing an ALTER TABLE command and it renames the
  2372. original table to a temporary table name. We want to preserve
  2373. the original foreign key constraint definitions despite the
  2374. name change. An exception is those constraints for which
  2375. the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
  2376. heap = mem_heap_create(100);
  2377. err = dict_foreign_parse_drop_constraints(heap, trx,
  2378. table,
  2379. &n_constraints_to_drop,
  2380. &constraints_to_drop);
  2381. if (err != DB_SUCCESS) {
  2382. goto funct_exit;
  2383. }
  2384. /* reserve space for all database names */
  2385. len += 2 * n_constraints_to_drop
  2386. * (ut_strlenq(old_name, ''')
  2387. - ut_strlenq(old_name + db_name_len, '''));
  2388. for (i = 0; i < n_constraints_to_drop; i++) {
  2389. ulint addlen
  2390. = 2 * ut_strlenq(constraints_to_drop[i], ''')
  2391. + ((sizeof str4a1) + (sizeof str4a2)
  2392. + (sizeof str4a3) - 3);
  2393. if (!strchr(constraints_to_drop[i], '/')) {
  2394. addlen *= 2;
  2395. }
  2396. len += addlen;
  2397. }
  2398. } else {
  2399. db_name_len = 0;
  2400. len += (sizeof str4b) - 1;
  2401. }
  2402. sql = sqlend = mem_alloc(len + 1);
  2403. memcpy(sql, str1, (sizeof str1) - 1);
  2404. sqlend += (sizeof str1) - 1;
  2405. sqlend = ut_strcpyq(sqlend, ''', new_name);
  2406. memcpy(sqlend, str2, (sizeof str2) - 1);
  2407. sqlend += (sizeof str2) - 1;
  2408. sqlend = ut_strcpyq(sqlend, ''', old_name);
  2409. memcpy(sqlend, str3, (sizeof str3) - 1);
  2410. sqlend += (sizeof str3) - 1;
  2411. if (db_name_len) {
  2412. /* Internally, old format < 4.0.18 constraints have as the
  2413. constraint id <number>_<number>, while new format constraints
  2414. have <databasename>/<constraintname>. */
  2415. for (i = 0; i < n_constraints_to_drop; i++) {
  2416. memcpy(sqlend, str4a1, (sizeof str4a1) - 1);
  2417. sqlend += (sizeof str4a1) - 1;
  2418. sqlend = ut_memcpyq(sqlend, ''',
  2419. old_name, db_name_len);
  2420. sqlend = ut_strcpyq(sqlend, ''',
  2421. constraints_to_drop[i]);
  2422. memcpy(sqlend, str4a2, (sizeof str4a2) - 1);
  2423. sqlend += (sizeof str4a2) - 1;
  2424. sqlend = ut_memcpyq(sqlend, ''',
  2425. old_name, db_name_len);
  2426.                         sqlend = ut_strcpyq(sqlend, ''',
  2427. constraints_to_drop[i]);
  2428. memcpy(sqlend, str4a3, (sizeof str4a3) - 1);
  2429. sqlend += (sizeof str4a3) - 1;
  2430. if (!strchr(constraints_to_drop[i], '/')) {
  2431. /* If this happens to be an old format
  2432. constraint, let us delete it. Since all new
  2433. format constraints contain '/', it does no
  2434. harm to run these DELETEs anyway. */
  2435. memcpy(sqlend, str4a1, (sizeof str4a1) - 1);
  2436. sqlend += (sizeof str4a1) - 1;
  2437. sqlend = ut_strcpyq(sqlend, ''',
  2438. constraints_to_drop[i]);
  2439. memcpy(sqlend, str4a2, (sizeof str4a2) - 1);
  2440. sqlend += (sizeof str4a2) - 1;
  2441.                          sqlend = ut_strcpyq(sqlend, ''',
  2442. constraints_to_drop[i]);
  2443. memcpy(sqlend, str4a3, (sizeof str4a3) - 1);
  2444. sqlend += (sizeof str4a3) - 1;
  2445. }
  2446. }
  2447. }
  2448. else {
  2449. memcpy(sqlend, str4b, (sizeof str4b) - 1);
  2450. sqlend += (sizeof str4b) - 1;
  2451. }
  2452. memcpy(sqlend, str5, sizeof str5);
  2453. sqlend += sizeof str5;
  2454. ut_a(sqlend == sql + len + 1);
  2455. graph = pars_sql(sql);
  2456. ut_a(graph);
  2457. mem_free(sql);
  2458. graph->trx = trx;
  2459. trx->graph = NULL;
  2460. graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
  2461. ut_a(thr = que_fork_start_command(graph));
  2462. que_run_threads(thr);
  2463. err = trx->error_state;
  2464. if (err != DB_SUCCESS) {
  2465. if (err == DB_DUPLICATE_KEY) {
  2466.      ut_print_timestamp(stderr);
  2467. fputs(
  2468.      "  InnoDB: Error; possible reasons:n"
  2469.      "InnoDB: 1) Table rename would cause two FOREIGN KEY constraintsn"
  2470.      "InnoDB: to have the same internal name in case-insensitive comparison.n"
  2471.      "InnoDB: 2) table ", stderr);
  2472.                 ut_print_name(stderr, trx, new_name);
  2473.                 fputs(" exists in the InnoDB internal datan"
  2474.      "InnoDB: dictionary though MySQL is trying rename table ", stderr);
  2475.                 ut_print_name(stderr, trx, old_name);
  2476. fputs(" to it.n"
  2477.      "InnoDB: Have you deleted the .frm file and not used DROP TABLE?n"
  2478.      "InnoDB: You can look for further help fromn"
  2479.      "InnoDB: http://dev.mysql.com/doc/mysql/en/"
  2480.      "InnoDB_troubleshooting_datadict.htmln"
  2481.      "InnoDB: If table ", stderr);
  2482. ut_print_name(stderr, trx, new_name);
  2483. fputs(
  2484. " is a temporary table #sql..., then it can be thatn"
  2485.      "InnoDB: there are still queries running on the table, and it will ben"
  2486.      "InnoDB: dropped automatically when the queries end.n"
  2487.      "InnoDB: You can drop the orphaned table inside InnoDB byn"
  2488.      "InnoDB: creating an InnoDB table with the same name in anothern"
  2489.      "InnoDB: database and copying the .frm file to the current database.n"
  2490.      "InnoDB: Then MySQL thinks the table exists, and DROP TABLE willn"
  2491.      "InnoDB: succeed.n", stderr);
  2492. }
  2493. trx->error_state = DB_SUCCESS;
  2494. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  2495. trx->error_state = DB_SUCCESS;
  2496. } else {
  2497. /* The following call will also rename the .ibd data file if
  2498. the table is stored in a single-table tablespace */
  2499. success = dict_table_rename_in_cache(table, new_name,
  2500. !row_is_mysql_tmp_table_name(new_name));
  2501. if (!success) {
  2502. trx->error_state = DB_SUCCESS;
  2503. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  2504. trx->error_state = DB_SUCCESS;
  2505. ut_print_timestamp(stderr);
  2506. fputs(" InnoDB: Error in table rename, cannot rename ",
  2507. stderr);
  2508. ut_print_name(stderr, trx, old_name);
  2509. fputs(" to ", stderr);
  2510. ut_print_name(stderr, trx, new_name);
  2511. putc('n', stderr);
  2512. err = DB_ERROR;
  2513. goto funct_exit;
  2514. }
  2515. err = dict_load_foreigns(new_name, trx->check_foreigns);
  2516. if (row_is_mysql_tmp_table_name(old_name)) {
  2517. /* MySQL is doing an ALTER TABLE command and it
  2518. renames the created temporary table to the name
  2519. of the original table. In the ALTER TABLE we maybe
  2520. created some FOREIGN KEY constraints for the temporary
  2521. table. But we want to load also the foreign key
  2522. constraint definitions for the original table name. */
  2523. if (err != DB_SUCCESS) {
  2524.      ut_print_timestamp(stderr);
  2525. fputs("  InnoDB: Error: in ALTER TABLE ",
  2526. stderr);
  2527. ut_print_name(stderr, trx, new_name);
  2528. fputs("n"
  2529. "InnoDB: has or is referenced in foreign key constraintsn"
  2530. "InnoDB: which are not compatible with the new table definition.n",
  2531. stderr);
  2532. ut_a(dict_table_rename_in_cache(table,
  2533. old_name, FALSE));
  2534. trx->error_state = DB_SUCCESS;
  2535. trx_general_rollback_for_mysql(trx, FALSE,
  2536. NULL);
  2537. trx->error_state = DB_SUCCESS;
  2538. }
  2539. } else {
  2540. if (err != DB_SUCCESS) {
  2541.      ut_print_timestamp(stderr);
  2542. fputs(
  2543. "  InnoDB: Error: in RENAME TABLE table ",
  2544. stderr);
  2545. ut_print_name(stderr, trx, new_name);
  2546. fputs("n"
  2547.      "InnoDB: is referenced in foreign key constraintsn"
  2548.      "InnoDB: which are not compatible with the new table definition.n",
  2549. stderr);
  2550.      
  2551. ut_a(dict_table_rename_in_cache(table,
  2552. old_name, FALSE));
  2553. trx->error_state = DB_SUCCESS;
  2554. trx_general_rollback_for_mysql(trx, FALSE,
  2555. NULL);
  2556. trx->error_state = DB_SUCCESS;
  2557. }
  2558. }
  2559. }
  2560. funct_exit:
  2561. if (!recovering_temp_table) {
  2562. row_mysql_unlock_data_dictionary(trx);
  2563. }
  2564. if (graph) {
  2565. que_graph_free(graph);
  2566. }
  2567. if (heap) {
  2568. mem_heap_free(heap);
  2569. }
  2570.    trx_commit_for_mysql(trx);
  2571. trx->op_info = "";
  2572. return((int) err);
  2573. }
  2574. /*************************************************************************
  2575. Checks that the index contains entries in an ascending order, unique
  2576. constraint is not broken, and calculates the number of index entries
  2577. in the read view of the current transaction. */
  2578. static
  2579. ibool
  2580. row_scan_and_check_index(
  2581. /*=====================*/
  2582. /* out: TRUE if ok */
  2583. row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL */
  2584. dict_index_t* index, /* in: index */
  2585. ulint* n_rows) /* out: number of entries seen in the
  2586. current consistent read */
  2587. {
  2588. mem_heap_t* heap;
  2589. dtuple_t* prev_entry = NULL;
  2590. ulint matched_fields;
  2591. ulint matched_bytes;
  2592. byte* buf;
  2593. ulint ret;
  2594. rec_t* rec;
  2595. ibool is_ok = TRUE;
  2596. int cmp;
  2597. ibool contains_null;
  2598. ulint i;
  2599. *n_rows = 0;
  2600. buf = mem_alloc(UNIV_PAGE_SIZE);
  2601. heap = mem_heap_create(100);
  2602. /* Make a dummy template in prebuilt, which we will use
  2603. in scanning the index entries */
  2604. prebuilt->index = index;
  2605. prebuilt->sql_stat_start = TRUE;
  2606. prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
  2607. prebuilt->n_template = 0;
  2608. prebuilt->need_to_access_clustered = FALSE;
  2609.   dtuple_set_n_fields(prebuilt->search_tuple, 0);
  2610. prebuilt->select_lock_type = LOCK_NONE;
  2611. ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
  2612. loop:
  2613. if (ret != DB_SUCCESS) {
  2614. mem_free(buf);
  2615. mem_heap_free(heap);
  2616. return(is_ok);
  2617. }
  2618. *n_rows = *n_rows + 1;
  2619. /* row_search... returns the index record in buf, record origin offset
  2620. within buf stored in the first 4 bytes, because we have built a dummy
  2621. template */
  2622. rec = buf + mach_read_from_4(buf);
  2623. if (prev_entry != NULL) {
  2624. matched_fields = 0;
  2625. matched_bytes = 0;
  2626. cmp = cmp_dtuple_rec_with_match(prev_entry, rec,
  2627. &matched_fields,
  2628. &matched_bytes);
  2629. contains_null = FALSE;
  2630. /* In a unique secondary index we allow equal key values if
  2631. they contain SQL NULLs */
  2632.         for (i = 0;
  2633.                      i < dict_index_get_n_ordering_defined_by_user(index);
  2634.      i++) {
  2635.                 if (UNIV_SQL_NULL == dfield_get_len(
  2636.                                       dtuple_get_nth_field(prev_entry, i))) {
  2637.                          contains_null = TRUE;
  2638.                 }
  2639.         }
  2640. if (cmp > 0) {
  2641. fputs("InnoDB: index records in a wrong order in ",
  2642. stderr);
  2643. not_ok:
  2644. dict_index_name_print(stderr,
  2645. prebuilt->trx, index);
  2646. fputs("n"
  2647. "InnoDB: prev record ", stderr);
  2648. dtuple_print(stderr, prev_entry);
  2649. fputs("n"
  2650. "InnoDB: record ", stderr);
  2651. rec_print(stderr, rec);
  2652. putc('n', stderr);
  2653. is_ok = FALSE;
  2654. } else if ((index->type & DICT_UNIQUE)
  2655.    && !contains_null
  2656.    && matched_fields >=
  2657.    dict_index_get_n_ordering_defined_by_user(index)) {
  2658. fputs("InnoDB: duplicate key in ", stderr);
  2659. goto not_ok;
  2660. }
  2661. }
  2662. mem_heap_empty(heap);
  2663. prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
  2664. ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
  2665. goto loop;
  2666. }
  2667. /*************************************************************************
  2668. Checks a table for corruption. */
  2669. ulint
  2670. row_check_table_for_mysql(
  2671. /*======================*/
  2672. /* out: DB_ERROR or DB_SUCCESS */
  2673. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  2674. handle */
  2675. {
  2676. dict_table_t* table = prebuilt->table;
  2677. dict_index_t* index;
  2678. ulint n_rows;
  2679. ulint n_rows_in_table = ULINT_UNDEFINED;
  2680. ulint ret  = DB_SUCCESS;
  2681. ulint old_isolation_level;
  2682. if (prebuilt->table->ibd_file_missing) {
  2683.         ut_print_timestamp(stderr);
  2684.         fprintf(stderr, "  InnoDB: Error:n"
  2685. "InnoDB: MySQL is trying to use a table handle but the .ibd file forn"
  2686. "InnoDB: table %s does not exist.n"
  2687. "InnoDB: Have you deleted the .ibd file from the database directory undern"
  2688. "InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?n"
  2689. "InnoDB: Look fromn"
  2690. "http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.htmln"
  2691. "InnoDB: how you can resolve the problem.n",
  2692. prebuilt->table->name);
  2693. return(DB_ERROR);
  2694. }
  2695. prebuilt->trx->op_info = "checking table";
  2696. old_isolation_level = prebuilt->trx->isolation_level;
  2697. /* We must run the index record counts at an isolation level
  2698. >= READ COMMITTED, because a dirty read can see a wrong number
  2699. of records in some index; to play safe, we use always
  2700. REPEATABLE READ here */
  2701. prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
  2702. /* Enlarge the fatal lock wait timeout during CHECK TABLE. */
  2703. mutex_enter(&kernel_mutex);
  2704. srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
  2705. mutex_exit(&kernel_mutex);
  2706. index = dict_table_get_first_index(table);
  2707. while (index != NULL) {
  2708. /* fputs("Validating index ", stderr);
  2709. ut_print_name(stderr, index->name);
  2710. putc('n', stderr); */
  2711. if (!btr_validate_tree(index->tree)) {
  2712. ret = DB_ERROR;
  2713. } else {
  2714. if (!row_scan_and_check_index(prebuilt,
  2715. index, &n_rows)) {
  2716. ret = DB_ERROR;
  2717. }
  2718. /* fprintf(stderr, "%lu entries in index %sn", n_rows,
  2719.   index->name); */
  2720. if (index == dict_table_get_first_index(table)) {
  2721. n_rows_in_table = n_rows;
  2722. } else if (n_rows != n_rows_in_table) {
  2723. ret = DB_ERROR;
  2724.  
  2725. fputs("Error: ", stderr);
  2726. dict_index_name_print(stderr,
  2727. prebuilt->trx, index);
  2728. fprintf(stderr,
  2729. " contains %lu entries, should be %lun",
  2730. (ulong) n_rows,
  2731. (ulong) n_rows_in_table);
  2732. }
  2733. }
  2734. index = dict_table_get_next_index(index);
  2735. }
  2736. /* Restore the original isolation level */
  2737. prebuilt->trx->isolation_level = old_isolation_level;
  2738. /* We validate also the whole adaptive hash index for all tables
  2739. at every CHECK TABLE */
  2740. if (!btr_search_validate()) {
  2741. ret = DB_ERROR;
  2742. }
  2743. /* Restore the fatal lock wait timeout after CHECK TABLE. */
  2744. mutex_enter(&kernel_mutex);
  2745. srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
  2746. mutex_exit(&kernel_mutex);
  2747. prebuilt->trx->op_info = "";
  2748. return(ret);
  2749. }