build fix
[LibreOffice.git] / connectivity / source / drivers / firebird / Blob.cxx
blob7a7481bb136725b89c74453e362cbb0a545c6acc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "Blob.hxx"
11 #include "Connection.hxx"
12 #include "Util.hxx"
14 #include <com/sun/star/lang/IllegalArgumentException.hpp>
15 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
16 #include <connectivity/dbexception.hxx>
17 #include <cppuhelper/exc_hlp.hxx>
19 using namespace ::connectivity::firebird;
21 using namespace ::cppu;
22 using namespace ::osl;
24 using namespace ::com::sun::star;
25 using namespace ::com::sun::star::io;
26 using namespace ::com::sun::star::sdbc;
27 using namespace ::com::sun::star::uno;
29 Blob::Blob(isc_db_handle* pDatabaseHandle,
30 isc_tr_handle* pTransactionHandle,
31 ISC_QUAD& aBlobID):
32 Blob_BASE(m_aMutex),
33 m_pDatabaseHandle(pDatabaseHandle),
34 m_pTransactionHandle(pTransactionHandle),
35 m_blobID(aBlobID),
36 #if SAL_TYPES_SIZEOFPOINTER == 8
37 m_blobHandle(0),
38 #else
39 m_blobHandle(nullptr),
40 #endif
41 m_bBlobOpened(false),
42 m_nBlobLength(0),
43 m_nBlobPosition(0)
47 void Blob::ensureBlobIsOpened()
48 throw(SQLException)
50 MutexGuard aGuard(m_aMutex);
52 if (m_bBlobOpened)
53 return;
55 ISC_STATUS aErr;
56 aErr = isc_open_blob2(m_statusVector,
57 m_pDatabaseHandle,
58 m_pTransactionHandle,
59 &m_blobHandle,
60 &m_blobID,
62 nullptr);
64 if (aErr)
65 evaluateStatusVector(m_statusVector, "isc_open_blob2", *this);
67 m_bBlobOpened = true;
68 m_nBlobPosition = 0;
70 char aBlobItems[] = {
71 isc_info_blob_total_length
73 char aResultBuffer[20];
75 isc_blob_info(m_statusVector,
76 &m_blobHandle,
77 sizeof(aBlobItems),
78 aBlobItems,
79 sizeof(aResultBuffer),
80 aResultBuffer);
82 if (aErr)
83 evaluateStatusVector(m_statusVector, "isc_blob_info", *this);
85 if (*aResultBuffer == isc_info_blob_total_length)
87 short aResultLength = (short) isc_vax_integer(aResultBuffer+1, 2);
88 m_nBlobLength = isc_vax_integer(aResultBuffer+3, aResultLength);
90 else
92 assert(false);
96 void Blob::closeBlob()
97 throw (SQLException)
99 MutexGuard aGuard(m_aMutex);
101 if (m_bBlobOpened)
103 ISC_STATUS aErr;
104 aErr = isc_close_blob(m_statusVector,
105 &m_blobHandle);
106 if (aErr)
107 evaluateStatusVector(m_statusVector, "isc_close_blob", *this);
109 m_bBlobOpened = false;
110 #if SAL_TYPES_SIZEOFPOINTER == 8
111 m_blobHandle = 0;
112 #else
113 m_blobHandle = nullptr;
114 #endif
118 void SAL_CALL Blob::disposing()
122 closeBlob();
124 catch (SQLException &e)
126 // we cannot throw any exceptions here...
127 SAL_WARN("connectivity.firebird", "isc_close_blob failed\n" <<
128 e.Message);
129 assert(false);
131 Blob_BASE::disposing();
134 sal_Int64 SAL_CALL Blob::length()
135 throw(SQLException, RuntimeException, std::exception)
137 MutexGuard aGuard(m_aMutex);
138 checkDisposed(Blob_BASE::rBHelper.bDisposed);
139 ensureBlobIsOpened();
141 return m_nBlobLength;
144 uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 nPosition,
145 sal_Int32 nBytes)
146 throw(SQLException, RuntimeException, std::exception)
148 MutexGuard aGuard(m_aMutex);
149 checkDisposed(Blob_BASE::rBHelper.bDisposed);
150 ensureBlobIsOpened();
152 if (nPosition > m_nBlobLength)
153 throw lang::IllegalArgumentException("nPosition out of range", *this, 0);
154 // We only have to read as many bytes as are available, i.e. nPosition+nBytes
155 // can legally be greater than the total length, hence we don't bother to check.
157 if (nPosition > m_nBlobPosition)
159 // Resets to the beginning (we can't seek these blobs)
160 closeBlob();
161 ensureBlobIsOpened();
164 skipBytes(nPosition - m_nBlobPosition);
166 // Don't bother preallocating: readBytes does the appropriate calculations
167 // and reallocates for us.
168 uno::Sequence< sal_Int8 > aBytes;
169 readBytes(aBytes, nBytes);
170 return aBytes;
173 uno::Reference< XInputStream > SAL_CALL Blob::getBinaryStream()
174 throw(SQLException, RuntimeException, std::exception)
176 return this;
179 sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/,
180 sal_Int64 /*nStart*/)
181 throw(SQLException, RuntimeException, std::exception)
183 ::dbtools::throwFeatureNotImplementedSQLException("Blob::position", *this);
184 return 0;
187 sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
188 sal_Int64 /*aStart*/)
189 throw(SQLException, RuntimeException, std::exception)
191 ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this);
192 return 0;
195 // ---- XInputStream ----------------------------------------------------------
197 sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
198 sal_Int32 nBytes)
199 throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
201 MutexGuard aGuard(m_aMutex);
205 checkDisposed(Blob_BASE::rBHelper.bDisposed);
206 ensureBlobIsOpened();
208 catch (const NotConnectedException&)
210 throw;
212 catch (const BufferSizeExceededException&)
214 throw;
216 catch (const IOException&)
218 throw;
220 catch (const RuntimeException&)
222 throw;
224 catch (const Exception& e)
226 css::uno::Any a(cppu::getCaughtException());
227 throw css::lang::WrappedTargetRuntimeException(
228 "wrapped Exception " + e.Message,
229 css::uno::Reference<css::uno::XInterface>(), a);
232 // Ensure we have enough space for the amount of data we can actually read.
233 const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
234 const sal_Int32 nBytesToRead = nBytes < nBytesAvailable ? nBytes : nBytesAvailable;
236 if (rDataOut.getLength() < nBytesToRead)
237 rDataOut.realloc(nBytesToRead);
239 sal_Int32 nTotalBytesRead = 0;
240 ISC_STATUS aErr;
241 while (nTotalBytesRead < nBytesToRead)
243 sal_uInt16 nBytesRead = 0;
244 sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
245 sal_uInt16 nReadSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
246 aErr = isc_get_segment(m_statusVector,
247 &m_blobHandle,
248 &nBytesRead,
249 nReadSize,
250 reinterpret_cast<char*>(rDataOut.getArray()) + nTotalBytesRead);
251 if (aErr && IndicatesError(m_statusVector))
253 OUString sError(StatusVectorToString(m_statusVector, "isc_get_segment"));
254 throw IOException(sError, *this);
256 nTotalBytesRead += nBytesRead;
257 m_nBlobPosition += nBytesRead;
260 return nTotalBytesRead;
263 sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
264 sal_Int32 nMaximumBytes)
265 throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
267 // We don't have any way of verifying how many bytes are immediately available,
268 // hence we just pass through direct to readBytes
269 // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
270 return readBytes(rDataOut, nMaximumBytes);
273 void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
274 throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
276 // There is no way of directly skipping, hence we have to pretend to skip
277 // by reading & discarding the data.
278 uno::Sequence< sal_Int8 > aBytes;
279 readBytes(aBytes, nBytesToSkip);
282 sal_Int32 SAL_CALL Blob::available()
283 throw (NotConnectedException, IOException, RuntimeException, std::exception)
285 MutexGuard aGuard(m_aMutex);
289 checkDisposed(Blob_BASE::rBHelper.bDisposed);
290 ensureBlobIsOpened();
292 catch (const NotConnectedException&)
294 throw;
296 catch (const IOException&)
298 throw;
300 catch (const RuntimeException&)
302 throw;
304 catch (const Exception& e)
306 css::uno::Any a(cppu::getCaughtException());
307 throw css::lang::WrappedTargetRuntimeException(
308 "wrapped Exception " + e.Message,
309 css::uno::Reference<css::uno::XInterface>(), a);
312 return m_nBlobLength - m_nBlobPosition;
315 void SAL_CALL Blob::closeInput()
316 throw(NotConnectedException, IOException, RuntimeException, std::exception)
320 closeBlob();
322 catch (const NotConnectedException&)
324 throw;
326 catch (const IOException&)
328 throw;
330 catch (const RuntimeException&)
332 throw;
334 catch (const Exception& e)
336 css::uno::Any a(cppu::getCaughtException());
337 throw css::lang::WrappedTargetRuntimeException(
338 "wrapped Exception " + e.Message,
339 css::uno::Reference<css::uno::XInterface>(), a);
343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */