|
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] |