8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Fix #7696 - select from external procedure validates output parameters even when fetch method returns false.

This commit is contained in:
Adriano dos Santos Fernandes 2023-08-03 22:19:23 -03:00
parent 04928a467a
commit f628e52bb5
3 changed files with 42 additions and 15 deletions

View File

@ -279,8 +279,10 @@ namespace
class MessageMoverNode : public CompoundStmtNode
{
public:
MessageMoverNode(MemoryPool& pool, MessageNode* fromMessage, MessageNode* toMessage)
: CompoundStmtNode(pool)
MessageMoverNode(MemoryPool& pool, MessageNode* fromMessage, MessageNode* toMessage,
MessageNode* aCheckMessageEof = nullptr)
: CompoundStmtNode(pool),
checkMessageEof(aCheckMessageEof)
{
// Iterate over the format items, except the EOF item.
for (USHORT i = 0; i < (fromMessage->format->fmt_count / 2) * 2; i += 2)
@ -314,6 +316,25 @@ namespace
assign->asgnTo = param;
}
}
const StmtNode* execute(thread_db* tdbb, Request* request, ExeState* exeState) const override
{
if (checkMessageEof &&
request->req_operation == Request::req_evaluate &&
(request->req_flags & req_proc_select))
{
const auto msg = request->getImpure<UCHAR>(checkMessageEof->impureOffset);
const auto eof = (SSHORT*) (msg + (IPTR) checkMessageEof->format->fmt_desc.back().dsc_address);
if (!*eof)
request->req_operation = Request::req_return;
}
return CompoundStmtNode::execute(tdbb, request, exeState);
}
private:
MessageNode* checkMessageEof;
};
// External function node.
@ -362,7 +383,8 @@ namespace
{
SuspendNode* suspend = FB_NEW_POOL(pool) SuspendNode(pool);
suspend->message = intOutMessageNode;
suspend->statement = FB_NEW_POOL(pool) MessageMoverNode(pool, extOutMessageNode, intOutMessageNode);
suspend->statement = FB_NEW_POOL(pool) MessageMoverNode(pool,
extOutMessageNode, intOutMessageNode, intOutMessageNode);
statements.add(suspend);
statements.add(FB_NEW_POOL(pool) StallNode(pool));
@ -381,34 +403,37 @@ namespace
switch (request->req_operation)
{
case Request::req_evaluate:
impure->sta_state = 0;
*eof = 0;
fb_assert(!resultSet);
resultSet = procedure->open(tdbb, extInMsg, extOutMsg);
if (!resultSet)
{
*eof = 0;
break;
}
else
*eof = -1;
// fall into
case Request::req_proceed:
case Request::req_sync:
*eof = 0;
if (resultSet)
{
if (resultSet->fetch(tdbb) && (request->req_flags & req_proc_fetch))
*eof = -1;
else
{
*eof = 0;
delete resultSet;
resultSet = NULL;
}
}
impure->sta_state = 0; // suspend node
request->req_operation = Request::req_sync;
if (!*eof)
request->req_operation = Request::req_return;
else
request->req_operation = Request::req_sync;
break;
case Request::req_unwind:

View File

@ -111,8 +111,8 @@ void ProcedureScan::internalOpen(thread_db* tdbb) const
// req_proc_fetch flag used only when fetching rows, so
// is set at end of open()
proc_request->req_flags &= ~req_proc_fetch;
AutoSetRestoreFlag<ULONG> autoSetReqProcSelect(&proc_request->req_flags, req_proc_select, true);
try
{
@ -197,6 +197,7 @@ bool ProcedureScan::internalGetRecord(thread_db* tdbb) const
TraceProcFetch trace(tdbb, proc_request);
AutoSetRestoreFlag<ULONG> autoSetReqProcSelect(&proc_request->req_flags, req_proc_select, true);
AutoSetRestore<USHORT> autoOriginalTimeZone(
&tdbb->getAttachment()->att_original_timezone,
tdbb->getAttachment()->att_current_timezone);

View File

@ -537,10 +537,11 @@ const ULONG req_warning = 0x40L;
const ULONG req_in_use = 0x80L;
const ULONG req_continue_loop = 0x100L; // PSQL continue statement
const ULONG req_proc_fetch = 0x200L; // Fetch from procedure in progress
const ULONG req_same_tx_upd = 0x400L; // record was updated by same transaction
const ULONG req_reserved = 0x800L; // Request reserved for client
const ULONG req_update_conflict = 0x1000L; // We need to restart request due to update conflict
const ULONG req_restart_ready = 0x2000L; // Request is ready to restart in case of update conflict
const ULONG req_proc_select = 0x400L; // Select from procedure in progress
const ULONG req_same_tx_upd = 0x800L; // record was updated by same transaction
const ULONG req_reserved = 0x1000L; // Request reserved for client
const ULONG req_update_conflict = 0x2000L; // We need to restart request due to update conflict
const ULONG req_restart_ready = 0x4000L; // Request is ready to restart in case of update conflict
// Index lock block