mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 00:03:02 +01:00
Fixed #7056 (Fetching from a scrollable cursor may overwrite user-specified buffer and corrupt memory) and #7057 (Client-side positioned updates work wrongly with scrollable cursors) with a single shot
This commit is contained in:
parent
35f0f1e70f
commit
c4ad5afb77
@ -34,10 +34,10 @@ static const char* const SCRATCH = "fb_cursor_";
|
||||
static const ULONG PREFETCH_SIZE = 65536; // 64 KB
|
||||
|
||||
DsqlCursor::DsqlCursor(dsql_req* req, ULONG flags)
|
||||
: m_request(req), m_resultSet(NULL), m_flags(flags),
|
||||
: m_request(req), m_message(req->getStatement()->getReceiveMsg()),
|
||||
m_resultSet(NULL), m_flags(flags),
|
||||
m_space(req->getPool(), SCRATCH),
|
||||
m_state(BOS), m_eof(false), m_position(0), m_cachedCount(0),
|
||||
m_messageSize(req->getStatement()->getReceiveMsg()->msg_length)
|
||||
m_state(BOS), m_eof(false), m_position(0), m_cachedCount(0)
|
||||
{
|
||||
TRA_link_cursor(m_request->req_transaction, this);
|
||||
}
|
||||
@ -232,9 +232,14 @@ int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 positio
|
||||
|
||||
fb_assert(position < m_cachedCount);
|
||||
|
||||
const FB_UINT64 offset = position * m_messageSize;
|
||||
const FB_UINT64 readBytes = m_space.read(offset, buffer, m_messageSize);
|
||||
fb_assert(readBytes == m_messageSize);
|
||||
UCHAR* const msgBuffer = m_request->req_msg_buffers[m_message->msg_buffer_number];
|
||||
|
||||
const FB_UINT64 offset = position * m_message->msg_length;
|
||||
const FB_UINT64 readBytes = m_space.read(offset, msgBuffer, m_message->msg_length);
|
||||
fb_assert(readBytes == m_message->msg_length);
|
||||
|
||||
m_request->mapInOut(tdbb, true, m_message, NULL, buffer);
|
||||
|
||||
m_position = position;
|
||||
m_state = POSITIONED;
|
||||
return 0;
|
||||
@ -244,34 +249,23 @@ bool DsqlCursor::cacheInput(thread_db* tdbb, FB_UINT64 position)
|
||||
{
|
||||
fb_assert(!m_eof);
|
||||
|
||||
const ULONG prefetchCount = MAX(PREFETCH_SIZE / m_messageSize, 1);
|
||||
const ULONG prefetchSize = prefetchCount * m_messageSize;
|
||||
|
||||
UCharBuffer messageBuffer;
|
||||
UCHAR* const buffer = messageBuffer.getBuffer(prefetchSize);
|
||||
const ULONG prefetchCount = MAX(PREFETCH_SIZE / m_message->msg_length, 1);
|
||||
const UCHAR* const msgBuffer = m_request->req_msg_buffers[m_message->msg_buffer_number];
|
||||
|
||||
while (position >= m_cachedCount)
|
||||
{
|
||||
ULONG count = 0;
|
||||
|
||||
for (; count < prefetchCount; count++)
|
||||
for (ULONG count = 0; count < prefetchCount; count++)
|
||||
{
|
||||
UCHAR* const ptr = buffer + count * m_messageSize;
|
||||
|
||||
if (!m_request->fetch(tdbb, ptr))
|
||||
if (!m_request->fetch(tdbb, NULL))
|
||||
{
|
||||
m_eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
const FB_UINT64 offset = m_cachedCount * m_messageSize;
|
||||
const ULONG fetchedSize = count * m_messageSize;
|
||||
const FB_UINT64 writtenBytes = m_space.write(offset, buffer, fetchedSize);
|
||||
fb_assert(writtenBytes == fetchedSize);
|
||||
m_cachedCount += count;
|
||||
const FB_UINT64 offset = m_cachedCount * m_message->msg_length;
|
||||
const FB_UINT64 writtenBytes = m_space.write(offset, msgBuffer, m_message->msg_length);
|
||||
fb_assert(writtenBytes == m_message->msg_length);
|
||||
m_cachedCount++;
|
||||
}
|
||||
|
||||
if (m_eof)
|
||||
|
@ -66,6 +66,7 @@ private:
|
||||
bool cacheInput(thread_db* tdbb, FB_UINT64 position = MAX_UINT64);
|
||||
|
||||
dsql_req* const m_request;
|
||||
const dsql_msg* const m_message;
|
||||
JResultSet* m_resultSet;
|
||||
const ULONG m_flags;
|
||||
TempSpace m_space;
|
||||
@ -73,7 +74,6 @@ private:
|
||||
bool m_eof;
|
||||
FB_UINT64 m_position;
|
||||
FB_UINT64 m_cachedCount;
|
||||
ULONG m_messageSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -80,9 +80,6 @@ using namespace Firebird;
|
||||
|
||||
static ULONG get_request_info(thread_db*, dsql_req*, ULONG, UCHAR*);
|
||||
static dsql_dbb* init(Jrd::thread_db*, Jrd::Attachment*);
|
||||
static void map_in_out(Jrd::thread_db*, dsql_req*, bool, const dsql_msg*, IMessageMetadata*, UCHAR*,
|
||||
const UCHAR* = NULL);
|
||||
static USHORT parse_metadata(dsql_req*, IMessageMetadata*, const Array<dsql_par*>&);
|
||||
static dsql_req* prepareRequest(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, bool);
|
||||
static dsql_req* prepareStatement(thread_db*, dsql_dbb*, jrd_tra*, ULONG, const TEXT*, USHORT, bool);
|
||||
static UCHAR* put_item(UCHAR, const USHORT, const UCHAR*, UCHAR*, const UCHAR* const);
|
||||
@ -272,6 +269,12 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer)
|
||||
|
||||
dsql_msg* message = (dsql_msg*) statement->getReceiveMsg();
|
||||
|
||||
if (delayedFormat && message)
|
||||
{
|
||||
parseMetadata(delayedFormat, message->msg_parameters);
|
||||
delayedFormat = NULL;
|
||||
}
|
||||
|
||||
// Set up things for tracing this call
|
||||
Jrd::Attachment* att = req_dbb->dbb_attachment;
|
||||
TraceDSQLFetch trace(att, this);
|
||||
@ -285,13 +288,12 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer)
|
||||
|
||||
if (eofReached)
|
||||
{
|
||||
delayedFormat = NULL;
|
||||
trace.fetch(true, ITracePlugin::RESULT_SUCCESS);
|
||||
return false;
|
||||
}
|
||||
|
||||
map_in_out(tdbb, this, true, message, delayedFormat, msgBuffer);
|
||||
delayedFormat = NULL;
|
||||
if (msgBuffer)
|
||||
mapInOut(tdbb, true, message, NULL, msgBuffer);
|
||||
|
||||
trace.fetch(false, ITracePlugin::RESULT_SUCCESS);
|
||||
return true;
|
||||
@ -679,9 +681,9 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
|
||||
|
||||
const dsql_msg* message = statement->getSendMsg();
|
||||
if (message)
|
||||
map_in_out(tdbb, this, false, message, inMetadata, NULL, inMsg);
|
||||
mapInOut(tdbb, false, message, inMetadata, NULL, inMsg);
|
||||
|
||||
// we need to map_in_out before tracing of execution start to let trace
|
||||
// we need to mapInOut before tracing of execution start to let trace
|
||||
// manager know statement parameters values
|
||||
TraceDSQLExecute trace(req_dbb->dbb_attachment, this);
|
||||
|
||||
@ -713,7 +715,7 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
|
||||
}
|
||||
|
||||
if (outMetadata && message)
|
||||
parse_metadata(this, outMetadata, message->msg_parameters);
|
||||
parseMetadata(outMetadata, message->msg_parameters);
|
||||
|
||||
if ((outMsg && message) || isBlock)
|
||||
{
|
||||
@ -736,7 +738,7 @@ void DsqlDmlRequest::execute(thread_db* tdbb, jrd_tra** traHandle,
|
||||
JRD_receive(tdbb, req_request, message->msg_number, message->msg_length, msgBuffer);
|
||||
|
||||
if (outMsg)
|
||||
map_in_out(tdbb, this, true, message, NULL, outMsg);
|
||||
mapInOut(tdbb, true, message, NULL, outMsg);
|
||||
|
||||
// if this is a singleton select, make sure there's in fact one record
|
||||
|
||||
@ -989,13 +991,12 @@ static dsql_dbb* init(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
|
||||
/**
|
||||
|
||||
map_in_out
|
||||
mapInOut
|
||||
|
||||
@brief Map data from external world into message or
|
||||
from message to external world.
|
||||
|
||||
|
||||
@param request
|
||||
@param toExternal
|
||||
@param message
|
||||
@param meta
|
||||
@ -1003,10 +1004,10 @@ static dsql_dbb* init(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
@param in_dsql_msg_buf
|
||||
|
||||
**/
|
||||
static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, const dsql_msg* message,
|
||||
void dsql_req::mapInOut(thread_db* tdbb, bool toExternal, const dsql_msg* message,
|
||||
IMessageMetadata* meta, UCHAR* dsql_msg_buf, const UCHAR* in_dsql_msg_buf)
|
||||
{
|
||||
USHORT count = parse_metadata(request, meta, message->msg_parameters);
|
||||
USHORT count = parseMetadata(meta, message->msg_parameters);
|
||||
|
||||
// Sanity check
|
||||
|
||||
@ -1041,7 +1042,7 @@ static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, cons
|
||||
// Make sure the message given to us is long enough
|
||||
|
||||
dsc desc;
|
||||
if (!request->req_user_descs.get(parameter, desc))
|
||||
if (!req_user_descs.get(parameter, desc))
|
||||
desc.clear();
|
||||
|
||||
/***
|
||||
@ -1059,14 +1060,14 @@ static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, cons
|
||||
Arg::Gds(isc_dsql_sqlvar_index) << Arg::Num(parameter->par_index-1));
|
||||
}
|
||||
|
||||
UCHAR* msgBuffer = request->req_msg_buffers[parameter->par_message->msg_buffer_number];
|
||||
UCHAR* msgBuffer = req_msg_buffers[parameter->par_message->msg_buffer_number];
|
||||
|
||||
SSHORT* flag = NULL;
|
||||
dsql_par* const null_ind = parameter->par_null;
|
||||
if (null_ind != NULL)
|
||||
{
|
||||
dsc userNullDesc;
|
||||
if (!request->req_user_descs.get(null_ind, userNullDesc))
|
||||
if (!req_user_descs.get(null_ind, userNullDesc))
|
||||
userNullDesc.clear();
|
||||
|
||||
const ULONG null_offset = (IPTR) userNullDesc.dsc_address;
|
||||
@ -1129,7 +1130,7 @@ static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, cons
|
||||
Arg::Gds(isc_dsql_wrong_param_num) << Arg::Num(count) <<Arg::Num(count2));
|
||||
}
|
||||
|
||||
const DsqlCompiledStatement* statement = request->getStatement();
|
||||
const DsqlCompiledStatement* statement = getStatement();
|
||||
const dsql_par* parameter;
|
||||
|
||||
const dsql_par* dbkey;
|
||||
@ -1138,7 +1139,7 @@ static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, cons
|
||||
{
|
||||
UCHAR* parentMsgBuffer = statement->getParentRequest() ?
|
||||
statement->getParentRequest()->req_msg_buffers[dbkey->par_message->msg_buffer_number] : NULL;
|
||||
UCHAR* msgBuffer = request->req_msg_buffers[parameter->par_message->msg_buffer_number];
|
||||
UCHAR* msgBuffer = req_msg_buffers[parameter->par_message->msg_buffer_number];
|
||||
|
||||
fb_assert(parentMsgBuffer);
|
||||
|
||||
@ -1168,7 +1169,7 @@ static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, cons
|
||||
UCHAR* parentMsgBuffer = statement->getParentRequest() ?
|
||||
statement->getParentRequest()->req_msg_buffers[rec_version->par_message->msg_buffer_number] :
|
||||
NULL;
|
||||
UCHAR* msgBuffer = request->req_msg_buffers[parameter->par_message->msg_buffer_number];
|
||||
UCHAR* msgBuffer = req_msg_buffers[parameter->par_message->msg_buffer_number];
|
||||
|
||||
fb_assert(parentMsgBuffer);
|
||||
|
||||
@ -1195,18 +1196,16 @@ static void map_in_out(thread_db* tdbb, dsql_req* request, bool toExternal, cons
|
||||
|
||||
/**
|
||||
|
||||
parse_metadata
|
||||
parseMetadata
|
||||
|
||||
@brief Parse the message of a request.
|
||||
|
||||
|
||||
@param request
|
||||
@param meta
|
||||
@param parameters_list
|
||||
|
||||
**/
|
||||
static USHORT parse_metadata(dsql_req* request, IMessageMetadata* meta,
|
||||
const Array<dsql_par*>& parameters_list)
|
||||
USHORT dsql_req::parseMetadata(IMessageMetadata* meta, const Array<dsql_par*>& parameters_list)
|
||||
{
|
||||
HalfStaticArray<const dsql_par*, 16> parameters;
|
||||
|
||||
@ -1280,7 +1279,7 @@ static USHORT parse_metadata(dsql_req* request, IMessageMetadata* meta,
|
||||
if (desc.isText() && desc.getTextType() == ttype_dynamic)
|
||||
desc.setTextType(ttype_none);
|
||||
|
||||
request->req_user_descs.put(parameter, desc);
|
||||
req_user_descs.put(parameter, desc);
|
||||
|
||||
dsql_par* null = parameter->par_null;
|
||||
if (null)
|
||||
@ -1291,7 +1290,7 @@ static USHORT parse_metadata(dsql_req* request, IMessageMetadata* meta,
|
||||
desc.dsc_length = sizeof(SSHORT);
|
||||
desc.dsc_address = (UCHAR*)(IPTR) nullOffset;
|
||||
|
||||
request->req_user_descs.put(null, desc);
|
||||
req_user_descs.put(null, desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,6 +573,10 @@ public:
|
||||
|
||||
virtual void setDelayedFormat(thread_db* tdbb, Firebird::IMessageMetadata* metadata);
|
||||
|
||||
USHORT parseMetadata(Firebird::IMessageMetadata* meta, const Firebird::Array<dsql_par*>& parameters_list);
|
||||
void mapInOut(Jrd::thread_db* tdbb, bool toExternal, const dsql_msg* message, Firebird::IMessageMetadata* meta,
|
||||
UCHAR* dsql_msg_buf, const UCHAR* in_dsql_msg_buf = NULL);
|
||||
|
||||
static void destroy(thread_db* tdbb, dsql_req* request, bool drop);
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user