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/FetchDirection.hpp>
29 #include <com/sun/star/sdbc/ResultSetType.hpp>
30 #include <comphelper/property.hxx>
31 #include <comphelper/sequence.hxx>
32 #include <cppuhelper/typeprovider.hxx>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <comphelper/types.hxx>
36 #include <connectivity/dbtools.hxx>
37 #include <connectivity/dbexception.hxx>
38 #include <sal/log.hxx>
40 using namespace ::comphelper
;
41 using namespace connectivity
;
42 using namespace connectivity::odbc
;
44 using namespace com::sun::star::uno
;
45 using namespace com::sun::star::lang
;
46 using namespace com::sun::star::beans
;
47 using namespace com::sun::star::sdbc
;
48 using namespace com::sun::star::sdbcx
;
49 using namespace com::sun::star::container
;
50 using namespace com::sun::star::io
;
51 using namespace com::sun::star::util
;
53 #define ODBC_SQL_NOT_DEFINED 99UL
54 static_assert(ODBC_SQL_NOT_DEFINED
!= SQL_UB_OFF
, "ODBC_SQL_NOT_DEFINED must be unique");
55 static_assert(ODBC_SQL_NOT_DEFINED
!= SQL_UB_ON
, "ODBC_SQL_NOT_DEFINED must be unique");
56 static_assert(ODBC_SQL_NOT_DEFINED
!= SQL_UB_FIXED
, "ODBC_SQL_NOT_DEFINED must be unique");
57 static_assert(ODBC_SQL_NOT_DEFINED
!= SQL_UB_VARIABLE
, "ODBC_SQL_NOT_DEFINED must be unique");
61 const SQLLEN nMaxBookmarkLen
= 20;
65 // IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.OResultSet","com.sun.star.sdbc.ResultSet");
66 OUString SAL_CALL
OResultSet::getImplementationName( )
68 return OUString("com.sun.star.sdbcx.odbc.ResultSet");
71 Sequence
< OUString
> SAL_CALL
OResultSet::getSupportedServiceNames( )
73 Sequence
< OUString
> aSupported(2);
74 aSupported
[0] = "com.sun.star.sdbc.ResultSet";
75 aSupported
[1] = "com.sun.star.sdbcx.ResultSet";
79 sal_Bool SAL_CALL
OResultSet::supportsService( const OUString
& _rServiceName
)
81 return cppu::supportsService(this, _rServiceName
);
85 OResultSet::OResultSet(SQLHANDLE _pStatementHandle
,OStatement_Base
* pStmt
) : OResultSet_BASE(m_aMutex
)
86 ,OPropertySetHelper(OResultSet_BASE::rBHelper
)
87 ,m_bFetchDataInOrder(true)
88 ,m_aStatementHandle(_pStatementHandle
)
89 ,m_aConnectionHandle(pStmt
->getConnectionHandle())
92 ,m_nTextEncoding(pStmt
->getOwnConnection()->getTextEncoding())
94 ,m_nUseBookmarks(ODBC_SQL_NOT_DEFINED
)
95 ,m_nCurrentFetchState(0)
98 ,m_bRowInserted(false)
100 ,m_bUseFetchScroll(false)
102 osl_atomic_increment( &m_refCount
);
105 m_pRowStatusArray
.reset( new SQLUSMALLINT
[1] ); // the default value
106 setStmtOption
<SQLUSMALLINT
*, SQL_IS_POINTER
>(SQL_ATTR_ROW_STATUS_PTR
, m_pRowStatusArray
.get());
108 catch(const Exception
&)
109 { // we don't want our result destroy here
111 SQLULEN nCurType
= 0;
114 nCurType
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CURSOR_TYPE
);
115 SQLUINTEGER nValueLen
= m_pStatement
->getCursorProperties(nCurType
,false);
116 if( (nValueLen
& SQL_CA2_SENSITIVITY_DELETIONS
) != SQL_CA2_SENSITIVITY_DELETIONS
||
117 (nValueLen
& SQL_CA2_CRC_EXACT
) != SQL_CA2_CRC_EXACT
)
118 m_pSkipDeletedSet
.reset( new OSkipDeletedSet(this) );
120 catch(const Exception
&)
121 { // we don't want our result destroy here
125 SQLUINTEGER nValueLen
= 0;
126 // Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441%28v=vs.85%29.aspx
127 // LibreOffice ODBC binds columns only on update, so we don't care about SQL_GD_ANY_COLUMN / SQL_GD_BOUND
128 // TODO: maybe a problem if a column is updated, then an earlier column fetched?
129 // an updated column is bound...
130 // TODO: aren't we assuming SQL_GD_OUTPUT_PARAMS?
131 // If yes, we should at least OSL_ENSURE it,
132 // even better throw an exception any OUT parameter registration if !SQL_GD_OUTPUT_PARAMS.
133 // If !SQL_GD_ANY_ORDER, cache the whole row so that callers can access columns in any order.
134 // In other words, isolate them from ODBC restrictions.
135 // TODO: we assume SQL_GD_BLOCK, unless fetchSize is 1
136 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_GETDATA_EXTENSIONS
,nValueLen
,nullptr);
137 m_bFetchDataInOrder
= ((SQL_GD_ANY_ORDER
& nValueLen
) != SQL_GD_ANY_ORDER
);
139 catch(const Exception
&)
141 m_bFetchDataInOrder
= true;
145 // TODO: this does *not* do what it appears.
146 // We use SQLFetchScroll unconditionally in several places
147 // the *only* difference this makes is whether ::next() uses SQLFetchScroll or SQLFetch
148 // so this test seems pointless
149 if ( getOdbcFunction(ODBC3SQLFunctionId::GetFunctions
) )
151 SQLUSMALLINT nSupported
= 0;
152 m_bUseFetchScroll
= ( N3SQLGetFunctions(m_aConnectionHandle
,SQL_API_SQLFETCHSCROLL
,&nSupported
) == SQL_SUCCESS
&& nSupported
== 1 );
155 catch(const Exception
&)
157 m_bUseFetchScroll
= false;
160 osl_atomic_decrement( &m_refCount
);
163 OResultSet::~OResultSet()
167 void OResultSet::construct()
169 osl_atomic_increment( &m_refCount
);
171 osl_atomic_decrement( &m_refCount
);
174 void OResultSet::disposing()
176 N3SQLCloseCursor(m_aStatementHandle
);
177 OPropertySetHelper::disposing();
179 ::osl::MutexGuard
aGuard(m_aMutex
);
182 setStmtOption
<SQLUSMALLINT
*, SQL_IS_POINTER
>(SQL_ATTR_ROW_STATUS_PTR
, nullptr);
183 m_xStatement
.clear();
187 SQLRETURN
OResultSet::unbind(bool _bUnbindHandle
)
190 if ( _bUnbindHandle
)
191 nRet
= N3SQLFreeStmt(m_aStatementHandle
,SQL_UNBIND
);
193 if ( !m_aBindVector
.empty() )
195 for(auto& [rPtrAddr
, rType
] : m_aBindVector
)
200 case DataType::VARCHAR
:
201 delete static_cast< OString
* >(reinterpret_cast< void * >(rPtrAddr
));
203 case DataType::BIGINT
:
204 delete static_cast< sal_Int64
* >(reinterpret_cast< void * >(rPtrAddr
));
206 case DataType::DECIMAL
:
207 case DataType::NUMERIC
:
208 delete static_cast< OString
* >(reinterpret_cast< void * >(rPtrAddr
));
211 case DataType::DOUBLE
:
212 delete static_cast< double* >(reinterpret_cast< void * >(rPtrAddr
));
214 case DataType::LONGVARCHAR
:
216 delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr
));
218 case DataType::LONGVARBINARY
:
220 delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr
));
223 delete static_cast< DATE_STRUCT
* >(reinterpret_cast< void * >(rPtrAddr
));
226 delete static_cast< TIME_STRUCT
* >(reinterpret_cast< void * >(rPtrAddr
));
228 case DataType::TIMESTAMP
:
229 delete static_cast< TIMESTAMP_STRUCT
* >(reinterpret_cast< void * >(rPtrAddr
));
232 case DataType::TINYINT
:
233 delete static_cast< sal_Int8
* >(reinterpret_cast< void * >(rPtrAddr
));
235 case DataType::SMALLINT
:
236 delete static_cast< sal_Int16
* >(reinterpret_cast< void * >(rPtrAddr
));
238 case DataType::INTEGER
:
239 delete static_cast< sal_Int32
* >(reinterpret_cast< void * >(rPtrAddr
));
241 case DataType::FLOAT
:
242 delete static_cast< float* >(reinterpret_cast< void * >(rPtrAddr
));
244 case DataType::BINARY
:
245 case DataType::VARBINARY
:
246 delete static_cast< sal_Int8
* >(reinterpret_cast< void * >(rPtrAddr
));
250 m_aBindVector
.clear();
255 TVoidPtr
OResultSet::allocBindColumn(sal_Int32 _nType
,sal_Int32 _nColumnIndex
)
261 case DataType::VARCHAR
:
262 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new OString()),_nType
);
264 case DataType::BIGINT
:
265 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int64(0)),_nType
);
267 case DataType::DECIMAL
:
268 case DataType::NUMERIC
:
269 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new OString()),_nType
);
272 case DataType::DOUBLE
:
273 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new double(0.0)),_nType
);
275 case DataType::LONGVARCHAR
:
277 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new char[2]),_nType
); // only for finding
279 case DataType::LONGVARBINARY
:
281 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new char[2]),_nType
); // only for finding
284 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new DATE_STRUCT
),_nType
);
287 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new TIME_STRUCT
),_nType
);
289 case DataType::TIMESTAMP
:
290 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new TIMESTAMP_STRUCT
),_nType
);
293 case DataType::TINYINT
:
294 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int8(0)),_nType
);
296 case DataType::SMALLINT
:
297 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int16(0)),_nType
);
299 case DataType::INTEGER
:
300 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int32(0)),_nType
);
302 case DataType::FLOAT
:
303 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new float(0)),_nType
);
305 case DataType::BINARY
:
306 case DataType::VARBINARY
:
307 aPair
= TVoidPtr(reinterpret_cast< sal_Int64
>(new sal_Int8
[m_aRow
[_nColumnIndex
].getSequence().getLength()]),_nType
);
310 SAL_WARN( "connectivity.odbc", "Unknown type");
311 aPair
= TVoidPtr(0,_nType
);
316 void OResultSet::allocBuffer()
318 Reference
< XResultSetMetaData
> xMeta
= getMetaData();
319 sal_Int32 nLen
= xMeta
->getColumnCount();
321 m_aBindVector
.reserve(nLen
);
322 m_aRow
.resize(nLen
+1);
324 m_aRow
[0].setTypeKind(DataType::VARBINARY
);
325 m_aRow
[0].setBound( false );
327 for(sal_Int32 i
= 1;i
<=nLen
;++i
)
329 sal_Int32 nType
= xMeta
->getColumnType(i
);
330 m_aRow
[i
].setTypeKind( nType
);
331 m_aRow
[i
].setBound( false );
333 m_aLengthVector
.resize(nLen
+ 1);
336 void OResultSet::releaseBuffer()
339 m_aLengthVector
.clear();
342 Any SAL_CALL
OResultSet::queryInterface( const Type
& rType
)
344 Any aRet
= OPropertySetHelper::queryInterface(rType
);
345 return aRet
.hasValue() ? aRet
: OResultSet_BASE::queryInterface(rType
);
348 Sequence
< Type
> SAL_CALL
OResultSet::getTypes( )
350 OTypeCollection
aTypes( cppu::UnoType
<css::beans::XMultiPropertySet
>::get(),
351 cppu::UnoType
<css::beans::XFastPropertySet
>::get(),
352 cppu::UnoType
<css::beans::XPropertySet
>::get());
354 return ::comphelper::concatSequences(aTypes
.getTypes(),OResultSet_BASE::getTypes());
358 sal_Int32 SAL_CALL
OResultSet::findColumn( const OUString
& columnName
)
360 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
363 ::osl::MutexGuard
aGuard( m_aMutex
);
365 Reference
< XResultSetMetaData
> xMeta
= getMetaData();
366 sal_Int32 nLen
= xMeta
->getColumnCount();
370 if(xMeta
->isCaseSensitive(i
) ? columnName
== xMeta
->getColumnName(i
) :
371 columnName
.equalsIgnoreAsciiCase(xMeta
->getColumnName(i
)))
375 ::dbtools::throwInvalidColumnException( columnName
, *this );
377 return 0; // Never reached
380 void OResultSet::ensureCacheForColumn(sal_Int32 columnIndex
)
382 SAL_INFO( "connectivity.odbc", "odbc lionel@mamane.lu OResultSet::ensureCacheForColumn" );
384 assert(columnIndex
>= 0);
386 const TDataRow::size_type oldCacheSize
= m_aRow
.size();
387 const TDataRow::size_type uColumnIndex
= static_cast<TDataRow::size_type
>(columnIndex
);
389 if (oldCacheSize
> uColumnIndex
)
393 m_aRow
.resize(columnIndex
+ 1);
394 TDataRow::iterator
i (m_aRow
.begin() + oldCacheSize
);
395 const TDataRow::const_iterator
end(m_aRow
.end());
396 for (; i
!= end
; ++i
)
401 void OResultSet::invalidateCache()
403 for(auto& rItem
: m_aRow
)
405 rItem
.setBound(false);
409 Reference
< XInputStream
> SAL_CALL
OResultSet::getBinaryStream( sal_Int32
/*columnIndex*/ )
411 ::osl::MutexGuard
aGuard( m_aMutex
);
412 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
414 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
419 Reference
< XInputStream
> SAL_CALL
OResultSet::getCharacterStream( sal_Int32
/*columnIndex*/ )
421 ::osl::MutexGuard
aGuard( m_aMutex
);
422 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
424 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this );
429 template < typename T
> T
OResultSet::impl_getValue( const sal_Int32 _nColumnIndex
, SQLSMALLINT nType
)
433 OTools::getValue(m_pStatement
->getOwnConnection(), m_aStatementHandle
, _nColumnIndex
, nType
, m_bWasNull
, **this, &val
, sizeof(val
));
438 // this function exists for the implicit conversion to sal_Bool (compared to a direct call to impl_getValue)
439 bool OResultSet::impl_getBoolean( sal_Int32 columnIndex
)
441 return impl_getValue
<sal_Int8
>(columnIndex
, SQL_C_BIT
);
444 template < typename T
> T
OResultSet::getValue( sal_Int32 columnIndex
)
446 ::osl::MutexGuard
aGuard( m_aMutex
);
447 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
448 fillColumn(columnIndex
);
449 m_bWasNull
= m_aRow
[columnIndex
].isNull();
450 return m_aRow
[columnIndex
];
452 sal_Bool SAL_CALL
OResultSet::getBoolean( sal_Int32 columnIndex
)
454 return getValue
<bool>( columnIndex
);
457 sal_Int8 SAL_CALL
OResultSet::getByte( sal_Int32 columnIndex
)
459 return getValue
<sal_Int8
>( columnIndex
);
463 Sequence
< sal_Int8
> SAL_CALL
OResultSet::getBytes( sal_Int32 columnIndex
)
465 ::osl::MutexGuard
aGuard( m_aMutex
);
466 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
467 fillColumn(columnIndex
);
468 m_bWasNull
= m_aRow
[columnIndex
].isNull();
470 Sequence
< sal_Int8
> nRet
;
471 switch(m_aRow
[columnIndex
].getTypeKind())
473 case DataType::BINARY
:
474 case DataType::VARBINARY
:
475 case DataType::LONGVARBINARY
:
476 nRet
= m_aRow
[columnIndex
];
480 OUString
const & sRet
= m_aRow
[columnIndex
].getString();
481 nRet
= Sequence
<sal_Int8
>(reinterpret_cast<const sal_Int8
*>(sRet
.getStr()),sizeof(sal_Unicode
)*sRet
.getLength());
486 Sequence
< sal_Int8
> OResultSet::impl_getBytes( sal_Int32 columnIndex
)
488 const SWORD nColumnType
= impl_getColumnType_nothrow(columnIndex
);
494 case SQL_WLONGVARCHAR
:
497 case SQL_LONGVARCHAR
:
499 OUString
const & aRet
= OTools::getStringValue(m_pStatement
->getOwnConnection(),m_aStatementHandle
,columnIndex
,nColumnType
,m_bWasNull
,**this,m_nTextEncoding
);
500 return Sequence
<sal_Int8
>(reinterpret_cast<const sal_Int8
*>(aRet
.getStr()),sizeof(sal_Unicode
)*aRet
.getLength());
503 return OTools::getBytesValue(m_pStatement
->getOwnConnection(),m_aStatementHandle
,columnIndex
,SQL_C_BINARY
,m_bWasNull
,**this);
507 Date
OResultSet::impl_getDate( sal_Int32 columnIndex
)
509 DATE_STRUCT aDate
= impl_getValue
< DATE_STRUCT
> ( columnIndex
,
510 m_pStatement
->getOwnConnection()->useOldDateFormat() ? SQL_C_DATE
: SQL_C_TYPE_DATE
);
512 return Date(aDate
.day
, aDate
.month
, aDate
.year
);
515 Date SAL_CALL
OResultSet::getDate( sal_Int32 columnIndex
)
517 return getValue
<Date
>( columnIndex
);
521 double SAL_CALL
OResultSet::getDouble( sal_Int32 columnIndex
)
523 return getValue
<double>( columnIndex
);
527 float SAL_CALL
OResultSet::getFloat( sal_Int32 columnIndex
)
529 return getValue
<float>( columnIndex
);
532 sal_Int16 SAL_CALL
OResultSet::getShort( sal_Int32 columnIndex
)
534 return getValue
<sal_Int16
>( columnIndex
);
537 sal_Int32 SAL_CALL
OResultSet::getInt( sal_Int32 columnIndex
)
539 return getValue
<sal_Int32
>( columnIndex
);
542 sal_Int64 SAL_CALL
OResultSet::getLong( sal_Int32 columnIndex
)
544 return getValue
<sal_Int64
>( columnIndex
);
546 sal_Int64
OResultSet::impl_getLong( sal_Int32 columnIndex
)
550 return impl_getValue
<sal_Int64
>(columnIndex
, SQL_C_SBIGINT
);
552 catch(const SQLException
&)
554 return getString(columnIndex
).toInt64();
558 sal_Int32 SAL_CALL
OResultSet::getRow( )
560 ::osl::MutexGuard
aGuard( m_aMutex
);
561 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
563 return m_pSkipDeletedSet
? m_pSkipDeletedSet
->getMappedPosition(getDriverPos()) : getDriverPos();
566 Reference
< XResultSetMetaData
> SAL_CALL
OResultSet::getMetaData( )
568 ::osl::MutexGuard
aGuard( m_aMutex
);
569 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
572 if(!m_xMetaData
.is())
573 m_xMetaData
= new OResultSetMetaData(m_pStatement
->getOwnConnection(),m_aStatementHandle
);
577 Reference
< XArray
> SAL_CALL
OResultSet::getArray( sal_Int32
/*columnIndex*/ )
579 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this );
584 Reference
< XClob
> SAL_CALL
OResultSet::getClob( sal_Int32
/*columnIndex*/ )
586 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this );
590 Reference
< XBlob
> SAL_CALL
OResultSet::getBlob( sal_Int32
/*columnIndex*/ )
592 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this );
597 Reference
< XRef
> SAL_CALL
OResultSet::getRef( sal_Int32
/*columnIndex*/ )
599 ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this );
604 Any SAL_CALL
OResultSet::getObject( sal_Int32 columnIndex
, const Reference
< css::container::XNameAccess
>& /*typeMap*/ )
606 return getValue
<ORowSetValue
>( columnIndex
).makeAny();
609 OUString
OResultSet::impl_getString( sal_Int32 columnIndex
)
611 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
612 const SWORD nColumnType
= impl_getColumnType_nothrow(columnIndex
);
613 return OTools::getStringValue(m_pStatement
->getOwnConnection(),m_aStatementHandle
,columnIndex
,nColumnType
,m_bWasNull
,**this,m_nTextEncoding
);
615 OUString
OResultSet::getString( sal_Int32 columnIndex
)
617 return getValue
<OUString
>( columnIndex
);
620 Time
OResultSet::impl_getTime( sal_Int32 columnIndex
)
622 TIME_STRUCT aTime
= impl_getValue
< TIME_STRUCT
> ( columnIndex
,
623 m_pStatement
->getOwnConnection()->useOldDateFormat() ? SQL_C_TIME
: SQL_C_TYPE_TIME
);
625 return Time(0, aTime
.second
,aTime
.minute
,aTime
.hour
, false);
627 Time SAL_CALL
OResultSet::getTime( sal_Int32 columnIndex
)
629 return getValue
<Time
>( columnIndex
);
632 DateTime
OResultSet::impl_getTimestamp( sal_Int32 columnIndex
)
634 TIMESTAMP_STRUCT aTime
= impl_getValue
< TIMESTAMP_STRUCT
> ( columnIndex
,
635 m_pStatement
->getOwnConnection()->useOldDateFormat() ? SQL_C_TIMESTAMP
: SQL_C_TYPE_TIMESTAMP
);
637 return DateTime(aTime
.fraction
,
646 DateTime SAL_CALL
OResultSet::getTimestamp( sal_Int32 columnIndex
)
648 return getValue
<DateTime
>( columnIndex
);
651 sal_Bool SAL_CALL
OResultSet::isBeforeFirst( )
653 ::osl::MutexGuard
aGuard( m_aMutex
);
654 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
655 return m_nRowPos
== 0;
658 sal_Bool SAL_CALL
OResultSet::isAfterLast( )
660 ::osl::MutexGuard
aGuard( m_aMutex
);
661 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
663 return m_nRowPos
!= 0 && m_nCurrentFetchState
== SQL_NO_DATA
;
666 sal_Bool SAL_CALL
OResultSet::isFirst( )
668 ::osl::MutexGuard
aGuard( m_aMutex
);
669 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
671 return m_nRowPos
== 1;
674 sal_Bool SAL_CALL
OResultSet::isLast( )
676 ::osl::MutexGuard
aGuard( m_aMutex
);
677 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
680 return m_bEOF
&& m_nCurrentFetchState
!= SQL_NO_DATA
;
683 void SAL_CALL
OResultSet::beforeFirst( )
685 ::osl::MutexGuard
aGuard( m_aMutex
);
686 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
691 m_nCurrentFetchState
= SQL_SUCCESS
;
694 void SAL_CALL
OResultSet::afterLast( )
696 ::osl::MutexGuard
aGuard( m_aMutex
);
697 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
705 void SAL_CALL
OResultSet::close( )
708 ::osl::MutexGuard
aGuard( m_aMutex
);
709 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
716 sal_Bool SAL_CALL
OResultSet::first( )
718 return moveImpl(IResultSetHelper::FIRST
,0);
722 sal_Bool SAL_CALL
OResultSet::last( )
724 return moveImpl(IResultSetHelper::LAST
,0);
727 sal_Bool SAL_CALL
OResultSet::absolute( sal_Int32 row
)
729 return moveImpl(IResultSetHelper::ABSOLUTE1
,row
);
732 sal_Bool SAL_CALL
OResultSet::relative( sal_Int32 row
)
734 return moveImpl(IResultSetHelper::RELATIVE1
,row
);
737 sal_Bool SAL_CALL
OResultSet::previous( )
739 return moveImpl(IResultSetHelper::PRIOR
,0);
742 Reference
< XInterface
> SAL_CALL
OResultSet::getStatement( )
744 ::osl::MutexGuard
aGuard( m_aMutex
);
745 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
750 sal_Bool SAL_CALL
OResultSet::rowDeleted()
752 ::osl::MutexGuard
aGuard( m_aMutex
);
753 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
755 bool bRet
= m_bRowDeleted
;
756 m_bRowDeleted
= false;
761 sal_Bool SAL_CALL
OResultSet::rowInserted( )
763 ::osl::MutexGuard
aGuard( m_aMutex
);
764 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
766 bool bInserted
= m_bRowInserted
;
767 m_bRowInserted
= false;
772 sal_Bool SAL_CALL
OResultSet::rowUpdated( )
774 ::osl::MutexGuard
aGuard( m_aMutex
);
775 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
778 return m_pRowStatusArray
[0] == SQL_ROW_UPDATED
;
782 sal_Bool SAL_CALL
OResultSet::next( )
784 return moveImpl(IResultSetHelper::NEXT
,1);
788 sal_Bool SAL_CALL
OResultSet::wasNull( )
790 ::osl::MutexGuard
aGuard( m_aMutex
);
791 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
797 void SAL_CALL
OResultSet::cancel( )
799 ::osl::MutexGuard
aGuard( m_aMutex
);
800 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
803 N3SQLCancel(m_aStatementHandle
);
806 void SAL_CALL
OResultSet::clearWarnings( )
810 Any SAL_CALL
OResultSet::getWarnings( )
815 void SAL_CALL
OResultSet::insertRow( )
817 ::osl::MutexGuard
aGuard( m_aMutex
);
818 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
822 Sequence
<sal_Int8
> aBookmark(nMaxBookmarkLen
);
823 static_assert(static_cast<size_t>(nMaxBookmarkLen
) >= sizeof(SQLLEN
), "must be larger");
825 SQLRETURN nRet
= N3SQLBindCol(m_aStatementHandle
,
828 aBookmark
.getArray(),
833 bool bPositionByBookmark
= ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations
) );
834 if ( bPositionByBookmark
)
836 nRet
= N3SQLBulkOperations( m_aStatementHandle
, SQL_ADD
);
837 fillNeededData( nRet
);
842 next(); // must be done
843 nRet
= N3SQLSetPos( m_aStatementHandle
, 1, SQL_ADD
, SQL_LOCK_NO_CHANGE
);
844 fillNeededData( nRet
);
846 aBookmark
.realloc(nRealLen
);
849 OTools::ThrowException(m_pStatement
->getOwnConnection(),nRet
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
851 catch(const SQLException
&)
858 OTools::ThrowException(m_pStatement
->getOwnConnection(),nRet
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
860 if ( bPositionByBookmark
)
862 setStmtOption
<SQLLEN
*, SQL_IS_POINTER
>(SQL_ATTR_FETCH_BOOKMARK_PTR
, reinterpret_cast<SQLLEN
*>(aBookmark
.getArray()));
864 nRet
= N3SQLFetchScroll(m_aStatementHandle
,SQL_FETCH_BOOKMARK
,0);
867 nRet
= N3SQLFetchScroll(m_aStatementHandle
,SQL_FETCH_RELATIVE
,0); // OJ 06.03.2004
868 // sometimes we got an error but we are not interested in anymore #106047# OJ
869 // OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this);
871 if(m_pSkipDeletedSet
)
873 if(moveToBookmark(makeAny(aBookmark
)))
875 sal_Int32 nRowPos
= getDriverPos();
876 if ( -1 == m_nRowPos
)
878 nRowPos
= m_aPosToBookmarks
.size() + 1;
880 if ( nRowPos
== m_nRowPos
)
883 m_pSkipDeletedSet
->insertNewPosition(nRowPos
);
884 m_aPosToBookmarks
[aBookmark
] = nRowPos
;
887 m_bRowInserted
= true;
891 void SAL_CALL
OResultSet::updateRow( )
893 ::osl::MutexGuard
aGuard( m_aMutex
);
894 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
900 bool bPositionByBookmark
= ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations
) );
901 if ( bPositionByBookmark
)
904 assert(m_aRow
[0].isBound());
905 Sequence
<sal_Int8
> aBookmark(m_aRow
[0].getSequence());
906 SQLLEN nRealLen
= aBookmark
.getLength();
907 nRet
= N3SQLBindCol(m_aStatementHandle
,
910 aBookmark
.getArray(),
911 aBookmark
.getLength(),
914 OTools::ThrowException(m_pStatement
->getOwnConnection(),nRet
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
915 nRet
= N3SQLBulkOperations(m_aStatementHandle
, SQL_UPDATE_BY_BOOKMARK
);
916 fillNeededData(nRet
);
917 // the driver should not have touched this
918 // (neither the contents of aBookmark FWIW)
919 assert(nRealLen
== aBookmark
.getLength());
923 nRet
= N3SQLSetPos(m_aStatementHandle
,1,SQL_UPDATE
,SQL_LOCK_NO_CHANGE
);
924 fillNeededData(nRet
);
926 OTools::ThrowException(m_pStatement
->getOwnConnection(),nRet
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
927 // unbind all columns so we can fetch all columns again with SQLGetData
928 // (and also so that our buffers don't clobber anything, and
929 // so that a subsequent fetch does not overwrite m_aRow[0])
932 OSL_ENSURE(nRet
== SQL_SUCCESS
,"ODBC insert could not unbind the columns after success");
936 // unbind all columns so that a subsequent fetch does not overwrite m_aRow[0]
938 OSL_ENSURE(nRet
== SQL_SUCCESS
,"ODBC insert could not unbind the columns after failure");
943 void SAL_CALL
OResultSet::deleteRow( )
945 SQLRETURN nRet
= SQL_SUCCESS
;
946 sal_Int32 nPos
= getDriverPos();
947 nRet
= N3SQLSetPos(m_aStatementHandle
,1,SQL_DELETE
,SQL_LOCK_NO_CHANGE
);
948 OTools::ThrowException(m_pStatement
->getOwnConnection(),nRet
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
950 m_bRowDeleted
= ( m_pRowStatusArray
[0] == SQL_ROW_DELETED
);
953 TBookmarkPosMap::iterator aIter
= std::find_if(m_aPosToBookmarks
.begin(), m_aPosToBookmarks
.end(),
954 [&nPos
](const TBookmarkPosMap::value_type
& rEntry
) { return rEntry
.second
== nPos
; });
955 if (aIter
!= m_aPosToBookmarks
.end())
956 m_aPosToBookmarks
.erase(aIter
);
958 if ( m_pSkipDeletedSet
)
959 m_pSkipDeletedSet
->deletePosition(nPos
);
963 void SAL_CALL
OResultSet::cancelRowUpdates( )
968 void SAL_CALL
OResultSet::moveToInsertRow( )
970 ::osl::MutexGuard
aGuard( m_aMutex
);
971 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
975 // first unbound all columns
976 OSL_VERIFY( unbind() == SQL_SUCCESS
);
977 // SQLRETURN nRet = N3SQLSetStmtAttr(m_aStatementHandle,SQL_ATTR_ROW_ARRAY_SIZE ,(SQLPOINTER)1,SQL_IS_INTEGER);
981 void SAL_CALL
OResultSet::moveToCurrentRow( )
986 void OResultSet::updateValue(sal_Int32 columnIndex
, SQLSMALLINT _nType
, void const * _pValue
)
988 ::osl::MutexGuard
aGuard( m_aMutex
);
989 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
991 m_aBindVector
.push_back(allocBindColumn(OTools::MapOdbcType2Jdbc(_nType
),columnIndex
));
992 void* pData
= reinterpret_cast<void*>(m_aBindVector
.rbegin()->first
);
993 OSL_ENSURE(pData
!= nullptr,"Data for update is NULL!");
994 OTools::bindValue( m_pStatement
->getOwnConnection(),
1001 &m_aLengthVector
[columnIndex
],
1004 m_pStatement
->getOwnConnection()->useOldDateFormat());
1007 void SAL_CALL
OResultSet::updateNull( sal_Int32 columnIndex
)
1009 ::osl::MutexGuard
aGuard( m_aMutex
);
1010 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1012 m_aBindVector
.push_back(allocBindColumn(DataType::CHAR
,columnIndex
));
1013 void* pData
= reinterpret_cast<void*>(m_aBindVector
.rbegin()->first
);
1014 OTools::bindValue(m_pStatement
->getOwnConnection(),m_aStatementHandle
,columnIndex
,SQL_CHAR
,0,nullptr,pData
,&m_aLengthVector
[columnIndex
],**this,m_nTextEncoding
,m_pStatement
->getOwnConnection()->useOldDateFormat());
1018 void SAL_CALL
OResultSet::updateBoolean( sal_Int32 columnIndex
, sal_Bool x
)
1020 updateValue(columnIndex
,SQL_BIT
,&x
);
1023 void SAL_CALL
OResultSet::updateByte( sal_Int32 columnIndex
, sal_Int8 x
)
1025 updateValue(columnIndex
,SQL_CHAR
,&x
);
1029 void SAL_CALL
OResultSet::updateShort( sal_Int32 columnIndex
, sal_Int16 x
)
1031 updateValue(columnIndex
,SQL_TINYINT
,&x
);
1034 void SAL_CALL
OResultSet::updateInt( sal_Int32 columnIndex
, sal_Int32 x
)
1036 updateValue(columnIndex
,SQL_INTEGER
,&x
);
1039 void SAL_CALL
OResultSet::updateLong( sal_Int32
/*columnIndex*/, sal_Int64
/*x*/ )
1041 ::dbtools::throwFunctionNotSupportedSQLException( "XRowUpdate::updateLong", *this );
1044 void SAL_CALL
OResultSet::updateFloat( sal_Int32 columnIndex
, float x
)
1046 updateValue(columnIndex
,SQL_REAL
,&x
);
1050 void SAL_CALL
OResultSet::updateDouble( sal_Int32 columnIndex
, double x
)
1052 updateValue(columnIndex
,SQL_DOUBLE
,&x
);
1055 void SAL_CALL
OResultSet::updateString( sal_Int32 columnIndex
, const OUString
& x
)
1057 sal_Int32 nType
= m_aRow
[columnIndex
].getTypeKind();
1058 SQLSMALLINT nOdbcType
= OTools::jdbcTypeToOdbc(nType
);
1059 m_aRow
[columnIndex
] = x
;
1060 m_aRow
[columnIndex
].setTypeKind(nType
); // OJ: otherwise longvarchar will be recognized by fillNeededData
1061 m_aRow
[columnIndex
].setBound(true);
1062 updateValue(columnIndex
,nOdbcType
, &x
);
1065 void SAL_CALL
OResultSet::updateBytes( sal_Int32 columnIndex
, const Sequence
< sal_Int8
>& x
)
1067 sal_Int32 nType
= m_aRow
[columnIndex
].getTypeKind();
1068 SQLSMALLINT nOdbcType
= OTools::jdbcTypeToOdbc(nType
);
1069 m_aRow
[columnIndex
] = x
;
1070 m_aRow
[columnIndex
].setTypeKind(nType
); // OJ: otherwise longvarbinary will be recognized by fillNeededData
1071 m_aRow
[columnIndex
].setBound(true);
1072 updateValue(columnIndex
,nOdbcType
, &x
);
1075 void SAL_CALL
OResultSet::updateDate( sal_Int32 columnIndex
, const Date
& x
)
1077 DATE_STRUCT aVal
= OTools::DateToOdbcDate(x
);
1078 updateValue(columnIndex
,SQL_DATE
,&aVal
);
1082 void SAL_CALL
OResultSet::updateTime( sal_Int32 columnIndex
, const css::util::Time
& x
)
1084 TIME_STRUCT aVal
= OTools::TimeToOdbcTime(x
);
1085 updateValue(columnIndex
,SQL_TIME
,&aVal
);
1089 void SAL_CALL
OResultSet::updateTimestamp( sal_Int32 columnIndex
, const DateTime
& x
)
1091 TIMESTAMP_STRUCT aVal
= OTools::DateTimeToTimestamp(x
);
1092 updateValue(columnIndex
,SQL_TIMESTAMP
,&aVal
);
1096 void SAL_CALL
OResultSet::updateBinaryStream( sal_Int32 columnIndex
, const Reference
< XInputStream
>& x
, sal_Int32 length
)
1099 ::dbtools::throwFunctionSequenceException(*this);
1101 Sequence
<sal_Int8
> aSeq
;
1102 x
->readBytes(aSeq
,length
);
1103 updateBytes(columnIndex
,aSeq
);
1106 void SAL_CALL
OResultSet::updateCharacterStream( sal_Int32 columnIndex
, const Reference
< XInputStream
>& x
, sal_Int32 length
)
1108 updateBinaryStream(columnIndex
,x
,length
);
1111 void SAL_CALL
OResultSet::refreshRow( )
1113 ::osl::MutexGuard
aGuard( m_aMutex
);
1114 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1117 // SQLRETURN nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_REFRESH,SQL_LOCK_NO_CHANGE);
1118 m_nCurrentFetchState
= N3SQLFetchScroll(m_aStatementHandle
,SQL_FETCH_RELATIVE
,0);
1119 OTools::ThrowException(m_pStatement
->getOwnConnection(),m_nCurrentFetchState
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
1122 void SAL_CALL
OResultSet::updateObject( sal_Int32 columnIndex
, const Any
& x
)
1124 if (!::dbtools::implUpdateObject(this, columnIndex
, x
))
1125 throw SQLException();
1129 void SAL_CALL
OResultSet::updateNumericObject( sal_Int32 columnIndex
, const Any
& x
, sal_Int32
/*scale*/ )
1131 if (!::dbtools::implUpdateObject(this, columnIndex
, x
))
1132 throw SQLException();
1136 Any SAL_CALL
OResultSet::getBookmark( )
1139 if(m_aRow
[0].isNull())
1140 throw SQLException();
1141 return m_aRow
[0].makeAny();
1143 Sequence
<sal_Int8
> OResultSet::impl_getBookmark( )
1145 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1147 TBookmarkPosMap::const_iterator aFind
= std::find_if(m_aPosToBookmarks
.begin(),m_aPosToBookmarks
.end(),
1148 [this] (const TBookmarkPosMap::value_type
& bookmarkPos
) {
1149 return bookmarkPos
.second
== m_nRowPos
;
1152 if ( aFind
== m_aPosToBookmarks
.end() )
1154 if ( m_nUseBookmarks
== ODBC_SQL_NOT_DEFINED
)
1156 m_nUseBookmarks
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_USE_BOOKMARKS
);
1158 if(m_nUseBookmarks
== SQL_UB_OFF
)
1159 throw SQLException();
1161 Sequence
<sal_Int8
> bookmark
= OTools::getBytesValue(m_pStatement
->getOwnConnection(),m_aStatementHandle
,0,SQL_C_VARBOOKMARK
,m_bWasNull
,**this);
1162 m_aPosToBookmarks
[bookmark
] = m_nRowPos
;
1163 OSL_ENSURE(bookmark
.getLength(),"Invalid bookmark from length 0!");
1168 return aFind
->first
;
1172 sal_Bool SAL_CALL
OResultSet::moveToBookmark( const Any
& bookmark
)
1174 ::osl::MutexGuard
aGuard( m_aMutex
);
1175 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1178 Sequence
<sal_Int8
> aBookmark
;
1179 bookmark
>>= aBookmark
;
1180 OSL_ENSURE(aBookmark
.getLength(),"Invalid bookmark from length 0!");
1181 if(aBookmark
.getLength())
1183 SQLRETURN nReturn
= setStmtOption
<SQLLEN
*, SQL_IS_POINTER
>(SQL_ATTR_FETCH_BOOKMARK_PTR
, reinterpret_cast<SQLLEN
*>(aBookmark
.getArray()));
1185 if ( SQL_INVALID_HANDLE
!= nReturn
&& SQL_ERROR
!= nReturn
)
1187 m_nCurrentFetchState
= N3SQLFetchScroll(m_aStatementHandle
,SQL_FETCH_BOOKMARK
,0);
1188 OTools::ThrowException(m_pStatement
->getOwnConnection(),m_nCurrentFetchState
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
1189 TBookmarkPosMap::const_iterator aFind
= m_aPosToBookmarks
.find(aBookmark
);
1190 if(aFind
!= m_aPosToBookmarks
.end())
1191 m_nRowPos
= aFind
->second
;
1194 return m_nCurrentFetchState
== SQL_SUCCESS
|| m_nCurrentFetchState
== SQL_SUCCESS_WITH_INFO
;
1200 sal_Bool SAL_CALL
OResultSet::moveRelativeToBookmark( const Any
& bookmark
, sal_Int32 rows
)
1202 ::osl::MutexGuard
aGuard( m_aMutex
);
1203 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1207 Sequence
<sal_Int8
> aBookmark
;
1208 bookmark
>>= aBookmark
;
1209 setStmtOption
<SQLLEN
*, SQL_IS_POINTER
>(SQL_ATTR_FETCH_BOOKMARK_PTR
, reinterpret_cast<SQLLEN
*>(aBookmark
.getArray()));
1211 m_nCurrentFetchState
= N3SQLFetchScroll(m_aStatementHandle
,SQL_FETCH_BOOKMARK
,rows
);
1212 OTools::ThrowException(m_pStatement
->getOwnConnection(),m_nCurrentFetchState
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
1213 return m_nCurrentFetchState
== SQL_SUCCESS
|| m_nCurrentFetchState
== SQL_SUCCESS_WITH_INFO
;
1216 sal_Int32 SAL_CALL
OResultSet::compareBookmarks( const Any
& lhs
, const Any
& rhs
)
1218 ::osl::MutexGuard
aGuard( m_aMutex
);
1219 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1221 return (lhs
== rhs
) ? CompareBookmark::EQUAL
: CompareBookmark::NOT_EQUAL
;
1224 sal_Bool SAL_CALL
OResultSet::hasOrderedBookmarks( )
1229 sal_Int32 SAL_CALL
OResultSet::hashBookmark( const Any
& /*bookmark*/ )
1231 ::dbtools::throwFunctionNotSupportedSQLException( "XRowLocate::hashBookmark", *this );
1236 Sequence
< sal_Int32
> SAL_CALL
OResultSet::deleteRows( const Sequence
< Any
>& rows
)
1238 Sequence
< sal_Int32
> aRet(rows
.getLength());
1239 sal_Int32
*pRet
= aRet
.getArray();
1241 const Any
*pBegin
= rows
.getConstArray();
1242 const Any
*pEnd
= pBegin
+ rows
.getLength();
1244 for(;pBegin
!= pEnd
;++pBegin
,++pRet
)
1248 if(moveToBookmark(*pBegin
))
1254 catch(const SQLException
&)
1262 template < typename T
, SQLINTEGER BufferLength
> T
OResultSet::getStmtOption (SQLINTEGER fOption
) const
1265 OSL_ENSURE(m_aStatementHandle
,"StatementHandle is null!");
1266 N3SQLGetStmtAttr(m_aStatementHandle
, fOption
, &result
, BufferLength
, nullptr);
1269 template < typename T
, SQLINTEGER BufferLength
> SQLRETURN
OResultSet::setStmtOption (SQLINTEGER fOption
, T value
) const
1271 OSL_ENSURE(m_aStatementHandle
,"StatementHandle is null!");
1272 SQLPOINTER sv
= reinterpret_cast<SQLPOINTER
>(value
);
1273 return N3SQLSetStmtAttr(m_aStatementHandle
, fOption
, sv
, BufferLength
);
1276 sal_Int32
OResultSet::getResultSetConcurrency() const
1278 sal_uInt32 nValue
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CONCURRENCY
);
1279 if(SQL_CONCUR_READ_ONLY
== nValue
)
1280 nValue
= ResultSetConcurrency::READ_ONLY
;
1282 nValue
= ResultSetConcurrency::UPDATABLE
;
1287 sal_Int32
OResultSet::getResultSetType() const
1289 sal_uInt32 nValue
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CURSOR_SENSITIVITY
);
1290 if(SQL_SENSITIVE
== nValue
)
1291 nValue
= ResultSetType::SCROLL_SENSITIVE
;
1292 else if(SQL_INSENSITIVE
== nValue
)
1293 nValue
= ResultSetType::SCROLL_INSENSITIVE
;
1296 SQLULEN nCurType
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CURSOR_TYPE
);
1297 if(SQL_CURSOR_KEYSET_DRIVEN
== nCurType
)
1298 nValue
= ResultSetType::SCROLL_SENSITIVE
;
1299 else if(SQL_CURSOR_STATIC
== nCurType
)
1300 nValue
= ResultSetType::SCROLL_INSENSITIVE
;
1301 else if(SQL_CURSOR_FORWARD_ONLY
== nCurType
)
1302 nValue
= ResultSetType::FORWARD_ONLY
;
1303 else if(SQL_CURSOR_DYNAMIC
== nCurType
)
1304 nValue
= ResultSetType::SCROLL_SENSITIVE
;
1309 sal_Int32
OResultSet::getFetchSize() const
1311 return getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_ROW_ARRAY_SIZE
);
1314 OUString
OResultSet::getCursorName() const
1317 SQLSMALLINT nRealLen
= 0;
1318 N3SQLGetCursorName(m_aStatementHandle
,pName
,256,&nRealLen
);
1319 return OUString::createFromAscii(reinterpret_cast<char*>(pName
));
1322 bool OResultSet::isBookmarkable() const
1324 if(!m_aConnectionHandle
)
1327 const SQLULEN nCursorType
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CURSOR_TYPE
);
1329 sal_Int32 nAttr
= 0;
1334 case SQL_CURSOR_FORWARD_ONLY
:
1336 case SQL_CURSOR_STATIC
:
1337 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_STATIC_CURSOR_ATTRIBUTES1
,nAttr
,nullptr);
1339 case SQL_CURSOR_KEYSET_DRIVEN
:
1340 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_KEYSET_CURSOR_ATTRIBUTES1
,nAttr
,nullptr);
1342 case SQL_CURSOR_DYNAMIC
:
1343 OTools::GetInfo(m_pStatement
->getOwnConnection(),m_aConnectionHandle
,SQL_DYNAMIC_CURSOR_ATTRIBUTES1
,nAttr
,nullptr);
1347 catch(const Exception
&)
1352 if ( m_nUseBookmarks
== ODBC_SQL_NOT_DEFINED
)
1354 m_nUseBookmarks
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_USE_BOOKMARKS
);
1357 return (m_nUseBookmarks
!= SQL_UB_OFF
) && (nAttr
& SQL_CA1_BOOKMARK
) == SQL_CA1_BOOKMARK
;
1360 void OResultSet::setFetchDirection(sal_Int32 _par0
)
1362 ::dbtools::throwFunctionNotSupportedSQLException( "setFetchDirection", *this );
1364 OSL_ENSURE(_par0
>0,"Illegal fetch direction!");
1367 setStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_CURSOR_TYPE
, _par0
);
1371 void OResultSet::setFetchSize(sal_Int32 _par0
)
1373 OSL_ENSURE(_par0
>0,"Illegal fetch size!");
1376 throw css::beans::PropertyVetoException("SDBC/ODBC layer not prepared for fetchSize > 1", *this);
1378 setStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_ROW_ARRAY_SIZE
, _par0
);
1379 m_pRowStatusArray
.reset( new SQLUSMALLINT
[_par0
] );
1380 setStmtOption
<SQLUSMALLINT
*, SQL_IS_POINTER
>(SQL_ATTR_ROW_STATUS_PTR
, m_pRowStatusArray
.get());
1383 IPropertyArrayHelper
* OResultSet::createArrayHelper( ) const
1385 Sequence
< Property
> aProps(6);
1386 Property
* pProperties
= aProps
.getArray();
1388 pProperties
[nPos
++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME
),
1389 PROPERTY_ID_CURSORNAME
, cppu::UnoType
<OUString
>::get(), PropertyAttribute::READONLY
);
1391 pProperties
[nPos
++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION
),
1392 PROPERTY_ID_FETCHDIRECTION
, cppu::UnoType
<sal_Int32
>::get(), 0);
1394 pProperties
[nPos
++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE
),
1395 PROPERTY_ID_FETCHSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0);
1397 pProperties
[nPos
++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE
),
1398 PROPERTY_ID_ISBOOKMARKABLE
, cppu::UnoType
<bool>::get(), PropertyAttribute::READONLY
);
1400 pProperties
[nPos
++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY
),
1401 PROPERTY_ID_RESULTSETCONCURRENCY
, cppu::UnoType
<sal_Int32
>::get(), PropertyAttribute::READONLY
);
1403 pProperties
[nPos
++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE
),
1404 PROPERTY_ID_RESULTSETTYPE
, cppu::UnoType
<sal_Int32
>::get(), PropertyAttribute::READONLY
);
1406 return new OPropertyArrayHelper(aProps
);
1409 IPropertyArrayHelper
& OResultSet::getInfoHelper()
1411 return *getArrayHelper();
1414 sal_Bool
OResultSet::convertFastPropertyValue(
1415 Any
& rConvertedValue
,
1422 case PROPERTY_ID_ISBOOKMARKABLE
:
1423 case PROPERTY_ID_CURSORNAME
:
1424 case PROPERTY_ID_RESULTSETCONCURRENCY
:
1425 case PROPERTY_ID_RESULTSETTYPE
:
1426 throw css::lang::IllegalArgumentException();
1427 case PROPERTY_ID_FETCHDIRECTION
:
1428 return ::comphelper::tryPropertyValue(rConvertedValue
, rOldValue
, rValue
, getFetchDirection());
1429 case PROPERTY_ID_FETCHSIZE
:
1430 return ::comphelper::tryPropertyValue(rConvertedValue
, rOldValue
, rValue
, getFetchSize());
1437 void OResultSet::setFastPropertyValue_NoBroadcast(
1444 case PROPERTY_ID_ISBOOKMARKABLE
:
1445 case PROPERTY_ID_CURSORNAME
:
1446 case PROPERTY_ID_RESULTSETCONCURRENCY
:
1447 case PROPERTY_ID_RESULTSETTYPE
:
1448 throw Exception("cannot set prop " + OUString::number(nHandle
), nullptr);
1449 case PROPERTY_ID_FETCHDIRECTION
:
1450 setFetchDirection(getINT32(rValue
));
1452 case PROPERTY_ID_FETCHSIZE
:
1453 setFetchSize(getINT32(rValue
));
1460 void OResultSet::getFastPropertyValue(
1467 case PROPERTY_ID_ISBOOKMARKABLE
:
1468 rValue
<<= isBookmarkable();
1470 case PROPERTY_ID_CURSORNAME
:
1471 rValue
<<= getCursorName();
1473 case PROPERTY_ID_RESULTSETCONCURRENCY
:
1474 rValue
<<= getResultSetConcurrency();
1476 case PROPERTY_ID_RESULTSETTYPE
:
1477 rValue
<<= getResultSetType();
1479 case PROPERTY_ID_FETCHDIRECTION
:
1480 rValue
<<= getFetchDirection();
1482 case PROPERTY_ID_FETCHSIZE
:
1483 rValue
<<= getFetchSize();
1488 void OResultSet::fillColumn(const sal_Int32 _nColumn
)
1490 ensureCacheForColumn(_nColumn
);
1492 if (m_aRow
[_nColumn
].isBound())
1496 if(m_bFetchDataInOrder
)
1498 // m_aRow necessarily has a prefix of bound values, then all unbound values
1499 // EXCEPT for column 0
1500 // so use binary search to find the earliest unbound value before or at _nColumn
1502 sal_Int32 upper
=_nColumn
;
1504 while (lower
< upper
)
1506 const sal_Int32 middle
=(upper
-lower
)/2 + lower
;
1507 if(m_aRow
[middle
].isBound())
1524 TDataRow::iterator pColumn
= m_aRow
.begin() + curCol
;
1525 const TDataRow::const_iterator pColumnEnd
= m_aRow
.begin() + _nColumn
+ 1;
1531 *pColumn
=impl_getBookmark();
1533 catch (SQLException
&)
1537 pColumn
->setBound(true);
1542 for (; pColumn
!= pColumnEnd
; ++curCol
, ++pColumn
)
1544 const sal_Int32 nType
= pColumn
->getTypeKind();
1547 case DataType::CHAR
:
1548 case DataType::VARCHAR
:
1549 case DataType::DECIMAL
:
1550 case DataType::NUMERIC
:
1551 case DataType::LONGVARCHAR
:
1552 case DataType::CLOB
:
1553 *pColumn
=impl_getString(curCol
);
1555 case DataType::FLOAT
:
1556 *pColumn
= impl_getValue
<float>(curCol
, SQL_C_FLOAT
);
1558 case DataType::REAL
:
1559 case DataType::DOUBLE
:
1560 *pColumn
= impl_getValue
<double>(curCol
, SQL_C_DOUBLE
);
1562 case DataType::BINARY
:
1563 case DataType::VARBINARY
:
1564 case DataType::LONGVARBINARY
:
1565 case DataType::BLOB
:
1566 *pColumn
= impl_getBytes(curCol
);
1568 case DataType::DATE
:
1569 *pColumn
= impl_getDate(curCol
);
1571 case DataType::TIME
:
1572 *pColumn
= impl_getTime(curCol
);
1574 case DataType::TIMESTAMP
:
1575 *pColumn
= impl_getTimestamp(curCol
);
1578 *pColumn
= impl_getBoolean(curCol
);
1580 case DataType::TINYINT
:
1581 *pColumn
= impl_getValue
<sal_Int8
>(curCol
, SQL_C_TINYINT
);
1583 case DataType::SMALLINT
:
1584 *pColumn
= impl_getValue
<sal_Int16
>(curCol
, SQL_C_SHORT
);
1586 case DataType::INTEGER
:
1587 *pColumn
= impl_getValue
<sal_Int32
>(curCol
, SQL_C_LONG
);
1589 case DataType::BIGINT
:
1590 *pColumn
= impl_getLong(curCol
);
1593 SAL_WARN( "connectivity.odbc","Unknown DataType");
1598 pColumn
->setBound(true);
1599 if(nType
!= pColumn
->getTypeKind())
1601 pColumn
->setTypeKind(nType
);
1606 void SAL_CALL
OResultSet::acquire() throw()
1608 OResultSet_BASE::acquire();
1611 void SAL_CALL
OResultSet::release() throw()
1613 OResultSet_BASE::release();
1616 css::uno::Reference
< css::beans::XPropertySetInfo
> SAL_CALL
OResultSet::getPropertySetInfo( )
1618 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
1621 bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition
, sal_Int32 _nOffset
, bool /*_bRetrieveData*/)
1623 SQLSMALLINT nFetchOrientation
= SQL_FETCH_NEXT
;
1624 switch(_eCursorPosition
)
1626 case IResultSetHelper::NEXT
:
1627 nFetchOrientation
= SQL_FETCH_NEXT
;
1629 case IResultSetHelper::PRIOR
:
1630 nFetchOrientation
= SQL_FETCH_PRIOR
;
1632 case IResultSetHelper::FIRST
:
1633 nFetchOrientation
= SQL_FETCH_FIRST
;
1635 case IResultSetHelper::LAST
:
1636 nFetchOrientation
= SQL_FETCH_LAST
;
1638 case IResultSetHelper::RELATIVE1
:
1639 nFetchOrientation
= SQL_FETCH_RELATIVE
;
1641 case IResultSetHelper::ABSOLUTE1
:
1642 nFetchOrientation
= SQL_FETCH_ABSOLUTE
;
1644 case IResultSetHelper::BOOKMARK
: // special case here because we are only called with position numbers
1646 TBookmarkPosMap::const_iterator aIter
= std::find_if(m_aPosToBookmarks
.begin(), m_aPosToBookmarks
.end(),
1647 [&_nOffset
](const TBookmarkPosMap::value_type
& rEntry
) { return rEntry
.second
== _nOffset
; });
1648 if (aIter
!= m_aPosToBookmarks
.end())
1649 return moveToBookmark(makeAny(aIter
->first
));
1650 SAL_WARN( "connectivity.odbc", "Bookmark not found!");
1658 SQLRETURN nOldFetchStatus
= m_nCurrentFetchState
;
1659 // TODO FIXME: both of these will misbehave for
1660 // _eCursorPosition == IResultSetHelper::NEXT/PREVIOUS
1661 // when fetchSize > 1
1662 if ( !m_bUseFetchScroll
&& _eCursorPosition
== IResultSetHelper::NEXT
)
1663 m_nCurrentFetchState
= N3SQLFetch(m_aStatementHandle
);
1665 m_nCurrentFetchState
= N3SQLFetchScroll(m_aStatementHandle
,nFetchOrientation
,_nOffset
);
1668 "connectivity.odbc",
1669 "move(" << nFetchOrientation
<< "," << _nOffset
<< "), FetchState = "
1670 << m_nCurrentFetchState
);
1671 OTools::ThrowException(m_pStatement
->getOwnConnection(),m_nCurrentFetchState
,m_aStatementHandle
,SQL_HANDLE_STMT
,*this);
1673 const bool bSuccess
= m_nCurrentFetchState
== SQL_SUCCESS
|| m_nCurrentFetchState
== SQL_SUCCESS_WITH_INFO
;
1676 switch(_eCursorPosition
)
1678 case IResultSetHelper::NEXT
:
1681 case IResultSetHelper::PRIOR
:
1684 case IResultSetHelper::FIRST
:
1687 case IResultSetHelper::LAST
:
1690 case IResultSetHelper::RELATIVE1
:
1691 m_nRowPos
+= _nOffset
;
1693 case IResultSetHelper::ABSOLUTE1
:
1694 case IResultSetHelper::BOOKMARK
: // special case here because we are only called with position numbers
1695 m_nRowPos
= _nOffset
;
1697 } // switch(_eCursorPosition)
1698 if ( m_nUseBookmarks
== ODBC_SQL_NOT_DEFINED
)
1700 m_nUseBookmarks
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_USE_BOOKMARKS
);
1702 if ( m_nUseBookmarks
== SQL_UB_OFF
)
1704 m_aRow
[0].setNull();
1708 ensureCacheForColumn(0);
1709 Sequence
<sal_Int8
> bookmark
= OTools::getBytesValue(m_pStatement
->getOwnConnection(),m_aStatementHandle
,0,SQL_C_VARBOOKMARK
,m_bWasNull
,**this);
1710 m_aPosToBookmarks
[bookmark
] = m_nRowPos
;
1711 OSL_ENSURE(bookmark
.getLength(),"Invalid bookmark from length 0!");
1712 m_aRow
[0] = bookmark
;
1714 m_aRow
[0].setBound(true);
1716 else if ( IResultSetHelper::PRIOR
== _eCursorPosition
&& m_nCurrentFetchState
== SQL_NO_DATA
)
1717 // we went beforeFirst
1719 else if(IResultSetHelper::NEXT
== _eCursorPosition
&& m_nCurrentFetchState
== SQL_NO_DATA
&& nOldFetchStatus
!= SQL_NO_DATA
)
1720 // we went afterLast
1726 sal_Int32
OResultSet::getDriverPos() const
1728 sal_Int32 nValue
= getStmtOption
<SQLULEN
, SQL_IS_UINTEGER
>(SQL_ATTR_ROW_NUMBER
);
1730 "connectivity.odbc",
1731 "RowNum = " << nValue
<< ", RowPos = " << m_nRowPos
);
1732 return nValue
? nValue
: m_nRowPos
;
1735 bool OResultSet::isRowDeleted() const
1737 return m_pRowStatusArray
[0] == SQL_ROW_DELETED
;
1740 bool OResultSet::moveImpl(IResultSetHelper::Movement _eCursorPosition
, sal_Int32 _nOffset
)
1742 ::osl::MutexGuard
aGuard( m_aMutex
);
1743 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
1744 return (m_pSkipDeletedSet
!= nullptr)
1745 ? m_pSkipDeletedSet
->skipDeleted(_eCursorPosition
,_nOffset
,true/*_bRetrieveData*/)
1746 : move(_eCursorPosition
,_nOffset
,true/*_bRetrieveData*/);
1749 void OResultSet::fillNeededData(SQLRETURN _nRet
)
1751 SQLRETURN nRet
= _nRet
;
1752 if( nRet
== SQL_NEED_DATA
)
1754 void* pColumnIndex
= nullptr;
1755 nRet
= N3SQLParamData(m_aStatementHandle
,&pColumnIndex
);
1759 if (nRet
!= SQL_SUCCESS
&& nRet
!= SQL_SUCCESS_WITH_INFO
&& nRet
!= SQL_NEED_DATA
)
1762 sal_IntPtr
nColumnIndex ( reinterpret_cast<sal_IntPtr
>(pColumnIndex
));
1763 Sequence
< sal_Int8
> aSeq
;
1764 switch(m_aRow
[nColumnIndex
].getTypeKind())
1766 case DataType::BINARY
:
1767 case DataType::VARBINARY
:
1768 case DataType::LONGVARBINARY
:
1769 case DataType::BLOB
:
1770 aSeq
= m_aRow
[nColumnIndex
];
1771 N3SQLPutData (m_aStatementHandle
, aSeq
.getArray(), aSeq
.getLength());
1773 case SQL_WLONGVARCHAR
:
1775 OUString
const & sRet
= m_aRow
[nColumnIndex
].getString();
1776 N3SQLPutData (m_aStatementHandle
, static_cast<SQLPOINTER
>(const_cast<sal_Unicode
*>(sRet
.getStr())), sizeof(sal_Unicode
)*sRet
.getLength());
1779 case DataType::LONGVARCHAR
:
1780 case DataType::CLOB
:
1782 OUString sRet
= m_aRow
[nColumnIndex
].getString();
1783 OString
aString(OUStringToOString(sRet
,m_nTextEncoding
));
1784 N3SQLPutData (m_aStatementHandle
, static_cast<SQLPOINTER
>(const_cast<char *>(aString
.getStr())), aString
.getLength());
1788 SAL_WARN( "connectivity.odbc", "Not supported at the moment!");
1790 nRet
= N3SQLParamData(m_aStatementHandle
,&pColumnIndex
);
1792 while (nRet
== SQL_NEED_DATA
);
1796 SWORD
OResultSet::impl_getColumnType_nothrow(sal_Int32 columnIndex
)
1798 std::map
<sal_Int32
,SWORD
>::const_iterator aFind
= m_aODBCColumnTypes
.find(columnIndex
);
1799 if ( aFind
== m_aODBCColumnTypes
.end() )
1800 aFind
= m_aODBCColumnTypes
.emplace(
1802 OResultSetMetaData::getColumnODBCType(m_pStatement
->getOwnConnection(),m_aStatementHandle
,*this,columnIndex
)
1804 return aFind
->second
;
1807 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */