mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 21:23:04 +01:00
Core (engine-level) support for scrollable DSQL cursors. Fixed the IResultSet API to match the JDBC spec. Renamed FB_EOF to FB_NO_DATA. Refactored some DSQL internals.
This commit is contained in:
parent
dcc5dfbba9
commit
cc8cc680a3
@ -161,7 +161,7 @@ private:
|
||||
Message out;
|
||||
Field<Varying> grantor(out, MAX_SQL_IDENTIFIER_SIZE);
|
||||
Firebird::IResultSet* curs = att->openCursor(&statusWrapper, tra, selGrantor.length(),
|
||||
selGrantor.c_str(), SQL_DIALECT_V6, NULL, NULL, out.getMetadata(), NULL);
|
||||
selGrantor.c_str(), SQL_DIALECT_V6, NULL, NULL, out.getMetadata(), NULL, 0);
|
||||
check(&statusWrapper);
|
||||
|
||||
bool hasGrant = curs->fetchNext(&statusWrapper, out.getBuffer()) == Firebird::IStatus::FB_OK;
|
||||
@ -563,7 +563,7 @@ public:
|
||||
}
|
||||
|
||||
rs = stmt->openCursor(status, tra, (par ? par->getMetadata() : NULL),
|
||||
(par ? par->getBuffer() : NULL), om);
|
||||
(par ? par->getBuffer() : NULL), om, 0);
|
||||
check(status);
|
||||
|
||||
while (rs->fetchNext(status, di.getBuffer()) == Firebird::IStatus::FB_OK)
|
||||
@ -853,7 +853,7 @@ private:
|
||||
{
|
||||
int cc = blob->getSegment(&statusWrapper, sizeof(segbuf), segbuf, &len);
|
||||
check(&statusWrapper);
|
||||
if (cc == Firebird::IStatus::FB_EOF)
|
||||
if (cc == Firebird::IStatus::FB_NO_DATA)
|
||||
break;
|
||||
s.append(segbuf, len);
|
||||
}
|
||||
|
270
src/dsql/DsqlCursor.cpp
Normal file
270
src/dsql/DsqlCursor.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Dmitry Yemanov
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2015 Dmitry Yemanov <dimitrf@firebirdsql.org>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../jrd/tra_proto.h"
|
||||
#include "../jrd/trace/TraceManager.h"
|
||||
#include "../jrd/trace/TraceDSQLHelpers.h"
|
||||
|
||||
#include "../dsql/DsqlCursor.h"
|
||||
|
||||
using namespace Firebird;
|
||||
using namespace Jrd;
|
||||
|
||||
const char* const SCRATCH = "fb_cursor_";
|
||||
const ULONG PREFETCH_SIZE = 65536; // 64 KB
|
||||
|
||||
DsqlCursor::DsqlCursor(dsql_req* req, ULONG flags)
|
||||
: m_request(req), 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)
|
||||
{
|
||||
TRA_link_cursor(m_request->req_transaction, this);
|
||||
}
|
||||
|
||||
jrd_tra* DsqlCursor::getTransaction() const
|
||||
{
|
||||
return m_request->req_transaction;
|
||||
}
|
||||
|
||||
Attachment* DsqlCursor::getAttachment() const
|
||||
{
|
||||
return m_request->req_dbb->dbb_attachment;
|
||||
}
|
||||
|
||||
void DsqlCursor::close(thread_db* tdbb, DsqlCursor* cursor)
|
||||
{
|
||||
if (!cursor)
|
||||
return;
|
||||
|
||||
Jrd::Attachment* const attachment = cursor->getAttachment();
|
||||
dsql_req* const request = cursor->m_request;
|
||||
|
||||
if (request->req_request)
|
||||
{
|
||||
ThreadStatusGuard status_vector(tdbb);
|
||||
try
|
||||
{
|
||||
// Report some remaining fetches if any
|
||||
if (request->req_fetch_baseline)
|
||||
{
|
||||
TraceDSQLFetch trace(attachment, request);
|
||||
trace.fetch(true, ITracePlugin::TRACE_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
if (request->req_traced && TraceManager::need_dsql_free(attachment))
|
||||
{
|
||||
TraceSQLStatementImpl stmt(request, NULL);
|
||||
TraceManager::event_dsql_free(attachment, &stmt, DSQL_close);
|
||||
}
|
||||
|
||||
JRD_unwind_request(tdbb, request->req_request);
|
||||
}
|
||||
catch (Firebird::Exception&)
|
||||
{} // no-op
|
||||
}
|
||||
|
||||
request->req_cursor = NULL;
|
||||
TRA_unlink_cursor(request->req_transaction, cursor);
|
||||
delete cursor;
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchNext(thread_db* tdbb, UCHAR* buffer)
|
||||
{
|
||||
if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE))
|
||||
{
|
||||
m_eof = !m_request->fetch(tdbb, buffer);
|
||||
|
||||
if (m_eof)
|
||||
{
|
||||
m_state = EOS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
m_state = POSITIONED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_state == EOS)
|
||||
return 1;
|
||||
|
||||
const FB_UINT64 position = (m_state == BOS) ? 0 : m_position + 1;
|
||||
return fetchFromCache(tdbb, buffer, position);
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchPrior(thread_db* tdbb, UCHAR* buffer)
|
||||
{
|
||||
if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE))
|
||||
(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("PRIOR")).raise();
|
||||
|
||||
if (m_state == BOS)
|
||||
return -1;
|
||||
|
||||
if (!m_position)
|
||||
{
|
||||
m_state = BOS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const FB_UINT64 position = ((m_state == EOS) ? m_cachedCount : m_position) - 1;
|
||||
return fetchFromCache(tdbb, buffer, position);
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchFirst(thread_db* tdbb, UCHAR* buffer)
|
||||
{
|
||||
if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE))
|
||||
(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("FIRST")).raise();
|
||||
|
||||
return fetchAbsolute(tdbb, buffer, 1);
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchLast(thread_db* tdbb, UCHAR* buffer)
|
||||
{
|
||||
if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE))
|
||||
(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("LAST")).raise();
|
||||
|
||||
return fetchAbsolute(tdbb, buffer, -1);
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchAbsolute(thread_db* tdbb, UCHAR* buffer, SLONG position)
|
||||
{
|
||||
if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE))
|
||||
(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("ABSOLUTE")).raise();
|
||||
|
||||
if (!position)
|
||||
{
|
||||
m_state = BOS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SINT64 offset = -1;
|
||||
|
||||
if (position < 0)
|
||||
{
|
||||
if (!m_eof)
|
||||
{
|
||||
cacheInput(tdbb);
|
||||
fb_assert(m_eof);
|
||||
}
|
||||
|
||||
offset = m_cachedCount;
|
||||
}
|
||||
|
||||
return fetchFromCache(tdbb, buffer, position + offset);
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchRelative(thread_db* tdbb, UCHAR* buffer, SLONG offset)
|
||||
{
|
||||
if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE))
|
||||
(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("RELATIVE")).raise();
|
||||
|
||||
if (m_state == BOS)
|
||||
{
|
||||
if (offset <= 0)
|
||||
return -1;
|
||||
|
||||
return fetchFromCache(tdbb, buffer, offset - 1);
|
||||
}
|
||||
else if (m_state == EOS)
|
||||
{
|
||||
if (offset >= 0)
|
||||
return 1;
|
||||
|
||||
fb_assert(m_eof);
|
||||
|
||||
if ((SINT64) m_cachedCount + offset < 0)
|
||||
return -1;
|
||||
|
||||
return fetchFromCache(tdbb, buffer, m_cachedCount + offset);
|
||||
}
|
||||
|
||||
if ((SINT64) m_position + offset < 0)
|
||||
{
|
||||
m_state = BOS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fetchFromCache(tdbb, buffer, m_position + offset);
|
||||
}
|
||||
|
||||
int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position)
|
||||
{
|
||||
if (position >= m_cachedCount)
|
||||
{
|
||||
if (m_eof || !cacheInput(tdbb, position))
|
||||
{
|
||||
m_state = EOS;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
m_position = position;
|
||||
m_state = POSITIONED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
while (position >= m_cachedCount)
|
||||
{
|
||||
ULONG count = 0;
|
||||
|
||||
for (; count < prefetchCount; count++)
|
||||
{
|
||||
UCHAR* const ptr = buffer + count * m_messageSize;
|
||||
|
||||
if (!m_request->fetch(tdbb, ptr))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (m_eof)
|
||||
break;
|
||||
}
|
||||
|
||||
return (position < m_cachedCount);
|
||||
}
|
78
src/dsql/DsqlCursor.h
Normal file
78
src/dsql/DsqlCursor.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Dmitry Yemanov
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2015 Dmitry Yemanov <dimitrf@firebirdsql.org>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef DSQL_CURSOR_H
|
||||
#define DSQL_CURSOR_H
|
||||
|
||||
#include "../jrd/TempSpace.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class dsql_req;
|
||||
|
||||
class DsqlCursor
|
||||
{
|
||||
enum State { BOS, POSITIONED, EOS };
|
||||
|
||||
public:
|
||||
explicit DsqlCursor(dsql_req* req, ULONG flags);
|
||||
|
||||
jrd_tra* getTransaction() const;
|
||||
Attachment* getAttachment() const;
|
||||
|
||||
static void close(thread_db* tdbb, DsqlCursor* cursor);
|
||||
|
||||
int fetchNext(thread_db* tdbb, UCHAR* buffer);
|
||||
int fetchPrior(thread_db* tdbb, UCHAR* buffer);
|
||||
int fetchFirst(thread_db* tdbb, UCHAR* buffer);
|
||||
int fetchLast(thread_db* tdbb, UCHAR* buffer);
|
||||
int fetchAbsolute(thread_db* tdbb, UCHAR* buffer, SLONG position);
|
||||
int fetchRelative(thread_db* tdbb, UCHAR* buffer, SLONG offset);
|
||||
|
||||
bool isBof() const
|
||||
{
|
||||
return (m_state == BOS);
|
||||
}
|
||||
|
||||
bool isEof() const
|
||||
{
|
||||
return (m_state == EOS);
|
||||
}
|
||||
|
||||
private:
|
||||
int fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position);
|
||||
bool cacheInput(thread_db* tdbb, FB_UINT64 position = MAX_UINT64);
|
||||
|
||||
dsql_req* const m_request;
|
||||
const ULONG m_flags;
|
||||
TempSpace m_space;
|
||||
State m_state;
|
||||
bool m_eof;
|
||||
FB_UINT64 m_position;
|
||||
FB_UINT64 m_cachedCount;
|
||||
ULONG m_messageSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // DSQL_CURSOR_H
|
||||
|
@ -77,7 +77,6 @@ using namespace Jrd;
|
||||
using namespace Firebird;
|
||||
|
||||
|
||||
static void close_cursor(thread_db*, dsql_req*);
|
||||
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(dsql_req*, bool, const dsql_msg*, IMessageMetadata*, UCHAR*,
|
||||
@ -130,11 +129,10 @@ dsql_dbb::~dsql_dbb()
|
||||
}
|
||||
|
||||
|
||||
// Execute a non-SELECT dynamic SQL statement.
|
||||
// Execute a dynamic SQL statement.
|
||||
void DSQL_execute(thread_db* tdbb,
|
||||
jrd_tra** tra_handle,
|
||||
jrd_tra** tra_handle,
|
||||
dsql_req* request,
|
||||
bool flOpenCursor,
|
||||
IMessageMetadata* in_meta, const UCHAR* in_msg,
|
||||
IMessageMetadata* out_meta, UCHAR* out_msg)
|
||||
{
|
||||
@ -166,44 +164,66 @@ void DSQL_execute(thread_db* tdbb,
|
||||
|
||||
if (reqTypeWithCursor(statement->getType()))
|
||||
{
|
||||
if (request->req_flags & dsql_req::FLAG_OPENED_CURSOR)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
|
||||
Arg::Gds(isc_dsql_cursor_open_err));
|
||||
}
|
||||
if (!(flOpenCursor || singleton))
|
||||
{
|
||||
(Arg::Gds(isc_random) << "Can not execute select statement").raise();
|
||||
}
|
||||
}
|
||||
else if (flOpenCursor)
|
||||
{
|
||||
if (request->req_flags & dsql_req::FLAG_OPENED_CURSOR)
|
||||
if (request->req_cursor)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
|
||||
Arg::Gds(isc_dsql_cursor_open_err));
|
||||
}
|
||||
|
||||
if (!singleton)
|
||||
(Arg::Gds(isc_random) << "Cannot execute SELECT statement").raise();
|
||||
}
|
||||
|
||||
request->req_transaction = *tra_handle;
|
||||
request->execute(tdbb, tra_handle, in_meta, in_msg, out_meta, out_msg, singleton);
|
||||
}
|
||||
|
||||
// If the output message length is zero on a TYPE_SELECT then we must
|
||||
// be doing an OPEN cursor operation.
|
||||
// If we do have an output message length, then we're doing
|
||||
// a singleton SELECT. In that event, we don't add the cursor
|
||||
// to the list of open cursors (it's not really open).
|
||||
|
||||
if (reqTypeWithCursor(statement->getType()) && !singleton)
|
||||
// Open a dynamic SQL cursor.
|
||||
DsqlCursor* DSQL_open(thread_db* tdbb,
|
||||
jrd_tra** tra_handle,
|
||||
dsql_req* request,
|
||||
IMessageMetadata* in_meta, const UCHAR* in_msg,
|
||||
IMessageMetadata* out_meta, ULONG flags)
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Jrd::ContextPoolHolder context(tdbb, &request->getPool());
|
||||
|
||||
const DsqlCompiledStatement* statement = request->getStatement();
|
||||
|
||||
if (statement->getFlags() & DsqlCompiledStatement::FLAG_ORPHAN)
|
||||
{
|
||||
fb_assert(flOpenCursor);
|
||||
request->req_flags |= dsql_req::FLAG_OPENED_CURSOR;
|
||||
TRA_link_cursor(request->req_transaction, request);
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
|
||||
Arg::Gds(isc_bad_req_handle));
|
||||
}
|
||||
else
|
||||
|
||||
// Validate transaction handle
|
||||
|
||||
if (!*tra_handle)
|
||||
{
|
||||
///fb_assert(!flOpenCursor);
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
|
||||
Arg::Gds(isc_bad_trans_handle));
|
||||
}
|
||||
|
||||
// Validate statement type
|
||||
|
||||
if (!reqTypeWithCursor(statement->getType()))
|
||||
(Arg::Gds(isc_random) << "Cannot open non-SELECT statement").raise();
|
||||
|
||||
// Validate cursor being not already open
|
||||
|
||||
if (request->req_cursor)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
|
||||
Arg::Gds(isc_dsql_cursor_open_err));
|
||||
}
|
||||
|
||||
request->req_transaction = *tra_handle;
|
||||
request->execute(tdbb, tra_handle, in_meta, in_msg, out_meta, NULL, false);
|
||||
|
||||
request->req_cursor = FB_NEW(request->getPool()) DsqlCursor(request, flags);
|
||||
return request->req_cursor;
|
||||
}
|
||||
|
||||
|
||||
@ -235,7 +255,7 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer)
|
||||
// if the cursor isn't open, we've got a problem
|
||||
if (reqTypeWithCursor(statement->getType()))
|
||||
{
|
||||
if (!(req_flags & dsql_req::FLAG_OPENED_CURSOR))
|
||||
if (!req_cursor)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-504) <<
|
||||
Arg::Gds(isc_dsql_cursor_err) <<
|
||||
@ -307,13 +327,13 @@ void DSQL_free_statement(thread_db* tdbb, dsql_req* request, USHORT option)
|
||||
// Just close the cursor associated with the request
|
||||
if (reqTypeWithCursor(statement->getType()))
|
||||
{
|
||||
if (!(request->req_flags & dsql_req::FLAG_OPENED_CURSOR))
|
||||
if (!request->req_cursor)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-501) <<
|
||||
Arg::Gds(isc_dsql_cursor_close_err));
|
||||
}
|
||||
|
||||
close_cursor(tdbb, request);
|
||||
DsqlCursor::close(tdbb, request->req_cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -419,7 +439,7 @@ void DsqlDmlRequest::setCursor(thread_db* tdbb, const TEXT* name)
|
||||
|
||||
USHORT length = (USHORT) fb_utils::name_length(cursor.c_str());
|
||||
|
||||
if (length == 0)
|
||||
if (!length)
|
||||
{
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
|
||||
Arg::Gds(isc_dsql_decl_err) <<
|
||||
@ -447,20 +467,18 @@ void DsqlDmlRequest::setCursor(thread_db* tdbb, const TEXT* name)
|
||||
// If there already is a cursor and its name isn't the same, ditto.
|
||||
// We already know there is no cursor by this name in the hash table
|
||||
|
||||
if (req_cursor.isEmpty() || !(req_flags & dsql_req::FLAG_OPENED_CURSOR))
|
||||
{
|
||||
if (req_cursor.hasData())
|
||||
req_dbb->dbb_cursors.remove(req_cursor);
|
||||
req_cursor = cursor;
|
||||
req_dbb->dbb_cursors.put(cursor, this);
|
||||
}
|
||||
else
|
||||
if (req_cursor && req_cursor_name.hasData())
|
||||
{
|
||||
fb_assert(!symbol);
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
|
||||
Arg::Gds(isc_dsql_decl_err) <<
|
||||
Arg::Gds(isc_dsql_cursor_redefined) << req_cursor);
|
||||
Arg::Gds(isc_dsql_cursor_redefined) << req_cursor_name);
|
||||
}
|
||||
|
||||
if (req_cursor_name.hasData())
|
||||
req_dbb->dbb_cursors.remove(req_cursor_name);
|
||||
req_cursor_name = cursor;
|
||||
req_dbb->dbb_cursors.put(cursor, this);
|
||||
}
|
||||
|
||||
|
||||
@ -492,55 +510,6 @@ void DSQL_sql_info(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
close_cursor
|
||||
|
||||
@brief Close an open cursor.
|
||||
|
||||
|
||||
@param request
|
||||
@param tdbb
|
||||
|
||||
**/
|
||||
static void close_cursor(thread_db* tdbb, dsql_req* request)
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Jrd::Attachment* attachment = request->req_dbb->dbb_attachment;
|
||||
const DsqlCompiledStatement* statement = request->getStatement();
|
||||
|
||||
if (request->req_request)
|
||||
{
|
||||
ThreadStatusGuard status_vector(tdbb);
|
||||
try
|
||||
{
|
||||
// Report some remaining fetches if any
|
||||
if (request->req_fetch_baseline)
|
||||
{
|
||||
TraceDSQLFetch trace(attachment, request);
|
||||
trace.fetch(true, ITracePlugin::TRACE_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
if (request->req_traced && TraceManager::need_dsql_free(attachment))
|
||||
{
|
||||
TraceSQLStatementImpl stmt(request, NULL);
|
||||
|
||||
TraceManager::event_dsql_free(attachment, &stmt, DSQL_close);
|
||||
}
|
||||
|
||||
JRD_unwind_request(tdbb, request->req_request);
|
||||
}
|
||||
catch (Firebird::Exception&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
request->req_flags &= ~dsql_req::FLAG_OPENED_CURSOR;
|
||||
TRA_unlink_cursor(request->req_transaction, request);
|
||||
}
|
||||
|
||||
|
||||
// Common part of prepare and execute a statement.
|
||||
void DSQL_execute_immediate(thread_db* tdbb, Jrd::Attachment* attachment, jrd_tra** tra_handle,
|
||||
ULONG length, const TEXT* string, USHORT dialect,
|
||||
@ -1530,7 +1499,8 @@ dsql_req::dsql_req(MemoryPool& pool)
|
||||
req_dbb(NULL),
|
||||
req_transaction(NULL),
|
||||
req_msg_buffers(req_pool),
|
||||
req_cursor(req_pool),
|
||||
req_cursor_name(req_pool),
|
||||
req_cursor(NULL),
|
||||
req_user_descs(req_pool),
|
||||
req_traced(false),
|
||||
req_interface(NULL)
|
||||
@ -1588,8 +1558,8 @@ void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop)
|
||||
|
||||
// If the request had an open cursor, close it
|
||||
|
||||
if (request->req_flags & dsql_req::FLAG_OPENED_CURSOR)
|
||||
close_cursor(tdbb, request);
|
||||
if (request->req_cursor)
|
||||
DsqlCursor::close(tdbb, request->req_cursor);
|
||||
|
||||
Jrd::Attachment* att = request->req_dbb->dbb_attachment;
|
||||
const bool need_trace_free = request->req_traced && TraceManager::need_dsql_free(att);
|
||||
@ -1600,10 +1570,10 @@ void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop)
|
||||
}
|
||||
request->req_traced = false;
|
||||
|
||||
if (request->req_cursor.hasData())
|
||||
if (request->req_cursor_name.hasData())
|
||||
{
|
||||
request->req_dbb->dbb_cursors.remove(request->req_cursor);
|
||||
request->req_cursor = "";
|
||||
request->req_dbb->dbb_cursors.remove(request->req_cursor_name);
|
||||
request->req_cursor_name = "";
|
||||
}
|
||||
|
||||
// If a request has been compiled, release it now
|
||||
@ -1618,8 +1588,7 @@ void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop)
|
||||
request->req_request = NULL;
|
||||
}
|
||||
catch (Firebird::Exception&)
|
||||
{
|
||||
}
|
||||
{} // no-op
|
||||
}
|
||||
|
||||
const DsqlCompiledStatement* statement = request->getStatement();
|
||||
@ -1628,9 +1597,7 @@ void dsql_req::destroy(thread_db* tdbb, dsql_req* request, bool drop)
|
||||
// Release the entire request if explicitly asked for
|
||||
|
||||
if (drop)
|
||||
{
|
||||
request->req_dbb->deletePool(&request->getPool());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,18 +34,21 @@
|
||||
#ifndef DSQL_DSQL_H
|
||||
#define DSQL_DSQL_H
|
||||
|
||||
#include "../jrd/RuntimeStatistics.h"
|
||||
#include "../jrd/ntrace.h"
|
||||
#include "../jrd/val.h" // Get rid of duplicated FUN_T enum.
|
||||
#include "../jrd/Attachment.h"
|
||||
#include "../dsql/BlrDebugWriter.h"
|
||||
#include "../dsql/ddl_proto.h"
|
||||
#include "../common/classes/array.h"
|
||||
#include "../common/classes/GenericMap.h"
|
||||
#include "../common/classes/MetaName.h"
|
||||
#include "../common/classes/stack.h"
|
||||
#include "../common/classes/auto.h"
|
||||
#include "../common/classes/NestConst.h"
|
||||
#include "../jrd/EngineInterface.h"
|
||||
#include "../jrd/RuntimeStatistics.h"
|
||||
#include "../jrd/ntrace.h"
|
||||
#include "../jrd/val.h" // Get rid of duplicated FUN_T enum.
|
||||
#include "../jrd/Attachment.h"
|
||||
#include "../dsql/BlrDebugWriter.h"
|
||||
#include "../dsql/ddl_proto.h"
|
||||
#include "../dsql/DsqlCursor.h"
|
||||
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
// This macro enables DSQL tracing code
|
||||
@ -61,8 +64,6 @@ DEFINE_TRACE_ROUTINE(dsql_trace);
|
||||
|
||||
#include "../dsql/sym.h"
|
||||
|
||||
#include "../jrd/EngineInterface.h"
|
||||
|
||||
// Context aliases used in triggers
|
||||
const char* const OLD_CONTEXT_NAME = "OLD";
|
||||
const char* const NEW_CONTEXT_NAME = "NEW";
|
||||
@ -523,9 +524,6 @@ private:
|
||||
|
||||
class dsql_req : public pool_alloc<dsql_type_req>
|
||||
{
|
||||
public:
|
||||
static const unsigned FLAG_OPENED_CURSOR = 0x01;
|
||||
|
||||
public:
|
||||
explicit dsql_req(MemoryPool& pool);
|
||||
|
||||
@ -572,10 +570,9 @@ public:
|
||||
jrd_tra* req_transaction; // JRD transaction
|
||||
jrd_req* req_request; // JRD request
|
||||
|
||||
unsigned req_flags; // flags
|
||||
|
||||
Firebird::Array<UCHAR*> req_msg_buffers;
|
||||
Firebird::string req_cursor; // Cursor name, if any
|
||||
Firebird::string req_cursor_name; // Cursor name, if any
|
||||
DsqlCursor* req_cursor; // Open cursor, if any
|
||||
Firebird::GenericMap<Firebird::NonPooled<const dsql_par*, dsc> > req_user_descs; // SQLDA data type
|
||||
|
||||
Firebird::AutoPtr<Jrd::RuntimeStatistics> req_fetch_baseline; // State of request performance counters when we reported it last time
|
||||
|
@ -34,12 +34,15 @@ namespace Jrd {
|
||||
class dsql_req;
|
||||
}
|
||||
|
||||
void DSQL_execute(Jrd::thread_db*, Jrd::jrd_tra**, Jrd::dsql_req*, bool,
|
||||
Firebird::IMessageMetadata*, const UCHAR*, Firebird::IMessageMetadata*, UCHAR*);
|
||||
void DSQL_execute(Jrd::thread_db*, Jrd::jrd_tra**, Jrd::dsql_req*,
|
||||
Firebird::IMessageMetadata*, const UCHAR*, Firebird::IMessageMetadata*, UCHAR*);
|
||||
void DSQL_execute_immediate(Jrd::thread_db*, Jrd::Attachment*, Jrd::jrd_tra**,
|
||||
ULONG, const TEXT*, USHORT, Firebird::IMessageMetadata*, const UCHAR*,
|
||||
Firebird::IMessageMetadata*, UCHAR*, bool);
|
||||
void DSQL_free_statement(Jrd::thread_db*, Jrd::dsql_req*, USHORT);
|
||||
Jrd::DsqlCursor* DSQL_open(Jrd::thread_db*, Jrd::jrd_tra**, Jrd::dsql_req*,
|
||||
Firebird::IMessageMetadata*, const UCHAR*,
|
||||
Firebird::IMessageMetadata*, ULONG);
|
||||
Jrd::dsql_req* DSQL_prepare(Jrd::thread_db*, Jrd::Attachment*, Jrd::jrd_tra*, ULONG, const TEXT*,
|
||||
USHORT, Firebird::Array<UCHAR>*, Firebird::Array<UCHAR>*, bool);
|
||||
void DSQL_sql_info(Jrd::thread_db*, Jrd::dsql_req*,
|
||||
|
@ -1002,7 +1002,7 @@ static void gen_blob_for( const act* action, USHORT column)
|
||||
column += INDENT;
|
||||
gen_get_segment(action, column);
|
||||
printa(column, "if (fbIStatus == Firebird::IStatus::FB_ERROR || "
|
||||
"fbIStatus == Firebird::IStatus::FB_EOF) break;");
|
||||
"fbIStatus == Firebird::IStatus::FB_NO_DATA) break;");
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,7 +59,7 @@ interface Status : Disposable
|
||||
// completion codes - not used in Status, but I must have them somewhere
|
||||
const int FB_ERROR = -1;
|
||||
const int FB_OK = 0;
|
||||
const int FB_EOF = 1;
|
||||
const int FB_NO_DATA = 1;
|
||||
const int FB_SEGMENT = 2;
|
||||
|
||||
void init();
|
||||
@ -385,7 +385,7 @@ interface ResultSet : ReferenceCounted
|
||||
[notImplemented(Status::FB_ERROR)] int fetchPrior(Status status, void* message);
|
||||
[notImplemented(Status::FB_ERROR)] int fetchFirst(Status status, void* message);
|
||||
[notImplemented(Status::FB_ERROR)] int fetchLast(Status status, void* message);
|
||||
[notImplemented(Status::FB_ERROR)] int fetchAbsolute(Status status, uint position, void* message);
|
||||
[notImplemented(Status::FB_ERROR)] int fetchAbsolute(Status status, int position, void* message);
|
||||
[notImplemented(Status::FB_ERROR)] int fetchRelative(Status status, int offset, void* message);
|
||||
boolean isEof(Status status);
|
||||
boolean isBof(Status status);
|
||||
@ -420,6 +420,9 @@ interface Statement : ReferenceCounted
|
||||
const uint FLAG_HAS_CURSOR = 0x01;
|
||||
const uint FLAG_REPEAT_EXECUTE = 0x02;
|
||||
|
||||
// Cursor flags.
|
||||
const uint CURSOR_TYPE_SCROLLABLE = 0x01;
|
||||
|
||||
void getInfo(Status status,
|
||||
uint itemsLength, const uchar* items,
|
||||
uint bufferLength, uchar* buffer);
|
||||
@ -431,7 +434,7 @@ interface Statement : ReferenceCounted
|
||||
Transaction execute(Status status, Transaction transaction,
|
||||
MessageMetadata inMetadata, void* inBuffer, MessageMetadata outMetadata, void* outBuffer);
|
||||
ResultSet openCursor(Status status, Transaction transaction,
|
||||
MessageMetadata inMetadata, void* inBuffer, MessageMetadata outMetadata);
|
||||
MessageMetadata inMetadata, void* inBuffer, MessageMetadata outMetadata, uint flags);
|
||||
void setCursorName(Status status, const string name);
|
||||
void free(Status status);
|
||||
uint getFlags(Status status);
|
||||
@ -495,7 +498,7 @@ interface Attachment : ReferenceCounted
|
||||
ResultSet openCursor(Status status, Transaction transaction,
|
||||
uint stmtLength, const string sqlStmt, uint dialect,
|
||||
MessageMetadata inMetadata, void* inBuffer, MessageMetadata outMetadata,
|
||||
const string cursorName);
|
||||
const string cursorName, uint cursorFlags);
|
||||
Events queEvents(Status status, EventCallback callback,
|
||||
uint length, const uchar* events);
|
||||
void cancelOperation(Status status, int option);
|
||||
|
@ -229,7 +229,7 @@ namespace Firebird
|
||||
static const unsigned FB_HAS_ERRORS = 2;
|
||||
static const int FB_ERROR = -1;
|
||||
static const int FB_OK = 0;
|
||||
static const int FB_EOF = 1;
|
||||
static const int FB_NO_DATA = 1;
|
||||
static const int FB_SEGMENT = 2;
|
||||
|
||||
void init()
|
||||
@ -1370,7 +1370,7 @@ namespace Firebird
|
||||
int (CLOOP_CARG *fetchPrior)(IResultSet* self, IStatus* status, void* message) throw();
|
||||
int (CLOOP_CARG *fetchFirst)(IResultSet* self, IStatus* status, void* message) throw();
|
||||
int (CLOOP_CARG *fetchLast)(IResultSet* self, IStatus* status, void* message) throw();
|
||||
int (CLOOP_CARG *fetchAbsolute)(IResultSet* self, IStatus* status, unsigned position, void* message) throw();
|
||||
int (CLOOP_CARG *fetchAbsolute)(IResultSet* self, IStatus* status, int position, void* message) throw();
|
||||
int (CLOOP_CARG *fetchRelative)(IResultSet* self, IStatus* status, int offset, void* message) throw();
|
||||
FB_BOOLEAN (CLOOP_CARG *isEof)(IResultSet* self, IStatus* status) throw();
|
||||
FB_BOOLEAN (CLOOP_CARG *isBof)(IResultSet* self, IStatus* status) throw();
|
||||
@ -1420,7 +1420,7 @@ namespace Firebird
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> int fetchAbsolute(StatusType* status, unsigned position, void* message)
|
||||
template <typename StatusType> int fetchAbsolute(StatusType* status, int position, void* message)
|
||||
{
|
||||
int ret = static_cast<VTable*>(this->cloopVTable)->fetchAbsolute(this, status, position, message);
|
||||
StatusType::checkException(status);
|
||||
@ -1480,7 +1480,7 @@ namespace Firebird
|
||||
IMessageMetadata* (CLOOP_CARG *getInputMetadata)(IStatement* self, IStatus* status) throw();
|
||||
IMessageMetadata* (CLOOP_CARG *getOutputMetadata)(IStatement* self, IStatus* status) throw();
|
||||
ITransaction* (CLOOP_CARG *execute)(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) throw();
|
||||
IResultSet* (CLOOP_CARG *openCursor)(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata) throw();
|
||||
IResultSet* (CLOOP_CARG *openCursor)(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags) throw();
|
||||
void (CLOOP_CARG *setCursorName)(IStatement* self, IStatus* status, const char* name) throw();
|
||||
void (CLOOP_CARG *free)(IStatement* self, IStatus* status) throw();
|
||||
unsigned (CLOOP_CARG *getFlags)(IStatement* self, IStatus* status) throw();
|
||||
@ -1511,6 +1511,8 @@ namespace Firebird
|
||||
static const unsigned PREPARE_PREFETCH_ALL = IStatement::PREPARE_PREFETCH_METADATA | IStatement::PREPARE_PREFETCH_LEGACY_PLAN | IStatement::PREPARE_PREFETCH_DETAILED_PLAN | IStatement::PREPARE_PREFETCH_AFFECTED_RECORDS;
|
||||
static const unsigned FLAG_HAS_CURSOR = 1;
|
||||
static const unsigned FLAG_REPEAT_EXECUTE = 2;
|
||||
static const unsigned CURSOR_TYPE_SCROLLABLE = 1;
|
||||
|
||||
|
||||
template <typename StatusType> void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer)
|
||||
{
|
||||
@ -1560,9 +1562,9 @@ namespace Firebird
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> IResultSet* openCursor(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata)
|
||||
template <typename StatusType> IResultSet* openCursor(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags)
|
||||
{
|
||||
IResultSet* ret = static_cast<VTable*>(this->cloopVTable)->openCursor(this, status, transaction, inMetadata, inBuffer, outMetadata);
|
||||
IResultSet* ret = static_cast<VTable*>(this->cloopVTable)->openCursor(this, status, transaction, inMetadata, inBuffer, outMetadata, flags);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
@ -1702,7 +1704,7 @@ namespace Firebird
|
||||
void (CLOOP_CARG *executeDyn)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned length, const unsigned char* dyn) throw();
|
||||
IStatement* (CLOOP_CARG *prepare)(IAttachment* self, IStatus* status, ITransaction* tra, unsigned stmtLength, const char* sqlStmt, unsigned dialect, unsigned flags) throw();
|
||||
ITransaction* (CLOOP_CARG *execute)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) throw();
|
||||
IResultSet* (CLOOP_CARG *openCursor)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName) throw();
|
||||
IResultSet* (CLOOP_CARG *openCursor)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName, unsigned cursorFlags) throw();
|
||||
IEvents* (CLOOP_CARG *queEvents)(IAttachment* self, IStatus* status, IEventCallback* callback, unsigned length, const unsigned char* events) throw();
|
||||
void (CLOOP_CARG *cancelOperation)(IAttachment* self, IStatus* status, int option) throw();
|
||||
void (CLOOP_CARG *ping)(IAttachment* self, IStatus* status) throw();
|
||||
@ -1803,9 +1805,9 @@ namespace Firebird
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> IResultSet* openCursor(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName)
|
||||
template <typename StatusType> IResultSet* openCursor(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName, unsigned cursorFlags)
|
||||
{
|
||||
IResultSet* ret = static_cast<VTable*>(this->cloopVTable)->openCursor(this, status, transaction, stmtLength, sqlStmt, dialect, inMetadata, inBuffer, outMetadata, cursorName);
|
||||
IResultSet* ret = static_cast<VTable*>(this->cloopVTable)->openCursor(this, status, transaction, stmtLength, sqlStmt, dialect, inMetadata, inBuffer, outMetadata, cursorName, cursorFlags);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
@ -7379,7 +7381,7 @@ namespace Firebird
|
||||
}
|
||||
}
|
||||
|
||||
static int CLOOP_CARG cloopfetchAbsoluteDispatcher(IResultSet* self, IStatus* status, unsigned position, void* message) throw()
|
||||
static int CLOOP_CARG cloopfetchAbsoluteDispatcher(IResultSet* self, IStatus* status, int position, void* message) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
@ -7525,7 +7527,7 @@ namespace Firebird
|
||||
virtual int fetchPrior(StatusType* status, void* message) = 0;
|
||||
virtual int fetchFirst(StatusType* status, void* message) = 0;
|
||||
virtual int fetchLast(StatusType* status, void* message) = 0;
|
||||
virtual int fetchAbsolute(StatusType* status, unsigned position, void* message) = 0;
|
||||
virtual int fetchAbsolute(StatusType* status, int position, void* message) = 0;
|
||||
virtual int fetchRelative(StatusType* status, int offset, void* message) = 0;
|
||||
virtual FB_BOOLEAN isEof(StatusType* status) = 0;
|
||||
virtual FB_BOOLEAN isBof(StatusType* status) = 0;
|
||||
@ -7670,13 +7672,13 @@ namespace Firebird
|
||||
}
|
||||
}
|
||||
|
||||
static IResultSet* CLOOP_CARG cloopopenCursorDispatcher(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata) throw()
|
||||
static IResultSet* CLOOP_CARG cloopopenCursorDispatcher(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::openCursor(&status2, transaction, inMetadata, inBuffer, outMetadata);
|
||||
return static_cast<Name*>(self)->Name::openCursor(&status2, transaction, inMetadata, inBuffer, outMetadata, flags);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -7774,7 +7776,7 @@ namespace Firebird
|
||||
virtual IMessageMetadata* getInputMetadata(StatusType* status) = 0;
|
||||
virtual IMessageMetadata* getOutputMetadata(StatusType* status) = 0;
|
||||
virtual ITransaction* execute(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) = 0;
|
||||
virtual IResultSet* openCursor(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata) = 0;
|
||||
virtual IResultSet* openCursor(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags) = 0;
|
||||
virtual void setCursorName(StatusType* status, const char* name) = 0;
|
||||
virtual void free(StatusType* status) = 0;
|
||||
virtual unsigned getFlags(StatusType* status) = 0;
|
||||
@ -8247,13 +8249,13 @@ namespace Firebird
|
||||
}
|
||||
}
|
||||
|
||||
static IResultSet* CLOOP_CARG cloopopenCursorDispatcher(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName) throw()
|
||||
static IResultSet* CLOOP_CARG cloopopenCursorDispatcher(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName, unsigned cursorFlags) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::openCursor(&status2, transaction, stmtLength, sqlStmt, dialect, inMetadata, inBuffer, outMetadata, cursorName);
|
||||
return static_cast<Name*>(self)->Name::openCursor(&status2, transaction, stmtLength, sqlStmt, dialect, inMetadata, inBuffer, outMetadata, cursorName, cursorFlags);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -8384,7 +8386,7 @@ namespace Firebird
|
||||
virtual void executeDyn(StatusType* status, ITransaction* transaction, unsigned length, const unsigned char* dyn) = 0;
|
||||
virtual IStatement* prepare(StatusType* status, ITransaction* tra, unsigned stmtLength, const char* sqlStmt, unsigned dialect, unsigned flags) = 0;
|
||||
virtual ITransaction* execute(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) = 0;
|
||||
virtual IResultSet* openCursor(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName) = 0;
|
||||
virtual IResultSet* openCursor(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, const char* cursorName, unsigned cursorFlags) = 0;
|
||||
virtual IEvents* queEvents(StatusType* status, IEventCallback* callback, unsigned length, const unsigned char* events) = 0;
|
||||
virtual void cancelOperation(StatusType* status, int option) = 0;
|
||||
virtual void ping(StatusType* status) = 0;
|
||||
|
@ -1880,7 +1880,7 @@ void ISQL_print_validation(FILE* fp,
|
||||
{
|
||||
unsigned int length;
|
||||
int cc = blob->getSegment(fbStatus, sizeof(buffer) - 1, buffer, &length);
|
||||
if (cc == Firebird::IStatus::FB_EOF || cc == Firebird::IStatus::FB_ERROR)
|
||||
if (cc == Firebird::IStatus::FB_NO_DATA || cc == Firebird::IStatus::FB_ERROR)
|
||||
break;
|
||||
|
||||
buffer[length] = 0;
|
||||
@ -7598,7 +7598,7 @@ processing_state ISQL_print_item_blob(FILE* fp, const IsqlVar* var, Firebird::IT
|
||||
{
|
||||
unsigned int length;
|
||||
int cc = blob->getSegment(fbStatus, sizeof(buffer) - 1, buffer, &length);
|
||||
if (cc == Firebird::IStatus::FB_EOF || cc == Firebird::IStatus::FB_ERROR)
|
||||
if (cc == Firebird::IStatus::FB_NO_DATA || cc == Firebird::IStatus::FB_ERROR)
|
||||
break;
|
||||
|
||||
// Special displays for blr or acl subtypes
|
||||
@ -8556,7 +8556,7 @@ static processing_state process_statement(const TEXT* str2)
|
||||
// Otherwise, open the cursor to start things up
|
||||
|
||||
Firebird::IResultSet* curs = global_Stmt->openCursor(fbStatus, M__trans,
|
||||
NULL, NULL, message);
|
||||
NULL, NULL, message, Firebird::IStatement::CURSOR_TYPE_SCROLLABLE);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
{
|
||||
return ps_ERR;
|
||||
@ -8591,10 +8591,8 @@ static processing_state process_statement(const TEXT* str2)
|
||||
|
||||
// Fetch the current cursor
|
||||
|
||||
if (curs->fetchNext(fbStatus, buffer) == Firebird::IStatus::FB_EOF)
|
||||
{
|
||||
if (curs->fetchNext(fbStatus, buffer) == Firebird::IStatus::FB_NO_DATA)
|
||||
break;
|
||||
}
|
||||
|
||||
// Print the header every Pagelength number of lines for
|
||||
// command-line ISQL only.
|
||||
|
@ -1611,7 +1611,7 @@ void SHOW_print_metadata_text_blob(FILE* fp, ISC_QUAD* blobid, bool escape_squot
|
||||
{
|
||||
unsigned int length;
|
||||
int cc = blob->getSegment(fbStatus, sizeof(buffer) - 1, buffer, &length);
|
||||
if (cc == Firebird::IStatus::FB_EOF || cc == Firebird::IStatus::FB_ERROR)
|
||||
if (cc == Firebird::IStatus::FB_NO_DATA || cc == Firebird::IStatus::FB_ERROR)
|
||||
break;
|
||||
|
||||
// ASF: In Windows, \n characters are printed as \r\n in text mode.
|
||||
@ -5810,7 +5810,7 @@ static processing_state show_users12()
|
||||
return ps_ERR;
|
||||
|
||||
Firebird::IResultSet* rs = DB->openCursor(fbStatus, fbTrans, 0, getusers, isqlGlob.SQL_dialect,
|
||||
NULL, NULL, outMetadata, NULL);
|
||||
NULL, NULL, outMetadata, NULL, 0);
|
||||
if (ISQL_errmsg (fbStatus))
|
||||
return ps_ERR;
|
||||
|
||||
|
@ -238,7 +238,7 @@ RecordBuffer* DbCreatorsList::getList(thread_db* tdbb, jrd_rel* relation)
|
||||
LocalStatus st;
|
||||
RefPtr<IResultSet> curs(att->openCursor(&st, tra, 0,
|
||||
"select RDB$USER_TYPE, RDB$USER from RDB$DB_CREATORS",
|
||||
SQL_DIALECT_V6, NULL, NULL, gr.getMetadata(), NULL));
|
||||
SQL_DIALECT_V6, NULL, NULL, gr.getMetadata(), NULL, 0));
|
||||
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
|
@ -33,6 +33,7 @@ namespace Jrd {
|
||||
// Engine objects used by interface objects
|
||||
class blb;
|
||||
class jrd_tra;
|
||||
class DsqlCursor;
|
||||
class dsql_req;
|
||||
class JrdStatement;
|
||||
class StableAttachmentPart;
|
||||
@ -148,7 +149,7 @@ public:
|
||||
int fetchPrior(Firebird::CheckStatusWrapper* status, void* message);
|
||||
int fetchFirst(Firebird::CheckStatusWrapper* status, void* message);
|
||||
int fetchLast(Firebird::CheckStatusWrapper* status, void* message);
|
||||
int fetchAbsolute(Firebird::CheckStatusWrapper* status, unsigned int position, void* message);
|
||||
int fetchAbsolute(Firebird::CheckStatusWrapper* status, int position, void* message);
|
||||
int fetchRelative(Firebird::CheckStatusWrapper* status, int offset, void* message);
|
||||
FB_BOOLEAN isEof(Firebird::CheckStatusWrapper* status);
|
||||
FB_BOOLEAN isBof(Firebird::CheckStatusWrapper* status);
|
||||
@ -157,21 +158,22 @@ public:
|
||||
void setDelayedOutputFormat(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* format);
|
||||
|
||||
public:
|
||||
JResultSet(JStatement* aStatement);
|
||||
JResultSet(DsqlCursor* handle, StableAttachmentPart* sa);
|
||||
|
||||
JStatement* getStatement()
|
||||
StableAttachmentPart* getAttachment()
|
||||
{
|
||||
return statement;
|
||||
return sAtt;
|
||||
}
|
||||
|
||||
StableAttachmentPart* getAttachment();
|
||||
|
||||
// Change after adding separate handle for cursor in dsql
|
||||
dsql_req* getHandle() throw();
|
||||
DsqlCursor* getHandle() throw()
|
||||
{
|
||||
return cursor;
|
||||
}
|
||||
|
||||
private:
|
||||
Firebird::RefPtr<JStatement> statement;
|
||||
bool eof;
|
||||
DsqlCursor* cursor;
|
||||
Firebird::RefPtr<StableAttachmentPart> sAtt;
|
||||
int state;
|
||||
|
||||
void freeEngineData(Firebird::CheckStatusWrapper* status);
|
||||
};
|
||||
@ -196,7 +198,7 @@ public:
|
||||
Firebird::IMessageMetadata* outMetadata, void* outBuffer);
|
||||
JResultSet* openCursor(Firebird::CheckStatusWrapper* status,
|
||||
Firebird::ITransaction* transaction, Firebird::IMessageMetadata* inMetadata, void* inBuffer,
|
||||
Firebird::IMessageMetadata* outMetadata);
|
||||
Firebird::IMessageMetadata* outMetadata, unsigned int flags);
|
||||
void setCursorName(Firebird::CheckStatusWrapper* status, const char* name);
|
||||
unsigned getFlags(Firebird::CheckStatusWrapper* status);
|
||||
|
||||
@ -221,17 +223,6 @@ private:
|
||||
void freeEngineData(Firebird::CheckStatusWrapper* status);
|
||||
};
|
||||
|
||||
inline StableAttachmentPart* JResultSet::getAttachment()
|
||||
{
|
||||
return statement->getAttachment();
|
||||
}
|
||||
|
||||
// Change after adding separate handle for cursor in dsql
|
||||
inline dsql_req* JResultSet::getHandle() throw()
|
||||
{
|
||||
return statement->getHandle();
|
||||
}
|
||||
|
||||
class JRequest FB_FINAL :
|
||||
public Firebird::RefCntIface<Firebird::IRequestImpl<JRequest, Firebird::CheckStatusWrapper> >
|
||||
{
|
||||
@ -343,7 +334,7 @@ public:
|
||||
Firebird::IResultSet* openCursor(Firebird::CheckStatusWrapper* status,
|
||||
Firebird::ITransaction* transaction, unsigned int stmtLength, const char* sqlStmt,
|
||||
unsigned int dialect, Firebird::IMessageMetadata* inMetadata, void* inBuffer,
|
||||
Firebird::IMessageMetadata* outMetadata, const char* cursorName);
|
||||
Firebird::IMessageMetadata* outMetadata, const char* cursorName, unsigned int cursorFlags);
|
||||
JEvents* queEvents(Firebird::CheckStatusWrapper* status, Firebird::IEventCallback* callback,
|
||||
unsigned int length, const unsigned char* events);
|
||||
void cancelOperation(Firebird::CheckStatusWrapper* status, int option);
|
||||
|
@ -279,7 +279,7 @@ public:
|
||||
"SELECT RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, "
|
||||
" RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO "
|
||||
"FROM RDB$AUTH_MAPPING",
|
||||
3, NULL, NULL, mMap.getMetadata(), NULL);
|
||||
3, NULL, NULL, mMap.getMetadata(), NULL, 0);
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
if (fb_utils::containsErrorCode(st.getErrors(), isc_dsql_relation_err))
|
||||
@ -1199,7 +1199,7 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation)
|
||||
"SELECT RDB$MAP_NAME, RDB$MAP_USING, RDB$MAP_PLUGIN, RDB$MAP_DB, "
|
||||
" RDB$MAP_FROM_TYPE, RDB$MAP_FROM, RDB$MAP_TO_TYPE, RDB$MAP_TO "
|
||||
"FROM RDB$AUTH_MAPPING",
|
||||
3, NULL, NULL, mMap.getMetadata(), NULL);
|
||||
3, NULL, NULL, mMap.getMetadata(), NULL, 0);
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
if (!fb_utils::containsErrorCode(st.getErrors(), isc_dsql_relation_err))
|
||||
|
@ -337,7 +337,7 @@ void PreparedStatement::execute(thread_db* tdbb, jrd_tra* transaction)
|
||||
if (builder)
|
||||
builder->moveToStatement(tdbb, this);
|
||||
|
||||
DSQL_execute(tdbb, &transaction, request, false, inMetadata, inMessage.begin(), NULL, NULL);
|
||||
DSQL_execute(tdbb, &transaction, request, inMetadata, inMessage.begin(), NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -348,7 +348,7 @@ void PreparedStatement::open(thread_db* tdbb, jrd_tra* transaction)
|
||||
if (builder)
|
||||
builder->moveToStatement(tdbb, this);
|
||||
|
||||
DSQL_execute(tdbb, &transaction, request, true, inMetadata, inMessage.begin(), outMetadata, NULL);
|
||||
DSQL_open(tdbb, &transaction, request, inMetadata, inMessage.begin(), outMetadata, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -536,7 +536,7 @@ void InternalStatement::doOpen(thread_db* tdbb)
|
||||
fb_assert(m_inMetadata->getMessageLength() == m_in_buffer.getCount());
|
||||
|
||||
m_cursor = m_request->openCursor(&statusWrapper, transaction,
|
||||
m_inMetadata, m_in_buffer.begin(), m_outMetadata);
|
||||
m_inMetadata, m_in_buffer.begin(), m_outMetadata, 0);
|
||||
}
|
||||
|
||||
if (status.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
@ -560,7 +560,7 @@ bool InternalStatement::doFetch(thread_db* tdbb)
|
||||
}
|
||||
|
||||
if (status.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
raise(status, tdbb, "JResultSet::fetch");
|
||||
raise(status, tdbb, "JResultSet::fetchNext");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
204
src/jrd/jrd.cpp
204
src/jrd/jrd.cpp
@ -49,6 +49,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "../jrd/ibase.h"
|
||||
#include "../jrd/EngineInterface.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/irq.h"
|
||||
#include "../jrd/drq.h"
|
||||
@ -126,7 +127,6 @@
|
||||
#include "../common/classes/RefMutex.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../jrd/DebugInterface.h"
|
||||
#include "../jrd/EngineInterface.h"
|
||||
#include "../jrd/CryptoManager.h"
|
||||
#include "../jrd/DbCreators.h"
|
||||
|
||||
@ -318,8 +318,8 @@ JTransaction::JTransaction(JTransaction* from)
|
||||
}
|
||||
|
||||
|
||||
JResultSet::JResultSet(JStatement* aStatement)
|
||||
: statement(aStatement), eof(false)
|
||||
JResultSet::JResultSet(DsqlCursor* handle, StableAttachmentPart* sa)
|
||||
: cursor(handle), sAtt(sa), state(-1)
|
||||
{
|
||||
}
|
||||
|
||||
@ -635,6 +635,15 @@ namespace
|
||||
validateHandle(tdbb, events->getAttachment()->getHandle());
|
||||
}
|
||||
|
||||
inline void validateHandle(thread_db* tdbb, DsqlCursor* const cursor)
|
||||
{
|
||||
if (!cursor)
|
||||
status_exception::raise(Arg::Gds(isc_bad_req_handle));
|
||||
|
||||
validateHandle(tdbb, cursor->getTransaction());
|
||||
validateHandle(tdbb, cursor->getAttachment());
|
||||
}
|
||||
|
||||
class AttachmentHolder
|
||||
{
|
||||
public:
|
||||
@ -3080,7 +3089,7 @@ int JBlob::getSegment(CheckStatusWrapper* user_status, unsigned int buffer_lengt
|
||||
}
|
||||
|
||||
if (getHandle()->blb_flags & BLB_eof)
|
||||
cc = IStatus::FB_EOF;
|
||||
cc = IStatus::FB_NO_DATA;
|
||||
else if (getHandle()->getFragmentSize())
|
||||
cc = IStatus::FB_SEGMENT;
|
||||
else
|
||||
@ -4413,7 +4422,7 @@ ITransaction* JStatement::execute(CheckStatusWrapper* user_status, ITransaction*
|
||||
|
||||
try
|
||||
{
|
||||
DSQL_execute(tdbb, &tra, getHandle(), false,
|
||||
DSQL_execute(tdbb, &tra, getHandle(),
|
||||
inMetadata, static_cast<UCHAR*>(inBuffer),
|
||||
outMetadata, static_cast<UCHAR*>(outBuffer));
|
||||
|
||||
@ -4456,7 +4465,7 @@ ITransaction* JStatement::execute(CheckStatusWrapper* user_status, ITransaction*
|
||||
|
||||
|
||||
JResultSet* JStatement::openCursor(CheckStatusWrapper* user_status, ITransaction* transaction,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata)
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned int flags)
|
||||
{
|
||||
JTransaction* jt = transaction ? getAttachment()->getTransactionInterface(user_status, transaction) : NULL;
|
||||
jrd_tra* tra = jt ? jt->getHandle() : NULL;
|
||||
@ -4483,10 +4492,12 @@ JResultSet* JStatement::openCursor(CheckStatusWrapper* user_status, ITransaction
|
||||
}
|
||||
}
|
||||
|
||||
DSQL_execute(tdbb, &tra, getHandle(), true,
|
||||
inMetadata, static_cast<UCHAR*>(inBuffer), outMetadata, NULL);
|
||||
DsqlCursor* const cursor =
|
||||
DSQL_open(tdbb, &tra, getHandle(),
|
||||
inMetadata, static_cast<UCHAR*>(inBuffer),
|
||||
outMetadata, flags);
|
||||
|
||||
rs = new JResultSet(this);
|
||||
rs = new JResultSet(cursor, getAttachment());
|
||||
rs->addRef();
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
@ -4510,7 +4521,7 @@ JResultSet* JStatement::openCursor(CheckStatusWrapper* user_status, ITransaction
|
||||
IResultSet* JAttachment::openCursor(CheckStatusWrapper* user_status, ITransaction* apiTra,
|
||||
unsigned int length, const char* string, unsigned int dialect,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata,
|
||||
const char* cursorName)
|
||||
const char* cursorName, unsigned int cursorFlags)
|
||||
{
|
||||
IStatement* tmpStatement = prepare(user_status, apiTra, length, string, dialect,
|
||||
(outMetadata ? 0 : IStatement::PREPARE_PREFETCH_OUTPUT_PARAMETERS));
|
||||
@ -4530,7 +4541,7 @@ IResultSet* JAttachment::openCursor(CheckStatusWrapper* user_status, ITransactio
|
||||
}
|
||||
|
||||
IResultSet* rs = tmpStatement->openCursor(user_status, apiTra,
|
||||
inMetadata, inBuffer, outMetadata);
|
||||
inMetadata, inBuffer, outMetadata, cursorFlags);
|
||||
|
||||
tmpStatement->release();
|
||||
return rs;
|
||||
@ -4593,36 +4604,28 @@ ITransaction* JAttachment::execute(CheckStatusWrapper* user_status, ITransaction
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return jt;
|
||||
}
|
||||
|
||||
|
||||
int JResultSet::fetchNext(CheckStatusWrapper* user_status, void* buffer)
|
||||
{
|
||||
bool hasMessage = false;
|
||||
|
||||
try
|
||||
{
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
dsql_req* req = getStatement()->getHandle();
|
||||
validateHandle(tdbb, req->req_transaction);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
hasMessage = req->fetch(tdbb, static_cast<UCHAR*>(buffer));
|
||||
if (!hasMessage)
|
||||
{
|
||||
eof = true;
|
||||
}
|
||||
state = cursor->fetchNext(tdbb, static_cast<UCHAR*>(buffer));
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JStatement::fetch");
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::fetchNext");
|
||||
return IStatus::FB_ERROR;
|
||||
}
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetch");
|
||||
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetchNext");
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4631,17 +4634,27 @@ int JResultSet::fetchNext(CheckStatusWrapper* user_status, void* buffer)
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
if (hasMessage)
|
||||
return IStatus::FB_OK;
|
||||
return IStatus::FB_EOF;
|
||||
return (state == 0) ? IStatus::FB_OK : IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
int JResultSet::fetchPrior(CheckStatusWrapper* user_status, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
state = cursor->fetchPrior(tdbb, static_cast<UCHAR*>(buffer));
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::fetchPrior");
|
||||
return IStatus::FB_ERROR;
|
||||
}
|
||||
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetchPrior");
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4650,15 +4663,28 @@ int JResultSet::fetchPrior(CheckStatusWrapper* user_status, void* buffer)
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return IStatus::FB_OK;
|
||||
return (state == 0) ? IStatus::FB_OK : IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
|
||||
int JResultSet::fetchFirst(CheckStatusWrapper* user_status, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
state = cursor->fetchFirst(tdbb, static_cast<UCHAR*>(buffer));
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::fetchFirst");
|
||||
return IStatus::FB_ERROR;
|
||||
}
|
||||
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetchFirst");
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4667,15 +4693,28 @@ int JResultSet::fetchFirst(CheckStatusWrapper* user_status, void* buffer)
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return IStatus::FB_OK;
|
||||
return (state == 0) ? IStatus::FB_OK : IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
|
||||
int JResultSet::fetchLast(CheckStatusWrapper* user_status, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
state = cursor->fetchLast(tdbb, static_cast<UCHAR*>(buffer));
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::fetchLast");
|
||||
return IStatus::FB_ERROR;
|
||||
}
|
||||
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetchLast");
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4684,15 +4723,28 @@ int JResultSet::fetchLast(CheckStatusWrapper* user_status, void* buffer)
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return IStatus::FB_OK;
|
||||
return (state == 0) ? IStatus::FB_OK : IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
int JResultSet::fetchAbsolute(CheckStatusWrapper* user_status, unsigned position, void* buffer)
|
||||
|
||||
int JResultSet::fetchAbsolute(CheckStatusWrapper* user_status, int position, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
state = cursor->fetchAbsolute(tdbb, static_cast<UCHAR*>(buffer), position);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::fetchAbsolute");
|
||||
return IStatus::FB_ERROR;
|
||||
}
|
||||
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetchAbsolute");
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4701,15 +4753,28 @@ int JResultSet::fetchAbsolute(CheckStatusWrapper* user_status, unsigned position
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return IStatus::FB_OK;
|
||||
return (state == 0) ? IStatus::FB_OK : IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
|
||||
int JResultSet::fetchRelative(CheckStatusWrapper* user_status, int offset, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
|
||||
check_database(tdbb);
|
||||
|
||||
try
|
||||
{
|
||||
state = cursor->fetchRelative(tdbb, static_cast<UCHAR*>(buffer), offset);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
transliterateException(tdbb, ex, user_status, "JResultSet::fetchRelative");
|
||||
return IStatus::FB_ERROR;
|
||||
}
|
||||
|
||||
trace_warning(tdbb, user_status, "JResultSet::fetchRelative");
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4718,26 +4783,37 @@ int JResultSet::fetchRelative(CheckStatusWrapper* user_status, int offset, void*
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return IStatus::FB_OK;
|
||||
return (state == 0) ? IStatus::FB_OK : IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
|
||||
FB_BOOLEAN JResultSet::isEof(CheckStatusWrapper* user_status)
|
||||
{
|
||||
return (state > 0);
|
||||
}
|
||||
|
||||
|
||||
FB_BOOLEAN JResultSet::isBof(CheckStatusWrapper* user_status)
|
||||
{
|
||||
return (state < 0);
|
||||
}
|
||||
|
||||
|
||||
int JResultSet::release()
|
||||
{
|
||||
if (--refCounter != 0)
|
||||
return 1;
|
||||
|
||||
if (statement)
|
||||
if (cursor)
|
||||
{
|
||||
LocalStatus status;
|
||||
CheckStatusWrapper statusWrapper(&status);
|
||||
|
||||
freeEngineData(&statusWrapper);
|
||||
}
|
||||
if (!statement)
|
||||
{
|
||||
|
||||
if (!cursor)
|
||||
delete this;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4752,8 +4828,8 @@ void JResultSet::freeEngineData(CheckStatusWrapper* user_status)
|
||||
|
||||
try
|
||||
{
|
||||
DSQL_free_statement(tdbb, getHandle(), DSQL_close);
|
||||
statement = NULL;
|
||||
DsqlCursor::close(tdbb, cursor);
|
||||
cursor = NULL;
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -4771,33 +4847,9 @@ void JResultSet::freeEngineData(CheckStatusWrapper* user_status)
|
||||
}
|
||||
|
||||
|
||||
FB_BOOLEAN JResultSet::isEof(CheckStatusWrapper* user_status)
|
||||
{
|
||||
return eof ? FB_TRUE : FB_FALSE;
|
||||
}
|
||||
|
||||
|
||||
FB_BOOLEAN JResultSet::isBof(CheckStatusWrapper* user_status)
|
||||
{
|
||||
try
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(user_status);
|
||||
return FB_FALSE;
|
||||
}
|
||||
|
||||
successful_completion(user_status);
|
||||
|
||||
return FB_TRUE;
|
||||
}
|
||||
|
||||
|
||||
IMessageMetadata* JResultSet::getMetadata(CheckStatusWrapper* user_status)
|
||||
{
|
||||
return statement->getOutputMetadata(user_status);
|
||||
return NULL;//statement->getOutputMetadata(user_status);
|
||||
}
|
||||
|
||||
|
||||
@ -5122,9 +5174,11 @@ void JResultSet::setDelayedOutputFormat(CheckStatusWrapper* user_status, Firebir
|
||||
|
||||
try
|
||||
{
|
||||
/*
|
||||
dsql_req* req = getStatement()->getHandle();
|
||||
fb_assert(req);
|
||||
req->setDelayedFormat(tdbb, outMetadata);
|
||||
*/
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -6297,7 +6351,7 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
dbb->dbb_event_mgr->deleteSession(attachment->att_event_session);
|
||||
|
||||
// CMP_release() changes att_requests.
|
||||
while (!attachment->att_requests.isEmpty())
|
||||
while (attachment->att_requests.hasData())
|
||||
CMP_release(tdbb, attachment->att_requests.back());
|
||||
|
||||
MET_clear_cache(tdbb);
|
||||
|
@ -748,7 +748,7 @@ void TRA_invalidate(thread_db* tdbb, ULONG mask)
|
||||
}
|
||||
|
||||
|
||||
void TRA_link_cursor(jrd_tra* transaction, dsql_req* cursor)
|
||||
void TRA_link_cursor(jrd_tra* transaction, DsqlCursor* cursor)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -766,7 +766,7 @@ void TRA_link_cursor(jrd_tra* transaction, dsql_req* cursor)
|
||||
}
|
||||
|
||||
|
||||
void TRA_unlink_cursor(jrd_tra* transaction, dsql_req* cursor)
|
||||
void TRA_unlink_cursor(jrd_tra* transaction, DsqlCursor* cursor)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -781,9 +781,7 @@ void TRA_unlink_cursor(jrd_tra* transaction, dsql_req* cursor)
|
||||
|
||||
FB_SIZE_T pos;
|
||||
if (transaction->tra_open_cursors.find(cursor, pos))
|
||||
{
|
||||
transaction->tra_open_cursors.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1217,10 +1215,8 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr
|
||||
|
||||
// Close all open DSQL cursors
|
||||
|
||||
while (transaction->tra_open_cursors.getCount())
|
||||
{
|
||||
DSQL_free_statement(tdbb, transaction->tra_open_cursors.pop(), DSQL_close);
|
||||
}
|
||||
while (transaction->tra_open_cursors.hasData())
|
||||
DsqlCursor::close(tdbb, transaction->tra_open_cursors.pop());
|
||||
|
||||
// Release the transaction and its pool
|
||||
|
||||
|
@ -278,7 +278,7 @@ public:
|
||||
jrd_req* tra_requests; // Doubly linked list of requests active in this transaction
|
||||
MonitoringSnapshot* tra_mon_snapshot; // Database state snapshot (for monitoring purposes)
|
||||
RuntimeStatistics tra_stats;
|
||||
Firebird::Array<dsql_req*> tra_open_cursors;
|
||||
Firebird::Array<DsqlCursor*> tra_open_cursors;
|
||||
bool tra_in_use; // transaction in use (can't be committed or rolled back)
|
||||
jrd_tra* const tra_outer; // outer transaction of an autonomous transaction
|
||||
CallerName tra_caller_name; // caller object name
|
||||
|
@ -45,8 +45,8 @@ void TRA_header_write(Jrd::thread_db* tdbb, Jrd::Database* dbb, TraNumber number
|
||||
#endif
|
||||
void TRA_init(Jrd::Attachment*);
|
||||
void TRA_invalidate(Jrd::thread_db* tdbb, ULONG);
|
||||
void TRA_link_cursor(Jrd::jrd_tra*, Jrd::dsql_req*);
|
||||
void TRA_unlink_cursor(Jrd::jrd_tra*, Jrd::dsql_req*);
|
||||
void TRA_link_cursor(Jrd::jrd_tra*, Jrd::DsqlCursor*);
|
||||
void TRA_unlink_cursor(Jrd::jrd_tra*, Jrd::DsqlCursor*);
|
||||
void TRA_post_resources(Jrd::thread_db* tdbb, Jrd::jrd_tra*, Jrd::ResourceList&);
|
||||
bool TRA_pc_active(Jrd::thread_db*, TraNumber);
|
||||
bool TRA_precommited(Jrd::thread_db* tdbb, TraNumber old_number, TraNumber new_number);
|
||||
|
@ -253,7 +253,7 @@ public:
|
||||
int fetchPrior(CheckStatusWrapper* status, void* message);
|
||||
int fetchFirst(CheckStatusWrapper* status, void* message);
|
||||
int fetchLast(CheckStatusWrapper* status, void* message);
|
||||
int fetchAbsolute(CheckStatusWrapper* status, unsigned int position, void* message);
|
||||
int fetchAbsolute(CheckStatusWrapper* status, int position, void* message);
|
||||
int fetchRelative(CheckStatusWrapper* status, int offset, void* message);
|
||||
FB_BOOLEAN isEof(CheckStatusWrapper* status);
|
||||
FB_BOOLEAN isBof(CheckStatusWrapper* status);
|
||||
@ -311,7 +311,8 @@ public:
|
||||
IMessageMetadata* inMetadata, void* inBuffer,
|
||||
IMessageMetadata* outMetadata, void* outBuffer);
|
||||
ResultSet* openCursor(CheckStatusWrapper* status, ITransaction* tra,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outFormat);
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outFormat,
|
||||
unsigned int flags);
|
||||
void setCursorName(CheckStatusWrapper* status, const char* name);
|
||||
void free(CheckStatusWrapper* status);
|
||||
unsigned getFlags(CheckStatusWrapper* status);
|
||||
@ -486,7 +487,7 @@ public:
|
||||
Firebird::IResultSet* openCursor(CheckStatusWrapper* status, ITransaction* transaction,
|
||||
unsigned int stmtLength, const char* sqlStmt, unsigned dialect,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, Firebird::IMessageMetadata* outMetadata,
|
||||
const char* cursorName);
|
||||
const char* cursorName, unsigned int cursorFlags);
|
||||
Firebird::IEvents* queEvents(CheckStatusWrapper* status, Firebird::IEventCallback* callback,
|
||||
unsigned int length, const unsigned char* events);
|
||||
void cancelOperation(CheckStatusWrapper* status, int option);
|
||||
@ -1850,7 +1851,7 @@ Firebird::ITransaction* Statement::execute(CheckStatusWrapper* status, Firebird:
|
||||
|
||||
|
||||
ResultSet* Statement::openCursor(CheckStatusWrapper* status, Firebird::ITransaction* apiTra,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outFormat)
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outFormat, unsigned int flags)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1986,7 +1987,7 @@ ResultSet* Statement::openCursor(CheckStatusWrapper* status, Firebird::ITransact
|
||||
IResultSet* Attachment::openCursor(CheckStatusWrapper* status, ITransaction* transaction,
|
||||
unsigned int stmtLength, const char* sqlStmt, unsigned dialect,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata,
|
||||
const char* cursorName)
|
||||
const char* cursorName, unsigned int cursorFlags)
|
||||
{
|
||||
Statement* stmt = prepare(status, transaction, stmtLength, sqlStmt, dialect,
|
||||
(outMetadata ? 0 : IStatement::PREPARE_PREFETCH_OUTPUT_PARAMETERS));
|
||||
@ -1995,7 +1996,7 @@ IResultSet* Attachment::openCursor(CheckStatusWrapper* status, ITransaction* tra
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ResultSet* rc = stmt->openCursor(status, transaction, inMetadata, inBuffer, outMetadata);
|
||||
ResultSet* rc = stmt->openCursor(status, transaction, inMetadata, inBuffer, outMetadata, cursorFlags);
|
||||
if (status->getStatus() & Firebird::IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
stmt->release();
|
||||
@ -2934,7 +2935,7 @@ int ResultSet::fetchNext(CheckStatusWrapper* status, void* buffer)
|
||||
//statement->rsr_flags.clear(Rsr::EOF_SET);
|
||||
statement->rsr_flags.set(Rsr::PAST_EOF);
|
||||
|
||||
return IStatus::FB_EOF;
|
||||
return IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
if (statement->rsr_flags.test(Rsr::STREAM_ERR))
|
||||
@ -3030,7 +3031,7 @@ int ResultSet::fetchLast(CheckStatusWrapper* user_status, void* buffer)
|
||||
}
|
||||
|
||||
|
||||
int ResultSet::fetchAbsolute(CheckStatusWrapper* user_status, unsigned position, void* buffer)
|
||||
int ResultSet::fetchAbsolute(CheckStatusWrapper* user_status, int position, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -3384,7 +3385,7 @@ int Blob::getSegment(CheckStatusWrapper* status, unsigned int bufferLength, void
|
||||
{
|
||||
if (segmentLength)
|
||||
*segmentLength = length;
|
||||
return IStatus::FB_EOF;
|
||||
return IStatus::FB_NO_DATA;
|
||||
}
|
||||
|
||||
// Here's the loop, passing out data from our basket & refilling it.
|
||||
@ -3462,7 +3463,7 @@ int Blob::getSegment(CheckStatusWrapper* status, unsigned int bufferLength, void
|
||||
if (blob->rbl_flags & Rbl::EOF_PENDING)
|
||||
{
|
||||
blob->rbl_flags |= Rbl::EOF_SET;
|
||||
code = IStatus::FB_EOF;
|
||||
code = IStatus::FB_NO_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3201,7 +3201,8 @@ ISC_STATUS rem_port::execute_statement(P_OP op, P_SQLDATA* sqldata, PACKET* send
|
||||
statement->rsr_cursor =
|
||||
statement->rsr_iface->openCursor(&status_vector, tra,
|
||||
iMsgBuffer.metadata, iMsgBuffer.buffer,
|
||||
(out_blr_length ? oMsgBuffer.metadata : DELAYED_OUT_FORMAT));
|
||||
(out_blr_length ? oMsgBuffer.metadata : DELAYED_OUT_FORMAT),
|
||||
0);
|
||||
if (!(status_vector.getStatus() & Firebird::IStatus::FB_HAS_ERRORS))
|
||||
{
|
||||
transaction->rtr_cursors.add(statement);
|
||||
@ -3558,9 +3559,9 @@ ISC_STATUS rem_port::get_segment(P_SGMT* segment, PACKET* sendL)
|
||||
p += 2;
|
||||
unsigned length;
|
||||
int cc = blob->rbl_iface->getSegment(&status_vector, buffer_length, p, &length);
|
||||
if (cc == IStatus::FB_EOF || cc == IStatus::FB_ERROR)
|
||||
if (cc == IStatus::FB_NO_DATA || cc == IStatus::FB_ERROR)
|
||||
{
|
||||
if (cc == IStatus::FB_EOF)
|
||||
if (cc == IStatus::FB_NO_DATA)
|
||||
state = 2;
|
||||
p -= 2;
|
||||
break;
|
||||
|
@ -307,7 +307,7 @@ public:
|
||||
int fetchPrior(Firebird::CheckStatusWrapper* status, void* message);
|
||||
int fetchFirst(Firebird::CheckStatusWrapper* status, void* message);
|
||||
int fetchLast(Firebird::CheckStatusWrapper* status, void* message);
|
||||
int fetchAbsolute(Firebird::CheckStatusWrapper* status, unsigned int position, void* message);
|
||||
int fetchAbsolute(Firebird::CheckStatusWrapper* status, int position, void* message);
|
||||
int fetchRelative(Firebird::CheckStatusWrapper* status, int offset, void* message);
|
||||
FB_BOOLEAN isEof(Firebird::CheckStatusWrapper* status);
|
||||
FB_BOOLEAN isBof(Firebird::CheckStatusWrapper* status);
|
||||
@ -359,7 +359,8 @@ public:
|
||||
Firebird::IMessageMetadata* inMetadata, void* inBuffer,
|
||||
Firebird::IMessageMetadata* outMetadata, void* outBuffer);
|
||||
Firebird::IResultSet* openCursor(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction,
|
||||
Firebird::IMessageMetadata* inMetadata, void* inBuffer, Firebird::IMessageMetadata* outMetadata);
|
||||
Firebird::IMessageMetadata* inMetadata, void* inBuffer, Firebird::IMessageMetadata* outMetadata,
|
||||
unsigned int flags);
|
||||
void setCursorName(Firebird::CheckStatusWrapper* status, const char* name);
|
||||
void free(Firebird::CheckStatusWrapper* status);
|
||||
unsigned getFlags(Firebird::CheckStatusWrapper* status);
|
||||
@ -439,7 +440,7 @@ public:
|
||||
Firebird::IResultSet* openCursor(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction,
|
||||
unsigned int stmtLength, const char* sqlStmt, unsigned int dialect,
|
||||
Firebird::IMessageMetadata* inMetadata, void* inBuffer, Firebird::IMessageMetadata* outMetadata,
|
||||
const char* cursorName);
|
||||
const char* cursorName, unsigned int cursorFlags);
|
||||
YEvents* queEvents(Firebird::CheckStatusWrapper* status, Firebird::IEventCallback* callback,
|
||||
unsigned int length, const unsigned char* eventsData);
|
||||
void cancelOperation(Firebird::CheckStatusWrapper* status, int option);
|
||||
|
@ -257,7 +257,7 @@ void dump(CheckStatusWrapper* status, ISC_QUAD* blobId, IAttachment* att, ITrans
|
||||
switch (blob->getSegment(status, short_length, buffer, &l))
|
||||
{
|
||||
case Firebird::IStatus::FB_ERROR:
|
||||
case Firebird::IStatus::FB_EOF:
|
||||
case Firebird::IStatus::FB_NO_DATA:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1317,7 +1317,7 @@ namespace {
|
||||
// Transaction is not optional for statement returning result set
|
||||
RefPtr<YTransaction> transaction = translateHandle(transactions, traHandle);;
|
||||
|
||||
statement->openCursor(status, transaction, inMetadata, buffer, outMetadata);
|
||||
statement->openCursor(status, transaction, inMetadata, buffer, outMetadata, 0);
|
||||
|
||||
if (status->getStatus() & Firebird::IStatus::FB_HAS_ERRORS)
|
||||
return;
|
||||
@ -2938,7 +2938,7 @@ ISC_STATUS API_ROUTINE isc_get_segment(ISC_STATUS* userStatus, FB_API_HANDLE* bl
|
||||
// Raise pseudo errors
|
||||
switch (cc)
|
||||
{
|
||||
case IStatus::FB_EOF:
|
||||
case IStatus::FB_NO_DATA:
|
||||
Arg::Gds(isc_segstr_eof).raise();
|
||||
break;
|
||||
case IStatus::FB_SEGMENT:
|
||||
@ -4310,7 +4310,7 @@ ITransaction* YStatement::execute(CheckStatusWrapper* status, ITransaction* tran
|
||||
}
|
||||
|
||||
IResultSet* YStatement::openCursor(Firebird::CheckStatusWrapper* status, ITransaction* transaction,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata)
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned int flags)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -4320,7 +4320,7 @@ IResultSet* YStatement::openCursor(Firebird::CheckStatusWrapper* status, ITransa
|
||||
if (transaction)
|
||||
attachment->getNextTransaction(status, transaction, trans);
|
||||
|
||||
IResultSet* rs = entry.next()->openCursor(status, trans, inMetadata, inBuffer, outMetadata);
|
||||
IResultSet* rs = entry.next()->openCursor(status, trans, inMetadata, inBuffer, outMetadata, flags);
|
||||
if (status->getStatus() & Firebird::IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
return NULL;
|
||||
@ -4498,7 +4498,7 @@ int YResultSet::fetchLast(CheckStatusWrapper* status, void* buffer)
|
||||
return FB_FALSE;
|
||||
}
|
||||
|
||||
int YResultSet::fetchAbsolute(CheckStatusWrapper* status, unsigned int position, void* buffer)
|
||||
int YResultSet::fetchAbsolute(CheckStatusWrapper* status, int position, void* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -5138,7 +5138,7 @@ void YAttachment::executeDyn(CheckStatusWrapper* status, ITransaction* transacti
|
||||
IResultSet* YAttachment::openCursor(CheckStatusWrapper* status, ITransaction* transaction,
|
||||
unsigned int length, const char* string, unsigned int dialect,
|
||||
IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata,
|
||||
const char* cursorName)
|
||||
const char* cursorName, unsigned int cursorFlags)
|
||||
{
|
||||
IResultSet* rs = NULL;
|
||||
try
|
||||
@ -5150,7 +5150,7 @@ IResultSet* YAttachment::openCursor(CheckStatusWrapper* status, ITransaction* tr
|
||||
getNextTransaction(status, transaction, trans);
|
||||
|
||||
rs = entry.next()->openCursor(status, trans, length, string, dialect,
|
||||
inMetadata, inBuffer, outMetadata, cursorName);
|
||||
inMetadata, inBuffer, outMetadata, cursorName, cursorFlags);
|
||||
if (status->getStatus() & Firebird::IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user