8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-26 07:23:08 +01:00
firebird-mirror/src/dsql/StmtNodes.cpp

273 lines
7.0 KiB
C++

/*
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, 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 Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
* Adriano dos Santos Fernandes - refactored from pass1.cpp, gen.cpp, cmp.cpp, par.cpp and exe.cpp
*/
#include "firebird.h"
#include "../jrd/common.h"
#include "../dsql/StmtNodes.h"
#include "../jrd/jrd.h"
#include "../jrd/blr.h"
#include "../jrd/exe.h"
#include "../jrd/tra.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/par_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/vio_proto.h"
#include "../dsql/gen_proto.h"
#include "../dsql/pass1_proto.h"
using namespace Jrd;
#include "gen/blrtable.h"
namespace Jrd {
template <typename T>
class RegisterNode
{
public:
explicit RegisterNode(UCHAR blr)
{
PAR_register(blr, T::parse);
}
};
//--------------------
DmlNode* DmlNode::pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* aNode)
{
node = aNode;
return pass2(tdbb, csb);
}
//--------------------
RegisterNode<InAutonomousTransactionNode> regInAutonomousTransactionNode(blr_auto_trans);
DmlNode* InAutonomousTransactionNode::parse(thread_db* tdbb, MemoryPool& pool,
CompilerScratch* csb)
{
InAutonomousTransactionNode* node = FB_NEW(pool) InAutonomousTransactionNode(pool);
if (csb->csb_blr_reader.getByte() != 0) // Reserved for future improvements. Should be 0 for now.
PAR_syntax_error(csb, "0");
node->action = PAR_parse_node(tdbb, csb, STATEMENT);
return node;
}
InAutonomousTransactionNode* InAutonomousTransactionNode::dsqlPass()
{
const bool autoTrans = compiledStatement->req_flags & REQ_in_auto_trans_block;
compiledStatement->req_flags |= REQ_in_auto_trans_block;
InAutonomousTransactionNode* node = FB_NEW(getPool()) InAutonomousTransactionNode(getPool());
node->compiledStatement = compiledStatement;
node->dsqlAction = PASS1_statement(compiledStatement, dsqlAction);
if (!autoTrans)
compiledStatement->req_flags &= ~REQ_in_auto_trans_block;
return node;
}
void InAutonomousTransactionNode::print(Firebird::string& text,
Firebird::Array<dsql_nod*>& nodes) const
{
text = "in autonomous transaction";
nodes.add(dsqlAction);
}
void InAutonomousTransactionNode::genBlr()
{
stuff(compiledStatement, blr_auto_trans);
stuff(compiledStatement, 0); // to extend syntax in the future
GEN_statement(compiledStatement, dsqlAction);
}
InAutonomousTransactionNode* InAutonomousTransactionNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
action = CMP_pass1(tdbb, csb, action);
return this;
}
InAutonomousTransactionNode* InAutonomousTransactionNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
savNumberOffset = CMP_impure(csb, sizeof(SLONG));
action = CMP_pass2(tdbb, csb, action, node);
return this;
}
jrd_nod* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* request)
{
SLONG* savNumber = (SLONG*) ((char*) request + savNumberOffset);
if (request->req_operation == jrd_req::req_evaluate)
{
fb_assert(tdbb->getTransaction() == request->req_transaction);
request->req_auto_trans.push(request->req_transaction);
request->req_transaction = TRA_start(tdbb, request->req_transaction->tra_flags,
request->req_transaction->tra_lock_timeout,
request->req_transaction);
tdbb->setTransaction(request->req_transaction);
VIO_start_save_point(tdbb, request->req_transaction);
*savNumber = request->req_transaction->tra_save_point->sav_number;
if (!(tdbb->getAttachment()->att_flags & ATT_no_db_triggers))
{
// run ON TRANSACTION START triggers
EXE_execute_db_triggers(tdbb, request->req_transaction, jrd_req::req_trigger_trans_start);
}
return action;
}
jrd_tra* transaction = request->req_transaction;
fb_assert(transaction);
fb_assert(transaction != tdbb->getDatabase()->dbb_sys_trans);
switch (request->req_operation)
{
case jrd_req::req_return:
if (!(tdbb->getAttachment()->att_flags & ATT_no_db_triggers))
{
// run ON TRANSACTION COMMIT triggers
EXE_execute_db_triggers(tdbb, transaction, jrd_req::req_trigger_trans_commit);
}
if (transaction->tra_save_point &&
!(transaction->tra_save_point->sav_flags & SAV_user) &&
!transaction->tra_save_point->sav_verb_count)
{
VIO_verb_cleanup(tdbb, transaction);
}
{ // scope
Firebird::AutoSetRestore2<jrd_req*, thread_db> autoNullifyRequest(
tdbb, &thread_db::getRequest, &thread_db::setRequest, NULL);
TRA_commit(tdbb, transaction, false);
} // end scope
break;
case jrd_req::req_unwind:
if (request->req_flags & req_leave)
{
try
{
if (!(tdbb->getAttachment()->att_flags & ATT_no_db_triggers))
{
// run ON TRANSACTION COMMIT triggers
EXE_execute_db_triggers(tdbb, transaction,
jrd_req::req_trigger_trans_commit);
}
if (transaction->tra_save_point &&
!(transaction->tra_save_point->sav_flags & SAV_user) &&
!transaction->tra_save_point->sav_verb_count)
{
VIO_verb_cleanup(tdbb, transaction);
}
Firebird::AutoSetRestore2<jrd_req*, thread_db> autoNullifyRequest(
tdbb, &thread_db::getRequest, &thread_db::setRequest, NULL);
TRA_commit(tdbb, transaction, false);
}
catch (...)
{
request->req_flags &= ~req_leave;
throw;
}
}
else
{
ThreadStatusGuard temp_status(tdbb);
if (!(tdbb->getAttachment()->att_flags & ATT_no_db_triggers))
{
try
{
// run ON TRANSACTION ROLLBACK triggers
EXE_execute_db_triggers(tdbb, transaction,
jrd_req::req_trigger_trans_rollback);
}
catch (const Firebird::Exception&)
{
if (tdbb->getDatabase()->dbb_flags & DBB_bugcheck)
{
throw;
}
}
}
try
{
Firebird::AutoSetRestore2<jrd_req*, thread_db> autoNullifyRequest(
tdbb, &thread_db::getRequest, &thread_db::setRequest, NULL);
// undo all savepoints up to our one
for (const Savepoint* save_point = transaction->tra_save_point;
save_point && *savNumber <= save_point->sav_number;
save_point = transaction->tra_save_point)
{
++transaction->tra_save_point->sav_verb_count;
VIO_verb_cleanup(tdbb, transaction);
}
TRA_rollback(tdbb, transaction, false, false);
}
catch (const Firebird::Exception&)
{
if (tdbb->getDatabase()->dbb_flags & DBB_bugcheck)
{
throw;
}
}
}
break;
default:
fb_assert(false);
}
request->req_transaction = request->req_auto_trans.pop();
tdbb->setTransaction(request->req_transaction);
return node->nod_parent;
}
} // namespace Jrd