2008-04-09 22:18:47 +02:00
|
|
|
/*
|
|
|
|
* 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"
|
2008-06-08 22:42:27 +02:00
|
|
|
#include "../tra.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/dsc.h"
|
2008-04-09 22:18:47 +02:00
|
|
|
#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"
|
2009-12-21 18:43:01 +01:00
|
|
|
#include "../Function.h"
|
2008-04-09 22:18:47 +02:00
|
|
|
|
|
|
|
#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";
|
2008-04-09 22:18:47 +02:00
|
|
|
|
|
|
|
class RegisterInternalProvider
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RegisterInternalProvider()
|
|
|
|
{
|
|
|
|
InternalProvider* provider = new InternalProvider(INTERNAL_PROVIDER_NAME);
|
2008-04-12 23:20:26 +02:00
|
|
|
Manager::addProvider(provider);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static RegisterInternalProvider reg;
|
|
|
|
|
|
|
|
// InternalProvider
|
|
|
|
|
2009-11-04 16:01:34 +01:00
|
|
|
void InternalProvider::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2008-04-09 22:18:47 +02:00
|
|
|
for (ptr--; ptr >= begin; ptr--)
|
|
|
|
{
|
2009-05-15 02:51:21 +02:00
|
|
|
InternalConnection* conn = (InternalConnection*) *ptr;
|
2008-04-09 22:18:47 +02:00
|
|
|
if (conn->getJrdAtt() == att)
|
|
|
|
releaseConnection(tdbb, *conn, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
void InternalProvider::getRemoteError(const ISC_STATUS* status, string& err) const
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
err = "";
|
|
|
|
|
2009-11-05 23:42:46 +01:00
|
|
|
char buff[1024];
|
2008-04-11 03:38:50 +02:00
|
|
|
const ISC_STATUS* p = status;
|
|
|
|
const ISC_STATUS* end = status + ISC_STATUS_LENGTH;
|
|
|
|
|
2008-04-09 22:18:47 +02:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
// Status helper
|
|
|
|
class IntStatus : public LocalStatus
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
IntStatus(ISC_STATUS *p)
|
|
|
|
: LocalStatus(), v(p) { }
|
|
|
|
~IntStatus()
|
|
|
|
{
|
|
|
|
if (v)
|
|
|
|
{
|
|
|
|
const ISC_STATUS *s = get();
|
|
|
|
fb_utils::copyStatus(v, ISC_STATUS_LENGTH, s, fb_utils::statusLength(s));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
ISC_STATUS *v;
|
|
|
|
};
|
|
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(!m_attachment);
|
2008-06-08 22:42:27 +02:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
|
|
|
fb_assert(dbName.isEmpty() || dbName == dbb->dbb_database_name.c_str());
|
|
|
|
|
2010-03-18 12:51:21 +01:00
|
|
|
// Don't wrap raised errors. This is needed for backward compatibility.
|
|
|
|
setWrapErrors(false);
|
|
|
|
|
2009-11-04 16:01:34 +01:00
|
|
|
Jrd::Attachment* attachment = tdbb->getAttachment();
|
2009-05-14 12:21:47 +02:00
|
|
|
if ((user.isEmpty() || user == attachment->att_user->usr_user_name) &&
|
2009-11-04 15:49:15 +01:00
|
|
|
pwd.isEmpty() &&
|
2009-05-14 12:21:47 +02:00
|
|
|
(role.isEmpty() || role == attachment->att_user->usr_sql_role_name))
|
2008-06-08 22:42:27 +02:00
|
|
|
{
|
|
|
|
m_isCurrent = true;
|
|
|
|
m_attachment = attachment;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_isCurrent = false;
|
|
|
|
m_dbName = dbb->dbb_database_name.c_str();
|
2009-05-14 12:21:47 +02:00
|
|
|
generateDPB(tdbb, m_dpb, user, pwd, role);
|
2008-06-08 22:42:27 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
|
|
|
FbApi::Attachment* a;
|
2008-06-08 22:42:27 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
currentProvider()->attachDatabase(&a, &status, 0, m_dbName.c_str(),
|
2008-06-08 22:42:27 +02:00
|
|
|
m_dpb.getBufferLength(), m_dpb.getBuffer());
|
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-06-08 22:42:27 +02:00
|
|
|
raise(status, tdbb, "attach");
|
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
m_attachment = reinterpret_cast<Jrd::Attachment*>(a);
|
2008-06-08 22:42:27 +02:00
|
|
|
}
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
m_sqlDialect = (m_attachment->att_database->dbb_flags & DBB_DB_SQL_dialect_3) ?
|
2008-04-09 22:18:47 +02:00
|
|
|
SQL_DIALECT_V6 : SQL_DIALECT_V5;
|
|
|
|
}
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalConnection::doDetach(thread_db* tdbb)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_attachment);
|
2008-11-17 13:30:28 +01:00
|
|
|
|
2008-06-08 22:42:27 +02:00
|
|
|
if (m_isCurrent)
|
|
|
|
{
|
|
|
|
m_attachment = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
|
|
|
Jrd::Attachment* att = m_attachment;
|
|
|
|
m_attachment = NULL;
|
2008-06-08 22:42:27 +02:00
|
|
|
|
2008-06-09 03:34:33 +02:00
|
|
|
{ // scope
|
2008-06-08 22:42:27 +02:00
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
att->detach(&status);
|
2008-06-08 22:42:27 +02:00
|
|
|
}
|
2008-06-09 03:34:33 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
if (status.get()[1] == isc_att_shutdown)
|
2009-03-13 14:17:20 +01:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
status.init();
|
2009-03-13 14:17:20 +01:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess())
|
2009-03-13 14:17:20 +01:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
m_attachment = att;
|
2008-11-17 13:30:28 +01:00
|
|
|
raise(status, tdbb, "detach");
|
2008-06-08 22:42:27 +02:00
|
|
|
}
|
|
|
|
}
|
2008-11-17 13:30:28 +01:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
fb_assert(!m_attachment);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
bool InternalConnection::cancelExecution(thread_db* tdbb)
|
2008-11-28 00:06:48 +01:00
|
|
|
{
|
|
|
|
if (m_isCurrent)
|
|
|
|
return true;
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
|
|
|
m_attachment->cancelOperation(&status, fb_cancel_raise);
|
|
|
|
return (status.isSuccess());
|
2008-11-28 00:06:48 +01:00
|
|
|
}
|
|
|
|
|
2008-06-08 22:42:27 +02:00
|
|
|
// 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-04-09 22:18:47 +02:00
|
|
|
{
|
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));
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
|
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
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
2008-06-08 22:42:27 +02:00
|
|
|
if (m_isCurrent)
|
2009-11-04 15:49:15 +01:00
|
|
|
{
|
2009-11-05 09:29:33 +01:00
|
|
|
const UserId* attUser = m_attachment->att_user;
|
2009-11-04 15:49:15 +01:00
|
|
|
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);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(!m_transaction);
|
|
|
|
|
2008-06-08 22:42:27 +02:00
|
|
|
if (m_scope == traCommon && m_IntConnection.isCurrent()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
m_transaction = tdbb->getTransaction();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-11-04 16:01:34 +01:00
|
|
|
Jrd::Attachment* att = m_IntConnection.getJrdAtt();
|
2008-04-09 22:18:47 +02:00
|
|
|
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
IntStatus s(status);
|
|
|
|
m_transaction = reinterpret_cast<jrd_tra*>
|
|
|
|
(att->startTransaction(&s, tpb.getBufferLength(), tpb.getBuffer(), NULL));
|
|
|
|
//// FIXME: public_handle
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-01 19:21:36 +02:00
|
|
|
void InternalTransaction::doPrepare(ISC_STATUS* /*status*/, thread_db* /*tdbb*/,
|
|
|
|
int /*info_len*/, const char* /*info*/)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_transaction);
|
|
|
|
fb_assert(false);
|
|
|
|
}
|
|
|
|
|
2009-05-01 19:21:36 +02:00
|
|
|
void InternalTransaction::doCommit(ISC_STATUS* status, thread_db* tdbb, bool retain)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_transaction);
|
2008-08-12 08:18:06 +02:00
|
|
|
|
2010-04-29 07:13:03 +02:00
|
|
|
if (m_scope == traCommon && m_IntConnection.isCurrent())
|
|
|
|
{
|
2008-08-12 08:18:06 +02:00
|
|
|
if (!retain) {
|
2009-03-14 20:17:34 +01:00
|
|
|
m_transaction = NULL;
|
2008-08-12 08:18:06 +02:00
|
|
|
}
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
IntStatus s(status);
|
2008-04-09 22:18:47 +02:00
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
|
|
|
if (retain)
|
2010-10-12 10:02:57 +02:00
|
|
|
m_transaction->commitRetaining(&s);
|
2008-04-09 22:18:47 +02:00
|
|
|
else
|
2010-10-12 10:02:57 +02:00
|
|
|
m_transaction->commit(&s);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalTransaction::doRollback(ISC_STATUS* status, thread_db* tdbb, bool retain)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_transaction);
|
|
|
|
|
2010-04-29 07:13:03 +02:00
|
|
|
if (m_scope == traCommon && m_IntConnection.isCurrent())
|
|
|
|
{
|
2008-08-12 08:18:06 +02:00
|
|
|
if (!retain) {
|
2009-03-14 20:17:34 +01:00
|
|
|
m_transaction = NULL;
|
2008-08-12 08:18:06 +02:00
|
|
|
}
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
IntStatus s(status);
|
2008-04-09 22:18:47 +02:00
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
|
|
|
if (retain)
|
2010-10-12 10:02:57 +02:00
|
|
|
m_transaction->rollbackRetaining(&s);
|
2008-04-09 22:18:47 +02:00
|
|
|
else
|
2010-10-12 10:02:57 +02:00
|
|
|
m_transaction->rollback(&s);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2009-03-13 14:17:20 +01:00
|
|
|
|
|
|
|
if (status[1] == isc_att_shutdown && !retain)
|
|
|
|
{
|
2009-03-14 20:17:34 +01:00
|
|
|
m_transaction = NULL;
|
2009-03-13 14:17:20 +01:00
|
|
|
fb_utils::init_status(status);
|
|
|
|
}
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
// InternalStatement
|
2008-04-09 22:18:47 +02:00
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
InternalStatement::InternalStatement(InternalConnection& conn) :
|
2008-04-09 22:18:47 +02:00
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
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();
|
2008-04-09 22:18:47 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-12-05 02:20:14 +01:00
|
|
|
if (!m_request)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(!m_allocated);
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_request = reinterpret_cast<Jrd::dsql_req*>(att->allocateStatement(&status));
|
2008-04-09 22:18:47 +02:00
|
|
|
m_allocated = (m_request != 0);
|
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
raise(status, tdbb, "jrd8_allocate_statement", &sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2008-06-09 03:34:33 +02:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
CallerName save_caller_name(tran->tra_caller_name);
|
|
|
|
|
|
|
|
if (m_callerPrivileges)
|
|
|
|
{
|
|
|
|
jrd_req* request = tdbb->getRequest();
|
2010-04-19 00:19:11 +02:00
|
|
|
JrdStatement* statement = request ? request->getStatement() : NULL;
|
2009-10-21 02:42:38 +02:00
|
|
|
CallerName callerName;
|
2009-12-30 02:40:39 +01:00
|
|
|
const Routine* routine;
|
2009-10-21 02:42:38 +02:00
|
|
|
|
2010-04-29 07:13:03 +02:00
|
|
|
if (statement && statement->triggerName.hasData())
|
2010-04-19 00:19:11 +02:00
|
|
|
tran->tra_caller_name = CallerName(obj_trigger, statement->triggerName);
|
2010-04-29 07:13:03 +02:00
|
|
|
else if (statement && (routine = statement->getRoutine()) &&
|
2009-12-30 02:40:39 +01:00
|
|
|
routine->getName().identifier.hasData())
|
2009-10-21 02:42:38 +02:00
|
|
|
{
|
2010-01-27 05:32:27 +01:00
|
|
|
if (routine->getName().package.isEmpty())
|
2009-12-30 02:40:39 +01:00
|
|
|
{
|
|
|
|
tran->tra_caller_name = CallerName(routine->getObjectType(),
|
|
|
|
routine->getName().identifier);
|
|
|
|
}
|
2009-10-21 02:42:38 +02:00
|
|
|
else
|
2009-12-30 02:40:39 +01:00
|
|
|
{
|
|
|
|
tran->tra_caller_name = CallerName(obj_package_header,
|
2010-01-27 05:32:27 +01:00
|
|
|
routine->getName().package);
|
2009-12-30 02:40:39 +01:00
|
|
|
}
|
2009-12-21 18:43:01 +01:00
|
|
|
}
|
2009-10-21 02:42:38 +02:00
|
|
|
else
|
|
|
|
tran->tra_caller_name = CallerName();
|
|
|
|
}
|
2008-06-08 22:42:27 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
m_request = reinterpret_cast<Jrd::dsql_req*>(m_request->
|
|
|
|
prepare(&status, tran, sql.length(), sql.c_str(),
|
|
|
|
m_connection.getSqlDialect(), 0, NULL, 0, NULL));
|
2008-06-08 22:42:27 +02:00
|
|
|
|
2009-10-21 02:42:38 +02:00
|
|
|
tran->tra_caller_name = save_caller_name;
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
raise(status, tdbb, "jrd8_prepare", &sql);
|
|
|
|
}
|
|
|
|
|
2009-12-21 00:41:48 +01:00
|
|
|
const DsqlCompiledStatement* statement = m_request->getStatement();
|
2009-12-20 22:01:10 +01:00
|
|
|
|
2010-04-29 07:13:03 +02:00
|
|
|
if (statement->getSendMsg())
|
|
|
|
{
|
2008-04-09 22:18:47 +02:00
|
|
|
try {
|
2009-12-22 16:36:10 +01:00
|
|
|
PreparedStatement::parseDsqlMessage(statement->getSendMsg(), m_inDescs,
|
|
|
|
m_inBlr, m_in_buffer);
|
2008-04-09 22:18:47 +02:00
|
|
|
m_inputs = m_inDescs.getCount() / 2;
|
|
|
|
}
|
|
|
|
catch (const Exception&) {
|
|
|
|
raise(tdbb->tdbb_status_vector, tdbb, "parse input message", &sql);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_inputs = 0;
|
|
|
|
}
|
|
|
|
|
2010-04-29 07:13:03 +02:00
|
|
|
if (statement->getReceiveMsg())
|
|
|
|
{
|
2008-04-09 22:18:47 +02:00
|
|
|
try {
|
2009-12-22 16:36:10 +01:00
|
|
|
PreparedStatement::parseDsqlMessage(statement->getReceiveMsg(), m_outDescs,
|
|
|
|
m_outBlr, m_out_buffer);
|
2008-04-09 22:18:47 +02:00
|
|
|
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;
|
2009-12-23 01:57:08 +01:00
|
|
|
|
|
|
|
switch (statement->getType())
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
2009-12-23 01:57:08 +01:00
|
|
|
case DsqlCompiledStatement::TYPE_SELECT:
|
|
|
|
case DsqlCompiledStatement::TYPE_SELECT_UPD:
|
|
|
|
case DsqlCompiledStatement::TYPE_SELECT_BLOCK:
|
2008-04-09 22:18:47 +02:00
|
|
|
m_stmt_selectable = true;
|
|
|
|
break;
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2009-12-23 01:57:08 +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:
|
2010-10-12 10:02:57 +02:00
|
|
|
status.set(Arg::Gds(isc_eds_expl_tran_ctrl).value());
|
2009-09-02 12:46:43 +02:00
|
|
|
raise(status, tdbb, "jrd8_prepare", &sql);
|
2008-04-09 22:18:47 +02:00
|
|
|
break;
|
|
|
|
|
2009-12-23 01:57:08 +01:00
|
|
|
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:
|
2008-04-09 22:18:47 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalStatement::doExecute(thread_db* tdbb)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
2009-05-15 02:51:21 +02:00
|
|
|
jrd_tra* transaction = getIntTransaction()->getJrdTran();
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_request->executeMessage(&status, transaction,
|
|
|
|
m_inBlr.getCount(), m_inBlr.begin(),
|
|
|
|
0, m_in_buffer.getCount(), m_in_buffer.begin(),
|
|
|
|
m_outBlr.getCount(), m_outBlr.begin(),
|
|
|
|
0, m_out_buffer.getCount(), m_out_buffer.begin());
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
raise(status, tdbb, "jrd8_execute");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalStatement::doOpen(thread_db* tdbb)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
2009-05-15 02:51:21 +02:00
|
|
|
jrd_tra* transaction = getIntTransaction()->getJrdTran();
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_request->executeMessage(&status, transaction,
|
|
|
|
m_inBlr.getCount(), m_inBlr.begin(),
|
|
|
|
0, m_in_buffer.getCount(), m_in_buffer.begin(),
|
2008-04-09 22:18:47 +02:00
|
|
|
0, NULL, 0, 0, NULL);
|
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
|
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
raise(status, tdbb, "jrd8_execute");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
bool InternalStatement::doFetch(thread_db* tdbb)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
|
|
|
int res = 0;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
res = m_request->fetchMessage(&status,
|
|
|
|
m_outBlr.getCount(), m_outBlr.begin(), 0,
|
|
|
|
m_out_buffer.getCount(), m_out_buffer.begin());
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
raise(status, tdbb, "jrd8_fetch");
|
|
|
|
}
|
|
|
|
|
|
|
|
return (res != 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalStatement::doClose(thread_db* tdbb, bool drop)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, *this);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_request->free(&status, drop ? DSQL_drop : DSQL_close);
|
|
|
|
if (drop)
|
|
|
|
{
|
|
|
|
m_allocated = 0;
|
|
|
|
m_request = NULL;
|
|
|
|
}
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess())
|
2008-11-28 00:06:48 +01:00
|
|
|
{
|
|
|
|
m_allocated = m_request = 0;
|
2008-04-09 22:18:47 +02:00
|
|
|
raise(status, tdbb, "jrd8_free_statement");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalStatement::putExtBlob(thread_db* tdbb, dsc& src, dsc& dst)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
if (m_transaction->getScope() == traCommon)
|
2008-04-13 10:11:16 +02:00
|
|
|
MOV_move(tdbb, &src, &dst);
|
2008-04-09 22:18:47 +02:00
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
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
|
2008-04-09 22:18:47 +02:00
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
InternalBlob::InternalBlob(InternalConnection& conn) :
|
2008-04-09 22:18:47 +02:00
|
|
|
Blob(conn),
|
|
|
|
m_connection(conn),
|
|
|
|
m_blob(NULL)
|
|
|
|
{
|
2010-10-12 10:02:57 +02:00
|
|
|
memset(&m_blob_id, 0, sizeof(m_blob_id));
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
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();
|
2008-04-09 22:18:47 +02:00
|
|
|
jrd_tra* transaction = ((InternalTransaction&) tran).getJrdTran();
|
|
|
|
memcpy(&m_blob_id, desc.dsc_address, sizeof(m_blob_id));
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, m_connection);
|
|
|
|
|
|
|
|
USHORT bpb_len = bpb ? bpb->getCount() : 0;
|
2008-04-13 10:11:16 +02:00
|
|
|
const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL;
|
2008-04-09 22:18:47 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
m_blob = reinterpret_cast<Jrd::blb*>(transaction->
|
|
|
|
openBlob(&status, &m_blob_id, bpb_len, bpb_buff, att));
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
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();
|
2008-04-09 22:18:47 +02:00
|
|
|
jrd_tra* transaction = ((InternalTransaction&) tran).getJrdTran();
|
2010-10-12 10:02:57 +02:00
|
|
|
memset(&m_blob_id, 0, sizeof(m_blob_id));
|
2008-04-09 22:18:47 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, m_connection);
|
|
|
|
|
2009-05-17 13:20:43 +02:00
|
|
|
const USHORT bpb_len = bpb ? bpb->getCount() : 0;
|
2008-04-13 10:11:16 +02:00
|
|
|
const UCHAR* bpb_buff = bpb ? bpb->begin() : NULL;
|
2008-04-09 22:18:47 +02:00
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
m_blob = reinterpret_cast<Jrd::blb*>(transaction->createBlob(&status, &m_blob_id,
|
|
|
|
bpb_len, bpb_buff, att));
|
2008-04-09 22:18:47 +02:00
|
|
|
memcpy(desc.dsc_address, &m_blob_id, sizeof(m_blob_id));
|
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
m_connection.raise(status, tdbb, "jrd8_create_blob2");
|
|
|
|
}
|
|
|
|
fb_assert(m_blob);
|
|
|
|
}
|
|
|
|
|
2009-06-08 16:57:58 +02:00
|
|
|
USHORT InternalBlob::read(thread_db* tdbb, UCHAR* buff, USHORT len)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_blob);
|
|
|
|
|
|
|
|
USHORT result = 0;
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, m_connection);
|
2010-10-12 10:02:57 +02:00
|
|
|
result = m_blob->getSegment(&status, len, buff);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
switch (status.get()[1])
|
2009-01-14 09:22:32 +01:00
|
|
|
{
|
|
|
|
case isc_segstr_eof:
|
2008-04-09 22:18:47 +02:00
|
|
|
fb_assert(result == 0);
|
2009-01-14 09:22:32 +01:00
|
|
|
break;
|
|
|
|
case isc_segment:
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
2008-04-09 22:18:47 +02:00
|
|
|
m_connection.raise(status, tdbb, "jrd8_get_segment");
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-06-08 16:57:58 +02:00
|
|
|
void InternalBlob::write(thread_db* tdbb, const UCHAR* buff, USHORT len)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_blob);
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, m_connection);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_blob->putSegment(&status, len, buff);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
m_connection.raise(status, tdbb, "jrd8_put_segment");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-15 02:51:21 +02:00
|
|
|
void InternalBlob::close(thread_db* tdbb)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
fb_assert(m_blob);
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, m_connection);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_blob->close(&status);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
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)
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
if (!m_blob) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-12 10:02:57 +02:00
|
|
|
LocalStatus status;
|
2008-04-09 22:18:47 +02:00
|
|
|
{
|
|
|
|
EngineCallbackGuard guard(tdbb, m_connection);
|
2010-10-12 10:02:57 +02:00
|
|
|
m_blob->cancel(&status);
|
2008-04-09 22:18:47 +02:00
|
|
|
}
|
2010-10-12 10:02:57 +02:00
|
|
|
if (!status.isSuccess()) {
|
2008-04-09 22:18:47 +02:00
|
|
|
m_connection.raise(status, tdbb, "jrd8_cancel_blob");
|
|
|
|
}
|
|
|
|
fb_assert(!m_blob);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-11 03:38:50 +02:00
|
|
|
} // namespace EDS
|