[Libreoffice-commits] core.git: Branch 'libreoffice-4-2' - 2 commits - connectivity/source
Andrzej Hunt
andrzej.hunt at collabora.com
Wed Jan 1 11:12:43 PST 2014
connectivity/source/drivers/firebird/Blob.cxx | 241 +++++++------
connectivity/source/drivers/firebird/Blob.hxx | 48 ++
connectivity/source/drivers/firebird/PreparedStatement.cxx | 128 ++++++
connectivity/source/drivers/firebird/PreparedStatement.hxx | 8
4 files changed, 316 insertions(+), 109 deletions(-)
New commits:
commit 3f65b5066c80a6af4f1f04c7f6f194d789a043cd
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date: Sat Dec 7 20:32:55 2013 +0000
fdo#70664 Allow reading firebird Blob as InputStream.
Change-Id: Ie0cb93a902961b3f37daf435828263478c9d2997
(cherry picked from commit 2b24eec3d4ca50e676c0c3af86ecb92a8eb0a8a2)
diff --git a/connectivity/source/drivers/firebird/Blob.cxx b/connectivity/source/drivers/firebird/Blob.cxx
index f27835d..e1968ba 100644
--- a/connectivity/source/drivers/firebird/Blob.cxx
+++ b/connectivity/source/drivers/firebird/Blob.cxx
@@ -13,6 +13,8 @@
#include "connectivity/dbexception.hxx"
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
using namespace ::connectivity::firebird;
using namespace ::cppu;
@@ -32,7 +34,8 @@ Blob::Blob(isc_db_handle* pDatabaseHandle,
m_blobID(aBlobID),
m_blobHandle(0),
m_bBlobOpened(false),
- m_blobData(0)
+ m_nBlobLength(0),
+ m_nBlobPosition(0)
{
}
@@ -52,12 +55,41 @@ void Blob::ensureBlobIsOpened()
&m_blobID,
0,
NULL);
+
if (aErr)
evaluateStatusVector(m_statusVector, "isc_open_blob2", *this);
+ m_bBlobOpened = true;
+ m_nBlobPosition = 0;
+
+ char aBlobItems[] = {
+ isc_info_blob_total_length
+ };
+ char aResultBuffer[20];
+
+ isc_blob_info(m_statusVector,
+ &m_blobHandle,
+ sizeof(aBlobItems),
+ aBlobItems,
+ sizeof(aResultBuffer),
+ aResultBuffer);
+
+ if (aErr)
+ evaluateStatusVector(m_statusVector, "isc_blob_info", *this);
+
+ if (*aResultBuffer == isc_info_blob_total_length)
+ {
+ short aResultLength = (short) isc_vax_integer(aResultBuffer+1, 2);
+ m_nBlobLength = isc_vax_integer(aResultBuffer+3, aResultLength);
+ }
+ else
+ {
+ assert(false);
+ }
}
-void SAL_CALL Blob::disposing(void)
+void Blob::closeBlob()
+ throw (SQLException)
{
MutexGuard aGuard(m_aMutex);
@@ -67,20 +99,26 @@ void SAL_CALL Blob::disposing(void)
aErr = isc_close_blob(m_statusVector,
&m_blobHandle);
if (aErr)
- {
- try
- {
- evaluateStatusVector(m_statusVector, "isc_close_blob", *this);
- }
- catch (SQLException e)
- {
- // we cannot throw any exceptions here anyway
- SAL_WARN("connectivity.firebird", "isc_close_blob failed\n" <<
- e.Message);
- }
- }
+ evaluateStatusVector(m_statusVector, "isc_close_blob", *this);
+
+ m_bBlobOpened = false;
+ m_blobHandle = 0;
}
+}
+void SAL_CALL Blob::disposing(void)
+{
+ try
+ {
+ closeBlob();
+ }
+ catch (SQLException e)
+ {
+ // we cannot throw any exceptions here...
+ SAL_WARN("connectivity.firebird", "isc_close_blob failed\n" <<
+ e.Message);
+ assert(false);
+ }
Blob_BASE::disposing();
}
@@ -91,118 +129,131 @@ sal_Int64 SAL_CALL Blob::length()
checkDisposed(Blob_BASE::rBHelper.bDisposed);
ensureBlobIsOpened();
- char aBlobItems[] = {
- isc_info_blob_total_length
- };
- char aResultBuffer[20];
-
- isc_blob_info(m_statusVector,
- &m_blobHandle,
- sizeof(aBlobItems),
- aBlobItems,
- sizeof(aResultBuffer),
- aResultBuffer);
-
- evaluateStatusVector(m_statusVector, "isc_blob_info", *this);
- if (*aResultBuffer == isc_info_blob_total_length)
- {
- short aResultLength = (short) isc_vax_integer(aResultBuffer, 2);
- return isc_vax_integer(aResultBuffer+2, aResultLength);
- }
- return 0;
+ return m_nBlobLength;
}
-uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 aPosition, sal_Int32 aLength)
+uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 nPosition,
+ sal_Int32 nBytes)
throw(SQLException, RuntimeException)
{
MutexGuard aGuard(m_aMutex);
checkDisposed(Blob_BASE::rBHelper.bDisposed);
ensureBlobIsOpened();
- sal_Int64 aTotalLength = length();
+ if (nPosition > m_nBlobLength)
+ throw lang::IllegalArgumentException("nPosition out of range", *this, 0);
+ // We only have to read as many bytes as are available, i.e. nPosition+nBytes
+ // can legally be greater than the total length, hence we don't bother to check.
- if (!(aPosition + aLength < aTotalLength))
+ if (nPosition > m_nBlobPosition)
{
- throw SQLException("Byte array requested outwith valid range", *this, OUString(), 1, Any() );
+ // Resets to the beginning (we can't seek these blobs)
+ closeBlob();
+ ensureBlobIsOpened();
}
- if (aTotalLength != m_blobData.getLength())
- {
- m_blobData = uno::Sequence< sal_Int8 >(aTotalLength);
- char* pArray = (char*) m_blobData.getArray();
- sal_Int64 aBytesRead = 0;
-
- unsigned short aLengthRead; // The amount read in in a isc_get_segment call
-
- ISC_STATUS aErr;
- do
- {
- aErr = isc_get_segment(m_statusVector,
- &m_blobHandle,
- &aLengthRead,
- aTotalLength - aBytesRead,
- pArray + aBytesRead);
- }
- while (aErr == 0 || m_statusVector[1] == isc_segment);
- // Denotes either sucessful read, or only part of segment read successfully.
- if (aErr)
- {
- m_blobData = uno::Sequence< sal_Int8 >(0);
- evaluateStatusVector(m_statusVector, "isc_get_segment", *this);
- }
- }
+ skipBytes(nPosition - m_nBlobPosition);
- if (aLength<aTotalLength)
- {
- uno::Sequence< sal_Int8 > aRet(aLength);
- memcpy(aRet.getArray(), m_blobData.getArray() + aLength, aLength);
- return aRet;
- }
- else
- {
- return m_blobData; // TODO: subsequence
- }
+ // Don't bother preallocating: readBytes does the appropriate calculations
+ // and reallocates for us.
+ uno::Sequence< sal_Int8 > aBytes;
+ readBytes(aBytes, nBytes);
+ return aBytes;
}
uno::Reference< XInputStream > SAL_CALL Blob::getBinaryStream()
throw(SQLException, RuntimeException)
{
-// MutexGuard aGuard(m_aMutex);
-// checkDisposed(Blob_BASE::rBHelper.bDisposed);
-// ensureBlobIsOpened();
-
- ::dbtools::throwFeatureNotImplementedException("Blob::positionOfBlob", *this);
- return NULL;
+ return this;
}
-sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& rPattern,
- sal_Int64 aStart)
+sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/,
+ sal_Int64 /*nStart*/)
throw(SQLException, RuntimeException)
{
-// MutexGuard aGuard(m_aMutex);
-// checkDisposed(Blob_BASE::rBHelper.bDisposed);
-// ensureBlobIsOpened();
-
- (void) rPattern;
- (void) aStart;
- ::dbtools::throwFeatureNotImplementedException("Blob::positionOfBlob", *this);
+ ::dbtools::throwFeatureNotImplementedException("Blob::position", *this);
return 0;
}
-sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& rPattern,
- sal_Int64 aStart)
+sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
+ sal_Int64 /*aStart*/)
throw(SQLException, RuntimeException)
{
-// MutexGuard aGuard(m_aMutex);
-// checkDisposed(Blob_BASE::rBHelper.bDisposed);
-// ensureBlobIsOpened();
-
- (void) rPattern;
- (void) aStart;
::dbtools::throwFeatureNotImplementedException("Blob::positionOfBlob", *this);
return 0;
}
+// ---- XInputStream ----------------------------------------------------------
+
+sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nBytes)
+ throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+
+ // Ensure we have enough space for the amount of data we can actually read.
+ const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
+ const sal_Int32 nBytesToRead = nBytes < nBytesAvailable ? nBytes : nBytesAvailable;
+
+ if (rDataOut.getLength() < nBytesToRead)
+ rDataOut.realloc(nBytesToRead);
+ sal_Int32 nTotalBytesRead = 0;
+ ISC_STATUS aErr;
+ while (nTotalBytesRead < nBytesToRead)
+ {
+ sal_uInt16 nBytesRead = 0;
+ sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
+ sal_uInt16 nReadSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
+ aErr = isc_get_segment(m_statusVector,
+ &m_blobHandle,
+ &nBytesRead,
+ nReadSize,
+ (char*) rDataOut.getArray() + nTotalBytesRead);
+ if (aErr)
+ evaluateStatusVector(m_statusVector, "isc_get_segment", *this);
+ nTotalBytesRead += nBytesRead;
+ m_nBlobPosition += nBytesRead;
+ }
+
+ return nTotalBytesRead;
+}
+
+sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nMaximumBytes)
+ throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
+{
+ // We don't have any way of verifying how many bytes are immediately available,
+ // hence we just pass through direct to readBytes
+ // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
+ return readBytes(rDataOut, nMaximumBytes);
+}
+
+void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
+ throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
+{
+ // There is no way of directly skipping, hence we have to pretend to skip
+ // by reading & discarding the data.
+ uno::Sequence< sal_Int8 > aBytes;
+ readBytes(aBytes, nBytesToSkip);
+}
+
+sal_Int32 SAL_CALL Blob::available()
+ throw (NotConnectedException, IOException, RuntimeException)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed(Blob_BASE::rBHelper.bDisposed);
+ ensureBlobIsOpened();
+
+ return m_nBlobLength - m_nBlobPosition;
+}
+
+void SAL_CALL Blob::closeInput()
+ throw(NotConnectedException, IOException, RuntimeException)
+{
+ closeBlob();
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
diff --git a/connectivity/source/drivers/firebird/Blob.hxx b/connectivity/source/drivers/firebird/Blob.hxx
index f4eb792..3814f59 100644
--- a/connectivity/source/drivers/firebird/Blob.hxx
+++ b/connectivity/source/drivers/firebird/Blob.hxx
@@ -12,15 +12,17 @@
#include <ibase.h>
-#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/compbase2.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/sdbc/XBlob.hpp>
namespace connectivity
{
namespace firebird
{
- typedef ::cppu::WeakComponentImplHelper1< ::com::sun::star::sdbc::XBlob >
+ typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::sdbc::XBlob,
+ ::com::sun::star::io::XInputStream >
Blob_BASE;
class Blob :
@@ -38,13 +40,19 @@ namespace connectivity
isc_blob_handle m_blobHandle;
bool m_bBlobOpened;
+ sal_Int64 m_nBlobLength;
+ sal_Int64 m_nBlobPosition;
ISC_STATUS_ARRAY m_statusVector;
- ::com::sun::star::uno::Sequence< sal_Int8 > m_blobData;
-
void ensureBlobIsOpened()
throw(::com::sun::star::sdbc::SQLException);
+ /**
+ * Closes the blob and cleans up resources -- can be used to reset
+ * the blob if we e.g. want to read from the beginning again.
+ */
+ void closeBlob()
+ throw(::com::sun::star::sdbc::SQLException);
public:
Blob(isc_db_handle* pDatabaseHandle,
@@ -75,6 +83,38 @@ namespace connectivity
throw(::com::sun::star::sdbc::SQLException,
::com::sun::star::uno::RuntimeException);
+ // ---- XInputStream ----------------------------------------------
+ virtual sal_Int32 SAL_CALL
+ readBytes(::com::sun::star::uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nBytes)
+ throw(::com::sun::star::io::NotConnectedException,
+ ::com::sun::star::io::BufferSizeExceededException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL
+ readSomeBytes(::com::sun::star::uno::Sequence< sal_Int8 >& rDataOut,
+ sal_Int32 nMaximumBytes)
+ throw(::com::sun::star::io::NotConnectedException,
+ ::com::sun::star::io::BufferSizeExceededException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ skipBytes(sal_Int32 nBytes)
+ throw(::com::sun::star::io::NotConnectedException,
+ ::com::sun::star::io::BufferSizeExceededException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL
+ available()
+ throw(::com::sun::star::io::NotConnectedException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ closeInput()
+ throw(::com::sun::star::io::NotConnectedException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+
// ---- OComponentHelper ------------------------------------------
virtual void SAL_CALL disposing();
};
commit 990c8f57b673eec03296ca72b19f946775840395
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date: Thu Dec 5 13:58:59 2013 +0000
fdo#70664 Implement Blob writing (firebird-sdbc).
Change-Id: Ia95c6e1a0ede2103aae25610baeb3c7a9642113a
(cherry picked from commit cb4b290bcfbc5ac73103a557f8de429c3d7d7c3b)
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx
index 5e02616..128f357 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.cxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx
@@ -432,6 +432,43 @@ void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 nIndex, const DateTime&
}
// -------------------------------------------------------------------------
+// void OPreaparedStatement::set
+void OPreparedStatement::openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId)
+{
+ ISC_STATUS aErr;
+
+ aErr = isc_create_blob2(m_statusVector,
+ &m_pConnection->getDBHandle(),
+ &m_pConnection->getTransaction(),
+ &rBlobHandle,
+ &rBlobId,
+ 0, // Blob parameter buffer length
+ 0); // Blob parameter buffer handle
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ "setBlob failed on " + m_sSqlStatement,
+ *this);
+ assert(false);
+ }
+}
+
+void OPreparedStatement::closeBlobAfterWriting(isc_blob_handle& rBlobHandle)
+{
+ ISC_STATUS aErr;
+
+ aErr = isc_close_blob(m_statusVector,
+ &rBlobHandle);
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ "isc_close_blob failed",
+ *this);
+ assert(false);
+ }
+}
+
void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) throw(SQLException, RuntimeException)
{
(void) parameterIndex;
@@ -440,16 +477,53 @@ void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Refer
checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
}
-// -------------------------------------------------------------------------
-void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x ) throw(SQLException, RuntimeException)
+void SAL_CALL OPreparedStatement::setBlob(sal_Int32 nParameterIndex,
+ const Reference< XBlob >& xBlob)
+ throw (SQLException, RuntimeException)
{
- (void) parameterIndex;
- (void) x;
- ::osl::MutexGuard aGuard( m_aMutex );
+ ::osl::MutexGuard aGuard(m_aMutex);
checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ isc_blob_handle aBlobHandle = 0;
+ ISC_QUAD aBlobId;
+
+ openBlobForWriting(aBlobHandle, aBlobId);
+
+ // Max segment size is 2^16 == SAL_MAX_UINT16
+ sal_uInt64 nDataWritten = 0;
+ ISC_STATUS aErr;
+ while (xBlob->length() - nDataWritten > 0)
+ {
+ sal_uInt64 nDataRemaining = xBlob->length() - nDataWritten;
+ sal_uInt16 nWriteSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
+ aErr = isc_put_segment(m_statusVector,
+ &aBlobHandle,
+ nWriteSize,
+ (const char*) xBlob->getBytes(nDataWritten, nWriteSize).getConstArray());
+ nDataWritten += nWriteSize;
+
+
+ if (aErr)
+ break;
+
+ }
+
+ // We need to make sure we close the Blob even if their are errors, hence evaluate
+ // errors after closing.
+ closeBlobAfterWriting(aBlobHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ "isc_put_segment failed",
+ *this);
+ assert(false);
+ }
+
+ setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
}
+
// -------------------------------------------------------------------------
void SAL_CALL OPreparedStatement::setArray( sal_Int32 parameterIndex, const Reference< XArray >& x ) throw(SQLException, RuntimeException)
@@ -503,15 +577,49 @@ void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any
checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
}
-// -------------------------------------------------------------------------
-void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) throw(SQLException, RuntimeException)
+void SAL_CALL OPreparedStatement::setBytes(sal_Int32 nParameterIndex,
+ const Sequence< sal_Int8 >& xBytes)
+ throw (SQLException, RuntimeException)
{
- (void) parameterIndex;
- (void) x;
- ::osl::MutexGuard aGuard( m_aMutex );
+ ::osl::MutexGuard aGuard(m_aMutex);
checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed);
+ isc_blob_handle aBlobHandle = 0;
+ ISC_QUAD aBlobId;
+
+ openBlobForWriting(aBlobHandle, aBlobId);
+
+ // Max segment size is 2^16 == SAL_MAX_UINT16
+ sal_uInt64 nDataWritten = 0;
+ ISC_STATUS aErr;
+ while (xBytes.getLength() - nDataWritten > 0)
+ {
+ sal_uInt64 nDataRemaining = xBytes.getLength() - nDataWritten;
+ sal_uInt16 nWriteSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
+ aErr = isc_put_segment(m_statusVector,
+ &aBlobHandle,
+ nWriteSize,
+ (const char*) xBytes.getConstArray() + nDataWritten);
+ nDataWritten += nWriteSize;
+
+ if (aErr)
+ break;
+ }
+
+ // We need to make sure we close the Blob even if their are errors, hence evaluate
+ // errors after closing.
+ closeBlobAfterWriting(aBlobHandle);
+
+ if (aErr)
+ {
+ evaluateStatusVector(m_statusVector,
+ "isc_put_segment failed",
+ *this);
+ assert(false);
+ }
+
+ setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB);
}
// -------------------------------------------------------------------------
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.hxx b/connectivity/source/drivers/firebird/PreparedStatement.hxx
index d052b7e..ea1bb05 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.hxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.hxx
@@ -87,6 +87,14 @@ namespace connectivity
void ensurePrepared()
throw(::com::sun::star::sdbc::SQLException,
::com::sun::star::uno::RuntimeException);
+ /**
+ * Assumes that all necessary mutexes have been taken.
+ */
+ void openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId);
+ /**
+ * Assumes that all necessary mutexes have been taken.
+ */
+ void closeBlobAfterWriting(isc_blob_handle& rBlobHandle);
protected:
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,
More information about the Libreoffice-commits
mailing list