📄 row0upd.c
字号:
Therefore we can assert that the restoration of the cursor succeeds. */ ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), index->table->comp)); err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, &big_rec, node->update, node->cmpl_info, thr, mtr); mtr_commit(mtr); if (err == DB_SUCCESS && big_rec) { mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; *offsets_ = (sizeof offsets_) / sizeof *offsets_; mtr_start(mtr); ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields(index, rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), big_rec, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } mtr_commit(mtr); } if (big_rec) { dtuple_big_rec_free(big_rec); } return(err);}/***************************************************************Delete marks a clustered index record. */staticulintrow_upd_del_mark_clust_rec(/*=======================*/ /* out: DB_SUCCESS if operation successfully completed, else error code */ upd_node_t* node, /* in: row update node */ dict_index_t* index, /* in: clustered index */ que_thr_t* thr, /* in: query thread */ ibool check_ref,/* in: TRUE if index may be referenced in a foreign key constraint */ mtr_t* mtr) /* in: mtr; gets committed here */{ btr_pcur_t* pcur; btr_cur_t* btr_cur; ulint err; ut_ad(node); ut_ad(index->type & DICT_CLUSTERED); ut_ad(node->is_delete); pcur = node->pcur; btr_cur = btr_pcur_get_btr_cur(pcur); /* Store row because we have to build also the secondary index entries */ row_upd_store_row(node); /* Mark the clustered index record deleted; we do not have to check locks, because we assume that we have an x-lock on the record */ err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG, btr_cur, TRUE, thr, mtr); if (err == DB_SUCCESS && check_ref) { /* NOTE that the following call loses the position of pcur ! */ err = row_upd_check_references_constraints(node, pcur, index->table, index, thr, mtr); if (err != DB_SUCCESS) { mtr_commit(mtr); return(err); } } mtr_commit(mtr); return(err);}/***************************************************************Updates the clustered index record. */staticulintrow_upd_clust_step(/*===============*/ /* out: DB_SUCCESS if operation successfully completed, DB_LOCK_WAIT in case of a lock wait, else error code */ upd_node_t* node, /* in: row update node */ que_thr_t* thr) /* in: query thread */{ dict_index_t* index; btr_pcur_t* pcur; ibool success; ibool check_ref; ulint err; mtr_t* mtr; mtr_t mtr_buf; rec_t* rec; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; const ulint* offsets; *offsets_ = (sizeof offsets_) / sizeof *offsets_; index = dict_table_get_first_index(node->table); check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr)); pcur = node->pcur; /* We have to restore the cursor to its position */ mtr = &mtr_buf; mtr_start(mtr); /* If the restoration does not succeed, then the same transaction has deleted the record on which the cursor was, and that is an SQL error. If the restoration succeeds, it may still be that the same transaction has successively deleted and inserted a record with the same ordering fields, but in that case we know that the transaction has at least an implicit x-lock on the record. */ ut_a(pcur->rel_pos == BTR_PCUR_ON); success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); if (!success) { err = DB_RECORD_NOT_FOUND; mtr_commit(mtr); return(err); } /* If this is a row in SYS_INDEXES table of the data dictionary, then we have to free the file segments of the index tree associated with the index */ if (node->is_delete && ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) { dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr); mtr_commit(mtr); mtr_start(mtr); success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); if (!success) { err = DB_ERROR; mtr_commit(mtr); return(err); } } rec = btr_pcur_get_rec(pcur); offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap); if (!node->has_clust_rec_x_lock) { err = lock_clust_rec_modify_check_and_lock(0, rec, index, offsets, thr); if (err != DB_SUCCESS) { mtr_commit(mtr); goto exit_func; } } /* NOTE: the following function calls will also commit mtr */ if (node->is_delete) { err = row_upd_del_mark_clust_rec(node, index, thr, check_ref, mtr); if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; node->index = dict_table_get_next_index(index); } exit_func: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } return(err); } /* If the update is made for MySQL, we already have the update vector ready, else we have to do some evaluation: */ if (!node->in_mysql_interface) { /* Copy the necessary columns from clust_rec and calculate the new values to set */ row_upd_copy_columns(rec, offsets, UT_LIST_GET_FIRST(node->columns)); row_upd_eval_new_vals(node->update); } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) { err = row_upd_clust_rec(node, index, thr, mtr); return(err); } row_upd_store_row(node); if (row_upd_changes_ord_field_binary(node->row, index, node->update)) { /* Update causes an ordering field (ordering fields within the B-tree) of the clustered index record to change: perform the update by delete marking and inserting. TODO! What to do to the 'Halloween problem', where an update moves the record forward in index so that it is again updated when the cursor arrives there? Solution: the read operation must check the undo record undo number when choosing records to update. MySQL solves now the problem externally! */ err = row_upd_clust_rec_by_insert(node, index, thr, check_ref, mtr); if (err != DB_SUCCESS) { return(err); } node->state = UPD_NODE_UPDATE_ALL_SEC; } else { err = row_upd_clust_rec(node, index, thr, mtr); if (err != DB_SUCCESS) { return(err); } node->state = UPD_NODE_UPDATE_SOME_SEC; } node->index = dict_table_get_next_index(index); return(err);}/***************************************************************Updates the affected index records of a row. When the control is transferredto this node, we assume that we have a persistent cursor which was on arecord, and the position of the cursor is stored in the cursor. */staticulintrow_upd(/*====*/ /* out: DB_SUCCESS if operation successfully completed, else error code or DB_LOCK_WAIT */ upd_node_t* node, /* in: row update node */ que_thr_t* thr) /* in: query thread */{ ulint err = DB_SUCCESS; ut_ad(node && thr); if (node->in_mysql_interface) { /* We do not get the cmpl_info value from the MySQL interpreter: we must calculate it on the fly: */ if (node->is_delete || row_upd_changes_some_index_ord_field_binary( node->table, node->update)) { node->cmpl_info = 0; } else { node->cmpl_info = UPD_NODE_NO_ORD_CHANGE; } } if (node->state == UPD_NODE_UPDATE_CLUSTERED || node->state == UPD_NODE_INSERT_CLUSTERED) { err = row_upd_clust_step(node, thr); if (err != DB_SUCCESS) { goto function_exit; } } if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { goto function_exit; } while (node->index != NULL) { err = row_upd_sec_step(node, thr); if (err != DB_SUCCESS) { goto function_exit; } node->index = dict_table_get_next_index(node->index); }function_exit: if (err == DB_SUCCESS) { /* Do some cleanup */ if (node->row != NULL) { node->row = NULL; node->n_ext_vec = 0; mem_heap_empty(node->heap); } node->state = UPD_NODE_UPDATE_CLUSTERED; } return(err);}/***************************************************************Updates a row in a table. This is a high-level function used in SQL executiongraphs. */que_thr_t*row_upd_step(/*=========*/ /* out: query thread to run next or NULL */ que_thr_t* thr) /* in: query thread */{ upd_node_t* node; sel_node_t* sel_node; que_node_t* parent; ulint err = DB_SUCCESS; trx_t* trx; ut_ad(thr); trx = thr_get_trx(thr); trx_start_if_not_started(trx); node = thr->run_node; sel_node = node->select; parent = que_node_get_parent(node); ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE); if (thr->prev_node == parent) { node->state = UPD_NODE_SET_IX_LOCK; } if (node->state == UPD_NODE_SET_IX_LOCK) { if (!node->has_clust_rec_x_lock) { /* It may be that the current session has not yet started its transaction, or it has been committed: */ err = lock_table(0, node->table, LOCK_IX, thr); if (err != DB_SUCCESS) { goto error_handling; } } node->state = UPD_NODE_UPDATE_CLUSTERED; if (node->searched_update) { /* Reset the cursor */ sel_node->state = SEL_NODE_OPEN; /* Fetch a row to update */ thr->run_node = sel_node; return(thr); } } /* sel_node is NULL if we are in the MySQL interface */ if (sel_node && (sel_node->state != SEL_NODE_FETCH)) { if (!node->searched_update) { /* An explicit cursor should be positioned on a row to update */ ut_error; err = DB_ERROR; goto error_handling; } ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS); /* No more rows to update, or the select node performed the updates directly in-place */ thr->run_node = parent; return(thr); } /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ err = row_upd(node, thr);error_handling: trx->error_state = err; if (err == DB_SUCCESS) { /* Ok: do nothing */ } else if (err == DB_LOCK_WAIT) { return(NULL); } else { return(NULL); } /* DO THE TRIGGER ACTIONS HERE */ if (node->searched_update) { /* Fetch next row to update */ thr->run_node = sel_node; } else { /* It was an explicit cursor update */ thr->run_node = parent; } node->state = UPD_NODE_UPDATE_CLUSTERED; return(thr);} /*************************************************************************Performs an in-place update for the current clustered index record inselect. */voidrow_upd_in_place_in_select(/*=======================*/ sel_node_t* sel_node, /* in: select node */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr) /* in: mtr */{ upd_node_t* node; btr_pcur_t* pcur; btr_cur_t* btr_cur; ulint err; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_ad(sel_node->select_will_do_update); ut_ad(sel_node->latch_mode == BTR_MODIFY_LEAF); ut_ad(sel_node->asc); node = que_node_get_parent(sel_node); ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE); pcur = node->pcur; btr_cur = btr_pcur_get_btr_cur(pcur); /* Copy the necessary columns from clust_rec and calculate the new values to set */ row_upd_copy_columns(btr_pcur_get_rec(pcur), rec_get_offsets( btr_pcur_get_rec(pcur), btr_cur->index, offsets_, ULINT_UNDEFINED, &heap), UT_LIST_GET_FIRST(node->columns)); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } row_upd_eval_new_vals(node->update); ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), btr_cur->index->table->comp)); ut_ad(node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE); ut_ad(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE); ut_ad(node->select_will_do_update); err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG, btr_cur, node->update, node->cmpl_info, thr, mtr); ut_ad(err == DB_SUCCESS);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -