📄 row0upd.c
字号:
ut_ad(update && index); n_unique = dict_index_get_n_unique(index); n_upd_fields = upd_get_n_fields(update); for (i = 0; i < n_unique; i++) { ind_field = dict_index_get_nth_field(index, i); col = dict_field_get_col(ind_field); col_pos = dict_col_get_clust_pos(col); col_no = dict_col_get_no(col); for (j = 0; j < n_upd_fields; j++) { upd_field = upd_get_nth_field(update, j); /* Note that if the index field is a column prefix then it may be that row does not contain an externally stored part of the column value, and we cannot compare the datas */ if (col_pos == upd_field->field_no && (row == NULL || ind_field->prefix_len > 0 || !dfield_datas_are_binary_equal( dtuple_get_nth_field(row, col_no), &(upd_field->new_val)))) { return(TRUE); } } } return(FALSE);}/***************************************************************Checks if an update vector changes an ordering field of an index record.NOTE: we compare the fields as binary strings! */iboolrow_upd_changes_some_index_ord_field_binary(/*========================================*/ /* out: TRUE if update vector may change an ordering field in an index record */ dict_table_t* table, /* in: table */ upd_t* update) /* in: update vector for the row */{ upd_field_t* upd_field; dict_index_t* index; ulint i; index = dict_table_get_first_index(table); for (i = 0; i < upd_get_n_fields(update); i++) { upd_field = upd_get_nth_field(update, i); if (dict_field_get_col(dict_index_get_nth_field(index, upd_field->field_no)) ->ord_part) { return(TRUE); } } return(FALSE);}/***************************************************************Checks if an update vector changes some of the first ordering fields of anindex record. This is only used in foreign key checks and we can assumethat index does not contain column prefixes. */staticiboolrow_upd_changes_first_fields_binary(/*================================*/ /* out: TRUE if changes */ dtuple_t* entry, /* in: index entry */ dict_index_t* index, /* in: index of entry */ upd_t* update, /* in: update vector for the row */ ulint n) /* in: how many first fields to check */{ upd_field_t* upd_field; dict_field_t* ind_field; dict_col_t* col; ulint n_upd_fields; ulint col_pos; ulint i, j; ut_a(update && index); ut_a(n <= dict_index_get_n_fields(index)); n_upd_fields = upd_get_n_fields(update); for (i = 0; i < n; i++) { ind_field = dict_index_get_nth_field(index, i); col = dict_field_get_col(ind_field); col_pos = dict_col_get_clust_pos(col); ut_a(ind_field->prefix_len == 0); for (j = 0; j < n_upd_fields; j++) { upd_field = upd_get_nth_field(update, j); if (col_pos == upd_field->field_no && !dfield_datas_are_binary_equal( dtuple_get_nth_field(entry, i), &(upd_field->new_val))) { return(TRUE); } } } return(FALSE);}/*************************************************************************Copies the column values from a record. */UNIV_INLINEvoidrow_upd_copy_columns(/*=================*/ rec_t* rec, /* in: record in a clustered index */ const ulint* offsets,/* in: array returned by rec_get_offsets() */ sym_node_t* column) /* in: first column in a column list, or NULL */{ byte* data; ulint len; while (column) { data = rec_get_nth_field(rec, offsets, column->field_nos[SYM_CLUST_FIELD_NO], &len); eval_node_copy_and_alloc_val(column, data, len); column = UT_LIST_GET_NEXT(col_var_list, column); }}/*************************************************************************Calculates the new values for fields to update. Note that row_upd_copy_columnsmust have been called first. */UNIV_INLINEvoidrow_upd_eval_new_vals(/*==================*/ upd_t* update) /* in: update vector */{ que_node_t* exp; upd_field_t* upd_field; ulint n_fields; ulint i; n_fields = upd_get_n_fields(update); for (i = 0; i < n_fields; i++) { upd_field = upd_get_nth_field(update, i); exp = upd_field->exp; eval_exp(exp); dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp)); }}/***************************************************************Stores to the heap the row on which the node->pcur is positioned. */staticvoidrow_upd_store_row(/*==============*/ upd_node_t* node) /* in: row update node */{ dict_index_t* clust_index; upd_t* update; rec_t* rec; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; const ulint* offsets; *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES); if (node->row != NULL) { mem_heap_empty(node->heap); node->row = NULL; } clust_index = dict_table_get_first_index(node->table); rec = btr_pcur_get_rec(node->pcur); offsets = rec_get_offsets(rec, clust_index, offsets_, ULINT_UNDEFINED, &heap); node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets, node->heap); node->ext_vec = mem_heap_alloc(node->heap, sizeof(ulint) * rec_offs_n_fields(offsets)); if (node->is_delete) { update = NULL; } else { update = node->update; } node->n_ext_vec = btr_push_update_extern_fields(node->ext_vec, offsets, update); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); }}/***************************************************************Updates a secondary index entry of a row. */staticulintrow_upd_sec_index_entry(/*====================*/ /* 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 */{ ibool check_ref; ibool found; dict_index_t* index; dtuple_t* entry; btr_pcur_t pcur; btr_cur_t* btr_cur; mem_heap_t* heap; rec_t* rec; ulint err = DB_SUCCESS; mtr_t mtr; trx_t* trx = thr_get_trx(thr); index = node->index; check_ref = row_upd_index_is_referenced(index, trx); heap = mem_heap_create(1024); /* Build old index entry */ entry = row_build_index_entry(node->row, index, heap); log_free_check(); mtr_start(&mtr); found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, &mtr); btr_cur = btr_pcur_get_btr_cur(&pcur); rec = btr_cur_get_rec(btr_cur); if (UNIV_UNLIKELY(!found)) { fputs("InnoDB: error in sec index entry update in\n" "InnoDB: ", stderr); dict_index_name_print(stderr, trx, index); fputs("\n" "InnoDB: tuple ", stderr); dtuple_print(stderr, entry); fputs("\n" "InnoDB: record ", stderr); rec_print(stderr, rec, index); putc('\n', stderr); trx_print(stderr, trx, 0); fputs("\n""InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); } else { /* Delete mark the old index record; it can already be delete marked if we return after a lock wait in row_ins_index_entry below */ if (!rec_get_deleted_flag(rec, index->table->comp)) { err = btr_cur_del_mark_set_sec_rec(0, 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) { goto close_cur; } } } }close_cur: btr_pcur_close(&pcur); mtr_commit(&mtr); if (node->is_delete || err != DB_SUCCESS) { mem_heap_free(heap); return(err); } /* Build a new index entry */ row_upd_index_replace_new_col_vals(entry, index, node->update, NULL); /* Insert new index entry */ err = row_ins_index_entry(index, entry, NULL, 0, thr); mem_heap_free(heap); return(err);}/***************************************************************Updates secondary index record if it is changed in the row update. Thisshould be quite rare in database applications. */UNIV_INLINEulintrow_upd_sec_step(/*=============*/ /* 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; ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC) || (node->state == UPD_NODE_UPDATE_SOME_SEC)); ut_ad(!(node->index->type & DICT_CLUSTERED)); if (node->state == UPD_NODE_UPDATE_ALL_SEC || row_upd_changes_ord_field_binary(node->row, node->index, node->update)) { err = row_upd_sec_index_entry(node, thr); return(err); } return(DB_SUCCESS);}/***************************************************************Marks the clustered index record deleted and inserts the updated versionof the record to the index. This function should be used when the orderingfields of the clustered index record change. This should be quite rare indatabase applications. */staticulintrow_upd_clust_rec_by_insert(/*========================*/ /* out: DB_SUCCESS if operation successfully completed, else error code or DB_LOCK_WAIT */ upd_node_t* node, /* in: row update node */ dict_index_t* index, /* in: clustered index of the record */ 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 */{ mem_heap_t* heap = NULL; btr_pcur_t* pcur; btr_cur_t* btr_cur; trx_t* trx; dict_table_t* table; dtuple_t* entry; ulint err; ut_ad(node); ut_ad(index->type & DICT_CLUSTERED); trx = thr_get_trx(thr); table = node->table; pcur = node->pcur; btr_cur = btr_pcur_get_btr_cur(pcur); if (node->state != UPD_NODE_INSERT_CLUSTERED) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; *offsets_ = (sizeof offsets_) / sizeof *offsets_; err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG, btr_cur, TRUE, thr, mtr); if (err != DB_SUCCESS) { mtr_commit(mtr); return(err); } /* Mark as not-owned the externally stored fields which the new row inherits from the delete marked record: purge should not free those externally stored fields even if the delete marked record is removed from the index tree, or updated. */ btr_cur_mark_extern_inherited_fields(btr_cur_get_rec(btr_cur), rec_get_offsets(btr_cur_get_rec(btr_cur), dict_table_get_first_index(table), offsets_, ULINT_UNDEFINED, &heap), node->update, mtr); if (check_ref) { /* NOTE that the following call loses the position of pcur ! */ err = row_upd_check_references_constraints(node, pcur, table, index, thr, mtr); if (err != DB_SUCCESS) { mtr_commit(mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } return(err); } } } mtr_commit(mtr); if (!heap) { heap = mem_heap_create(500); } node->state = UPD_NODE_INSERT_CLUSTERED; entry = row_build_index_entry(node->row, index, heap); row_upd_index_replace_new_col_vals(entry, index, node->update, NULL); row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id); /* If we return from a lock wait, for example, we may have extern fields marked as not-owned in entry (marked in the if-branch above). We must unmark them. */ btr_cur_unmark_dtuple_extern_fields(entry, node->ext_vec, node->n_ext_vec); /* We must mark non-updated extern fields in entry as inherited, so that a possible rollback will not free them */ btr_cur_mark_dtuple_inherited_extern(entry, node->ext_vec, node->n_ext_vec, node->update); err = row_ins_index_entry(index, entry, node->ext_vec, node->n_ext_vec, thr); mem_heap_free(heap); return(err);}/***************************************************************Updates a clustered index record of a row when the ordering fields donot change. */staticulintrow_upd_clust_rec(/*==============*/ /* out: DB_SUCCESS if operation successfully completed, else error code or DB_LOCK_WAIT */ upd_node_t* node, /* in: row update node */ dict_index_t* index, /* in: clustered index */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr) /* in: mtr; gets committed here */{ big_rec_t* big_rec = NULL; btr_pcur_t* pcur; btr_cur_t* btr_cur; ulint err; ut_ad(node); ut_ad(index->type & DICT_CLUSTERED); pcur = node->pcur; btr_cur = btr_pcur_get_btr_cur(pcur); ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), index->table->comp)); /* Try optimistic updating of the record, keeping changes within the page; we do not check locks because we assume the x-lock on the record to update */ if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) { err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG, btr_cur, node->update, node->cmpl_info, thr, mtr); } else { err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, node->update, node->cmpl_info, thr, mtr); } mtr_commit(mtr); if (err == DB_SUCCESS) { return(err); } if (buf_LRU_buf_pool_running_out()) { return(DB_LOCK_TABLE_FULL); } /* We may have to modify the tree structure: do a pessimistic descent down the index tree */ mtr_start(mtr); /* NOTE: this transaction has an s-lock or x-lock on the record and therefore other transactions cannot modify the record when we have no latch on the page. In addition, we assume that other query threads of the same transaction do not modify the record in the meantime.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -