28
28
29
29
#include " ../dsql/dsql_proto.h"
30
30
#include " ../dsql/DsqlCursor.h"
31
+ #include " ../dsql/StmtNodes.h"
31
32
32
33
using namespace Firebird ;
33
34
using namespace Jrd ;
@@ -36,7 +37,8 @@ static const char* const SCRATCH = "fb_cursor_";
36
37
static const ULONG PREFETCH_SIZE = 65536 ; // 64 KB
37
38
38
39
DsqlCursor::DsqlCursor (DsqlDmlRequest* req, ULONG flags)
39
- : m_dsqlRequest(req), m_message(req->getDsqlStatement ()->getReceiveMsg()),
40
+ : m_dsqlRequest(req), m_message(req->getDsqlStatement ()->getReceiveMsg()->msg_number),
41
+ m_messageLength(0 ),
40
42
m_resultSet(NULL ), m_flags(flags),
41
43
m_space(req->getPool (), SCRATCH),
42
44
m_state(BOS), m_eof(false ), m_position(0 ), m_cachedCount(0 )
@@ -163,7 +165,7 @@ int DsqlCursor::fetchAbsolute(thread_db* tdbb, UCHAR* buffer, SLONG position)
163
165
{
164
166
if (!m_eof)
165
167
{
166
- cacheInput (tdbb);
168
+ cacheInput (tdbb, buffer );
167
169
fb_assert (m_eof);
168
170
}
169
171
@@ -248,7 +250,7 @@ void DsqlCursor::getInfo(thread_db* tdbb,
248
250
case IResultSet::INF_RECORD_COUNT:
249
251
if (isScrollable && !m_eof)
250
252
{
251
- cacheInput (tdbb);
253
+ cacheInput (tdbb, nullptr );
252
254
fb_assert (m_eof);
253
255
}
254
256
response.insertInt (tag, isScrollable ? m_cachedCount : -1 );
@@ -291,48 +293,62 @@ int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 positio
291
293
{
292
294
if (position >= m_cachedCount)
293
295
{
294
- if (m_eof || !cacheInput (tdbb, position))
296
+ if (m_eof || !cacheInput (tdbb, buffer, position))
295
297
{
296
298
m_state = EOS;
297
299
return 1 ;
298
300
}
299
301
}
300
302
301
303
fb_assert (position < m_cachedCount);
304
+ fb_assert (m_messageLength > 0 ); // At this point m_messageLength must be set by cacheInput
302
305
303
- UCHAR* const msgBuffer = m_dsqlRequest->req_msg_buffers [m_message->msg_buffer_number ];
304
-
305
- const FB_UINT64 offset = position * m_message->msg_length ;
306
- const FB_UINT64 readBytes = m_space.read (offset, msgBuffer, m_message->msg_length );
307
- fb_assert (readBytes == m_message->msg_length );
308
-
309
- m_dsqlRequest->mapInOut (tdbb, true , m_message, NULL , buffer);
306
+ const FB_UINT64 offset = position * m_messageLength;
307
+ const FB_UINT64 readBytes = m_space.read (offset, buffer, m_messageLength);
308
+ fb_assert (readBytes == m_messageLength);
310
309
311
310
m_position = position;
312
311
m_state = POSITIONED;
313
312
return 0 ;
314
313
}
315
314
316
- bool DsqlCursor::cacheInput (thread_db* tdbb, FB_UINT64 position)
315
+ bool DsqlCursor::cacheInput (thread_db* tdbb, UCHAR* buffer, FB_UINT64 position)
317
316
{
318
317
fb_assert (!m_eof);
319
318
320
- const ULONG prefetchCount = MAX (PREFETCH_SIZE / m_message->msg_length , 1 );
321
- const UCHAR* const msgBuffer = m_dsqlRequest->req_msg_buffers [m_message->msg_buffer_number ];
319
+ // It could not be done before: user buffer length may be unknown until call setDelayedOutputMetadata()
320
+ if (m_messageLength == 0 )
321
+ {
322
+ Request* req = m_dsqlRequest->getRequest ();
323
+ const MessageNode* msg = req->getStatement ()->messages [m_message];
324
+ m_messageLength = msg->getFormat (req)->fmt_length ;
325
+ }
326
+
327
+ std::unique_ptr<UCHAR[]> ownBuffer;
328
+ if (buffer == nullptr )
329
+ {
330
+ // We are called from getInfo() and there is no user-provided buffer for data.
331
+ // Create a temporary one.
332
+ // This code cannot be moved into getInfo() itself because it is most likely called before fetch()
333
+ // so m_messageLength is still unknown there.
334
+ ownBuffer.reset (buffer = new UCHAR[m_messageLength]);
335
+ }
336
+
337
+ const ULONG prefetchCount = MAX (PREFETCH_SIZE / m_messageLength, 1 );
322
338
323
339
while (position >= m_cachedCount)
324
340
{
325
341
for (ULONG count = 0 ; count < prefetchCount; count++)
326
342
{
327
- if (!m_dsqlRequest->fetch (tdbb, NULL ))
343
+ if (!m_dsqlRequest->fetch (tdbb, buffer ))
328
344
{
329
345
m_eof = true ;
330
346
break ;
331
347
}
332
348
333
- const FB_UINT64 offset = m_cachedCount * m_message-> msg_length ;
334
- const FB_UINT64 writtenBytes = m_space.write (offset, msgBuffer, m_message-> msg_length );
335
- fb_assert (writtenBytes == m_message-> msg_length );
349
+ const FB_UINT64 offset = m_cachedCount * m_messageLength ;
350
+ const FB_UINT64 writtenBytes = m_space.write (offset, buffer, m_messageLength );
351
+ fb_assert (writtenBytes == m_messageLength );
336
352
m_cachedCount++;
337
353
}
338
354
0 commit comments