28#include <rtl/ustrbuf.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>
42using namespace ::
cppu;
56OResultSet::OResultSet(Connection* pConnection,
58 const uno::Reference< XInterface >& xStatement,
59 isc_stmt_handle aStatementHandle,
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().");
81 PropertyAttribute::READONLY,
86 PropertyAttribute::READONLY,
91 PropertyAttribute::READONLY,
96 PropertyAttribute::READONLY,
101 PropertyAttribute::READONLY,
102 &m_nResultSetConcurrency,
110OResultSet::~OResultSet()
115sal_Int32 SAL_CALL OResultSet::getRow()
117 MutexGuard aGuard(m_rMutex);
125 MutexGuard aGuard(m_rMutex);
130 ISC_STATUS fetchStat = isc_dsql_fetch(m_statusVector,
138 else if (fetchStat == 100)
140 m_bIsAfterLastRow =
true;
145 SAL_WARN(
"connectivity.firebird",
"Error when fetching data");
152sal_Bool SAL_CALL OResultSet::previous()
159sal_Bool SAL_CALL OResultSet::isLast()
166sal_Bool SAL_CALL OResultSet::isBeforeFirst()
168 MutexGuard aGuard(m_rMutex);
171 return m_currentRow == 0;
174sal_Bool SAL_CALL OResultSet::isAfterLast()
176 MutexGuard aGuard(m_rMutex);
179 return m_bIsAfterLastRow;
182sal_Bool SAL_CALL OResultSet::isFirst()
184 MutexGuard aGuard(m_rMutex);
187 return m_currentRow == 1 && !m_bIsAfterLastRow;
190void SAL_CALL OResultSet::beforeFirst()
192 MutexGuard aGuard(m_rMutex);
195 if (m_currentRow != 0)
200void SAL_CALL OResultSet::afterLast()
202 MutexGuard aGuard(m_rMutex);
205 if (!m_bIsAfterLastRow)
210sal_Bool SAL_CALL OResultSet::first()
212 MutexGuard aGuard(m_rMutex);
215 if (m_currentRow == 0)
219 else if (m_currentRow == 1 && !m_bIsAfterLastRow)
240sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 aRow)
242 MutexGuard aGuard(m_rMutex);
245 if (aRow > m_currentRow)
247 sal_Int32 aIterations = aRow - m_currentRow;
248 return relative(aIterations);
258sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row)
260 MutexGuard aGuard(m_rMutex);
280void OResultSet::checkColumnIndex(sal_Int32 nIndex)
282 MutexGuard aGuard(m_rMutex);
285 if( nIndex < 1 || nIndex > m_fieldCount )
288 "No column " + OUString::number(nIndex),
289 ::dbtools::StandardSQLState::COLUMN_NOT_FOUND,
294void OResultSet::checkRowIndex()
299 if((m_currentRow < 1) || m_bIsAfterLastRow)
303 ::dbtools::StandardSQLState::INVALID_CURSOR_POSITION,
308Any 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());
319sal_Int32 SAL_CALL OResultSet::findColumn(
const OUString& rColumnName)
321 MutexGuard aGuard(m_rMutex);
324 uno::Reference< XResultSetMetaData > xMeta = getMetaData();
325 sal_Int32 nLen = xMeta->getColumnCount();
328 for(i = 1;
i<=nLen; ++
i)
332 if (rColumnName == xMeta->getColumnName(i))
341uno::Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 )
343 MutexGuard aGuard(m_rMutex);
349uno::Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 )
351 MutexGuard aGuard(m_rMutex);
358bool OResultSet::isNull(
const sal_Int32 nColumnIndex)
360 assert(nColumnIndex <= m_fieldCount);
361 XSQLVAR* pVar = m_pSqlda->sqlvar;
363 if (pVar[nColumnIndex-1].sqltype & 1)
365 if (*pVar[nColumnIndex-1].sqlind == -1)
372OUString OResultSet::makeNumericString(
const sal_Int32 nColumnIndex)
375 int nDecimalCount = -(m_pSqlda->sqlvar[nColumnIndex-1].sqlscale);
376 if(nDecimalCount < 0)
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;
393 sRetBuffer.append(
static_cast<sal_Int64
>(nAllDigits / nDecimalCountExp) );
394 if( nDecimalCount > 0)
396 sRetBuffer.append(
'.');
398 sal_Int64 nFractionalPart = nAllDigits % nDecimalCountExp;
401 sal_Int64 nFracTemp = nFractionalPart;
408 int nMissingNulls = nDecimalCount - iCount;
411 for(
int i=0;
i<nMissingNulls;
i++)
413 sRetBuffer.append(
'0');
417 sRetBuffer.append(nFractionalPart);
420 return sRetBuffer.makeStringAndClear();
424T 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);
434 ORowSetValue row = retrieveValue< ORowSetValue >(nColumnIndex, 0);
435 if constexpr ( std::is_same_v<sal_Int64, T> )
437 else if constexpr ( std::is_same_v<sal_Int32, T> )
439 else if constexpr ( std::is_same_v<sal_Int16, T> )
441 else if constexpr ( std::is_same_v<float, T> )
443 else if constexpr ( std::is_same_v<double, T> )
445 else if constexpr ( std::is_same_v<bool, T> )
453ORowSetValue OResultSet::retrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT )
462 int nSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype;
467 if( nSqlSubType == 0 && m_pSqlda->sqlvar[nColumnIndex-1].sqlscale < 0 )
470 switch (m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1)
476 if(nSqlSubType == 1 || nSqlSubType == 2)
478 return getShort(nColumnIndex);
480 if(nSqlSubType == 1 || nSqlSubType == 2)
482 return getInt(nColumnIndex);
486 if(nSqlSubType == 1 || nSqlSubType == 2)
492 return getTimestamp(nColumnIndex);
494 return getTime(nColumnIndex);
496 return getDate(nColumnIndex);
498 if(nSqlSubType == 1 || nSqlSubType == 2)
500 return getLong(nColumnIndex);
517Date OResultSet::retrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT )
519 if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_DATE)
521 ISC_DATE aISCDate = *
reinterpret_cast<ISC_DATE*
>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
524 isc_decode_sql_date(&aISCDate, &aCTime);
526 return Date(aCTime.tm_mday, aCTime.tm_mon + 1, aCTime.tm_year + 1900);
530 return retrieveValue< ORowSetValue >(nColumnIndex, 0).getDate();
535Time OResultSet::retrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT )
537 if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_TIME)
539 ISC_TIME aISCTime = *
reinterpret_cast<ISC_TIME*
>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
542 isc_decode_sql_time(&aISCTime, &aCTime);
548 return Time((aISCTime % ISC_TIME_SECONDS_PRECISION) * (1000000000 / ISC_TIME_SECONDS_PRECISION),
549 aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour,
false);
553 return retrieveValue< ORowSetValue >(nColumnIndex, 0).getTime();
558DateTime OResultSet::retrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT )
560 if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TIMESTAMP)
562 ISC_TIMESTAMP aISCTimestamp = *
reinterpret_cast<ISC_TIMESTAMP*
>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
565 isc_decode_timestamp(&aISCTimestamp, &aCTime);
568 return DateTime((aISCTimestamp.timestamp_time % ISC_TIME_SECONDS_PRECISION) * (1000000000 / ISC_TIME_SECONDS_PRECISION),
574 aCTime.tm_year + 1900,
579 return retrieveValue< ORowSetValue >(nColumnIndex, 0).getDateTime();
584OUString OResultSet::retrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT )
587 int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1;
588 int aSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype;
589 if (aSqlType == SQL_TEXT )
591 return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata,
592 m_pSqlda->sqlvar[nColumnIndex-1].sqllen,
593 RTL_TEXTENCODING_UTF8);
595 else if (aSqlType == SQL_VARYING)
599 sal_uInt16 aLength = *
reinterpret_cast<sal_uInt16*
>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
601 return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata + 2,
602 std::min<sal_Int32>(aLength, m_pSqlda->sqlvar[nColumnIndex-1].sqllen),
603 RTL_TEXTENCODING_UTF8);
605 else if ((aSqlType == SQL_SHORT || aSqlType == SQL_LONG ||
606 aSqlType == SQL_DOUBLE || aSqlType == SQL_INT64)
607 && (aSqlSubType == 1 ||
609 (aSqlSubType == 0 && m_pSqlda->sqlvar[nColumnIndex-1].sqlscale < 0) ) )
615 return makeNumericString<sal_Int16>(nColumnIndex);
617 return makeNumericString<sal_Int32>(nColumnIndex);
621 return makeNumericString<sal_Int64>(nColumnIndex);
627 else if(aSqlType == SQL_BLOB && aSqlSubType ==
static_cast<short>(BlobSubtype::Clob) )
629 uno::Reference<XClob> xClob = getClob(nColumnIndex);
630 return xClob->getSubString( 1, xClob->length() );
634 return retrieveValue< ORowSetValue >(nColumnIndex, 0).getString();
639ISC_QUAD* OResultSet::retrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT nType)
642 if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) !=
nType)
643 throw SQLException();
645 return reinterpret_cast<ISC_QUAD*
>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata);
649T OResultSet::safelyRetrieveValue(
const sal_Int32 nColumnIndex,
const ISC_SHORT nType)
654 checkColumnIndex(nColumnIndex);
657 m_bWasNull = isNull(nColumnIndex);
661 return retrieveValue< T >(nColumnIndex,
nType);
665sal_Bool SAL_CALL OResultSet::wasNull()
667 MutexGuard aGuard(m_rMutex);
674sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 nColumnIndex)
676 return safelyRetrieveValue< bool >(nColumnIndex, SQL_BOOLEAN);
679sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 nColumnIndex)
682 return safelyRetrieveValue< ORowSetValue >(nColumnIndex).getInt8();
685Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes(sal_Int32 nColumnIndex)
688 int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1;
689 if ( aSqlType == SQL_BLOB )
691 Reference< XBlob> xBlob = getBlob(nColumnIndex);
694 const sal_Int64 aBlobLength = xBlob->length();
695 if (aBlobLength > SAL_MAX_INT32)
697 SAL_WARN(
"connectivity.firebird",
"getBytes can't return " << aBlobLength <<
" bytes but only max " << SAL_MAX_INT32);
698 return xBlob->getBytes(1, SAL_MAX_INT32);
700 return xBlob->getBytes(1,
static_cast<sal_Int32
>(aBlobLength));
703 return Sequence< sal_Int8 >();
709 return Sequence< sal_Int8 >();
713sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 columnIndex)
715 return safelyRetrieveValue< sal_Int16 >(columnIndex, SQL_SHORT);
718sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 columnIndex)
720 return safelyRetrieveValue< sal_Int32 >(columnIndex, SQL_LONG);
723sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 columnIndex)
725 return safelyRetrieveValue< sal_Int64 >(columnIndex, SQL_INT64);
728float SAL_CALL OResultSet::getFloat(sal_Int32 columnIndex)
730 return safelyRetrieveValue< float >(columnIndex, SQL_FLOAT);
733double SAL_CALL OResultSet::getDouble(sal_Int32 columnIndex)
735 return safelyRetrieveValue< double >(columnIndex, SQL_DOUBLE);
739OUString SAL_CALL OResultSet::getString(sal_Int32 nIndex)
741 return safelyRetrieveValue< OUString >(nIndex);
744Date SAL_CALL OResultSet::getDate(sal_Int32 nIndex)
746 return safelyRetrieveValue< Date >(nIndex, SQL_TYPE_DATE);
749Time SAL_CALL OResultSet::getTime(sal_Int32 nIndex)
751 return safelyRetrieveValue< css::util::Time >(nIndex, SQL_TYPE_TIME);
754DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 nIndex)
756 return safelyRetrieveValue< DateTime >(nIndex, SQL_TIMESTAMP);
760uno::Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
762 MutexGuard aGuard(m_rMutex);
765 if(!m_xMetaData.is())
766 m_xMetaData =
new OResultSetMetaData(m_pConnection
771uno::Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 )
773 MutexGuard aGuard(m_rMutex);
780uno::Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 columnIndex )
782 MutexGuard aGuard(m_rMutex);
785 int aSqlSubType = m_pSqlda->sqlvar[columnIndex-1].sqlsubtype;
788 "connectivity.firebird",
"wrong subtype, not a textual blob");
790 ISC_QUAD* pBlobID = safelyRetrieveValue< ISC_QUAD* >(columnIndex, SQL_BLOB);
793 return m_pConnection->createClob(pBlobID);
796uno::Reference< XBlob > SAL_CALL OResultSet::getBlob(sal_Int32 columnIndex)
798 MutexGuard aGuard(m_rMutex);
803 ISC_QUAD* pBlobID = safelyRetrieveValue< ISC_QUAD* >(columnIndex, SQL_BLOB);
806 return m_pConnection->createBlob(pBlobID);
810uno::Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 )
812 MutexGuard aGuard(m_rMutex);
819Any SAL_CALL OResultSet::getObject( sal_Int32,
const uno::Reference< css::container::XNameAccess >& )
821 MutexGuard aGuard(m_rMutex);
828void SAL_CALL OResultSet::close()
830 SAL_INFO(
"connectivity.firebird",
"close().");
833 MutexGuard aGuard(m_rMutex);
840uno::Reference< XInterface > SAL_CALL OResultSet::getStatement()
842 MutexGuard aGuard(m_rMutex);
848sal_Bool SAL_CALL OResultSet::rowDeleted()
854sal_Bool SAL_CALL OResultSet::rowInserted()
861sal_Bool SAL_CALL OResultSet::rowUpdated()
868void SAL_CALL OResultSet::refreshRow()
875void SAL_CALL OResultSet::cancel( )
877 MutexGuard aGuard(m_rMutex);
883IPropertyArrayHelper* OResultSet::createArrayHelper()
const
886 describeProperties(aProperties);
887 return new ::cppu::OPropertyArrayHelper(aProperties);
890IPropertyArrayHelper & OResultSet::getInfoHelper()
892 return *getArrayHelper();
895void SAL_CALL OResultSet::acquire() noexcept
897 OResultSet_BASE::acquire();
900void SAL_CALL OResultSet::release() noexcept
902 OResultSet_BASE::release();
905uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
907 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
911OUString SAL_CALL OResultSet::getImplementationName()
913 return "com.sun.star.sdbcx.firebird.ResultSet";
916Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames()
918 return {
"com.sun.star.sdbc.ResultSet",
"com.sun.star.sdbcx.ResultSet"};
921sal_Bool SAL_CALL OResultSet::supportsService(
const OUString& _rServiceName)
PropertiesInfo aProperties
sal_Int32 getInt32() const
sal_Int16 getInt16() const
sal_Int64 getLong() const
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
css::uno::Sequence< T > concatSequences(const css::uno::Sequence< T > &rS1, const Ss &... rSn)
double getDouble(const Any &_rAny)
float getFloat(const Any &_rAny)
OUString getString(const Any &_rAny)
::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier, css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XCloseable, css::sdbc::XColumnLocate, css::lang::XServiceInfo > OResultSet_BASE
sal_Int64 pow10Integer(int nDecimalCount)
void evaluateStatusVector(const ISC_STATUS_ARRAY &rStatusVector, std::u16string_view aCause, const css::uno::Reference< css::uno::XInterface > &_rxContext)
Evaluate a firebird status vector and throw exceptions as necessary.
void checkDisposed(bool _bThrow)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
#define PROPERTY_ID_ISBOOKMARKABLE
#define PROPERTY_ID_RESULTSETTYPE
#define PROPERTY_ID_RESULTSETCONCURRENCY
#define PROPERTY_ID_FETCHSIZE
#define PROPERTY_ID_FETCHDIRECTION
TransliterationModules tm