8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 04:03:04 +01:00

Patch from Dimitry Sibiryakov - enable access to messages longer than 64Kb from SQLDA. Slightly modified to avoid code duplication.

This commit is contained in:
alexpeshkoff 2014-03-12 09:19:40 +00:00
parent 3e52925a0d
commit 578c5cf033

View File

@ -1966,6 +1966,70 @@ ISC_STATUS API_ROUTINE isc_dsql_execute(ISC_STATUS* userStatus, FB_API_HANDLE* t
} }
static void execute_32bit_m(IStatus* status, YTransaction* transaction, FB_API_HANDLE* traHandle,
IscStatement* statement,
unsigned inBlrLength, const UCHAR* inBlr, unsigned inMsgLength, UCHAR* inMsg,
unsigned outBlrLength, const UCHAR* outBlr, unsigned outMsgLength, UCHAR* outMsg)
{
InternalMessageBuffer inMsgBuffer(inBlrLength, inBlr, inMsgLength, inMsg);
InternalMessageBuffer outMsgBuffer(outBlrLength, outBlr, outMsgLength, outMsg);
statement->checkCursor(false);
unsigned flags = statement->statement->getFlags(status);
if (status->isSuccess())
{
if ((flags & IStatement::FLAG_HAS_CURSOR) && (outMsgLength == 0))
{
if (outBlrLength)
{
statement->statement->openCursor(status, transaction,
inMsgBuffer.metadata, inMsgBuffer.buffer, outMsgBuffer.metadata);
if (!status->isSuccess())
return;
fb_assert(statement->statement->cursor);
if (statement->cursorName.hasData())
{
statement->statement->cursor->setCursorName(status, statement->cursorName.c_str());
if (status->isSuccess())
statement->cursorName = "";
}
}
else // delay execution till first fetch (with output format)
{
statement->parMetadata = inMsgBuffer.metadata;
statement->parameters.assign(static_cast<UCHAR*>(inMsgBuffer.buffer), inMsgLength);
statement->transaction = transaction;
}
}
else
{
ITransaction* newTrans = statement->statement->execute(status, transaction,
inMsgBuffer.metadata, inMsgBuffer.buffer, outMsgBuffer.metadata, outMsgBuffer.buffer);
if (status->isSuccess())
{
if (transaction && !newTrans)
{
transaction->destroy();
*traHandle = 0;
}
else if (!transaction && newTrans)
{
// in this case we know for sure that newTrans points to YTransaction
if (traHandle)
*traHandle = static_cast<YTransaction*>(newTrans)->getHandle();
}
}
}
}
}
// Execute a non-SELECT dynamic SQL statement. // Execute a non-SELECT dynamic SQL statement.
ISC_STATUS API_ROUTINE isc_dsql_execute2(ISC_STATUS* userStatus, FB_API_HANDLE* traHandle, ISC_STATUS API_ROUTINE isc_dsql_execute2(ISC_STATUS* userStatus, FB_API_HANDLE* traHandle,
FB_API_HANDLE* stmtHandle, USHORT dialect, const XSQLDA* inSqlda, const XSQLDA* outSqlda) FB_API_HANDLE* stmtHandle, USHORT dialect, const XSQLDA* inSqlda, const XSQLDA* outSqlda)
@ -1978,6 +2042,10 @@ ISC_STATUS API_ROUTINE isc_dsql_execute2(ISC_STATUS* userStatus, FB_API_HANDLE*
statement->checkPrepared(); statement->checkPrepared();
RefPtr<YTransaction> transaction;
if (traHandle && *traHandle)
transaction = translateHandle(transactions, traHandle);
Array<UCHAR> inBlr, inMessage, outBlr, outMessage; Array<UCHAR> inBlr, inMessage, outBlr, outMessage;
sqldaParse(inSqlda, inBlr, inMessage, dialect); sqldaParse(inSqlda, inBlr, inMessage, dialect);
@ -1985,14 +2053,9 @@ ISC_STATUS API_ROUTINE isc_dsql_execute2(ISC_STATUS* userStatus, FB_API_HANDLE*
sqldaParse(outSqlda, outBlr, outMessage, dialect); sqldaParse(outSqlda, outBlr, outMessage, dialect);
if (isc_dsql_execute2_m(status, traHandle, stmtHandle, execute_32bit_m(&status, transaction, traHandle, statement,
inBlr.getCount(), reinterpret_cast<SCHAR*>(inBlr.begin()), 0, inBlr.getCount(), inBlr.begin(), inMessage.getCount(), inMessage.begin(),
inMessage.getCount(), reinterpret_cast<SCHAR*>(inMessage.begin()), outBlr.getCount(), outBlr.begin(), outMessage.getCount(), outMessage.begin());
outBlr.getCount(), reinterpret_cast<SCHAR*>(outBlr.begin()), 0,
outMessage.getCount(), reinterpret_cast<SCHAR*>(outMessage.begin())))
{
return status[1];
}
sqldaMove(outSqlda, outMessage, false); sqldaMove(outSqlda, outMessage, false);
} }
@ -2039,67 +2102,11 @@ ISC_STATUS API_ROUTINE isc_dsql_execute2_m(ISC_STATUS* userStatus, FB_API_HANDLE
if (traHandle && *traHandle) if (traHandle && *traHandle)
transaction = translateHandle(transactions, traHandle); transaction = translateHandle(transactions, traHandle);
InternalMessageBuffer inMsgBuffer(inBlrLength, reinterpret_cast<const unsigned char*>(inBlr), execute_32bit_m(&status, transaction, traHandle, statement,
inMsgLength, reinterpret_cast<UCHAR*>(const_cast<SCHAR*>(inMsg))); inBlrLength, reinterpret_cast<const unsigned char*>(inBlr),
InternalMessageBuffer outMsgBuffer(outBlrLength, reinterpret_cast<unsigned char*>(outBlr), inMsgLength, reinterpret_cast<UCHAR*>(const_cast<SCHAR*>(inMsg)),
outMsgLength, reinterpret_cast<unsigned char*>(outMsg)); outBlrLength, reinterpret_cast<unsigned char*>(outBlr),
outMsgLength, reinterpret_cast<unsigned char*>(outMsg));
statement->checkCursor(false);
unsigned flags = statement->statement->getFlags(&status);
if (!status.isSuccess())
{
return status[1];
}
if ((flags & IStatement::FLAG_HAS_CURSOR) && (outMsgLength == 0))
{
if (outBlrLength)
{
statement->statement->openCursor(&status, transaction,
inMsgBuffer.metadata, inMsgBuffer.buffer, outMsgBuffer.metadata);
if (!status.isSuccess())
return status[1];
fb_assert(statement->statement->cursor);
if (statement->cursorName.hasData())
{
statement->statement->cursor->setCursorName(&status, statement->cursorName.c_str());
if (status.isSuccess())
statement->cursorName = "";
}
}
else // delay execution till first fetch (with output format)
{
statement->parMetadata = inMsgBuffer.metadata;
statement->parameters.assign(static_cast<UCHAR*>(inMsgBuffer.buffer), inMsgLength);
statement->transaction = transaction;
return 0;
}
}
else
{
ITransaction* newTrans = statement->statement->execute(&status, transaction,
inMsgBuffer.metadata, inMsgBuffer.buffer, outMsgBuffer.metadata, outMsgBuffer.buffer);
if (status.isSuccess())
{
if (transaction && !newTrans)
{
transaction->destroy();
*traHandle = 0;
}
else if (!transaction && newTrans)
{
// in this case we know for sure that newTrans points to YTransaction
if (traHandle)
*traHandle = static_cast<YTransaction*>(newTrans)->getHandle();
}
}
}
} }
catch (const Exception& e) catch (const Exception& e)
{ {
@ -2136,13 +2143,29 @@ ISC_STATUS API_ROUTINE isc_dsql_exec_immed2(ISC_STATUS* userStatus, FB_API_HANDL
const XSQLDA* inSqlda, const XSQLDA* outSqlda) const XSQLDA* inSqlda, const XSQLDA* outSqlda)
{ {
StatusVector status(userStatus); StatusVector status(userStatus);
ISC_STATUS s = 0;
try try
{ {
if (!sqlStmt) if (!sqlStmt)
Arg::Gds(isc_command_end_err).raise(); Arg::Gds(isc_command_end_err).raise();
FB_BOOLEAN stmtIsCrDb = FB_FALSE;
YAttachment* att = utlInterface.executeCreateDatabase(&status, stmtLength, sqlStmt, dialect, &stmtIsCrDb);
if (stmtIsCrDb)
{
if (status.isSuccess())
*dbHandle = att->getHandle();
return status[1];
}
RefPtr<YAttachment> attachment(translateHandle(attachments, dbHandle));
RefPtr<YTransaction> transaction;
if (traHandle && *traHandle)
transaction = translateHandle(transactions, traHandle);
Array<UCHAR> inBlr, inMessage, outBlr, outMessage; Array<UCHAR> inBlr, inMessage, outBlr, outMessage;
sqldaParse(inSqlda, inBlr, inMessage, dialect); sqldaParse(inSqlda, inBlr, inMessage, dialect);
@ -2150,22 +2173,39 @@ ISC_STATUS API_ROUTINE isc_dsql_exec_immed2(ISC_STATUS* userStatus, FB_API_HANDL
sqldaParse(outSqlda, outBlr, outMessage, dialect); sqldaParse(outSqlda, outBlr, outMessage, dialect);
s = isc_dsql_exec_immed2_m(status, dbHandle, traHandle, stmtLength, sqlStmt, dialect, InternalMessageBuffer inMsgBuffer(inBlr.getCount(), inBlr.begin(),
inBlr.getCount(), reinterpret_cast<SCHAR*>(inBlr.begin()), 0, inMessage.getCount(), inMessage.begin());
inMessage.getCount(), reinterpret_cast<SCHAR*>(inMessage.begin()), InternalMessageBuffer outMsgBuffer(outBlr.getCount(), outBlr.begin(),
outBlr.getCount(), reinterpret_cast<SCHAR*>(outBlr.begin()), 0, outMessage.getCount(), outMessage.begin());
outMessage.getCount(), reinterpret_cast<SCHAR*>(outMessage.begin()));
ITransaction* newTrans = attachment->execute(&status, transaction, stmtLength, sqlStmt,
dialect, inMsgBuffer.metadata, inMsgBuffer.buffer,
outMsgBuffer.metadata, outMsgBuffer.buffer);
if (status.isSuccess())
{
if (transaction && !newTrans)
{
transaction->destroy();
*traHandle = 0;
}
else if (!transaction && newTrans)
{
// in this case we know for sure that newTrans points to YTransaction
if (traHandle)
*traHandle = static_cast<YTransaction*>(newTrans)->getHandle();
}
if (s == 0)
sqldaMove(outSqlda, outMessage, false); sqldaMove(outSqlda, outMessage, false);
}
} }
catch (const Exception& e) catch (const Exception& e)
{ {
e.stuffException(&status); e.stuffException(&status);
s = status[1];
} }
return s; return status[1];
} }
@ -2263,6 +2303,51 @@ ISC_STATUS API_ROUTINE isc_dsql_exec_immed3_m(ISC_STATUS* userStatus, FB_API_HAN
} }
static ISC_STATUS fetch_32bit_m(IStatus* status, FB_API_HANDLE* stmtHandle,
unsigned blrLength, const UCHAR* blr, unsigned msgLength, UCHAR* msg)
{
RefPtr<IscStatement> statement(translateHandle(statements, stmtHandle));
if (!statement->parMetadata)
statement->checkCursor(true);
else
{
statement->checkCursor(false);
InternalMessageBuffer msgBuffer(blrLength, blr, msgLength, msg);
if (!msgBuffer.metadata)
{
(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
Arg::Gds(isc_dsql_cursor_open_err)).raise();
}
statement->statement->openCursor(status, statement->transaction,
statement->parMetadata, statement->parameters.begin(), msgBuffer.metadata);
if (!status->isSuccess())
return status->get()[1];
fb_assert(statement->statement->cursor);
statement->parMetadata = NULL;
statement->parameters.clear();
statement->transaction = NULL;
if (statement->cursorName.hasData())
{
statement->statement->cursor->setCursorName(status, statement->cursorName.c_str());
if (status->isSuccess())
statement->cursorName = "";
}
}
if (!statement->statement->cursor->fetchNext(status, reinterpret_cast<UCHAR*>(msg)))
return status->isSuccess() ? 100 : status->get()[1];
return status->get()[1];
}
// Fetch next record from a dynamic SQL cursor // Fetch next record from a dynamic SQL cursor
ISC_STATUS API_ROUTINE isc_dsql_fetch(ISC_STATUS* userStatus, FB_API_HANDLE* stmtHandle, ISC_STATUS API_ROUTINE isc_dsql_fetch(ISC_STATUS* userStatus, FB_API_HANDLE* stmtHandle,
USHORT dialect, const XSQLDA* sqlda) USHORT dialect, const XSQLDA* sqlda)
@ -2277,12 +2362,11 @@ ISC_STATUS API_ROUTINE isc_dsql_fetch(ISC_STATUS* userStatus, FB_API_HANDLE* stm
Array<UCHAR> outBlr, outMessage; Array<UCHAR> outBlr, outMessage;
sqldaParse(sqlda, outBlr, outMessage, dialect); sqldaParse(sqlda, outBlr, outMessage, dialect);
ISC_STATUS s = isc_dsql_fetch_m(status, stmtHandle, ISC_STATUS rc = fetch_32bit_m(&status, stmtHandle, outBlr.getCount(), outBlr.begin(),
outBlr.getCount(), reinterpret_cast<SCHAR*>(outBlr.begin()), 0, outMessage.getCount(), outMessage.begin());
outMessage.getCount(), reinterpret_cast<SCHAR*>(outMessage.begin()));
if (s && s != 101) if (rc)
return s; return rc;
sqldaMove(sqlda, outMessage, false); sqldaMove(sqlda, outMessage, false);
} }
@ -2303,44 +2387,8 @@ ISC_STATUS API_ROUTINE isc_dsql_fetch_m(ISC_STATUS* userStatus, FB_API_HANDLE* s
try try
{ {
RefPtr<IscStatement> statement(translateHandle(statements, stmtHandle)); return fetch_32bit_m(&status, stmtHandle, blrLength, reinterpret_cast<UCHAR*>(blr),
msgLength, reinterpret_cast<UCHAR*>(msg));
if (!statement->parMetadata)
statement->checkCursor(true);
else
{
statement->checkCursor(false);
InternalMessageBuffer msgBuffer(blrLength, reinterpret_cast<UCHAR*>(blr),
msgLength, reinterpret_cast<UCHAR*>(msg));
if (!msgBuffer.metadata)
{
(Arg::Gds(isc_sqlerr) << Arg::Num(-502) <<
Arg::Gds(isc_dsql_cursor_open_err)).raise();
}
statement->statement->openCursor(&status, statement->transaction,
statement->parMetadata, statement->parameters.begin(), msgBuffer.metadata);
if (!status.isSuccess())
return status[1];
fb_assert(statement->statement->cursor);
statement->parMetadata = NULL;
statement->parameters.clear();
statement->transaction = NULL;
if (statement->cursorName.hasData())
{
statement->statement->cursor->setCursorName(&status, statement->cursorName.c_str());
if (status.isSuccess())
statement->cursorName = "";
}
}
if (!statement->statement->cursor->fetchNext(&status, reinterpret_cast<UCHAR*>(msg)))
return status.isSuccess() ? 100 : status[1];
} }
catch (const Exception& e) catch (const Exception& e)
{ {