row0mysql.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:26k
源码类别:

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 "trx0roll.h"
  20. #include "trx0purge.h"
  21. #include "lock0lock.h"
  22. /***********************************************************************
  23. Reads a MySQL format variable-length field (like VARCHAR) length and
  24. returns pointer to the field data. */
  25. byte*
  26. row_mysql_read_var_ref_noninline(
  27. /*=============================*/
  28. /* out: field + 2 */
  29. ulint* len, /* out: variable-length field length */
  30. byte* field) /* in: field */
  31. {
  32. return(row_mysql_read_var_ref(len, field));
  33. }
  34. /***********************************************************************
  35. Stores a reference to a BLOB in the MySQL format. */
  36. void
  37. row_mysql_store_blob_ref(
  38. /*=====================*/
  39. byte* dest, /* in: where to store */
  40. ulint col_len, /* in: dest buffer size: determines into
  41. how many bytes the BLOB length is stored,
  42. this may vary from 1 to 4 bytes */
  43. byte* data, /* in: BLOB data */
  44. ulint len) /* in: BLOB length */
  45. {
  46. /* In dest there are 1 - 4 bytes reserved for the BLOB length,
  47. and after that 8 bytes reserved for the pointer to the data.
  48. In 32-bit architectures we only use the first 4 bytes of the pointer
  49. slot. */
  50. mach_write_to_n_little_endian(dest, col_len - 8, len);
  51. ut_memcpy(dest + col_len - 8, (byte*)&data, sizeof(byte*));
  52. }
  53. /***********************************************************************
  54. Reads a reference to a BLOB in the MySQL format. */
  55. byte*
  56. row_mysql_read_blob_ref(
  57. /*====================*/
  58. /* out: pointer to BLOB data */
  59. ulint* len, /* out: BLOB length */
  60. byte* ref, /* in: BLOB reference in the MySQL format */
  61. ulint col_len) /* in: BLOB reference length (not BLOB
  62. length) */
  63. {
  64. byte* data;
  65. *len = mach_read_from_n_little_endian(ref, col_len - 8);
  66. ut_memcpy((byte*)&data, ref + col_len - 8, sizeof(byte*));
  67. return(data);
  68. }
  69. /******************************************************************
  70. Convert a row in the MySQL format to a row in the Innobase format. */
  71. static
  72. void
  73. row_mysql_convert_row_to_innobase(
  74. /*==============================*/
  75. dtuple_t* row, /* in/out: Innobase row where the
  76. field type information is already
  77. copied there, or will be copied
  78. later */
  79. row_prebuilt_t* prebuilt, /* in: prebuilt struct where template
  80. must be of type ROW_MYSQL_WHOLE_ROW */
  81. byte* mysql_rec) /* in: row in the MySQL format;
  82. NOTE: do not discard as long as
  83. row is used, as row may contain
  84. pointers to this record! */
  85. {
  86. mysql_row_templ_t* templ;
  87. dfield_t* dfield;
  88. ulint i;
  89. ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
  90. ut_ad(prebuilt->mysql_template);
  91. for (i = 0; i < prebuilt->n_template; i++) {
  92. templ = prebuilt->mysql_template + i;
  93. dfield = dtuple_get_nth_field(row, i);
  94. if (templ->mysql_null_bit_mask != 0) {
  95. /* Column may be SQL NULL */
  96. if (mysql_rec[templ->mysql_null_byte_offset] &
  97.   (byte) (templ->mysql_null_bit_mask)) {
  98. /* It is SQL NULL */
  99. dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
  100. goto next_column;
  101. }
  102. }
  103. row_mysql_store_col_in_innobase_format(dfield,
  104. prebuilt->ins_upd_rec_buff
  105. + templ->mysql_col_offset,
  106. mysql_rec + templ->mysql_col_offset,
  107. templ->mysql_col_len,
  108. templ->type, templ->is_unsigned);
  109. next_column:
  110. ;
  111. }
  112. /********************************************************************
  113. Handles user errors and lock waits detected by the database engine. */
  114. ibool
  115. row_mysql_handle_errors(
  116. /*====================*/
  117. /* out: TRUE if it was a lock wait and
  118. we should continue running the query thread */
  119. ulint* new_err,/* out: possible new error encountered in
  120. rollback, or the old error which was
  121. during the function entry */
  122. trx_t* trx, /* in: transaction */
  123. que_thr_t* thr, /* in: query thread */
  124. trx_savept_t* savept) /* in: savepoint */
  125. {
  126. ibool timeout_expired;
  127. ulint err;
  128. handle_new_error:
  129. err = trx->error_state;
  130. ut_a(err != DB_SUCCESS);
  131. trx->error_state = DB_SUCCESS;
  132. if (err == DB_DUPLICATE_KEY) {
  133. if (savept) {
  134. /* Roll back the latest, possibly incomplete
  135. insertion or update */
  136. trx_general_rollback_for_mysql(trx, TRUE, savept);
  137. }
  138. } else if (err == DB_TOO_BIG_RECORD) {
  139. if (savept) {
  140. /* Roll back the latest, possibly incomplete
  141. insertion or update */
  142. trx_general_rollback_for_mysql(trx, TRUE, savept);
  143. }
  144. } else if (err == DB_LOCK_WAIT) {
  145. timeout_expired = srv_suspend_mysql_thread(thr);
  146. if (timeout_expired) {
  147. trx->error_state = DB_DEADLOCK;
  148. que_thr_stop_for_mysql(thr);
  149. goto handle_new_error;
  150. }
  151. *new_err = err;
  152. return(TRUE);
  153. } else if (err == DB_DEADLOCK) {
  154. /* Roll back the whole transaction */
  155. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  156. } else if (err == DB_OUT_OF_FILE_SPACE) {
  157. /* Roll back the whole transaction */
  158. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  159. } else if (err == DB_MUST_GET_MORE_FILE_SPACE) {
  160. ut_a(0); /* TODO: print something to MySQL error log */
  161. } else {
  162. ut_a(0);
  163. }
  164. if (trx->error_state != DB_SUCCESS) {
  165. *new_err = trx->error_state;
  166. } else {
  167. *new_err = err;
  168. }
  169. trx->error_state = DB_SUCCESS;
  170. return(FALSE);
  171. }
  172. /************************************************************************
  173. Create a prebuilt struct for a MySQL table handle. */
  174. row_prebuilt_t*
  175. row_create_prebuilt(
  176. /*================*/
  177. /* out, own: a prebuilt struct */
  178. dict_table_t* table) /* in: Innobase table handle */
  179. {
  180. row_prebuilt_t* prebuilt;
  181. mem_heap_t* heap;
  182. dict_index_t* clust_index;
  183. dtuple_t* ref;
  184. ulint ref_len;
  185. ulint i;
  186. heap = mem_heap_create(128);
  187. prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
  188. prebuilt->table = table;
  189. prebuilt->trx = NULL;
  190. prebuilt->sql_stat_start = TRUE;
  191. prebuilt->index = NULL;
  192. prebuilt->n_template = 0;
  193. prebuilt->mysql_template = NULL;
  194. prebuilt->heap = heap;
  195. prebuilt->ins_node = NULL;
  196. prebuilt->ins_upd_rec_buff = NULL;
  197. prebuilt->upd_node = NULL;
  198. prebuilt->ins_graph = NULL;
  199. prebuilt->upd_graph = NULL;
  200.    prebuilt->pcur = btr_pcur_create_for_mysql();
  201.    prebuilt->clust_pcur = btr_pcur_create_for_mysql();
  202. prebuilt->select_lock_type = LOCK_NONE;
  203. prebuilt->sel_graph = NULL;
  204. prebuilt->search_tuple = dtuple_create(heap,
  205. dict_table_get_n_cols(table));
  206. clust_index = dict_table_get_first_index(table);
  207. ref_len = dict_index_get_n_unique(clust_index);
  208. ref = dtuple_create(heap, ref_len);
  209. dict_index_copy_types(ref, clust_index, ref_len);
  210. prebuilt->clust_ref = ref;
  211. for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
  212. prebuilt->fetch_cache[i] = NULL;
  213. }
  214. prebuilt->n_fetch_cached = 0;
  215. prebuilt->blob_heap = NULL;
  216. prebuilt->old_vers_heap = NULL;
  217. return(prebuilt);
  218. }
  219. /************************************************************************
  220. Free a prebuilt struct for a MySQL table handle. */
  221. void
  222. row_prebuilt_free(
  223. /*==============*/
  224. row_prebuilt_t* prebuilt) /* in, own: prebuilt struct */
  225. {
  226. ulint i;
  227. btr_pcur_free_for_mysql(prebuilt->pcur);
  228. btr_pcur_free_for_mysql(prebuilt->clust_pcur);
  229. if (prebuilt->mysql_template) {
  230. mem_free(prebuilt->mysql_template);
  231. }
  232. if (prebuilt->ins_graph) {
  233. que_graph_free_recursive(prebuilt->ins_graph);
  234. }
  235. if (prebuilt->sel_graph) {
  236. que_graph_free_recursive(prebuilt->sel_graph);
  237. }
  238. if (prebuilt->upd_graph) {
  239. que_graph_free_recursive(prebuilt->upd_graph);
  240. }
  241. if (prebuilt->blob_heap) {
  242. mem_heap_free(prebuilt->blob_heap);
  243. }
  244. if (prebuilt->old_vers_heap) {
  245. mem_heap_free(prebuilt->old_vers_heap);
  246. }
  247. for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
  248. if (prebuilt->fetch_cache[i] != NULL) {
  249. mem_free(prebuilt->fetch_cache[i]);
  250. }
  251. }
  252. mem_heap_free(prebuilt->heap);
  253. }
  254. /*************************************************************************
  255. Updates the transaction pointers in query graphs stored in the prebuilt
  256. struct. */
  257. void
  258. row_update_prebuilt_trx(
  259. /*====================*/
  260. /* out: prebuilt dtuple */
  261. row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
  262. handle */
  263. trx_t* trx) /* in: transaction handle */
  264. {
  265. prebuilt->trx = trx;
  266. if (prebuilt->ins_graph) {
  267. prebuilt->ins_graph->trx = trx;
  268. }
  269. if (prebuilt->upd_graph) {
  270. prebuilt->upd_graph->trx = trx;
  271. }
  272. if (prebuilt->sel_graph) {
  273. prebuilt->sel_graph->trx = trx;
  274. }
  275. }
  276. /*************************************************************************
  277. Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
  278. has not yet been built in the prebuilt struct, then this function first
  279. builds it. */
  280. static
  281. dtuple_t*
  282. row_get_prebuilt_insert_row(
  283. /*========================*/
  284. /* out: prebuilt dtuple */
  285. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  286. handle */
  287. {
  288. ins_node_t* node;
  289. dtuple_t* row;
  290. dict_table_t* table = prebuilt->table;
  291. ut_ad(prebuilt && table && prebuilt->trx);
  292. if (prebuilt->ins_node == NULL) {
  293. /* Not called before for this handle: create an insert node
  294. and query graph to the prebuilt struct */
  295. node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
  296. prebuilt->ins_node = node;
  297. if (prebuilt->ins_upd_rec_buff == NULL) {
  298. prebuilt->ins_upd_rec_buff = mem_heap_alloc(
  299. prebuilt->heap,
  300. prebuilt->mysql_row_len);
  301. }
  302. row = dtuple_create(prebuilt->heap,
  303. dict_table_get_n_cols(table));
  304. dict_table_copy_types(row, table);
  305. ins_node_set_new_row(node, row);
  306. prebuilt->ins_graph =
  307. que_node_get_parent(
  308. pars_complete_graph_for_exec(node,
  309. prebuilt->trx,
  310. prebuilt->heap));
  311. prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
  312. }
  313. return(prebuilt->ins_node->row);
  314. }
  315. /*************************************************************************
  316. Updates the table modification counter and calculates new estimates
  317. for table and index statistics if necessary. */
  318. UNIV_INLINE
  319. void
  320. row_update_statistics_if_needed(
  321. /*============================*/
  322. row_prebuilt_t* prebuilt) /* in: prebuilt struct */
  323. {
  324. ulint counter;
  325. ulint old_counter;
  326. counter = prebuilt->table->stat_modif_counter;
  327. counter += prebuilt->mysql_row_len;
  328. prebuilt->table->stat_modif_counter = counter;
  329. old_counter = prebuilt->table->stat_last_estimate_counter;
  330. if (counter - old_counter >= DICT_STAT_CALCULATE_INTERVAL
  331.     || counter - old_counter >=
  332. (UNIV_PAGE_SIZE
  333. * prebuilt->table->stat_clustered_index_size / 2)) {
  334. dict_update_statistics(prebuilt->table);
  335. }
  336. }
  337. /*************************************************************************
  338. Does an insert for MySQL. */
  339. int
  340. row_insert_for_mysql(
  341. /*=================*/
  342. /* out: error code or DB_SUCCESS */
  343. byte* mysql_rec, /* in: row in the MySQL format */
  344. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  345. handle */
  346. {
  347. trx_savept_t savept;
  348. que_thr_t* thr;
  349. ulint err;
  350. ibool was_lock_wait;
  351. trx_t* trx  = prebuilt->trx;
  352. ins_node_t* node = prebuilt->ins_node;
  353. ut_ad(trx);
  354. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  355. if (node == NULL) {
  356. row_get_prebuilt_insert_row(prebuilt);
  357. node = prebuilt->ins_node;
  358. }
  359. row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
  360. savept = trx_savept_take(trx);
  361. thr = que_fork_get_first_thr(prebuilt->ins_graph);
  362. if (prebuilt->sql_stat_start) {
  363. node->state = INS_NODE_SET_IX_LOCK;
  364. prebuilt->sql_stat_start = FALSE;
  365. } else {
  366. node->state = INS_NODE_ALLOC_ROW_ID;
  367. }
  368. que_thr_move_to_run_state_for_mysql(thr, trx);
  369. run_again:
  370. thr->run_node = node;
  371. thr->prev_node = node;
  372. row_ins_step(thr);
  373. err = trx->error_state;
  374. if (err != DB_SUCCESS) {
  375. que_thr_stop_for_mysql(thr);
  376. was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
  377. &savept);
  378. if (was_lock_wait) {
  379. goto run_again;
  380. }
  381. return(err);
  382. }
  383. que_thr_stop_for_mysql_no_error(thr, trx);
  384. prebuilt->table->stat_n_rows++;
  385. if (prebuilt->table->stat_n_rows == 0) {
  386. /* Avoid wrap-over */
  387. prebuilt->table->stat_n_rows--;
  388. }
  389. row_update_statistics_if_needed(prebuilt);
  390. return((int) err);
  391. }
  392. /*************************************************************************
  393. Builds a dummy query graph used in selects. */
  394. void
  395. row_prebuild_sel_graph(
  396. /*===================*/
  397. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  398. handle */
  399. {
  400. sel_node_t* node;
  401. ut_ad(prebuilt && prebuilt->trx);
  402. if (prebuilt->sel_graph == NULL) {
  403. node = sel_node_create(prebuilt->heap);
  404. prebuilt->sel_graph =
  405. que_node_get_parent(
  406. pars_complete_graph_for_exec(node,
  407. prebuilt->trx,
  408. prebuilt->heap));
  409. prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
  410. }
  411. }
  412. /*************************************************************************
  413. Gets pointer to a prebuilt update vector used in updates. If the update
  414. graph has not yet been built in the prebuilt struct, then this function
  415. first builds it. */
  416. upd_t*
  417. row_get_prebuilt_update_vector(
  418. /*===========================*/
  419. /* out: prebuilt update vector */
  420. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  421. handle */
  422. {
  423. dict_table_t* table = prebuilt->table;
  424. upd_node_t* node;
  425. ut_ad(prebuilt && table && prebuilt->trx);
  426. if (prebuilt->upd_node == NULL) {
  427. /* Not called before for this handle: create an update node
  428. and query graph to the prebuilt struct */
  429. node = upd_node_create(prebuilt->heap);
  430. prebuilt->upd_node = node;
  431. node->in_mysql_interface = TRUE;
  432. node->is_delete = FALSE;
  433. node->searched_update = FALSE;
  434. node->select_will_do_update = FALSE;
  435. node->select = NULL;
  436. node->pcur = btr_pcur_create_for_mysql();
  437. node->table = table;
  438. node->update = upd_create(dict_table_get_n_cols(table),
  439. prebuilt->heap);
  440. UT_LIST_INIT(node->columns);
  441. node->has_clust_rec_x_lock = TRUE;
  442. node->cmpl_info = 0;
  443. node->table_sym = NULL;
  444. node->col_assign_list = NULL;
  445. prebuilt->upd_graph =
  446. que_node_get_parent(
  447. pars_complete_graph_for_exec(node,
  448. prebuilt->trx,
  449. prebuilt->heap));
  450. prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
  451. }
  452. return(prebuilt->upd_node->update);
  453. }
  454. /*************************************************************************
  455. Does an update or delete of a row for MySQL. */
  456. int
  457. row_update_for_mysql(
  458. /*=================*/
  459. /* out: error code or DB_SUCCESS */
  460. byte* mysql_rec, /* in: the row to be updated, in
  461. the MySQL format */
  462. row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
  463. handle */
  464. {
  465. trx_savept_t savept;
  466. ulint err;
  467. que_thr_t* thr;
  468. ibool was_lock_wait;
  469. dict_index_t* clust_index; 
  470. /* ulint ref_len; */
  471. upd_node_t* node;
  472. dict_table_t* table = prebuilt->table;
  473. trx_t* trx = prebuilt->trx;
  474. /* mem_heap_t* heap;
  475. dtuple_t* search_tuple;
  476. dtuple_t* row_tuple;
  477. mtr_t mtr; */
  478. ut_ad(prebuilt && trx);
  479. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  480. node = prebuilt->upd_node;
  481. clust_index = dict_table_get_first_index(table);
  482. if (prebuilt->pcur->btr_cur.index == clust_index) {
  483. btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
  484. } else {
  485. btr_pcur_copy_stored_position(node->pcur, prebuilt->clust_pcur);
  486. }
  487. ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
  488.  
  489. /* MySQL seems to call rnd_pos before updating each row it
  490. has cached: we can get the correct cursor position from
  491. prebuilt->pcur; NOTE that we cannot build the row reference
  492. from mysql_rec if the clustered index was automatically
  493. generated for the table: MySQL does not know anything about
  494. the row id used as the clustered index key */
  495. #ifdef notdefined
  496. /* We have to search for the correct cursor position */
  497. ref_len = dict_index_get_n_unique(clust_index);
  498. heap = mem_heap_create(450);
  499. row_tuple = dtuple_create(heap, dict_table_get_n_cols(table));
  500. dict_table_copy_types(row_tuple, table);
  501. if (prebuilt->ins_upd_rec_buff == NULL) {
  502. prebuilt->ins_upd_rec_buff = mem_heap_alloc(prebuilt->heap,
  503. prebuilt->mysql_row_len);
  504. }
  505. row_mysql_convert_row_to_innobase(row_tuple, prebuilt, mysql_rec);
  506. search_tuple = dtuple_create(heap, ref_len);
  507. row_build_row_ref_from_row(search_tuple, table, row_tuple);
  508. mtr_start(&mtr);
  509. btr_pcur_open_with_no_init(clust_index, search_tuple, PAGE_CUR_LE,
  510. BTR_SEARCH_LEAF, node->pcur, 0, &mtr);
  511. btr_pcur_store_position(node->pcur, &mtr);
  512. mtr_commit(&mtr);
  513. mem_heap_free(heap);
  514. #endif
  515. savept = trx_savept_take(trx);
  516. thr = que_fork_get_first_thr(prebuilt->upd_graph);
  517. node->state = UPD_NODE_UPDATE_CLUSTERED;
  518. ut_ad(!prebuilt->sql_stat_start);
  519. que_thr_move_to_run_state_for_mysql(thr, trx);
  520. run_again:
  521. thr->run_node = node;
  522. thr->prev_node = node;
  523. row_upd_step(thr);
  524. err = trx->error_state;
  525. if (err != DB_SUCCESS) {
  526. que_thr_stop_for_mysql(thr);
  527. if (err == DB_RECORD_NOT_FOUND) {
  528. trx->error_state = DB_SUCCESS;
  529. return((int) err);
  530. }
  531. was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
  532. &savept);
  533. if (was_lock_wait) {
  534. goto run_again;
  535. }
  536. return(err);
  537. }
  538. que_thr_stop_for_mysql_no_error(thr, trx);
  539. if (prebuilt->upd_node->is_delete) {
  540. if (prebuilt->table->stat_n_rows > 0) {
  541. prebuilt->table->stat_n_rows--;
  542. }
  543. }
  544. row_update_statistics_if_needed(prebuilt);
  545. return((int) err);
  546. }
  547. /*************************************************************************
  548. Checks if a table is such that we automatically created a clustered
  549. index on it (on row id). */
  550. ibool
  551. row_table_got_default_clust_index(
  552. /*==============================*/
  553. dict_table_t* table)
  554. {
  555. dict_index_t* clust_index;
  556. clust_index = dict_table_get_first_index(table);
  557. if (dtype_get_mtype(dict_index_get_nth_type(clust_index, 0))
  558.   == DATA_SYS) {
  559.   return(TRUE);
  560. }
  561. return(FALSE);
  562. }
  563. /*************************************************************************
  564. Calculates the key number used inside MySQL for an Innobase index. We have
  565. to take into account if we generated a default clustered index for the table */
  566. ulint
  567. row_get_mysql_key_number_for_index(
  568. /*===============================*/
  569. dict_index_t* index)
  570. {
  571. dict_index_t* ind;
  572. ulint i;
  573. ut_a(index);
  574. i = 0;
  575. ind = dict_table_get_first_index(index->table);
  576. while (index != ind) {
  577. ind = dict_table_get_next_index(ind);
  578. i++;
  579. }
  580. if (row_table_got_default_clust_index(index->table)) {
  581. ut_a(i > 0);
  582. i--;
  583. }
  584. return(i);
  585. }
  586. /*************************************************************************
  587. Does a table creation operation for MySQL. */
  588. int
  589. row_create_table_for_mysql(
  590. /*=======================*/
  591. /* out: error code or DB_SUCCESS */
  592. dict_table_t* table, /* in: table definition */
  593. trx_t* trx) /* in: transaction handle */
  594. {
  595. tab_node_t* node;
  596. mem_heap_t* heap;
  597. que_thr_t* thr;
  598. ulint err;
  599. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  600. /* Serialize data dictionary operations with dictionary mutex:
  601. no deadlocks can occur then in these operations */
  602. mutex_enter(&(dict_sys->mutex));
  603. heap = mem_heap_create(512);
  604. trx->dict_operation = TRUE;
  605. node = tab_create_graph_create(table, heap);
  606. thr = pars_complete_graph_for_exec(node, trx, heap);
  607. ut_a(thr == que_fork_start_command(que_node_get_parent(thr),
  608. SESS_COMM_EXECUTE, 0));
  609. que_run_threads(thr);
  610. err = trx->error_state;
  611. if (err != DB_SUCCESS) {
  612. /* We have special error handling here */
  613. trx->error_state = DB_SUCCESS;
  614. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  615. if (err == DB_OUT_OF_FILE_SPACE) {
  616.          row_drop_table_for_mysql(table->name, trx, TRUE);
  617. } else {
  618.          assert(err == DB_DUPLICATE_KEY);
  619.  fprintf(stderr, 
  620.      "Innobase: error: table %s already exists in Innobase data dictionaryn",
  621.  table->name);
  622. }
  623. trx->error_state = DB_SUCCESS;
  624. }
  625. mutex_exit(&(dict_sys->mutex));
  626. que_graph_free((que_t*) que_node_get_parent(thr));
  627. return((int) err);
  628. }
  629. /*************************************************************************
  630. Does an index creation operation for MySQL. TODO: currently failure
  631. to create an index results in dropping the whole table! This is no problem
  632. currently as all indexes must be created at the same time as the table. */
  633. int
  634. row_create_index_for_mysql(
  635. /*=======================*/
  636. /* out: error number or DB_SUCCESS */
  637. dict_index_t* index, /* in: index defintion */
  638. trx_t* trx) /* in: transaction handle */
  639. {
  640. ind_node_t* node;
  641. mem_heap_t* heap;
  642. que_thr_t* thr;
  643. ulint err;
  644. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  645. /* Serialize data dictionary operations with dictionary mutex:
  646. no deadlocks can occur then in these operations */
  647. mutex_enter(&(dict_sys->mutex));
  648. heap = mem_heap_create(512);
  649. trx->dict_operation = TRUE;
  650. node = ind_create_graph_create(index, heap);
  651. thr = pars_complete_graph_for_exec(node, trx, heap);
  652. ut_a(thr == que_fork_start_command(que_node_get_parent(thr),
  653. SESS_COMM_EXECUTE, 0));
  654. que_run_threads(thr);
  655. err = trx->error_state;
  656. if (err != DB_SUCCESS) {
  657. /* We have special error handling here */
  658. ut_a(err == DB_OUT_OF_FILE_SPACE);
  659. trx->error_state = DB_SUCCESS;
  660. trx_general_rollback_for_mysql(trx, FALSE, NULL);
  661. row_drop_table_for_mysql(index->table_name, trx, TRUE);
  662. trx->error_state = DB_SUCCESS;
  663. }
  664. mutex_exit(&(dict_sys->mutex));
  665. que_graph_free((que_t*) que_node_get_parent(thr));
  666. return((int) err);
  667. }
  668. /*************************************************************************
  669. Drops a table for MySQL. */
  670. int
  671. row_drop_table_for_mysql(
  672. /*=====================*/
  673. /* out: error code or DB_SUCCESS */
  674. char* name, /* in: table name */
  675. trx_t* trx, /* in: transaction handle */
  676. ibool has_dict_mutex) /* in: TRUE if the caller already owns the
  677. dictionary system mutex */
  678. {
  679. dict_table_t* table;
  680. que_thr_t* thr;
  681. que_t* graph;
  682. ulint err;
  683. char* str1;
  684. char* str2;
  685. ulint len;
  686. char buf[10000];
  687. retry:
  688. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  689. ut_a(name != NULL);
  690. /* We use the private SQL parser of Innobase to generate the
  691. query graphs needed in deleting the dictionary data from system
  692. tables in Innobase. Deleting a row from SYS_INDEXES table also
  693. frees the file segments of the B-tree associated with the index. */
  694. str1 =
  695. "PROCEDURE DROP_TABLE_PROC () ISn"
  696. "table_id CHAR;n"
  697. "index_id CHAR;n"
  698. "found INT;n"
  699. "BEGINn"
  700. "SELECT ID INTO table_idn"
  701. "FROM SYS_TABLESn"
  702. "WHERE NAME ='";
  703. str2 = 
  704. "';n"
  705. "IF (SQL % NOTFOUND) THENn"
  706. " COMMIT WORK;n"
  707. " RETURN;n"
  708. "END IF;n"
  709. "found := 1;n"
  710. "WHILE found = 1 LOOPn"
  711. " SELECT ID INTO index_idn"
  712. " FROM SYS_INDEXESn"
  713. " WHERE TABLE_ID = table_id;n"
  714. " IF (SQL % NOTFOUND) THENn"
  715. " found := 0;n"
  716. " ELSE"
  717. " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;n"
  718. " DELETE FROM SYS_INDEXES WHERE ID = index_id;n"
  719. " END IF;n"
  720. "END LOOP;n"
  721. "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;n"
  722. "DELETE FROM SYS_TABLES WHERE ID = table_id;n"
  723. "COMMIT WORK;n"
  724. "END;n";
  725. len = ut_strlen(str1);
  726. ut_memcpy(buf, str1, len);
  727. ut_memcpy(buf + len, name, ut_strlen(name));
  728. len += ut_strlen(name);
  729. ut_memcpy(buf + len, str2, ut_strlen(str2) + 1);
  730. /* Serialize data dictionary operations with dictionary mutex:
  731. no deadlocks can occur then in these operations */
  732. if (!has_dict_mutex) {
  733. mutex_enter(&(dict_sys->mutex));
  734. }
  735. graph = pars_sql(buf);
  736. ut_a(graph);
  737. graph->trx = trx;
  738. trx->graph = NULL;
  739. graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
  740. /* Prevent purge from running while we are dropping the table */
  741. rw_lock_s_lock(&(purge_sys->purge_is_running));
  742. table = dict_table_get_low(name);
  743. if (!table) {
  744. err = DB_TABLE_NOT_FOUND;
  745. goto funct_exit;
  746. }
  747. /* Check if there are any locks on the table: if yes, it cannot
  748. be dropped: we have to wait for the locks to be released  */
  749. if (lock_is_on_table(table)) {
  750. err = DB_TABLE_IS_BEING_USED;
  751. goto funct_exit;
  752. }
  753. /* TODO: check that MySQL prevents users from accessing the table
  754. after this function row_drop_table_for_mysql has been called:
  755. otherwise anyone with an open handle to the table could, for example,
  756. come to read the table! */
  757. trx->dict_operation = TRUE;
  758. trx->table_id = table->id;
  759. ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
  760. que_run_threads(thr);
  761. err = trx->error_state;
  762. if (err != DB_SUCCESS) {
  763. ut_a(err == DB_OUT_OF_FILE_SPACE);
  764. err = DB_MUST_GET_MORE_FILE_SPACE;
  765. row_mysql_handle_errors(&err, trx, thr, NULL);
  766. ut_a(0);
  767. } else {
  768. dict_table_remove_from_cache(table);
  769. }
  770. funct_exit:
  771. rw_lock_s_unlock(&(purge_sys->purge_is_running));
  772. if (!has_dict_mutex) {
  773. mutex_exit(&(dict_sys->mutex));
  774. }
  775. que_graph_free(graph);
  776. if (err == DB_TABLE_IS_BEING_USED) {
  777. os_thread_sleep(200000);
  778. goto retry;
  779. }
  780. return((int) err);
  781. }
  782. /*************************************************************************
  783. Renames a table for MySQL. */
  784. int
  785. row_rename_table_for_mysql(
  786. /*=======================*/
  787. /* out: error code or DB_SUCCESS */
  788. char* old_name, /* in: old table name */
  789. char* new_name, /* in: new table name */
  790. trx_t* trx) /* in: transaction handle */
  791. {
  792. dict_table_t* table;
  793. que_thr_t* thr;
  794. que_t* graph;
  795. ulint err;
  796. char* str1;
  797. char* str2;
  798. char* str3;
  799. ulint len;
  800. char buf[10000];
  801. ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
  802. ut_a(old_name != NULL);
  803. ut_a(new_name != NULL);
  804. str1 =
  805. "PROCEDURE RENAME_TABLE_PROC () ISn"
  806. "BEGINn"
  807. "UPDATE SYS_TABLES SET NAME ='";
  808. str2 = 
  809. "' WHERE NAME = '";
  810. str3 =
  811. "';n"
  812. "COMMIT WORK;n"
  813. "END;n";
  814. len = ut_strlen(str1);
  815. ut_memcpy(buf, str1, len);
  816. ut_memcpy(buf + len, new_name, ut_strlen(new_name));
  817. len += ut_strlen(new_name);
  818. ut_memcpy(buf + len, str2, ut_strlen(str2));
  819. len += ut_strlen(str2);
  820. ut_memcpy(buf + len, old_name, ut_strlen(old_name));
  821. len += ut_strlen(old_name);
  822. ut_memcpy(buf + len, str3, ut_strlen(str3) + 1);
  823. /* Serialize data dictionary operations with dictionary mutex:
  824. no deadlocks can occur then in these operations */
  825. mutex_enter(&(dict_sys->mutex));
  826. table = dict_table_get_low(old_name);
  827. graph = pars_sql(buf);
  828. ut_a(graph);
  829. graph->trx = trx;
  830. trx->graph = NULL;
  831. graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
  832. if (!table) {
  833. err = DB_TABLE_NOT_FOUND;
  834. goto funct_exit;
  835. }
  836. ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
  837. que_run_threads(thr);
  838. err = trx->error_state;
  839. if (err != DB_SUCCESS) {
  840. row_mysql_handle_errors(&err, trx, thr, NULL);
  841. } else {
  842. ut_a(dict_table_rename_in_cache(table, new_name));
  843. }
  844. funct_exit:
  845. mutex_exit(&(dict_sys->mutex));
  846. que_graph_free(graph);
  847. return((int) err);
  848. }