1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
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");
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())
88 ,m_nTextEncoding(pStmt
->getOwnConnection()->getTextEncoding())
90 ,m_nUseBookmarks(ODBC_SQL_NOT_DEFINED
)
91 ,m_nCurrentFetchState(0)
94 ,m_bRowInserted(false)
96 ,m_bUseFetchScroll(false)
98 osl_atomic_increment( &m_refCount
);
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
);
167 osl_atomic_decrement( &m_refCount
);
170 void OResultSet::disposing()
172 N3SQLCloseCursor(m_aStatementHandle
);
173 OPropertySetHelper::disposing();
175 ::osl::MutexGuard
aGuard(m_aMutex
);
178 setStmtOption
<SQLUSMALLINT
*, SQL_IS_POINTER
>(SQL_ATTR_ROW_STATUS_PTR
, nullptr);
179 m_xStatement
.clear();
183 SQLRETURN
OResultSet::unbind(bool _bUnbindHandle
)
186 if ( _bUnbindHandle
)
187 nRet
= N3SQLFreeStmt(m_aStatementHandle
,SQL_UNBIND
);
189 if ( !m_aBindVector
.empty() )
191 for(auto& [rPtrAddr
, rType
] : m_aBindVector
)
196 case DataType::VARCHAR
:
197 delete static_cast< OString
* >(reinterpret_cast< void * >(rPtrAddr
));
199 case DataType::BIGINT
:
200 delete static_cast< sal_Int64
* >(reinterpret_cast< void * >(rPtrAddr
));
202 case DataType::DECIMAL
:
203 case DataType::NUMERIC
:
204 delete static_cast< OString
* >(reinterpret_cast< void * >(rPtrAddr
));
207 case DataType::DOUBLE
:
208 delete static_cast< double* >(reinterpret_cast< void * >(rPtrAddr
));
210 case DataType::LONGVARCHAR
:
212 delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr
));
214 case DataType::LONGVARBINARY
:
216 delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr
));
219 delete static_cast< DATE_STRUCT
* >(reinterpret_cast< void * >(rPtrAddr
));
222 delete static_cast< TIME_STRUCT
* >(reinterpret_cast< void * >(rPtrAddr
));
224 case DataType::TIMESTAMP
:
225 delete static_cast< TIMESTAMP_STRUCT
* >(reinterpret_cast< void * >(rPtrAddr
));
228 case DataType::TINYINT
:
229 delete static_cast< sal_Int8
* >(reinterpret_cast< void * >(rPtrAddr
));
231 case DataType::SMALLINT
:
232 delete static_cast< sal_Int16
* >(reinterpret_cast< void * >(rPtrAddr
));
234 case DataType::INTEGER
:
235 delete static_cast< sal_Int32
* >(reinterpret_cast< void * >(rPtrAddr
));
237 case DataType::FLOAT
:
238 delete static_cast< float* >(reinterpret_cast< void * >(rPtrAddr
));
240 case DataType::BINARY
:
241 case DataType::VARBINARY
:
242 delete static_cast< sal_Int8
* >(reinterpret_cast< void * >(rPtrAddr
));
246 m_aBindVector
.clear();
251 TVoidPtr
OResultSet::allocBindColumn(sal_Int32 _nType
,sal_Int32 _nColumnIndex
)
257 case DataType::VARCHAR
:
258 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new OString()),_nType
);
260 case DataType::BIGINT
:
261 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int64(0)),_nType
);
263 case DataType::DECIMAL
:
264 case DataType::NUMERIC
:
265 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new OString()),_nType
);
268 case DataType::DOUBLE
:
269 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new double(0.0)),_nType
);
271 case DataType::LONGVARCHAR
:
273 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new char[2]),_nType
); // only for finding
275 case DataType::LONGVARBINARY
:
277 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new char[2]),_nType
); // only for finding
280 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new DATE_STRUCT
),_nType
);
283 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new TIME_STRUCT
),_nType
);
285 case DataType::TIMESTAMP
:
286 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new TIMESTAMP_STRUCT
),_nType
);
289 case DataType::TINYINT
:
290 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int8(0)),_nType
);
292 case DataType::SMALLINT
:
293 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int16(0)),_nType
);
295 case DataType::INTEGER
:
296 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int32(0)),_nType
);
298 case DataType::FLOAT
:
299 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new float(0)),_nType
);
301 case DataType::BINARY
:
302 case DataType::VARBINARY
:
303 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int8
[m_aRow
[_nColumnIndex
].getSequence().getLength()]),_nType
);
306 SAL_WARN( "connectivity.odbc", "Unknown type");
307 aPair
= TVoidPtr(0,_nType
);
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()
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();
366 if(xMeta
->isCaseSensitive(i
) ? columnName
== xMeta
->getColumnName(i
) :
367 columnName
.equalsIgnoreAsciiCase(xMeta
->getColumnName(i
)))
371 ::dbtools::throwInvalidColumnException( columnName
, *this );
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
)
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
)
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 );
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 );
425 template < typename T
> T
OResultSet::impl_getValue( const sal_Int32 _nColumnIndex
, SQLSMALLINT nType
)
429 OTools::getValue(m_pStatement
->getOwnConnection(), m_aStatementHandle
, _nColumnIndex
, nType
, m_bWasNull
, **this, &val
, sizeof(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
];
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());
482 Sequence
< sal_Int8
> OResultSet::impl_getBytes( sal_Int32 columnIndex
)
484 const SWORD nColumnType
= impl_getColumnType_nothrow(columnIndex
);
490 case SQL_WLONGVARCHAR
:
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());
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
);
573 Reference
< XArray
> SAL_CALL
OResultSet::getArray( sal_Int32
/*columnIndex*/ )
575 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this );
580 Reference
< XClob
> SAL_CALL
OResultSet::getClob( sal_Int32
/*columnIndex*/ )
582 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this );
586 Reference
< XBlob
> SAL_CALL
OResultSet::getBlob( sal_Int32
/*columnIndex*/ )
588 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this );
593 Reference
< XRef
> SAL_CALL
OResultSet::getRef( sal_Int32
/*columnIndex*/ )
595 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this );
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
,
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
);
687 m_nCurrentFetchState
= SQL_SUCCESS
;
690 void SAL_CALL
OResultSet::afterLast( )
692 ::osl::MutexGuard
aGuard( m_aMutex
);
693 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
701 void SAL_CALL
OResultSet::close( )
704 ::osl::MutexGuard
aGuard( m_aMutex
);
705 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
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
);
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;
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;
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
);
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( )
811 void SAL_CALL
OResultSet::insertRow( )
813 ::osl::MutexGuard
aGuard( m_aMutex
);
814 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
818 Sequence
<sal_Int8
> aBookmark(nMaxBookmarkLen
);
819 static_assert(o3tl::make_unsigned(nMaxBookmarkLen
) >= sizeof(SQLLEN
), "must be larger");
821 SQLRETURN nRet
= N3SQLBindCol(m_aStatementHandle
,
824 aBookmark
.getArray(),
829 bool bPositionByBookmark
= ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations
) );
830 if ( bPositionByBookmark
)
832 nRet
= N3SQLBulkOperations( m_aStatementHandle
, SQL_ADD
);
833 fillNeededData( nRet
);
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
&)
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);
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
)
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
);
896 bool bPositionByBookmark
= ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations
) );
897 if ( bPositionByBookmark
)
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
,
906 aBookmark
.getArray(),
907 aBookmark
.getLength(),
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());
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])
928 OSL_ENSURE(nRet
== SQL_SUCCESS
,"ODBC insert could not unbind the columns after success");
932 // unbind all columns so that a subsequent fetch does not overwrite m_aRow[0]
934 OSL_ENSURE(nRet
== SQL_SUCCESS
,"ODBC insert could not unbind the columns after failure");
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
);
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
);
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( )
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(),
997 &m_aLengthVector
[columnIndex
],
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
)
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();
1132 Any SAL_CALL
OResultSet::getBookmark( )
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!");
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
);
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
;
1190 return m_nCurrentFetchState
== SQL_SUCCESS
|| m_nCurrentFetchState
== SQL_SUCCESS_WITH_INFO
;
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
);
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( )
1225 sal_Int32 SAL_CALL
OResultSet::hashBookmark( const Any
& /*bookmark*/ )
1227 ::dbtools::throwFunctionNotSupportedSQLException( "XRowLocate::hashBookmark", *this );
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
))
1250 catch(const SQLException
&)
1258 template < typename T
, SQLINTEGER BufferLength
> T
OResultSet::getStmtOption (SQLINTEGER fOption
) const
1261 OSL_ENSURE(m_aStatementHandle
,"StatementHandle is null!");
1262 N3SQLGetStmtAttr(m_aStatementHandle
, fOption
, &result
, BufferLength
, nullptr);
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
;
1278 nValue
= ResultSetConcurrency::UPDATABLE
;
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
;
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
;
1305 sal_Int32
OResultSet::getFetchSize() const
1307 return getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_ROW_ARRAY_SIZE
);
1310 OUString
OResultSet::getCursorName() const
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
)
1323 const SQLULEN nCursorType
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CURSOR_TYPE
);
1325 sal_Int32 nAttr
= 0;
1330 case SQL_CURSOR_FORWARD_ONLY
:
1332 case SQL_CURSOR_STATIC
:
1333 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_STATIC_CURSOR_ATTRIBUTES1
,nAttr
,nullptr);
1335 case SQL_CURSOR_KEYSET_DRIVEN
:
1336 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_KEYSET_CURSOR_ATTRIBUTES1
,nAttr
,nullptr);
1338 case SQL_CURSOR_DYNAMIC
:
1339 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_DYNAMIC_CURSOR_ATTRIBUTES1
,nAttr
,nullptr);
1343 catch(const Exception
&)
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!");
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!");
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();
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
,
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());
1433 void OResultSet::setFastPropertyValue_NoBroadcast(
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
));
1448 case PROPERTY_ID_FETCHSIZE
:
1449 setFetchSize(getINT32(rValue
));
1456 void OResultSet::getFastPropertyValue(
1463 case PROPERTY_ID_ISBOOKMARKABLE
:
1464 rValue
<<= isBookmarkable();
1466 case PROPERTY_ID_CURSORNAME
:
1467 rValue
<<= getCursorName();
1469 case PROPERTY_ID_RESULTSETCONCURRENCY
:
1470 rValue
<<= getResultSetConcurrency();
1472 case PROPERTY_ID_RESULTSETTYPE
:
1473 rValue
<<= getResultSetType();
1475 case PROPERTY_ID_FETCHDIRECTION
:
1476 rValue
<<= getFetchDirection();
1478 case PROPERTY_ID_FETCHSIZE
:
1479 rValue
<<= getFetchSize();
1484 void OResultSet::fillColumn(const sal_Int32 _nColumn
)
1486 ensureCacheForColumn(_nColumn
);
1488 if (m_aRow
[_nColumn
].isBound())
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
1498 sal_Int32 upper
=_nColumn
;
1500 while (lower
< upper
)
1502 const sal_Int32 middle
=(upper
-lower
)/2 + lower
;
1503 if(m_aRow
[middle
].isBound())
1520 TDataRow::iterator pColumn
= m_aRow
.begin() + curCol
;
1521 const TDataRow::const_iterator pColumnEnd
= m_aRow
.begin() + _nColumn
+ 1;
1527 *pColumn
=impl_getBookmark();
1529 catch (SQLException
&)
1533 pColumn
->setBound(true);
1538 for (; pColumn
!= pColumnEnd
; ++curCol
, ++pColumn
)
1540 const sal_Int32 nType
= pColumn
->getTypeKind();
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
);
1551 case DataType::FLOAT
:
1552 *pColumn
= impl_getValue
<float>(curCol
, SQL_C_FLOAT
);
1554 case DataType::REAL
:
1555 case DataType::DOUBLE
:
1556 *pColumn
= impl_getValue
<double>(curCol
, SQL_C_DOUBLE
);
1558 case DataType::BINARY
:
1559 case DataType::VARBINARY
:
1560 case DataType::LONGVARBINARY
:
1561 case DataType::BLOB
:
1562 *pColumn
= impl_getBytes(curCol
);
1564 case DataType::DATE
:
1565 *pColumn
= impl_getDate(curCol
);
1567 case DataType::TIME
:
1568 *pColumn
= impl_getTime(curCol
);
1570 case DataType::TIMESTAMP
:
1571 *pColumn
= impl_getTimestamp(curCol
);
1574 *pColumn
= impl_getBoolean(curCol
);
1576 case DataType::TINYINT
:
1577 *pColumn
= impl_getValue
<sal_Int8
>(curCol
, SQL_C_TINYINT
);
1579 case DataType::SMALLINT
:
1580 *pColumn
= impl_getValue
<sal_Int16
>(curCol
, SQL_C_SHORT
);
1582 case DataType::INTEGER
:
1583 *pColumn
= impl_getValue
<sal_Int32
>(curCol
, SQL_C_LONG
);
1585 case DataType::BIGINT
:
1586 *pColumn
= impl_getLong(curCol
);
1589 SAL_WARN( "connectivity.odbc","Unknown DataType");
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
;
1625 case IResultSetHelper::PRIOR
:
1626 nFetchOrientation
= SQL_FETCH_PRIOR
;
1628 case IResultSetHelper::FIRST
:
1629 nFetchOrientation
= SQL_FETCH_FIRST
;
1631 case IResultSetHelper::LAST
:
1632 nFetchOrientation
= SQL_FETCH_LAST
;
1634 case IResultSetHelper::RELATIVE1
:
1635 nFetchOrientation
= SQL_FETCH_RELATIVE
;
1637 case IResultSetHelper::ABSOLUTE1
:
1638 nFetchOrientation
= SQL_FETCH_ABSOLUTE
;
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!");
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
);
1661 m_nCurrentFetchState
= N3SQLFetchScroll(m_aStatementHandle
,nFetchOrientation
,_nOffset
);
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
;
1672 switch(_eCursorPosition
)
1674 case IResultSetHelper::NEXT
:
1677 case IResultSetHelper::PRIOR
:
1680 case IResultSetHelper::FIRST
:
1683 case IResultSetHelper::LAST
:
1686 case IResultSetHelper::RELATIVE1
:
1687 m_nRowPos
+= _nOffset
;
1689 case IResultSetHelper::ABSOLUTE1
:
1690 case IResultSetHelper::BOOKMARK
: // special case here because we are only called with position numbers
1691 m_nRowPos
= _nOffset
;
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();
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
1715 else if(IResultSetHelper::NEXT
== _eCursorPosition
&& m_nCurrentFetchState
== SQL_NO_DATA
&& nOldFetchStatus
!= SQL_NO_DATA
)
1716 // we went afterLast
1722 sal_Int32
OResultSet::getDriverPos() const
1724 sal_Int32 nValue
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_ROW_NUMBER
);
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
)
1751 void* pColumnIndex
= nullptr;
1752 nRet
= N3SQLParamData(m_aStatementHandle
,&pColumnIndex
);
1756 if (nRet
!= SQL_SUCCESS
&& nRet
!= SQL_SUCCESS_WITH_INFO
&& nRet
!= SQL_NEED_DATA
)
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());
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());
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());
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(
1798 OResultSetMetaData::getColumnODBCType(m_pStatement
->getOwnConnection(),m_aStatementHandle
,*this,columnIndex
)
1800 return aFind
->second
;
1803 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */