8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 04:03:04 +01:00

Fixed CORE-5526 and CORE-5527.

CORE-5526: External routines receives parameters with incorrect length or datatype.
CORE-5527: External routines does not receive default values for they output parameters.
This commit is contained in:
Adriano dos Santos Fernandes 2017-04-30 23:46:19 -03:00
parent 3338a9f752
commit 7b1b3af467
4 changed files with 209 additions and 160 deletions

View File

@ -286,6 +286,7 @@ void MsgMetadata::addItem(const MetaName& name, bool nullable, const dsc& desc)
item.subType = sqlSubType;
item.length = sqlLen;
item.scale = sqlScale;
item.charSet = desc.getCharSet();
item.finished = true;
}

View File

@ -5521,11 +5521,8 @@ void MessageNode::setup(thread_db* tdbb, CompilerScratch* csb, USHORT message, U
// So we only check even indexes, which is the actual parameter.
if (itemInfo.isSpecial() && index % 2 == 0)
{
csb->csb_dbg_info->argInfoToName.get(
ArgumentInfo(csb->csb_msg_number, index / 2), itemInfo.name);
csb->csb_map_item_info.put(Item(Item::TYPE_PARAMETER, csb->csb_msg_number, index),
itemInfo);
csb->csb_dbg_info->argInfoToName.get(ArgumentInfo(csb->csb_msg_number, index / 2), itemInfo.name);
csb->csb_map_item_info.put(Item(Item::TYPE_PARAMETER, message, index), itemInfo);
}
}

View File

@ -59,16 +59,15 @@ using namespace Jrd;
namespace
{
// External message node.
class ExtMessageNode : public MessageNode
// Internal message node.
class IntMessageNode : public MessageNode
{
public:
ExtMessageNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, USHORT message,
IntMessageNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, USHORT message,
Array<NestConst<Parameter> >& aParameters, const Format* aFormat)
: MessageNode(pool),
parameters(aParameters),
format(aFormat),
isSpecial(pool)
format(aFormat)
{
setup(tdbb, csb, message, format->fmt_count);
}
@ -104,13 +103,34 @@ namespace
if (!param->prm_nullable)
itemInfo->nullable = false;
isSpecial.getBuffer(index / 2 + 1)[index / 2] = itemInfo->isSpecial();
}
return type_alignments[desc->dsc_dtype];
}
public:
Array<NestConst<Parameter> >& parameters;
const Format* format;
};
// External message node.
class ExtMessageNode : public MessageNode
{
public:
ExtMessageNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, USHORT message, const Format* aFormat)
: MessageNode(pool),
format(aFormat)
{
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];
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)
@ -124,32 +144,34 @@ namespace
}
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>
class InitParameterNode : public TypedNode<StmtNode, StmtNode::TYPE_EXT_INIT_PARAMETER>
{
public:
ExtInitParameterNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb,
ExtMessageNode* aMessage, USHORT aArgNumber)
InitParameterNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb,
Array<NestConst<Parameter> >& parameters, MessageNode* aMessage, USHORT aArgNumber)
: TypedNode<StmtNode, StmtNode::TYPE_EXT_INIT_PARAMETER>(pool),
message(aMessage),
argNumber(aArgNumber)
{
Parameter* parameter = message->parameters[argNumber / 2];
Parameter* parameter = parameters[argNumber / 2];
defaultValueNode = NULL;
if (parameter->prm_mechanism == prm_mech_type_of ||
fb_utils::implicit_domain(parameter->prm_field_source.c_str()) ||
!parameter->prm_default_value)
if (parameter->prm_mechanism != prm_mech_type_of &&
!fb_utils::implicit_domain(parameter->prm_field_source.c_str()))
{
defaultValueNode = NULL;
MetaNamePair namePair(parameter->prm_field_source, "");
FieldInfo fieldInfo;
bool exist = csb->csb_map_field_info.get(namePair, fieldInfo);
if (exist && fieldInfo.defaultValue)
defaultValueNode = CMP_clone_node(tdbb, csb, fieldInfo.defaultValue);
}
else
defaultValueNode = CMP_clone_node(tdbb, csb, parameter->prm_default_value);
}
string internalPrint(NodePrinter& printer) const
@ -160,20 +182,20 @@ namespace
NODE_PRINT(printer, argNumber);
NODE_PRINT(printer, defaultValueNode);
return "ExtInitParameterNode";
return "InitParameterNode";
}
void genBlr(DsqlCompilerScratch* /*dsqlScratch*/)
{
}
ExtInitParameterNode* pass1(thread_db* tdbb, CompilerScratch* csb)
InitParameterNode* pass1(thread_db* tdbb, CompilerScratch* csb)
{
doPass1(tdbb, csb, &defaultValueNode);
return this;
}
ExtInitParameterNode* pass2(thread_db* tdbb, CompilerScratch* csb)
InitParameterNode* pass2(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::doPass2(tdbb, csb, &defaultValueNode);
return this;
@ -224,48 +246,45 @@ namespace
}
private:
ExtMessageNode* message;
MessageNode* message;
USHORT argNumber;
ValueExprNode* defaultValueNode;
};
// External output parameters initialization.
class ExtInitOutputNode : public CompoundStmtNode
// Output parameters initialization.
class InitOutputNode : public CompoundStmtNode
{
public:
ExtInitOutputNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb,
ExtMessageNode* message)
InitOutputNode(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb,
Array<NestConst<Parameter> >& parameters, MessageNode* message)
: CompoundStmtNode(pool)
{
// Iterate over the format items, except the EOF item.
for (USHORT i = 0; i < (message->format->fmt_count / 2) * 2; i += 2)
{
ExtInitParameterNode* init = FB_NEW_POOL(pool) ExtInitParameterNode(
tdbb, pool, csb, message, i);
InitParameterNode* init = FB_NEW_POOL(pool) InitParameterNode(
tdbb, pool, csb, parameters, message, i);
statements.add(init);
}
}
};
// External parameters validation.
class ExtValidationNode : public CompoundStmtNode
// Move parameters from a message to another, validating theirs values.
class MessageMoverNode : public CompoundStmtNode
{
public:
ExtValidationNode(MemoryPool& pool, ExtMessageNode* message, bool procedure, bool input)
MessageMoverNode(MemoryPool& pool, MessageNode* fromMessage, MessageNode* toMessage)
: CompoundStmtNode(pool)
{
// Iterate over the format items, except the EOF item.
for (USHORT i = 0; i < (message->format->fmt_count / 2) * 2; i += 2)
for (USHORT i = 0; i < (fromMessage->format->fmt_count / 2) * 2; i += 2)
{
if (!message->isSpecial[i / 2])
continue;
ParameterNode* flag = FB_NEW_POOL(pool) ParameterNode(pool);
flag->message = message;
flag->message = fromMessage;
flag->argNumber = i + 1;
ParameterNode* param = FB_NEW_POOL(pool) ParameterNode(pool);
param->message = message;
param->message = fromMessage;
param->argNumber = i;
param->argFlag = flag;
@ -273,28 +292,17 @@ namespace
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(pool) NullNode(pool);
else
{
flag = FB_NEW_POOL(pool) ParameterNode(pool);
flag->message = message;
flag->argNumber = i + 1;
flag = FB_NEW_POOL(pool) ParameterNode(pool);
flag->message = toMessage;
flag->argNumber = i + 1;
param = FB_NEW_POOL(pool) ParameterNode(pool);
param->message = message;
param->argNumber = i;
param->argFlag = flag;
param = FB_NEW_POOL(pool) ParameterNode(pool);
param->message = toMessage;
param->argNumber = i;
param->argFlag = flag;
assign->asgnTo = param;
}
assign->asgnTo = param;
}
// A stall is required to read req_proc_fetch state correctly.
if (procedure)
statements.add(FB_NEW_POOL(pool) StallNode(pool));
}
};
@ -302,10 +310,11 @@ namespace
class ExtFunctionNode : public SuspendNode
{
public:
ExtFunctionNode(MemoryPool& pool, const ReceiveNode* aReceiveNode,
ExtFunctionNode(MemoryPool& pool, const MessageNode* aExtInMessageNode, const MessageNode* aExtOutMessageNode,
const ExtEngineManager::Function* aFunction)
: SuspendNode(pool),
receiveNode(aReceiveNode),
extInMessageNode(aExtInMessageNode),
extOutMessageNode(aExtOutMessageNode),
function(aFunction)
{
}
@ -314,9 +323,8 @@ namespace
{
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);
UCHAR* inMsg = extInMessageNode ? request->getImpure<UCHAR>(extInMessageNode->impureOffset) : NULL;
UCHAR* outMsg = request->getImpure<UCHAR>(extOutMessageNode->impureOffset);
function->execute(tdbb, inMsg, outMsg);
}
@ -325,83 +333,87 @@ namespace
}
private:
const ReceiveNode* receiveNode;
const MessageNode* extInMessageNode;
const MessageNode* extOutMessageNode;
const ExtEngineManager::Function* function;
};
// External procedure node.
class ExtProcedureNode : public SuspendNode
class ExtProcedureNode : public CompoundStmtNode
{
public:
ExtProcedureNode(MemoryPool& pool, const ReceiveNode* aReceiveNode,
const ExtEngineManager::Procedure* aProcedure)
: SuspendNode(pool),
receiveNode(aReceiveNode),
ExtProcedureNode(MemoryPool& pool, MessageNode* aExtInMessageNode, MessageNode* aExtOutMessageNode,
MessageNode* aIntOutMessageNode, const ExtEngineManager::Procedure* aProcedure)
: CompoundStmtNode(pool),
extInMessageNode(aExtInMessageNode),
extOutMessageNode(aExtOutMessageNode),
intOutMessageNode(aIntOutMessageNode),
procedure(aProcedure)
{
SuspendNode* suspend = FB_NEW_POOL(pool) SuspendNode(pool);
suspend->message = intOutMessageNode;
suspend->statement = FB_NEW_POOL(getPool()) MessageMoverNode(pool, extOutMessageNode, intOutMessageNode);
statements.add(suspend);
statements.add(FB_NEW_POOL(getPool()) StallNode(pool));
}
virtual const StmtNode* execute(thread_db* tdbb, jrd_req* request, ExeState* exeState) const
{
impure_state* const impure = request->getImpure<impure_state>(impureOffset);
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);
UCHAR* extInMsg = extInMessageNode ? request->getImpure<UCHAR>(extInMessageNode->impureOffset) : NULL;
UCHAR* extOutMsg = extOutMessageNode ? request->getImpure<UCHAR>(extOutMessageNode->impureOffset) : NULL;
UCHAR* intOutMsg = intOutMessageNode ? request->getImpure<UCHAR>(intOutMessageNode->impureOffset) : NULL;
SSHORT* eof = intOutMsg ?
(SSHORT*) (intOutMsg + (IPTR) intOutMessageNode->format->fmt_desc.back().dsc_address) : NULL;
switch (request->req_operation)
{
case jrd_req::req_evaluate:
fb_assert(!resultSet && *eof == 0);
resultSet = procedure->open(tdbb, inMsg, outMsg);
fb_assert(!resultSet);
resultSet = procedure->open(tdbb, extInMsg, extOutMsg);
if (resultSet)
*eof = -1;
else
if (!resultSet)
{
if (!(request->req_flags & req_proc_fetch))
*eof = 0;
break;
}
else
*eof = -1;
// fall into
case jrd_req::req_proceed:
case jrd_req::req_sync:
if (resultSet)
{
if (resultSet->fetch(tdbb) && (request->req_flags & req_proc_fetch))
*eof = -1;
else
{
request->req_operation = jrd_req::req_evaluate;
return statement;
*eof = 0;
delete resultSet;
resultSet = NULL;
}
}
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;
}
impure->sta_state = 0; // suspend node
request->req_operation = jrd_req::req_sync;
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);
return CompoundStmtNode::execute(tdbb, request, exeState);
}
private:
const ReceiveNode* receiveNode;
MessageNode* extInMessageNode;
MessageNode* extOutMessageNode;
MessageNode* intOutMessageNode;
const ExtEngineManager::Procedure* procedure;
};
@ -776,7 +788,8 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out
firstFetch(true)
{
attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine);
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ? procedure->prc->owner : "";
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ?
procedure->prc->owner : "";
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, procedure->procedure,
(procedure->prc->getName().package.isEmpty() ?
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
@ -810,7 +823,8 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
if (!resultSet)
return wasFirstFetch;
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ? procedure->prc->owner : "";
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ?
procedure->prc->owner : "";
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, charSet,
(procedure->prc->getName().package.isEmpty() ?
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
@ -1078,6 +1092,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
status.check();
IExternalFunction* externalFunction;
RefPtr<IMessageMetadata> extInputParameters, extOutputParameters;
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
@ -1092,16 +1107,19 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
Arg::Gds(isc_eem_func_not_returned) << udf->getName().toString() << engine);
}
metadata->inputParameters = inBuilder->getMetadata(&status);
extInputParameters = inBuilder->getMetadata(&status);
status.check();
metadata->outputParameters = outBuilder->getMetadata(&status);
extOutputParameters = outBuilder->getMetadata(&status);
status.check();
}
udf->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false));
udf->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true));
const Format* extInputFormat = Routine::createFormat(pool, extInputParameters, false);
const Format* extOutputFormat = Routine::createFormat(pool, extOutputParameters, true);
try
{
udf->fun_external = FB_NEW_POOL(getPool()) Function(tdbb, this, attInfo->engine,
@ -1109,38 +1127,48 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool());
ExtMessageNode* inMessageNode = udf->getInputFields().hasData() ?
FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0,
IntMessageNode* intInMessageNode = udf->getInputFields().hasData() ?
FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 0,
udf->getInputFields(), udf->getInputFormat()) :
NULL;
if (inMessageNode)
mainNode->statements.add(inMessageNode);
ExtMessageNode* extInMessageNode = NULL;
ExtMessageNode* outMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1,
if (intInMessageNode)
{
mainNode->statements.add(intInMessageNode);
extInMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 2, extInputFormat);
mainNode->statements.add(extInMessageNode);
}
IntMessageNode* intOutMessageNode = FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 1,
udf->getOutputFields(), udf->getOutputFormat());
mainNode->statements.add(outMessageNode);
mainNode->statements.add(intOutMessageNode);
ExtInitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) ExtInitOutputNode(
tdbb, getPool(), csb, outMessageNode);
ExtMessageNode* extOutMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 3,
extOutputFormat);
mainNode->statements.add(extOutMessageNode);
// Initialize the output fields into the external message.
InitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) InitOutputNode(
tdbb, getPool(), csb, udf->getOutputFields(), extOutMessageNode);
mainNode->statements.add(initOutputNode);
ReceiveNode* receiveNode = inMessageNode ?
FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL;
if (inMessageNode)
if (intInMessageNode)
{
receiveNode->message = inMessageNode;
receiveNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode(
getPool(), inMessageNode, false, true);
ReceiveNode* receiveNode = intInMessageNode ? FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL;
receiveNode->message = intInMessageNode;
receiveNode->statement = FB_NEW_POOL(getPool()) MessageMoverNode(
getPool(), intInMessageNode, extInMessageNode);
mainNode->statements.add(receiveNode);
}
ExtFunctionNode* extFunctionNode = FB_NEW_POOL(getPool()) ExtFunctionNode(getPool(),
receiveNode, udf->fun_external);
extInMessageNode, extOutMessageNode, udf->fun_external);
mainNode->statements.add(extFunctionNode);
extFunctionNode->message = outMessageNode;
extFunctionNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode(
getPool(), outMessageNode, false, false);
extFunctionNode->message = intOutMessageNode;
extFunctionNode->statement = FB_NEW_POOL(getPool()) MessageMoverNode(
getPool(), extOutMessageNode, intOutMessageNode);
JrdStatement* statement = udf->getStatement();
PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0);
@ -1188,6 +1216,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
status.check();
IExternalProcedure* externalProcedure;
RefPtr<IMessageMetadata> extInputParameters, extOutputParameters;
{ // scope
EngineCheckout cout(tdbb, FB_FUNCTION);
@ -1203,16 +1232,19 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
prc->getName().toString() << engine);
}
metadata->inputParameters = inBuilder->getMetadata(&status);
extInputParameters = inBuilder->getMetadata(&status);
status.check();
metadata->outputParameters = outBuilder->getMetadata(&status);
extOutputParameters = outBuilder->getMetadata(&status);
status.check();
}
prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false));
prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true));
const Format* extInputFormat = Routine::createFormat(pool, extInputParameters, false);
const Format* extOutputFormat = Routine::createFormat(pool, extOutputParameters, true);
try
{
prc->setExternal(FB_NEW_POOL(getPool()) Procedure(tdbb, this, attInfo->engine,
@ -1220,38 +1252,54 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool());
ExtMessageNode* inMessageNode = prc->getInputFields().hasData() ?
FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 0,
IntMessageNode* intInMessageNode = prc->getInputFields().hasData() ?
FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 0,
prc->getInputFields(), prc->getInputFormat()) :
NULL;
if (inMessageNode)
mainNode->statements.add(inMessageNode);
ExtMessageNode* extInMessageNode = NULL;
ExtMessageNode* outMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 1,
prc->getOutputFields(), prc->getOutputFormat());
mainNode->statements.add(outMessageNode);
ExtInitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) ExtInitOutputNode(
tdbb, getPool(), csb, outMessageNode);
mainNode->statements.add(initOutputNode);
ReceiveNode* receiveNode = inMessageNode ?
FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL;
if (inMessageNode)
if (intInMessageNode)
{
receiveNode->message = inMessageNode;
receiveNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode(
getPool(), inMessageNode, true, true);
mainNode->statements.add(receiveNode);
mainNode->statements.add(intInMessageNode);
extInMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 2, extInputFormat);
mainNode->statements.add(extInMessageNode);
}
IntMessageNode* intOutMessageNode = FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 1,
prc->getOutputFields(), prc->getOutputFormat());
mainNode->statements.add(intOutMessageNode);
ExtMessageNode* extOutMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(),
csb, 3, extOutputFormat);
mainNode->statements.add(extOutMessageNode);
// Initialize the output fields into the external message.
InitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) InitOutputNode(
tdbb, getPool(), csb, prc->getOutputFields(), extOutMessageNode);
mainNode->statements.add(initOutputNode);
ReceiveNode* receiveNode = intInMessageNode ?
FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL;
if (intInMessageNode)
{
CompoundStmtNode* receiveSubStatement = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool());
receiveSubStatement->statements.add(FB_NEW_POOL(getPool()) MessageMoverNode(
getPool(), intInMessageNode, extInMessageNode));
receiveSubStatement->statements.add(FB_NEW_POOL(getPool()) StallNode(getPool()));
receiveNode->statement = receiveSubStatement;
receiveNode->message = intInMessageNode;
mainNode->statements.add(receiveNode);
}
else
mainNode->statements.add(FB_NEW_POOL(getPool()) StallNode(getPool()));
ExtProcedureNode* extProcedureNode = FB_NEW_POOL(getPool()) ExtProcedureNode(getPool(),
receiveNode, prc->getExternal());
extInMessageNode, extOutMessageNode, intOutMessageNode, prc->getExternal());
mainNode->statements.add(extProcedureNode);
extProcedureNode->message = outMessageNode;
extProcedureNode->statement = FB_NEW_POOL(getPool()) ExtValidationNode(
getPool(), outMessageNode, true, false);
JrdStatement* statement = prc->getStatement();
PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0);

View File

@ -909,7 +909,7 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
{
const JrdStatement* statement = request->getStatement();
if (statement->fors.getCount() || request->req_ext_stmt)
if (statement->fors.getCount() || request->req_ext_resultset || request->req_ext_stmt)
{
Jrd::ContextPoolHolder context(tdbb, request->req_pool);
jrd_req* old_request = tdbb->getRequest();
@ -925,7 +925,10 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
}
if (request->req_ext_resultset)
{
delete request->req_ext_resultset;
request->req_ext_resultset = NULL;
}
while (request->req_ext_stmt)
request->req_ext_stmt->close(tdbb);