mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 18:43:02 +01:00
Backport fix for bug CORE-2731 : Recursive EXECUTE STATEMENT works wrong
This commit is contained in:
parent
39f3ec8018
commit
dc3cb55183
@ -108,6 +108,7 @@
|
||||
#define isc_dpb_trusted_role 75
|
||||
#define isc_dpb_org_filename 76
|
||||
#define isc_dpb_utf8_filename 77
|
||||
#define isc_dpb_ext_call_depth 78
|
||||
|
||||
/**************************************************/
|
||||
/* clumplet tags used inside isc_dpb_address_path */
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include "../jrd/exe.h"
|
||||
#include "../jrd/ibase.h"
|
||||
|
||||
const int MAX_CALLBACKS = 50;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
|
||||
|
@ -185,6 +185,11 @@ Provider::~Provider()
|
||||
Connection* Provider::getConnection(thread_db* tdbb, const string& dbName,
|
||||
const string& user, const string& pwd, const string& role, TraScope tra_scope)
|
||||
{
|
||||
const Attachment* attachment = tdbb->getAttachment();
|
||||
|
||||
if (attachment->att_ext_call_depth >= MAX_CALLBACKS)
|
||||
ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded));
|
||||
|
||||
{ // m_mutex scope
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
|
||||
@ -194,7 +199,8 @@ Connection* Provider::getConnection(thread_db* tdbb, const string& dbName,
|
||||
for (; conn_ptr < end; conn_ptr++)
|
||||
{
|
||||
Connection* conn = *conn_ptr;
|
||||
if (conn->isSameDatabase(tdbb, dbName, user, pwd, role) &&
|
||||
if (conn->m_boundAtt == attachment &&
|
||||
conn->isSameDatabase(tdbb, dbName, user, pwd, role) &&
|
||||
conn->isAvailable(tdbb, tra_scope))
|
||||
{
|
||||
return conn;
|
||||
@ -206,6 +212,7 @@ Connection* Provider::getConnection(thread_db* tdbb, const string& dbName,
|
||||
try
|
||||
{
|
||||
conn->attach(tdbb, dbName, user, pwd, role);
|
||||
conn->m_boundAtt = attachment;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -228,6 +235,8 @@ void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool /*inPoo
|
||||
{ // m_mutex scope
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
|
||||
conn.m_boundAtt = NULL;
|
||||
|
||||
size_t pos;
|
||||
if (!m_connections.find(&conn, pos))
|
||||
{
|
||||
@ -282,6 +291,7 @@ Connection::Connection(Provider& prov) :
|
||||
m_transactions(getPool()),
|
||||
m_statements(getPool()),
|
||||
m_freeStatements(NULL),
|
||||
m_boundAtt(NULL),
|
||||
m_used_stmts(0),
|
||||
m_free_stmts(0),
|
||||
m_deleting(false),
|
||||
@ -308,8 +318,11 @@ void Connection::generateDPB(thread_db* tdbb, ClumpletWriter& dpb,
|
||||
{
|
||||
dpb.reset(isc_dpb_version1);
|
||||
|
||||
const string& attUser = tdbb->getAttachment()->att_user->usr_user_name;
|
||||
const string& attRole = tdbb->getAttachment()->att_user->usr_sql_role_name;
|
||||
const Attachment *attachment = tdbb->getAttachment();
|
||||
dpb.insertInt(isc_dpb_ext_call_depth, attachment->att_ext_call_depth + 1);
|
||||
|
||||
const string& attUser = attachment->att_user->usr_user_name;
|
||||
const string& attRole = attachment->att_user->usr_sql_role_name;
|
||||
|
||||
if ((m_provider.getFlags() & prvTrustedAuth) &&
|
||||
(user.isEmpty() || user == attUser) && pwd.isEmpty() &&
|
||||
@ -331,7 +344,7 @@ void Connection::generateDPB(thread_db* tdbb, ClumpletWriter& dpb,
|
||||
}
|
||||
}
|
||||
|
||||
CharSet* const cs = INTL_charset_lookup(tdbb, tdbb->getAttachment()->att_charset);
|
||||
CharSet* const cs = INTL_charset_lookup(tdbb, attachment->att_charset);
|
||||
if (cs) {
|
||||
dpb.insertString(isc_dpb_lc_ctype, cs->getName());
|
||||
}
|
||||
@ -1521,17 +1534,24 @@ void EngineCallbackGuard::init(thread_db* tdbb, Connection& conn)
|
||||
{
|
||||
m_tdbb = tdbb;
|
||||
m_mutex = conn.isConnected() ? &conn.m_mutex : &conn.m_provider.m_mutex;
|
||||
m_saveConnection = NULL;
|
||||
|
||||
if (m_tdbb)
|
||||
{
|
||||
if (m_tdbb->getTransaction()) {
|
||||
m_tdbb->getTransaction()->tra_callback_count++;
|
||||
jrd_tra *transaction = m_tdbb->getTransaction();
|
||||
if (transaction)
|
||||
{
|
||||
if (transaction->tra_callback_count >= MAX_CALLBACKS)
|
||||
ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded));
|
||||
|
||||
transaction->tra_callback_count++;
|
||||
}
|
||||
|
||||
if (m_tdbb->getAttachment())
|
||||
Attachment *attachment = m_tdbb->getAttachment();
|
||||
if (attachment)
|
||||
{
|
||||
fb_assert(!m_tdbb->getAttachment()->att_ext_connection);
|
||||
m_tdbb->getAttachment()->att_ext_connection = &conn;
|
||||
m_saveConnection = attachment->att_ext_connection;
|
||||
attachment->att_ext_connection = &conn;
|
||||
}
|
||||
|
||||
m_tdbb->getDatabase()->dbb_sync->unlock();
|
||||
@ -1552,12 +1572,14 @@ EngineCallbackGuard::~EngineCallbackGuard()
|
||||
{
|
||||
m_tdbb->getDatabase()->dbb_sync->lock();
|
||||
|
||||
if (m_tdbb->getTransaction()) {
|
||||
m_tdbb->getTransaction()->tra_callback_count--;
|
||||
jrd_tra *transaction = m_tdbb->getTransaction();
|
||||
if (transaction) {
|
||||
transaction->tra_callback_count--;
|
||||
}
|
||||
|
||||
if (m_tdbb->getAttachment()) {
|
||||
m_tdbb->getAttachment()->att_ext_connection = NULL;
|
||||
Attachment *attachment = m_tdbb->getAttachment();
|
||||
if (attachment) {
|
||||
attachment->att_ext_connection = m_saveConnection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,7 @@ class Connection : public Firebird::PermanentStorage
|
||||
{
|
||||
protected:
|
||||
friend class EngineCallbackGuard;
|
||||
friend class Provider;
|
||||
|
||||
explicit Connection(Provider& prov);
|
||||
virtual ~Connection();
|
||||
@ -228,6 +229,8 @@ protected:
|
||||
Firebird::Array<Statement*> m_statements;
|
||||
Statement* m_freeStatements;
|
||||
|
||||
const Jrd::Attachment* m_boundAtt;
|
||||
|
||||
static const int MAX_CACHED_STMTS = 16;
|
||||
int m_used_stmts;
|
||||
int m_free_stmts;
|
||||
@ -454,6 +457,7 @@ private:
|
||||
|
||||
Jrd::thread_db* m_tdbb;
|
||||
Firebird::Mutex* m_mutex;
|
||||
Connection* m_saveConnection;
|
||||
};
|
||||
|
||||
} // namespace EDS
|
||||
|
@ -83,7 +83,7 @@ void InternalProvider::getRemoteError(ISC_STATUS* status, string& err) const
|
||||
{
|
||||
err = "";
|
||||
|
||||
char buff[512];
|
||||
char buff[1024];
|
||||
const ISC_STATUS* p = status;
|
||||
const ISC_STATUS* end = status + ISC_STATUS_LENGTH;
|
||||
|
||||
@ -209,10 +209,9 @@ bool InternalConnection::isSameDatabase(thread_db* tdbb, const Firebird::string&
|
||||
const Firebird::string& user, const Firebird::string& pwd,
|
||||
const Firebird::string& role) const
|
||||
{
|
||||
const UserId *attUser = m_attachment->att_user;
|
||||
|
||||
if (m_isCurrent)
|
||||
{
|
||||
const UserId* attUser = m_attachment->att_user;
|
||||
return ((user.isEmpty() || user == attUser->usr_user_name) &&
|
||||
pwd.isEmpty() &&
|
||||
(role.isEmpty() || role == attUser->usr_sql_role_name));
|
||||
|
@ -70,7 +70,13 @@ void IscProvider::getRemoteError(ISC_STATUS* status, string& err) const
|
||||
{
|
||||
err = "";
|
||||
|
||||
char buff[512];
|
||||
// We can't use safe fb_interpet here as we have no idea what implementation
|
||||
// of ISC API is used by current provider. We can test for existance of
|
||||
// fb_interpet and use it if present, but i don't want to complicate code.
|
||||
// So, buffer should be big enough to please old isc_interprete.
|
||||
// Probably in next version we should use fb_interpet only.
|
||||
|
||||
char buff[1024];
|
||||
ISC_STATUS* p = status;
|
||||
const ISC_STATUS* const end = status + ISC_STATUS_LENGTH;
|
||||
|
||||
|
@ -431,6 +431,7 @@ public:
|
||||
bool dpb_gbak_attach;
|
||||
bool dpb_trusted_role;
|
||||
bool dpb_utf8_filename;
|
||||
ULONG dpb_ext_call_depth;
|
||||
ULONG dpb_flags; // to OR'd with dbb_flags
|
||||
|
||||
// here begin compound objects
|
||||
@ -932,6 +933,7 @@ ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
|
||||
attachment->att_remote_pid = options.dpb_remote_pid;
|
||||
attachment->att_remote_process = options.dpb_remote_process;
|
||||
attachment->att_next = dbb->dbb_attachments;
|
||||
attachment->att_ext_call_depth = options.dpb_ext_call_depth;
|
||||
|
||||
dbb->dbb_attachments = attachment;
|
||||
dbb->dbb_flags &= ~DBB_being_opened;
|
||||
@ -1936,6 +1938,7 @@ ISC_STATUS GDS_CREATE_DATABASE(ISC_STATUS* user_status,
|
||||
attachment->att_remote_address = options.dpb_remote_address;
|
||||
attachment->att_remote_pid = options.dpb_remote_pid;
|
||||
attachment->att_remote_process = options.dpb_remote_process;
|
||||
attachment->att_ext_call_depth = options.dpb_ext_call_depth;
|
||||
attachment->att_next = dbb->dbb_attachments;
|
||||
|
||||
dbb->dbb_attachments = attachment;
|
||||
@ -4753,6 +4756,12 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
|
||||
getPath(rdr, dpb_org_filename);
|
||||
break;
|
||||
|
||||
case isc_dpb_ext_call_depth:
|
||||
dpb_ext_call_depth = (ULONG) rdr.getInt();
|
||||
if (dpb_ext_call_depth >= MAX_CALLBACKS)
|
||||
ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -5200,6 +5209,7 @@ Attachment::Attachment(MemoryPool* pool, Database* dbb)
|
||||
att_dsql_cache(*pool),
|
||||
att_udf_pointers(*pool),
|
||||
att_ext_connection(NULL),
|
||||
att_ext_call_depth(0),
|
||||
att_trace_manager(FB_NEW(*att_pool) TraceManager(this))
|
||||
{
|
||||
att_mutex.enter();
|
||||
|
@ -105,6 +105,7 @@ namespace Jrd {
|
||||
|
||||
const int QUANTUM = 100; // Default quantum
|
||||
const int SWEEP_QUANTUM = 10; // Make sweeps less disruptive
|
||||
const int MAX_CALLBACKS = 50;
|
||||
|
||||
// fwd. decl.
|
||||
class thread_db;
|
||||
@ -331,6 +332,7 @@ public:
|
||||
Firebird::Mutex att_mutex; // attachment mutex
|
||||
|
||||
EDS::Connection* att_ext_connection; // external connection executed by this attachment
|
||||
ULONG att_ext_call_depth; // external connection call depth, 0 for user attachment
|
||||
TraceManager* att_trace_manager; // Trace API manager
|
||||
|
||||
bool locksmith() const;
|
||||
|
Loading…
Reference in New Issue
Block a user