📄 row0ins.c
字号:
/******************************************************Insert into a table(c) 1996 Innobase OyCreated 4/20/1996 Heikki Tuuri*******************************************************/#include "row0ins.h"#ifdef UNIV_NONINL#include "row0ins.ic"#endif#include "dict0dict.h"#include "dict0boot.h"#include "trx0undo.h"#include "btr0btr.h"#include "btr0cur.h"#include "mach0data.h"#include "que0que.h"#include "row0upd.h"#include "row0sel.h"#include "row0row.h"#include "rem0cmp.h"#include "lock0lock.h"#include "log0log.h"#include "eval0eval.h"#include "data0data.h"#include "usr0sess.h"#include "buf0lru.h"#define ROW_INS_PREV 1#define ROW_INS_NEXT 2/*********************************************************************This prototype is copied from /mysql/sql/ha_innodb.cc.Invalidates the MySQL query cache for the table.NOTE that the exact prototype of this function has to be in/innobase/row/row0ins.c! */externvoidinnobase_invalidate_query_cache(/*============================*/ trx_t* trx, /* in: transaction which modifies the table */ char* full_name, /* in: concatenation of database name, null char '\0', table name, null char'\0'; NOTE that in Windows this is always in LOWER CASE! */ ulint full_name_len); /* in: full name length where also the null chars count *//**********************************************************************This function returns true if 1) SQL-query in the current threadis either REPLACE or LOAD DATA INFILE REPLACE. 2) SQL-query in the current threadis INSERT ON DUPLICATE KEY UPDATE.NOTE that /mysql/innobase/row/row0ins.c must contain the prototype for this function ! */iboolinnobase_query_is_update(void);/*************************************************************************Creates an insert node struct. */ins_node_t*ins_node_create(/*============*/ /* out, own: insert node struct */ ulint ins_type, /* in: INS_VALUES, ... */ dict_table_t* table, /* in: table where to insert */ mem_heap_t* heap) /* in: mem heap where created */{ ins_node_t* node; node = mem_heap_alloc(heap, sizeof(ins_node_t)); node->common.type = QUE_NODE_INSERT; node->ins_type = ins_type; node->state = INS_NODE_SET_IX_LOCK; node->table = table; node->index = NULL; node->entry = NULL; node->select = NULL; node->trx_id = ut_dulint_zero; node->entry_sys_heap = mem_heap_create(128); node->magic_n = INS_NODE_MAGIC_N; return(node);}/***************************************************************Creates an entry template for each index of a table. */staticvoidins_node_create_entry_list(/*=======================*/ ins_node_t* node) /* in: row insert node */{ dict_index_t* index; dtuple_t* entry; ut_ad(node->entry_sys_heap); UT_LIST_INIT(node->entry_list); index = dict_table_get_first_index(node->table); while (index != NULL) { entry = row_build_index_entry(node->row, index, node->entry_sys_heap); UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry); index = dict_table_get_next_index(index); }}/*********************************************************************Adds system field buffers to a row. */staticvoidrow_ins_alloc_sys_fields(/*=====================*/ ins_node_t* node) /* in: insert node */{ dtuple_t* row; dict_table_t* table; mem_heap_t* heap; dict_col_t* col; dfield_t* dfield; ulint len; byte* ptr; row = node->row; table = node->table; heap = node->entry_sys_heap; ut_ad(row && table && heap); ut_ad(dtuple_get_n_fields(row) == dict_table_get_n_cols(table)); /* 1. Allocate buffer for row id */ col = dict_table_get_sys_col(table, DATA_ROW_ID); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN); dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN); node->row_id_buf = ptr; if (table->type == DICT_TABLE_CLUSTER_MEMBER) { /* 2. Fill in the dfield for mix id */ col = dict_table_get_sys_col(table, DATA_MIX_ID); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); len = mach_dulint_get_compressed_size(table->mix_id); ptr = mem_heap_alloc(heap, DATA_MIX_ID_LEN); mach_dulint_write_compressed(ptr, table->mix_id); dfield_set_data(dfield, ptr, len); } /* 3. Allocate buffer for trx id */ col = dict_table_get_sys_col(table, DATA_TRX_ID); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN); dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN); node->trx_id_buf = ptr; /* 4. Allocate buffer for roll ptr */ col = dict_table_get_sys_col(table, DATA_ROLL_PTR); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN); dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN);}/*************************************************************************Sets a new row to insert for an INS_DIRECT node. This function is only usedif we have constructed the row separately, which is a rare case; thisfunction is quite slow. */voidins_node_set_new_row(/*=================*/ ins_node_t* node, /* in: insert node */ dtuple_t* row) /* in: new row (or first row) for the node */{ node->state = INS_NODE_SET_IX_LOCK; node->index = NULL; node->entry = NULL; node->row = row; mem_heap_empty(node->entry_sys_heap); /* Create templates for index entries */ ins_node_create_entry_list(node); /* Allocate from entry_sys_heap buffers for sys fields */ row_ins_alloc_sys_fields(node); /* As we allocated a new trx id buf, the trx id should be written there again: */ node->trx_id = ut_dulint_zero;}/***********************************************************************Does an insert operation by updating a delete-marked existing recordin the index. This situation can occur if the delete-marked record iskept in the index for consistent reads. */staticulintrow_ins_sec_index_entry_by_modify(/*==============================*/ /* out: DB_SUCCESS or error code */ ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, depending on whether mtr holds just a leaf latch or also a tree latch */ btr_cur_t* cursor, /* in: B-tree cursor */ dtuple_t* entry, /* in: index entry to insert */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr) /* in: mtr */{ big_rec_t* dummy_big_rec; mem_heap_t* heap; upd_t* update; rec_t* rec; ulint err; rec = btr_cur_get_rec(cursor); ut_ad((cursor->index->type & DICT_CLUSTERED) == 0); ut_ad(rec_get_deleted_flag(rec, cursor->index->table->comp)); /* We know that in the alphabetical ordering, entry and rec are identified. But in their binary form there may be differences if there are char fields in them. Therefore we have to calculate the difference. */ heap = mem_heap_create(1024); update = row_upd_build_sec_rec_difference_binary(cursor->index, entry, rec, thr_get_trx(thr), heap); if (mode == BTR_MODIFY_LEAF) { /* Try an optimistic updating of the record, keeping changes within the page */ err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor, update, 0, thr, mtr); if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { err = DB_FAIL; } } else { ut_a(mode == BTR_MODIFY_TREE); if (buf_LRU_buf_pool_running_out()) { err = DB_LOCK_TABLE_FULL; goto func_exit; } err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, &dummy_big_rec, update, 0, thr, mtr); }func_exit: mem_heap_free(heap); return(err);}/***********************************************************************Does an insert operation by delete unmarking and updating a delete markedexisting record in the index. This situation can occur if the delete markedrecord is kept in the index for consistent reads. */staticulintrow_ins_clust_index_entry_by_modify(/*================================*/ /* out: DB_SUCCESS, DB_FAIL, or error code */ ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, depending on whether mtr holds just a leaf latch or also a tree latch */ btr_cur_t* cursor, /* in: B-tree cursor */ big_rec_t** big_rec,/* out: possible big rec vector of fields which have to be stored externally by the caller */ 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 */ mtr_t* mtr) /* in: mtr */{ mem_heap_t* heap; rec_t* rec; upd_t* update; ulint err; ut_ad(cursor->index->type & DICT_CLUSTERED); *big_rec = NULL; rec = btr_cur_get_rec(cursor); ut_ad(rec_get_deleted_flag(rec, cursor->index->table->comp)); heap = mem_heap_create(1024); /* Build an update vector containing all the fields to be modified; NOTE that this vector may NOT contain system columns trx_id or roll_ptr */ update = row_upd_build_difference_binary(cursor->index, entry, ext_vec, n_ext_vec, rec, thr_get_trx(thr), heap); if (mode == BTR_MODIFY_LEAF) { /* Try optimistic updating of the record, keeping changes within the page */ err = btr_cur_optimistic_update(0, cursor, update, 0, thr, mtr); if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { err = DB_FAIL; } } else { ut_a(mode == BTR_MODIFY_TREE); if (buf_LRU_buf_pool_running_out()) { err = DB_LOCK_TABLE_FULL; goto func_exit; } err = btr_cur_pessimistic_update(0, cursor, big_rec, update, 0, thr, mtr); }func_exit: mem_heap_free(heap); return(err);}/*************************************************************************Returns TRUE if in a cascaded update/delete an ancestor node of nodeupdates (not DELETE, but UPDATE) table. */staticiboolrow_ins_cascade_ancestor_updates_table(/*===================================*/ /* out: TRUE if an ancestor updates table */ que_node_t* node, /* in: node in a query graph */ dict_table_t* table) /* in: table */{ que_node_t* parent; upd_node_t* upd_node; parent = que_node_get_parent(node); while (que_node_get_type(parent) == QUE_NODE_UPDATE) { upd_node = parent; if (upd_node->table == table && upd_node->is_delete == FALSE) { return(TRUE); } parent = que_node_get_parent(parent); ut_a(parent); } return(FALSE);} /*************************************************************************Returns the number of ancestor UPDATE or DELETE nodes of acascaded update/delete node. */staticulintrow_ins_cascade_n_ancestors(/*========================*/ /* out: number of ancestors */ que_node_t* node) /* in: node in a query graph */{ que_node_t* parent; ulint n_ancestors = 0; parent = que_node_get_parent(node); while (que_node_get_type(parent) == QUE_NODE_UPDATE) { n_ancestors++; parent = que_node_get_parent(parent); ut_a(parent); } return(n_ancestors);} /**********************************************************************Calculates the update vector node->cascade->update for a child table ina cascaded update. */staticulintrow_ins_cascade_calc_update_vec(/*============================*/ /* out: number of fields in the calculated update vector; the value can also be 0 if no foreign key fields changed; the returned value is ULINT_UNDEFINED if the column type in the child table is too short to fit the new value in the parent table: that means the update fails */ upd_node_t* node, /* in: update node of the parent table */ dict_foreign_t* foreign, /* in: foreign key constraint whose type is != 0 */ mem_heap_t* heap) /* in: memory heap to use as temporary storage */{ upd_node_t* cascade = node->cascade_node; dict_table_t* table = foreign->foreign_table; dict_index_t* index = foreign->foreign_index; upd_t* update; upd_field_t* ufield; dict_table_t* parent_table; dict_index_t* parent_index; upd_t* parent_update; upd_field_t* parent_ufield; ulint n_fields_updated; ulint parent_field_no; dtype_t* type; ulint i; ulint j; ut_a(node && foreign && cascade && table && index); /* Calculate the appropriate update vector which will set the fields in the child index record to the same value (possibly padded with spaces if the column is a fixed length CHAR or FIXBINARY column) as the referenced index record will get in the update. */ parent_table = node->table; ut_a(parent_table == foreign->referenced_table); parent_index = foreign->referenced_index; parent_update = node->update; update = cascade->update; update->info_bits = 0; update->n_fields = foreign->n_fields; n_fields_updated = 0; for (i = 0; i < foreign->n_fields; i++) { parent_field_no = dict_table_get_nth_col_pos( parent_table, dict_index_get_nth_col_no( parent_index, i)); for (j = 0; j < parent_update->n_fields; j++) { parent_ufield = parent_update->fields + j; if (parent_ufield->field_no == parent_field_no) { ulint min_size; /* A field in the parent index record is updated. Let us make the update vector field for the child table. */ ufield = update->fields + n_fields_updated;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -