8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 07:23:04 +01:00

Implemented improvement CORE-1928 : Allow EXECUTE STATEMENT to inherit access privileges of caller stored procedure or trigger.

Allow to specify EXECUTE STATEMENToptional clauses in any (not fixed) order.
Use INTERNAL_PROVIDER for access to the current database by another user too.
This commit is contained in:
hvlad 2008-06-08 20:42:27 +00:00
parent d331961962
commit 5d9c430674
16 changed files with 308 additions and 117 deletions

View File

@ -72,6 +72,7 @@ static void gen_for_select(CompiledStatement*, const dsql_nod*);
static void gen_gen_id(CompiledStatement*, const dsql_nod*);
static void gen_join_rse(CompiledStatement*, const dsql_nod*);
static void gen_map(CompiledStatement*, dsql_map*);
static inline void gen_optional_expr(CompiledStatement*, dsql_nod*);
static void gen_parameter(CompiledStatement*, const dsql_par*);
static void gen_plan(CompiledStatement*, const dsql_nod*);
static void gen_relation(CompiledStatement*, dsql_ctx*);
@ -1101,11 +1102,12 @@ void GEN_statement( CompiledStatement* statement, dsql_nod* node)
case nod_exec_stmt:
{ // scope
const bool old_syntax =
(node->nod_arg[e_exec_stmt_inputs] == NULL) &&
(node->nod_arg[e_exec_stmt_data_src]->nod_type == nod_null) &&
(node->nod_arg[e_exec_stmt_user]->nod_type == nod_null) &&
(node->nod_arg[e_exec_stmt_pwd]->nod_type == nod_null) &&
(node->nod_arg[e_exec_stmt_tran]->nod_flags == NOD_TRAN_COMMON);
!node->nod_arg[e_exec_stmt_inputs] &&
!node->nod_arg[e_exec_stmt_data_src] &&
!node->nod_arg[e_exec_stmt_user] &&
!node->nod_arg[e_exec_stmt_pwd] &&
!node->nod_arg[e_exec_stmt_tran] &&
!node->nod_arg[e_exec_stmt_privs];
const bool old_exec_into = old_syntax && node->nod_arg[e_exec_stmt_outputs];
@ -1144,13 +1146,22 @@ void GEN_statement( CompiledStatement* statement, dsql_nod* node)
if (!old_syntax)
{
// external data source, user and password
GEN_expr(statement, node->nod_arg[e_exec_stmt_data_src]);
GEN_expr(statement, node->nod_arg[e_exec_stmt_user]);
GEN_expr(statement, node->nod_arg[e_exec_stmt_pwd]);
gen_optional_expr(statement, node->nod_arg[e_exec_stmt_data_src]);
gen_optional_expr(statement, node->nod_arg[e_exec_stmt_user]);
gen_optional_expr(statement, node->nod_arg[e_exec_stmt_pwd]);
// statement's transaction behavior
stuff(statement, (UCHAR) node->nod_arg[e_exec_stmt_tran]->nod_flags);
const dsql_nod* opt = node->nod_arg[e_exec_stmt_tran];
stuff(statement, (UCHAR) opt ? opt->nod_flags : NOD_TRAN_DEFAULT);
stuff(statement, 0); // transaction parameters equal to current transaction
// inherit caller's privileges ?
if (node->nod_arg[e_exec_stmt_privs]) {
stuff(statement, 1);
}
else {
stuff(statement, 0);
}
}
// singleton flag and proc block body
@ -2024,6 +2035,13 @@ static void gen_map( CompiledStatement* statement, dsql_map* map)
}
}
static void gen_optional_expr(CompiledStatement* statement, dsql_nod* node)
{
if (node)
GEN_expr(statement, node);
else
stuff(statement, blr_null);
}
/**

View File

@ -95,6 +95,7 @@ static const TOK tokens[] =
{BOTH, "BOTH", 2, false},
{KW_BREAK, "BREAK", 2, true},
{BY, "BY", 1, false},
{CALLER, "CALLER", 2, true},
{CASCADE, "CASCADE", 1, true},
{CASE, "CASE", 2, false},
{CAST, "CAST", 1, false},

View File

@ -366,6 +366,10 @@ enum nod_t
nod_del_user,
nod_exec_stmt,
nod_exec_stmt_inputs, // 290
nod_exec_stmt_datasrc,
nod_exec_stmt_user,
nod_exec_stmt_pwd,
nod_exec_stmt_privs,
nod_tran_params,
nod_named_param,
nod_dfl_collate,
@ -436,11 +440,13 @@ enum node_args {
e_exec_stmt_inputs,
e_exec_stmt_outputs,
e_exec_stmt_proc_block,
e_exec_stmt_label,
e_exec_stmt_options,
e_exec_stmt_data_src,
e_exec_stmt_user,
e_exec_stmt_pwd,
e_exec_stmt_tran,
e_exec_stmt_label,
e_exec_stmt_privs,
e_exec_stmt_count,
e_exec_stmt_inputs_sql = 0, // nod_exec_stmt_inputs
@ -1090,7 +1096,8 @@ enum nod_flags_vals {
NOD_TRAN_AUTONOMOUS = 1, // nod_exec_stmt
NOD_TRAN_COMMON = 2,
NOD_TRAN_2PC = 3
NOD_TRAN_2PC = 3,
NOD_TRAN_DEFAULT = NOD_TRAN_COMMON
};
} // namespace

View File

@ -551,6 +551,7 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%token SIMILAR
%token UUID_TO_CHAR
// new execute statement
%token CALLER
%token COMMON
%token DATA
%token SOURCE
@ -1751,32 +1752,29 @@ for_select : label_opt FOR select INTO variable_list cursor_def DO proc_block
// ;
exec_sql
: EXECUTE STATEMENT exec_stmt_inputs
ext_datasrc_opt ext_user_opt ext_pwd_opt ext_tran_opt
: EXECUTE STATEMENT exec_stmt_inputs exec_stmt_options
{
$$ = make_node (nod_exec_stmt, int (e_exec_stmt_count),
($3)->nod_arg[0], ($3)->nod_arg[1], NULL, NULL, $4, $5, $6, $7, NULL);
($3)->nod_arg[0], ($3)->nod_arg[1], NULL, NULL, NULL, make_list($4), NULL, NULL, NULL, NULL, NULL);
}
;
exec_into
: EXECUTE STATEMENT exec_stmt_inputs
ext_datasrc_opt ext_user_opt ext_pwd_opt ext_tran_opt
: EXECUTE STATEMENT exec_stmt_inputs exec_stmt_options
INTO variable_list
{
$$ = make_node (nod_exec_stmt, int (e_exec_stmt_count),
($3)->nod_arg[0], ($3)->nod_arg[1], make_list ($9), NULL, $4, $5, $6, $7, NULL);
($3)->nod_arg[0], ($3)->nod_arg[1], make_list($6), NULL, NULL, make_list($4), NULL, NULL, NULL, NULL, NULL);
}
;
for_exec_into
: label_opt FOR EXECUTE STATEMENT exec_stmt_inputs
ext_datasrc_opt ext_user_opt ext_pwd_opt ext_tran_opt
: label_opt FOR EXECUTE STATEMENT exec_stmt_inputs exec_stmt_options
INTO variable_list
DO proc_block
{
$$ = make_node (nod_exec_stmt, int (e_exec_stmt_count),
($5)->nod_arg[0], ($5)->nod_arg[1], make_list ($11), $13, $6, $7, $8, $9, $1);
($5)->nod_arg[0], ($5)->nod_arg[1], make_list($8), $10, $1, make_list($6), NULL, NULL, NULL, NULL, NULL);
}
;
@ -1811,38 +1809,55 @@ not_named_param
{ $$ = make_node (nod_named_param, e_named_param_count, NULL, $1); }
;
ext_datasrc_opt
exec_stmt_options
: exec_stmt_options_list
|
{ $$ = NULL; }
;
exec_stmt_options_list
: exec_stmt_options_list exec_stmt_option
{ $$ = make_node (nod_list, 2, $1, $2); }
| exec_stmt_option
;
exec_stmt_option
: ext_datasrc
| ext_user
| ext_pwd
| ext_tran
| ext_privs
;
ext_datasrc
: ON EXTERNAL DATA SOURCE value
{ $$ = $5; }
{ $$ = make_node (nod_exec_stmt_datasrc, 1, $5); }
| ON EXTERNAL value
{ $$ = $3; }
|
{ $$ = make_node (nod_null, 0, NULL); }
{ $$ = make_node (nod_exec_stmt_datasrc, 1, $3); }
;
ext_user_opt
ext_user
: AS USER value
{ $$ = $3; }
|
{ $$ = make_node (nod_null, 0, NULL); }
{ $$ = make_node (nod_exec_stmt_user, 1, $3); }
;
ext_pwd_opt
ext_pwd
: PASSWORD value
{ $$ = $2; }
|
{ $$ = make_node (nod_null, 0, NULL); }
{ $$ = make_node (nod_exec_stmt_pwd, 1, $2); }
;
ext_tran_opt
ext_tran
: WITH AUTONOMOUS TRANSACTION
{ $$ = make_flag_node(nod_tran_params, NOD_TRAN_AUTONOMOUS, 1, NULL); }
| WITH COMMON TRANSACTION
{ $$ = make_flag_node(nod_tran_params, NOD_TRAN_COMMON, 1, NULL); }
// | WITH TWO_PHASE TRANSACTION
// { $$ = make_flag_node(nod_tran_params, NOD_TRAN_2PC, 1, NULL); }
|
{ $$ = make_flag_node(nod_tran_params, NOD_TRAN_COMMON, 1, NULL); }
;
ext_privs
: WITH CALLER PRIVILEGES
{ $$ = make_node (nod_exec_stmt_privs, 1, NULL); }
;
if_then_else : IF '(' search_condition ')' THEN proc_block ELSE proc_block
@ -5003,7 +5018,8 @@ non_reserved_word :
| MAPPING
| OS_NAME
| UUID_TO_CHAR
| COMMON // new execute statement
| CALLER // new execute statement
| COMMON
| DATA
| SOURCE
| TWO_PHASE

View File

@ -1110,6 +1110,9 @@ dsql_nod* PASS1_node(CompiledStatement* statement, dsql_nod* input)
case nod_tran_params:
return input;
case nod_exec_stmt_privs:
return input;
case nod_named_param:
node = MAKE_node(input->nod_type, input->nod_count);
node->nod_arg[e_named_param_name] = input->nod_arg[e_named_param_name];
@ -1780,17 +1783,66 @@ dsql_nod* PASS1_statement(CompiledStatement* statement, dsql_nod* input)
statement->req_labels.pop();
}
node->nod_arg[e_exec_stmt_data_src] =
PASS1_node(statement, input->nod_arg[e_exec_stmt_data_src]);
// process various optional arguments
if (input->nod_arg[e_exec_stmt_options])
{
dsql_nod *list = input->nod_arg[e_exec_stmt_options];
fb_assert(list->nod_type == nod_list);
node->nod_arg[e_exec_stmt_user] =
PASS1_node(statement, input->nod_arg[e_exec_stmt_user]);
dsql_nod **ptr = list->nod_arg;
const dsql_nod *const *end = list->nod_arg + list->nod_count;
for (; ptr < end; ptr++)
{
char *dupClause = NULL;
dsql_nod *opt = *ptr;
switch (opt->nod_type)
{
case nod_exec_stmt_datasrc:
if (node->nod_arg[e_exec_stmt_data_src])
dupClause = "EXTERNAL DATA SOURCE";
else
node->nod_arg[e_exec_stmt_data_src] = PASS1_node(statement, opt->nod_arg[0]);
break;
node->nod_arg[e_exec_stmt_pwd] =
PASS1_node(statement, input->nod_arg[e_exec_stmt_pwd]);
case nod_exec_stmt_user:
if (node->nod_arg[e_exec_stmt_user])
dupClause = "USER";
else
node->nod_arg[e_exec_stmt_user] = PASS1_node(statement, opt->nod_arg[0]);
break;
node->nod_arg[e_exec_stmt_tran] =
PASS1_node(statement, input->nod_arg[e_exec_stmt_tran]);
case nod_exec_stmt_pwd:
if (node->nod_arg[e_exec_stmt_pwd])
dupClause = "PASSWORD";
else
node->nod_arg[e_exec_stmt_pwd] = PASS1_node(statement, opt->nod_arg[0]);
break;
case nod_tran_params:
if (node->nod_arg[e_exec_stmt_tran])
dupClause = "TRANSACTION";
else
node->nod_arg[e_exec_stmt_tran] = PASS1_node(statement, opt);
break;
case nod_exec_stmt_privs:
if (node->nod_arg[e_exec_stmt_privs])
dupClause = "CALLER PRIVILEGES";
else
node->nod_arg[e_exec_stmt_privs] = PASS1_node(statement, opt);
break;
default:
fb_assert(false);
}
if (dupClause) {
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -637,
isc_arg_gds, isc_dsql_duplicate_spec,
isc_arg_string, dupClause, 0);
}
}
}
return pass1_savepoint(statement, node);

View File

@ -399,6 +399,7 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
* resources it used indirectecty via procedures or triggers
*
**************************************/
ExternalAccessList external;
build_external_access(tdbb, external, request);
@ -445,12 +446,28 @@ void CMP_verify_access(thread_db* tdbb, jrd_req* request)
}
}
// Inherit privileges of caller stored procedure or trigger if and only if
// this request is called immediately by caller (check for empty req_caller).
// Currently (in v2.5) this rule will work for EXECUTE STATEMENT only, as
// tra_callback_count incremented only by it.
// When external SP's will be introduced we need to decide if they also can
// inherit caller's privileges
jrd_tra* transaction = tdbb->getTransaction();
const jrd_req *exec_stmt_caller =
(transaction && transaction->tra_callback_count && !request->req_caller) ?
transaction->tra_callback_caller : NULL;
for (const AccessItem* access = request->req_access.begin(); access < request->req_access.end();
access++)
{
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
SCL_check_access(sec_class, access->acc_view_id, NULL, NULL, access->acc_mask,
access->acc_type, access->acc_name, access->acc_r_name);
Firebird::MetaName trgName(exec_stmt_caller ? exec_stmt_caller->req_trg_name : NULL);
Firebird::MetaName prcName(exec_stmt_caller && exec_stmt_caller->req_procedure ?
exec_stmt_caller->req_procedure->prc_name : NULL);
SCL_check_access(sec_class, access->acc_view_id, trgName, prcName,
access->acc_mask, access->acc_type, access->acc_name, access->acc_r_name);
}
}

View File

@ -1646,6 +1646,9 @@ static jrd_nod* execute_statement(thread_db* tdbb, jrd_req* request, jrd_nod* no
const jrd_nod* tra_node = node->nod_arg[node->nod_count + e_exec_stmt_extra_tran];
const EDS::TraScope tra_scope = tra_node ? (EDS::TraScope)(IPTR) tra_node : EDS::traCommon;
const jrd_nod* privs_node = node->nod_arg[node->nod_count + e_exec_stmt_extra_privs];
const bool caller_privs = (privs_node != NULL);
Firebird::string sSql;
get_string(tdbb, request, node->nod_arg[e_exec_stmt_stmt_sql], sSql);
@ -1662,10 +1665,10 @@ static jrd_nod* execute_statement(thread_db* tdbb, jrd_req* request, jrd_nod* no
stmt = conn->createStatement(sSql);
EDS::Transaction* tran = EDS::Transaction::getTransaction(tdbb,
stmt->getConnection(), tra_scope);
EDS::Transaction* tran = EDS::Transaction::getTransaction(tdbb, stmt->getConnection(), tra_scope);
stmt->bindToRequest(request, stmt_ptr);
stmt->setCallerPrivileges(caller_privs);
const Firebird::string* const * inp_names = inputs_names ? inputs_names->begin() : NULL;
stmt->prepare(tdbb, tran, sSql, inputs_names != NULL);

View File

@ -553,7 +553,8 @@ const int e_exec_stmt_extra_inputs = 0;
const int e_exec_stmt_extra_input_names = 1;
const int e_exec_stmt_extra_outputs = 2;
const int e_exec_stmt_extra_tran = 3;
const int e_exec_stmt_extra_count = 4;
const int e_exec_stmt_extra_privs = 4;
const int e_exec_stmt_extra_count = 5;
// Request resources

View File

@ -39,6 +39,7 @@
#include "../exe_proto.h"
#include "../err_proto.h"
#include "../evl_proto.h"
#include "../intl_proto.h"
#include "../mov_proto.h"
using namespace Jrd;
@ -102,10 +103,8 @@ Connection* Manager::getConnection(thread_db *tdbb, const string &dataSource,
if (dataSource.isEmpty())
{
if (user.isEmpty() || user == tdbb->getAttachment()->att_user->usr_user_name)
prvName = INTERNAL_PROVIDER_NAME;
else
prvName = FIREBIRD_PROVIDER_NAME;
prvName = INTERNAL_PROVIDER_NAME;
dbName = tdbb->getDatabase()->dbb_database_name.c_str();
}
else
{
@ -221,6 +220,7 @@ Connection::Connection(Provider &prov) :
PermanentStorage(prov.getPool()),
m_provider(prov),
m_dbName(getPool()),
m_dpb(getPool(), ClumpletReader::Tagged, MAX_DPB_SIZE),
m_transactions(getPool()),
m_statements(getPool()),
m_freeStatements(NULL),
@ -247,6 +247,47 @@ Connection::~Connection()
{
}
void Connection::generateDPB(thread_db *tdbb, ClumpletWriter &dpb,
const string &dbName, const string &user, const string &pwd) const
{
dpb.reset(isc_dpb_version1);
Firebird::string &attUser = tdbb->getAttachment()->att_user->usr_user_name;
if ((m_provider.getFlags() & prvTrustedAuth) &&
(user.isEmpty() || user == attUser) && pwd.isEmpty())
{
dpb.insertString(isc_dpb_trusted_auth, attUser);
}
else
{
if (!user.isEmpty()) {
dpb.insertString(isc_dpb_user_name, user);
}
if (!pwd.isEmpty()) {
dpb.insertString(isc_dpb_password, pwd);
}
}
CharSet* const cs = INTL_charset_lookup(tdbb, tdbb->getAttachment()->att_charset);
if (cs) {
dpb.insertString(isc_dpb_lc_ctype, cs->getName());
}
}
bool Connection::isSameDatabase(thread_db *tdbb, const string &dbName,
const string &user, const string &pwd) const
{
if (m_dbName != dbName)
return false;
ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
generateDPB(tdbb, dpb, dbName, user, pwd);
return m_dpb.simpleCompare(dpb);
}
Transaction* Connection::createTransaction()
{
Transaction* tran = doCreateTransaction();
@ -602,6 +643,8 @@ Statement::Statement(Connection &conn) :
m_stmt_selectable(false),
m_inputs(0),
m_outputs(0),
m_callerPrivileges(false),
m_preparedByReq(NULL),
m_sqlParamNames(getPool()),
m_sqlParamsMap(getPool()),
m_in_buffer(getPool()),
@ -627,12 +670,14 @@ void Statement::prepare(thread_db *tdbb, Transaction *tran, const string& sql, b
fb_assert(!m_active);
// already prepared the same non-empty statement
if (isAllocated() && (m_sql == sql) && (m_sql != ""))
if (isAllocated() && (m_sql == sql) && (m_sql != "") &&
m_preparedByReq == (m_callerPrivileges ? tdbb->getRequest() : NULL))
return;
m_error = false;
m_transaction = tran;
m_sql = "";
m_preparedByReq = NULL;
m_in_buffer.clear();
m_out_buffer.clear();
@ -662,6 +707,7 @@ void Statement::prepare(thread_db *tdbb, Transaction *tran, const string& sql, b
m_sql = sql;
m_sql.trim();
m_preparedByReq = m_callerPrivileges ? tdbb->getRequest() : NULL;
}
void Statement::execute(thread_db* tdbb, Transaction* tran, int in_count,

View File

@ -162,7 +162,7 @@ public:
virtual bool isConnected() const = 0;
virtual bool isSameDatabase(Jrd::thread_db *tdbb, const Firebird::string &dbName,
const Firebird::string &user, const Firebird::string &pwd) const = 0;
const Firebird::string &user, const Firebird::string &pwd) const;
// Search for existing transaction of given scope, may return NULL.
Transaction* findTransaction(Jrd::thread_db *tdbb, TraScope traScope) const;
@ -192,6 +192,10 @@ public:
virtual Blob* createBlob() = 0;
protected:
void generateDPB(Jrd::thread_db *tdbb, Firebird::ClumpletWriter &dpb,
const Firebird::string &dbName, const Firebird::string &user,
const Firebird::string &pwd) const;
virtual Transaction* doCreateTransaction() = 0;
virtual Statement* doCreateStatement() = 0;
void clearStatements(Jrd::thread_db *tdbb);
@ -201,6 +205,7 @@ protected:
Provider &m_provider;
Firebird::string m_dbName;
Firebird::ClumpletWriter m_dpb;
Firebird::Array<Transaction*> m_transactions;
Firebird::Array<Statement*> m_statements;
@ -293,6 +298,8 @@ public:
const Firebird::string& getSql() const { return m_sql; }
void setCallerPrivileges(bool use) { m_callerPrivileges = use; }
bool isActive() const { return m_active; }
bool isAllocated() const { return m_allocated; }
@ -366,6 +373,9 @@ protected:
int m_inputs;
int m_outputs;
bool m_callerPrivileges;
Jrd::jrd_req* m_preparedByReq;
// set in preprocess
ParamNames m_sqlParamNames;
ParamNames m_sqlParamsMap;

View File

@ -28,6 +28,7 @@
#include "../align.h"
#include "../exe.h"
#include "../jrd.h"
#include "../tra.h"
#include "../dsc.h"
#include "../../dsql/dsql.h"
#include "../../dsql/sqlda_pub.h"
@ -114,7 +115,33 @@ void InternalConnection::attach(thread_db *tdbb, const Firebird::string &dbName,
const Firebird::string &user, const Firebird::string &pwd)
{
fb_assert(!m_attachment);
m_attachment = tdbb->getAttachment();
Database* dbb = tdbb->getDatabase();
fb_assert(dbName.isEmpty() || dbName == dbb->dbb_database_name.c_str());
Attachment* attachment = tdbb->getAttachment();
if (user.isEmpty() || user == attachment->att_user->usr_user_name)
{
m_isCurrent = true;
m_attachment = attachment;
}
else
{
m_isCurrent = false;
m_dbName = dbb->dbb_database_name.c_str();
generateDPB(tdbb, m_dpb, m_dbName, user, pwd);
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, *this);
jrd8_attach_database(status, m_dbName.c_str(), &m_attachment,
m_dpb.getBufferLength(), m_dpb.getBuffer());
}
if (status[1]) {
raise(status, tdbb, "attach");
}
}
m_sqlDialect = (m_attachment->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
SQL_DIALECT_V6 : SQL_DIALECT_V5;
}
@ -124,18 +151,47 @@ void InternalConnection::detach(thread_db *tdbb)
clearStatements(tdbb);
fb_assert(m_attachment);
m_attachment = 0;
if (m_isCurrent)
{
m_attachment = 0;
}
else
{
ISC_STATUS_ARRAY status = {0};
{
Attachment* att = m_attachment;
m_attachment = NULL;
EngineCallbackGuard guard(tdbb, *this);
jrd8_detach_database(status, &att);
m_attachment = att;
}
if (status[1]) {
raise(status, tdbb, "dettach");
}
}
fb_assert(!m_attachment)
}
// this internal connection instance is available for the current execution context if it
// a) is current conenction and current thread's attachment is equal to
// this attachment, or
// b) is not current conenction
bool InternalConnection::isAvailable(thread_db *tdbb, TraScope traScope) const
{
return (tdbb->getAttachment() == m_attachment);
return !m_isCurrent ||
m_isCurrent && (tdbb->getAttachment() == m_attachment);
}
bool InternalConnection::isSameDatabase(thread_db *tdbb, const Firebird::string &dbName,
const Firebird::string &user, const Firebird::string &pwd) const
{
return dbName.isEmpty() && user.isEmpty() && (tdbb->getAttachment() == m_attachment);
if (m_isCurrent)
return (tdbb->getAttachment() == m_attachment);
else
return Connection::isSameDatabase(tdbb, dbName, user, pwd);
}
Transaction* InternalConnection::doCreateTransaction()
@ -160,7 +216,7 @@ void InternalTransaction::doStart(ISC_STATUS* status, thread_db *tdbb, ClumpletW
{
fb_assert(!m_transaction);
if (m_scope == traCommon) {
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
m_transaction = tdbb->getTransaction();
}
else
@ -184,7 +240,7 @@ void InternalTransaction::doCommit(ISC_STATUS* status, thread_db *tdbb, bool ret
{
fb_assert(m_transaction);
if (m_scope == traCommon) {
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
m_transaction = 0;
}
else
@ -201,7 +257,7 @@ void InternalTransaction::doRollback(ISC_STATUS* status, thread_db *tdbb, bool r
{
fb_assert(m_transaction);
if (m_scope == traCommon) {
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
m_transaction = 0;
}
else
@ -253,8 +309,14 @@ void InternalStatement::doPrepare(thread_db *tdbb, const string &sql)
{
EngineCallbackGuard guard(tdbb, *this);
jrd_req* save_caller = tran->tra_callback_caller;
tran->tra_callback_caller = m_callerPrivileges ? tdbb->getRequest() : NULL;
jrd8_prepare(status, &tran, &m_request, sql.length(), sql.c_str(),
m_connection.getSqlDialect(), 0, NULL, 0, NULL);
tran->tra_callback_caller = save_caller;
}
if (status[1]) {
raise(status, tdbb, "jrd8_prepare", &sql);

View File

@ -56,7 +56,8 @@ protected:
explicit InternalConnection(InternalProvider &prov) :
Connection(prov),
m_attachment(0)
m_attachment(0),
m_isCurrent(false)
{}
virtual ~InternalConnection();
@ -75,6 +76,8 @@ public:
virtual bool isSameDatabase(Jrd::thread_db *tdbb, const Firebird::string &dbName,
const Firebird::string &user, const Firebird::string &pwd) const;
bool isCurrent() const { return m_isCurrent; }
Jrd::Attachment* getJrdAtt()
{ return m_attachment; }
@ -85,6 +88,7 @@ protected:
virtual Statement* doCreateStatement();
Jrd::Attachment* m_attachment;
bool m_isCurrent;
};

View File

@ -93,8 +93,7 @@ Connection* IscProvider::doCreateConnection()
IscConnection::IscConnection(IscProvider &prov) :
Connection(prov),
m_iscProvider(prov),
m_handle(0),
m_dpb(getPool(), ClumpletReader::Tagged, MAX_DPB_SIZE)
m_handle(0)
{
}
@ -102,34 +101,6 @@ IscConnection::~IscConnection()
{
}
void IscConnection::generateDPB(thread_db *tdbb, ClumpletWriter &dpb,
const string &dbName, const string &user, const string &pwd) const
{
dpb.reset(isc_dpb_version1);
Firebird::string &attUser = tdbb->getAttachment()->att_user->usr_user_name;
if ((m_provider.getFlags() & prvTrustedAuth) &&
(user.isEmpty() || user == attUser) && pwd.isEmpty())
{
dpb.insertString(isc_dpb_trusted_auth, attUser);
}
else
{
if (!user.isEmpty()) {
dpb.insertString(isc_dpb_user_name, user);
}
if (!pwd.isEmpty()) {
dpb.insertString(isc_dpb_password, pwd);
}
}
CharSet* const cs = INTL_charset_lookup(tdbb, tdbb->getAttachment()->att_charset);
if (cs) {
dpb.insertString(isc_dpb_lc_ctype, cs->getName());
}
}
void IscConnection::attach(thread_db *tdbb, const string &dbName, const string &user,
const string &pwd)
{
@ -203,7 +174,7 @@ void IscConnection::detach(thread_db *tdbb)
}
}
// connection is available for the current execution context if it
// this ISC connection instance is available for the current execution context if it
// a) have no active statements or support many active statements
// and
// b) have no active transactions or have active transaction of given
@ -224,18 +195,6 @@ bool IscConnection::isAvailable(thread_db *tdbb, TraScope traScope) const
return true;
}
bool IscConnection::isSameDatabase(thread_db *tdbb, const string &dbName,
const string &user, const string &pwd) const
{
if (m_dbName != dbName)
return false;
ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
generateDPB(tdbb, dpb, dbName, user, pwd);
return m_dpb.simpleCompare(dpb);
}
Blob* IscConnection::createBlob()
{
return new IscBlob(*this);

View File

@ -516,22 +516,14 @@ public:
virtual bool isConnected() const
{ return (m_handle != 0); }
virtual bool isSameDatabase(Jrd::thread_db *tdbb, const Firebird::string &dbName,
const Firebird::string &user, const Firebird::string &pwd) const;
virtual Blob* createBlob();
protected:
virtual Transaction* doCreateTransaction();
virtual Statement* doCreateStatement();
void generateDPB(Jrd::thread_db *tdbb, Firebird::ClumpletWriter &dpb,
const Firebird::string &dbName, const Firebird::string &user,
const Firebird::string &pwd) const;
IscProvider &m_iscProvider;
FB_API_HANDLE m_handle;
Firebird::ClumpletWriter m_dpb;
};

View File

@ -2868,14 +2868,15 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected,
*arg++ = PAR_parse_node(tdbb, csb, VALUE); // e_exec_stmt_data_src
*arg++ = PAR_parse_node(tdbb, csb, VALUE); // e_exec_stmt_user
*arg++ = PAR_parse_node(tdbb, csb, VALUE); // e_exec_stmt_password
const UCHAR tra_mode = BLR_BYTE; // e_exec_stmt_tran
const UCHAR tra_mode = BLR_BYTE; // e_exec_stmt_tran
if (BLR_BYTE != 0) {
// external transaction parameters is not implemented currently
PAR_syntax_error(csb, "external transaction parameters");
}
const UCHAR use_caller_privs = BLR_BYTE; // e_exec_stmt_extra_privs
if (BLR_BYTE) // singleton flag
*arg++ = 0; // e_exec_stmt_proc_block
*arg++ = 0; // e_exec_stmt_proc_block
else
*arg++ = PAR_parse_node(tdbb, csb, STATEMENT); // e_exec_stmt_proc_block
@ -2910,6 +2911,7 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected,
*arg++ = (jrd_nod*) paramNames; // e_exec_stmt_extra_input_names
*arg++ = (jrd_nod*)(IPTR) outputs; // e_exec_stmt_extra_outputs
*arg++ = (jrd_nod*)(IPTR) tra_mode; // e_exec_stmt_extra_tran
*arg++ = (jrd_nod*)(IPTR) use_caller_privs; // e_exec_stmt_extra_privs
}
break;

View File

@ -196,6 +196,7 @@ public:
RuntimeStatistics tra_stats;
Firebird::Array<dsql_req*> tra_open_cursors;
jrd_tra* const tra_outer; // outer transaction of an autonomous transaction
jrd_req* tra_callback_caller; // caller request for execute statement
Firebird::Array<UCHAR> tra_transactions;
EDS::Transaction *tra_ext_common;