1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 "ResultSet.hxx"
21 #include "ResultSetMetaData.hxx"
24 #include <comphelper/sequence.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <connectivity/dbexception.hxx>
27 #include <propertyids.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <sal/log.hxx>
30 #include <TConnection.hxx>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/sdbc/DataType.hpp>
34 #include <com/sun/star/sdbc/FetchDirection.hpp>
35 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
36 #include <com/sun/star/sdbc/ResultSetType.hpp>
37 #include <com/sun/star/sdbc/SQLException.hpp>
39 using namespace ::comphelper
;
40 using namespace ::connectivity
;
41 using namespace ::connectivity::firebird
;
42 using namespace ::cppu
;
43 using namespace ::dbtools
;
44 using namespace ::osl
;
46 using namespace ::com::sun::star
;
47 using namespace ::com::sun::star::uno
;
48 using namespace ::com::sun::star::lang
;
49 using namespace ::com::sun::star::beans
;
50 using namespace ::com::sun::star::sdbc
;
51 using namespace ::com::sun::star::sdbcx
;
52 using namespace ::com::sun::star::container
;
53 using namespace ::com::sun::star::io
;
54 using namespace ::com::sun::star::util
;
56 OResultSet::OResultSet(Connection
* pConnection
,
58 const uno::Reference
< XInterface
>& xStatement
,
59 isc_stmt_handle aStatementHandle
,
61 : OResultSet_BASE(rMutex
)
62 , OPropertyContainer(OResultSet_BASE::rBHelper
)
63 , m_bIsBookmarkable(false)
65 , m_nResultSetType(css::sdbc::ResultSetType::FORWARD_ONLY
)
66 , m_nFetchDirection(css::sdbc::FetchDirection::FORWARD
)
67 , m_nResultSetConcurrency(css::sdbc::ResultSetConcurrency::READ_ONLY
)
68 , m_pConnection(pConnection
)
70 , m_xStatement(xStatement
)
72 , m_statementHandle(aStatementHandle
)
75 , m_bIsAfterLastRow(false)
76 , m_fieldCount(pSqlda
? pSqlda
->sqld
: 0)
78 SAL_INFO("connectivity.firebird", "OResultSet().");
79 registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE
),
80 PROPERTY_ID_ISBOOKMARKABLE
,
81 PropertyAttribute::READONLY
,
83 cppu::UnoType
<decltype(m_bIsBookmarkable
)>::get());
84 registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE
),
85 PROPERTY_ID_FETCHSIZE
,
86 PropertyAttribute::READONLY
,
88 cppu::UnoType
<decltype(m_nFetchSize
)>::get());
89 registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE
),
90 PROPERTY_ID_RESULTSETTYPE
,
91 PropertyAttribute::READONLY
,
93 cppu::UnoType
<decltype(m_nResultSetType
)>::get());
94 registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION
),
95 PROPERTY_ID_FETCHDIRECTION
,
96 PropertyAttribute::READONLY
,
98 cppu::UnoType
<decltype(m_nFetchDirection
)>::get());
99 registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY
),
100 PROPERTY_ID_RESULTSETCONCURRENCY
,
101 PropertyAttribute::READONLY
,
102 &m_nResultSetConcurrency
,
103 cppu::UnoType
<decltype(m_nResultSetConcurrency
)>::get());
106 return; // TODO: what?
110 OResultSet::~OResultSet()
114 // ---- XResultSet -- Row retrieval methods ------------------------------------
115 sal_Int32 SAL_CALL
OResultSet::getRow()
117 MutexGuard
aGuard(m_rMutex
);
118 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
123 sal_Bool SAL_CALL
OResultSet::next()
125 MutexGuard
aGuard(m_rMutex
);
126 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
130 ISC_STATUS fetchStat
= isc_dsql_fetch(m_statusVector
,
134 if (fetchStat
== 0) // SUCCESSFUL
138 else if (fetchStat
== 100) // END OF DATASET
140 m_bIsAfterLastRow
= true;
145 SAL_WARN("connectivity.firebird", "Error when fetching data");
146 // Throws sql exception as appropriate
147 evaluateStatusVector(m_statusVector
, u
"isc_dsql_fetch", *this);
152 sal_Bool SAL_CALL
OResultSet::previous()
154 ::dbtools::throwFunctionNotSupportedSQLException("previous not supported in firebird",
159 sal_Bool SAL_CALL
OResultSet::isLast()
161 ::dbtools::throwFunctionNotSupportedSQLException("isLast not supported in firebird",
166 sal_Bool SAL_CALL
OResultSet::isBeforeFirst()
168 MutexGuard
aGuard(m_rMutex
);
169 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
171 return m_currentRow
== 0;
174 sal_Bool SAL_CALL
OResultSet::isAfterLast()
176 MutexGuard
aGuard(m_rMutex
);
177 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
179 return m_bIsAfterLastRow
;
182 sal_Bool SAL_CALL
OResultSet::isFirst()
184 MutexGuard
aGuard(m_rMutex
);
185 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
187 return m_currentRow
== 1 && !m_bIsAfterLastRow
;
190 void SAL_CALL
OResultSet::beforeFirst()
192 MutexGuard
aGuard(m_rMutex
);
193 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
195 if (m_currentRow
!= 0)
196 ::dbtools::throwFunctionNotSupportedSQLException("beforeFirst not supported in firebird",
200 void SAL_CALL
OResultSet::afterLast()
202 MutexGuard
aGuard(m_rMutex
);
203 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
205 if (!m_bIsAfterLastRow
)
206 ::dbtools::throwFunctionNotSupportedSQLException("afterLast not supported in firebird",
210 sal_Bool SAL_CALL
OResultSet::first()
212 MutexGuard
aGuard(m_rMutex
);
213 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
215 if (m_currentRow
== 0)
219 else if (m_currentRow
== 1 && !m_bIsAfterLastRow
)
225 ::dbtools::throwFunctionNotSupportedSQLException("first not supported in firebird",
231 sal_Bool SAL_CALL
OResultSet::last()
233 // We need to iterate past the last row to know when we've passed the last
234 // row, hence we can't actually move to last.
235 ::dbtools::throwFunctionNotSupportedSQLException("last not supported in firebird",
240 sal_Bool SAL_CALL
OResultSet::absolute(sal_Int32 aRow
)
242 MutexGuard
aGuard(m_rMutex
);
243 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
245 if (aRow
> m_currentRow
)
247 sal_Int32 aIterations
= aRow
- m_currentRow
;
248 return relative(aIterations
);
252 ::dbtools::throwFunctionNotSupportedSQLException("absolute not supported in firebird",
258 sal_Bool SAL_CALL
OResultSet::relative(sal_Int32 row
)
260 MutexGuard
aGuard(m_rMutex
);
261 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
274 ::dbtools::throwFunctionNotSupportedSQLException("relative not supported in firebird",
280 void OResultSet::checkColumnIndex(sal_Int32 nIndex
)
282 MutexGuard
aGuard(m_rMutex
);
283 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
285 if( nIndex
< 1 || nIndex
> m_fieldCount
)
287 ::dbtools::throwSQLException(
288 "No column " + OUString::number(nIndex
),
289 ::dbtools::StandardSQLState::COLUMN_NOT_FOUND
,
294 void OResultSet::checkRowIndex()
296 MutexGuard
aGuard(m_rMutex
);
297 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
299 if((m_currentRow
< 1) || m_bIsAfterLastRow
)
301 ::dbtools::throwSQLException(
303 ::dbtools::StandardSQLState::INVALID_CURSOR_POSITION
,
308 Any SAL_CALL
OResultSet::queryInterface( const Type
& rType
)
310 Any aRet
= OPropertySetHelper::queryInterface(rType
);
311 return aRet
.hasValue() ? aRet
: OResultSet_BASE::queryInterface(rType
);
314 Sequence
< Type
> SAL_CALL
OResultSet::getTypes()
316 return concatSequences(OPropertySetHelper::getTypes(), OResultSet_BASE::getTypes());
318 // ---- XColumnLocate ---------------------------------------------------------
319 sal_Int32 SAL_CALL
OResultSet::findColumn(const OUString
& rColumnName
)
321 MutexGuard
aGuard(m_rMutex
);
322 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
324 uno::Reference
< XResultSetMetaData
> xMeta
= getMetaData();
325 sal_Int32 nLen
= xMeta
->getColumnCount();
328 for(i
= 1; i
<=nLen
; ++i
)
330 // We assume case sensitive, otherwise you'd have to test
331 // xMeta->isCaseSensitive and use qualsIgnoreAsciiCase as needed.
332 if (rColumnName
== xMeta
->getColumnName(i
))
336 ::dbtools::throwInvalidColumnException(rColumnName
, *this);
338 return 0; // Never reached
341 uno::Reference
< XInputStream
> SAL_CALL
OResultSet::getBinaryStream( sal_Int32
)
343 MutexGuard
aGuard(m_rMutex
);
344 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
349 uno::Reference
< XInputStream
> SAL_CALL
OResultSet::getCharacterStream( sal_Int32
)
351 MutexGuard
aGuard(m_rMutex
);
352 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
357 // ---- Internal Utilities ---------------------------------------------------
358 bool OResultSet::isNull(const sal_Int32 nColumnIndex
)
360 assert(nColumnIndex
<= m_fieldCount
);
361 XSQLVAR
* pVar
= m_pSqlda
->sqlvar
;
363 if (pVar
[nColumnIndex
-1].sqltype
& 1) // Indicates column may contain null
365 if (*pVar
[nColumnIndex
-1].sqlind
== -1)
371 template <typename T
>
372 OUString
OResultSet::makeNumericString(const sal_Int32 nColumnIndex
)
374 // minus because firebird stores scale as a negative number
375 int nDecimalCount
= -(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqlscale
);
376 if(nDecimalCount
< 0)
378 // scale should be always positive
383 OUStringBuffer sRetBuffer
;
384 T nAllDigits
= *reinterpret_cast<T
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
385 sal_Int64 nDecimalCountExp
= pow10Integer(nDecimalCount
);
389 sRetBuffer
.append('-');
390 nAllDigits
= -nAllDigits
; // abs
393 sRetBuffer
.append(static_cast<sal_Int64
>(nAllDigits
/ nDecimalCountExp
) );
394 if( nDecimalCount
> 0)
396 sRetBuffer
.append('.');
398 sal_Int64 nFractionalPart
= nAllDigits
% nDecimalCountExp
;
400 int iCount
= 0; // digit count
401 sal_Int64 nFracTemp
= nFractionalPart
;
408 int nMissingNulls
= nDecimalCount
- iCount
;
410 // append nulls after dot and before nFractionalPart
411 for(int i
=0; i
<nMissingNulls
; i
++)
413 sRetBuffer
.append('0');
417 sRetBuffer
.append(nFractionalPart
);
420 return sRetBuffer
.makeStringAndClear();
423 template <typename T
>
424 T
OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT nType
)
426 m_bWasNull
= isNull(nColumnIndex
);
430 if ((m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1) == nType
)
431 return *reinterpret_cast<T
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
433 return retrieveValue
< ORowSetValue
>(nColumnIndex
, 0);
437 ORowSetValue
OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT
/*nType*/)
439 // See http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Using_the_getXXX_Methods
440 // (bottom of page) for a chart of possible conversions, we should allow all
441 // of these -- Blob/Clob will probably need some specialist handling especially
442 // w.r.t. to generating Strings for them.
444 // Basically we just have to map to the correct direct request and
445 // ORowSetValue does the rest for us here.
446 int nSqlSubType
= m_pSqlda
->sqlvar
[nColumnIndex
-1].sqlsubtype
;
448 // TODO Firebird 3.0 does not set subtype (i.e. set to 0) for computed numeric/decimal value.
449 // It may change in the future.
450 // Imply numeric data type when subtype is 0 and scale is negative
451 if( nSqlSubType
== 0 && m_pSqlda
->sqlvar
[nColumnIndex
-1].sqlscale
< 0 )
454 switch (m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1)
458 return getString(nColumnIndex
);
460 if(nSqlSubType
== 1 || nSqlSubType
== 2) //numeric or decimal
461 return getString(nColumnIndex
);
462 return getShort(nColumnIndex
);
464 if(nSqlSubType
== 1 || nSqlSubType
== 2) //numeric or decimal
465 return getString(nColumnIndex
);
466 return getInt(nColumnIndex
);
468 return getFloat(nColumnIndex
);
470 if(nSqlSubType
== 1 || nSqlSubType
== 2) //numeric or decimal
471 return getString(nColumnIndex
);
472 return getDouble(nColumnIndex
);
474 return getFloat(nColumnIndex
);
476 return getTimestamp(nColumnIndex
);
478 return getTime(nColumnIndex
);
480 return getDate(nColumnIndex
);
482 if(nSqlSubType
== 1 || nSqlSubType
== 2) //numeric or decimal
483 return getString(nColumnIndex
);
484 return getLong(nColumnIndex
);
486 return ORowSetValue(bool(getBoolean(nColumnIndex
)));
491 // TODO: these are all invalid conversions, so maybe we should
492 // throw an exception?
493 return ORowSetValue();
496 return ORowSetValue();
501 Date
OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT
/*nType*/)
503 if ((m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1) == SQL_TYPE_DATE
)
505 ISC_DATE aISCDate
= *reinterpret_cast<ISC_DATE
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
508 isc_decode_sql_date(&aISCDate
, &aCTime
);
510 return Date(aCTime
.tm_mday
, aCTime
.tm_mon
+ 1, aCTime
.tm_year
+ 1900);
514 return retrieveValue
< ORowSetValue
>(nColumnIndex
, 0);
519 Time
OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT
/*nType*/)
521 if ((m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1) == SQL_TYPE_TIME
)
523 ISC_TIME aISCTime
= *reinterpret_cast<ISC_TIME
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
526 isc_decode_sql_time(&aISCTime
, &aCTime
);
528 // First field is nanoseconds.
529 // last field denotes UTC (true) or unknown (false)
530 // Here we "know" that ISC_TIME is simply in units of seconds/ISC_TIME_SECONDS_PRECISION
531 // with no other funkiness, so we can get the fractional seconds easily.
532 return Time((aISCTime
% ISC_TIME_SECONDS_PRECISION
) * (1000000000 / ISC_TIME_SECONDS_PRECISION
),
533 aCTime
.tm_sec
, aCTime
.tm_min
, aCTime
.tm_hour
, false);
537 return retrieveValue
< ORowSetValue
>(nColumnIndex
, 0);
542 DateTime
OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT
/*nType*/)
544 if ((m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1) == SQL_TIMESTAMP
)
546 ISC_TIMESTAMP aISCTimestamp
= *reinterpret_cast<ISC_TIMESTAMP
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
549 isc_decode_timestamp(&aISCTimestamp
, &aCTime
);
551 // Ditto here, see comment in previous function about ISC_TIME and ISC_TIME_SECONDS_PRECISION.
552 return DateTime((aISCTimestamp
.timestamp_time
% ISC_TIME_SECONDS_PRECISION
) * (1000000000 / ISC_TIME_SECONDS_PRECISION
), //nanoseconds
557 aCTime
.tm_mon
+ 1, // tm is from 0 to 11
558 aCTime
.tm_year
+ 1900, //tm_year is the years since 1900
559 false); // denotes UTC (true), or unknown (false)
563 return retrieveValue
< ORowSetValue
>(nColumnIndex
, 0);
568 OUString
OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT
/*nType*/)
570 // &~1 to remove the "can contain NULL" indicator
571 int aSqlType
= m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1;
572 int aSqlSubType
= m_pSqlda
->sqlvar
[nColumnIndex
-1].sqlsubtype
;
573 if (aSqlType
== SQL_TEXT
)
575 return OUString(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
,
576 m_pSqlda
->sqlvar
[nColumnIndex
-1].sqllen
,
577 RTL_TEXTENCODING_UTF8
);
579 else if (aSqlType
== SQL_VARYING
)
581 // First 2 bytes are a short containing the length of the string
582 // Under unclear conditions, it may be wrong and greater than sqllen.
583 sal_uInt16 aLength
= *reinterpret_cast<sal_uInt16
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
584 // Use greater signed type sal_Int32 to get the minimum of two 16-bit values
585 return OUString(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
+ 2,
586 std::min
<sal_Int32
>(aLength
, m_pSqlda
->sqlvar
[nColumnIndex
-1].sqllen
),
587 RTL_TEXTENCODING_UTF8
);
589 else if ((aSqlType
== SQL_SHORT
|| aSqlType
== SQL_LONG
||
590 aSqlType
== SQL_DOUBLE
|| aSqlType
== SQL_INT64
)
591 && (aSqlSubType
== 1 ||
593 (aSqlSubType
== 0 && m_pSqlda
->sqlvar
[nColumnIndex
-1].sqlscale
< 0) ) )
595 // decimal and numeric types
599 return makeNumericString
<sal_Int16
>(nColumnIndex
);
601 return makeNumericString
<sal_Int32
>(nColumnIndex
);
603 // TODO FIXME 64 bits?
605 return makeNumericString
<sal_Int64
>(nColumnIndex
);
608 return OUString(); // never reached
611 else if(aSqlType
== SQL_BLOB
&& aSqlSubType
== static_cast<short>(BlobSubtype::Clob
) )
613 uno::Reference
<XClob
> xClob
= getClob(nColumnIndex
);
614 return xClob
->getSubString( 0, xClob
->length() );
618 return retrieveValue
< ORowSetValue
>(nColumnIndex
, 0);
623 ISC_QUAD
* OResultSet::retrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT nType
)
625 // TODO: this is probably wrong
626 if ((m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1) != nType
)
627 throw SQLException(); // TODO: better exception (can't convert Blob)
629 return reinterpret_cast<ISC_QUAD
*>(m_pSqlda
->sqlvar
[nColumnIndex
-1].sqldata
);
632 template <typename T
>
633 T
OResultSet::safelyRetrieveValue(const sal_Int32 nColumnIndex
, const ISC_SHORT nType
)
635 MutexGuard
aGuard(m_rMutex
);
636 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
638 checkColumnIndex(nColumnIndex
);
641 m_bWasNull
= isNull(nColumnIndex
);
645 return retrieveValue
< T
>(nColumnIndex
, nType
);
648 // ---- XRow -----------------------------------------------------------------
649 sal_Bool SAL_CALL
OResultSet::wasNull()
651 MutexGuard
aGuard(m_rMutex
);
652 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
657 // ---- XRow: Simple Numerical types ------------------------------------------
658 sal_Bool SAL_CALL
OResultSet::getBoolean(sal_Int32 nColumnIndex
)
660 return safelyRetrieveValue
< bool >(nColumnIndex
, SQL_BOOLEAN
);
663 sal_Int8 SAL_CALL
OResultSet::getByte(sal_Int32 nColumnIndex
)
665 // Not a native firebird type hence we always have to convert.
666 return safelyRetrieveValue
< ORowSetValue
>(nColumnIndex
);
669 Sequence
< sal_Int8
> SAL_CALL
OResultSet::getBytes(sal_Int32 nColumnIndex
)
671 // &~1 to remove the "can contain NULL" indicator
672 int aSqlType
= m_pSqlda
->sqlvar
[nColumnIndex
-1].sqltype
& ~1;
673 if ( aSqlType
== SQL_BLOB
)
675 Reference
< XBlob
> xBlob
= getBlob(nColumnIndex
);
678 const sal_Int64 aBlobLength
= xBlob
->length();
679 if (aBlobLength
> SAL_MAX_INT32
)
681 SAL_WARN("connectivity.firebird", "getBytes can't return " << aBlobLength
<< " bytes but only max " << SAL_MAX_INT32
);
682 return xBlob
->getBytes(1, SAL_MAX_INT32
);
684 return xBlob
->getBytes(1, static_cast<sal_Int32
>(aBlobLength
));
687 return Sequence
< sal_Int8
>();
689 // TODO implement SQL_VARYING and SQL_TEXT
690 // as it's the counterpart as OPreparedStatement::setBytes
693 return Sequence
< sal_Int8
>(); // TODO: implement
697 sal_Int16 SAL_CALL
OResultSet::getShort(sal_Int32 columnIndex
)
699 return safelyRetrieveValue
< sal_Int16
>(columnIndex
, SQL_SHORT
);
702 sal_Int32 SAL_CALL
OResultSet::getInt(sal_Int32 columnIndex
)
704 return safelyRetrieveValue
< sal_Int32
>(columnIndex
, SQL_LONG
);
707 sal_Int64 SAL_CALL
OResultSet::getLong(sal_Int32 columnIndex
)
709 return safelyRetrieveValue
< sal_Int64
>(columnIndex
, SQL_INT64
);
712 float SAL_CALL
OResultSet::getFloat(sal_Int32 columnIndex
)
714 return safelyRetrieveValue
< float >(columnIndex
, SQL_FLOAT
);
717 double SAL_CALL
OResultSet::getDouble(sal_Int32 columnIndex
)
719 return safelyRetrieveValue
< double >(columnIndex
, SQL_DOUBLE
);
722 // ---- XRow: More complex types ----------------------------------------------
723 OUString SAL_CALL
OResultSet::getString(sal_Int32 nIndex
)
725 return safelyRetrieveValue
< OUString
>(nIndex
);
728 Date SAL_CALL
OResultSet::getDate(sal_Int32 nIndex
)
730 return safelyRetrieveValue
< Date
>(nIndex
, SQL_TYPE_DATE
);
733 Time SAL_CALL
OResultSet::getTime(sal_Int32 nIndex
)
735 return safelyRetrieveValue
< css::util::Time
>(nIndex
, SQL_TYPE_TIME
);
738 DateTime SAL_CALL
OResultSet::getTimestamp(sal_Int32 nIndex
)
740 return safelyRetrieveValue
< DateTime
>(nIndex
, SQL_TIMESTAMP
);
744 uno::Reference
< XResultSetMetaData
> SAL_CALL
OResultSet::getMetaData( )
746 MutexGuard
aGuard(m_rMutex
);
747 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
749 if(!m_xMetaData
.is())
750 m_xMetaData
= new OResultSetMetaData(m_pConnection
755 uno::Reference
< XArray
> SAL_CALL
OResultSet::getArray( sal_Int32
)
757 MutexGuard
aGuard(m_rMutex
);
758 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
764 uno::Reference
< XClob
> SAL_CALL
OResultSet::getClob( sal_Int32 columnIndex
)
766 MutexGuard
aGuard(m_rMutex
);
767 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
769 int aSqlSubType
= m_pSqlda
->sqlvar
[columnIndex
-1].sqlsubtype
;
771 SAL_WARN_IF(aSqlSubType
!= 1,
772 "connectivity.firebird", "wrong subtype, not a textual blob");
774 ISC_QUAD
* pBlobID
= safelyRetrieveValue
< ISC_QUAD
* >(columnIndex
, SQL_BLOB
);
777 return m_pConnection
->createClob(pBlobID
);
780 uno::Reference
< XBlob
> SAL_CALL
OResultSet::getBlob(sal_Int32 columnIndex
)
782 MutexGuard
aGuard(m_rMutex
);
783 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
785 // TODO: CLOB etc. should be valid here too, but we probably want some more
786 // cleverness around this.
787 ISC_QUAD
* pBlobID
= safelyRetrieveValue
< ISC_QUAD
* >(columnIndex
, SQL_BLOB
);
790 return m_pConnection
->createBlob(pBlobID
);
794 uno::Reference
< XRef
> SAL_CALL
OResultSet::getRef( sal_Int32
)
796 MutexGuard
aGuard(m_rMutex
);
797 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
803 Any SAL_CALL
OResultSet::getObject( sal_Int32
, const uno::Reference
< css::container::XNameAccess
>& )
805 MutexGuard
aGuard(m_rMutex
);
806 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
812 void SAL_CALL
OResultSet::close()
814 SAL_INFO("connectivity.firebird", "close().");
817 MutexGuard
aGuard(m_rMutex
);
818 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
824 uno::Reference
< XInterface
> SAL_CALL
OResultSet::getStatement()
826 MutexGuard
aGuard(m_rMutex
);
827 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
831 //----- XResultSet: unsupported change detection methods ---------------------
832 sal_Bool SAL_CALL
OResultSet::rowDeleted()
834 ::dbtools::throwFunctionNotSupportedSQLException("rowDeleted not supported in firebird",
838 sal_Bool SAL_CALL
OResultSet::rowInserted()
840 ::dbtools::throwFunctionNotSupportedSQLException("rowInserted not supported in firebird",
845 sal_Bool SAL_CALL
OResultSet::rowUpdated()
847 ::dbtools::throwFunctionNotSupportedSQLException("rowUpdated not supported in firebird",
852 void SAL_CALL
OResultSet::refreshRow()
854 ::dbtools::throwFunctionNotSupportedSQLException("refreshRow not supported in firebird",
859 void SAL_CALL
OResultSet::cancel( )
861 MutexGuard
aGuard(m_rMutex
);
862 checkDisposed(OResultSet_BASE::rBHelper
.bDisposed
);
866 //----- OIdPropertyArrayUsageHelper ------------------------------------------
867 IPropertyArrayHelper
* OResultSet::createArrayHelper() const
869 Sequence
< Property
> aProperties
;
870 describeProperties(aProperties
);
871 return new ::cppu::OPropertyArrayHelper(aProperties
);
874 IPropertyArrayHelper
& OResultSet::getInfoHelper()
876 return *getArrayHelper();
879 void SAL_CALL
OResultSet::acquire() noexcept
881 OResultSet_BASE::acquire();
884 void SAL_CALL
OResultSet::release() noexcept
886 OResultSet_BASE::release();
889 uno::Reference
< css::beans::XPropertySetInfo
> SAL_CALL
OResultSet::getPropertySetInfo( )
891 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
894 // ---- XServiceInfo -----------------------------------------------------------
895 OUString SAL_CALL
OResultSet::getImplementationName()
897 return "com.sun.star.sdbcx.firebird.ResultSet";
900 Sequence
< OUString
> SAL_CALL
OResultSet::getSupportedServiceNames()
902 return {"com.sun.star.sdbc.ResultSet","com.sun.star.sdbcx.ResultSet"};
905 sal_Bool SAL_CALL
OResultSet::supportsService(const OUString
& _rServiceName
)
907 return cppu::supportsService(this, _rServiceName
);
910 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */