📄 row0mysql.c
字号:
row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL table handle */ dict_table_t* table, /* in: table to lock, or NULL if prebuilt->table should be locked as prebuilt->select_lock_type */ ulint mode) /* in: lock mode of table (ignored if table==NULL) */{ trx_t* trx = prebuilt->trx; que_thr_t* thr; ulint err; ibool was_lock_wait; ut_ad(trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); trx->op_info = "setting table lock"; if (prebuilt->sel_graph == NULL) { /* Build a dummy select query graph */ row_prebuild_sel_graph(prebuilt); } /* We use the select query graph as the dummy graph needed in the lock module call */ thr = que_fork_get_first_thr(prebuilt->sel_graph); que_thr_move_to_run_state_for_mysql(thr, trx);run_again: thr->run_node = thr; thr->prev_node = thr->common.parent; /* It may be that the current session has not yet started its transaction, or it has been committed: */ trx_start_if_not_started(trx); if (table) { err = lock_table(0, table, mode, thr); } else { err = lock_table(0, prebuilt->table, prebuilt->select_lock_type, thr); } trx->error_state = err; if (err != DB_SUCCESS) { que_thr_stop_for_mysql(thr); was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL); if (was_lock_wait) { goto run_again; } trx->op_info = ""; return((int) err); } que_thr_stop_for_mysql_no_error(thr, trx); trx->op_info = ""; return((int) err); } /*************************************************************************Does an insert for MySQL. */introw_insert_for_mysql(/*=================*/ /* out: error code or DB_SUCCESS */ byte* mysql_rec, /* in: row in the MySQL format */ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL handle */{ trx_savept_t savept; que_thr_t* thr; ulint err; ibool was_lock_wait; trx_t* trx = prebuilt->trx; ins_node_t* node = prebuilt->ins_node; ut_ad(trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); if (prebuilt->table->ibd_file_missing) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error:\n""InnoDB: MySQL is trying to use a table handle but the .ibd file for\n""InnoDB: table %s does not exist.\n""InnoDB: Have you deleted the .ibd file from the database directory under\n""InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n""InnoDB: Look from\n""http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n""InnoDB: how you can resolve the problem.\n", prebuilt->table->name); return(DB_ERROR); } if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" "InnoDB: table handle. Magic n %lu, table name", (ulong) prebuilt->magic_n); ut_print_name(stderr, prebuilt->trx, prebuilt->table->name); putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); ut_error; } if (srv_created_new_raw || srv_force_recovery) { fputs( "InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); return(DB_ERROR); } trx->op_info = "inserting"; row_mysql_delay_if_needed(); trx_start_if_not_started(trx); if (node == NULL) { row_get_prebuilt_insert_row(prebuilt); node = prebuilt->ins_node; } row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec); savept = trx_savept_take(trx); thr = que_fork_get_first_thr(prebuilt->ins_graph); if (prebuilt->sql_stat_start) { node->state = INS_NODE_SET_IX_LOCK; prebuilt->sql_stat_start = FALSE; } else { node->state = INS_NODE_ALLOC_ROW_ID; } que_thr_move_to_run_state_for_mysql(thr, trx);run_again: thr->run_node = node; thr->prev_node = node; row_ins_step(thr); err = trx->error_state; if (err != DB_SUCCESS) { que_thr_stop_for_mysql(thr);/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW; was_lock_wait = row_mysql_handle_errors(&err, trx, thr, &savept); thr->lock_state= QUE_THR_LOCK_NOLOCK; if (was_lock_wait) { goto run_again; } trx->op_info = ""; return((int) err); } que_thr_stop_for_mysql_no_error(thr, trx); prebuilt->table->stat_n_rows++; srv_n_rows_inserted++; if (prebuilt->table->stat_n_rows == 0) { /* Avoid wrap-over */ prebuilt->table->stat_n_rows--; } row_update_statistics_if_needed(prebuilt->table); trx->op_info = ""; return((int) err);}/*************************************************************************Builds a dummy query graph used in selects. */voidrow_prebuild_sel_graph(/*===================*/ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL handle */{ sel_node_t* node; ut_ad(prebuilt && prebuilt->trx); if (prebuilt->sel_graph == NULL) { node = sel_node_create(prebuilt->heap); prebuilt->sel_graph = que_node_get_parent( pars_complete_graph_for_exec(node, prebuilt->trx, prebuilt->heap)); prebuilt->sel_graph->state = QUE_FORK_ACTIVE; }}/*************************************************************************Creates an query graph node of 'update' type to be used in the MySQLinterface. */upd_node_t*row_create_update_node_for_mysql(/*=============================*/ /* out, own: update node */ dict_table_t* table, /* in: table to update */ mem_heap_t* heap) /* in: mem heap from which allocated */{ upd_node_t* node; node = upd_node_create(heap); node->in_mysql_interface = TRUE; node->is_delete = FALSE; node->searched_update = FALSE; node->select_will_do_update = FALSE; node->select = NULL; node->pcur = btr_pcur_create_for_mysql(); node->table = table; node->update = upd_create(dict_table_get_n_cols(table), heap); node->update_n_fields = dict_table_get_n_cols(table); UT_LIST_INIT(node->columns); node->has_clust_rec_x_lock = TRUE; node->cmpl_info = 0; node->table_sym = NULL; node->col_assign_list = NULL; return(node);}/*************************************************************************Gets pointer to a prebuilt update vector used in updates. If the updategraph has not yet been built in the prebuilt struct, then this functionfirst builds it. */upd_t*row_get_prebuilt_update_vector(/*===========================*/ /* out: prebuilt update vector */ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL handle */{ dict_table_t* table = prebuilt->table; upd_node_t* node; ut_ad(prebuilt && table && prebuilt->trx); if (prebuilt->upd_node == NULL) { /* Not called before for this handle: create an update node and query graph to the prebuilt struct */ node = row_create_update_node_for_mysql(table, prebuilt->heap); prebuilt->upd_node = node; prebuilt->upd_graph = que_node_get_parent( pars_complete_graph_for_exec(node, prebuilt->trx, prebuilt->heap)); prebuilt->upd_graph->state = QUE_FORK_ACTIVE; } return(prebuilt->upd_node->update);}/*************************************************************************Does an update or delete of a row for MySQL. */introw_update_for_mysql(/*=================*/ /* out: error code or DB_SUCCESS */ byte* mysql_rec, /* in: the row to be updated, in the MySQL format */ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL handle */{ trx_savept_t savept; ulint err; que_thr_t* thr; ibool was_lock_wait; dict_index_t* clust_index; /* ulint ref_len; */ upd_node_t* node; dict_table_t* table = prebuilt->table; trx_t* trx = prebuilt->trx; ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); UT_NOT_USED(mysql_rec); if (prebuilt->table->ibd_file_missing) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Error:\n""InnoDB: MySQL is trying to use a table handle but the .ibd file for\n""InnoDB: table %s does not exist.\n""InnoDB: Have you deleted the .ibd file from the database directory under\n""InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n""InnoDB: Look from\n""http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n""InnoDB: how you can resolve the problem.\n", prebuilt->table->name); return(DB_ERROR); } if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" "InnoDB: table handle. Magic n %lu, table name", (ulong) prebuilt->magic_n); ut_print_name(stderr, prebuilt->trx, prebuilt->table->name); putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); ut_error; } if (srv_created_new_raw || srv_force_recovery) { fputs( "InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); return(DB_ERROR); } trx->op_info = "updating or deleting"; row_mysql_delay_if_needed(); trx_start_if_not_started(trx); node = prebuilt->upd_node; clust_index = dict_table_get_first_index(table); if (prebuilt->pcur->btr_cur.index == clust_index) { btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur); } else { btr_pcur_copy_stored_position(node->pcur, prebuilt->clust_pcur); } ut_a(node->pcur->rel_pos == BTR_PCUR_ON); /* MySQL seems to call rnd_pos before updating each row it has cached: we can get the correct cursor position from prebuilt->pcur; NOTE that we cannot build the row reference from mysql_rec if the clustered index was automatically generated for the table: MySQL does not know anything about the row id used as the clustered index key */ savept = trx_savept_take(trx); thr = que_fork_get_first_thr(prebuilt->upd_graph); node->state = UPD_NODE_UPDATE_CLUSTERED; ut_ad(!prebuilt->sql_stat_start); que_thr_move_to_run_state_for_mysql(thr, trx);run_again: thr->run_node = node; thr->prev_node = node; row_upd_step(thr); err = trx->error_state; if (err != DB_SUCCESS) { que_thr_stop_for_mysql(thr); if (err == DB_RECORD_NOT_FOUND) { trx->error_state = DB_SUCCESS; trx->op_info = ""; return((int) err); } thr->lock_state= QUE_THR_LOCK_ROW; was_lock_wait = row_mysql_handle_errors(&err, trx, thr, &savept); thr->lock_state= QUE_THR_LOCK_NOLOCK;; if (was_lock_wait) { goto run_again; } trx->op_info = ""; return((int) err); } que_thr_stop_for_mysql_no_error(thr, trx); if (node->is_delete) { if (prebuilt->table->stat_n_rows > 0) { prebuilt->table->stat_n_rows--; } srv_n_rows_deleted++; } else { srv_n_rows_updated++; } row_update_statistics_if_needed(prebuilt->table); trx->op_info = ""; return((int) err);}/*************************************************************************This can only be used when srv_locks_unsafe_for_binlog is TRUE. Beforecalling this function we must use trx_reset_new_rec_lock_info() andtrx_register_new_rec_lock() to store the information which new record locksreally were set. This function removes a newly set lock under prebuilt->pcur,and also under prebuilt->clust_pcur. Currently, this is only used and testedin the case of an UPDATE or a DELETE statement, where the row lock is of theLOCK_X or LOCK_S type. Thus, this implements a 'mini-rollback' that releases the latest record locks we set. */introw_unlock_for_mysql(/*=================*/ /* out: error code or DB_SUCCESS */ row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL handle */ ibool has_latches_on_recs)/* TRUE if called so that we have the latches on the records under pcur and clust_pcur, and we do not need to reposition the cursors. */{ dict_index_t* index; btr_pcur_t* pcur = prebuilt->pcur; btr_pcur_t* clust_pcur = prebuilt->clust_pcur; trx_t* trx = prebuilt->trx; rec_t* rec; mtr_t mtr; ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); if (!srv_locks_unsafe_for_binlog) { fprintf(stderr,"InnoDB: Error: calling row_unlock_for_mysql though\n""InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -