bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / odbc / OResultSet.cxx
blob9e6bb3d91887c945a72a9feee1158957e982e39b
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <odbc/OResultSet.hxx>
21 #include <odbc/OTools.hxx>
22 #include <odbc/OResultSetMetaData.hxx>
23 #include <com/sun/star/sdbc/DataType.hpp>
24 #include <com/sun/star/beans/PropertyAttribute.hpp>
25 #include <com/sun/star/beans/PropertyVetoException.hpp>
26 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
27 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
28 #include <com/sun/star/sdbc/ResultSetType.hpp>
29 #include <comphelper/property.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <cppuhelper/typeprovider.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <comphelper/types.hxx>
34 #include <connectivity/dbtools.hxx>
35 #include <connectivity/dbexception.hxx>
36 #include <o3tl/safeint.hxx>
37 #include <sal/log.hxx>
39 using namespace ::comphelper;
40 using namespace connectivity;
41 using namespace connectivity::odbc;
42 using namespace cppu;
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::lang;
45 using namespace com::sun::star::beans;
46 using namespace com::sun::star::sdbc;
47 using namespace com::sun::star::sdbcx;
48 using namespace com::sun::star::container;
49 using namespace com::sun::star::io;
50 using namespace com::sun::star::util;
52 #define ODBC_SQL_NOT_DEFINED 99UL
53 static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_OFF, "ODBC_SQL_NOT_DEFINED must be unique");
54 static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_ON, "ODBC_SQL_NOT_DEFINED must be unique");
55 static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_FIXED, "ODBC_SQL_NOT_DEFINED must be unique");
56 static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_VARIABLE, "ODBC_SQL_NOT_DEFINED must be unique");
58 namespace
60 const SQLLEN nMaxBookmarkLen = 20;
64 // IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.OResultSet","com.sun.star.sdbc.ResultSet");
65 OUString SAL_CALL OResultSet::getImplementationName( )
67 return "com.sun.star.sdbcx.odbc.ResultSet";
70 Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames( )
72 return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" };
75 sal_Bool SAL_CALL OResultSet::supportsService( const OUString& _rServiceName )
77 return cppu::supportsService(this, _rServiceName);
81 OResultSet::OResultSet(SQLHANDLE _pStatementHandle ,OStatement_Base* pStmt) : OResultSet_BASE(m_aMutex)
82 ,OPropertySetHelper(OResultSet_BASE::rBHelper)
83 ,m_bFetchDataInOrder(true)
84 ,m_aStatementHandle(_pStatementHandle)
85 ,m_aConnectionHandle(pStmt->getConnectionHandle())
86 ,m_pStatement(pStmt)
87 ,m_xStatement(*pStmt)
88 ,m_nTextEncoding(pStmt->getOwnConnection()->getTextEncoding())
89 ,m_nRowPos(0)
90 ,m_nUseBookmarks(ODBC_SQL_NOT_DEFINED)
91 ,m_nCurrentFetchState(0)
92 ,m_bWasNull(true)
93 ,m_bEOF(true)
94 ,m_bRowInserted(false)
95 ,m_bRowDeleted(false)
96 ,m_bUseFetchScroll(false)
98 osl_atomic_increment( &m_refCount );
99 try
101 m_pRowStatusArray.reset( new SQLUSMALLINT[1] ); // the default value
102 setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray.get());
104 catch(const Exception&)
105 { // we don't want our result destroy here
110 SQLULEN nCurType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE);
111 SQLUINTEGER nValueLen = m_pStatement->getCursorProperties(nCurType,false);
112 if( (nValueLen & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS ||
113 (nValueLen & SQL_CA2_CRC_EXACT) != SQL_CA2_CRC_EXACT)
114 m_pSkipDeletedSet.reset( new OSkipDeletedSet(this) );
116 catch(const Exception&)
117 { // we don't want our result destroy here
121 SQLUINTEGER nValueLen = 0;
122 // Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441%28v=vs.85%29.aspx
123 // LibreOffice ODBC binds columns only on update, so we don't care about SQL_GD_ANY_COLUMN / SQL_GD_BOUND
124 // TODO: maybe a problem if a column is updated, then an earlier column fetched?
125 // an updated column is bound...
126 // TODO: aren't we assuming SQL_GD_OUTPUT_PARAMS?
127 // If yes, we should at least OSL_ENSURE it,
128 // even better throw an exception any OUT parameter registration if !SQL_GD_OUTPUT_PARAMS.
129 // If !SQL_GD_ANY_ORDER, cache the whole row so that callers can access columns in any order.
130 // In other words, isolate them from ODBC restrictions.
131 // TODO: we assume SQL_GD_BLOCK, unless fetchSize is 1
132 OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_GETDATA_EXTENSIONS,nValueLen,nullptr);
133 m_bFetchDataInOrder = ((SQL_GD_ANY_ORDER & nValueLen) != SQL_GD_ANY_ORDER);
135 catch(const Exception&)
137 m_bFetchDataInOrder = true;
141 // TODO: this does *not* do what it appears.
142 // We use SQLFetchScroll unconditionally in several places
143 // the *only* difference this makes is whether ::next() uses SQLFetchScroll or SQLFetch
144 // so this test seems pointless
145 if ( getOdbcFunction(ODBC3SQLFunctionId::GetFunctions) )
147 SQLUSMALLINT nSupported = 0;
148 m_bUseFetchScroll = ( N3SQLGetFunctions(m_aConnectionHandle,SQL_API_SQLFETCHSCROLL,&nSupported) == SQL_SUCCESS && nSupported == 1 );
151 catch(const Exception&)
153 m_bUseFetchScroll = false;
156 osl_atomic_decrement( &m_refCount );
159 OResultSet::~OResultSet()
163 void OResultSet::construct()
165 osl_atomic_increment( &m_refCount );
166 allocBuffer();
167 osl_atomic_decrement( &m_refCount );
170 void OResultSet::disposing()
172 N3SQLCloseCursor(m_aStatementHandle);
173 OPropertySetHelper::disposing();
175 ::osl::MutexGuard aGuard(m_aMutex);
176 releaseBuffer();
178 setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, nullptr);
179 m_xStatement.clear();
180 m_xMetaData.clear();
183 SQLRETURN OResultSet::unbind(bool _bUnbindHandle)
185 SQLRETURN nRet = 0;
186 if ( _bUnbindHandle )
187 nRet = N3SQLFreeStmt(m_aStatementHandle,SQL_UNBIND);
189 if ( !m_aBindVector.empty() )
191 for(auto& [rPtrAddr, rType] : m_aBindVector)
193 switch (rType)
195 case DataType::CHAR:
196 case DataType::VARCHAR:
197 delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr));
198 break;
199 case DataType::BIGINT:
200 delete static_cast< sal_Int64* >(reinterpret_cast< void * >(rPtrAddr));
201 break;
202 case DataType::DECIMAL:
203 case DataType::NUMERIC:
204 delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr));
205 break;
206 case DataType::REAL:
207 case DataType::DOUBLE:
208 delete static_cast< double* >(reinterpret_cast< void * >(rPtrAddr));
209 break;
210 case DataType::LONGVARCHAR:
211 case DataType::CLOB:
212 delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr));
213 break;
214 case DataType::LONGVARBINARY:
215 case DataType::BLOB:
216 delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr));
217 break;
218 case DataType::DATE:
219 delete static_cast< DATE_STRUCT* >(reinterpret_cast< void * >(rPtrAddr));
220 break;
221 case DataType::TIME:
222 delete static_cast< TIME_STRUCT* >(reinterpret_cast< void * >(rPtrAddr));
223 break;
224 case DataType::TIMESTAMP:
225 delete static_cast< TIMESTAMP_STRUCT* >(reinterpret_cast< void * >(rPtrAddr));
226 break;
227 case DataType::BIT:
228 case DataType::TINYINT:
229 delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr));
230 break;
231 case DataType::SMALLINT:
232 delete static_cast< sal_Int16* >(reinterpret_cast< void * >(rPtrAddr));
233 break;
234 case DataType::INTEGER:
235 delete static_cast< sal_Int32* >(reinterpret_cast< void * >(rPtrAddr));
236 break;
237 case DataType::FLOAT:
238 delete static_cast< float* >(reinterpret_cast< void * >(rPtrAddr));
239 break;
240 case DataType::BINARY:
241 case DataType::VARBINARY:
242 delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr));
243 break;
246 m_aBindVector.clear();
248 return nRet;
251 TVoidPtr OResultSet::allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex)
253 TVoidPtr aPair;
254 switch (_nType)
256 case DataType::CHAR:
257 case DataType::VARCHAR:
258 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType);
259 break;
260 case DataType::BIGINT:
261 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int64(0)),_nType);
262 break;
263 case DataType::DECIMAL:
264 case DataType::NUMERIC:
265 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType);
266 break;
267 case DataType::REAL:
268 case DataType::DOUBLE:
269 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new double(0.0)),_nType);
270 break;
271 case DataType::LONGVARCHAR:
272 case DataType::CLOB:
273 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding
274 break;
275 case DataType::LONGVARBINARY:
276 case DataType::BLOB:
277 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding
278 break;
279 case DataType::DATE:
280 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new DATE_STRUCT),_nType);
281 break;
282 case DataType::TIME:
283 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIME_STRUCT),_nType);
284 break;
285 case DataType::TIMESTAMP:
286 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIMESTAMP_STRUCT),_nType);
287 break;
288 case DataType::BIT:
289 case DataType::TINYINT:
290 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8(0)),_nType);
291 break;
292 case DataType::SMALLINT:
293 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int16(0)),_nType);
294 break;
295 case DataType::INTEGER:
296 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int32(0)),_nType);
297 break;
298 case DataType::FLOAT:
299 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new float(0)),_nType);
300 break;
301 case DataType::BINARY:
302 case DataType::VARBINARY:
303 aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8[m_aRow[_nColumnIndex].getSequence().getLength()]),_nType);
304 break;
305 default:
306 SAL_WARN( "connectivity.odbc", "Unknown type");
307 aPair = TVoidPtr(0,_nType);
309 return aPair;
312 void OResultSet::allocBuffer()
314 Reference< XResultSetMetaData > xMeta = getMetaData();
315 sal_Int32 nLen = xMeta->getColumnCount();
317 m_aBindVector.reserve(nLen);
318 m_aRow.resize(nLen+1);
320 m_aRow[0].setTypeKind(DataType::VARBINARY);
321 m_aRow[0].setBound( false );
323 for(sal_Int32 i = 1;i<=nLen;++i)
325 sal_Int32 nType = xMeta->getColumnType(i);
326 m_aRow[i].setTypeKind( nType );
327 m_aRow[i].setBound( false );
329 m_aLengthVector.resize(nLen + 1);
332 void OResultSet::releaseBuffer()
334 unbind(false);
335 m_aLengthVector.clear();
338 Any SAL_CALL OResultSet::queryInterface( const Type & rType )
340 Any aRet = OPropertySetHelper::queryInterface(rType);
341 return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType);
344 Sequence< Type > SAL_CALL OResultSet::getTypes( )
346 OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
347 cppu::UnoType<css::beans::XFastPropertySet>::get(),
348 cppu::UnoType<css::beans::XPropertySet>::get());
350 return ::comphelper::concatSequences(aTypes.getTypes(),OResultSet_BASE::getTypes());
354 sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName )
356 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
359 ::osl::MutexGuard aGuard( m_aMutex );
361 Reference< XResultSetMetaData > xMeta = getMetaData();
362 sal_Int32 nLen = xMeta->getColumnCount();
363 sal_Int32 i = 1;
364 for(;i<=nLen;++i)
366 if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
367 columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
368 return i;
371 ::dbtools::throwInvalidColumnException( columnName, *this );
372 assert(false);
373 return 0; // Never reached
376 void OResultSet::ensureCacheForColumn(sal_Int32 columnIndex)
378 SAL_INFO( "connectivity.odbc", "odbc lionel@mamane.lu OResultSet::ensureCacheForColumn" );
380 assert(columnIndex >= 0);
382 const TDataRow::size_type oldCacheSize = m_aRow.size();
383 const TDataRow::size_type uColumnIndex = static_cast<TDataRow::size_type>(columnIndex);
385 if (oldCacheSize > uColumnIndex)
386 // nothing to do
387 return;
389 m_aRow.resize(columnIndex + 1);
390 TDataRow::iterator i (m_aRow.begin() + oldCacheSize);
391 const TDataRow::const_iterator end(m_aRow.end());
392 for (; i != end; ++i)
394 i->setBound(false);
397 void OResultSet::invalidateCache()
399 for(auto& rItem : m_aRow)
401 rItem.setBound(false);
405 Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
407 ::osl::MutexGuard aGuard( m_aMutex );
408 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
410 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
412 return nullptr;
415 Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
417 ::osl::MutexGuard aGuard( m_aMutex );
418 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
420 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
422 return nullptr;
425 template < typename T > T OResultSet::impl_getValue( const sal_Int32 _nColumnIndex, SQLSMALLINT nType )
427 T val;
429 OTools::getValue(m_pStatement->getOwnConnection(), m_aStatementHandle, _nColumnIndex, nType, m_bWasNull, **this, &val, sizeof(val));
431 return val;
434 // this function exists for the implicit conversion to sal_Bool (compared to a direct call to impl_getValue)
435 bool OResultSet::impl_getBoolean( sal_Int32 columnIndex )
437 return impl_getValue<sal_Int8>(columnIndex, SQL_C_BIT);
440 template < typename T > T OResultSet::getValue( sal_Int32 columnIndex )
442 ::osl::MutexGuard aGuard( m_aMutex );
443 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
444 fillColumn(columnIndex);
445 m_bWasNull = m_aRow[columnIndex].isNull();
446 return m_aRow[columnIndex];
448 sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex )
450 return getValue<bool>( columnIndex );
453 sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex )
455 return getValue<sal_Int8>( columnIndex );
459 Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex )
461 ::osl::MutexGuard aGuard( m_aMutex );
462 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
463 fillColumn(columnIndex);
464 m_bWasNull = m_aRow[columnIndex].isNull();
466 Sequence< sal_Int8 > nRet;
467 switch(m_aRow[columnIndex].getTypeKind())
469 case DataType::BINARY:
470 case DataType::VARBINARY:
471 case DataType::LONGVARBINARY:
472 nRet = m_aRow[columnIndex];
473 break;
474 default:
476 OUString const & sRet = m_aRow[columnIndex].getString();
477 nRet = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(sRet.getStr()),sizeof(sal_Unicode)*sRet.getLength());
480 return nRet;
482 Sequence< sal_Int8 > OResultSet::impl_getBytes( sal_Int32 columnIndex )
484 const SWORD nColumnType = impl_getColumnType_nothrow(columnIndex);
486 switch(nColumnType)
488 case SQL_WVARCHAR:
489 case SQL_WCHAR:
490 case SQL_WLONGVARCHAR:
491 case SQL_VARCHAR:
492 case SQL_CHAR:
493 case SQL_LONGVARCHAR:
495 OUString const & aRet = OTools::getStringValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,nColumnType,m_bWasNull,**this,m_nTextEncoding);
496 return Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),sizeof(sal_Unicode)*aRet.getLength());
498 default:
499 return OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this);
503 Date OResultSet::impl_getDate( sal_Int32 columnIndex )
505 DATE_STRUCT aDate = impl_getValue< DATE_STRUCT> ( columnIndex,
506 m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_DATE : SQL_C_TYPE_DATE );
508 return Date(aDate.day, aDate.month, aDate.year);
511 Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex )
513 return getValue<Date>( columnIndex );
517 double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex )
519 return getValue<double>( columnIndex );
523 float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex )
525 return getValue<float>( columnIndex );
528 sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex )
530 return getValue<sal_Int16>( columnIndex );
533 sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex )
535 return getValue<sal_Int32>( columnIndex );
538 sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 columnIndex )
540 return getValue<sal_Int64>( columnIndex );
542 sal_Int64 OResultSet::impl_getLong( sal_Int32 columnIndex )
546 return impl_getValue<sal_Int64>(columnIndex, SQL_C_SBIGINT);
548 catch(const SQLException&)
550 return getString(columnIndex).toInt64();
554 sal_Int32 SAL_CALL OResultSet::getRow( )
556 ::osl::MutexGuard aGuard( m_aMutex );
557 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
559 return m_pSkipDeletedSet ? m_pSkipDeletedSet->getMappedPosition(getDriverPos()) : getDriverPos();
562 Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
564 ::osl::MutexGuard aGuard( m_aMutex );
565 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
568 if(!m_xMetaData.is())
569 m_xMetaData = new OResultSetMetaData(m_pStatement->getOwnConnection(),m_aStatementHandle);
570 return m_xMetaData;
573 Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ )
575 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this );
576 return nullptr;
580 Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ )
582 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this );
583 return nullptr;
586 Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ )
588 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this );
589 return nullptr;
593 Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ )
595 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this );
596 return nullptr;
600 Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
602 return getValue<ORowSetValue>( columnIndex ).makeAny();
605 OUString OResultSet::impl_getString( sal_Int32 columnIndex )
607 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
608 const SWORD nColumnType = impl_getColumnType_nothrow(columnIndex);
609 return OTools::getStringValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,nColumnType,m_bWasNull,**this,m_nTextEncoding);
611 OUString OResultSet::getString( sal_Int32 columnIndex )
613 return getValue<OUString>( columnIndex );
616 Time OResultSet::impl_getTime( sal_Int32 columnIndex )
618 TIME_STRUCT aTime = impl_getValue< TIME_STRUCT > ( columnIndex,
619 m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_TIME : SQL_C_TYPE_TIME );
621 return Time(0, aTime.second,aTime.minute,aTime.hour, false);
623 Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex )
625 return getValue<Time>( columnIndex );
628 DateTime OResultSet::impl_getTimestamp( sal_Int32 columnIndex )
630 TIMESTAMP_STRUCT aTime = impl_getValue< TIMESTAMP_STRUCT > ( columnIndex,
631 m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_TIMESTAMP : SQL_C_TYPE_TIMESTAMP );
633 return DateTime(aTime.fraction,
634 aTime.second,
635 aTime.minute,
636 aTime.hour,
637 aTime.day,
638 aTime.month,
639 aTime.year,
640 false);
642 DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex )
644 return getValue<DateTime>( columnIndex );
647 sal_Bool SAL_CALL OResultSet::isBeforeFirst( )
649 ::osl::MutexGuard aGuard( m_aMutex );
650 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
651 return m_nRowPos == 0;
654 sal_Bool SAL_CALL OResultSet::isAfterLast( )
656 ::osl::MutexGuard aGuard( m_aMutex );
657 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
659 return m_nRowPos != 0 && m_nCurrentFetchState == SQL_NO_DATA;
662 sal_Bool SAL_CALL OResultSet::isFirst( )
664 ::osl::MutexGuard aGuard( m_aMutex );
665 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
667 return m_nRowPos == 1;
670 sal_Bool SAL_CALL OResultSet::isLast( )
672 ::osl::MutexGuard aGuard( m_aMutex );
673 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
676 return m_bEOF && m_nCurrentFetchState != SQL_NO_DATA;
679 void SAL_CALL OResultSet::beforeFirst( )
681 ::osl::MutexGuard aGuard( m_aMutex );
682 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
685 if(first())
686 previous();
687 m_nCurrentFetchState = SQL_SUCCESS;
690 void SAL_CALL OResultSet::afterLast( )
692 ::osl::MutexGuard aGuard( m_aMutex );
693 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
695 if(last())
696 next();
697 m_bEOF = true;
701 void SAL_CALL OResultSet::close( )
704 ::osl::MutexGuard aGuard( m_aMutex );
705 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
708 dispose();
712 sal_Bool SAL_CALL OResultSet::first( )
714 return moveImpl(IResultSetHelper::FIRST,0);
718 sal_Bool SAL_CALL OResultSet::last( )
720 return moveImpl(IResultSetHelper::LAST,0);
723 sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row )
725 return moveImpl(IResultSetHelper::ABSOLUTE1,row);
728 sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row )
730 return moveImpl(IResultSetHelper::RELATIVE1,row);
733 sal_Bool SAL_CALL OResultSet::previous( )
735 return moveImpl(IResultSetHelper::PRIOR,0);
738 Reference< XInterface > SAL_CALL OResultSet::getStatement( )
740 ::osl::MutexGuard aGuard( m_aMutex );
741 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
742 return m_xStatement;
746 sal_Bool SAL_CALL OResultSet::rowDeleted()
748 ::osl::MutexGuard aGuard( m_aMutex );
749 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
751 bool bRet = m_bRowDeleted;
752 m_bRowDeleted = false;
754 return bRet;
757 sal_Bool SAL_CALL OResultSet::rowInserted( )
759 ::osl::MutexGuard aGuard( m_aMutex );
760 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
762 bool bInserted = m_bRowInserted;
763 m_bRowInserted = false;
765 return bInserted;
768 sal_Bool SAL_CALL OResultSet::rowUpdated( )
770 ::osl::MutexGuard aGuard( m_aMutex );
771 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
774 return m_pRowStatusArray[0] == SQL_ROW_UPDATED;
778 sal_Bool SAL_CALL OResultSet::next( )
780 return moveImpl(IResultSetHelper::NEXT,1);
784 sal_Bool SAL_CALL OResultSet::wasNull( )
786 ::osl::MutexGuard aGuard( m_aMutex );
787 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
789 return m_bWasNull;
793 void SAL_CALL OResultSet::cancel( )
795 ::osl::MutexGuard aGuard( m_aMutex );
796 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
799 N3SQLCancel(m_aStatementHandle);
802 void SAL_CALL OResultSet::clearWarnings( )
806 Any SAL_CALL OResultSet::getWarnings( )
808 return Any();
811 void SAL_CALL OResultSet::insertRow( )
813 ::osl::MutexGuard aGuard( m_aMutex );
814 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
817 SQLLEN nRealLen = 0;
818 Sequence<sal_Int8> aBookmark(nMaxBookmarkLen);
819 static_assert(o3tl::make_unsigned(nMaxBookmarkLen) >= sizeof(SQLLEN), "must be larger");
821 SQLRETURN nRet = N3SQLBindCol(m_aStatementHandle,
823 SQL_C_VARBOOKMARK,
824 aBookmark.getArray(),
825 nMaxBookmarkLen,
826 &nRealLen
829 bool bPositionByBookmark = ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations ) );
830 if ( bPositionByBookmark )
832 nRet = N3SQLBulkOperations( m_aStatementHandle, SQL_ADD );
833 fillNeededData( nRet );
835 else
837 if(isBeforeFirst())
838 next(); // must be done
839 nRet = N3SQLSetPos( m_aStatementHandle, 1, SQL_ADD, SQL_LOCK_NO_CHANGE );
840 fillNeededData( nRet );
842 aBookmark.realloc(nRealLen);
845 OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
847 catch(const SQLException&)
849 nRet = unbind();
850 throw;
853 nRet = unbind();
854 OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
856 if ( bPositionByBookmark )
858 setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray()));
860 nRet = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,0);
862 else
863 nRet = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,0); // OJ 06.03.2004
864 // sometimes we got an error but we are not interested in anymore #106047# OJ
865 // OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
867 if(m_pSkipDeletedSet)
869 if(moveToBookmark(makeAny(aBookmark)))
871 sal_Int32 nRowPos = getDriverPos();
872 if ( -1 == m_nRowPos )
874 nRowPos = m_aPosToBookmarks.size() + 1;
876 if ( nRowPos == m_nRowPos )
877 ++nRowPos;
878 m_nRowPos = nRowPos;
879 m_pSkipDeletedSet->insertNewPosition(nRowPos);
880 m_aPosToBookmarks[aBookmark] = nRowPos;
883 m_bRowInserted = true;
887 void SAL_CALL OResultSet::updateRow( )
889 ::osl::MutexGuard aGuard( m_aMutex );
890 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
892 SQLRETURN nRet;
896 bool bPositionByBookmark = ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations ) );
897 if ( bPositionByBookmark )
899 getBookmark();
900 assert(m_aRow[0].isBound());
901 Sequence<sal_Int8> aBookmark(m_aRow[0].getSequence());
902 SQLLEN nRealLen = aBookmark.getLength();
903 nRet = N3SQLBindCol(m_aStatementHandle,
905 SQL_C_VARBOOKMARK,
906 aBookmark.getArray(),
907 aBookmark.getLength(),
908 &nRealLen
910 OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
911 nRet = N3SQLBulkOperations(m_aStatementHandle, SQL_UPDATE_BY_BOOKMARK);
912 fillNeededData(nRet);
913 // the driver should not have touched this
914 // (neither the contents of aBookmark FWIW)
915 assert(nRealLen == aBookmark.getLength());
917 else
919 nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_UPDATE,SQL_LOCK_NO_CHANGE);
920 fillNeededData(nRet);
922 OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
923 // unbind all columns so we can fetch all columns again with SQLGetData
924 // (and also so that our buffers don't clobber anything, and
925 // so that a subsequent fetch does not overwrite m_aRow[0])
926 invalidateCache();
927 nRet = unbind();
928 OSL_ENSURE(nRet == SQL_SUCCESS,"ODBC insert could not unbind the columns after success");
930 catch(...)
932 // unbind all columns so that a subsequent fetch does not overwrite m_aRow[0]
933 nRet = unbind();
934 OSL_ENSURE(nRet == SQL_SUCCESS,"ODBC insert could not unbind the columns after failure");
935 throw;
939 void SAL_CALL OResultSet::deleteRow( )
941 SQLRETURN nRet = SQL_SUCCESS;
942 sal_Int32 nPos = getDriverPos();
943 nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_DELETE,SQL_LOCK_NO_CHANGE);
944 OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
946 m_bRowDeleted = ( m_pRowStatusArray[0] == SQL_ROW_DELETED );
947 if ( m_bRowDeleted )
949 TBookmarkPosMap::iterator aIter = std::find_if(m_aPosToBookmarks.begin(), m_aPosToBookmarks.end(),
950 [&nPos](const TBookmarkPosMap::value_type& rEntry) { return rEntry.second == nPos; });
951 if (aIter != m_aPosToBookmarks.end())
952 m_aPosToBookmarks.erase(aIter);
954 if ( m_pSkipDeletedSet )
955 m_pSkipDeletedSet->deletePosition(nPos);
959 void SAL_CALL OResultSet::cancelRowUpdates( )
964 void SAL_CALL OResultSet::moveToInsertRow( )
966 ::osl::MutexGuard aGuard( m_aMutex );
967 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
970 invalidateCache();
971 // first unbound all columns
972 OSL_VERIFY( unbind() == SQL_SUCCESS );
973 // SQLRETURN nRet = N3SQLSetStmtAttr(m_aStatementHandle,SQL_ATTR_ROW_ARRAY_SIZE ,(SQLPOINTER)1,SQL_IS_INTEGER);
977 void SAL_CALL OResultSet::moveToCurrentRow( )
979 invalidateCache();
982 void OResultSet::updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void const * _pValue)
984 ::osl::MutexGuard aGuard( m_aMutex );
985 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
987 m_aBindVector.push_back(allocBindColumn(OTools::MapOdbcType2Jdbc(_nType),columnIndex));
988 void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first);
989 OSL_ENSURE(pData != nullptr,"Data for update is NULL!");
990 OTools::bindValue( m_pStatement->getOwnConnection(),
991 m_aStatementHandle,
992 columnIndex,
993 _nType,
995 _pValue,
996 pData,
997 &m_aLengthVector[columnIndex],
998 **this,
999 m_nTextEncoding,
1000 m_pStatement->getOwnConnection()->useOldDateFormat());
1003 void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex )
1005 ::osl::MutexGuard aGuard( m_aMutex );
1006 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1008 m_aBindVector.push_back(allocBindColumn(DataType::CHAR,columnIndex));
1009 void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first);
1010 OTools::bindValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_CHAR,0,nullptr,pData,&m_aLengthVector[columnIndex],**this,m_nTextEncoding,m_pStatement->getOwnConnection()->useOldDateFormat());
1014 void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
1016 updateValue(columnIndex,SQL_BIT,&x);
1019 void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
1021 updateValue(columnIndex,SQL_CHAR,&x);
1025 void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
1027 updateValue(columnIndex,SQL_TINYINT,&x);
1030 void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
1032 updateValue(columnIndex,SQL_INTEGER,&x);
1035 void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ )
1037 ::dbtools::throwFunctionNotSupportedSQLException( "XRowUpdate::updateLong", *this );
1040 void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x )
1042 updateValue(columnIndex,SQL_REAL,&x);
1046 void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x )
1048 updateValue(columnIndex,SQL_DOUBLE,&x);
1051 void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
1053 sal_Int32 nType = m_aRow[columnIndex].getTypeKind();
1054 SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType);
1055 m_aRow[columnIndex] = x;
1056 m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarchar will be recognized by fillNeededData
1057 m_aRow[columnIndex].setBound(true);
1058 updateValue(columnIndex,nOdbcType, &x);
1061 void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
1063 sal_Int32 nType = m_aRow[columnIndex].getTypeKind();
1064 SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType);
1065 m_aRow[columnIndex] = x;
1066 m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarbinary will be recognized by fillNeededData
1067 m_aRow[columnIndex].setBound(true);
1068 updateValue(columnIndex,nOdbcType, &x);
1071 void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const Date& x )
1073 DATE_STRUCT aVal = OTools::DateToOdbcDate(x);
1074 updateValue(columnIndex,SQL_DATE,&aVal);
1078 void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
1080 TIME_STRUCT aVal = OTools::TimeToOdbcTime(x);
1081 updateValue(columnIndex,SQL_TIME,&aVal);
1085 void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const DateTime& x )
1087 TIMESTAMP_STRUCT aVal = OTools::DateTimeToTimestamp(x);
1088 updateValue(columnIndex,SQL_TIMESTAMP,&aVal);
1092 void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< XInputStream >& x, sal_Int32 length )
1094 if(!x.is())
1095 ::dbtools::throwFunctionSequenceException(*this);
1097 Sequence<sal_Int8> aSeq;
1098 x->readBytes(aSeq,length);
1099 updateBytes(columnIndex,aSeq);
1102 void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< XInputStream >& x, sal_Int32 length )
1104 updateBinaryStream(columnIndex,x,length);
1107 void SAL_CALL OResultSet::refreshRow( )
1109 ::osl::MutexGuard aGuard( m_aMutex );
1110 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1113 // SQLRETURN nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_REFRESH,SQL_LOCK_NO_CHANGE);
1114 m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,0);
1115 OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
1118 void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x )
1120 if (!::dbtools::implUpdateObject(this, columnIndex, x))
1121 throw SQLException();
1125 void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
1127 if (!::dbtools::implUpdateObject(this, columnIndex, x))
1128 throw SQLException();
1131 // XRowLocate
1132 Any SAL_CALL OResultSet::getBookmark( )
1134 fillColumn(0);
1135 if(m_aRow[0].isNull())
1136 throw SQLException();
1137 return m_aRow[0].makeAny();
1139 Sequence<sal_Int8> OResultSet::impl_getBookmark( )
1141 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1143 TBookmarkPosMap::const_iterator aFind = std::find_if(m_aPosToBookmarks.begin(),m_aPosToBookmarks.end(),
1144 [this] (const TBookmarkPosMap::value_type& bookmarkPos) {
1145 return bookmarkPos.second == m_nRowPos;
1148 if ( aFind == m_aPosToBookmarks.end() )
1150 if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED )
1152 m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
1154 if(m_nUseBookmarks == SQL_UB_OFF)
1155 throw SQLException();
1157 Sequence<sal_Int8> bookmark = OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,0,SQL_C_VARBOOKMARK,m_bWasNull,**this);
1158 m_aPosToBookmarks[bookmark] = m_nRowPos;
1159 OSL_ENSURE(bookmark.hasElements(),"Invalid bookmark from length 0!");
1160 return bookmark;
1162 else
1164 return aFind->first;
1168 sal_Bool SAL_CALL OResultSet::moveToBookmark( const Any& bookmark )
1170 ::osl::MutexGuard aGuard( m_aMutex );
1171 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1173 invalidateCache();
1174 Sequence<sal_Int8> aBookmark;
1175 bookmark >>= aBookmark;
1176 OSL_ENSURE(aBookmark.hasElements(),"Invalid bookmark from length 0!");
1177 if(aBookmark.hasElements())
1179 SQLRETURN nReturn = setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray()));
1181 if ( SQL_INVALID_HANDLE != nReturn && SQL_ERROR != nReturn )
1183 m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,0);
1184 OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
1185 TBookmarkPosMap::const_iterator aFind = m_aPosToBookmarks.find(aBookmark);
1186 if(aFind != m_aPosToBookmarks.end())
1187 m_nRowPos = aFind->second;
1188 else
1189 m_nRowPos = -1;
1190 return m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
1193 return false;
1196 sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
1198 ::osl::MutexGuard aGuard( m_aMutex );
1199 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1202 invalidateCache();
1203 Sequence<sal_Int8> aBookmark;
1204 bookmark >>= aBookmark;
1205 setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray()));
1207 m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,rows);
1208 OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
1209 return m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
1212 sal_Int32 SAL_CALL OResultSet::compareBookmarks( const Any& lhs, const Any& rhs )
1214 ::osl::MutexGuard aGuard( m_aMutex );
1215 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1217 return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL;
1220 sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks( )
1222 return false;
1225 sal_Int32 SAL_CALL OResultSet::hashBookmark( const Any& /*bookmark*/ )
1227 ::dbtools::throwFunctionNotSupportedSQLException( "XRowLocate::hashBookmark", *this );
1228 return 0;
1231 // XDeleteRows
1232 Sequence< sal_Int32 > SAL_CALL OResultSet::deleteRows( const Sequence< Any >& rows )
1234 Sequence< sal_Int32 > aRet(rows.getLength());
1235 sal_Int32 *pRet = aRet.getArray();
1237 const Any *pBegin = rows.getConstArray();
1238 const Any *pEnd = pBegin + rows.getLength();
1240 for(;pBegin != pEnd;++pBegin,++pRet)
1244 if(moveToBookmark(*pBegin))
1246 deleteRow();
1247 *pRet = 1;
1250 catch(const SQLException&)
1252 *pRet = 0;
1255 return aRet;
1258 template < typename T, SQLINTEGER BufferLength > T OResultSet::getStmtOption (SQLINTEGER fOption) const
1260 T result (0);
1261 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
1262 N3SQLGetStmtAttr(m_aStatementHandle, fOption, &result, BufferLength, nullptr);
1263 return result;
1265 template < typename T, SQLINTEGER BufferLength > SQLRETURN OResultSet::setStmtOption (SQLINTEGER fOption, T value) const
1267 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
1268 SQLPOINTER sv = reinterpret_cast<SQLPOINTER>(value);
1269 return N3SQLSetStmtAttr(m_aStatementHandle, fOption, sv, BufferLength);
1272 sal_Int32 OResultSet::getResultSetConcurrency() const
1274 sal_uInt32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY);
1275 if(SQL_CONCUR_READ_ONLY == nValue)
1276 nValue = ResultSetConcurrency::READ_ONLY;
1277 else
1278 nValue = ResultSetConcurrency::UPDATABLE;
1280 return nValue;
1283 sal_Int32 OResultSet::getResultSetType() const
1285 sal_uInt32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SENSITIVITY);
1286 if(SQL_SENSITIVE == nValue)
1287 nValue = ResultSetType::SCROLL_SENSITIVE;
1288 else if(SQL_INSENSITIVE == nValue)
1289 nValue = ResultSetType::SCROLL_INSENSITIVE;
1290 else
1292 SQLULEN nCurType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE);
1293 if(SQL_CURSOR_KEYSET_DRIVEN == nCurType)
1294 nValue = ResultSetType::SCROLL_SENSITIVE;
1295 else if(SQL_CURSOR_STATIC == nCurType)
1296 nValue = ResultSetType::SCROLL_INSENSITIVE;
1297 else if(SQL_CURSOR_FORWARD_ONLY == nCurType)
1298 nValue = ResultSetType::FORWARD_ONLY;
1299 else if(SQL_CURSOR_DYNAMIC == nCurType)
1300 nValue = ResultSetType::SCROLL_SENSITIVE;
1302 return nValue;
1305 sal_Int32 OResultSet::getFetchSize() const
1307 return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE);
1310 OUString OResultSet::getCursorName() const
1312 SQLCHAR pName[258];
1313 SQLSMALLINT nRealLen = 0;
1314 N3SQLGetCursorName(m_aStatementHandle,pName,256,&nRealLen);
1315 return OUString::createFromAscii(reinterpret_cast<char*>(pName));
1318 bool OResultSet::isBookmarkable() const
1320 if(!m_aConnectionHandle)
1321 return false;
1323 const SQLULEN nCursorType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE);
1325 sal_Int32 nAttr = 0;
1328 switch(nCursorType)
1330 case SQL_CURSOR_FORWARD_ONLY:
1331 return false;
1332 case SQL_CURSOR_STATIC:
1333 OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_STATIC_CURSOR_ATTRIBUTES1,nAttr,nullptr);
1334 break;
1335 case SQL_CURSOR_KEYSET_DRIVEN:
1336 OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_KEYSET_CURSOR_ATTRIBUTES1,nAttr,nullptr);
1337 break;
1338 case SQL_CURSOR_DYNAMIC:
1339 OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nAttr,nullptr);
1340 break;
1343 catch(const Exception&)
1345 return false;
1348 if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED )
1350 m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
1353 return (m_nUseBookmarks != SQL_UB_OFF) && (nAttr & SQL_CA1_BOOKMARK) == SQL_CA1_BOOKMARK;
1356 void OResultSet::setFetchDirection(sal_Int32 _par0)
1358 ::dbtools::throwFunctionNotSupportedSQLException( "setFetchDirection", *this );
1360 OSL_ENSURE(_par0>0,"Illegal fetch direction!");
1361 if ( _par0 > 0 )
1363 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, _par0);
1367 void OResultSet::setFetchSize(sal_Int32 _par0)
1369 OSL_ENSURE(_par0>0,"Illegal fetch size!");
1370 if ( _par0 != 1 )
1372 throw css::beans::PropertyVetoException("SDBC/ODBC layer not prepared for fetchSize > 1", *this);
1374 setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE, _par0);
1375 m_pRowStatusArray.reset( new SQLUSMALLINT[_par0] );
1376 setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray.get());
1379 IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
1381 Sequence< Property > aProps(6);
1382 Property* pProperties = aProps.getArray();
1383 sal_Int32 nPos = 0;
1384 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME),
1385 PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY);
1387 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION),
1388 PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0);
1390 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE),
1391 PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0);
1393 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
1394 PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY);
1396 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY),
1397 PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY);
1399 pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE),
1400 PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY);
1402 return new OPropertyArrayHelper(aProps);
1405 IPropertyArrayHelper & OResultSet::getInfoHelper()
1407 return *getArrayHelper();
1410 sal_Bool OResultSet::convertFastPropertyValue(
1411 Any & rConvertedValue,
1412 Any & rOldValue,
1413 sal_Int32 nHandle,
1414 const Any& rValue )
1416 switch(nHandle)
1418 case PROPERTY_ID_ISBOOKMARKABLE:
1419 case PROPERTY_ID_CURSORNAME:
1420 case PROPERTY_ID_RESULTSETCONCURRENCY:
1421 case PROPERTY_ID_RESULTSETTYPE:
1422 throw css::lang::IllegalArgumentException();
1423 case PROPERTY_ID_FETCHDIRECTION:
1424 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection());
1425 case PROPERTY_ID_FETCHSIZE:
1426 return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize());
1427 default:
1430 return false;
1433 void OResultSet::setFastPropertyValue_NoBroadcast(
1434 sal_Int32 nHandle,
1435 const Any& rValue
1438 switch(nHandle)
1440 case PROPERTY_ID_ISBOOKMARKABLE:
1441 case PROPERTY_ID_CURSORNAME:
1442 case PROPERTY_ID_RESULTSETCONCURRENCY:
1443 case PROPERTY_ID_RESULTSETTYPE:
1444 throw Exception("cannot set prop " + OUString::number(nHandle), nullptr);
1445 case PROPERTY_ID_FETCHDIRECTION:
1446 setFetchDirection(getINT32(rValue));
1447 break;
1448 case PROPERTY_ID_FETCHSIZE:
1449 setFetchSize(getINT32(rValue));
1450 break;
1451 default:
1456 void OResultSet::getFastPropertyValue(
1457 Any& rValue,
1458 sal_Int32 nHandle
1459 ) const
1461 switch(nHandle)
1463 case PROPERTY_ID_ISBOOKMARKABLE:
1464 rValue <<= isBookmarkable();
1465 break;
1466 case PROPERTY_ID_CURSORNAME:
1467 rValue <<= getCursorName();
1468 break;
1469 case PROPERTY_ID_RESULTSETCONCURRENCY:
1470 rValue <<= getResultSetConcurrency();
1471 break;
1472 case PROPERTY_ID_RESULTSETTYPE:
1473 rValue <<= getResultSetType();
1474 break;
1475 case PROPERTY_ID_FETCHDIRECTION:
1476 rValue <<= getFetchDirection();
1477 break;
1478 case PROPERTY_ID_FETCHSIZE:
1479 rValue <<= getFetchSize();
1480 break;
1484 void OResultSet::fillColumn(const sal_Int32 _nColumn)
1486 ensureCacheForColumn(_nColumn);
1488 if (m_aRow[_nColumn].isBound())
1489 return;
1491 sal_Int32 curCol;
1492 if(m_bFetchDataInOrder)
1494 // m_aRow necessarily has a prefix of bound values, then all unbound values
1495 // EXCEPT for column 0
1496 // so use binary search to find the earliest unbound value before or at _nColumn
1497 sal_Int32 lower=0;
1498 sal_Int32 upper=_nColumn;
1500 while (lower < upper)
1502 const sal_Int32 middle=(upper-lower)/2 + lower;
1503 if(m_aRow[middle].isBound())
1505 lower=middle+1;
1507 else
1509 upper=middle;
1513 curCol = upper;
1515 else
1517 curCol = _nColumn;
1520 TDataRow::iterator pColumn = m_aRow.begin() + curCol;
1521 const TDataRow::const_iterator pColumnEnd = m_aRow.begin() + _nColumn + 1;
1523 if(curCol==0)
1527 *pColumn=impl_getBookmark();
1529 catch (SQLException &)
1531 pColumn->setNull();
1533 pColumn->setBound(true);
1534 ++curCol;
1535 ++pColumn;
1538 for (; pColumn != pColumnEnd; ++curCol, ++pColumn)
1540 const sal_Int32 nType = pColumn->getTypeKind();
1541 switch (nType)
1543 case DataType::CHAR:
1544 case DataType::VARCHAR:
1545 case DataType::DECIMAL:
1546 case DataType::NUMERIC:
1547 case DataType::LONGVARCHAR:
1548 case DataType::CLOB:
1549 *pColumn=impl_getString(curCol);
1550 break;
1551 case DataType::FLOAT:
1552 *pColumn = impl_getValue<float>(curCol, SQL_C_FLOAT);
1553 break;
1554 case DataType::REAL:
1555 case DataType::DOUBLE:
1556 *pColumn = impl_getValue<double>(curCol, SQL_C_DOUBLE);
1557 break;
1558 case DataType::BINARY:
1559 case DataType::VARBINARY:
1560 case DataType::LONGVARBINARY:
1561 case DataType::BLOB:
1562 *pColumn = impl_getBytes(curCol);
1563 break;
1564 case DataType::DATE:
1565 *pColumn = impl_getDate(curCol);
1566 break;
1567 case DataType::TIME:
1568 *pColumn = impl_getTime(curCol);
1569 break;
1570 case DataType::TIMESTAMP:
1571 *pColumn = impl_getTimestamp(curCol);
1572 break;
1573 case DataType::BIT:
1574 *pColumn = impl_getBoolean(curCol);
1575 break;
1576 case DataType::TINYINT:
1577 *pColumn = impl_getValue<sal_Int8>(curCol, SQL_C_TINYINT);
1578 break;
1579 case DataType::SMALLINT:
1580 *pColumn = impl_getValue<sal_Int16>(curCol, SQL_C_SHORT);
1581 break;
1582 case DataType::INTEGER:
1583 *pColumn = impl_getValue<sal_Int32>(curCol, SQL_C_LONG);
1584 break;
1585 case DataType::BIGINT:
1586 *pColumn = impl_getLong(curCol);
1587 break;
1588 default:
1589 SAL_WARN( "connectivity.odbc","Unknown DataType");
1592 if ( m_bWasNull )
1593 pColumn->setNull();
1594 pColumn->setBound(true);
1595 if(nType != pColumn->getTypeKind())
1597 pColumn->setTypeKind(nType);
1602 void SAL_CALL OResultSet::acquire() noexcept
1604 OResultSet_BASE::acquire();
1607 void SAL_CALL OResultSet::release() noexcept
1609 OResultSet_BASE::release();
1612 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
1614 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
1617 bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool /*_bRetrieveData*/)
1619 SQLSMALLINT nFetchOrientation = SQL_FETCH_NEXT;
1620 switch(_eCursorPosition)
1622 case IResultSetHelper::NEXT:
1623 nFetchOrientation = SQL_FETCH_NEXT;
1624 break;
1625 case IResultSetHelper::PRIOR:
1626 nFetchOrientation = SQL_FETCH_PRIOR;
1627 break;
1628 case IResultSetHelper::FIRST:
1629 nFetchOrientation = SQL_FETCH_FIRST;
1630 break;
1631 case IResultSetHelper::LAST:
1632 nFetchOrientation = SQL_FETCH_LAST;
1633 break;
1634 case IResultSetHelper::RELATIVE1:
1635 nFetchOrientation = SQL_FETCH_RELATIVE;
1636 break;
1637 case IResultSetHelper::ABSOLUTE1:
1638 nFetchOrientation = SQL_FETCH_ABSOLUTE;
1639 break;
1640 case IResultSetHelper::BOOKMARK: // special case here because we are only called with position numbers
1642 TBookmarkPosMap::const_iterator aIter = std::find_if(m_aPosToBookmarks.begin(), m_aPosToBookmarks.end(),
1643 [&_nOffset](const TBookmarkPosMap::value_type& rEntry) { return rEntry.second == _nOffset; });
1644 if (aIter != m_aPosToBookmarks.end())
1645 return moveToBookmark(makeAny(aIter->first));
1646 SAL_WARN( "connectivity.odbc", "Bookmark not found!");
1648 return false;
1651 m_bEOF = false;
1652 invalidateCache();
1654 SQLRETURN nOldFetchStatus = m_nCurrentFetchState;
1655 // TODO FIXME: both of these will misbehave for
1656 // _eCursorPosition == IResultSetHelper::NEXT/PREVIOUS
1657 // when fetchSize > 1
1658 if ( !m_bUseFetchScroll && _eCursorPosition == IResultSetHelper::NEXT )
1659 m_nCurrentFetchState = N3SQLFetch(m_aStatementHandle);
1660 else
1661 m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,nFetchOrientation,_nOffset);
1663 SAL_INFO(
1664 "connectivity.odbc",
1665 "move(" << nFetchOrientation << "," << _nOffset << "), FetchState = "
1666 << m_nCurrentFetchState);
1667 OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this);
1669 const bool bSuccess = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO;
1670 if ( bSuccess )
1672 switch(_eCursorPosition)
1674 case IResultSetHelper::NEXT:
1675 ++m_nRowPos;
1676 break;
1677 case IResultSetHelper::PRIOR:
1678 --m_nRowPos;
1679 break;
1680 case IResultSetHelper::FIRST:
1681 m_nRowPos = 1;
1682 break;
1683 case IResultSetHelper::LAST:
1684 m_bEOF = true;
1685 break;
1686 case IResultSetHelper::RELATIVE1:
1687 m_nRowPos += _nOffset;
1688 break;
1689 case IResultSetHelper::ABSOLUTE1:
1690 case IResultSetHelper::BOOKMARK: // special case here because we are only called with position numbers
1691 m_nRowPos = _nOffset;
1692 break;
1693 } // switch(_eCursorPosition)
1694 if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED )
1696 m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS);
1698 if ( m_nUseBookmarks == SQL_UB_OFF )
1700 m_aRow[0].setNull();
1702 else
1704 ensureCacheForColumn(0);
1705 Sequence<sal_Int8> bookmark = OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,0,SQL_C_VARBOOKMARK,m_bWasNull,**this);
1706 m_aPosToBookmarks[bookmark] = m_nRowPos;
1707 OSL_ENSURE(bookmark.hasElements(),"Invalid bookmark from length 0!");
1708 m_aRow[0] = bookmark;
1710 m_aRow[0].setBound(true);
1712 else if ( IResultSetHelper::PRIOR == _eCursorPosition && m_nCurrentFetchState == SQL_NO_DATA )
1713 // we went beforeFirst
1714 m_nRowPos = 0;
1715 else if(IResultSetHelper::NEXT == _eCursorPosition && m_nCurrentFetchState == SQL_NO_DATA && nOldFetchStatus != SQL_NO_DATA)
1716 // we went afterLast
1717 ++m_nRowPos;
1719 return bSuccess;
1722 sal_Int32 OResultSet::getDriverPos() const
1724 sal_Int32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_NUMBER);
1725 SAL_INFO(
1726 "connectivity.odbc",
1727 "RowNum = " << nValue << ", RowPos = " << m_nRowPos);
1728 return nValue ? nValue : m_nRowPos;
1731 bool OResultSet::isRowDeleted() const
1733 return m_pRowStatusArray[0] == SQL_ROW_DELETED;
1736 bool OResultSet::moveImpl(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset)
1738 ::osl::MutexGuard aGuard( m_aMutex );
1739 checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
1740 return (m_pSkipDeletedSet != nullptr)
1741 ? m_pSkipDeletedSet->skipDeleted(_eCursorPosition,_nOffset,true/*_bRetrieveData*/)
1742 : move(_eCursorPosition,_nOffset,true/*_bRetrieveData*/);
1745 void OResultSet::fillNeededData(SQLRETURN _nRet)
1747 SQLRETURN nRet = _nRet;
1748 if( nRet != SQL_NEED_DATA)
1749 return;
1751 void* pColumnIndex = nullptr;
1752 nRet = N3SQLParamData(m_aStatementHandle,&pColumnIndex);
1756 if (nRet != SQL_SUCCESS && nRet != SQL_SUCCESS_WITH_INFO && nRet != SQL_NEED_DATA)
1757 break;
1759 sal_IntPtr nColumnIndex ( reinterpret_cast<sal_IntPtr>(pColumnIndex));
1760 Sequence< sal_Int8 > aSeq;
1761 switch(m_aRow[nColumnIndex].getTypeKind())
1763 case DataType::BINARY:
1764 case DataType::VARBINARY:
1765 case DataType::LONGVARBINARY:
1766 case DataType::BLOB:
1767 aSeq = m_aRow[nColumnIndex];
1768 N3SQLPutData (m_aStatementHandle, aSeq.getArray(), aSeq.getLength());
1769 break;
1770 case SQL_WLONGVARCHAR:
1772 OUString const & sRet = m_aRow[nColumnIndex].getString();
1773 N3SQLPutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<sal_Unicode *>(sRet.getStr())), sizeof(sal_Unicode)*sRet.getLength());
1774 break;
1776 case DataType::LONGVARCHAR:
1777 case DataType::CLOB:
1779 OUString sRet = m_aRow[nColumnIndex].getString();
1780 OString aString(OUStringToOString(sRet,m_nTextEncoding));
1781 N3SQLPutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<char *>(aString.getStr())), aString.getLength());
1782 break;
1784 default:
1785 SAL_WARN( "connectivity.odbc", "Not supported at the moment!");
1787 nRet = N3SQLParamData(m_aStatementHandle,&pColumnIndex);
1789 while (nRet == SQL_NEED_DATA);
1792 SWORD OResultSet::impl_getColumnType_nothrow(sal_Int32 columnIndex)
1794 std::map<sal_Int32,SWORD>::const_iterator aFind = m_aODBCColumnTypes.find(columnIndex);
1795 if ( aFind == m_aODBCColumnTypes.end() )
1796 aFind = m_aODBCColumnTypes.emplace(
1797 columnIndex,
1798 OResultSetMetaData::getColumnODBCType(m_pStatement->getOwnConnection(),m_aStatementHandle,*this,columnIndex)
1799 ).first;
1800 return aFind->second;
1803 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */