You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2504 lines
66 KiB

17 years ago
17 years ago
17 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
14 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
16 years ago
16 years ago
16 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
- maria/ma_test_all.sh can now be run with --tmpdir=/dev/shm for faster testing - Fixed mysql-test-run failures on window - Fixed compiler warnings from my last push (sorry about that) - Fixed that maria_chk --repair --extended works again - Fixed compiler warnings about using not unitialized data mysql-test/mysql-test-run.pl: Better output mysql-test/suite/parts/inc/partition_check_drop.inc: Use remove_files_wildcard instead of rm mysys/safemalloc.c: Fixed argument to printf storage/maria/ma_cache.c: Don't give errors when running maria_chk storage/maria/ma_dynrec.c: Don't give errors when running maria_chk storage/maria/ma_rt_test.c: Added option --datadir for where to put logs and test data storage/maria/ma_test1.c: Added option --datadir for where to put logs and test data storage/maria/ma_test2.c: Added option --datadir for where to put logs and test data storage/maria/maria_chk.c: If --datadir is used but --logdir is not, set --logdir from --datadir (this reflects how --help said how things should work) storage/maria/maria_read_log.c: Changed short option for 'maria-log-dir-path' from -l to -h to be same as mysqld, maria_chk, ma_test1 etc.. storage/maria/unittest/ma_test_all-t: Allow one to specify --tmpdir for where to store logs and data storage/xtradb/buf/buf0buf.c: Fixed compiler warnings about using not unitialized data storage/xtradb/row/row0upd.c: Fixed compiler warnings about using not unitialized data storage/xtradb/srv/srv0srv.c: Fixed compiler warnings about using not unitialized data
15 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
14 years ago
14 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
14 years ago
16 years ago
14 years ago
14 years ago
16 years ago
16 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
  1. /*****************************************************************************
  2. Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
  3. This program is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free Software
  5. Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along with
  10. this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
  12. *****************************************************************************/
  13. /**************************************************//**
  14. @file row/row0upd.c
  15. Update of a row
  16. Created 12/27/1996 Heikki Tuuri
  17. *******************************************************/
  18. #include "m_string.h" /* for my_sys.h */
  19. #include "my_sys.h" /* DEBUG_SYNC_C */
  20. #include "row0upd.h"
  21. #ifdef UNIV_NONINL
  22. #include "row0upd.ic"
  23. #endif
  24. #include "dict0dict.h"
  25. #include "trx0undo.h"
  26. #include "rem0rec.h"
  27. #ifndef UNIV_HOTBACKUP
  28. #include "dict0boot.h"
  29. #include "dict0crea.h"
  30. #include "mach0data.h"
  31. #include "btr0btr.h"
  32. #include "btr0cur.h"
  33. #include "que0que.h"
  34. #include "row0ext.h"
  35. #include "row0ins.h"
  36. #include "row0sel.h"
  37. #include "row0row.h"
  38. #include "rem0cmp.h"
  39. #include "lock0lock.h"
  40. #include "log0log.h"
  41. #include "pars0sym.h"
  42. #include "eval0eval.h"
  43. #include "buf0lru.h"
  44. /* What kind of latch and lock can we assume when the control comes to
  45. -------------------------------------------------------------------
  46. an update node?
  47. --------------
  48. Efficiency of massive updates would require keeping an x-latch on a
  49. clustered index page through many updates, and not setting an explicit
  50. x-lock on clustered index records, as they anyway will get an implicit
  51. x-lock when they are updated. A problem is that the read nodes in the
  52. graph should know that they must keep the latch when passing the control
  53. up to the update node, and not set any record lock on the record which
  54. will be updated. Another problem occurs if the execution is stopped,
  55. as the kernel switches to another query thread, or the transaction must
  56. wait for a lock. Then we should be able to release the latch and, maybe,
  57. acquire an explicit x-lock on the record.
  58. Because this seems too complicated, we conclude that the less
  59. efficient solution of releasing all the latches when the control is
  60. transferred to another node, and acquiring explicit x-locks, is better. */
  61. /* How is a delete performed? If there is a delete without an
  62. explicit cursor, i.e., a searched delete, there are at least
  63. two different situations:
  64. the implicit select cursor may run on (1) the clustered index or
  65. on (2) a secondary index. The delete is performed by setting
  66. the delete bit in the record and substituting the id of the
  67. deleting transaction for the original trx id, and substituting a
  68. new roll ptr for previous roll ptr. The old trx id and roll ptr
  69. are saved in the undo log record. Thus, no physical changes occur
  70. in the index tree structure at the time of the delete. Only
  71. when the undo log is purged, the index records will be physically
  72. deleted from the index trees.
  73. The query graph executing a searched delete would consist of
  74. a delete node which has as a subtree a select subgraph.
  75. The select subgraph should return a (persistent) cursor
  76. in the clustered index, placed on page which is x-latched.
  77. The delete node should look for all secondary index records for
  78. this clustered index entry and mark them as deleted. When is
  79. the x-latch freed? The most efficient way for performing a
  80. searched delete is obviously to keep the x-latch for several
  81. steps of query graph execution. */
  82. /*************************************************************************
  83. IMPORTANT NOTE: Any operation that generates redo MUST check that there
  84. is enough space in the redo log before for that operation. This is
  85. done by calling log_free_check(). The reason for checking the
  86. availability of the redo log space before the start of the operation is
  87. that we MUST not hold any synchonization objects when performing the
  88. check.
  89. If you make a change in this module make sure that no codepath is
  90. introduced where a call to log_free_check() is bypassed. */
  91. /***********************************************************//**
  92. Checks if an update vector changes some of the first ordering fields of an
  93. index record. This is only used in foreign key checks and we can assume
  94. that index does not contain column prefixes.
  95. @return TRUE if changes */
  96. static
  97. ibool
  98. row_upd_changes_first_fields_binary(
  99. /*================================*/
  100. dtuple_t* entry, /*!< in: old value of index entry */
  101. dict_index_t* index, /*!< in: index of entry */
  102. const upd_t* update, /*!< in: update vector for the row */
  103. ulint n); /*!< in: how many first fields to check */
  104. /*********************************************************************//**
  105. Checks if index currently is mentioned as a referenced index in a foreign
  106. key constraint.
  107. NOTE that since we do not hold dict_operation_lock when leaving the
  108. function, it may be that the referencing table has been dropped when
  109. we leave this function: this function is only for heuristic use!
  110. @return TRUE if referenced */
  111. static
  112. ibool
  113. row_upd_index_is_referenced(
  114. /*========================*/
  115. dict_index_t* index, /*!< in: index */
  116. trx_t* trx) /*!< in: transaction */
  117. {
  118. dict_table_t* table = index->table;
  119. dict_foreign_t* foreign;
  120. ibool froze_data_dict = FALSE;
  121. ibool is_referenced = FALSE;
  122. if (!UT_LIST_GET_FIRST(table->referenced_list)) {
  123. return(FALSE);
  124. }
  125. if (trx->dict_operation_lock_mode == 0) {
  126. row_mysql_freeze_data_dictionary(trx);
  127. froze_data_dict = TRUE;
  128. }
  129. foreign = UT_LIST_GET_FIRST(table->referenced_list);
  130. while (foreign) {
  131. if (foreign->referenced_index == index) {
  132. is_referenced = TRUE;
  133. goto func_exit;
  134. }
  135. foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
  136. }
  137. func_exit:
  138. if (froze_data_dict) {
  139. row_mysql_unfreeze_data_dictionary(trx);
  140. }
  141. return(is_referenced);
  142. }
  143. /*********************************************************************//**
  144. Checks if possible foreign key constraints hold after a delete of the record
  145. under pcur.
  146. NOTE that this function will temporarily commit mtr and lose the
  147. pcur position!
  148. @return DB_SUCCESS or an error code */
  149. static
  150. ulint
  151. row_upd_check_references_constraints(
  152. /*=================================*/
  153. upd_node_t* node, /*!< in: row update node */
  154. btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the
  155. cursor position is lost in this function! */
  156. dict_table_t* table, /*!< in: table in question */
  157. dict_index_t* index, /*!< in: index of the cursor */
  158. ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */
  159. que_thr_t* thr, /*!< in: query thread */
  160. mtr_t* mtr) /*!< in: mtr */
  161. {
  162. dict_foreign_t* foreign;
  163. mem_heap_t* heap;
  164. dtuple_t* entry;
  165. trx_t* trx;
  166. const rec_t* rec;
  167. ulint n_ext;
  168. ulint err;
  169. ibool got_s_lock = FALSE;
  170. if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
  171. return(DB_SUCCESS);
  172. }
  173. trx = thr_get_trx(thr);
  174. rec = btr_pcur_get_rec(pcur);
  175. ut_ad(rec_offs_validate(rec, index, offsets));
  176. heap = mem_heap_create(500);
  177. entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
  178. &n_ext, heap);
  179. mtr_commit(mtr);
  180. mtr_start(mtr);
  181. if (trx->dict_operation_lock_mode == 0) {
  182. got_s_lock = TRUE;
  183. row_mysql_freeze_data_dictionary(trx);
  184. }
  185. foreign = UT_LIST_GET_FIRST(table->referenced_list);
  186. while (foreign) {
  187. /* Note that we may have an update which updates the index
  188. record, but does NOT update the first fields which are
  189. referenced in a foreign key constraint. Then the update does
  190. NOT break the constraint. */
  191. if (foreign->referenced_index == index
  192. && (node->is_delete
  193. || row_upd_changes_first_fields_binary(
  194. entry, index, node->update,
  195. foreign->n_fields))) {
  196. if (foreign->foreign_table == NULL) {
  197. dict_table_get(foreign->foreign_table_name_lookup,
  198. FALSE,
  199. DICT_ERR_IGNORE_NONE);
  200. }
  201. if (foreign->foreign_table) {
  202. mutex_enter(&(dict_sys->mutex));
  203. (foreign->foreign_table
  204. ->n_foreign_key_checks_running)++;
  205. mutex_exit(&(dict_sys->mutex));
  206. }
  207. /* NOTE that if the thread ends up waiting for a lock
  208. we will release dict_operation_lock temporarily!
  209. But the counter on the table protects 'foreign' from
  210. being dropped while the check is running. */
  211. err = row_ins_check_foreign_constraint(
  212. FALSE, foreign, table, entry, thr);
  213. if (foreign->foreign_table) {
  214. mutex_enter(&(dict_sys->mutex));
  215. ut_a(foreign->foreign_table
  216. ->n_foreign_key_checks_running > 0);
  217. (foreign->foreign_table
  218. ->n_foreign_key_checks_running)--;
  219. mutex_exit(&(dict_sys->mutex));
  220. }
  221. if (err != DB_SUCCESS) {
  222. goto func_exit;
  223. }
  224. }
  225. foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
  226. }
  227. err = DB_SUCCESS;
  228. func_exit:
  229. if (got_s_lock) {
  230. row_mysql_unfreeze_data_dictionary(trx);
  231. }
  232. mem_heap_free(heap);
  233. return(err);
  234. }
  235. /*********************************************************************//**
  236. Creates an update node for a query graph.
  237. @return own: update node */
  238. UNIV_INTERN
  239. upd_node_t*
  240. upd_node_create(
  241. /*============*/
  242. mem_heap_t* heap) /*!< in: mem heap where created */
  243. {
  244. upd_node_t* node;
  245. node = mem_heap_alloc(heap, sizeof(upd_node_t));
  246. node->common.type = QUE_NODE_UPDATE;
  247. node->state = UPD_NODE_UPDATE_CLUSTERED;
  248. node->in_mysql_interface = FALSE;
  249. node->row = NULL;
  250. node->ext = NULL;
  251. node->upd_row = NULL;
  252. node->upd_ext = NULL;
  253. node->index = NULL;
  254. node->update = NULL;
  255. node->foreign = NULL;
  256. node->cascade_heap = NULL;
  257. node->cascade_node = NULL;
  258. node->select = NULL;
  259. node->heap = mem_heap_create(128);
  260. node->magic_n = UPD_NODE_MAGIC_N;
  261. node->cmpl_info = 0;
  262. return(node);
  263. }
  264. #endif /* !UNIV_HOTBACKUP */
  265. /*********************************************************************//**
  266. Updates the trx id and roll ptr field in a clustered index record in database
  267. recovery. */
  268. UNIV_INTERN
  269. void
  270. row_upd_rec_sys_fields_in_recovery(
  271. /*===============================*/
  272. rec_t* rec, /*!< in/out: record */
  273. page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
  274. const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
  275. ulint pos, /*!< in: TRX_ID position in rec */
  276. trx_id_t trx_id, /*!< in: transaction id */
  277. roll_ptr_t roll_ptr)/*!< in: roll ptr of the undo log record */
  278. {
  279. ut_ad(rec_offs_validate(rec, NULL, offsets));
  280. if (UNIV_LIKELY_NULL(page_zip)) {
  281. page_zip_write_trx_id_and_roll_ptr(
  282. page_zip, rec, offsets, pos, trx_id, roll_ptr);
  283. } else {
  284. byte* field;
  285. ulint len;
  286. field = rec_get_nth_field(rec, offsets, pos, &len);
  287. ut_ad(len == DATA_TRX_ID_LEN);
  288. #if DATA_TRX_ID + 1 != DATA_ROLL_PTR
  289. # error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
  290. #endif
  291. trx_write_trx_id(field, trx_id);
  292. trx_write_roll_ptr(field + DATA_TRX_ID_LEN, roll_ptr);
  293. }
  294. }
  295. #ifndef UNIV_HOTBACKUP
  296. /*********************************************************************//**
  297. Sets the trx id or roll ptr field of a clustered index entry. */
  298. UNIV_INTERN
  299. void
  300. row_upd_index_entry_sys_field(
  301. /*==========================*/
  302. dtuple_t* entry, /*!< in/out: index entry, where the memory
  303. buffers for sys fields are already allocated:
  304. the function just copies the new values to
  305. them */
  306. dict_index_t* index, /*!< in: clustered index */
  307. ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
  308. ib_uint64_t val) /*!< in: value to write */
  309. {
  310. dfield_t* dfield;
  311. byte* field;
  312. ulint pos;
  313. ut_ad(dict_index_is_clust(index));
  314. pos = dict_index_get_sys_col_pos(index, type);
  315. dfield = dtuple_get_nth_field(entry, pos);
  316. field = dfield_get_data(dfield);
  317. if (type == DATA_TRX_ID) {
  318. trx_write_trx_id(field, val);
  319. } else {
  320. ut_ad(type == DATA_ROLL_PTR);
  321. trx_write_roll_ptr(field, val);
  322. }
  323. }
  324. /***********************************************************//**
  325. Returns TRUE if row update changes size of some field in index or if some
  326. field to be updated is stored externally in rec or update.
  327. @return TRUE if the update changes the size of some field in index or
  328. the field is external in rec or update */
  329. UNIV_INTERN
  330. ibool
  331. row_upd_changes_field_size_or_external(
  332. /*===================================*/
  333. dict_index_t* index, /*!< in: index */
  334. const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
  335. const upd_t* update) /*!< in: update vector */
  336. {
  337. const upd_field_t* upd_field;
  338. const dfield_t* new_val;
  339. ulint old_len;
  340. ulint new_len;
  341. ulint n_fields;
  342. ulint i;
  343. ut_ad(rec_offs_validate(NULL, index, offsets));
  344. n_fields = upd_get_n_fields(update);
  345. for (i = 0; i < n_fields; i++) {
  346. upd_field = upd_get_nth_field(update, i);
  347. new_val = &(upd_field->new_val);
  348. new_len = dfield_get_len(new_val);
  349. if (dfield_is_null(new_val) && !rec_offs_comp(offsets)) {
  350. /* A bug fixed on Dec 31st, 2004: we looked at the
  351. SQL NULL size from the wrong field! We may backport
  352. this fix also to 4.0. The merge to 5.0 will be made
  353. manually immediately after we commit this to 4.1. */
  354. new_len = dict_col_get_sql_null_size(
  355. dict_index_get_nth_col(index,
  356. upd_field->field_no),
  357. 0);
  358. }
  359. if (srv_use_sys_stats_table
  360. && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
  361. && upd_field->field_no >= rec_offs_n_fields(offsets)) {
  362. return(TRUE);
  363. }
  364. old_len = rec_offs_nth_size(offsets, upd_field->field_no);
  365. if (rec_offs_comp(offsets)
  366. && rec_offs_nth_sql_null(offsets,
  367. upd_field->field_no)) {
  368. /* Note that in the compact table format, for a
  369. variable length field, an SQL NULL will use zero
  370. bytes in the offset array at the start of the physical
  371. record, but a zero-length value (empty string) will
  372. use one byte! Thus, we cannot use update-in-place
  373. if we update an SQL NULL varchar to an empty string! */
  374. old_len = UNIV_SQL_NULL;
  375. }
  376. if (dfield_is_ext(new_val) || old_len != new_len
  377. || rec_offs_nth_extern(offsets, upd_field->field_no)) {
  378. return(TRUE);
  379. }
  380. }
  381. return(FALSE);
  382. }
  383. #endif /* !UNIV_HOTBACKUP */
  384. /***********************************************************//**
  385. Replaces the new column values stored in the update vector to the
  386. record given. No field size changes are allowed. This function is
  387. usually invoked on a clustered index. The only use case for a
  388. secondary index is row_ins_sec_index_entry_by_modify() or its
  389. counterpart in ibuf_insert_to_index_page(). */
  390. UNIV_INTERN
  391. void
  392. row_upd_rec_in_place(
  393. /*=================*/
  394. rec_t* rec, /*!< in/out: record where replaced */
  395. dict_index_t* index, /*!< in: the index the record belongs to */
  396. const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
  397. const upd_t* update, /*!< in: update vector */
  398. page_zip_des_t* page_zip)/*!< in: compressed page with enough space
  399. available, or NULL */
  400. {
  401. const upd_field_t* upd_field;
  402. const dfield_t* new_val;
  403. ulint n_fields;
  404. ulint i;
  405. ut_ad(rec_offs_validate(rec, index, offsets));
  406. if (rec_offs_comp(offsets)) {
  407. rec_set_info_bits_new(rec, update->info_bits);
  408. } else {
  409. rec_set_info_bits_old(rec, update->info_bits);
  410. }
  411. n_fields = upd_get_n_fields(update);
  412. for (i = 0; i < n_fields; i++) {
  413. #ifdef UNIV_BLOB_DEBUG
  414. btr_blob_dbg_t b;
  415. const byte* field_ref = NULL;
  416. #endif /* UNIV_BLOB_DEBUG */
  417. upd_field = upd_get_nth_field(update, i);
  418. new_val = &(upd_field->new_val);
  419. ut_ad(!dfield_is_ext(new_val) ==
  420. !rec_offs_nth_extern(offsets, upd_field->field_no));
  421. #ifdef UNIV_BLOB_DEBUG
  422. if (dfield_is_ext(new_val)) {
  423. ulint len;
  424. field_ref = rec_get_nth_field(rec, offsets, i, &len);
  425. ut_a(len != UNIV_SQL_NULL);
  426. ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
  427. field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
  428. b.ref_page_no = page_get_page_no(page_align(rec));
  429. b.ref_heap_no = page_rec_get_heap_no(rec);
  430. b.ref_field_no = i;
  431. b.blob_page_no = mach_read_from_4(
  432. field_ref + BTR_EXTERN_PAGE_NO);
  433. ut_a(b.ref_field_no >= index->n_uniq);
  434. btr_blob_dbg_rbt_delete(index, &b, "upd_in_place");
  435. }
  436. #endif /* UNIV_BLOB_DEBUG */
  437. rec_set_nth_field(rec, offsets, upd_field->field_no,
  438. dfield_get_data(new_val),
  439. dfield_get_len(new_val));
  440. #ifdef UNIV_BLOB_DEBUG
  441. if (dfield_is_ext(new_val)) {
  442. b.blob_page_no = mach_read_from_4(
  443. field_ref + BTR_EXTERN_PAGE_NO);
  444. b.always_owner = b.owner = !(field_ref[BTR_EXTERN_LEN]
  445. & BTR_EXTERN_OWNER_FLAG);
  446. b.del = rec_get_deleted_flag(
  447. rec, rec_offs_comp(offsets));
  448. btr_blob_dbg_rbt_insert(index, &b, "upd_in_place");
  449. }
  450. #endif /* UNIV_BLOB_DEBUG */
  451. }
  452. if (UNIV_LIKELY_NULL(page_zip)) {
  453. page_zip_write_rec(page_zip, rec, index, offsets, 0);
  454. }
  455. }
  456. #ifndef UNIV_HOTBACKUP
  457. /*********************************************************************//**
  458. Writes into the redo log the values of trx id and roll ptr and enough info
  459. to determine their positions within a clustered index record.
  460. @return new pointer to mlog */
  461. UNIV_INTERN
  462. byte*
  463. row_upd_write_sys_vals_to_log(
  464. /*==========================*/
  465. dict_index_t* index, /*!< in: clustered index */
  466. trx_t* trx, /*!< in: transaction */
  467. roll_ptr_t roll_ptr,/*!< in: roll ptr of the undo log record */
  468. byte* log_ptr,/*!< pointer to a buffer of size > 20 opened
  469. in mlog */
  470. mtr_t* mtr __attribute__((unused))) /*!< in: mtr */
  471. {
  472. ut_ad(dict_index_is_clust(index));
  473. ut_ad(mtr);
  474. log_ptr += mach_write_compressed(log_ptr,
  475. dict_index_get_sys_col_pos(
  476. index, DATA_TRX_ID));
  477. trx_write_roll_ptr(log_ptr, roll_ptr);
  478. log_ptr += DATA_ROLL_PTR_LEN;
  479. log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
  480. return(log_ptr);
  481. }
  482. #endif /* !UNIV_HOTBACKUP */
  483. /*********************************************************************//**
  484. Parses the log data of system field values.
  485. @return log data end or NULL */
  486. UNIV_INTERN
  487. byte*
  488. row_upd_parse_sys_vals(
  489. /*===================*/
  490. byte* ptr, /*!< in: buffer */
  491. byte* end_ptr,/*!< in: buffer end */
  492. ulint* pos, /*!< out: TRX_ID position in record */
  493. trx_id_t* trx_id, /*!< out: trx id */
  494. roll_ptr_t* roll_ptr)/*!< out: roll ptr */
  495. {
  496. ptr = mach_parse_compressed(ptr, end_ptr, pos);
  497. if (ptr == NULL) {
  498. return(NULL);
  499. }
  500. if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
  501. return(NULL);
  502. }
  503. *roll_ptr = trx_read_roll_ptr(ptr);
  504. ptr += DATA_ROLL_PTR_LEN;
  505. ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
  506. return(ptr);
  507. }
  508. #ifndef UNIV_HOTBACKUP
  509. /***********************************************************//**
  510. Writes to the redo log the new values of the fields occurring in the index. */
  511. UNIV_INTERN
  512. void
  513. row_upd_index_write_log(
  514. /*====================*/
  515. const upd_t* update, /*!< in: update vector */
  516. byte* log_ptr,/*!< in: pointer to mlog buffer: must
  517. contain at least MLOG_BUF_MARGIN bytes
  518. of free space; the buffer is closed
  519. within this function */
  520. mtr_t* mtr) /*!< in: mtr into whose log to write */
  521. {
  522. const upd_field_t* upd_field;
  523. const dfield_t* new_val;
  524. ulint len;
  525. ulint n_fields;
  526. byte* buf_end;
  527. ulint i;
  528. n_fields = upd_get_n_fields(update);
  529. buf_end = log_ptr + MLOG_BUF_MARGIN;
  530. mach_write_to_1(log_ptr, update->info_bits);
  531. log_ptr++;
  532. log_ptr += mach_write_compressed(log_ptr, n_fields);
  533. for (i = 0; i < n_fields; i++) {
  534. #if MLOG_BUF_MARGIN <= 30
  535. # error "MLOG_BUF_MARGIN <= 30"
  536. #endif
  537. if (log_ptr + 30 > buf_end) {
  538. mlog_close(mtr, log_ptr);
  539. log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
  540. buf_end = log_ptr + MLOG_BUF_MARGIN;
  541. }
  542. upd_field = upd_get_nth_field(update, i);
  543. new_val = &(upd_field->new_val);
  544. len = dfield_get_len(new_val);
  545. log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
  546. log_ptr += mach_write_compressed(log_ptr, len);
  547. if (len != UNIV_SQL_NULL) {
  548. if (log_ptr + len < buf_end) {
  549. memcpy(log_ptr, dfield_get_data(new_val), len);
  550. log_ptr += len;
  551. } else {
  552. mlog_close(mtr, log_ptr);
  553. mlog_catenate_string(mtr,
  554. dfield_get_data(new_val),
  555. len);
  556. log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
  557. buf_end = log_ptr + MLOG_BUF_MARGIN;
  558. }
  559. }
  560. }
  561. mlog_close(mtr, log_ptr);
  562. }
  563. #endif /* !UNIV_HOTBACKUP */
  564. /*********************************************************************//**
  565. Parses the log data written by row_upd_index_write_log.
  566. @return log data end or NULL */
  567. UNIV_INTERN
  568. byte*
  569. row_upd_index_parse(
  570. /*================*/
  571. byte* ptr, /*!< in: buffer */
  572. byte* end_ptr,/*!< in: buffer end */
  573. mem_heap_t* heap, /*!< in: memory heap where update vector is
  574. built */
  575. upd_t** update_out)/*!< out: update vector */
  576. {
  577. upd_t* update;
  578. upd_field_t* upd_field;
  579. dfield_t* new_val;
  580. ulint len;
  581. ulint n_fields;
  582. ulint info_bits;
  583. ulint i;
  584. if (end_ptr < ptr + 1) {
  585. return(NULL);
  586. }
  587. info_bits = mach_read_from_1(ptr);
  588. ptr++;
  589. ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
  590. if (ptr == NULL) {
  591. return(NULL);
  592. }
  593. update = upd_create(n_fields, heap);
  594. update->info_bits = info_bits;
  595. for (i = 0; i < n_fields; i++) {
  596. ulint field_no;
  597. upd_field = upd_get_nth_field(update, i);
  598. new_val = &(upd_field->new_val);
  599. ptr = mach_parse_compressed(ptr, end_ptr, &field_no);
  600. if (ptr == NULL) {
  601. return(NULL);
  602. }
  603. upd_field->field_no = field_no;
  604. ptr = mach_parse_compressed(ptr, end_ptr, &len);
  605. if (ptr == NULL) {
  606. return(NULL);
  607. }
  608. if (len != UNIV_SQL_NULL) {
  609. if (end_ptr < ptr + len) {
  610. return(NULL);
  611. }
  612. dfield_set_data(new_val,
  613. mem_heap_dup(heap, ptr, len), len);
  614. ptr += len;
  615. } else {
  616. dfield_set_null(new_val);
  617. }
  618. }
  619. *update_out = update;
  620. return(ptr);
  621. }
  622. #ifndef UNIV_HOTBACKUP
  623. /***************************************************************//**
  624. Builds an update vector from those fields which in a secondary index entry
  625. differ from a record that has the equal ordering fields. NOTE: we compare
  626. the fields as binary strings!
  627. @return own: update vector of differing fields */
  628. UNIV_INTERN
  629. upd_t*
  630. row_upd_build_sec_rec_difference_binary(
  631. /*====================================*/
  632. dict_index_t* index, /*!< in: index */
  633. const dtuple_t* entry, /*!< in: entry to insert */
  634. const rec_t* rec, /*!< in: secondary index record */
  635. trx_t* trx, /*!< in: transaction */
  636. mem_heap_t* heap) /*!< in: memory heap from which allocated */
  637. {
  638. upd_field_t* upd_field;
  639. const dfield_t* dfield;
  640. const byte* data;
  641. ulint len;
  642. upd_t* update;
  643. ulint n_diff;
  644. ulint i;
  645. ulint offsets_[REC_OFFS_SMALL_SIZE];
  646. const ulint* offsets;
  647. rec_offs_init(offsets_);
  648. /* This function is used only for a secondary index */
  649. ut_a(!dict_index_is_clust(index));
  650. update = upd_create(dtuple_get_n_fields(entry), heap);
  651. n_diff = 0;
  652. offsets = rec_get_offsets(rec, index, offsets_,
  653. ULINT_UNDEFINED, &heap);
  654. for (i = 0; i < dtuple_get_n_fields(entry); i++) {
  655. data = rec_get_nth_field(rec, offsets, i, &len);
  656. dfield = dtuple_get_nth_field(entry, i);
  657. /* NOTE that it may be that len != dfield_get_len(dfield) if we
  658. are updating in a character set and collation where strings of
  659. different length can be equal in an alphabetical comparison,
  660. and also in the case where we have a column prefix index
  661. and the last characters in the index field are spaces; the
  662. latter case probably caused the assertion failures reported at
  663. row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
  664. /* NOTE: we compare the fields as binary strings!
  665. (No collation) */
  666. if (!dfield_data_is_binary_equal(dfield, len, data)) {
  667. upd_field = upd_get_nth_field(update, n_diff);
  668. dfield_copy(&(upd_field->new_val), dfield);
  669. upd_field_set_field_no(upd_field, i, index, trx);
  670. n_diff++;
  671. }
  672. }
  673. update->n_fields = n_diff;
  674. return(update);
  675. }
  676. /***************************************************************//**
  677. Builds an update vector from those fields, excluding the roll ptr and
  678. trx id fields, which in an index entry differ from a record that has
  679. the equal ordering fields. NOTE: we compare the fields as binary strings!
  680. @return own: update vector of differing fields, excluding roll ptr and
  681. trx id */
  682. UNIV_INTERN
  683. upd_t*
  684. row_upd_build_difference_binary(
  685. /*============================*/
  686. dict_index_t* index, /*!< in: clustered index */
  687. const dtuple_t* entry, /*!< in: entry to insert */
  688. const rec_t* rec, /*!< in: clustered index record */
  689. trx_t* trx, /*!< in: transaction */
  690. mem_heap_t* heap) /*!< in: memory heap from which allocated */
  691. {
  692. upd_field_t* upd_field;
  693. const dfield_t* dfield;
  694. const byte* data;
  695. ulint len;
  696. upd_t* update;
  697. ulint n_diff;
  698. ulint roll_ptr_pos;
  699. ulint trx_id_pos;
  700. ulint i;
  701. ulint offsets_[REC_OFFS_NORMAL_SIZE];
  702. const ulint* offsets;
  703. rec_offs_init(offsets_);
  704. /* This function is used only for a clustered index */
  705. ut_a(dict_index_is_clust(index));
  706. update = upd_create(dtuple_get_n_fields(entry), heap);
  707. n_diff = 0;
  708. roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
  709. trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
  710. offsets = rec_get_offsets(rec, index, offsets_,
  711. ULINT_UNDEFINED, &heap);
  712. for (i = 0; i < dtuple_get_n_fields(entry); i++) {
  713. if (srv_use_sys_stats_table
  714. && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
  715. && i >= rec_offs_n_fields(offsets)) {
  716. dfield = dtuple_get_nth_field(entry, i);
  717. upd_field = upd_get_nth_field(update, n_diff);
  718. dfield_copy(&(upd_field->new_val), dfield);
  719. upd_field_set_field_no(upd_field, i, index, trx);
  720. n_diff++;
  721. goto skip_compare;
  722. }
  723. data = rec_get_nth_field(rec, offsets, i, &len);
  724. dfield = dtuple_get_nth_field(entry, i);
  725. /* NOTE: we compare the fields as binary strings!
  726. (No collation) */
  727. if (i == trx_id_pos || i == roll_ptr_pos) {
  728. goto skip_compare;
  729. }
  730. if (UNIV_UNLIKELY(!dfield_is_ext(dfield)
  731. != !rec_offs_nth_extern(offsets, i))
  732. || !dfield_data_is_binary_equal(dfield, len, data)) {
  733. upd_field = upd_get_nth_field(update, n_diff);
  734. dfield_copy(&(upd_field->new_val), dfield);
  735. upd_field_set_field_no(upd_field, i, index, trx);
  736. n_diff++;
  737. }
  738. skip_compare:
  739. ;
  740. }
  741. update->n_fields = n_diff;
  742. return(update);
  743. }
  744. /***********************************************************//**
  745. Fetch a prefix of an externally stored column. This is similar
  746. to row_ext_lookup(), but the row_ext_t holds the old values
  747. of the column and must not be poisoned with the new values.
  748. @return BLOB prefix */
  749. static
  750. byte*
  751. row_upd_ext_fetch(
  752. /*==============*/
  753. const byte* data, /*!< in: 'internally' stored part of the
  754. field containing also the reference to
  755. the external part */
  756. ulint local_len, /*!< in: length of data, in bytes */
  757. ulint zip_size, /*!< in: nonzero=compressed BLOB
  758. page size, zero for uncompressed
  759. BLOBs */
  760. ulint* len, /*!< in: length of prefix to fetch;
  761. out: fetched length of the prefix */
  762. mem_heap_t* heap) /*!< in: heap where to allocate */
  763. {
  764. byte* buf = mem_heap_alloc(heap, *len);
  765. *len = btr_copy_externally_stored_field_prefix(buf, *len,
  766. zip_size,
  767. data, local_len);
  768. /* We should never update records containing a half-deleted BLOB. */
  769. ut_a(*len);
  770. return(buf);
  771. }
  772. /***********************************************************//**
  773. Replaces the new column value stored in the update vector in
  774. the given index entry field. */
  775. static
  776. void
  777. row_upd_index_replace_new_col_val(
  778. /*==============================*/
  779. dfield_t* dfield, /*!< in/out: data field
  780. of the index entry */
  781. const dict_field_t* field, /*!< in: index field */
  782. const dict_col_t* col, /*!< in: field->col */
  783. const upd_field_t* uf, /*!< in: update field */
  784. mem_heap_t* heap, /*!< in: memory heap for allocating
  785. and copying the new value */
  786. ulint zip_size)/*!< in: compressed page
  787. size of the table, or 0 */
  788. {
  789. ulint len;
  790. const byte* data;
  791. dfield_copy_data(dfield, &uf->new_val);
  792. if (dfield_is_null(dfield)) {
  793. return;
  794. }
  795. len = dfield_get_len(dfield);
  796. data = dfield_get_data(dfield);
  797. if (field->prefix_len > 0) {
  798. ibool fetch_ext = dfield_is_ext(dfield)
  799. && len < (ulint) field->prefix_len
  800. + BTR_EXTERN_FIELD_REF_SIZE;
  801. if (fetch_ext) {
  802. ulint l = len;
  803. len = field->prefix_len;
  804. data = row_upd_ext_fetch(data, l, zip_size,
  805. &len, heap);
  806. }
  807. len = dtype_get_at_most_n_mbchars(col->prtype,
  808. col->mbminmaxlen,
  809. field->prefix_len, len,
  810. (const char*) data);
  811. dfield_set_data(dfield, data, len);
  812. if (!fetch_ext) {
  813. dfield_dup(dfield, heap);
  814. }
  815. return;
  816. }
  817. switch (uf->orig_len) {
  818. byte* buf;
  819. case BTR_EXTERN_FIELD_REF_SIZE:
  820. /* Restore the original locally stored
  821. part of the column. In the undo log,
  822. InnoDB writes a longer prefix of externally
  823. stored columns, so that column prefixes
  824. in secondary indexes can be reconstructed. */
  825. dfield_set_data(dfield,
  826. data + len - BTR_EXTERN_FIELD_REF_SIZE,
  827. BTR_EXTERN_FIELD_REF_SIZE);
  828. dfield_set_ext(dfield);
  829. /* fall through */
  830. case 0:
  831. dfield_dup(dfield, heap);
  832. break;
  833. default:
  834. /* Reconstruct the original locally
  835. stored part of the column. The data
  836. will have to be copied. */
  837. ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
  838. buf = mem_heap_alloc(heap, uf->orig_len);
  839. /* Copy the locally stored prefix. */
  840. memcpy(buf, data,
  841. uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE);
  842. /* Copy the BLOB pointer. */
  843. memcpy(buf + uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE,
  844. data + len - BTR_EXTERN_FIELD_REF_SIZE,
  845. BTR_EXTERN_FIELD_REF_SIZE);
  846. dfield_set_data(dfield, buf, uf->orig_len);
  847. dfield_set_ext(dfield);
  848. break;
  849. }
  850. }
  851. /***********************************************************//**
  852. Replaces the new column values stored in the update vector to the index entry
  853. given. */
  854. UNIV_INTERN
  855. void
  856. row_upd_index_replace_new_col_vals_index_pos(
  857. /*=========================================*/
  858. dtuple_t* entry, /*!< in/out: index entry where replaced;
  859. the clustered index record must be
  860. covered by a lock or a page latch to
  861. prevent deletion (rollback or purge) */
  862. dict_index_t* index, /*!< in: index; NOTE that this may also be a
  863. non-clustered index */
  864. const upd_t* update, /*!< in: an update vector built for the index so
  865. that the field number in an upd_field is the
  866. index position */
  867. ibool order_only,
  868. /*!< in: if TRUE, limit the replacement to
  869. ordering fields of index; note that this
  870. does not work for non-clustered indexes. */
  871. mem_heap_t* heap) /*!< in: memory heap for allocating and
  872. copying the new values */
  873. {
  874. ulint i;
  875. ulint n_fields;
  876. const ulint zip_size = dict_table_zip_size(index->table);
  877. ut_ad(index);
  878. dtuple_set_info_bits(entry, update->info_bits);
  879. if (order_only) {
  880. n_fields = dict_index_get_n_unique(index);
  881. } else {
  882. n_fields = dict_index_get_n_fields(index);
  883. }
  884. for (i = 0; i < n_fields; i++) {
  885. const dict_field_t* field;
  886. const dict_col_t* col;
  887. const upd_field_t* uf;
  888. field = dict_index_get_nth_field(index, i);
  889. col = dict_field_get_col(field);
  890. uf = upd_get_field_by_field_no(update, i);
  891. if (uf) {
  892. row_upd_index_replace_new_col_val(
  893. dtuple_get_nth_field(entry, i),
  894. field, col, uf, heap, zip_size);
  895. }
  896. }
  897. }
  898. /***********************************************************//**
  899. Replaces the new column values stored in the update vector to the index entry
  900. given. */
  901. UNIV_INTERN
  902. void
  903. row_upd_index_replace_new_col_vals(
  904. /*===============================*/
  905. dtuple_t* entry, /*!< in/out: index entry where replaced;
  906. the clustered index record must be
  907. covered by a lock or a page latch to
  908. prevent deletion (rollback or purge) */
  909. dict_index_t* index, /*!< in: index; NOTE that this may also be a
  910. non-clustered index */
  911. const upd_t* update, /*!< in: an update vector built for the
  912. CLUSTERED index so that the field number in
  913. an upd_field is the clustered index position */
  914. mem_heap_t* heap) /*!< in: memory heap for allocating and
  915. copying the new values */
  916. {
  917. ulint i;
  918. const dict_index_t* clust_index
  919. = dict_table_get_first_index(index->table);
  920. const ulint zip_size
  921. = dict_table_zip_size(index->table);
  922. dtuple_set_info_bits(entry, update->info_bits);
  923. for (i = 0; i < dict_index_get_n_fields(index); i++) {
  924. const dict_field_t* field;
  925. const dict_col_t* col;
  926. const upd_field_t* uf;
  927. field = dict_index_get_nth_field(index, i);
  928. col = dict_field_get_col(field);
  929. uf = upd_get_field_by_field_no(
  930. update, dict_col_get_clust_pos(col, clust_index));
  931. if (uf) {
  932. row_upd_index_replace_new_col_val(
  933. dtuple_get_nth_field(entry, i),
  934. field, col, uf, heap, zip_size);
  935. }
  936. }
  937. }
  938. /***********************************************************//**
  939. Replaces the new column values stored in the update vector. */
  940. UNIV_INTERN
  941. void
  942. row_upd_replace(
  943. /*============*/
  944. dtuple_t* row, /*!< in/out: row where replaced,
  945. indexed by col_no;
  946. the clustered index record must be
  947. covered by a lock or a page latch to
  948. prevent deletion (rollback or purge) */
  949. row_ext_t** ext, /*!< out, own: NULL, or externally
  950. stored column prefixes */
  951. const dict_index_t* index, /*!< in: clustered index */
  952. const upd_t* update, /*!< in: an update vector built for the
  953. clustered index */
  954. mem_heap_t* heap) /*!< in: memory heap */
  955. {
  956. ulint col_no;
  957. ulint i;
  958. ulint n_cols;
  959. ulint n_ext_cols;
  960. ulint* ext_cols;
  961. const dict_table_t* table;
  962. ut_ad(row);
  963. ut_ad(ext);
  964. ut_ad(index);
  965. ut_ad(dict_index_is_clust(index));
  966. ut_ad(update);
  967. ut_ad(heap);
  968. n_cols = dtuple_get_n_fields(row);
  969. table = index->table;
  970. ut_ad(n_cols == dict_table_get_n_cols(table));
  971. ext_cols = mem_heap_alloc(heap, n_cols * sizeof *ext_cols);
  972. n_ext_cols = 0;
  973. dtuple_set_info_bits(row, update->info_bits);
  974. for (col_no = 0; col_no < n_cols; col_no++) {
  975. const dict_col_t* col
  976. = dict_table_get_nth_col(table, col_no);
  977. const ulint clust_pos
  978. = dict_col_get_clust_pos(col, index);
  979. dfield_t* dfield;
  980. if (UNIV_UNLIKELY(clust_pos == ULINT_UNDEFINED)) {
  981. continue;
  982. }
  983. dfield = dtuple_get_nth_field(row, col_no);
  984. for (i = 0; i < upd_get_n_fields(update); i++) {
  985. const upd_field_t* upd_field
  986. = upd_get_nth_field(update, i);
  987. if (upd_field->field_no != clust_pos) {
  988. continue;
  989. }
  990. dfield_copy_data(dfield, &upd_field->new_val);
  991. break;
  992. }
  993. if (dfield_is_ext(dfield) && col->ord_part) {
  994. ext_cols[n_ext_cols++] = col_no;
  995. }
  996. }
  997. if (n_ext_cols) {
  998. *ext = row_ext_create(n_ext_cols, ext_cols, table->flags, row,
  999. heap);
  1000. } else {
  1001. *ext = NULL;
  1002. }
  1003. }
  1004. /***********************************************************//**
  1005. Checks if an update vector changes an ordering field of an index record.
  1006. This function is fast if the update vector is short or the number of ordering
  1007. fields in the index is small. Otherwise, this can be quadratic.
  1008. NOTE: we compare the fields as binary strings!
  1009. @return TRUE if update vector changes an ordering field in the index record */
  1010. UNIV_INTERN
  1011. ibool
  1012. row_upd_changes_ord_field_binary_func(
  1013. /*==================================*/
  1014. dict_index_t* index, /*!< in: index of the record */
  1015. const upd_t* update, /*!< in: update vector for the row; NOTE: the
  1016. field numbers in this MUST be clustered index
  1017. positions! */
  1018. #ifdef UNIV_DEBUG
  1019. const que_thr_t*thr, /*!< in: query thread */
  1020. #endif /* UNIV_DEBUG */
  1021. const dtuple_t* row, /*!< in: old value of row, or NULL if the
  1022. row and the data values in update are not
  1023. known when this function is called, e.g., at
  1024. compile time */
  1025. const row_ext_t*ext) /*!< NULL, or prefixes of the externally
  1026. stored columns in the old row */
  1027. {
  1028. ulint n_unique;
  1029. ulint i;
  1030. const dict_index_t* clust_index;
  1031. ut_ad(index);
  1032. ut_ad(update);
  1033. ut_ad(thr);
  1034. ut_ad(thr->graph);
  1035. ut_ad(thr->graph->trx);
  1036. n_unique = dict_index_get_n_unique(index);
  1037. clust_index = dict_table_get_first_index(index->table);
  1038. for (i = 0; i < n_unique; i++) {
  1039. const dict_field_t* ind_field;
  1040. const dict_col_t* col;
  1041. ulint col_no;
  1042. const upd_field_t* upd_field;
  1043. const dfield_t* dfield;
  1044. dfield_t dfield_ext;
  1045. ulint dfield_len= 0;
  1046. const byte* buf;
  1047. ind_field = dict_index_get_nth_field(index, i);
  1048. col = dict_field_get_col(ind_field);
  1049. col_no = dict_col_get_no(col);
  1050. upd_field = upd_get_field_by_field_no(
  1051. update, dict_col_get_clust_pos(col, clust_index));
  1052. if (upd_field == NULL) {
  1053. continue;
  1054. }
  1055. if (row == NULL) {
  1056. ut_ad(ext == NULL);
  1057. return(TRUE);
  1058. }
  1059. dfield = dtuple_get_nth_field(row, col_no);
  1060. /* This treatment of column prefix indexes is loosely
  1061. based on row_build_index_entry(). */
  1062. if (UNIV_LIKELY(ind_field->prefix_len == 0)
  1063. || dfield_is_null(dfield)) {
  1064. /* do nothing special */
  1065. } else if (UNIV_LIKELY_NULL(ext)) {
  1066. /* Silence a compiler warning without
  1067. silencing a Valgrind error. */
  1068. dfield_len = 0;
  1069. UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len);
  1070. /* See if the column is stored externally. */
  1071. buf = row_ext_lookup(ext, col_no, &dfield_len);
  1072. ut_ad(col->ord_part);
  1073. if (UNIV_LIKELY_NULL(buf)) {
  1074. if (UNIV_UNLIKELY(buf == field_ref_zero)) {
  1075. /* The externally stored field
  1076. was not written yet. This
  1077. record should only be seen by
  1078. recv_recovery_rollback_active(),
  1079. when the server had crashed before
  1080. storing the field. */
  1081. ut_ad(thr->graph->trx->is_recovered);
  1082. ut_ad(trx_is_recv(thr->graph->trx));
  1083. return(TRUE);
  1084. }
  1085. goto copy_dfield;
  1086. }
  1087. } else if (dfield_is_ext(dfield)) {
  1088. dfield_len = dfield_get_len(dfield);
  1089. ut_a(dfield_len > BTR_EXTERN_FIELD_REF_SIZE);
  1090. dfield_len -= BTR_EXTERN_FIELD_REF_SIZE;
  1091. ut_a(dict_index_is_clust(index)
  1092. || ind_field->prefix_len <= dfield_len);
  1093. buf = dfield_get_data(dfield);
  1094. copy_dfield:
  1095. ut_a(dfield_len > 0);
  1096. dfield_copy(&dfield_ext, dfield);
  1097. dfield_set_data(&dfield_ext, buf, dfield_len);
  1098. dfield = &dfield_ext;
  1099. }
  1100. if (!dfield_datas_are_binary_equal(
  1101. dfield, &upd_field->new_val,
  1102. ind_field->prefix_len)) {
  1103. return(TRUE);
  1104. }
  1105. }
  1106. return(FALSE);
  1107. }
  1108. /***********************************************************//**
  1109. Checks if an update vector changes an ordering field of an index record.
  1110. NOTE: we compare the fields as binary strings!
  1111. @return TRUE if update vector may change an ordering field in an index
  1112. record */
  1113. UNIV_INTERN
  1114. ibool
  1115. row_upd_changes_some_index_ord_field_binary(
  1116. /*========================================*/
  1117. const dict_table_t* table, /*!< in: table */
  1118. const upd_t* update) /*!< in: update vector for the row */
  1119. {
  1120. upd_field_t* upd_field;
  1121. dict_index_t* index;
  1122. ulint i;
  1123. index = dict_table_get_first_index(table);
  1124. for (i = 0; i < upd_get_n_fields(update); i++) {
  1125. upd_field = upd_get_nth_field(update, i);
  1126. if (dict_field_get_col(dict_index_get_nth_field(
  1127. index, upd_field->field_no))
  1128. ->ord_part) {
  1129. return(TRUE);
  1130. }
  1131. }
  1132. return(FALSE);
  1133. }
  1134. /***********************************************************//**
  1135. Checks if an update vector changes some of the first ordering fields of an
  1136. index record. This is only used in foreign key checks and we can assume
  1137. that index does not contain column prefixes.
  1138. @return TRUE if changes */
  1139. static
  1140. ibool
  1141. row_upd_changes_first_fields_binary(
  1142. /*================================*/
  1143. dtuple_t* entry, /*!< in: index entry */
  1144. dict_index_t* index, /*!< in: index of entry */
  1145. const upd_t* update, /*!< in: update vector for the row */
  1146. ulint n) /*!< in: how many first fields to check */
  1147. {
  1148. ulint n_upd_fields;
  1149. ulint i, j;
  1150. dict_index_t* clust_index;
  1151. ut_ad(update && index);
  1152. ut_ad(n <= dict_index_get_n_fields(index));
  1153. n_upd_fields = upd_get_n_fields(update);
  1154. clust_index = dict_table_get_first_index(index->table);
  1155. for (i = 0; i < n; i++) {
  1156. const dict_field_t* ind_field;
  1157. const dict_col_t* col;
  1158. ulint col_pos;
  1159. ind_field = dict_index_get_nth_field(index, i);
  1160. col = dict_field_get_col(ind_field);
  1161. col_pos = dict_col_get_clust_pos(col, clust_index);
  1162. ut_a(ind_field->prefix_len == 0);
  1163. for (j = 0; j < n_upd_fields; j++) {
  1164. upd_field_t* upd_field
  1165. = upd_get_nth_field(update, j);
  1166. if (col_pos == upd_field->field_no
  1167. && !dfield_datas_are_binary_equal(
  1168. dtuple_get_nth_field(entry, i),
  1169. &upd_field->new_val, 0)) {
  1170. return(TRUE);
  1171. }
  1172. }
  1173. }
  1174. return(FALSE);
  1175. }
  1176. /*********************************************************************//**
  1177. Copies the column values from a record. */
  1178. UNIV_INLINE
  1179. void
  1180. row_upd_copy_columns(
  1181. /*=================*/
  1182. rec_t* rec, /*!< in: record in a clustered index */
  1183. const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
  1184. sym_node_t* column) /*!< in: first column in a column list, or
  1185. NULL */
  1186. {
  1187. byte* data;
  1188. ulint len;
  1189. while (column) {
  1190. data = rec_get_nth_field(rec, offsets,
  1191. column->field_nos[SYM_CLUST_FIELD_NO],
  1192. &len);
  1193. eval_node_copy_and_alloc_val(column, data, len);
  1194. column = UT_LIST_GET_NEXT(col_var_list, column);
  1195. }
  1196. }
  1197. /*********************************************************************//**
  1198. Calculates the new values for fields to update. Note that row_upd_copy_columns
  1199. must have been called first. */
  1200. UNIV_INLINE
  1201. void
  1202. row_upd_eval_new_vals(
  1203. /*==================*/
  1204. upd_t* update) /*!< in/out: update vector */
  1205. {
  1206. que_node_t* exp;
  1207. upd_field_t* upd_field;
  1208. ulint n_fields;
  1209. ulint i;
  1210. n_fields = upd_get_n_fields(update);
  1211. for (i = 0; i < n_fields; i++) {
  1212. upd_field = upd_get_nth_field(update, i);
  1213. exp = upd_field->exp;
  1214. eval_exp(exp);
  1215. dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
  1216. }
  1217. }
  1218. /***********************************************************//**
  1219. Stores to the heap the row on which the node->pcur is positioned. */
  1220. static
  1221. void
  1222. row_upd_store_row(
  1223. /*==============*/
  1224. upd_node_t* node) /*!< in: row update node */
  1225. {
  1226. dict_index_t* clust_index;
  1227. rec_t* rec;
  1228. mem_heap_t* heap = NULL;
  1229. row_ext_t** ext;
  1230. ulint offsets_[REC_OFFS_NORMAL_SIZE];
  1231. const ulint* offsets;
  1232. rec_offs_init(offsets_);
  1233. ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
  1234. if (node->row != NULL) {
  1235. mem_heap_empty(node->heap);
  1236. }
  1237. clust_index = dict_table_get_first_index(node->table);
  1238. rec = btr_pcur_get_rec(node->pcur);
  1239. offsets = rec_get_offsets(rec, clust_index, offsets_,
  1240. ULINT_UNDEFINED, &heap);
  1241. if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) {
  1242. /* In DYNAMIC or COMPRESSED format, there is no prefix
  1243. of externally stored columns in the clustered index
  1244. record. Build a cache of column prefixes. */
  1245. ext = &node->ext;
  1246. } else {
  1247. /* REDUNDANT and COMPACT formats store a local
  1248. 768-byte prefix of each externally stored column.
  1249. No cache is needed. */
  1250. ext = NULL;
  1251. node->ext = NULL;
  1252. }
  1253. node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
  1254. NULL, ext, node->heap);
  1255. if (node->is_delete) {
  1256. node->upd_row = NULL;
  1257. node->upd_ext = NULL;
  1258. } else {
  1259. node->upd_row = dtuple_copy(node->row, node->heap);
  1260. row_upd_replace(node->upd_row, &node->upd_ext,
  1261. clust_index, node->update, node->heap);
  1262. }
  1263. if (UNIV_LIKELY_NULL(heap)) {
  1264. mem_heap_free(heap);
  1265. }
  1266. }
  1267. /***********************************************************//**
  1268. Updates a secondary index entry of a row.
  1269. @return DB_SUCCESS if operation successfully completed, else error
  1270. code or DB_LOCK_WAIT */
  1271. static
  1272. ulint
  1273. row_upd_sec_index_entry(
  1274. /*====================*/
  1275. upd_node_t* node, /*!< in: row update node */
  1276. que_thr_t* thr) /*!< in: query thread */
  1277. {
  1278. mtr_t mtr;
  1279. const rec_t* rec;
  1280. btr_pcur_t pcur;
  1281. mem_heap_t* heap;
  1282. dtuple_t* entry;
  1283. dict_index_t* index;
  1284. btr_cur_t* btr_cur;
  1285. ibool referenced;
  1286. ulint err = DB_SUCCESS;
  1287. trx_t* trx = thr_get_trx(thr);
  1288. ulint mode = BTR_MODIFY_LEAF;
  1289. enum row_search_result search_result;
  1290. index = node->index;
  1291. referenced = row_upd_index_is_referenced(index, trx);
  1292. heap = mem_heap_create(1024);
  1293. /* Build old index entry */
  1294. entry = row_build_index_entry(node->row, node->ext, index, heap);
  1295. ut_a(entry);
  1296. mtr_start(&mtr);
  1297. /* Set the query thread, so that ibuf_insert_low() will be
  1298. able to invoke thd_get_trx(). */
  1299. btr_pcur_get_btr_cur(&pcur)->thr = thr;
  1300. /* We can only try to use the insert/delete buffer to buffer
  1301. delete-mark operations if the index we're modifying has no foreign
  1302. key constraints referring to it. */
  1303. if (!referenced) {
  1304. mode |= BTR_DELETE_MARK;
  1305. }
  1306. search_result = row_search_index_entry(index, entry,
  1307. UNIV_UNLIKELY(trx->fake_changes)
  1308. ? BTR_SEARCH_LEAF : mode,
  1309. &pcur, &mtr);
  1310. btr_cur = btr_pcur_get_btr_cur(&pcur);
  1311. rec = btr_cur_get_rec(btr_cur);
  1312. switch (search_result) {
  1313. case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
  1314. ut_error;
  1315. break;
  1316. case ROW_BUFFERED:
  1317. /* Entry was delete marked already. */
  1318. break;
  1319. case ROW_NOT_FOUND:
  1320. fputs("InnoDB: error in sec index entry update in\n"
  1321. "InnoDB: ", stderr);
  1322. dict_index_name_print(stderr, trx, index);
  1323. fputs("\n"
  1324. "InnoDB: tuple ", stderr);
  1325. dtuple_print(stderr, entry);
  1326. fputs("\n"
  1327. "InnoDB: record ", stderr);
  1328. rec_print(stderr, rec, index);
  1329. putc('\n', stderr);
  1330. trx_print(stderr, trx, 0);
  1331. fputs("\n"
  1332. "InnoDB: Submit a detailed bug report"
  1333. " to http://bugs.mysql.com\n", stderr);
  1334. ut_ad(0);
  1335. break;
  1336. case ROW_FOUND:
  1337. /* Delete mark the old index record; it can already be
  1338. delete marked if we return after a lock wait in
  1339. row_ins_index_entry below */
  1340. if (!rec_get_deleted_flag(
  1341. rec, dict_table_is_comp(index->table))) {
  1342. err = btr_cur_del_mark_set_sec_rec(
  1343. 0, btr_cur, TRUE, thr, &mtr);
  1344. if (err == DB_SUCCESS && referenced) {
  1345. ulint* offsets;
  1346. offsets = rec_get_offsets(
  1347. rec, index, NULL, ULINT_UNDEFINED,
  1348. &heap);
  1349. /* NOTE that the following call loses
  1350. the position of pcur ! */
  1351. err = row_upd_check_references_constraints(
  1352. node, &pcur, index->table,
  1353. index, offsets, thr, &mtr);
  1354. }
  1355. }
  1356. break;
  1357. }
  1358. btr_pcur_close(&pcur);
  1359. mtr_commit(&mtr);
  1360. if (node->is_delete || err != DB_SUCCESS) {
  1361. goto func_exit;
  1362. }
  1363. /* Build a new index entry */
  1364. entry = row_build_index_entry(node->upd_row, node->upd_ext,
  1365. index, heap);
  1366. ut_a(entry);
  1367. /* Insert new index entry */
  1368. err = row_ins_index_entry(index, entry, 0, TRUE, thr);
  1369. func_exit:
  1370. mem_heap_free(heap);
  1371. return(err);
  1372. }
  1373. /***********************************************************//**
  1374. Updates the secondary index record if it is changed in the row update or
  1375. deletes it if this is a delete.
  1376. @return DB_SUCCESS if operation successfully completed, else error
  1377. code or DB_LOCK_WAIT */
  1378. static
  1379. ulint
  1380. row_upd_sec_step(
  1381. /*=============*/
  1382. upd_node_t* node, /*!< in: row update node */
  1383. que_thr_t* thr) /*!< in: query thread */
  1384. {
  1385. ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
  1386. || (node->state == UPD_NODE_UPDATE_SOME_SEC));
  1387. ut_ad(!dict_index_is_clust(node->index));
  1388. if (node->state == UPD_NODE_UPDATE_ALL_SEC
  1389. || row_upd_changes_ord_field_binary(node->index, node->update,
  1390. thr, node->row, node->ext)) {
  1391. return(row_upd_sec_index_entry(node, thr));
  1392. }
  1393. return(DB_SUCCESS);
  1394. }
  1395. #ifdef UNIV_DEBUG
  1396. # define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
  1397. row_upd_clust_rec_by_insert_inherit_func(rec,offsets,entry,update)
  1398. #else /* UNIV_DEBUG */
  1399. # define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
  1400. row_upd_clust_rec_by_insert_inherit_func(entry,update)
  1401. #endif /* UNIV_DEBUG */
  1402. /*******************************************************************//**
  1403. Mark non-updated off-page columns inherited when the primary key is
  1404. updated. We must mark them as inherited in entry, so that they are not
  1405. freed in a rollback. A limited version of this function used to be
  1406. called btr_cur_mark_dtuple_inherited_extern().
  1407. @return TRUE if any columns were inherited */
  1408. static __attribute__((warn_unused_result))
  1409. ibool
  1410. row_upd_clust_rec_by_insert_inherit_func(
  1411. /*=====================================*/
  1412. #ifdef UNIV_DEBUG
  1413. const rec_t* rec, /*!< in: old record, or NULL */
  1414. const ulint* offsets,/*!< in: rec_get_offsets(rec), or NULL */
  1415. #endif /* UNIV_DEBUG */
  1416. dtuple_t* entry, /*!< in/out: updated entry to be
  1417. inserted into the clustered index */
  1418. const upd_t* update) /*!< in: update vector */
  1419. {
  1420. ibool inherit = FALSE;
  1421. ulint i;
  1422. ut_ad(!rec == !offsets);
  1423. ut_ad(!rec || rec_offs_any_extern(offsets));
  1424. for (i = 0; i < dtuple_get_n_fields(entry); i++) {
  1425. dfield_t* dfield = dtuple_get_nth_field(entry, i);
  1426. byte* data;
  1427. ulint len;
  1428. ut_ad(!offsets
  1429. || !rec_offs_nth_extern(offsets, i)
  1430. == !dfield_is_ext(dfield)
  1431. || upd_get_field_by_field_no(update, i));
  1432. if (!dfield_is_ext(dfield)
  1433. || upd_get_field_by_field_no(update, i)) {
  1434. continue;
  1435. }
  1436. #ifdef UNIV_DEBUG
  1437. if (UNIV_LIKELY(rec != NULL)) {
  1438. const byte* rec_data
  1439. = rec_get_nth_field(rec, offsets, i, &len);
  1440. ut_ad(len == dfield_get_len(dfield));
  1441. ut_ad(len != UNIV_SQL_NULL);
  1442. ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
  1443. rec_data += len - BTR_EXTERN_FIELD_REF_SIZE;
  1444. /* The pointer must not be zero. */
  1445. ut_ad(memcmp(rec_data, field_ref_zero,
  1446. BTR_EXTERN_FIELD_REF_SIZE));
  1447. /* The BLOB must be owned. */
  1448. ut_ad(!(rec_data[BTR_EXTERN_LEN]
  1449. & BTR_EXTERN_OWNER_FLAG));
  1450. }
  1451. #endif /* UNIV_DEBUG */
  1452. len = dfield_get_len(dfield);
  1453. ut_a(len != UNIV_SQL_NULL);
  1454. ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
  1455. data = dfield_get_data(dfield);
  1456. data += len - BTR_EXTERN_FIELD_REF_SIZE;
  1457. /* The pointer must not be zero. */
  1458. ut_a(memcmp(data, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE));
  1459. data[BTR_EXTERN_LEN] &= ~BTR_EXTERN_OWNER_FLAG;
  1460. data[BTR_EXTERN_LEN] |= BTR_EXTERN_INHERITED_FLAG;
  1461. /* The BTR_EXTERN_INHERITED_FLAG only matters in
  1462. rollback. Purge will always free the extern fields of
  1463. a delete-marked row. */
  1464. inherit = TRUE;
  1465. }
  1466. return(inherit);
  1467. }
  1468. /***********************************************************//**
  1469. Marks the clustered index record deleted and inserts the updated version
  1470. of the record to the index. This function should be used when the ordering
  1471. fields of the clustered index record change. This should be quite rare in
  1472. database applications.
  1473. @return DB_SUCCESS if operation successfully completed, else error
  1474. code or DB_LOCK_WAIT */
  1475. static
  1476. ulint
  1477. row_upd_clust_rec_by_insert(
  1478. /*========================*/
  1479. upd_node_t* node, /*!< in/out: row update node */
  1480. dict_index_t* index, /*!< in: clustered index of the record */
  1481. que_thr_t* thr, /*!< in: query thread */
  1482. ibool referenced,/*!< in: TRUE if index may be referenced in
  1483. a foreign key constraint */
  1484. mtr_t* mtr) /*!< in/out: mtr; gets committed here */
  1485. {
  1486. mem_heap_t* heap;
  1487. btr_pcur_t* pcur;
  1488. btr_cur_t* btr_cur;
  1489. trx_t* trx;
  1490. dict_table_t* table;
  1491. dtuple_t* entry;
  1492. ulint err;
  1493. ibool change_ownership = FALSE;
  1494. rec_t* rec;
  1495. ulint* offsets = NULL;
  1496. ut_ad(node);
  1497. ut_ad(dict_index_is_clust(index));
  1498. trx = thr_get_trx(thr);
  1499. table = node->table;
  1500. pcur = node->pcur;
  1501. btr_cur = btr_pcur_get_btr_cur(pcur);
  1502. heap = mem_heap_create(1000);
  1503. entry = row_build_index_entry(node->upd_row, node->upd_ext,
  1504. index, heap);
  1505. ut_a(entry);
  1506. row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
  1507. switch (node->state) {
  1508. default:
  1509. ut_error;
  1510. case UPD_NODE_INSERT_BLOB:
  1511. /* A lock wait occurred in row_ins_index_entry() in
  1512. the previous invocation of this function. Mark the
  1513. off-page columns in the entry inherited. */
  1514. if (UNIV_LIKELY(!trx->fake_changes)) {
  1515. change_ownership = row_upd_clust_rec_by_insert_inherit(
  1516. NULL, NULL, entry, node->update);
  1517. ut_a(change_ownership);
  1518. }
  1519. /* fall through */
  1520. case UPD_NODE_INSERT_CLUSTERED:
  1521. /* A lock wait occurred in row_ins_index_entry() in
  1522. the previous invocation of this function. */
  1523. break;
  1524. case UPD_NODE_UPDATE_CLUSTERED:
  1525. /* This is the first invocation of the function where
  1526. we update the primary key. Delete-mark the old record
  1527. in the clustered index and prepare to insert a new entry. */
  1528. rec = btr_cur_get_rec(btr_cur);
  1529. offsets = rec_get_offsets(rec, index, NULL,
  1530. ULINT_UNDEFINED, &heap);
  1531. ut_ad(page_rec_is_user_rec(rec));
  1532. err = btr_cur_del_mark_set_clust_rec(
  1533. BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
  1534. rec, index, offsets, TRUE, thr, mtr);
  1535. if (err != DB_SUCCESS) {
  1536. err_exit:
  1537. mtr_commit(mtr);
  1538. mem_heap_free(heap);
  1539. return(err);
  1540. }
  1541. /* If the the new row inherits externally stored
  1542. fields (off-page columns a.k.a. BLOBs) from the
  1543. delete-marked old record, mark them disowned by the
  1544. old record and owned by the new entry. */
  1545. if (rec_offs_any_extern(offsets)
  1546. && UNIV_LIKELY(!(trx->fake_changes))) {
  1547. change_ownership = row_upd_clust_rec_by_insert_inherit(
  1548. rec, offsets, entry, node->update);
  1549. if (change_ownership) {
  1550. /* The blobs are disowned here, expecting the
  1551. insert down below to inherit them. But if the
  1552. insert fails, then this disown will be undone
  1553. when the operation is rolled back. */
  1554. btr_cur_disown_inherited_fields(
  1555. btr_cur_get_page_zip(btr_cur),
  1556. rec, index, offsets, node->update, mtr);
  1557. }
  1558. }
  1559. if (referenced) {
  1560. /* NOTE that the following call loses
  1561. the position of pcur ! */
  1562. err = row_upd_check_references_constraints(
  1563. node, pcur, table, index, offsets, thr, mtr);
  1564. if (err != DB_SUCCESS) {
  1565. goto err_exit;
  1566. }
  1567. }
  1568. }
  1569. mtr_commit(mtr);
  1570. err = row_ins_index_entry(index, entry,
  1571. node->upd_ext ? node->upd_ext->n_ext : 0,
  1572. TRUE, thr);
  1573. node->state = change_ownership
  1574. ? UPD_NODE_INSERT_BLOB
  1575. : UPD_NODE_INSERT_CLUSTERED;
  1576. mem_heap_free(heap);
  1577. return(err);
  1578. }
  1579. /***********************************************************//**
  1580. Updates a clustered index record of a row when the ordering fields do
  1581. not change.
  1582. @return DB_SUCCESS if operation successfully completed, else error
  1583. code or DB_LOCK_WAIT */
  1584. static
  1585. ulint
  1586. row_upd_clust_rec(
  1587. /*==============*/
  1588. upd_node_t* node, /*!< in: row update node */
  1589. dict_index_t* index, /*!< in: clustered index */
  1590. que_thr_t* thr, /*!< in: query thread */
  1591. mtr_t* mtr) /*!< in: mtr; gets committed here */
  1592. {
  1593. mem_heap_t* heap = NULL;
  1594. big_rec_t* big_rec = NULL;
  1595. btr_pcur_t* pcur;
  1596. btr_cur_t* btr_cur;
  1597. ulint err;
  1598. ut_ad(node);
  1599. ut_ad(dict_index_is_clust(index));
  1600. pcur = node->pcur;
  1601. btr_cur = btr_pcur_get_btr_cur(pcur);
  1602. ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
  1603. dict_table_is_comp(index->table)));
  1604. /* Try optimistic updating of the record, keeping changes within
  1605. the page; we do not check locks because we assume the x-lock on the
  1606. record to update */
  1607. if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
  1608. err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
  1609. btr_cur, node->update,
  1610. node->cmpl_info, thr, mtr);
  1611. } else {
  1612. err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
  1613. btr_cur, node->update,
  1614. node->cmpl_info, thr, mtr);
  1615. }
  1616. mtr_commit(mtr);
  1617. if (UNIV_LIKELY(err == DB_SUCCESS)) {
  1618. return(DB_SUCCESS);
  1619. }
  1620. if (buf_LRU_buf_pool_running_out()) {
  1621. return(DB_LOCK_TABLE_FULL);
  1622. }
  1623. /* We may have to modify the tree structure: do a pessimistic descent
  1624. down the index tree */
  1625. mtr_start(mtr);
  1626. /* NOTE: this transaction has an s-lock or x-lock on the record and
  1627. therefore other transactions cannot modify the record when we have no
  1628. latch on the page. In addition, we assume that other query threads of
  1629. the same transaction do not modify the record in the meantime.
  1630. Therefore we can assert that the restoration of the cursor succeeds. */
  1631. ut_a(btr_pcur_restore_position(
  1632. (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)
  1633. ? BTR_SEARCH_TREE : BTR_MODIFY_TREE),
  1634. pcur, mtr));
  1635. ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
  1636. dict_table_is_comp(index->table)));
  1637. err = btr_cur_pessimistic_update(
  1638. BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur,
  1639. &heap, &big_rec, node->update,
  1640. node->cmpl_info, thr, mtr);
  1641. /* skip store extern for fake_changes */
  1642. if (err == DB_SUCCESS && big_rec
  1643. && UNIV_LIKELY(!(thr_get_trx(thr)->fake_changes))) {
  1644. ulint offsets_[REC_OFFS_NORMAL_SIZE];
  1645. rec_t* rec;
  1646. rec_offs_init(offsets_);
  1647. ut_a(err == DB_SUCCESS);
  1648. /* Write out the externally stored
  1649. columns while still x-latching
  1650. index->lock and block->lock. Allocate
  1651. pages for big_rec in the mtr that
  1652. modified the B-tree, but be sure to skip
  1653. any pages that were freed in mtr. We will
  1654. write out the big_rec pages before
  1655. committing the B-tree mini-transaction. If
  1656. the system crashes so that crash recovery
  1657. will not replay the mtr_commit(&mtr), the
  1658. big_rec pages will be left orphaned until
  1659. the pages are allocated for something else.
  1660. TODO: If the allocation extends the tablespace, it
  1661. will not be redo logged, in either mini-transaction.
  1662. Tablespace extension should be redo-logged in the
  1663. big_rec mini-transaction, so that recovery will not
  1664. fail when the big_rec was written to the extended
  1665. portion of the file, in case the file was somehow
  1666. truncated in the crash. */
  1667. rec = btr_cur_get_rec(btr_cur);
  1668. DEBUG_SYNC_C("before_row_upd_extern");
  1669. err = btr_store_big_rec_extern_fields(
  1670. index, btr_cur_get_block(btr_cur), rec,
  1671. rec_get_offsets(rec, index, offsets_,
  1672. ULINT_UNDEFINED, &heap),
  1673. big_rec, mtr, BTR_STORE_UPDATE);
  1674. DEBUG_SYNC_C("after_row_upd_extern");
  1675. /* If writing big_rec fails (for example, because of
  1676. DB_OUT_OF_FILE_SPACE), the record will be corrupted.
  1677. Even if we did not update any externally stored
  1678. columns, our update could cause the record to grow so
  1679. that a non-updated column was selected for external
  1680. storage. This non-update would not have been written
  1681. to the undo log, and thus the record cannot be rolled
  1682. back.
  1683. However, because we have not executed mtr_commit(mtr)
  1684. yet, the update will not be replayed in crash
  1685. recovery, and the following assertion failure will
  1686. effectively "roll back" the operation. */
  1687. ut_a(err == DB_SUCCESS);
  1688. }
  1689. mtr_commit(mtr);
  1690. if (UNIV_LIKELY_NULL(heap)) {
  1691. mem_heap_free(heap);
  1692. }
  1693. if (big_rec) {
  1694. dtuple_big_rec_free(big_rec);
  1695. }
  1696. return(err);
  1697. }
  1698. /***********************************************************//**
  1699. Delete marks a clustered index record.
  1700. @return DB_SUCCESS if operation successfully completed, else error code */
  1701. static
  1702. ulint
  1703. row_upd_del_mark_clust_rec(
  1704. /*=======================*/
  1705. upd_node_t* node, /*!< in: row update node */
  1706. dict_index_t* index, /*!< in: clustered index */
  1707. ulint* offsets,/*!< in/out: rec_get_offsets() for the
  1708. record under the cursor */
  1709. que_thr_t* thr, /*!< in: query thread */
  1710. ibool referenced,
  1711. /*!< in: TRUE if index may be referenced in
  1712. a foreign key constraint */
  1713. mtr_t* mtr) /*!< in: mtr; gets committed here */
  1714. {
  1715. btr_pcur_t* pcur;
  1716. btr_cur_t* btr_cur;
  1717. ulint err;
  1718. ut_ad(node);
  1719. ut_ad(dict_index_is_clust(index));
  1720. ut_ad(node->is_delete);
  1721. pcur = node->pcur;
  1722. btr_cur = btr_pcur_get_btr_cur(pcur);
  1723. /* Store row because we have to build also the secondary index
  1724. entries */
  1725. row_upd_store_row(node);
  1726. /* Mark the clustered index record deleted; we do not have to check
  1727. locks, because we assume that we have an x-lock on the record */
  1728. err = btr_cur_del_mark_set_clust_rec(
  1729. BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
  1730. btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
  1731. if (err == DB_SUCCESS && referenced) {
  1732. /* NOTE that the following call loses the position of pcur ! */
  1733. err = row_upd_check_references_constraints(
  1734. node, pcur, index->table, index, offsets, thr, mtr);
  1735. }
  1736. mtr_commit(mtr);
  1737. return(err);
  1738. }
  1739. /***********************************************************//**
  1740. Updates the clustered index record.
  1741. @return DB_SUCCESS if operation successfully completed, DB_LOCK_WAIT
  1742. in case of a lock wait, else error code */
  1743. static
  1744. ulint
  1745. row_upd_clust_step(
  1746. /*===============*/
  1747. upd_node_t* node, /*!< in: row update node */
  1748. que_thr_t* thr) /*!< in: query thread */
  1749. {
  1750. dict_index_t* index;
  1751. btr_pcur_t* pcur;
  1752. ibool success;
  1753. ulint err;
  1754. mtr_t* mtr;
  1755. mtr_t mtr_buf;
  1756. rec_t* rec;
  1757. mem_heap_t* heap = NULL;
  1758. ulint offsets_[REC_OFFS_NORMAL_SIZE];
  1759. ulint* offsets;
  1760. ibool referenced;
  1761. rec_offs_init(offsets_);
  1762. index = dict_table_get_first_index(node->table);
  1763. referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
  1764. pcur = node->pcur;
  1765. /* We have to restore the cursor to its position */
  1766. mtr = &mtr_buf;
  1767. mtr_start(mtr);
  1768. /* If the restoration does not succeed, then the same
  1769. transaction has deleted the record on which the cursor was,
  1770. and that is an SQL error. If the restoration succeeds, it may
  1771. still be that the same transaction has successively deleted
  1772. and inserted a record with the same ordering fields, but in
  1773. that case we know that the transaction has at least an
  1774. implicit x-lock on the record. */
  1775. ut_a(pcur->rel_pos == BTR_PCUR_ON);
  1776. success = btr_pcur_restore_position(
  1777. (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)
  1778. ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF),
  1779. pcur, mtr);
  1780. if (!success) {
  1781. err = DB_RECORD_NOT_FOUND;
  1782. mtr_commit(mtr);
  1783. return(err);
  1784. }
  1785. /* If this is a row in SYS_INDEXES table of the data dictionary,
  1786. then we have to free the file segments of the index tree associated
  1787. with the index */
  1788. if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
  1789. dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
  1790. mtr_commit(mtr);
  1791. mtr_start(mtr);
  1792. success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
  1793. mtr);
  1794. if (!success) {
  1795. err = DB_ERROR;
  1796. mtr_commit(mtr);
  1797. return(err);
  1798. }
  1799. }
  1800. rec = btr_pcur_get_rec(pcur);
  1801. offsets = rec_get_offsets(rec, index, offsets_,
  1802. ULINT_UNDEFINED, &heap);
  1803. if (!node->has_clust_rec_x_lock) {
  1804. err = lock_clust_rec_modify_check_and_lock(
  1805. 0, btr_pcur_get_block(pcur),
  1806. rec, index, offsets, thr);
  1807. if (err != DB_SUCCESS) {
  1808. mtr_commit(mtr);
  1809. goto exit_func;
  1810. }
  1811. }
  1812. /* NOTE: the following function calls will also commit mtr */
  1813. if (node->is_delete) {
  1814. err = row_upd_del_mark_clust_rec(
  1815. node, index, offsets, thr, referenced, mtr);
  1816. if (err == DB_SUCCESS) {
  1817. node->state = UPD_NODE_UPDATE_ALL_SEC;
  1818. node->index = dict_table_get_next_index(index);
  1819. }
  1820. exit_func:
  1821. if (UNIV_LIKELY_NULL(heap)) {
  1822. mem_heap_free(heap);
  1823. }
  1824. return(err);
  1825. }
  1826. /* If the update is made for MySQL, we already have the update vector
  1827. ready, else we have to do some evaluation: */
  1828. if (UNIV_UNLIKELY(!node->in_mysql_interface)) {
  1829. /* Copy the necessary columns from clust_rec and calculate the
  1830. new values to set */
  1831. row_upd_copy_columns(rec, offsets,
  1832. UT_LIST_GET_FIRST(node->columns));
  1833. row_upd_eval_new_vals(node->update);
  1834. }
  1835. if (UNIV_LIKELY_NULL(heap)) {
  1836. mem_heap_free(heap);
  1837. }
  1838. if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
  1839. err = row_upd_clust_rec(node, index, thr, mtr);
  1840. return(err);
  1841. }
  1842. row_upd_store_row(node);
  1843. if (row_upd_changes_ord_field_binary(index, node->update, thr,
  1844. node->row, node->ext)) {
  1845. /* Update causes an ordering field (ordering fields within
  1846. the B-tree) of the clustered index record to change: perform
  1847. the update by delete marking and inserting.
  1848. TODO! What to do to the 'Halloween problem', where an update
  1849. moves the record forward in index so that it is again
  1850. updated when the cursor arrives there? Solution: the
  1851. read operation must check the undo record undo number when
  1852. choosing records to update. MySQL solves now the problem
  1853. externally! */
  1854. err = row_upd_clust_rec_by_insert(
  1855. node, index, thr, referenced, mtr);
  1856. if (err != DB_SUCCESS) {
  1857. return(err);
  1858. }
  1859. node->state = UPD_NODE_UPDATE_ALL_SEC;
  1860. } else {
  1861. err = row_upd_clust_rec(node, index, thr, mtr);
  1862. if (err != DB_SUCCESS) {
  1863. return(err);
  1864. }
  1865. node->state = UPD_NODE_UPDATE_SOME_SEC;
  1866. }
  1867. node->index = dict_table_get_next_index(index);
  1868. return(err);
  1869. }
  1870. /***********************************************************//**
  1871. Updates the affected index records of a row. When the control is transferred
  1872. to this node, we assume that we have a persistent cursor which was on a
  1873. record, and the position of the cursor is stored in the cursor.
  1874. @return DB_SUCCESS if operation successfully completed, else error
  1875. code or DB_LOCK_WAIT */
  1876. static
  1877. ulint
  1878. row_upd(
  1879. /*====*/
  1880. upd_node_t* node, /*!< in: row update node */
  1881. que_thr_t* thr) /*!< in: query thread */
  1882. {
  1883. ulint err = DB_SUCCESS;
  1884. ut_ad(node && thr);
  1885. if (UNIV_LIKELY(node->in_mysql_interface)) {
  1886. /* We do not get the cmpl_info value from the MySQL
  1887. interpreter: we must calculate it on the fly: */
  1888. if (node->is_delete
  1889. || row_upd_changes_some_index_ord_field_binary(
  1890. node->table, node->update)) {
  1891. node->cmpl_info = 0;
  1892. } else {
  1893. node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
  1894. }
  1895. }
  1896. if (node->state == UPD_NODE_UPDATE_CLUSTERED
  1897. || node->state == UPD_NODE_INSERT_CLUSTERED
  1898. || node->state == UPD_NODE_INSERT_BLOB) {
  1899. log_free_check();
  1900. err = row_upd_clust_step(node, thr);
  1901. if (err != DB_SUCCESS) {
  1902. goto function_exit;
  1903. }
  1904. }
  1905. if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
  1906. goto function_exit;
  1907. }
  1908. while (node->index != NULL) {
  1909. /* Skip corrupted index */
  1910. dict_table_skip_corrupt_index(node->index);
  1911. if (!node->index) {
  1912. break;
  1913. }
  1914. log_free_check();
  1915. err = row_upd_sec_step(node, thr);
  1916. if (err != DB_SUCCESS) {
  1917. goto function_exit;
  1918. }
  1919. node->index = dict_table_get_next_index(node->index);
  1920. }
  1921. function_exit:
  1922. if (err == DB_SUCCESS) {
  1923. /* Do some cleanup */
  1924. if (node->row != NULL) {
  1925. node->row = NULL;
  1926. node->ext = NULL;
  1927. node->upd_row = NULL;
  1928. node->upd_ext = NULL;
  1929. mem_heap_empty(node->heap);
  1930. }
  1931. node->state = UPD_NODE_UPDATE_CLUSTERED;
  1932. }
  1933. return(err);
  1934. }
  1935. /***********************************************************//**
  1936. Updates a row in a table. This is a high-level function used in SQL execution
  1937. graphs.
  1938. @return query thread to run next or NULL */
  1939. UNIV_INTERN
  1940. que_thr_t*
  1941. row_upd_step(
  1942. /*=========*/
  1943. que_thr_t* thr) /*!< in: query thread */
  1944. {
  1945. upd_node_t* node;
  1946. sel_node_t* sel_node;
  1947. que_node_t* parent;
  1948. ulint err = DB_SUCCESS;
  1949. trx_t* trx;
  1950. ut_ad(thr);
  1951. trx = thr_get_trx(thr);
  1952. trx_start_if_not_started(trx);
  1953. node = thr->run_node;
  1954. sel_node = node->select;
  1955. parent = que_node_get_parent(node);
  1956. ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
  1957. if (thr->prev_node == parent) {
  1958. node->state = UPD_NODE_SET_IX_LOCK;
  1959. }
  1960. if (node->state == UPD_NODE_SET_IX_LOCK) {
  1961. if (!node->has_clust_rec_x_lock) {
  1962. /* It may be that the current session has not yet
  1963. started its transaction, or it has been committed: */
  1964. err = lock_table(0, node->table, LOCK_IX, thr);
  1965. if (err != DB_SUCCESS) {
  1966. goto error_handling;
  1967. }
  1968. }
  1969. node->state = UPD_NODE_UPDATE_CLUSTERED;
  1970. if (node->searched_update) {
  1971. /* Reset the cursor */
  1972. sel_node->state = SEL_NODE_OPEN;
  1973. /* Fetch a row to update */
  1974. thr->run_node = sel_node;
  1975. return(thr);
  1976. }
  1977. }
  1978. /* sel_node is NULL if we are in the MySQL interface */
  1979. if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
  1980. if (!node->searched_update) {
  1981. /* An explicit cursor should be positioned on a row
  1982. to update */
  1983. ut_error;
  1984. err = DB_ERROR;
  1985. goto error_handling;
  1986. }
  1987. ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
  1988. /* No more rows to update, or the select node performed the
  1989. updates directly in-place */
  1990. thr->run_node = parent;
  1991. return(thr);
  1992. }
  1993. /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
  1994. err = row_upd(node, thr);
  1995. error_handling:
  1996. trx->error_state = err;
  1997. if (err != DB_SUCCESS) {
  1998. return(NULL);
  1999. }
  2000. /* DO THE TRIGGER ACTIONS HERE */
  2001. if (node->searched_update) {
  2002. /* Fetch next row to update */
  2003. thr->run_node = sel_node;
  2004. } else {
  2005. /* It was an explicit cursor update */
  2006. thr->run_node = parent;
  2007. }
  2008. node->state = UPD_NODE_UPDATE_CLUSTERED;
  2009. return(thr);
  2010. }
  2011. #endif /* !UNIV_HOTBACKUP */