mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
A fix and a test case for Bug#12713 "Error in a stored function called from
a SELECT doesn't cause ROLLBACK of statem". The idea of the fix is to ensure that we always commit the current statement at the end of dispatch_command(). In order to not issue redundant disc syncs, an optimization of the two-phase commit protocol is implemented to bypass the two phase commit if the transaction is read-only.
This commit is contained in:
122
sql/handler.h
122
sql/handler.h
@ -721,14 +721,14 @@ struct handlerton
|
||||
#define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables
|
||||
#define HTON_NO_PARTITION (1 << 8) //You can not partition these tables
|
||||
|
||||
typedef struct st_thd_trans
|
||||
class Ha_trx_info;
|
||||
|
||||
struct THD_TRANS
|
||||
{
|
||||
/* number of entries in the ht[] */
|
||||
uint nht;
|
||||
/* true is not all entries in the ht[] support 2pc */
|
||||
bool no_2pc;
|
||||
/* storage engines that registered themselves for this transaction */
|
||||
handlerton *ht[MAX_HA];
|
||||
/* storage engines that registered in this transaction */
|
||||
Ha_trx_info *ha_list;
|
||||
/*
|
||||
The purpose of this flag is to keep track of non-transactional
|
||||
tables that were modified in scope of:
|
||||
@ -758,7 +758,106 @@ typedef struct st_thd_trans
|
||||
saved value.
|
||||
*/
|
||||
bool modified_non_trans_table;
|
||||
} THD_TRANS;
|
||||
|
||||
void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Either statement transaction or normal transaction - related
|
||||
thread-specific storage engine data.
|
||||
|
||||
If a storage engine participates in a statement/transaction,
|
||||
an instance of this class is present in
|
||||
thd->transaction.{stmt|all}.ha_list. The addition to
|
||||
{stmt|all}.ha_list is made by trans_register_ha().
|
||||
|
||||
When it's time to commit or rollback, each element of ha_list
|
||||
is used to access storage engine's prepare()/commit()/rollback()
|
||||
methods, and also to evaluate if a full two phase commit is
|
||||
necessary.
|
||||
|
||||
@sa General description of transaction handling in handler.cc.
|
||||
*/
|
||||
|
||||
class Ha_trx_info
|
||||
{
|
||||
public:
|
||||
/** Register this storage engine in the given transaction context. */
|
||||
void register_ha(THD_TRANS *trans, handlerton *ht_arg)
|
||||
{
|
||||
DBUG_ASSERT(m_flags == 0);
|
||||
DBUG_ASSERT(m_ht == NULL);
|
||||
DBUG_ASSERT(m_next == NULL);
|
||||
|
||||
m_ht= ht_arg;
|
||||
m_flags= (int) TRX_READ_ONLY; /* Assume read-only at start. */
|
||||
|
||||
m_next= trans->ha_list;
|
||||
trans->ha_list= this;
|
||||
}
|
||||
|
||||
/** Clear, prepare for reuse. */
|
||||
void reset()
|
||||
{
|
||||
m_next= NULL;
|
||||
m_ht= NULL;
|
||||
m_flags= 0;
|
||||
}
|
||||
|
||||
Ha_trx_info() { reset(); }
|
||||
|
||||
void set_trx_read_write()
|
||||
{
|
||||
DBUG_ASSERT(is_started());
|
||||
m_flags|= (int) TRX_READ_WRITE;
|
||||
}
|
||||
bool is_trx_read_write() const
|
||||
{
|
||||
DBUG_ASSERT(is_started());
|
||||
return m_flags & (int) TRX_READ_WRITE;
|
||||
}
|
||||
bool is_started() const { return m_ht != NULL; }
|
||||
/** Mark this transaction read-write if the argument is read-write. */
|
||||
void coalesce_trx_with(const Ha_trx_info *stmt_trx)
|
||||
{
|
||||
/*
|
||||
Must be called only after the transaction has been started.
|
||||
Can be called many times, e.g. when we have many
|
||||
read-write statements in a transaction.
|
||||
*/
|
||||
DBUG_ASSERT(is_started());
|
||||
if (stmt_trx->is_trx_read_write())
|
||||
set_trx_read_write();
|
||||
}
|
||||
Ha_trx_info *next() const
|
||||
{
|
||||
DBUG_ASSERT(is_started());
|
||||
return m_next;
|
||||
}
|
||||
handlerton *ht() const
|
||||
{
|
||||
DBUG_ASSERT(is_started());
|
||||
return m_ht;
|
||||
}
|
||||
private:
|
||||
enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 };
|
||||
/** Auxiliary, used for ha_list management */
|
||||
Ha_trx_info *m_next;
|
||||
/**
|
||||
Although a given Ha_trx_info instance is currently always used
|
||||
for the same storage engine, 'ht' is not-NULL only when the
|
||||
corresponding storage is a part of a transaction.
|
||||
*/
|
||||
handlerton *m_ht;
|
||||
/**
|
||||
Transaction flags related to this engine.
|
||||
Not-null only if this instance is a part of transaction.
|
||||
May assume a combination of enum values above.
|
||||
*/
|
||||
uchar m_flags;
|
||||
};
|
||||
|
||||
|
||||
enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
|
||||
ISO_REPEATABLE_READ, ISO_SERIALIZABLE};
|
||||
@ -1640,7 +1739,14 @@ protected:
|
||||
provide useful functionality.
|
||||
*/
|
||||
virtual int rename_table(const char *from, const char *to);
|
||||
/**
|
||||
Delete a table in the engine. Called for base as well as temporary
|
||||
tables.
|
||||
*/
|
||||
virtual int delete_table(const char *name);
|
||||
private:
|
||||
/* Private helpers */
|
||||
inline void mark_trx_read_write();
|
||||
private:
|
||||
/*
|
||||
Low-level primitives for storage engines. These should be
|
||||
@ -1821,9 +1927,7 @@ extern TYPELIB tx_isolation_typelib;
|
||||
extern TYPELIB myisam_stats_method_typelib;
|
||||
extern ulong total_ha, total_ha_2pc;
|
||||
|
||||
/* Wrapper functions */
|
||||
#define ha_commit_stmt(thd) (ha_commit_trans((thd), FALSE))
|
||||
#define ha_rollback_stmt(thd) (ha_rollback_trans((thd), FALSE))
|
||||
/* Wrapper functions */
|
||||
#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
|
||||
#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
|
||||
|
||||
|
Reference in New Issue
Block a user