mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:03:03 +01:00
Let external transaction run with CONCURRENCY isolation mode if local transaction runs with READ COMMITED READ CONSISTENCY isolation and such isolation mode is not supported by external data source.
Allow to reuse external connection if external data source doesn't support ALTER SESSION RESET statement. Update documentation.
This commit is contained in:
parent
6260af2a78
commit
94d3a7cfe8
@ -76,7 +76,11 @@ Syntax and notes :
|
||||
This transaction lifetime is bound to the lifetime of current (local) transaction
|
||||
and commits\rolled back the same way as current transaction.
|
||||
|
||||
- by default COMMON TRANSACTION is used
|
||||
- by default COMMON TRANSACTION is used.
|
||||
|
||||
- if local transaction is READ COMMITTED READ CONSISTENCY and if external data source not
|
||||
supported this isolation mode, then external transaction will run with CONCURRENCY
|
||||
isolation mode.
|
||||
|
||||
- if PASSWORD clause is omitted then
|
||||
a) if <user_name> is omitted, NULL or equal to CURRENT_USER value and
|
||||
|
@ -15,7 +15,9 @@ How pool works:
|
||||
active transactions), it is reset and placed into idle list (on successful
|
||||
reset) or closed (if reset failed).
|
||||
Connection is reset using ALTER SESSION RESET statement. It is considered
|
||||
successful if no error occurs.
|
||||
successful if no error occurs. Note, if external data source not supported
|
||||
ALTER SESSION RESET statement - it is not considered as error and such
|
||||
connection will be placed into pool.
|
||||
- if the pool has reached max. size, the oldest idle connection is closed
|
||||
- when engine ask to create a new external connection, the pool first looks
|
||||
for candidate at the idle list. The search is based on 4 parameters:
|
||||
|
@ -525,7 +525,8 @@ Connection::Connection(Provider& prov) :
|
||||
m_deleting(false),
|
||||
m_sqlDialect(0),
|
||||
m_wrapErrors(true),
|
||||
m_broken(false)
|
||||
m_broken(false),
|
||||
m_features(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -437,6 +437,8 @@ public:
|
||||
virtual void detach(Jrd::thread_db* tdbb);
|
||||
|
||||
virtual bool cancelExecution(bool forced) = 0;
|
||||
|
||||
// Try to reset connection, return true if it can be pooled
|
||||
virtual bool resetSession() = 0;
|
||||
|
||||
int getSqlDialect() const { return m_sqlDialect; }
|
||||
@ -492,6 +494,13 @@ public:
|
||||
|
||||
virtual Blob* createBlob() = 0;
|
||||
|
||||
// Test specified flags, return true if all bits present
|
||||
bool testFeature(ULONG value) const { return m_features & value; }
|
||||
// Set specified flags, return new value
|
||||
ULONG setFeature(ULONG value) { return m_features |= value; }
|
||||
// Clear specified flags, return new value
|
||||
ULONG clearFeature(ULONG value) { return m_features &= ~value; }
|
||||
|
||||
protected:
|
||||
virtual Transaction* doCreateTransaction() = 0;
|
||||
virtual Statement* doCreateStatement() = 0;
|
||||
@ -522,8 +531,16 @@ protected:
|
||||
int m_sqlDialect; // must be filled in attach call
|
||||
bool m_wrapErrors;
|
||||
bool m_broken;
|
||||
ULONG m_features; // bitmask
|
||||
};
|
||||
|
||||
// Connection features flags
|
||||
const ULONG conFtrSessionReset = 0x01; // supports ALTER SESSION RESET
|
||||
const ULONG conFtrReadConsistency = 0x02; // supports READ COMMITTED READ CONSISTENCY
|
||||
const ULONG conFtrStatementTimeout = 0x04; // supports statements timeout
|
||||
|
||||
// Features of Firebird 4
|
||||
const ULONG conFtrFB4 = conFtrSessionReset | conFtrReadConsistency | conFtrStatementTimeout;
|
||||
|
||||
class Transaction : public Firebird::PermanentStorage
|
||||
{
|
||||
|
@ -187,6 +187,8 @@ void InternalConnection::attach(thread_db* tdbb)
|
||||
|
||||
m_sqlDialect = (attachment->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
|
||||
SQL_DIALECT_V6 : SQL_DIALECT_V5;
|
||||
|
||||
m_features = conFtrFB4;
|
||||
}
|
||||
|
||||
void InternalConnection::doDetach(thread_db* tdbb)
|
||||
|
@ -191,6 +191,8 @@ void IscConnection::attach(thread_db* tdbb)
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
|
||||
m_features = conFtrFB4; // Exact feature set will be detected at first usage
|
||||
}
|
||||
|
||||
void IscConnection::doDetach(thread_db* tdbb)
|
||||
@ -238,6 +240,9 @@ bool IscConnection::resetSession()
|
||||
if (!m_handle)
|
||||
return false;
|
||||
|
||||
if (!testFeature(conFtrSessionReset))
|
||||
return true;
|
||||
|
||||
FbLocalStatus status;
|
||||
m_iscProvider.isc_dsql_execute_immediate(&status, &m_handle,
|
||||
NULL, 0, "ALTER SESSION RESET", m_sqlDialect, NULL);
|
||||
@ -245,7 +250,13 @@ bool IscConnection::resetSession()
|
||||
if (!(status->getState() & IStatus::STATE_ERRORS))
|
||||
return true;
|
||||
|
||||
return false; // (status->getErrors()[1] == isc_dsql_error);
|
||||
if (status->getErrors()[1] == isc_dsql_error)
|
||||
{
|
||||
clearFeature(conFtrSessionReset);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// this ISC connection instance is available for the current execution context if it
|
||||
@ -301,14 +312,44 @@ Statement* IscConnection::doCreateStatement()
|
||||
|
||||
// IscTransaction
|
||||
|
||||
void IscTransaction::generateTPB(thread_db* tdbb, ClumpletWriter& tpb,
|
||||
TraModes traMode, bool readOnly, bool wait, int lockTimeout) const
|
||||
{
|
||||
if (traMode == traReadCommitedReadConsistency && !m_connection.testFeature(conFtrReadConsistency))
|
||||
traMode = traConcurrency;
|
||||
|
||||
Transaction::generateTPB(tdbb, tpb, traMode, readOnly, wait, lockTimeout);
|
||||
}
|
||||
|
||||
void IscTransaction::doStart(FbStatusVector* status, thread_db* tdbb, Firebird::ClumpletWriter& tpb)
|
||||
{
|
||||
fb_assert(!m_handle);
|
||||
FB_API_HANDLE& db_handle = m_iscConnection.getAPIHandle();
|
||||
|
||||
{
|
||||
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
|
||||
m_iscProvider.isc_start_transaction(status, &m_handle, 1, &db_handle,
|
||||
tpb.getBufferLength(), tpb.getBuffer());
|
||||
}
|
||||
|
||||
if ((status->getState() & IStatus::STATE_ERRORS) &&
|
||||
(status->getErrors()[1] == isc_bad_tpb_form) &&
|
||||
tpb.find(isc_tpb_read_consistency) &&
|
||||
m_connection.testFeature(conFtrReadConsistency))
|
||||
{
|
||||
tpb.deleteWithTag(isc_tpb_read_committed);
|
||||
tpb.deleteWithTag(isc_tpb_read_consistency);
|
||||
tpb.insertTag(isc_tpb_concurrency);
|
||||
|
||||
{
|
||||
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
|
||||
m_iscProvider.isc_start_transaction(status, &m_handle, 1, &db_handle,
|
||||
tpb.getBufferLength(), tpb.getBuffer());
|
||||
}
|
||||
|
||||
if (!(status->getState() & IStatus::STATE_ERRORS))
|
||||
m_connection.clearFeature(conFtrReadConsistency);
|
||||
}
|
||||
}
|
||||
|
||||
void IscTransaction::doPrepare(FbStatusVector* /*status*/, thread_db* /*tdbb*/, int /*info_len*/, const char* /*info*/)
|
||||
@ -521,6 +562,9 @@ void IscStatement::doPrepare(thread_db* tdbb, const string& sql)
|
||||
|
||||
void IscStatement::doSetTimeout(thread_db* tdbb, unsigned int timeout)
|
||||
{
|
||||
if (!m_connection.testFeature(conFtrStatementTimeout))
|
||||
return;
|
||||
|
||||
FbLocalStatus status;
|
||||
|
||||
{
|
||||
@ -533,7 +577,10 @@ void IscStatement::doSetTimeout(thread_db* tdbb, unsigned int timeout)
|
||||
// silently ignore error if timeouts is not supported by remote server
|
||||
// or loaded client library
|
||||
if (status[0] == isc_arg_gds && (status[1] == isc_wish_list || status[1] == isc_unavailable))
|
||||
{
|
||||
m_connection.clearFeature(conFtrStatementTimeout);
|
||||
return;
|
||||
}
|
||||
|
||||
raise(&status, tdbb, "fb_dsql_set_timeout");
|
||||
}
|
||||
|
@ -556,6 +556,9 @@ protected:
|
||||
|
||||
virtual ~IscTransaction() {}
|
||||
|
||||
virtual void generateTPB(Jrd::thread_db* tdbb, Firebird::ClumpletWriter& tpb,
|
||||
TraModes traMode, bool readOnly, bool wait, int lockTimeout) const;
|
||||
|
||||
virtual void doStart(Jrd::FbStatusVector* status, Jrd::thread_db* tdbb, Firebird::ClumpletWriter& tpb);
|
||||
virtual void doPrepare(Jrd::FbStatusVector* status, Jrd::thread_db* tdbb, int info_len, const char* info);
|
||||
virtual void doCommit(Jrd::FbStatusVector* status, Jrd::thread_db* tdbb, bool retain);
|
||||
|
Loading…
Reference in New Issue
Block a user