/* * 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 "../dsql/gen_proto.h" #include "../dsql/pass1_proto.h" using namespace Jrd; #include "gen/blrtable.h" namespace Jrd { template class RegisterNode { public: 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 regInAutonomousTransactionNode(blr_auto_trans); DmlNode* InAutonomousTransactionNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb) { InAutonomousTransactionNode* node = FB_NEW(pool) InAutonomousTransactionNode(pool); if (csb->getBlrByte() != 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& 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) { action = CMP_pass2(tdbb, csb, action, node); return this; } jrd_nod* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* request) { 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); 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; } 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, request->req_transaction, jrd_req::req_trigger_trans_commit); } Firebird::AutoSetRestore2 autoNullifyRequest( tdbb, &thread_db::getRequest, &thread_db::setRequest, NULL); TRA_commit(tdbb, request->req_transaction, false); 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, request->req_transaction, jrd_req::req_trigger_trans_commit); } Firebird::AutoSetRestore2 autoNullifyRequest( tdbb, &thread_db::getRequest, &thread_db::setRequest, NULL); TRA_commit(tdbb, request->req_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, request->req_transaction, jrd_req::req_trigger_trans_rollback); } catch (const Firebird::Exception&) { if (tdbb->getDatabase()->dbb_flags & DBB_bugcheck) { throw; } } } try { Firebird::AutoSetRestore2 autoNullifyRequest( tdbb, &thread_db::getRequest, &thread_db::setRequest, NULL); TRA_rollback(tdbb, request->req_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