/**********************************************************************//** Does the transaction prepare for MySQL. @return 0 or error number */ UNIV_INTERN ulint trx_prepare_for_mysql( /*==================*/ trx_t* trx) /*!< in: trx handle */ { /* Because we do not do the prepare by sending an Innobase sig to the transaction, we must here make sure that trx has been started. */ ut_a(trx); trx->op_info = "preparing"; trx_start_if_not_started(trx); mutex_enter(&kernel_mutex); trx_prepare_off_kernel(trx); mutex_exit(&kernel_mutex); trx->op_info = ""; return(0); }
void trx_start_if_not_started_noninline( /*===============================*/ trx_t* trx) /* in: transaction */ { trx_start_if_not_started(trx); }
/*******************************************************************//** Rollback a transaction used in MySQL. @return error code or DB_SUCCESS */ UNIV_INTERN int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ trx_savept_t* savept) /*!< in: pointer to savepoint undo number, if partial rollback requested, or NULL for complete rollback */ { mem_heap_t* heap; que_thr_t* thr; roll_node_t* roll_node; /* Tell Innobase server that there might be work for utility threads: */ srv_active_wake_master_thread(); trx_start_if_not_started(trx); heap = mem_heap_create(512); roll_node = roll_node_create(heap); if (savept) { roll_node->partial = TRUE; roll_node->savept = *savept; } trx->error_state = DB_SUCCESS; thr = pars_complete_graph_for_exec(roll_node, trx, heap); ut_a(thr == que_fork_start_command(que_node_get_parent(thr))); que_run_threads(thr); mutex_enter(&kernel_mutex); while (trx->que_state != TRX_QUE_RUNNING) { mutex_exit(&kernel_mutex); os_thread_sleep(100000); mutex_enter(&kernel_mutex); } mutex_exit(&kernel_mutex); mem_heap_free(heap); ut_a(trx->error_state == DB_SUCCESS); /* Tell Innobase server that there might be work for utility threads: */ srv_active_wake_master_thread(); return((int) trx->error_state); }
/*******************************************************************//** Creates a named savepoint. If the transaction is not yet started, starts it. If there is already a savepoint of the same name, this call erases that old savepoint and replaces it with a new. Savepoints are deleted in a transaction commit or rollback. @return always DB_SUCCESS */ UNIV_INTERN ulint trx_savepoint_for_mysql( /*====================*/ trx_t* trx, /*!< in: transaction handle */ const char* savepoint_name, /*!< in: savepoint name */ ib_int64_t binlog_cache_pos) /*!< in: MySQL binlog cache position corresponding to this connection at the time of the savepoint */ { trx_named_savept_t* savep; ut_a(trx); ut_a(savepoint_name); trx_start_if_not_started(trx); savep = UT_LIST_GET_FIRST(trx->trx_savepoints); while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { /* Found */ break; } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } if (savep) { /* There is a savepoint with the same name: free that */ UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); mem_free(savep->name); mem_free(savep); } /* Create a new savepoint and add it as the last in the list */ savep = mem_alloc(sizeof(trx_named_savept_t)); savep->name = mem_strdup(savepoint_name); savep->savept = trx_savept_take(trx); savep->mysql_binlog_cache_pos = binlog_cache_pos; UT_LIST_ADD_LAST(trx_savepoints, trx->trx_savepoints, savep); return(DB_SUCCESS); }
ulint trx_commit_for_mysql( /*=================*/ /* out: 0 or error number */ trx_t* trx) /* in: trx handle */ { /* Because we do not do the commit by sending an Innobase sig to the transaction, we must here make sure that trx has been started. */ ut_a(trx); trx->op_info = "committing"; /* If we are doing the XA recovery of prepared transactions, then the transaction object does not have an InnoDB session object, and we set the dummy session that we use for all MySQL transactions. */ if (trx->sess == NULL) { /* Open a dummy session */ if (!trx_dummy_sess) { mutex_enter(&kernel_mutex); if (!trx_dummy_sess) { trx_dummy_sess = sess_open(); } mutex_exit(&kernel_mutex); } trx->sess = trx_dummy_sess; } trx_start_if_not_started(trx); mutex_enter(&kernel_mutex); trx_commit_off_kernel(trx); mutex_exit(&kernel_mutex); trx->op_info = ""; return(0); }
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); }