mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 17:23:03 +01:00
Merge pull request #7083 from FirebirdSQL/cursor-info
ResultSet::getInfo() implementation
This commit is contained in:
commit
44b76cc2ea
@ -1796,15 +1796,15 @@ interface – replaces isc_db_handle:</font></p>
|
||||
cursor (analogue of isc_dsql_set_cursor_name()). Parameter
|
||||
cursorFlags is needed to open bidirectional cursor setting it's
|
||||
value to Istatement::CURSOR_TYPE_SCROLLABLE.</font></p>
|
||||
<li><p><font size="4" style="font-size: 14pt">I</font><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">Batch*
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IBatch*
|
||||
createBatch(StatusType* status, ITransaction* transaction, unsigned
|
||||
stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata*
|
||||
inMetadata, unsigned</font></font> <font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">parLength,
|
||||
inMetadata, unsigned parLength,
|
||||
const unsigned char* par) – prepares sqlStmt and creates <a href="#Batch">Batch</a>
|
||||
interface ready to accept multiple sets of input parameters in
|
||||
inMetadata format. Leaving inMetadata</font></font> <font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">NULL
|
||||
inMetadata format. Leaving inMetadata NULL
|
||||
makes batch use default format for sqlStmt. Parameters block may be
|
||||
passed to createBatch() making it possible to adjust batch behavior.</font></font></p>
|
||||
passed to createBatch() making it possible to adjust batch behavior.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IEvents*
|
||||
queEvents(StatusType* status, IEventCallback* callback, unsigned
|
||||
length, const unsigned char* events) – replaces isc_que_events()
|
||||
@ -1951,7 +1951,6 @@ possible buffer size (one set by TAG_BUFFER_BYTES_SIZE)</font></p>
|
||||
<a href="#Batch">Batch</a> interface. It contains more or less
|
||||
(depending upon parameters passed when <a href="#Batch">Batch</a> was
|
||||
created) detailed information about the results of batch execution.</font></p>
|
||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">{</font></p>
|
||||
<ol>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">uint
|
||||
getSize(StatusType* status) – returns the total number of
|
||||
@ -2377,14 +2376,13 @@ with execution of SQL statements.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">unsigned
|
||||
getMessageLength(StatusType* status) - returns length of message
|
||||
buffer (use it to allocate memory for the buffer).</font></p>
|
||||
<li><p><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">unsigned
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">unsigned
|
||||
getAlignment(StatusType* status) – returns alignment required for
|
||||
message buffer.</font></font></p>
|
||||
<li><p><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">unsigned</font></font>
|
||||
<font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">getAlignedLength(StatusType*
|
||||
status) – returns length of message buffer taking into an account
|
||||
message buffer.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">unsigned
|
||||
getAlignedLength(StatusType* status) – returns length of message buffer taking into an account
|
||||
alignment requirements (use it to allocate memory for an array of
|
||||
buffers and navigate through that array).</font></font></p>
|
||||
buffers and navigate through that array).</font></p>
|
||||
</ol>
|
||||
<p style="margin-bottom: 0cm"><br/>
|
||||
|
||||
@ -2426,18 +2424,18 @@ message or construct metadata from the beginning.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IMessageMetadata*
|
||||
getMetadata(StatusType* status) – get <a href="#10. MessageMetadata">MessageMetadata</a>
|
||||
interface built by this builder.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
setField(StatusType* status, uint index, const string field) – set
|
||||
name of a field / column.</font></font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
|
||||
name of a field / column.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
setRelation(StatusType* status, uint index, const string relation) –
|
||||
set name of the relation from which the field was selected.</font></font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
|
||||
set name of the relation from which the field was selected.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
setOwner(StatusType* status, uint index, const string owner) – set
|
||||
name of that relation owner.</font></font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
|
||||
name of that relation owner.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
setAlias(StatusType* status, uint index, const string alias) – set
|
||||
alias name of the field in related statement.</font></font></p>
|
||||
alias name of the field in related statement.</font></p>
|
||||
</ol>
|
||||
<p style="margin-bottom: 0cm"><br/>
|
||||
|
||||
@ -2639,6 +2637,11 @@ of isc_stmt_handle. This interface is returned by openCursor() call
|
||||
in <a href="#Attachment">IAttachment</a> or <a href="#Statement">IStatement</a>.
|
||||
All fetch calls except fetchNext() work only for bidirectional
|
||||
(opened with CURSOR_TYPE_SCROLLABLE flag) result set.</font></p>
|
||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">Items
|
||||
accepted in getInfo() call:</font></p>
|
||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">INF_RECORD_COUNT
|
||||
– number of records stored inside a scrollable cursor, or -1 for a uni-directional cursor.</font></p>
|
||||
<p style="margin-bottom: 0cm"><br/>
|
||||
<ol>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">int
|
||||
fetchNext(StatusType* status, void* message) – fetch next record,
|
||||
@ -2673,6 +2676,10 @@ All fetch calls except fetchNext() work only for bidirectional
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
close(StatusType* status) – close result set, releases interface
|
||||
on success.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
getInfo(StatusType* status, unsigned itemsLength, const unsigned
|
||||
char* items, unsigned bufferLength, unsigned char* buffer) –
|
||||
retrieve information about result set.</font></p>
|
||||
</ol>
|
||||
<p style="margin-bottom: 0cm"><br/>
|
||||
|
||||
@ -2733,7 +2740,7 @@ interface – replaces (partially) isc_stmt_handle.</font></p>
|
||||
returning multiple rows of data. Partial analogue of
|
||||
isc_dsql_execute2() - in and out XSLQDAs replaced with input and
|
||||
output messages with appropriate buffers.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">IResultSet*
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IResultSet*
|
||||
openCursor(StatusType* status, ITransaction* transaction,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata*
|
||||
outMetadata, unsigned flags) – executes SQL statement potentially
|
||||
@ -2741,8 +2748,8 @@ interface – replaces (partially) isc_stmt_handle.</font></p>
|
||||
interface which should be used to fetch that data. Format of output
|
||||
data is defined by outMetadata parameter, leaving it NULL default
|
||||
format may be used. Parameter flags is needed to open bidirectional
|
||||
cursor setting it's value to Istatement::CURSOR_TYPE_SCROLLABLE.</font></font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">IBatch*
|
||||
cursor setting it's value to Istatement::CURSOR_TYPE_SCROLLABLE.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">IBatch*
|
||||
createBatch(StatusType* status, IMessageMetadata* inMetadata, uint
|
||||
parLength, const uchar* par) – creates <a href="#Batch">Batch</a>
|
||||
interface to SQL statement with input parameters making it possible
|
||||
@ -2750,10 +2757,10 @@ interface – replaces (partially) isc_stmt_handle.</font></p>
|
||||
of input data is defined by inMetadata parameter, leaving it NULL
|
||||
makes batch use default format from this interface. Parameters block
|
||||
may be passed to createBatch() making it possible to adjust batch
|
||||
behavior.</font></font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font face="Liberation Serif, serif"><font size="4" style="font-size: 14pt">void
|
||||
behavior.</font></p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
setCursorName(StatusType* status, const char* name) – replaces
|
||||
isc_dsql_set_cursor_name(). </font></font>
|
||||
isc_dsql_set_cursor_name().</font>
|
||||
</p>
|
||||
<li><p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">void
|
||||
free(StatusType* status) – free statement, releases interface on
|
||||
|
@ -21,10 +21,12 @@
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../common/classes/ClumpletWriter.h"
|
||||
#include "../jrd/tra_proto.h"
|
||||
#include "../jrd/trace/TraceManager.h"
|
||||
#include "../jrd/trace/TraceDSQLHelpers.h"
|
||||
|
||||
#include "../dsql/dsql_proto.h"
|
||||
#include "../dsql/DsqlCursor.h"
|
||||
|
||||
using namespace Firebird;
|
||||
@ -210,6 +212,81 @@ int DsqlCursor::fetchRelative(thread_db* tdbb, UCHAR* buffer, SLONG offset)
|
||||
return fetchFromCache(tdbb, buffer, position);
|
||||
}
|
||||
|
||||
void DsqlCursor::getInfo(thread_db* tdbb,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer)
|
||||
{
|
||||
if (bufferLength < 7) // isc_info_error + 2-byte length + 4-byte error code
|
||||
{
|
||||
if (bufferLength)
|
||||
*buffer = isc_info_truncated;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isScrollable = (m_flags & IStatement::CURSOR_TYPE_SCROLLABLE);
|
||||
|
||||
ClumpletWriter response(ClumpletReader::InfoResponse, bufferLength - 1); // isc_info_end
|
||||
ISC_STATUS errorCode = 0;
|
||||
bool needLength = false, completed = false;
|
||||
|
||||
try
|
||||
{
|
||||
ClumpletReader infoItems(ClumpletReader::InfoItems, items, itemsLength);
|
||||
for (infoItems.rewind(); !errorCode && !infoItems.isEof(); infoItems.moveNext())
|
||||
{
|
||||
const auto tag = infoItems.getClumpTag();
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
case isc_info_end:
|
||||
break;
|
||||
|
||||
case isc_info_length:
|
||||
needLength = true;
|
||||
break;
|
||||
|
||||
case IResultSet::INF_RECORD_COUNT:
|
||||
if (isScrollable && !m_eof)
|
||||
{
|
||||
cacheInput(tdbb);
|
||||
fb_assert(m_eof);
|
||||
}
|
||||
response.insertInt(tag, isScrollable ? m_cachedCount : -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
errorCode = isc_infunk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
completed = infoItems.isEof();
|
||||
|
||||
if (needLength && completed)
|
||||
{
|
||||
response.rewind();
|
||||
response.insertInt(isc_info_length, response.getBufferLength() + 1); // isc_info_end
|
||||
}
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
if (!response.hasOverflow())
|
||||
throw;
|
||||
}
|
||||
|
||||
if (errorCode)
|
||||
{
|
||||
response.clear();
|
||||
response.insertInt(isc_info_error, (SLONG) errorCode);
|
||||
}
|
||||
|
||||
fb_assert(response.getBufferLength() <= bufferLength);
|
||||
memcpy(buffer, response.getBuffer(), response.getBufferLength());
|
||||
buffer += response.getBufferLength();
|
||||
|
||||
*buffer = completed ? isc_info_end : isc_info_truncated;
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position)
|
||||
{
|
||||
if (position >= m_cachedCount)
|
||||
|
@ -61,6 +61,10 @@ public:
|
||||
return (m_state == EOS);
|
||||
}
|
||||
|
||||
void getInfo(thread_db* tdbb,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer);
|
||||
|
||||
private:
|
||||
int fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position);
|
||||
bool cacheInput(thread_db* tdbb, FB_UINT64 position = MAX_UINT64);
|
||||
|
@ -433,6 +433,9 @@ version: // 3.0 => 4.0
|
||||
|
||||
interface ResultSet : ReferenceCounted
|
||||
{
|
||||
// Info items
|
||||
const uchar INF_RECORD_COUNT = 10; // Number of records in the result set
|
||||
|
||||
[notImplemented(Status::RESULT_ERROR)] int fetchNext(Status status, void* message);
|
||||
[notImplemented(Status::RESULT_ERROR)] int fetchPrior(Status status, void* message);
|
||||
[notImplemented(Status::RESULT_ERROR)] int fetchFirst(Status status, void* message);
|
||||
@ -452,6 +455,11 @@ interface ResultSet : ReferenceCounted
|
||||
version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1
|
||||
[notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif]
|
||||
void close(Status status);
|
||||
|
||||
version: // 4.0.1 => 5.0
|
||||
void getInfo(Status status,
|
||||
uint itemsLength, const uchar* items,
|
||||
uint bufferLength, uchar* buffer);
|
||||
}
|
||||
|
||||
interface Statement : ReferenceCounted
|
||||
|
@ -1668,6 +1668,7 @@ namespace Firebird
|
||||
void (CLOOP_CARG *deprecatedClose)(IResultSet* self, IStatus* status) throw();
|
||||
void (CLOOP_CARG *setDelayedOutputFormat)(IResultSet* self, IStatus* status, IMessageMetadata* format) throw();
|
||||
void (CLOOP_CARG *close)(IResultSet* self, IStatus* status) throw();
|
||||
void (CLOOP_CARG *getInfo)(IResultSet* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -1681,7 +1682,9 @@ namespace Firebird
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 4;
|
||||
static const unsigned VERSION = 5;
|
||||
|
||||
static const unsigned char INF_RECORD_COUNT = 10;
|
||||
|
||||
template <typename StatusType> int fetchNext(StatusType* status, void* message)
|
||||
{
|
||||
@ -1786,6 +1789,19 @@ namespace Firebird
|
||||
static_cast<VTable*>(this->cloopVTable)->close(this, status);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
template <typename StatusType> void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer)
|
||||
{
|
||||
if (cloopVTable->version < 5)
|
||||
{
|
||||
StatusType::setVersionError(status, "IResultSet", cloopVTable->version, 5);
|
||||
StatusType::checkException(status);
|
||||
return;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->getInfo(this, status, itemsLength, items, bufferLength, buffer);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
};
|
||||
|
||||
class IStatement : public IReferenceCounted
|
||||
@ -9620,6 +9636,7 @@ namespace Firebird
|
||||
this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher;
|
||||
this->setDelayedOutputFormat = &Name::cloopsetDelayedOutputFormatDispatcher;
|
||||
this->close = &Name::cloopcloseDispatcher;
|
||||
this->getInfo = &Name::cloopgetInfoDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -9803,6 +9820,20 @@ namespace Firebird
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopgetInfoDispatcher(IResultSet* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::getInfo(&status2, itemsLength, items, bufferLength, buffer);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
|
||||
{
|
||||
try
|
||||
@ -9854,6 +9885,7 @@ namespace Firebird
|
||||
virtual void deprecatedClose(StatusType* status) = 0;
|
||||
virtual void setDelayedOutputFormat(StatusType* status, IMessageMetadata* format) = 0;
|
||||
virtual void close(StatusType* status) = 0;
|
||||
virtual void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
|
@ -339,6 +339,7 @@ type
|
||||
IResultSet_deprecatedClosePtr = procedure(this: IResultSet; status: IStatus); cdecl;
|
||||
IResultSet_setDelayedOutputFormatPtr = procedure(this: IResultSet; status: IStatus; format: IMessageMetadata); cdecl;
|
||||
IResultSet_closePtr = procedure(this: IResultSet; status: IStatus); cdecl;
|
||||
IResultSet_getInfoPtr = procedure(this: IResultSet; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
|
||||
IStatement_getInfoPtr = procedure(this: IStatement; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
|
||||
IStatement_getTypePtr = function(this: IStatement; status: IStatus): Cardinal; cdecl;
|
||||
IStatement_getPlanPtr = function(this: IStatement; status: IStatus; detailed: Boolean): PAnsiChar; cdecl;
|
||||
@ -1425,10 +1426,12 @@ type
|
||||
deprecatedClose: IResultSet_deprecatedClosePtr;
|
||||
setDelayedOutputFormat: IResultSet_setDelayedOutputFormatPtr;
|
||||
close: IResultSet_closePtr;
|
||||
getInfo: IResultSet_getInfoPtr;
|
||||
end;
|
||||
|
||||
IResultSet = class(IReferenceCounted)
|
||||
const VERSION = 4;
|
||||
const VERSION = 5;
|
||||
const INF_RECORD_COUNT = Byte(10);
|
||||
|
||||
function fetchNext(status: IStatus; message: Pointer): Integer;
|
||||
function fetchPrior(status: IStatus; message: Pointer): Integer;
|
||||
@ -1442,6 +1445,7 @@ type
|
||||
procedure deprecatedClose(status: IStatus);
|
||||
procedure setDelayedOutputFormat(status: IStatus; format: IMessageMetadata);
|
||||
procedure close(status: IStatus);
|
||||
procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr);
|
||||
end;
|
||||
|
||||
IResultSetImpl = class(IResultSet)
|
||||
@ -1461,6 +1465,7 @@ type
|
||||
procedure deprecatedClose(status: IStatus); virtual; abstract;
|
||||
procedure setDelayedOutputFormat(status: IStatus; format: IMessageMetadata); virtual; abstract;
|
||||
procedure close(status: IStatus); virtual; abstract;
|
||||
procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract;
|
||||
end;
|
||||
|
||||
StatementVTable = class(ReferenceCountedVTable)
|
||||
@ -6501,6 +6506,17 @@ begin
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IResultSet.getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr);
|
||||
begin
|
||||
if (vTable.version < 5) then begin
|
||||
FbException.setVersionError(status, 'IResultSet', vTable.version, 5);
|
||||
end
|
||||
else begin
|
||||
ResultSetVTable(vTable).getInfo(Self, status, itemsLength, items, bufferLength, buffer);
|
||||
end;
|
||||
FbException.checkException(status);
|
||||
end;
|
||||
|
||||
procedure IStatement.getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr);
|
||||
begin
|
||||
StatementVTable(vTable).getInfo(Self, status, itemsLength, items, bufferLength, buffer);
|
||||
@ -10435,6 +10451,15 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
procedure IResultSetImpl_getInfoDispatcher(this: IResultSet; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
|
||||
begin
|
||||
try
|
||||
IResultSetImpl(this).getInfo(status, itemsLength, items, bufferLength, buffer);
|
||||
except
|
||||
on e: Exception do FbException.catchException(status, e);
|
||||
end
|
||||
end;
|
||||
|
||||
var
|
||||
IResultSetImpl_vTable: ResultSetVTable;
|
||||
|
||||
@ -15620,7 +15645,7 @@ initialization
|
||||
IMetadataBuilderImpl_vTable.setAlias := @IMetadataBuilderImpl_setAliasDispatcher;
|
||||
|
||||
IResultSetImpl_vTable := ResultSetVTable.create;
|
||||
IResultSetImpl_vTable.version := 4;
|
||||
IResultSetImpl_vTable.version := 5;
|
||||
IResultSetImpl_vTable.addRef := @IResultSetImpl_addRefDispatcher;
|
||||
IResultSetImpl_vTable.release := @IResultSetImpl_releaseDispatcher;
|
||||
IResultSetImpl_vTable.fetchNext := @IResultSetImpl_fetchNextDispatcher;
|
||||
@ -15635,6 +15660,7 @@ initialization
|
||||
IResultSetImpl_vTable.deprecatedClose := @IResultSetImpl_deprecatedCloseDispatcher;
|
||||
IResultSetImpl_vTable.setDelayedOutputFormat := @IResultSetImpl_setDelayedOutputFormatDispatcher;
|
||||
IResultSetImpl_vTable.close := @IResultSetImpl_closeDispatcher;
|
||||
IResultSetImpl_vTable.getInfo := @IResultSetImpl_getInfoDispatcher;
|
||||
|
||||
IStatementImpl_vTable := StatementVTable.create;
|
||||
IStatementImpl_vTable.version := 5;
|
||||
|
@ -169,6 +169,9 @@ public:
|
||||
void close(Firebird::CheckStatusWrapper* status) override;
|
||||
void deprecatedClose(Firebird::CheckStatusWrapper* status) override;
|
||||
void setDelayedOutputFormat(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* format) override;
|
||||
void getInfo(Firebird::CheckStatusWrapper* status,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer) override;
|
||||
|
||||
public:
|
||||
JResultSet(DsqlCursor* handle, JStatement* aStatement);
|
||||
|
@ -5471,6 +5471,34 @@ IMessageMetadata* JResultSet::getMetadata(CheckStatusWrapper* user_status)
|
||||
}
|
||||
|
||||
|
||||
void JResultSet::getInfo(CheckStatusWrapper* user_status,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
cursor->getInfo(tdbb, itemsLength, items, bufferLength, buffer);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::getInfo");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(user_status);
|
||||
return;
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
}
|
||||
|
||||
void JResultSet::deprecatedClose(CheckStatusWrapper* user_status)
|
||||
{
|
||||
freeEngineData(user_status);
|
||||
|
@ -292,6 +292,9 @@ public:
|
||||
void close(CheckStatusWrapper* status) override;
|
||||
void deprecatedClose(CheckStatusWrapper* status) override;
|
||||
void setDelayedOutputFormat(CheckStatusWrapper* status, IMessageMetadata* format) override;
|
||||
void getInfo(CheckStatusWrapper* status,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer) override;
|
||||
|
||||
ResultSet(Statement* s, IMessageMetadata* outFmt, unsigned f)
|
||||
: stmt(s), flags(f), tmpStatement(false), delayedFormat(outFmt == DELAYED_OUT_FORMAT)
|
||||
@ -5062,6 +5065,38 @@ IMessageMetadata* ResultSet::getMetadata(CheckStatusWrapper* status)
|
||||
return outputFormat;
|
||||
}
|
||||
|
||||
void ResultSet::getInfo(CheckStatusWrapper* status,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
reset(status);
|
||||
|
||||
// Check and validate handles, etc.
|
||||
|
||||
if (!stmt)
|
||||
Arg::Gds(isc_dsql_cursor_err).raise();
|
||||
|
||||
const auto statement = stmt->getStatement();
|
||||
CHECK_HANDLE(statement, isc_bad_req_handle);
|
||||
|
||||
const auto rdb = statement->rsr_rdb;
|
||||
const auto port = rdb->rdb_port;
|
||||
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
|
||||
|
||||
if (port->port_protocol < PROTOCOL_FETCH_SCROLL)
|
||||
unsupported();
|
||||
|
||||
info(status, rdb, op_info_cursor, statement->rsr_id, 0,
|
||||
itemsLength, items, 0, 0, bufferLength, buffer);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(status);
|
||||
}
|
||||
}
|
||||
|
||||
void ResultSet::freeClientData(CheckStatusWrapper* status, bool force)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -507,6 +507,7 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p)
|
||||
case op_service_info:
|
||||
case op_info_sql:
|
||||
case op_info_batch:
|
||||
case op_info_cursor:
|
||||
info = &p->p_info;
|
||||
MAP(xdr_short, reinterpret_cast<SSHORT&>(info->p_info_object));
|
||||
MAP(xdr_short, reinterpret_cast<SSHORT&>(info->p_info_incarnation));
|
||||
|
@ -316,6 +316,7 @@ enum P_OP
|
||||
op_info_batch = 111,
|
||||
|
||||
op_fetch_scroll = 112,
|
||||
op_info_cursor = 113,
|
||||
|
||||
op_max
|
||||
};
|
||||
|
@ -4594,7 +4594,7 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL)
|
||||
|
||||
case op_info_sql:
|
||||
getHandle(statement, stuff->p_info_object);
|
||||
statement->checkIface(isc_info_unprepared_stmt);
|
||||
statement->checkIface();
|
||||
|
||||
statement->rsr_iface->getInfo(&status_vector, info_len, info_buffer,
|
||||
buffer_length, buffer);
|
||||
@ -4608,6 +4608,18 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL)
|
||||
statement->rsr_batch->getInfo(&status_vector, info_len, info_buffer,
|
||||
buffer_length, buffer);
|
||||
break;
|
||||
|
||||
case op_info_cursor:
|
||||
getHandle(statement, stuff->p_info_object);
|
||||
statement->checkIface();
|
||||
statement->checkCursor();
|
||||
|
||||
statement->rsr_cursor->getInfo(&status_vector, info_len, info_buffer,
|
||||
buffer_length, buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
}
|
||||
|
||||
// Send a response that includes the segment.
|
||||
@ -5089,6 +5101,7 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p
|
||||
case op_service_info:
|
||||
case op_info_sql:
|
||||
case op_info_batch:
|
||||
case op_info_cursor:
|
||||
port->info(op, &receive->p_info, sendL);
|
||||
break;
|
||||
|
||||
|
@ -366,6 +366,9 @@ public:
|
||||
void close(Firebird::CheckStatusWrapper* status);
|
||||
void deprecatedClose(Firebird::CheckStatusWrapper* status);
|
||||
void setDelayedOutputFormat(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* format);
|
||||
void getInfo(Firebird::CheckStatusWrapper* status,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer);
|
||||
|
||||
public:
|
||||
AtomicAttPtr attachment;
|
||||
|
@ -4884,6 +4884,21 @@ IMessageMetadata* YResultSet::getMetadata(CheckStatusWrapper* status)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void YResultSet::getInfo(CheckStatusWrapper* status,
|
||||
unsigned int itemsLength, const unsigned char* items,
|
||||
unsigned int bufferLength, unsigned char* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
YEntry<YResultSet> entry(status, this);
|
||||
|
||||
entry.next()->getInfo(status, itemsLength, items, bufferLength, buffer);
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
e.stuffException(status);
|
||||
}
|
||||
}
|
||||
|
||||
void YResultSet::close(CheckStatusWrapper* status)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user