8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 03:23:03 +01:00
firebird-mirror/src/jrd/extds/InternalDS.cpp

685 lines
16 KiB
C++
Raw Normal View History

/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Vlad Khorsun
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Vlad Khorsun <hvlad@users.sourceforge.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "fb_types.h"
#include "../common.h"
#include "../../include/fb_blk.h"
#include "../align.h"
#include "../exe.h"
#include "../jrd.h"
#include "../tra.h"
#include "../dsc.h"
#include "../../dsql/dsql.h"
#include "../../dsql/sqlda_pub.h"
#include "../blb_proto.h"
#include "../evl_proto.h"
#include "../exe_proto.h"
#include "../mov_proto.h"
#include "../mov_proto.h"
#include "../PreparedStatement.h"
#include "../Function.h"
#include "InternalDS.h"
using namespace Jrd;
using namespace Firebird;
namespace EDS {
2009-05-15 02:51:21 +02:00
const char* INTERNAL_PROVIDER_NAME = "Internal";
class RegisterInternalProvider
{
public:
RegisterInternalProvider()
{
InternalProvider* provider = new InternalProvider(INTERNAL_PROVIDER_NAME);
Manager::addProvider(provider);
}
};
static RegisterInternalProvider reg;
// InternalProvider
2009-11-04 16:01:34 +01:00
void InternalProvider::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att)
{
if (m_connections.getCount() == 0)
return;
2009-05-15 02:51:21 +02:00
Connection** ptr = m_connections.end();
Connection** begin = m_connections.begin();
2008-04-11 03:38:50 +02:00
for (ptr--; ptr >= begin; ptr--)
{
2009-05-15 02:51:21 +02:00
InternalConnection* conn = (InternalConnection*) *ptr;
if (conn->getJrdAtt() == att)
releaseConnection(tdbb, *conn, false);
}
}
2009-05-15 02:51:21 +02:00
void InternalProvider::getRemoteError(ISC_STATUS* status, string& err) const
{
err = "";
char buff[1024];
2008-04-11 03:38:50 +02:00
const ISC_STATUS* p = status;
const ISC_STATUS* end = status + ISC_STATUS_LENGTH;
while (p < end)
{
const ISC_STATUS code = *p ? p[1] : 0;
if (!fb_interpret(buff, sizeof(buff), &p))
break;
string rem_err;
rem_err.printf("%lu : %s\n", code, buff);
err += rem_err;
}
}
Connection* InternalProvider::doCreateConnection()
{
return new InternalConnection(*this);
}
// InternalConnection
InternalConnection::~InternalConnection()
{
}
2009-05-15 02:51:21 +02:00
void InternalConnection::attach(thread_db* tdbb, const Firebird::string& dbName,
const Firebird::string& user, const Firebird::string& pwd,
const Firebird::string& role)
{
fb_assert(!m_attachment);
Database* dbb = tdbb->getDatabase();
fb_assert(dbName.isEmpty() || dbName == dbb->dbb_database_name.c_str());
2009-11-04 16:01:34 +01:00
Jrd::Attachment* attachment = tdbb->getAttachment();
if ((user.isEmpty() || user == attachment->att_user->usr_user_name) &&
pwd.isEmpty() &&
(role.isEmpty() || role == attachment->att_user->usr_sql_role_name))
{
m_isCurrent = true;
m_attachment = attachment;
}
else
{
m_isCurrent = false;
m_dbName = dbb->dbb_database_name.c_str();
generateDPB(tdbb, m_dpb, user, pwd, role);
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, *this);
jrd8_attach_database(status, 0, m_dbName.c_str(), &m_attachment,
m_dpb.getBufferLength(), m_dpb.getBuffer());
}
if (status[1]) {
raise(status, tdbb, "attach");
}
}
2008-12-05 02:20:14 +01:00
m_sqlDialect = (m_attachment->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
SQL_DIALECT_V6 : SQL_DIALECT_V5;
}
2009-05-15 02:51:21 +02:00
void InternalConnection::doDetach(thread_db* tdbb)
{
fb_assert(m_attachment);
if (m_isCurrent)
{
m_attachment = 0;
}
else
{
ISC_STATUS_ARRAY status = {0};
2008-06-09 03:34:33 +02:00
{ // scope
2009-11-04 16:01:34 +01:00
Jrd::Attachment* att = m_attachment;
m_attachment = NULL;
EngineCallbackGuard guard(tdbb, *this);
jrd8_detach_database(status, &att);
2008-12-05 02:20:14 +01:00
m_attachment = att;
}
2008-06-09 03:34:33 +02:00
if (status[1] == isc_att_shutdown)
{
2009-03-14 20:17:34 +01:00
m_attachment = NULL;
fb_utils::init_status(status);
}
2009-04-04 18:39:31 +02:00
if (status[1])
{
raise(status, tdbb, "detach");
}
}
fb_assert(!m_attachment)
}
2009-05-15 02:51:21 +02:00
bool InternalConnection::cancelExecution(thread_db* tdbb)
{
if (m_isCurrent)
return true;
2008-12-01 10:21:31 +01:00
ISC_STATUS_ARRAY status = {0, 0, 0};
jrd8_cancel_operation(status, &m_attachment, fb_cancel_raise);
return (status[1] == 0);
}
// 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
2009-05-15 02:51:21 +02:00
bool InternalConnection::isAvailable(thread_db* tdbb, TraScope /*traScope*/) const
{
2008-12-05 02:20:14 +01:00
return !m_isCurrent ||
2008-06-09 03:34:33 +02:00
(m_isCurrent && (tdbb->getAttachment() == m_attachment));
}
2009-05-15 02:51:21 +02:00
bool InternalConnection::isSameDatabase(thread_db* tdbb, const Firebird::string& dbName,
const Firebird::string& user, const Firebird::string& pwd,
const Firebird::string& role) const
{
if (m_isCurrent)
{
2009-11-05 09:29:33 +01:00
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));
}
2009-09-03 13:17:46 +02:00
return Connection::isSameDatabase(tdbb, dbName, user, pwd, role);
}
Transaction* InternalConnection::doCreateTransaction()
{
return new InternalTransaction(*this);
}
Statement* InternalConnection::doCreateStatement()
{
return new InternalStatement(*this);
}
Blob* InternalConnection::createBlob()
{
return new InternalBlob(*this);
}
// InternalTransaction()
2009-05-15 02:51:21 +02:00
void InternalTransaction::doStart(ISC_STATUS* status, thread_db* tdbb, ClumpletWriter& tpb)
{
fb_assert(!m_transaction);
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
m_transaction = tdbb->getTransaction();
}
else
{
2009-11-04 16:01:34 +01:00
Jrd::Attachment* att = m_IntConnection.getJrdAtt();
EngineCallbackGuard guard(tdbb, *this);
jrd8_start_transaction(status, 0, &m_transaction, 1, &att, //// FIXME: public_handle
tpb.getBufferLength(), tpb.getBuffer());
}
}
void InternalTransaction::doPrepare(ISC_STATUS* /*status*/, thread_db* /*tdbb*/,
int /*info_len*/, const char* /*info*/)
{
fb_assert(m_transaction);
fb_assert(false);
}
void InternalTransaction::doCommit(ISC_STATUS* status, thread_db* tdbb, bool retain)
{
fb_assert(m_transaction);
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
if (!retain) {
2009-03-14 20:17:34 +01:00
m_transaction = NULL;
}
}
else
{
EngineCallbackGuard guard(tdbb, *this);
if (retain)
jrd8_commit_retaining(status, &m_transaction);
else
jrd8_commit_transaction(status, &m_transaction);
}
}
2009-05-15 02:51:21 +02:00
void InternalTransaction::doRollback(ISC_STATUS* status, thread_db* tdbb, bool retain)
{
fb_assert(m_transaction);
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
if (!retain) {
2009-03-14 20:17:34 +01:00
m_transaction = NULL;
}
}
else
{
EngineCallbackGuard guard(tdbb, *this);
if (retain)
jrd8_rollback_retaining(status, &m_transaction);
else
jrd8_rollback_transaction(status, &m_transaction);
}
if (status[1] == isc_att_shutdown && !retain)
{
2009-03-14 20:17:34 +01:00
m_transaction = NULL;
fb_utils::init_status(status);
}
}
2008-12-05 02:20:14 +01:00
// InternalStatement
2009-05-15 02:51:21 +02:00
InternalStatement::InternalStatement(InternalConnection& conn) :
Statement(conn),
m_intConnection(conn),
m_intTransaction(0),
m_request(0),
m_inBlr(getPool()),
m_outBlr(getPool())
{
}
InternalStatement::~InternalStatement()
{
}
2009-05-15 02:51:21 +02:00
void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
{
m_inBlr.clear();
m_outBlr.clear();
2009-11-04 16:01:34 +01:00
Jrd::Attachment* att = m_intConnection.getJrdAtt();
2009-05-15 02:51:21 +02:00
jrd_tra* tran = getIntTransaction()->getJrdTran();
ISC_STATUS_ARRAY status = {0};
2008-12-05 02:20:14 +01:00
if (!m_request)
{
fb_assert(!m_allocated);
EngineCallbackGuard guard(tdbb, *this);
jrd8_allocate_statement(status, &att, &m_request);
m_allocated = (m_request != 0);
}
if (status[1]) {
raise(status, tdbb, "jrd8_allocate_statement", &sql);
}
{
EngineCallbackGuard guard(tdbb, *this);
2008-06-09 03:34:33 +02:00
CallerName save_caller_name(tran->tra_caller_name);
if (m_callerPrivileges)
{
jrd_req* request = tdbb->getRequest();
CallerName callerName;
if (request && request->req_trg_name.hasData())
tran->tra_caller_name = CallerName(obj_trigger, request->req_trg_name);
else if (request && request->req_procedure &&
request->req_procedure->getName().identifier.hasData())
{
if (request->req_procedure->getName().qualifier.isEmpty())
tran->tra_caller_name = CallerName(obj_procedure, request->req_procedure->getName().identifier);
else
tran->tra_caller_name = CallerName(obj_package_header, request->req_procedure->getName().qualifier);
}
else if (request && request->req_function &&
request->req_function->getName().identifier.hasData())
{
if (request->req_function->getName().qualifier.isEmpty())
tran->tra_caller_name = CallerName(obj_udf, request->req_function->getName().identifier);
else
tran->tra_caller_name = CallerName(obj_package_header, request->req_function->getName().qualifier);
}
else
tran->tra_caller_name = CallerName();
}
2008-12-05 02:20:14 +01:00
jrd8_prepare(status, &tran, &m_request, sql.length(), sql.c_str(),
m_connection.getSqlDialect(), 0, NULL, 0, NULL);
tran->tra_caller_name = save_caller_name;
}
if (status[1]) {
raise(status, tdbb, "jrd8_prepare", &sql);
}
2009-12-21 00:41:48 +01:00
const DsqlCompiledStatement* statement = m_request->getStatement();
if (statement->getSendMsg()) {
try {
PreparedStatement::parseDsqlMessage(statement->getSendMsg(), m_inDescs,
m_inBlr, m_in_buffer);
m_inputs = m_inDescs.getCount() / 2;
}
catch (const Exception&) {
raise(tdbb->tdbb_status_vector, tdbb, "parse input message", &sql);
}
}
else {
m_inputs = 0;
}
if (statement->getReceiveMsg()) {
try {
PreparedStatement::parseDsqlMessage(statement->getReceiveMsg(), m_outDescs,
m_outBlr, m_out_buffer);
m_outputs = m_outDescs.getCount() / 2;
}
catch (const Exception&) {
raise(tdbb->tdbb_status_vector, tdbb, "parse output message", &sql);
}
}
else {
m_outputs = 0;
}
m_stmt_selectable = false;
switch (statement->getType())
{
case DsqlCompiledStatement::TYPE_SELECT:
case DsqlCompiledStatement::TYPE_SELECT_UPD:
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
m_stmt_selectable = true;
break;
2008-12-05 02:20:14 +01:00
case DsqlCompiledStatement::TYPE_START_TRANS:
case DsqlCompiledStatement::TYPE_COMMIT:
case DsqlCompiledStatement::TYPE_ROLLBACK:
case DsqlCompiledStatement::TYPE_COMMIT_RETAIN:
case DsqlCompiledStatement::TYPE_ROLLBACK_RETAIN:
case DsqlCompiledStatement::TYPE_CREATE_DB:
ERR_build_status(status, Arg::Gds(isc_eds_expl_tran_ctrl));
raise(status, tdbb, "jrd8_prepare", &sql);
break;
case DsqlCompiledStatement::TYPE_INSERT:
case DsqlCompiledStatement::TYPE_DELETE:
case DsqlCompiledStatement::TYPE_UPDATE:
case DsqlCompiledStatement::TYPE_UPDATE_CURSOR:
case DsqlCompiledStatement::TYPE_DELETE_CURSOR:
case DsqlCompiledStatement::TYPE_DDL:
case DsqlCompiledStatement::TYPE_GET_SEGMENT:
case DsqlCompiledStatement::TYPE_PUT_SEGMENT:
case DsqlCompiledStatement::TYPE_EXEC_PROCEDURE:
case DsqlCompiledStatement::TYPE_SET_GENERATOR:
case DsqlCompiledStatement::TYPE_SAVEPOINT:
case DsqlCompiledStatement::TYPE_EXEC_BLOCK:
break;
}
}
2009-05-15 02:51:21 +02:00
void InternalStatement::doExecute(thread_db* tdbb)
{
2009-05-15 02:51:21 +02:00
jrd_tra* transaction = getIntTransaction()->getJrdTran();
2008-12-05 02:20:14 +01:00
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, *this);
2008-12-05 02:20:14 +01:00
jrd8_execute(status, &transaction, &m_request,
m_inBlr.getCount(), reinterpret_cast<const SCHAR*>(m_inBlr.begin()),
0, m_in_buffer.getCount(), reinterpret_cast<const SCHAR*>(m_in_buffer.begin()),
m_outBlr.getCount(), (SCHAR*) m_outBlr.begin(),
0, m_out_buffer.getCount(), (SCHAR*) m_out_buffer.begin());
}
if (status[1]) {
raise(status, tdbb, "jrd8_execute");
}
}
2009-05-15 02:51:21 +02:00
void InternalStatement::doOpen(thread_db* tdbb)
{
2009-05-15 02:51:21 +02:00
jrd_tra* transaction = getIntTransaction()->getJrdTran();
2008-12-05 02:20:14 +01:00
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, *this);
2008-12-05 02:20:14 +01:00
jrd8_execute(status, &transaction, &m_request,
m_inBlr.getCount(), reinterpret_cast<const SCHAR*>(m_inBlr.begin()),
0, m_in_buffer.getCount(), reinterpret_cast<const SCHAR*>(m_in_buffer.begin()),
0, NULL, 0, 0, NULL);
}
if (status[1]) {
raise(status, tdbb, "jrd8_execute");
}
}
2009-05-15 02:51:21 +02:00
bool InternalStatement::doFetch(thread_db* tdbb)
{
ISC_STATUS_ARRAY status = {0};
ISC_STATUS res = 0;
{
EngineCallbackGuard guard(tdbb, *this);
2008-12-05 02:20:14 +01:00
res = jrd8_fetch(status, &m_request,
m_outBlr.getCount(), reinterpret_cast<const SCHAR*>(m_outBlr.begin()), 0,
m_out_buffer.getCount(), (SCHAR*) m_out_buffer.begin());
}
if (status[1]) {
raise(status, tdbb, "jrd8_fetch");
}
return (res != 100);
}
2009-05-15 02:51:21 +02:00
void InternalStatement::doClose(thread_db* tdbb, bool drop)
{
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, *this);
jrd8_free_statement(status, &m_request, drop ? DSQL_drop : DSQL_close);
m_allocated = (m_request != 0);
}
2008-12-05 02:20:14 +01:00
if (status[1])
{
m_allocated = m_request = 0;
raise(status, tdbb, "jrd8_free_statement");
}
}
2009-05-15 02:51:21 +02:00
void InternalStatement::putExtBlob(thread_db* tdbb, dsc& src, dsc& dst)
{
if (m_transaction->getScope() == traCommon)
MOV_move(tdbb, &src, &dst);
else
Statement::putExtBlob(tdbb, src, dst);
}
2009-05-15 02:51:21 +02:00
void InternalStatement::getExtBlob(thread_db* tdbb, const dsc& src, dsc& dst)
{
fb_assert(dst.dsc_length == src.dsc_length);
fb_assert(dst.dsc_length == sizeof(bid));
if (m_transaction->getScope() == traCommon)
memcpy(dst.dsc_address, src.dsc_address, sizeof(bid));
else
Statement::getExtBlob(tdbb, src, dst);
}
2008-12-05 02:20:14 +01:00
// InternalBlob
2009-05-15 02:51:21 +02:00
InternalBlob::InternalBlob(InternalConnection& conn) :
Blob(conn),
m_connection(conn),
m_blob(NULL)
{
m_blob_id.clear();
}
InternalBlob::~InternalBlob()
{
fb_assert(!m_blob);
}
2009-05-15 02:51:21 +02:00
void InternalBlob::open(thread_db* tdbb, Transaction& tran, const dsc& desc, const UCharBuffer* bpb)
{
fb_assert(!m_blob);
fb_assert(sizeof(m_blob_id) == desc.dsc_length);
2009-11-04 16:01:34 +01:00
Jrd::Attachment* att = m_connection.getJrdAtt();
jrd_tra* transaction = ((InternalTransaction&) tran).getJrdTran();
memcpy(&m_blob_id, desc.dsc_address, sizeof(m_blob_id));
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, m_connection);
USHORT bpb_len = bpb ? bpb->getCount() : 0;
const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL;
2008-12-05 02:20:14 +01:00
jrd8_open_blob2(status, &att, &transaction, &m_blob, &m_blob_id,
bpb_len, bpb_buff);
}
if (status[1]) {
m_connection.raise(status, tdbb, "jrd8_open_blob2");
}
fb_assert(m_blob);
}
2009-05-15 02:51:21 +02:00
void InternalBlob::create(thread_db* tdbb, Transaction& tran, dsc& desc, const UCharBuffer* bpb)
{
fb_assert(!m_blob);
fb_assert(sizeof(m_blob_id) == desc.dsc_length);
2009-11-04 16:01:34 +01:00
Jrd::Attachment* att = m_connection.getJrdAtt();
jrd_tra* transaction = ((InternalTransaction&) tran).getJrdTran();
m_blob_id.clear();
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, m_connection);
2009-05-17 13:20:43 +02:00
const USHORT bpb_len = bpb ? bpb->getCount() : 0;
const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL;
2008-12-05 02:20:14 +01:00
jrd8_create_blob2(status, &att, &transaction, &m_blob, &m_blob_id,
bpb_len, bpb_buff);
memcpy(desc.dsc_address, &m_blob_id, sizeof(m_blob_id));
}
if (status[1]) {
m_connection.raise(status, tdbb, "jrd8_create_blob2");
}
fb_assert(m_blob);
}
USHORT InternalBlob::read(thread_db* tdbb, UCHAR* buff, USHORT len)
{
fb_assert(m_blob);
USHORT result = 0;
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, m_connection);
jrd8_get_segment(status, &m_blob, &result, len, buff);
}
2009-01-14 09:22:32 +01:00
switch (status[1])
{
case isc_segstr_eof:
fb_assert(result == 0);
2009-01-14 09:22:32 +01:00
break;
case isc_segment:
case 0:
break;
default:
m_connection.raise(status, tdbb, "jrd8_get_segment");
}
return result;
}
void InternalBlob::write(thread_db* tdbb, const UCHAR* buff, USHORT len)
{
fb_assert(m_blob);
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, m_connection);
jrd8_put_segment(status, &m_blob, len, buff);
}
if (status[1]) {
m_connection.raise(status, tdbb, "jrd8_put_segment");
}
}
2009-05-15 02:51:21 +02:00
void InternalBlob::close(thread_db* tdbb)
{
fb_assert(m_blob);
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, m_connection);
jrd8_close_blob(status, &m_blob);
}
if (status[1]) {
m_connection.raise(status, tdbb, "jrd8_close_blob");
}
fb_assert(!m_blob);
}
2009-05-15 02:51:21 +02:00
void InternalBlob::cancel(thread_db* tdbb)
{
if (!m_blob) {
return;
}
ISC_STATUS_ARRAY status = {0};
{
EngineCallbackGuard guard(tdbb, m_connection);
jrd8_cancel_blob(status, &m_blob);
}
if (status[1]) {
m_connection.raise(status, tdbb, "jrd8_cancel_blob");
}
fb_assert(!m_blob);
}
2008-04-11 03:38:50 +02:00
} // namespace EDS