Skip to content

Commit 44b76cc

Browse files
authored
Merge pull request #7083 from FirebirdSQL/cursor-info
ResultSet::getInfo() implementation
2 parents 5727c86 + 4c8f31f commit 44b76cc

File tree

14 files changed

+282
-29
lines changed

14 files changed

+282
-29
lines changed

doc/Using_OO_API.html

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,15 +1796,15 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
17961796
cursor (analogue of isc_dsql_set_cursor_name()). Parameter
17971797
cursorFlags is needed to open bidirectional cursor setting it's
17981798
value to Istatement::CURSOR_TYPE_SCROLLABLE.</font></p>
1799-
<li><p><font size="4" style="font-size: 14pt">I</font><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">Batch*
1799+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IBatch*
18001800
createBatch(StatusType* status, ITransaction* transaction, unsigned
18011801
stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata*
1802-
inMetadata, unsigned</font></font> <font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">parLength,
1802+
inMetadata, unsigned parLength,
18031803
const unsigned char* par) – prepares sqlStmt and creates <a href="#Batch">Batch</a>
18041804
interface ready to accept multiple sets of input parameters in
1805-
inMetadata format. Leaving inMetadata</font></font> <font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">NULL
1805+
inMetadata format. Leaving inMetadata NULL
18061806
makes batch use default format for sqlStmt. Parameters block may be
1807-
passed to createBatch() making it possible to adjust batch behavior.</font></font></p>
1807+
passed to createBatch() making it possible to adjust batch behavior.</font></p>
18081808
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IEvents*
18091809
queEvents(StatusType* status, IEventCallback* callback, unsigned
18101810
length, const unsigned char* events) – replaces isc_que_events()
@@ -1951,7 +1951,6 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
19511951
<a href="#Batch">Batch</a> interface. It contains more or less
19521952
(depending upon parameters passed when <a href="#Batch">Batch</a> was
19531953
created) detailed information about the results of batch execution.</font></p>
1954-
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">{</font></p>
19551954
<ol>
19561955
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">uint
19571956
getSize(StatusType* status) – returns the total number of
@@ -2377,14 +2376,13 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
23772376
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">unsigned
23782377
getMessageLength(StatusType* status) - returns length of message
23792378
buffer (use it to allocate memory for the buffer).</font></p>
2380-
<li><p><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">unsigned
2379+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">unsigned
23812380
getAlignment(StatusType* status) – returns alignment required for
2382-
message buffer.</font></font></p>
2383-
<li><p><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">unsigned</font></font>
2384-
<font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">getAlignedLength(StatusType*
2385-
status) – returns length of message buffer taking into an account
2381+
message buffer.</font></p>
2382+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">unsigned
2383+
getAlignedLength(StatusType* status) – returns length of message buffer taking into an account
23862384
alignment requirements (use it to allocate memory for an array of
2387-
buffers and navigate through that array).</font></font></p>
2385+
buffers and navigate through that array).</font></p>
23882386
</ol>
23892387
<p style="margin-bottom: 0cm"><br/>
23902388

@@ -2426,18 +2424,18 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
24262424
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IMessageMetadata*
24272425
getMetadata(StatusType* status) – get <a href="#10. MessageMetadata">MessageMetadata</a>
24282426
interface built by this builder.</font></p>
2429-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
2427+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
24302428
setField(StatusType* status, uint index, const string field) – set
2431-
name of a field / column.</font></font></p>
2432-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
2429+
name of a field / column.</font></p>
2430+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
24332431
setRelation(StatusType* status, uint index, const string relation) –
2434-
set name of the relation from which the field was selected.</font></font></p>
2435-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
2432+
set name of the relation from which the field was selected.</font></p>
2433+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
24362434
setOwner(StatusType* status, uint index, const string owner) – set
2437-
name of that relation owner.</font></font></p>
2438-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
2435+
name of that relation owner.</font></p>
2436+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
24392437
setAlias(StatusType* status, uint index, const string alias) – set
2440-
alias name of the field in related statement.</font></font></p>
2438+
alias name of the field in related statement.</font></p>
24412439
</ol>
24422440
<p style="margin-bottom: 0cm"><br/>
24432441

@@ -2639,6 +2637,11 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
26392637
in <a href="#Attachment">IAttachment</a> or <a href="#Statement">IStatement</a>.
26402638
All fetch calls except fetchNext() work only for bidirectional
26412639
(opened with CURSOR_TYPE_SCROLLABLE flag) result set.</font></p>
2640+
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Items
2641+
accepted in getInfo() call:</font></p>
2642+
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">INF_RECORD_COUNT
2643+
– number of records stored inside a scrollable cursor, or -1 for a uni-directional cursor.</font></p>
2644+
<p style="margin-bottom: 0cm"><br/>
26422645
<ol>
26432646
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">int
26442647
fetchNext(StatusType* status, void* message) – fetch next record,
@@ -2673,6 +2676,10 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
26732676
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
26742677
close(StatusType* status) – close result set, releases interface
26752678
on success.</font></p>
2679+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
2680+
getInfo(StatusType* status, unsigned itemsLength, const unsigned
2681+
char* items, unsigned bufferLength, unsigned char* buffer) –
2682+
retrieve information about result set.</font></p>
26762683
</ol>
26772684
<p style="margin-bottom: 0cm"><br/>
26782685

@@ -2733,27 +2740,27 @@ <h1><font size="4" style="font-size: 14pt">Generic interfaces.</font></h1>
27332740
returning multiple rows of data. Partial analogue of
27342741
isc_dsql_execute2() - in and out XSLQDAs replaced with input and
27352742
output messages with appropriate buffers.</font></p>
2736-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">IResultSet*
2743+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IResultSet*
27372744
openCursor(StatusType* status, ITransaction* transaction,
27382745
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata*
27392746
outMetadata, unsigned flags) – executes SQL statement potentially
27402747
returning multiple rows of data. Returns <a href="#ResultSet">ResultSet</a>
27412748
interface which should be used to fetch that data. Format of output
27422749
data is defined by outMetadata parameter, leaving it NULL default
27432750
format may be used. Parameter flags is needed to open bidirectional
2744-
cursor setting it's value to Istatement::CURSOR_TYPE_SCROLLABLE.</font></font></p>
2745-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">IBatch*
2751+
cursor setting it's value to Istatement::CURSOR_TYPE_SCROLLABLE.</font></p>
2752+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IBatch*
27462753
createBatch(StatusType* status, IMessageMetadata* inMetadata, uint
27472754
parLength, const uchar* par) – creates <a href="#Batch">Batch</a>
27482755
interface to SQL statement with input parameters making it possible
27492756
to execute that statement with multiple sets of parameters. Format
27502757
of input data is defined by inMetadata parameter, leaving it NULL
27512758
makes batch use default format from this interface. Parameters block
27522759
may be passed to createBatch() making it possible to adjust batch
2753-
behavior.</font></font></p>
2754-
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
2760+
behavior.</font></p>
2761+
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
27552762
setCursorName(StatusType* status, const char* name) – replaces
2756-
isc_dsql_set_cursor_name(). </font></font>
2763+
isc_dsql_set_cursor_name().</font>
27572764
</p>
27582765
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
27592766
free(StatusType* status) – free statement, releases interface on

src/dsql/DsqlCursor.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
*/
2222

2323
#include "firebird.h"
24+
#include "../common/classes/ClumpletWriter.h"
2425
#include "../jrd/tra_proto.h"
2526
#include "../jrd/trace/TraceManager.h"
2627
#include "../jrd/trace/TraceDSQLHelpers.h"
2728

29+
#include "../dsql/dsql_proto.h"
2830
#include "../dsql/DsqlCursor.h"
2931

3032
using namespace Firebird;
@@ -210,6 +212,81 @@ int DsqlCursor::fetchRelative(thread_db* tdbb, UCHAR* buffer, SLONG offset)
210212
return fetchFromCache(tdbb, buffer, position);
211213
}
212214

215+
void DsqlCursor::getInfo(thread_db* tdbb,
216+
unsigned int itemsLength, const unsigned char* items,
217+
unsigned int bufferLength, unsigned char* buffer)
218+
{
219+
if (bufferLength < 7) // isc_info_error + 2-byte length + 4-byte error code
220+
{
221+
if (bufferLength)
222+
*buffer = isc_info_truncated;
223+
return;
224+
}
225+
226+
const bool isScrollable = (m_flags & IStatement::CURSOR_TYPE_SCROLLABLE);
227+
228+
ClumpletWriter response(ClumpletReader::InfoResponse, bufferLength - 1); // isc_info_end
229+
ISC_STATUS errorCode = 0;
230+
bool needLength = false, completed = false;
231+
232+
try
233+
{
234+
ClumpletReader infoItems(ClumpletReader::InfoItems, items, itemsLength);
235+
for (infoItems.rewind(); !errorCode && !infoItems.isEof(); infoItems.moveNext())
236+
{
237+
const auto tag = infoItems.getClumpTag();
238+
239+
switch (tag)
240+
{
241+
case isc_info_end:
242+
break;
243+
244+
case isc_info_length:
245+
needLength = true;
246+
break;
247+
248+
case IResultSet::INF_RECORD_COUNT:
249+
if (isScrollable && !m_eof)
250+
{
251+
cacheInput(tdbb);
252+
fb_assert(m_eof);
253+
}
254+
response.insertInt(tag, isScrollable ? m_cachedCount : -1);
255+
break;
256+
257+
default:
258+
errorCode = isc_infunk;
259+
break;
260+
}
261+
}
262+
263+
completed = infoItems.isEof();
264+
265+
if (needLength && completed)
266+
{
267+
response.rewind();
268+
response.insertInt(isc_info_length, response.getBufferLength() + 1); // isc_info_end
269+
}
270+
}
271+
catch (const Exception&)
272+
{
273+
if (!response.hasOverflow())
274+
throw;
275+
}
276+
277+
if (errorCode)
278+
{
279+
response.clear();
280+
response.insertInt(isc_info_error, (SLONG) errorCode);
281+
}
282+
283+
fb_assert(response.getBufferLength() <= bufferLength);
284+
memcpy(buffer, response.getBuffer(), response.getBufferLength());
285+
buffer += response.getBufferLength();
286+
287+
*buffer = completed ? isc_info_end : isc_info_truncated;
288+
}
289+
213290
int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position)
214291
{
215292
if (position >= m_cachedCount)

src/dsql/DsqlCursor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ class DsqlCursor
6161
return (m_state == EOS);
6262
}
6363

64+
void getInfo(thread_db* tdbb,
65+
unsigned int itemsLength, const unsigned char* items,
66+
unsigned int bufferLength, unsigned char* buffer);
67+
6468
private:
6569
int fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position);
6670
bool cacheInput(thread_db* tdbb, FB_UINT64 position = MAX_UINT64);

src/include/firebird/FirebirdInterface.idl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ version: // 3.0 => 4.0
433433

434434
interface ResultSet : ReferenceCounted
435435
{
436+
// Info items
437+
const uchar INF_RECORD_COUNT = 10; // Number of records in the result set
438+
436439
[notImplemented(Status::RESULT_ERROR)] int fetchNext(Status status, void* message);
437440
[notImplemented(Status::RESULT_ERROR)] int fetchPrior(Status status, void* message);
438441
[notImplemented(Status::RESULT_ERROR)] int fetchFirst(Status status, void* message);
@@ -452,6 +455,11 @@ interface ResultSet : ReferenceCounted
452455
version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1
453456
[notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif]
454457
void close(Status status);
458+
459+
version: // 4.0.1 => 5.0
460+
void getInfo(Status status,
461+
uint itemsLength, const uchar* items,
462+
uint bufferLength, uchar* buffer);
455463
}
456464

457465
interface Statement : ReferenceCounted

src/include/firebird/IdlFbInterfaces.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,7 @@ namespace Firebird
16681668
void (CLOOP_CARG *deprecatedClose)(IResultSet* self, IStatus* status) throw();
16691669
void (CLOOP_CARG *setDelayedOutputFormat)(IResultSet* self, IStatus* status, IMessageMetadata* format) throw();
16701670
void (CLOOP_CARG *close)(IResultSet* self, IStatus* status) throw();
1671+
void (CLOOP_CARG *getInfo)(IResultSet* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw();
16711672
};
16721673

16731674
protected:
@@ -1681,7 +1682,9 @@ namespace Firebird
16811682
}
16821683

16831684
public:
1684-
static const unsigned VERSION = 4;
1685+
static const unsigned VERSION = 5;
1686+
1687+
static const unsigned char INF_RECORD_COUNT = 10;
16851688

16861689
template <typename StatusType> int fetchNext(StatusType* status, void* message)
16871690
{
@@ -1786,6 +1789,19 @@ namespace Firebird
17861789
static_cast<VTable*>(this->cloopVTable)->close(this, status);
17871790
StatusType::checkException(status);
17881791
}
1792+
1793+
template <typename StatusType> void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer)
1794+
{
1795+
if (cloopVTable->version < 5)
1796+
{
1797+
StatusType::setVersionError(status, "IResultSet", cloopVTable->version, 5);
1798+
StatusType::checkException(status);
1799+
return;
1800+
}
1801+
StatusType::clearException(status);
1802+
static_cast<VTable*>(this->cloopVTable)->getInfo(this, status, itemsLength, items, bufferLength, buffer);
1803+
StatusType::checkException(status);
1804+
}
17891805
};
17901806

17911807
class IStatement : public IReferenceCounted
@@ -9620,6 +9636,7 @@ namespace Firebird
96209636
this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher;
96219637
this->setDelayedOutputFormat = &Name::cloopsetDelayedOutputFormatDispatcher;
96229638
this->close = &Name::cloopcloseDispatcher;
9639+
this->getInfo = &Name::cloopgetInfoDispatcher;
96239640
}
96249641
} vTable;
96259642

@@ -9803,6 +9820,20 @@ namespace Firebird
98039820
}
98049821
}
98059822

9823+
static void CLOOP_CARG cloopgetInfoDispatcher(IResultSet* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw()
9824+
{
9825+
StatusType status2(status);
9826+
9827+
try
9828+
{
9829+
static_cast<Name*>(self)->Name::getInfo(&status2, itemsLength, items, bufferLength, buffer);
9830+
}
9831+
catch (...)
9832+
{
9833+
StatusType::catchException(&status2);
9834+
}
9835+
}
9836+
98069837
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
98079838
{
98089839
try
@@ -9854,6 +9885,7 @@ namespace Firebird
98549885
virtual void deprecatedClose(StatusType* status) = 0;
98559886
virtual void setDelayedOutputFormat(StatusType* status, IMessageMetadata* format) = 0;
98569887
virtual void close(StatusType* status) = 0;
9888+
virtual void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) = 0;
98579889
};
98589890

98599891
template <typename Name, typename StatusType, typename Base>

0 commit comments

Comments
 (0)