From: <asf...@us...> - 2013-04-11 15:44:24
|
Revision: 57933 http://sourceforge.net/p/firebird/code/57933 Author: asfernandes Date: 2013-04-11 15:44:17 +0000 (Thu, 11 Apr 2013) Log Message: ----------- Revert external routines to request-based (*) code, but now using a totally different internal approach. * This is not ideal IMO, but much more easier to currently support stack traces, and domain's defaults and validations. Modified Paths: -------------- firebird/trunk/examples/udr/UdrCppExample.cpp firebird/trunk/src/dsql/ExprNodes.cpp firebird/trunk/src/dsql/Nodes.h firebird/trunk/src/dsql/StmtNodes.cpp firebird/trunk/src/dsql/StmtNodes.h firebird/trunk/src/jrd/ExtEngineManager.cpp firebird/trunk/src/jrd/ExtEngineManager.h firebird/trunk/src/jrd/Function.epp firebird/trunk/src/jrd/exe.cpp firebird/trunk/src/jrd/jrd.cpp firebird/trunk/src/jrd/met.epp firebird/trunk/src/jrd/par.cpp firebird/trunk/src/jrd/par_proto.h firebird/trunk/src/jrd/recsrc/ProcedureScan.cpp firebird/trunk/src/jrd/recsrc/RecordSource.h firebird/trunk/src/jrd/req.h Modified: firebird/trunk/examples/udr/UdrCppExample.cpp =================================================================== --- firebird/trunk/examples/udr/UdrCppExample.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/examples/udr/UdrCppExample.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -190,8 +190,7 @@ unsigned outNullOffset = outMetadata->getNullOffset(status, 0); StatusException::check(status->get()); - // By default, the return value is NOT NULL. - ///*(ISC_SHORT*) (out + outNullOffset) = FB_FALSE; + *(ISC_SHORT*) (out + outNullOffset) = FB_FALSE; // Get offset of the return value. unsigned outOffset = outMetadata->getOffset(status, 0); @@ -244,7 +243,7 @@ ***/ FB_UDR_BEGIN_PROCEDURE(gen_rows) // Procedure variables. - unsigned inOffsetStart, inOffsetEnd, outOffset; + unsigned inOffsetStart, inOffsetEnd, outNullOffset, outOffset; /*** Procedure destructor. ~FB_UDR_PROCEDURE(gen_rows)() @@ -269,6 +268,9 @@ IMessageMetadata* outMetadata = metadata->getOutputMetadata(status); StatusException::check(status->get()); + outNullOffset = outMetadata->getNullOffset(status, 0); + StatusException::check(status->get()); + outOffset = outMetadata->getOffset(status, 0); StatusException::check(status->get()); @@ -279,6 +281,8 @@ { counter = *(ISC_LONG*) (in + procedure->inOffsetStart); end = *(ISC_LONG*) (in + procedure->inOffsetEnd); + + *(ISC_SHORT*) (out + procedure->outNullOffset) = FB_FALSE; } FB_UDR_FETCH_PROCEDURE @@ -320,6 +324,7 @@ , (FB_INTEGER, result)) { + out->resultNull = FB_FALSE; out->result = in->start - 1; } Modified: firebird/trunk/src/dsql/ExprNodes.cpp =================================================================== --- firebird/trunk/src/dsql/ExprNodes.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/dsql/ExprNodes.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -10671,10 +10671,7 @@ CMP_impure(csb, function->getInputFormat()->fmt_length); } - if (function->fun_external) - fb_assert(function->getOutputFormat()->fmt_count == 2); - else - fb_assert(function->getOutputFormat()->fmt_count == 3); + fb_assert(function->getOutputFormat()->fmt_count == 3); fb_assert(function->getOutputFormat()->fmt_length); CMP_impure(csb, function->getOutputFormat()->fmt_length); @@ -10763,13 +10760,6 @@ UCHAR* const inMsg = (UCHAR*) FB_ALIGN((IPTR) impure + sizeof(impure_value), FB_ALIGNMENT); UCHAR* const outMsg = (UCHAR*) FB_ALIGN((IPTR) inMsg + inMsgLength, FB_ALIGNMENT); - if (function->fun_external) - { - // We must clear messages of external functions. - memset(inMsg, 0, inMsgLength); - memset(outMsg, 0, outMsgLength); - } - if (function->fun_inputs != 0) { const NestConst<ValueExprNode>* const sourceEnd = args->items.end(); @@ -10801,10 +10791,28 @@ const SLONG savePointNumber = transaction->tra_save_point ? transaction->tra_save_point->sav_number : 0; - if (function->fun_external) + jrd_req* funcRequest = function->getStatement()->findRequest(tdbb); + + // trace function execution start + //// TODO: TraceProcExecute trace(tdbb, funcRequest, request, inputTargets); + + // Catch errors so we can unwind cleanly. + + try { - function->fun_external->execute(tdbb, inMsg, outMsg); + Jrd::ContextPoolHolder context(tdbb, funcRequest->req_pool); // Save the old pool. + funcRequest->req_timestamp = request->req_timestamp; + + EXE_start(tdbb, funcRequest, transaction); + + if (inMsgLength != 0) + EXE_send(tdbb, funcRequest, 0, inMsgLength, inMsg); + + EXE_receive(tdbb, funcRequest, 1, outMsgLength, outMsg); + + // Clean up all savepoints started during execution of the procedure. + if (transaction != attachment->getSysTransaction()) { for (const Savepoint* savePoint = transaction->tra_save_point; @@ -10815,65 +10823,30 @@ } } } - else + catch (const Exception& ex) { - jrd_req* funcRequest = function->getStatement()->findRequest(tdbb); + /*** TODO: + const bool noPriv = (ex.stuff_exception(tdbb->tdbb_status_vector) == isc_no_priv); + trace.finish(false, noPriv ? res_unauthorized : res_failed); + ***/ - // trace function execution start - //// TODO: TraceProcExecute trace(tdbb, funcRequest, request, inputTargets); - - // Catch errors so we can unwind cleanly. - - try - { - Jrd::ContextPoolHolder context(tdbb, funcRequest->req_pool); // Save the old pool. - - funcRequest->req_timestamp = request->req_timestamp; - - EXE_start(tdbb, funcRequest, transaction); - - if (inMsgLength != 0) - EXE_send(tdbb, funcRequest, 0, inMsgLength, inMsg); - - EXE_receive(tdbb, funcRequest, 1, outMsgLength, outMsg); - - // Clean up all savepoints started during execution of the procedure. - - if (transaction != attachment->getSysTransaction()) - { - for (const Savepoint* savePoint = transaction->tra_save_point; - savePoint && savePointNumber < savePoint->sav_number; - savePoint = transaction->tra_save_point) - { - VIO_verb_cleanup(tdbb, transaction); - } - } - } - catch (const Exception& ex) - { - /*** TODO: - const bool noPriv = (ex.stuff_exception(tdbb->tdbb_status_vector) == isc_no_priv); - trace.finish(false, noPriv ? res_unauthorized : res_failed); - ***/ - - tdbb->setRequest(request); - EXE_unwind(tdbb, funcRequest); - funcRequest->req_attachment = NULL; - funcRequest->req_flags &= ~(req_in_use | req_proc_fetch); - funcRequest->req_timestamp.invalidate(); - throw; - } - - //// TODO: trace.finish(false, res_successful); - + tdbb->setRequest(request); EXE_unwind(tdbb, funcRequest); - tdbb->setRequest(request); - funcRequest->req_attachment = NULL; funcRequest->req_flags &= ~(req_in_use | req_proc_fetch); funcRequest->req_timestamp.invalidate(); + throw; } + //// TODO: trace.finish(false, res_successful); + + EXE_unwind(tdbb, funcRequest); + tdbb->setRequest(request); + + funcRequest->req_attachment = NULL; + funcRequest->req_flags &= ~(req_in_use | req_proc_fetch); + funcRequest->req_timestamp.invalidate(); + const dsc* fmtDesc = function->getOutputFormat()->fmt_desc.begin(); const ULONG nullOffset = (IPTR) fmtDesc[1].dsc_address; SSHORT* const nullPtr = reinterpret_cast<SSHORT*>(outMsg + nullOffset); Modified: firebird/trunk/src/dsql/Nodes.h =================================================================== --- firebird/trunk/src/dsql/Nodes.h 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/dsql/Nodes.h 2013-04-11 15:44:17 UTC (rev 57933) @@ -1286,7 +1286,10 @@ TYPE_STORE, TYPE_SUSPEND, TYPE_UPDATE_OR_INSERT, - TYPE_USER_SAVEPOINT + TYPE_USER_SAVEPOINT, + + TYPE_EXT_INIT_PARAMETER, + TYPE_EXT_TRIGGER }; enum WhichTrigger Modified: firebird/trunk/src/dsql/StmtNodes.cpp =================================================================== --- firebird/trunk/src/dsql/StmtNodes.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/dsql/StmtNodes.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -2745,13 +2745,6 @@ outMsg = (UCHAR*) FB_ALIGN((U_IPTR) outMsg, FB_DOUBLE_ALIGN); } - if (procedure->getExternal()) - { - // We must clear messages of external procedures. - memset(inMsg, 0, inMsgLength); - memset(outMsg, 0, outMsgLength); - } - if (inputSources) { const NestConst<ValueExprNode>* const sourceEnd = inputSources->items.end(); @@ -2766,14 +2759,26 @@ const SLONG savePointNumber = transaction->tra_save_point ? transaction->tra_save_point->sav_number : 0; - if (procedure->getExternal()) + jrd_req* procRequest = procedure->getStatement()->findRequest(tdbb); + + // trace procedure execution start + TraceProcExecute trace(tdbb, procRequest, request, inputTargets); + + // Catch errors so we can unwind cleanly. + + try { - { // scope - AutoPtr<ExtEngineManager::ResultSet> resultSet(procedure->getExternal()->open( - tdbb, inMsg, outMsg)); - resultSet->fetch(tdbb); - } + Jrd::ContextPoolHolder context(tdbb, procRequest->req_pool); // Save the old pool. + procRequest->req_timestamp = request->req_timestamp; + + EXE_start(tdbb, procRequest, transaction); + + if (inputMessage) + EXE_send(tdbb, procRequest, 0, inMsgLength, inMsg); + + EXE_receive(tdbb, procRequest, 1, outMsgLength, outMsg); + // Clean up all savepoints started during execution of the procedure. if (transaction != attachment->getSysTransaction()) @@ -2786,64 +2791,29 @@ } } } - else + catch (const Exception& ex) { - jrd_req* procRequest = procedure->getStatement()->findRequest(tdbb); + const bool noPriv = (ex.stuff_exception(tdbb->tdbb_status_vector) == isc_no_priv); + trace.finish(false, noPriv ? res_unauthorized : res_failed); - // trace procedure execution start - TraceProcExecute trace(tdbb, procRequest, request, inputTargets); - - // Catch errors so we can unwind cleanly. - - try - { - Jrd::ContextPoolHolder context(tdbb, procRequest->req_pool); // Save the old pool. - - procRequest->req_timestamp = request->req_timestamp; - - EXE_start(tdbb, procRequest, transaction); - - if (inputMessage) - EXE_send(tdbb, procRequest, 0, inMsgLength, inMsg); - - EXE_receive(tdbb, procRequest, 1, outMsgLength, outMsg); - - // Clean up all savepoints started during execution of the procedure. - - if (transaction != attachment->getSysTransaction()) - { - for (const Savepoint* savePoint = transaction->tra_save_point; - savePoint && savePointNumber < savePoint->sav_number; - savePoint = transaction->tra_save_point) - { - VIO_verb_cleanup(tdbb, transaction); - } - } - } - catch (const Exception& ex) - { - const bool noPriv = (ex.stuff_exception(tdbb->tdbb_status_vector) == isc_no_priv); - trace.finish(false, noPriv ? res_unauthorized : res_failed); - - tdbb->setRequest(request); - EXE_unwind(tdbb, procRequest); - procRequest->req_attachment = NULL; - procRequest->req_flags &= ~(req_in_use | req_proc_fetch); - procRequest->req_timestamp.invalidate(); - throw; - } - - // trace procedure execution finish - trace.finish(false, res_successful); - + tdbb->setRequest(request); EXE_unwind(tdbb, procRequest); - tdbb->setRequest(request); - procRequest->req_attachment = NULL; procRequest->req_flags &= ~(req_in_use | req_proc_fetch); procRequest->req_timestamp.invalidate(); + throw; } + // trace procedure execution finish + trace.finish(false, res_successful); + + EXE_unwind(tdbb, procRequest); + tdbb->setRequest(request); + + procRequest->req_attachment = NULL; + procRequest->req_flags &= ~(req_in_use | req_proc_fetch); + procRequest->req_timestamp.invalidate(); + if (outputSources) { const NestConst<ValueExprNode>* const sourceEnd = outputSources->items.end(); @@ -5193,35 +5163,43 @@ { MessageNode* node = FB_NEW(pool) MessageNode(pool); - // Get message number, register it in the compiler scratch block, and + // Parse the BLR and finish the node creation. + USHORT message = csb->csb_blr_reader.getByte(); + USHORT count = csb->csb_blr_reader.getWord(); + node->setup(tdbb, csb, message, count); + + return node; +} + +void MessageNode::setup(thread_db* tdbb, CompilerScratch* csb, USHORT message, USHORT count) +{ + // Register message number in the compiler scratch block, and // allocate a node to represent the message. - USHORT n = csb->csb_blr_reader.getByte(); - CompilerScratch::csb_repeat* tail = CMP_csb_element(csb, n); + CompilerScratch::csb_repeat* tail = CMP_csb_element(csb, message); - tail->csb_message = node; - node->messageNumber = n; + tail->csb_message = this; + messageNumber = message; - if (n > csb->csb_msg_number) - csb->csb_msg_number = n; + if (message > csb->csb_msg_number) + csb->csb_msg_number = message; USHORT padField; - bool shouldPad = csb->csb_message_pad.get(node->messageNumber, padField); + bool shouldPad = csb->csb_message_pad.get(messageNumber, padField); // Get the number of parameters in the message and prepare to fill out the format block. - n = csb->csb_blr_reader.getWord(); - node->format = Format::newFormat(*tdbb->getDefaultPool(), n); + format = Format::newFormat(*tdbb->getDefaultPool(), count); USHORT maxAlignment = 0; ULONG offset = 0; Format::fmt_desc_iterator desc, end; USHORT index = 0; - for (desc = node->format->fmt_desc.begin(), end = desc + n; desc < end; ++desc, ++index) + for (desc = format->fmt_desc.begin(), end = desc + count; desc < end; ++desc, ++index) { ItemInfo itemInfo; - const USHORT alignment = PAR_desc(tdbb, csb, &*desc, &itemInfo); + const USHORT alignment = setupDesc(tdbb, csb, index, &*desc, &itemInfo); if (alignment) offset = FB_ALIGN(offset, alignment); @@ -5248,9 +5226,13 @@ if (offset > MAX_MESSAGE_SIZE) PAR_error(csb, Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig)); - node->format->fmt_length = offset; + format->fmt_length = offset; +} - return node; +USHORT MessageNode::setupDesc(thread_db* tdbb, CompilerScratch* csb, USHORT /*index*/, + dsc* desc, ItemInfo* itemInfo) +{ + return PAR_desc(tdbb, csb, desc, itemInfo); } MessageNode* MessageNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/) Modified: firebird/trunk/src/dsql/StmtNodes.h =================================================================== --- firebird/trunk/src/dsql/StmtNodes.h 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/dsql/StmtNodes.h 2013-04-11 15:44:17 UTC (rev 57933) @@ -1067,6 +1067,11 @@ public: static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp); + void setup(thread_db* tdbb, CompilerScratch* csb, USHORT message, USHORT count); + + virtual USHORT setupDesc(thread_db* tdbb, CompilerScratch* csb, USHORT index, + dsc* desc, ItemInfo* itemInfo); + virtual void print(Firebird::string& text) const; virtual MessageNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch); Modified: firebird/trunk/src/jrd/ExtEngineManager.cpp =================================================================== --- firebird/trunk/src/jrd/ExtEngineManager.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/ExtEngineManager.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -34,7 +34,9 @@ #include "../jrd/status.h" #include "../jrd/tra.h" #include "../jrd/ibase.h" +#include "../dsql/StmtNodes.h" #include "../common/os/path_utils.h" +#include "../jrd/cmp_proto.h" #include "../jrd/cvt_proto.h" #include "../jrd/evl_proto.h" #include "../jrd/intl_proto.h" @@ -54,8 +56,407 @@ #include "../common/classes/GetPlugins.h" using namespace Firebird; +using namespace Jrd; +namespace +{ + // External message node. + class ExtMessageNode : public MessageNode + { + public: + ExtMessageNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, USHORT message, + Array<NestConst<Parameter> >& aParameters, const Format* aFormat) + : MessageNode(pool), + parameters(aParameters), + format(aFormat), + isSpecial(pool) + { + setup(tdbb, csb, message, format->fmt_count); + } + + virtual USHORT setupDesc(thread_db* tdbb, CompilerScratch* csb, USHORT index, + dsc* desc, ItemInfo* itemInfo) + { + *desc = format->fmt_desc[index]; + + if (index % 2 == 0 && index / 2 < parameters.getCount()) + { + const Parameter* param = parameters[index / 2]; + + if (param->prm_mechanism != prm_mech_type_of && + !fb_utils::implicit_domain(param->prm_field_source.c_str())) + { + MetaNamePair namePair(param->prm_field_source, ""); + + FieldInfo fieldInfo; + bool exist = csb->csb_map_field_info.get(namePair, fieldInfo); + MET_get_domain(tdbb, param->prm_field_source, desc, (exist ? NULL : &fieldInfo)); + + if (!exist) + csb->csb_map_field_info.put(namePair, fieldInfo); + + itemInfo->field = namePair; + itemInfo->nullable = fieldInfo.nullable; + itemInfo->fullDomain = true; + } + + itemInfo->name = param->prm_name; + + if (!param->prm_nullable) + itemInfo->nullable = false; + + isSpecial.getBuffer(index / 2 + 1)[index / 2] = itemInfo->isSpecial(); + } + + return type_alignments[desc->dsc_dtype]; + } + + virtual const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const + { + if (request->req_operation == jrd_req::req_evaluate) + { + // Clear the message. This is important for external routines. + UCHAR* msg = request->getImpure<UCHAR>(impureOffset); + memset(msg, 0, format->fmt_length); + } + + return MessageNode::execute(tdbb, request, exeState); + } + + public: + Array<NestConst<Parameter> >& parameters; + const Format* format; + Array<bool> isSpecial; + }; + + // Initialize output parameters with their domains default value or NULL. + // Kind of blr_init_variable, but for parameters. + class ExtInitParameterNode : public TypedNode<StmtNode, StmtNode::TYPE_EXT_INIT_PARAMETER> + { + public: + ExtInitParameterNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, + ExtMessageNode* aMessage, USHORT aArgNumber) + : TypedNode<StmtNode, StmtNode::TYPE_EXT_INIT_PARAMETER>(pool), + message(aMessage), + argNumber(aArgNumber) + { + Parameter* parameter = message->parameters[argNumber / 2]; + + if (parameter->prm_mechanism == prm_mech_type_of || + fb_utils::implicit_domain(parameter->prm_field_source.c_str()) || + !parameter->prm_default_value) + { + defaultValueNode = NULL; + } + else + defaultValueNode = CMP_clone_node(tdbb, csb, parameter->prm_default_value); + } + + void print(string& text) const + { + text = "ExtInitParameterNode"; + } + + void genBlr(DsqlCompilerScratch* /*dsqlScratch*/) + { + } + + ExtInitParameterNode* pass1(thread_db* tdbb, CompilerScratch* csb) + { + doPass1(tdbb, csb, &defaultValueNode); + return this; + } + + ExtInitParameterNode* pass2(thread_db* tdbb, CompilerScratch* csb) + { + ExprNode::doPass2(tdbb, csb, &defaultValueNode); + return this; + } + + const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* /*exeState*/) const + { + if (request->req_operation == jrd_req::req_evaluate) + { + dsc* defaultDesc = NULL; + + if (defaultValueNode) + { + defaultDesc = EVL_expr(tdbb, request, defaultValueNode); + + if (request->req_flags & req_null) + defaultDesc = NULL; + } + + if (defaultDesc) + { + // Initialize the value. The null flag is already initialized to not-null + // by the ExtMessageNode. + + dsc desc = message->format->fmt_desc[argNumber]; + desc.dsc_address = request->getImpure<UCHAR>( + message->impureOffset + (IPTR) desc.dsc_address); + + MOV_move(tdbb, defaultDesc, &desc); + } + else + { + SSHORT tempValue = -1; + dsc temp; + temp.makeShort(0, &tempValue); + + dsc desc = message->format->fmt_desc[argNumber + 1]; + desc.dsc_address = request->getImpure<UCHAR>( + message->impureOffset + (IPTR) desc.dsc_address); + + MOV_move(tdbb, &temp, &desc); + } + + request->req_operation = jrd_req::req_return; + } + + return parentStmt; + } + + private: + ExtMessageNode* message; + USHORT argNumber; + ValueExprNode* defaultValueNode; + }; + + // External output parameters initialization. + class ExtInitOutputNode : public CompoundStmtNode + { + public: + ExtInitOutputNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, + ExtMessageNode* message) + : CompoundStmtNode(pool) + { + for (USHORT i = 0; i < message->format->fmt_count; i += 2) + { + if (i + 1 >= message->format->fmt_count) + continue; + + ExtInitParameterNode* init = FB_NEW(pool) ExtInitParameterNode( + tdbb, pool, csb, message, i); + statements.add(init); + } + } + }; + + // External parameters validation. + class ExtValidationNode : public CompoundStmtNode + { + public: + ExtValidationNode(MemoryPool& pool, ExtMessageNode* message, bool procedure, bool input) + : CompoundStmtNode(pool) + { + for (USHORT i = 0; i < message->format->fmt_count; i += 2) + { + if (i + 1 >= message->format->fmt_count || !message->isSpecial[i / 2]) + continue; + + ParameterNode* flag = FB_NEW(pool) ParameterNode(pool); + flag->message = message; + flag->argNumber = i + 1; + + ParameterNode* param = FB_NEW(pool) ParameterNode(pool); + param->message = message; + param->argNumber = i; + param->argFlag = flag; + + AssignmentNode* assign = FB_NEW(pool) AssignmentNode(pool); + assign->asgnFrom = param; + statements.add(assign); + + // It's sufficient to assign input parameters to NULL, but output parameters + // need to be assigned to themselves to validate correctly. + if (input) + assign->asgnTo = FB_NEW(pool) NullNode(pool); + else + { + flag = FB_NEW(pool) ParameterNode(pool); + flag->message = message; + flag->argNumber = i + 1; + + param = FB_NEW(pool) ParameterNode(pool); + param->message = message; + param->argNumber = i; + param->argFlag = flag; + + assign->asgnTo = param; + } + } + + // A stall is required to read req_proc_fetch state correctly. + if (procedure) + statements.add(FB_NEW(pool) StallNode(pool)); + } + }; + + // External function node. + class ExtFunctionNode : public SuspendNode + { + public: + ExtFunctionNode(MemoryPool& pool, const ReceiveNode* aReceiveNode, + const ExtEngineManager::Function* aFunction) + : SuspendNode(pool), + receiveNode(aReceiveNode), + function(aFunction) + { + } + + virtual const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const + { + if (request->req_operation == jrd_req::req_evaluate) + { + UCHAR* inMsg = receiveNode ? + request->getImpure<UCHAR>(receiveNode->message->impureOffset) : NULL; + UCHAR* outMsg = request->getImpure<UCHAR>(message->impureOffset); + + function->execute(tdbb, inMsg, outMsg); + } + + return SuspendNode::execute(tdbb, request, exeState); + } + + private: + const ReceiveNode* receiveNode; + const ExtEngineManager::Function* function; + }; + + // External procedure node. + class ExtProcedureNode : public SuspendNode + { + public: + ExtProcedureNode(MemoryPool& pool, const ReceiveNode* aReceiveNode, + const ExtEngineManager::Procedure* aProcedure) + : SuspendNode(pool), + receiveNode(aReceiveNode), + procedure(aProcedure) + { + } + + virtual const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const + { + ExtEngineManager::ResultSet*& resultSet = request->req_ext_resultset; + UCHAR* inMsg = receiveNode ? + request->getImpure<UCHAR>(receiveNode->message->impureOffset) : NULL; + UCHAR* outMsg = request->getImpure<UCHAR>(message->impureOffset); + USHORT* eof = (USHORT*) (outMsg + (IPTR) message->format->fmt_desc.back().dsc_address); + + switch (request->req_operation) + { + case jrd_req::req_evaluate: + fb_assert(!resultSet && *eof == 0); + resultSet = procedure->open(tdbb, inMsg, outMsg); + + if (resultSet) + *eof = -1; + else + { + if (!(request->req_flags & req_proc_fetch)) + { + request->req_operation = jrd_req::req_evaluate; + return statement; + } + } + + request->req_operation = jrd_req::req_return; + // fall into + + case jrd_req::req_return: + if (*eof == 0) + { + fb_assert(!resultSet); + return parentStmt; + } + + fb_assert(resultSet); + + if (!resultSet->fetch(tdbb) || !(request->req_flags & req_proc_fetch)) + { + *eof = 0; + delete resultSet; + resultSet = NULL; + } + + break; + + case jrd_req::req_proceed: + request->req_operation = jrd_req::req_evaluate; + return statement; + + case jrd_req::req_unwind: + delete resultSet; + resultSet = NULL; + break; + } + + return SuspendNode::execute(tdbb, request, exeState); + } + + private: + const ReceiveNode* receiveNode; + const ExtEngineManager::Procedure* procedure; + }; + + // External trigger node. + class ExtTriggerNode : public TypedNode<StmtNode, StmtNode::TYPE_EXT_TRIGGER> + { + public: + ExtTriggerNode(MemoryPool& pool, const ExtEngineManager::Trigger* aTrigger) + : TypedNode<StmtNode, StmtNode::TYPE_EXT_TRIGGER>(pool), + trigger(aTrigger) + { + } + + void print(string& text) const + { + text = "ExtTriggerNode"; + } + + void genBlr(DsqlCompilerScratch* /*dsqlScratch*/) + { + } + + ExtTriggerNode* pass1(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) + { + return this; + } + + ExtTriggerNode* pass2(thread_db* /*tdbb*/, CompilerScratch* /*csb*/) + { + return this; + } + + const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* /*exeState*/) const + { + if (request->req_operation == jrd_req::req_evaluate) + { + trigger->execute(tdbb, (ExternalTrigger::Action) request->req_trigger_action, + getRpb(request, 0), getRpb(request, 1)); + + request->req_operation = jrd_req::req_return; + } + + return parentStmt; + } + + private: + static record_param* getRpb(jrd_req* request, USHORT n) + { + return request->req_rpb.getCount() > n && request->req_rpb[n].rpb_number.isValid() ? + &request->req_rpb[n] : NULL; + } + + + private: + const ExtEngineManager::Trigger* trigger; + }; +} + + namespace Jrd { static MakeUpgradeInfo<> upInfo; @@ -614,7 +1015,7 @@ } -void ExtEngineManager::makeFunction(thread_db* tdbb, Jrd::Function* udf, +void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::Function* udf, const MetaName& engine, const string& entryPoint, const string& body) { string entryPointTrimmed = entryPoint; @@ -669,13 +1070,52 @@ status.check(); } + udf->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); + udf->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); + try { - udf->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); - udf->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, false)); - udf->fun_external = FB_NEW(getPool()) Function(tdbb, this, attInfo->engine, metadata.release(), externalFunction, udf); + + CompoundStmtNode* mainNode = FB_NEW(getPool()) CompoundStmtNode(getPool()); + + ExtMessageNode* inMessageNode = udf->getInputFields().hasData() ? + FB_NEW(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0, + udf->getInputFields(), udf->getInputFormat()) : + NULL; + if (inMessageNode) + mainNode->statements.add(inMessageNode); + + ExtMessageNode* outMessageNode = FB_NEW(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1, + udf->getOutputFields(), udf->getOutputFormat()); + mainNode->statements.add(outMessageNode); + + ExtInitOutputNode* initOutputNode = FB_NEW(getPool()) ExtInitOutputNode( + tdbb, getPool(), csb, outMessageNode); + mainNode->statements.add(initOutputNode); + + ReceiveNode* receiveNode = inMessageNode ? + FB_NEW(getPool()) ReceiveNode(getPool()) : NULL; + + if (inMessageNode) + { + receiveNode->message = inMessageNode; + receiveNode->statement = FB_NEW(getPool()) ExtValidationNode( + getPool(), inMessageNode, false, true); + mainNode->statements.add(receiveNode); + } + + ExtFunctionNode* extFunctionNode = FB_NEW(getPool()) ExtFunctionNode(getPool(), + receiveNode, udf->fun_external); + mainNode->statements.add(extFunctionNode); + extFunctionNode->message = outMessageNode; + extFunctionNode->statement = FB_NEW(getPool()) ExtValidationNode( + getPool(), outMessageNode, false, false); + + JrdStatement* statement = udf->getStatement(); + PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0); + udf->setStatement(statement); } catch (...) { @@ -686,7 +1126,7 @@ } -void ExtEngineManager::makeProcedure(thread_db* tdbb, jrd_prc* prc, +void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_prc* prc, const MetaName& engine, const string& entryPoint, const string& body) { string entryPointTrimmed = entryPoint; @@ -742,13 +1182,52 @@ status.check(); } + prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); + prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); + try { - prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); - prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, false)); - prc->setExternal(FB_NEW(getPool()) Procedure(tdbb, this, attInfo->engine, metadata.release(), externalProcedure, prc)); + + CompoundStmtNode* mainNode = FB_NEW(getPool()) CompoundStmtNode(getPool()); + + ExtMessageNode* inMessageNode = prc->getInputFields().hasData() ? + FB_NEW(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0, + prc->getInputFields(), prc->getInputFormat()) : + NULL; + if (inMessageNode) + mainNode->statements.add(inMessageNode); + + ExtMessageNode* outMessageNode = FB_NEW(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1, + prc->getOutputFields(), prc->getOutputFormat()); + mainNode->statements.add(outMessageNode); + + ExtInitOutputNode* initOutputNode = FB_NEW(getPool()) ExtInitOutputNode( + tdbb, getPool(), csb, outMessageNode); + mainNode->statements.add(initOutputNode); + + ReceiveNode* receiveNode = inMessageNode ? + FB_NEW(getPool()) ReceiveNode(getPool()) : NULL; + + if (inMessageNode) + { + receiveNode->message = inMessageNode; + receiveNode->statement = FB_NEW(getPool()) ExtValidationNode( + getPool(), inMessageNode, true, true); + mainNode->statements.add(receiveNode); + } + + ExtProcedureNode* extProcedureNode = FB_NEW(getPool()) ExtProcedureNode(getPool(), + receiveNode, prc->getExternal()); + mainNode->statements.add(extProcedureNode); + extProcedureNode->message = outMessageNode; + extProcedureNode->statement = FB_NEW(getPool()) ExtValidationNode( + getPool(), outMessageNode, true, false); + + JrdStatement* statement = prc->getStatement(); + PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0); + prc->setStatement(statement); } catch (...) { @@ -759,7 +1238,7 @@ } -void ExtEngineManager::makeTrigger(thread_db* tdbb, Jrd::Trigger* trg, +void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::Trigger* trg, const MetaName& engine, const string& entryPoint, const string& body, ExternalTrigger::Type type) { @@ -835,6 +1314,14 @@ { trg->extTrigger = FB_NEW(getPool()) Trigger(tdbb, pool, this, attInfo->engine, metadata.release(), externalTrigger, trg); + + CompoundStmtNode* mainNode = FB_NEW(getPool()) CompoundStmtNode(getPool()); + + ExtTriggerNode* extTriggerNode = FB_NEW(getPool()) ExtTriggerNode(getPool(), + trg->extTrigger); + mainNode->statements.add(extTriggerNode); + + PAR_preparsed_node(tdbb, trg->relation, mainNode, NULL, &csb, &trg->statement, true, 0); } catch (...) { Modified: firebird/trunk/src/jrd/ExtEngineManager.h =================================================================== --- firebird/trunk/src/jrd/ExtEngineManager.h 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/ExtEngineManager.h 2013-04-11 15:44:17 UTC (rev 57933) @@ -43,6 +43,7 @@ class jrd_prc; class jrd_tra; class Attachment; +class CompilerScratch; class Database; class Format; class Trigger; @@ -311,13 +312,13 @@ public: void closeAttachment(thread_db* tdbb, Attachment* attachment); - void makeFunction(thread_db* tdbb, Jrd::Function* udf, + void makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::Function* udf, const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::string& body); - void makeProcedure(thread_db* tdbb, jrd_prc* prc, + void makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_prc* prc, const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::string& body); - void makeTrigger(thread_db* tdbb, Jrd::Trigger* trg, + void makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::Trigger* trg, const Firebird::MetaName& engine, const Firebird::string& entryPoint, const Firebird::string& body, Firebird::ExternalTrigger::Type type); Modified: firebird/trunk/src/jrd/Function.epp =================================================================== --- firebird/trunk/src/jrd/Function.epp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/Function.epp 2013-04-11 15:44:17 UTC (rev 57933) @@ -374,27 +374,23 @@ function->fun_external = NULL; function->setStatement(NULL); - if (!X.RDB$ENGINE_NAME.NULL) + if (!X.RDB$MODULE_NAME.NULL && !X.RDB$ENTRYPOINT.NULL) { - HalfStaticArray<UCHAR, 512> body; + function->fun_entrypoint = + Module::lookup(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT, dbb->dbb_modules); - if (!X.RDB$FUNCTION_SOURCE.NULL) + // Could not find a function with given MODULE, ENTRYPOINT. + // Try the list of internally implemented functions. + if (!function->fun_entrypoint) { - blb* const blob = blb::open(tdbb, sysTransaction, &X.RDB$FUNCTION_SOURCE); - const ULONG len = blob->BLB_get_data(tdbb, - body.getBuffer(blob->blb_length + 1), blob->blb_length + 1); - body[MIN(blob->blb_length, len)] = 0; + function->fun_entrypoint = + BUILTIN_entrypoint(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT); } - else - body.getBuffer(1)[0] = 0; - dbb->dbb_extManager.makeFunction(tdbb, function, X.RDB$ENGINE_NAME, - (X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin()); - - if (!function->fun_external) + if (!function->fun_entrypoint) function->setDefined(false); } - else if (!X.RDB$FUNCTION_BLR.NULL) + else if (!X.RDB$ENGINE_NAME.NULL || !X.RDB$FUNCTION_BLR.NULL) { MemoryPool* const csb_pool = attachment->createPool(); Jrd::ContextPoolHolder context(tdbb, csb_pool); @@ -403,17 +399,40 @@ { AutoPtr<CompilerScratch> csb(CompilerScratch::newCsb(*csb_pool, 5)); - if (!X.RDB$DEBUG_INFO.NULL) - DBG_parse_debug_info(tdbb, &X.RDB$DEBUG_INFO, *csb->csb_dbg_info); + if (!X.RDB$ENGINE_NAME.NULL) + { + HalfStaticArray<UCHAR, 512> body; - try - { - function->parseBlr(tdbb, csb, &X.RDB$FUNCTION_BLR); + if (!X.RDB$FUNCTION_SOURCE.NULL) + { + blb* const blob = blb::open(tdbb, sysTransaction, &X.RDB$FUNCTION_SOURCE); + const ULONG len = blob->BLB_get_data(tdbb, + body.getBuffer(blob->blb_length + 1), blob->blb_length + 1); + body[MIN(blob->blb_length, len)] = 0; + } + else + body.getBuffer(1)[0] = 0; + + dbb->dbb_extManager.makeFunction(tdbb, csb, function, X.RDB$ENGINE_NAME, + (X.RDB$ENTRYPOINT.NULL ? "" : X.RDB$ENTRYPOINT), (char*) body.begin()); + + if (!function->fun_external) + function->setDefined(false); } - catch (const Exception&) + else if (!X.RDB$FUNCTION_BLR.NULL) { - const string name = function->getName().toString(); - status_exception::raise(Arg::Gds(isc_bad_fun_BLR) << Arg::Str(name)); + if (!X.RDB$DEBUG_INFO.NULL) + DBG_parse_debug_info(tdbb, &X.RDB$DEBUG_INFO, *csb->csb_dbg_info); + + try + { + function->parseBlr(tdbb, csb, &X.RDB$FUNCTION_BLR); + } + catch (const Exception&) + { + const string name = function->getName().toString(); + status_exception::raise(Arg::Gds(isc_bad_fun_BLR) << Arg::Str(name)); + } } } catch (const Exception&) @@ -424,22 +443,6 @@ function->getStatement()->function = function; } - else if (!X.RDB$MODULE_NAME.NULL && !X.RDB$ENTRYPOINT.NULL) - { - function->fun_entrypoint = - Module::lookup(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT, dbb->dbb_modules); - - // Could not find a function with given MODULE, ENTRYPOINT. - // Try the list of internally implemented functions. - if (!function->fun_entrypoint) - { - function->fun_entrypoint = - BUILTIN_entrypoint(X.RDB$MODULE_NAME, X.RDB$ENTRYPOINT); - } - - if (!function->fun_entrypoint) - function->setDefined(false); - } else { RefPtr<MsgMetadata> inputMetadata(createMetadata(function->getInputFields())); Modified: firebird/trunk/src/jrd/exe.cpp =================================================================== --- firebird/trunk/src/jrd/exe.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/exe.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -955,6 +955,9 @@ (*ptr)->close(tdbb); } + if (request->req_ext_resultset) + delete request->req_ext_resultset; + while (request->req_ext_stmt) request->req_ext_stmt->close(tdbb); } @@ -1099,72 +1102,62 @@ { ptr->compile(tdbb); - if (ptr->extTrigger) + jrd_req* trigger = ptr->statement->findRequest(tdbb); + + if (trigger->req_rpb.getCount() > 0) { - //// TODO: trace stuff + trigger->req_rpb[0].rpb_record = old_rec ? old_rec : null_rec.get(); - ptr->extTrigger->execute(tdbb, (Firebird::ExternalTrigger::Action) trigger_action, - old_rpb, new_rpb); + if (old_rec && trigger_action != jrd_req::req_trigger_insert) + { + trigger->req_rpb[0].rpb_number = old_rpb->rpb_number; + trigger->req_rpb[0].rpb_number.setValid(true); + } + else + trigger->req_rpb[0].rpb_number.setValid(false); } - else + + if (trigger->req_rpb.getCount() > 1) + trigger->req_rpb[1].rpb_record = new_rec ? new_rec : null_rec.get(); + + if (new_rec && !(which_trig == StmtNode::PRE_TRIG && + trigger_action == jrd_req::req_trigger_insert)) { - jrd_req* trigger = ptr->statement->findRequest(tdbb); - - if (trigger->req_rpb.getCount() > 0) + if (which_trig == StmtNode::PRE_TRIG && + trigger_action == jrd_req::req_trigger_update) { - trigger->req_rpb[0].rpb_record = old_rec ? old_rec : null_rec.get(); - - if (old_rec && trigger_action != jrd_req::req_trigger_insert) - { - trigger->req_rpb[0].rpb_number = old_rpb->rpb_number; - trigger->req_rpb[0].rpb_number.setValid(true); - } - else - trigger->req_rpb[0].rpb_number.setValid(false); + new_rpb->rpb_number = old_rpb->rpb_number; } if (trigger->req_rpb.getCount() > 1) - trigger->req_rpb[1].rpb_record = new_rec ? new_rec : null_rec.get(); - - if (new_rec && !(which_trig == StmtNode::PRE_TRIG && - trigger_action == jrd_req::req_trigger_insert)) { - if (which_trig == StmtNode::PRE_TRIG && - trigger_action == jrd_req::req_trigger_update) - { - new_rpb->rpb_number = old_rpb->rpb_number; - } - - if (trigger->req_rpb.getCount() > 1) - { - trigger->req_rpb[1].rpb_number = new_rpb->rpb_number; - trigger->req_rpb[1].rpb_number.setValid(true); - } + trigger->req_rpb[1].rpb_number = new_rpb->rpb_number; + trigger->req_rpb[1].rpb_number.setValid(true); } - else if (trigger->req_rpb.getCount() > 1) - trigger->req_rpb[1].rpb_number.setValid(false); + } + else if (trigger->req_rpb.getCount() > 1) + trigger->req_rpb[1].rpb_number.setValid(false); - trigger->req_timestamp = timestamp; - trigger->req_trigger_action = trigger_action; + trigger->req_timestamp = timestamp; + trigger->req_trigger_action = trigger_action; - TraceTrigExecute trace(tdbb, trigger, which_trig); + TraceTrigExecute trace(tdbb, trigger, which_trig); - EXE_start(tdbb, trigger, transaction); + EXE_start(tdbb, trigger, transaction); - const bool ok = (trigger->req_operation != jrd_req::req_unwind); - trace.finish(ok ? res_successful : res_failed); + const bool ok = (trigger->req_operation != jrd_req::req_unwind); + trace.finish(ok ? res_successful : res_failed); - EXE_unwind(tdbb, trigger); + EXE_unwind(tdbb, trigger); - trigger->req_attachment = NULL; - trigger->req_flags &= ~req_in_use; - trigger->req_timestamp.invalidate(); + trigger->req_attachment = NULL; + trigger->req_flags &= ~req_in_use; + trigger->req_timestamp.invalidate(); - if (!ok) - { - trigger_failure(tdbb, trigger); - break; - } + if (!ok) + { + trigger_failure(tdbb, trigger); + break; } } Modified: firebird/trunk/src/jrd/jrd.cpp =================================================================== --- firebird/trunk/src/jrd/jrd.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/jrd.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -586,78 +586,77 @@ Database* dbb = tdbb->getDatabase(); Jrd::Attachment* const att = tdbb->getAttachment(); - if (engine.isEmpty() && !extTrigger) + if (extTrigger) + return; + + if (!statement /*&& !compile_in_progress*/) { - if (!statement /*&& !compile_in_progress*/) - { - if (statement) - return; + if (statement) + return; - compile_in_progress = true; - // Allocate statement memory pool - MemoryPool* new_pool = att->createPool(); - // Trigger request is not compiled yet. Lets do it now - USHORT par_flags = (USHORT) (flags & TRG_ignore_perm) ? csb_ignore_perm : 0; - if (type & 1) - par_flags |= csb_pre_trigger; - else - par_flags |= csb_post_trigger; + compile_in_progress = true; + // Allocate statement memory pool + MemoryPool* new_pool = att->createPool(); + // Trigger request is not compiled yet. Lets do it now + USHORT par_flags = (USHORT) (flags & TRG_ignore_perm) ? csb_ignore_perm : 0; + if (type & 1) + par_flags |= csb_pre_trigger; + else + par_flags |= csb_post_trigger; - CompilerScratch* csb = NULL; - try { - Jrd::ContextPoolHolder context(tdbb, new_pool); + CompilerScratch* csb = NULL; + try + { + Jrd::ContextPoolHolder context(tdbb, new_pool); - csb = CompilerScratch::newCsb(*tdbb->getDefaultPool(), 5); - csb->csb_g_flags |= par_flags; + csb = CompilerScratch::newCsb(*tdbb->getDefaultPool(), 5); + csb->csb_g_flags |= par_flags; + if (engine.isEmpty()) + { if (!dbg_blob_id.isEmpty()) DBG_parse_debug_info(tdbb, &dbg_blob_id, *csb->csb_dbg_info); PAR_blr(tdbb, relation, blr.begin(), (ULONG) blr.getCount(), NULL, &csb, &statement, (relation ? true : false), par_flags); - - delete csb; } - catch (const Exception&) + else { - compile_in_progress = false; - delete csb; - csb = NULL; + dbb->dbb_extManager.makeTrigger(tdbb, csb, this, engine, entryPoint, extBody.c_str(), + (relation ? + (type & 1 ? ExternalTrigger::TYPE_BEFORE : ExternalTrigger::TYPE_AFTER) : + Firebird::ExternalTrigger::TYPE_DATABASE)); + } - if (statement) - { - statement->release(tdbb); - statement = NULL; - } - else - att->deletePool(new_pool); + delete csb; + } + catch (const Exception&) + { + compile_in_progress = false; + delete csb; + csb = NULL; - throw; + if (statement) + { + statement->release(tdbb); + statement = NULL; } + else + att->deletePool(new_pool); - statement->triggerName = name; + throw; + } - if (sys_trigger) - statement->flags |= JrdStatement::FLAG_SYS_TRIGGER; + statement->triggerName = name; - if (flags & TRG_ignore_perm) - statement->flags |= JrdStatement::FLAG_IGNORE_PERM; + if (sys_trigger) + statement->flags |= JrdStatement::FLAG_SYS_TRIGGER; - compile_in_progress = false; - } + if (flags & TRG_ignore_perm) + statement->flags |= JrdStatement::FLAG_IGNORE_PERM; - return; + compile_in_progress = false; } - - // external trigger - - if (extTrigger) - return; - - dbb->dbb_extManager.makeTrigger(tdbb, this, engine, entryPoint, extBody.c_str(), - (relation ? - (type & 1 ? ExternalTrigger::TYPE_BEFORE : ExternalTrigger::TYPE_AFTER) : - Firebird::ExternalTrigger::TYPE_DATABASE)); } void Trigger::release(thread_db* tdbb) Modified: firebird/trunk/src/jrd/met.epp =================================================================== --- firebird/trunk/src/jrd/met.epp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/met.epp 2013-04-11 15:44:17 UTC (rev 57933) @@ -3001,25 +3001,6 @@ const bool external = !P.RDB$ENGINE_NAME.NULL; // ODS_12_0 - if (external) - { - HalfStaticArray<char, 512> body; - - if (!P.RDB$PROCEDURE_SOURCE.NULL) - { - blb* blob = blb::open(tdbb, attachment->getSysTransaction(), - &P.RDB$PROCEDURE_SOURCE); - ULONG len = blob->BLB_get_data(tdbb, - (UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1); - body.begin()[MIN(blob->blb_length, len)] = '\0'; - } - else - body.getBuffer(1)[0] = '\0'; - - dbb->dbb_extManager.makeProcedure(tdbb, procedure, P.RDB$ENGINE_NAME, - (P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin()); - } - Array<NestConst<Parameter> >& paramArray = procedure->getOutputFields(); if (paramArray.hasData() && paramArray[0]) @@ -3051,69 +3032,85 @@ procedure->prc_type = P.RDB$PROCEDURE_TYPE.NULL ? prc_legacy : (prc_t) P.RDB$PROCEDURE_TYPE; - if (!external) + if (external || !P.RDB$PROCEDURE_BLR.NULL) { - if (!P.RDB$PROCEDURE_BLR.NULL) - { - MemoryPool* csb_pool = attachment->createPool(); + MemoryPool* csb_pool = attachment->createPool(); - Jrd::ContextPoolHolder context(tdbb, csb_pool); - CompilerScratch* csb = CompilerScratch::newCsb(*tdbb->getDefaultPool(), 5); + Jrd::ContextPoolHolder context(tdbb, csb_pool); + CompilerScratch* csb = CompilerScratch::newCsb(*tdbb->getDefaultPool(), 5); - if (!P.RDB$DEBUG_INFO.NULL) - DBG_parse_debug_info(tdbb, &P.RDB$DEBUG_INFO, *csb->csb_dbg_info); + if (!P.RDB$DEBUG_INFO.NULL) + DBG_parse_debug_info(tdbb, &P.RDB$DEBUG_INFO, *csb->csb_dbg_info); - try + try + { + if (external) { - procedure->parseBlr(tdbb, csb, &P.RDB$PROCEDURE_BLR); - } - catch (const Exception&) - { - delete csb; + HalfStaticArray<char, 512> body; - if (procedure->getStatement()) - procedure->releaseStatement(tdbb); + if (!P.RDB$PROCEDURE_SOURCE.NULL) + { + blb* blob = blb::open(tdbb, attachment->getSysTransaction(), + &P.RDB$PROCEDURE_SOURCE); + ULONG len = blob->BLB_get_data(tdbb, + (UCHAR*) body.getBuffer(blob->blb_length + 1), blob->blb_length + 1); + body.begin()[MIN(blob->blb_length, len)] = '\0'; + } else - attachment->deletePool(csb_pool); + body.getBuffer(1)[0] = '\0'; - ERR_post(Arg::Gds(isc_bad_proc_BLR) << Arg::Str(procedure->getName().toString())); + dbb->dbb_extManager.makeProcedure(tdbb, csb, procedure, P.RDB$ENGINE_NAME, + (P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin()); } + else + procedure->parseBlr(tdbb, csb, &P.RDB$PROCEDURE_BLR); + } + catch (const Exception&) + { + delete csb; - procedure->getStatement()->procedure = procedure; + if (procedure->getStatement()) + procedure->releaseStatement(tdbb); + else + attachment->deletePool(csb_pool); - for (size_t i = 0; i < csb->csb_rpt.getCount(); i++) - { - MessageNode* node = csb->csb_rpt[i].csb_message; + ERR_post(Arg::Gds(isc_bad_proc_BLR) << Arg::Str(procedure->getName().toString())); + } - /*** - if (node) - { - if (node->messageNumber == 1) - procedure->prc_output_msg = node; - } - ***/ - } + procedure->getStatement()->procedure = procedure; - delete csb; - } - else + for (size_t i = 0; i < csb->csb_rpt.getCount(); i++) { - RefPtr<MsgMetadata> inputMetadata( - Routine::createMetadata(procedure->getInputFields())); - inputMetadata->release(); - procedure->setInputFormat( - Routine::createFormat(procedure->getPool(), inputMetadata, false)); + MessageNode* node = csb->csb_rpt[i].csb_message; - RefPtr<MsgMetadata> outputMetadata( - Routine::createMetadata(procedure->getOutputFields())); - outputMetadata->release(); - procedure->setOutputFormat( - Routine::createFormat(procedure->getPool(), outputMetadata, true)); + /*** + if (node) + { + if (node->messageNumber == 1) + procedure->prc_output_msg = node; + } + ***/ + } - procedure->setImplemented(false); - } + delete csb; } + else + { + RefPtr<MsgMetadata> inputMetadata( + Routine::createMetadata(procedure->getInputFields())); + inputMetadata->release(); + procedure->setInputFormat( + Routine::createFormat(procedure->getPool(), inputMetadata, false)); + RefPtr<MsgMetadata> outputMetadata( + Routine::createMetadata(procedure->getOutputFields())); + outputMetadata->release(); + procedure->setOutputFormat( + Routine::createFormat(procedure->getPool(), outputMetadata, true)); + + procedure->setImplemented(false); + } + if (P.RDB$VALID_BLR.NULL || P.RDB$VALID_BLR == FALSE) valid_blr = false; } Modified: firebird/trunk/src/jrd/par.cpp =================================================================== --- firebird/trunk/src/jrd/par.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/par.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -79,6 +79,8 @@ static NodeParseFunc blr_parsers[256] = {NULL}; +static CompilerScratch* par_start(thread_db* tdbb, jrd_rel* relation, CompilerScratch* view_csb, + CompilerScratch** csb_ptr, const bool trigger, USHORT flags); static void par_error(BlrReader& blrReader, const Arg::StatusVector& v, bool isSyntaxError = true); static PlanNode* par_plan(thread_db*, CompilerScratch*); static void getBlrVersion(CompilerScratch* csb); @@ -134,20 +136,12 @@ } // namespace -// Parse blr, returning a compiler scratch block with the results. -// Caller must do pool handling. -DmlNode* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, - CompilerScratch* view_csb, CompilerScratch** csb_ptr, JrdStatement** statementPtr, - const bool trigger, USHORT flags) +// Common start for PAR_blr and PAR_preparsed_node. Returns the possibily created csb. +static CompilerScratch* par_start(thread_db* tdbb, jrd_rel* relation, CompilerScratch* view_csb, + CompilerScratch** csb_ptr, const bool trigger, USHORT flags) { SET_TDBB(tdbb); -#ifdef CMP_DEBUG - cmp_trace("BLR code given for JRD parsing:"); - // CVC: Couldn't find isc_trace_printer, so changed it to gds__trace_printer. - fb_print_blr(blr, blr_length, gds__trace_printer, 0, 0); -#endif - CompilerScratch* csb; if (!(csb_ptr && (csb = *csb_ptr))) { @@ -183,8 +177,6 @@ t1->csb_flags = csb_used | csb_active; } - csb->csb_blr_reader = BlrReader(blr, blr_length); - if (view_csb) { CompilerScratch::rpt_itr ptr = view_csb->csb_rpt.begin(); @@ -203,6 +195,26 @@ csb->csb_n_stream = view_csb->csb_n_stream; } + return csb; +} + + +// Parse blr, returning a compiler scratch block with the results. +// Caller must do pool handling. +DmlNode* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, + CompilerScratch* view_csb, CompilerScratch** csb_ptr, JrdStatement** statementPtr, + const bool trigger, USHORT flags) +{ +#ifdef CMP_DEBUG + cmp_trace("BLR code given for JRD parsing:"); + // CVC: Couldn't find isc_trace_printer, so changed it to gds__trace_printer. + fb_print_blr(blr, blr_length, gds__trace_printer, 0, 0); +#endif + + CompilerScratch* csb = par_start(tdbb, relation, view_csb, csb_ptr, trigger, flags); + + csb->csb_blr_reader = BlrReader(blr, blr_length); + getBlrVersion(csb); DmlNode* node = PAR_parse_node(tdbb, csb); @@ -223,6 +235,27 @@ } +// Finish parse of memory nodes, returning a compiler scratch block with the results. +// Caller must do pool handling. +void PAR_preparsed_node(thread_db* tdbb, jrd_rel* relation, DmlNode* node, + CompilerScratch* view_csb, CompilerScratch** csb_ptr, JrdStatement** statementPtr, + const bool trigger, USHORT flags) +{ + CompilerScratch* csb = par_start(tdbb, relation, view_csb, csb_ptr, trigger, flags); + + csb->blrVersion = 5; // blr_version5 + csb->csb_node = node; + + if (statementPtr) + *statementPtr = JrdStatement::makeStatement(tdbb, csb, true); + + if (csb_ptr) + *csb_ptr = csb; + else + delete csb; +} + + // PAR_blr equivalent for validation expressions. // Validation expressions are boolean expressions, but may be prefixed with a blr_stmt_expr. BoolExprNode* PAR_validation_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length, Modified: firebird/trunk/src/jrd/par_proto.h =================================================================== --- firebird/trunk/src/jrd/par_proto.h 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/par_proto.h 2013-04-11 15:44:17 UTC (rev 57933) @@ -47,6 +47,8 @@ Jrd::ValueListNode* PAR_args(Jrd::thread_db*, Jrd::CompilerScratch*); Jrd::DmlNode* PAR_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR*, ULONG blr_length, Jrd::CompilerScratch*, Jrd::CompilerScratch**, Jrd::JrdStatement**, const bool, USHORT); +void PAR_preparsed_node(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::DmlNode*, + Jrd::CompilerScratch*, Jrd::CompilerScratch**, Jrd::JrdStatement**, const bool, USHORT); Jrd::BoolExprNode* PAR_validation_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR* blr, ULONG blr_length, Jrd::CompilerScratch*, Jrd::CompilerScratch**, USHORT); StreamType PAR_context(Jrd::CompilerScratch*, SSHORT*); Modified: firebird/trunk/src/jrd/recsrc/ProcedureScan.cpp =================================================================== --- firebird/trunk/src/jrd/recsrc/ProcedureScan.cpp 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/recsrc/ProcedureScan.cpp 2013-04-11 15:44:17 UTC (rev 57933) @@ -78,9 +78,6 @@ iml = m_message->format->fmt_length; im = request->getImpure<UCHAR>(m_message->impureOffset); - // We must clear messages of external procedures. - memset(im, 0, iml); - const NestConst<ValueExprNode>* const sourceEnd = m_sourceList->items.end(); const NestConst<ValueExprNode>* sourcePtr = m_sourceList->items.begin(); const NestConst<ValueExprNode>* targetPtr = m_targetList->items.begin(); @@ -94,55 +91,36 @@ im = NULL; } - if (m_procedure->getExternal()) - { - ///const Format* const msg_format = m_procedure->prc_output_msg->format; - const Format* const msg_format = m_procedure->getOutputFormat(); - const ULONG oml = msg_format->fmt_length; - UCHAR* om = impure->irsb_message; + jrd_req* const proc_request = m_procedure->getStatement()->findRequest(tdbb); + impure->irsb_req_handle = proc_request; - if (!om) - om = impure->irsb_message = FB_NEW(*tdbb->getDefaultPool()) UCHAR[oml]; + // req_proc_fetch flag used only when fetching rows, so + // is set at end of open() - // We must clear messages of external procedures. - memset(om, 0, oml); + proc_request->req_flags &= ~req_proc_fetch; - ExtEngineManager::ResultSet* rs = impure->irsb_ext_resultset = - m_procedure->getExternal()->open(tdbb, im, om); - } - else + try { - jrd_req* const proc_request = m_procedure->getStatement()->findRequest(tdbb); - impure->irsb_req_handle = proc_request; + proc_request->req_timestamp = request->req_timestamp; - // req_proc_fetch flag used only when fetching rows, so - // is set at end of open() + TraceProcExecute trace(tdbb, proc_request, request, m_targetList); - proc_request->req_flags &= ~req_proc_fetch; + EXE_start(tdbb, proc_request, request->req_transaction); - try + if (iml) { - proc_request->req_timestamp = request->req_timestamp; - - TraceProcExecute trace(tdbb, proc_request, request, m_targetList); - - EXE_start(tdbb, proc_request, request->req_transaction); - - if (iml) - { - EXE_send(tdbb, proc_request, 0, iml, im); - } - - trace.finish(true, res_successful); + EXE_send(tdbb, proc_request, 0, iml, im); } - catch (const Firebird::Exception&) - { - close(tdbb); - throw; - } - proc_request->req_flags |= req_proc_fetch; + trace.finish(true, res_successful); } + catch (const Firebird::Exception&) + { + close(tdbb); + throw; + } + + proc_request->req_flags |= req_proc_fetch; } void ProcedureScan::close(thread_db* tdbb) const @@ -157,24 +135,16 @@ { impure->irsb_flags &= ~irsb_open; - if (m_procedure->getExternal()) + jrd_req* const proc_request = impure->irsb_req_handle; + + if (proc_request) { - delete impure->irsb_ext_resultset; - impure->irsb_ext_resultset = NULL; + EXE_unwind(tdbb, proc_request); + proc_request->req_flags &= ~req_in_use; + impure->irsb_req_handle = NULL; + proc_request->req_attachment = NULL; } - else - { - jrd_req* const proc_request = impure->irsb_req_handle; - if (proc_request) - { - EXE_unwind(tdbb, proc_request); - proc_request->req_flags &= ~req_in_use; - impure->irsb_req_handle = NULL; - proc_request->req_attachment = NULL; - } - } - delete [] impure->irsb_message; impure->irsb_message = NULL; } @@ -216,50 +186,37 @@ else record = rpb->rpb_record; - if (m_procedure->getExternal()) + jrd_req* const proc_request = impure->irsb_req_handle; + + TraceProcFetch trace(tdbb, proc_request); + + try { - fb_assert(impure->irsb_ext_resultset); + EXE_receive(tdbb, proc_request, 1, oml, om); - if (!impure->irsb_ext_resultset->fetch(tdbb)) + dsc desc = msg_format->fmt_desc[msg_format->fmt_count - 1]; + desc.dsc_address = (UCHAR*) (om + (IPTR) desc.dsc_address); + SSHORT eos; + dsc eos_desc; + eos_desc.makeShort(0, &eos); + MOV_move(tdbb, &desc, &eos_desc); + + if (!eos) { + trace.fetch(true, res_successful); rpb->rpb_number.setValid(false); return false; } } - else + catch (const Firebird::Exception&) { - jrd_req* const proc_request = impure->irsb_req_handle; + trace.fetch(true, res_failed); + close(tdbb); + throw; + } - TraceProcFetch trace(tdbb, proc_request); + trace.fetch(false, res_successful); - try - { - EXE_receive(tdbb, proc_request, 1, oml, om); - - dsc desc = msg_format->fmt_desc[msg_format->fmt_count - 1]; - desc.dsc_address = (UCHAR*) (om + (IPTR) desc.dsc_address); - SSHORT eos; - dsc eos_desc; - eos_desc.makeShort(0, &eos); - MOV_move(tdbb, &desc, &eos_desc); - - if (!eos) - { - trace.fetch(true, res_successful); - rpb->rpb_number.setValid(false); - return false; - } - } - catch (const Firebird::Exception&) - { - trace.fetch(true, res_failed); - close(tdbb); - throw; - } - - trace.fetch(false, res_successful); - } - for (unsigned i = 0; i < rec_format->fmt_count; i++) { assignParams(tdbb, &msg_format->fmt_desc[2 * i], &msg_format->fmt_desc[2 * i + 1], Modified: firebird/trunk/src/jrd/recsrc/RecordSource.h =================================================================== --- firebird/trunk/src/jrd/recsrc/RecordSource.h 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/recsrc/RecordSource.h 2013-04-11 15:44:17 UTC (rev 57933) @@ -285,7 +285,6 @@ struct Impure : public RecordSource::Impure { jrd_req* irsb_req_handle; - ExtEngineManager::ResultSet* irsb_ext_resultset; UCHAR* irsb_message; }; Modified: firebird/trunk/src/jrd/req.h =================================================================== --- firebird/trunk/src/jrd/req.h 2013-04-11 14:28:01 UTC (rev 57932) +++ firebird/trunk/src/jrd/req.h 2013-04-11 15:44:17 UTC (rev 57933) @@ -238,6 +238,7 @@ req_base_stats(*req_pool), req_ext_stmt(NULL), req_cursors(*req_pool), + req_ext_resu... [truncated message content] |