📄 row0ins.c
字号:
#ifdef UNIV_DEBUG { page_t* page = btr_cur_get_page(&cursor); rec_t* first_rec = page_rec_get_next( page_get_infimum_rec(page)); if (UNIV_LIKELY(first_rec != page_get_supremum_rec(page))) { ut_a(rec_get_n_fields(first_rec, index) == dtuple_get_n_fields(entry)); } }#endif n_unique = dict_index_get_n_unique(index); if (index->type & DICT_UNIQUE && (cursor.up_match >= n_unique || cursor.low_match >= n_unique)) { if (index->type & DICT_CLUSTERED) { /* Note that the following may return also DB_LOCK_WAIT */ err = row_ins_duplicate_error_in_clust(&cursor, entry, thr, &mtr); if (err != DB_SUCCESS) { goto function_exit; } } else { mtr_commit(&mtr); err = row_ins_scan_sec_index_for_duplicate(index, entry, thr); mtr_start(&mtr); if (err != DB_SUCCESS) { goto function_exit; } /* We did not find a duplicate and we have now locked with s-locks the necessary records to prevent any insertion of a duplicate by another transaction. Let us now reposition the cursor and continue the insertion. */ btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode | BTR_INSERT, &cursor, 0, &mtr); } } modify = row_ins_must_modify(&cursor); if (modify != 0) { /* There is already an index entry with a long enough common prefix, we must convert the insert into a modify of an existing record */ if (modify == ROW_INS_NEXT) { rec = page_rec_get_next(btr_cur_get_rec(&cursor)); btr_cur_position(index, rec, &cursor); } if (index->type & DICT_CLUSTERED) { err = row_ins_clust_index_entry_by_modify(mode, &cursor, &big_rec, entry, ext_vec, n_ext_vec, thr, &mtr); } else { err = row_ins_sec_index_entry_by_modify(mode, &cursor, entry, thr, &mtr); } } else { if (mode == BTR_MODIFY_LEAF) { err = btr_cur_optimistic_insert(0, &cursor, entry, &insert_rec, &big_rec, thr, &mtr); } else { ut_a(mode == BTR_MODIFY_TREE); if (buf_LRU_buf_pool_running_out()) { err = DB_LOCK_TABLE_FULL; goto function_exit; } err = btr_cur_pessimistic_insert(0, &cursor, entry, &insert_rec, &big_rec, thr, &mtr); } if (err == DB_SUCCESS) { if (ext_vec) { rec_set_field_extern_bits(insert_rec, index, ext_vec, n_ext_vec, &mtr); } } }function_exit: mtr_commit(&mtr); if (big_rec) { rec_t* rec; mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, BTR_MODIFY_TREE, &cursor, 0, &mtr); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); err = btr_store_big_rec_extern_fields(index, rec, offsets, big_rec, &mtr); if (modify) { dtuple_big_rec_free(big_rec); } else { dtuple_convert_back_big_rec(index, entry, big_rec); } mtr_commit(&mtr); } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } return(err);}/*******************************************************************Inserts an index entry to index. Tries first optimistic, then pessimisticdescent down the tree. If the entry matches enough to a delete marked record,performs the insert by updating or delete unmarking the delete markedrecord. */ulintrow_ins_index_entry(/*================*/ /* out: DB_SUCCESS, DB_LOCK_WAIT, DB_DUPLICATE_KEY, or some other error code */ dict_index_t* index, /* in: index */ dtuple_t* entry, /* in: index entry to insert */ ulint* ext_vec,/* in: array containing field numbers of externally stored fields in entry, or NULL */ ulint n_ext_vec,/* in: number of fields in ext_vec */ que_thr_t* thr) /* in: query thread */{ ulint err; if (UT_LIST_GET_FIRST(index->table->foreign_list)) { err = row_ins_check_foreign_constraints(index->table, index, entry, thr); if (err != DB_SUCCESS) { return(err); } } /* Try first optimistic descent to the B-tree */ err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry, ext_vec, n_ext_vec, thr); if (err != DB_FAIL) { return(err); } /* Try then pessimistic descent to the B-tree */ err = row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry, ext_vec, n_ext_vec, thr); return(err);}/***************************************************************Sets the values of the dtuple fields in entry from the values of appropriatecolumns in row. */staticvoidrow_ins_index_entry_set_vals(/*=========================*/ dict_index_t* index, /* in: index */ dtuple_t* entry, /* in: index entry to make */ dtuple_t* row) /* in: row */{ dict_field_t* ind_field; dfield_t* field; dfield_t* row_field; ulint n_fields; ulint i; dtype_t* cur_type; ut_ad(entry && row); n_fields = dtuple_get_n_fields(entry); for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(entry, i); ind_field = dict_index_get_nth_field(index, i); row_field = dtuple_get_nth_field(row, ind_field->col->ind); /* Check column prefix indexes */ if (ind_field->prefix_len > 0 && dfield_get_len(row_field) != UNIV_SQL_NULL) { cur_type = dict_col_get_type( dict_field_get_col(ind_field)); field->len = dtype_get_at_most_n_mbchars(cur_type, ind_field->prefix_len, dfield_get_len(row_field), row_field->data); } else { field->len = row_field->len; } field->data = row_field->data; }}/***************************************************************Inserts a single index entry to the table. */staticulintrow_ins_index_entry_step(/*=====================*/ /* out: DB_SUCCESS if operation successfully completed, else error code or DB_LOCK_WAIT */ ins_node_t* node, /* in: row insert node */ que_thr_t* thr) /* in: query thread */{ ulint err; ut_ad(dtuple_check_typed(node->row)); row_ins_index_entry_set_vals(node->index, node->entry, node->row); ut_ad(dtuple_check_typed(node->entry)); err = row_ins_index_entry(node->index, node->entry, NULL, 0, thr); return(err);}/***************************************************************Allocates a row id for row and inits the node->index field. */UNIV_INLINEvoidrow_ins_alloc_row_id_step(/*======================*/ ins_node_t* node) /* in: row insert node */{ dulint row_id; ut_ad(node->state == INS_NODE_ALLOC_ROW_ID); if (dict_table_get_first_index(node->table)->type & DICT_UNIQUE) { /* No row id is stored if the clustered index is unique */ return; } /* Fill in row id value to row */ row_id = dict_sys_get_new_row_id(); dict_sys_write_row_id(node->row_id_buf, row_id);}/***************************************************************Gets a row to insert from the values list. */UNIV_INLINEvoidrow_ins_get_row_from_values(/*========================*/ ins_node_t* node) /* in: row insert node */{ que_node_t* list_node; dfield_t* dfield; dtuple_t* row; ulint i; /* The field values are copied in the buffers of the select node and it is safe to use them until we fetch from select again: therefore we can just copy the pointers */ row = node->row; i = 0; list_node = node->values_list; while (list_node) { eval_exp(list_node); dfield = dtuple_get_nth_field(row, i); dfield_copy_data(dfield, que_node_get_val(list_node)); i++; list_node = que_node_get_next(list_node); }}/***************************************************************Gets a row to insert from the select list. */UNIV_INLINEvoidrow_ins_get_row_from_select(/*========================*/ ins_node_t* node) /* in: row insert node */{ que_node_t* list_node; dfield_t* dfield; dtuple_t* row; ulint i; /* The field values are copied in the buffers of the select node and it is safe to use them until we fetch from select again: therefore we can just copy the pointers */ row = node->row; i = 0; list_node = node->select->select_list; while (list_node) { dfield = dtuple_get_nth_field(row, i); dfield_copy_data(dfield, que_node_get_val(list_node)); i++; list_node = que_node_get_next(list_node); }} /***************************************************************Inserts a row to a table. */ulintrow_ins(/*====*/ /* out: DB_SUCCESS if operation successfully completed, else error code or DB_LOCK_WAIT */ ins_node_t* node, /* in: row insert node */ que_thr_t* thr) /* in: query thread */{ ulint err; ut_ad(node && thr); if (node->state == INS_NODE_ALLOC_ROW_ID) { row_ins_alloc_row_id_step(node); node->index = dict_table_get_first_index(node->table); node->entry = UT_LIST_GET_FIRST(node->entry_list); if (node->ins_type == INS_SEARCHED) { row_ins_get_row_from_select(node); } else if (node->ins_type == INS_VALUES) { row_ins_get_row_from_values(node); } node->state = INS_NODE_INSERT_ENTRIES; } ut_ad(node->state == INS_NODE_INSERT_ENTRIES); while (node->index != NULL) { err = row_ins_index_entry_step(node, thr); if (err != DB_SUCCESS) { return(err); } node->index = dict_table_get_next_index(node->index); node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); } ut_ad(node->entry == NULL); node->state = INS_NODE_ALLOC_ROW_ID; return(DB_SUCCESS);}/***************************************************************Inserts a row to a table. This is a high-level function used in SQL executiongraphs. */que_thr_t*row_ins_step(/*=========*/ /* out: query thread to run next or NULL */ que_thr_t* thr) /* in: query thread */{ ins_node_t* node; que_node_t* parent; sel_node_t* sel_node; trx_t* trx; ulint err; ut_ad(thr); trx = thr_get_trx(thr); trx_start_if_not_started(trx); node = thr->run_node; ut_ad(que_node_get_type(node) == QUE_NODE_INSERT); parent = que_node_get_parent(node); sel_node = node->select; if (thr->prev_node == parent) { node->state = INS_NODE_SET_IX_LOCK; } /* If this is the first time this node is executed (or when execution resumes after wait for the table IX lock), set an IX lock on the table and reset the possible select node. */ if (node->state == INS_NODE_SET_IX_LOCK) { /* It may be that the current session has not yet started its transaction, or it has been committed: */ if (UT_DULINT_EQ(trx->id, node->trx_id)) { /* No need to do IX-locking or write trx id to buf */ goto same_trx; } trx_write_trx_id(node->trx_id_buf, trx->id); err = lock_table(0, node->table, LOCK_IX, thr); if (err != DB_SUCCESS) { goto error_handling; } node->trx_id = trx->id; same_trx: node->state = INS_NODE_ALLOC_ROW_ID; if (node->ins_type == INS_SEARCHED) { /* Reset the cursor */ sel_node->state = SEL_NODE_OPEN; /* Fetch a row to insert */ thr->run_node = sel_node; return(thr); } } if ((node->ins_type == INS_SEARCHED) && (sel_node->state != SEL_NODE_FETCH)) { ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS); /* No more rows to insert */ thr->run_node = parent; return(thr); } /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ err = row_ins(node, thr);error_handling: trx->error_state = err; if (err != DB_SUCCESS) { /* err == DB_LOCK_WAIT or SQL error detected */ return(NULL); } /* DO THE TRIGGER ACTIONS HERE */ if (node->ins_type == INS_SEARCHED) { /* Fetch a row to insert */ thr->run_node = sel_node; } else { thr->run_node = que_node_get_parent(node); } return(thr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -