/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2 . 0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
#include "sortresult.hxx"
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
#include <com/sun/star/ucb/ListActionType.hpp>
#include <com/sun/star/ucb/XAnyCompare.hpp>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <memory>
using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::io;
using namespace com::sun::star::lang;
using namespace com::sun::star::sdbc;
using namespace com::sun::star::ucb;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
using namespace comphelper;
using namespace cppu;
struct SortInfo
{
bool mbUseOwnCompare;
bool mbAscending;
bool mbCaseSensitive;
sal_Int32 mnColumn;
sal_Int32 mnType;
SortInfo* mpNext;
Reference < XAnyCompare > mxCompareFunction;
};
struct SortListData
{
bool mbModified;
sal_IntPtr mnCurPos;
sal_IntPtr mnOldPos;
explicit SortListData( sal_IntPtr nPos );
};
class SRSPropertySetInfo : public cppu::WeakImplHelper <
XPropertySetInfo >
{
Property maProps[2 ];
private :
public :
SRSPropertySetInfo();
// XPropertySetInfo
virtual Sequence< Property > SAL_CALL getProperties() override;
virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override;
virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
};
SortedResultSet::SortedResultSet( Reference< XResultSet > const & aResult )
{
mxOriginal = aResult;
mpSortInfo = nullptr;
mnLastSort = 0 ;
mnCurEntry = 0 ;
mnCount = 0 ;
mbIsCopy = false ;
}
SortedResultSet::~SortedResultSet()
{
mxOriginal.clear();
mxOther.clear();
if ( !mbIsCopy )
{
SortInfo *pInfo = mpSortInfo;
while ( pInfo )
{
mpSortInfo = pInfo->mpNext;
delete pInfo;
pInfo = mpSortInfo;
}
}
mpSortInfo = nullptr;
mpPropSetInfo.clear();
}
// XServiceInfo methods.
OUString SAL_CALL SortedResultSet::getImplementationName()
{
return u"com.sun.star.comp.ucb.SortedResultSet" _ustr;
}
sal_Bool SAL_CALL SortedResultSet::supportsService( const OUString& ServiceName )
{
return cppu::supportsService( this , ServiceName );
}
css::uno::Sequence< OUString > SAL_CALL SortedResultSet::getSupportedServiceNames()
{
return { RESULTSET_SERVICE_NAME };
}
// XComponent methods.
void SAL_CALL SortedResultSet::dispose()
{
std::unique_lock aGuard( maMutex );
if ( maDisposeEventListeners.getLength(aGuard) )
{
EventObject aEvt;
aEvt.Source = static_cast < XComponent * >( this );
maDisposeEventListeners.disposeAndClear( aGuard, aEvt );
}
if ( maPropChangeListeners.hasContainedTypes(aGuard) )
{
EventObject aEvt;
aEvt.Source = static_cast < XPropertySet * >( this );
maPropChangeListeners.disposeAndClear( aGuard, aEvt );
}
if ( maVetoChangeListeners.hasContainedTypes(aGuard) )
{
EventObject aEvt;
aEvt.Source = static_cast < XPropertySet * >( this );
maVetoChangeListeners.disposeAndClear( aGuard, aEvt );
}
mxOriginal.clear();
mxOther.clear();
}
void SAL_CALL SortedResultSet::addEventListener(
const Reference< XEventListener >& Listener )
{
std::unique_lock aGuard( maMutex );
maDisposeEventListeners.addInterface( aGuard, Listener );
}
void SAL_CALL SortedResultSet::removeEventListener(
const Reference< XEventListener >& Listener )
{
std::unique_lock aGuard( maMutex );
maDisposeEventListeners.removeInterface( aGuard, Listener );
}
// XContentAccess methods.
OUString SAL_CALL
SortedResultSet::queryContentIdentifierString()
{
std::unique_lock aGuard( maMutex );
return Reference< XContentAccess >::query(mxOriginal)->queryContentIdentifierString();
}
Reference< XContentIdentifier > SAL_CALL
SortedResultSet::queryContentIdentifier()
{
std::unique_lock aGuard( maMutex );
return Reference< XContentAccess >::query(mxOriginal)->queryContentIdentifier();
}
Reference< XContent > SAL_CALL
SortedResultSet::queryContent()
{
std::unique_lock aGuard( maMutex );
return Reference< XContentAccess >::query(mxOriginal)->queryContent();
}
// XResultSet methods.
sal_Bool SAL_CALL SortedResultSet::next()
{
std::unique_lock aGuard( maMutex );
mnCurEntry++;
if ( mnCurEntry > 0 )
{
if ( mnCurEntry <= mnCount )
{
sal_Int32 nIndex = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nIndex );
}
else
{
mnCurEntry = mnCount + 1 ;
}
}
return false ;
}
sal_Bool SAL_CALL SortedResultSet::isBeforeFirst()
{
std::unique_lock aGuard( maMutex );
if ( mnCurEntry )
return false ;
else
return true ;
}
sal_Bool SAL_CALL SortedResultSet::isAfterLast()
{
std::unique_lock aGuard( maMutex );
if ( mnCurEntry > mnCount )
return true ;
else
return false ;
}
sal_Bool SAL_CALL SortedResultSet::isFirst()
{
std::unique_lock aGuard( maMutex );
if ( mnCurEntry == 1 )
return true ;
else
return false ;
}
sal_Bool SAL_CALL SortedResultSet::isLast()
{
std::unique_lock aGuard( maMutex );
if ( mnCurEntry == mnCount )
return true ;
else
return false ;
}
void SAL_CALL SortedResultSet::beforeFirst()
{
std::unique_lock aGuard( maMutex );
mnCurEntry = 0 ;
mxOriginal->beforeFirst();
}
void SAL_CALL SortedResultSet::afterLast()
{
std::unique_lock aGuard( maMutex );
mnCurEntry = mnCount+1 ;
mxOriginal->afterLast();
}
sal_Bool SAL_CALL SortedResultSet::first()
{
std::unique_lock aGuard( maMutex );
if ( mnCount )
{
mnCurEntry = 1 ;
sal_Int32 nIndex = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nIndex );
}
else
{
mnCurEntry = 0 ;
return false ;
}
}
sal_Bool SAL_CALL SortedResultSet::last()
{
std::unique_lock aGuard( maMutex );
if ( mnCount )
{
mnCurEntry = mnCount;
sal_Int32 nIndex = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nIndex );
}
else
{
mnCurEntry = 0 ;
return false ;
}
}
sal_Int32 SAL_CALL SortedResultSet::getRow()
{
std::unique_lock aGuard( maMutex );
return mnCurEntry;
}
/**
moves the cursor to the given row number in the result set .
< p > If the row number is positive , the cursor moves to the given row
number with respect to the beginning of the result set . The first
row is row 1 , the second is row 2 , and so on .
< p > If the given row number is negative , the cursor moves to an
absolute row position with respect to the end of the result set .
For example , calling < code > moveToPosition ( - 1 ) < / code > positions the
cursor on the last row , < code > moveToPosition ( - 2 ) < / code > indicates the
next - to - last row , and so on .
< p > An attempt to position the cursor beyond the first / last row in the
result set leaves the cursor before / after the first / last row ,
respectively .
< p > Note : Calling < code > moveToPosition ( 1 ) < / code > is the same
as calling < code > moveToFirst ( ) < / code > . Calling
< code > moveToPosition ( - 1 ) < / code > is the same as calling
< code > moveToLast ( ) < / code > .
@ param row
is the number of rows to move . Could be negative .
@ returns
< TRUE / > if the cursor is on a row ; < FALSE / > otherwise
@ throws SQLException
if a database access error occurs or if row is 0 , or the result set
type is FORWARD_ONLY .
*/
sal_Bool SAL_CALL SortedResultSet::absolute( sal_Int32 row )
{
std::unique_lock aGuard( maMutex );
sal_Int32 nIndex;
if ( row > 0 )
{
if ( row <= mnCount )
{
mnCurEntry = row;
nIndex = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nIndex );
}
else
{
mnCurEntry = mnCount + 1 ;
return false ;
}
}
else if ( row == 0 )
{
throw SQLException();
}
else
{
if ( mnCount + row + 1 > 0 )
{
mnCurEntry = mnCount + row + 1 ;
nIndex = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nIndex );
}
else
{
mnCurEntry = 0 ;
return false ;
}
}
}
/**
moves the cursor a relative number of rows , either positive or negative .
< p >
Attempting to move beyond the first / last row in the result set positions
the cursor before / after the first / last row . Calling
< code > moveRelative ( 0 ) < / code > is valid , but does not change the cursor
position .
< p > Note : Calling < code > moveRelative ( 1 ) < / code > is different from calling
< code > moveNext ( ) < / code > because is makes sense to call
< code > moveNext ( ) < / code > when there is no current row , for example ,
when the cursor is positioned before the first row or after the last
row of the result set .
@ param rows
is the number of rows to move . Could be negative .
@ returns
< TRUE / > if the cursor is on a valid row ; < FALSE / > if it is off
the result set .
@ throws SQLException
if a database access error occurs or if there is no
current row , or the result set type is FORWARD_ONLY .
*/
sal_Bool SAL_CALL SortedResultSet::relative( sal_Int32 rows )
{
std::unique_lock aGuard( maMutex );
if ( ( mnCurEntry <= 0 ) || ( mnCurEntry > mnCount ) )
{
throw SQLException();
}
if ( rows == 0 )
return true ;
sal_Int32 nTmp = mnCurEntry + rows;
if ( nTmp <= 0 )
{
mnCurEntry = 0 ;
return false ;
}
else if ( nTmp > mnCount )
{
mnCurEntry = mnCount + 1 ;
return false ;
}
else
{
mnCurEntry = nTmp;
nTmp = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nTmp );
}
}
/**
moves the cursor to the previous row in the result set .
< p > Note : < code > previous ( ) < / code > is not the same as
< code > relative ( - 1 ) < / code > because it makes sense to call
< code > previous ( ) < / code > when there is no current row .
@ returns < TRUE / > if the cursor is on a valid row ; < FALSE / > if it is off
the result set .
@ throws SQLException
if a database access error occurs or the result set type
is FORWARD_ONLY .
*/
sal_Bool SAL_CALL SortedResultSet::previous()
{
std::unique_lock aGuard( maMutex );
mnCurEntry -= 1 ;
if ( mnCurEntry > 0 )
{
if ( mnCurEntry <= mnCount )
{
sal_Int32 nIndex = maS2O[ mnCurEntry ];
return mxOriginal->absolute( nIndex );
}
}
else
mnCurEntry = 0 ;
return false ;
}
void SAL_CALL SortedResultSet::refreshRow()
{
std::unique_lock aGuard( maMutex );
if ( ( mnCurEntry <= 0 ) || ( mnCurEntry > mnCount ) )
{
throw SQLException();
}
mxOriginal->refreshRow();
}
sal_Bool SAL_CALL SortedResultSet::rowUpdated()
{
std::unique_lock aGuard( maMutex );
if ( ( mnCurEntry <= 0 ) || ( mnCurEntry > mnCount ) )
{
throw SQLException();
}
return mxOriginal->rowUpdated();
}
sal_Bool SAL_CALL SortedResultSet::rowInserted()
{
std::unique_lock aGuard( maMutex );
if ( ( mnCurEntry <= 0 ) || ( mnCurEntry > mnCount ) )
{
throw SQLException();
}
return mxOriginal->rowInserted();
}
sal_Bool SAL_CALL SortedResultSet::rowDeleted()
{
std::unique_lock aGuard( maMutex );
if ( ( mnCurEntry <= 0 ) || ( mnCurEntry > mnCount ) )
{
throw SQLException();
}
return mxOriginal->rowDeleted();
}
Reference< XInterface > SAL_CALL SortedResultSet::getStatement()
{
std::unique_lock aGuard( maMutex );
if ( ( mnCurEntry <= 0 ) || ( mnCurEntry > mnCount ) )
{
throw SQLException();
}
return mxOriginal->getStatement();
}
// XRow methods.
sal_Bool SAL_CALL SortedResultSet::wasNull()
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->wasNull();
}
OUString SAL_CALL SortedResultSet::getString( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getString( columnIndex );
}
sal_Bool SAL_CALL SortedResultSet::getBoolean( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getBoolean( columnIndex );
}
sal_Int8 SAL_CALL SortedResultSet::getByte( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getByte( columnIndex );
}
sal_Int16 SAL_CALL SortedResultSet::getShort( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getShort( columnIndex );
}
sal_Int32 SAL_CALL SortedResultSet::getInt( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getInt( columnIndex );
}
sal_Int64 SAL_CALL SortedResultSet::getLong( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getLong( columnIndex );
}
float SAL_CALL SortedResultSet::getFloat( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getFloat( columnIndex );
}
double SAL_CALL SortedResultSet::getDouble( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getDouble( columnIndex );
}
Sequence< sal_Int8 > SAL_CALL SortedResultSet::getBytes( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getBytes( columnIndex );
}
Date SAL_CALL SortedResultSet::getDate( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getDate( columnIndex );
}
Time SAL_CALL SortedResultSet::getTime( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getTime( columnIndex );
}
DateTime SAL_CALL SortedResultSet::getTimestamp( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getTimestamp( columnIndex );
}
Reference< XInputStream > SAL_CALL
SortedResultSet::getBinaryStream( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getBinaryStream( columnIndex );
}
Reference< XInputStream > SAL_CALL
SortedResultSet::getCharacterStream( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getCharacterStream( columnIndex );
}
Any SAL_CALL SortedResultSet::getObject( sal_Int32 columnIndex,
const Reference< XNameAccess >& typeMap )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getObject( columnIndex,
typeMap);
}
Reference< XRef > SAL_CALL SortedResultSet::getRef( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getRef( columnIndex );
}
Reference< XBlob > SAL_CALL SortedResultSet::getBlob( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getBlob( columnIndex );
}
Reference< XClob > SAL_CALL SortedResultSet::getClob( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getClob( columnIndex );
}
Reference< XArray > SAL_CALL SortedResultSet::getArray( sal_Int32 columnIndex )
{
std::unique_lock aGuard( maMutex );
return Reference< XRow >::query(mxOriginal)->getArray( columnIndex );
}
// XCloseable methods.
void SAL_CALL SortedResultSet::close()
{
std::unique_lock aGuard( maMutex );
Reference< XCloseable >::query(mxOriginal)->close();
}
// XResultSetMetaDataSupplier methods.
Reference< XResultSetMetaData > SAL_CALL SortedResultSet::getMetaData()
{
std::unique_lock aGuard( maMutex );
return Reference< XResultSetMetaDataSupplier >::query(mxOriginal)->getMetaData();
}
// XPropertySet methods.
Reference< XPropertySetInfo > SAL_CALL
SortedResultSet::getPropertySetInfo()
{
std::unique_lock aGuard( maMutex );
if ( !mpPropSetInfo.is() )
{
mpPropSetInfo = new SRSPropertySetInfo();
}
return mpPropSetInfo;
}
void SAL_CALL SortedResultSet::setPropertyValue(
const OUString& PropertyName,
const Any& )
{
if ( PropertyName == "RowCount" || PropertyName == "IsRowCountFinal" )
throw IllegalArgumentException();
else
throw UnknownPropertyException(PropertyName);
}
Any SAL_CALL SortedResultSet::getPropertyValue( const OUString& PropertyName )
{
std::unique_lock aGuard( maMutex );
Any aRet;
if ( PropertyName == "RowCount" )
{
aRet <<= maS2O.Count();
}
else if ( PropertyName == "IsRowCountFinal" )
{
bool bOrgFinal = false ;
Any aOrgRet;
aRet <<= false ;
aOrgRet = Reference< XPropertySet >::query(mxOriginal)->
getPropertyValue( PropertyName );
aOrgRet >>= bOrgFinal;
if ( bOrgFinal )
{
aOrgRet = Reference< XPropertySet >::query(mxOriginal)->
getPropertyValue(u"RowCount" _ustr);
sal_uInt32 nOrgCount = 0 ;
aOrgRet >>= nOrgCount;
if ( nOrgCount == maS2O.Count() )
aRet <<= true ;
}
}
else
throw UnknownPropertyException(PropertyName);
return aRet;
}
void SAL_CALL SortedResultSet::addPropertyChangeListener(
const OUString& PropertyName,
const Reference< XPropertyChangeListener >& Listener )
{
std::unique_lock aGuard( maMutex );
maPropChangeListeners.addInterface( aGuard, PropertyName, Listener );
}
void SAL_CALL SortedResultSet::removePropertyChangeListener(
const OUString& PropertyName,
const Reference< XPropertyChangeListener >& Listener )
{
std::unique_lock aGuard( maMutex );
maPropChangeListeners.removeInterface( aGuard, PropertyName, Listener );
}
void SAL_CALL SortedResultSet::addVetoableChangeListener(
const OUString& PropertyName,
const Reference< XVetoableChangeListener >& Listener )
{
std::unique_lock aGuard( maMutex );
maVetoChangeListeners.addInterface( aGuard, PropertyName, Listener );
}
void SAL_CALL SortedResultSet::removeVetoableChangeListener(
const OUString& PropertyName,
const Reference< XVetoableChangeListener >& Listener )
{
std::unique_lock aGuard( maMutex );
maVetoChangeListeners.removeInterface( aGuard, PropertyName, Listener );
}
// private methods
sal_Int32 SortedResultSet::CompareImpl( const Reference < XResultSet >& xResultOne,
const Reference < XResultSet >& xResultTwo,
sal_Int32 nIndexOne, sal_Int32 nIndexTwo,
SortInfo const * pSortInfo )
{
Reference < XRow > xRowOne( xResultOne, UNO_QUERY );
Reference < XRow > xRowTwo( xResultTwo, UNO_QUERY );
sal_IntPtr nCompare = 0 ;
sal_Int32 nColumn = pSortInfo->mnColumn;
switch ( pSortInfo->mnType )
{
case DataType::BIT :
case DataType::TINYINT :
case DataType::SMALLINT :
case DataType::INTEGER :
{
sal_Int32 aOne = 0 ;
sal_Int32 aTwo = 0 ;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getInt( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getInt( nColumn );
if ( aOne < aTwo )
nCompare = -1 ;
else if ( aOne == aTwo )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
case DataType::BIGINT :
{
sal_Int64 aOne = 0 ;
sal_Int64 aTwo = 0 ;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getLong( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getLong( nColumn );
if ( aOne < aTwo )
nCompare = -1 ;
else if ( aOne == aTwo )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
case DataType::CHAR :
case DataType::VARCHAR :
case DataType::LONGVARCHAR :
{
OUString aOne, aTwo;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getString( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getString( nColumn );
if ( ! pSortInfo->mbCaseSensitive )
{
aOne = aOne.toAsciiLowerCase();
aTwo = aTwo.toAsciiLowerCase();
}
nCompare = aOne.compareTo( aTwo );
break ;
}
case DataType::DATE :
{
Date aOne, aTwo;
sal_Int32 nTmp;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getDate( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getDate( nColumn );
nTmp = static_cast <sal_Int32>(aTwo.Year) - static_cast <sal_Int32>(aOne.Year);
if ( !nTmp ) {
nTmp = static_cast <sal_Int32>(aTwo.Month) - static_cast <sal_Int32>(aOne.Month);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Day) - static_cast <sal_Int32>(aOne.Day);
}
if ( nTmp < 0 )
nCompare = -1 ;
else if ( nTmp == 0 )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
case DataType::TIME :
{
Time aOne, aTwo;
sal_Int32 nTmp;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getTime( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getTime( nColumn );
nTmp = static_cast <sal_Int32>(aTwo.Hours) - static_cast <sal_Int32>(aOne.Hours);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Minutes) - static_cast <sal_Int32>(aOne.Minutes);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Seconds) - static_cast <sal_Int32>(aOne.Seconds);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.NanoSeconds)
- static_cast <sal_Int32>(aOne.NanoSeconds);
if ( nTmp < 0 )
nCompare = -1 ;
else if ( nTmp == 0 )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
case DataType::TIMESTAMP :
{
DateTime aOne, aTwo;
sal_Int32 nTmp;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getTimestamp( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getTimestamp( nColumn );
nTmp = static_cast <sal_Int32>(aTwo.Year) - static_cast <sal_Int32>(aOne.Year);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Month) - static_cast <sal_Int32>(aOne.Month);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Day) - static_cast <sal_Int32>(aOne.Day);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Hours) - static_cast <sal_Int32>(aOne.Hours);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Minutes) - static_cast <sal_Int32>(aOne.Minutes);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.Seconds) - static_cast <sal_Int32>(aOne.Seconds);
if ( !nTmp )
nTmp = static_cast <sal_Int32>(aTwo.NanoSeconds)
- static_cast <sal_Int32>(aOne.NanoSeconds);
if ( nTmp < 0 )
nCompare = -1 ;
else if ( nTmp == 0 )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
case DataType::REAL :
{
float aOne = 0 ;
float aTwo = 0 ;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getFloat( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getFloat( nColumn );
if ( aOne < aTwo )
nCompare = -1 ;
else if ( aOne == aTwo )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
case DataType::FLOAT :
case DataType::DOUBLE :
{
double aOne = 0 ;
double aTwo = 0 ;
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getDouble( nColumn );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getDouble( nColumn );
if ( aOne < aTwo )
nCompare = -1 ;
else if ( aOne == aTwo )
nCompare = 0 ;
else
nCompare = 1 ;
break ;
}
default :
{
OSL_FAIL( "DataType not supported for compare!" );
}
}
return nCompare;
}
sal_Int32 SortedResultSet::CompareImpl( const Reference < XResultSet >& xResultOne,
const Reference < XResultSet >& xResultTwo,
sal_Int32 nIndexOne, sal_Int32 nIndexTwo )
{
sal_IntPtr nCompare = 0 ;
SortInfo* pInfo = mpSortInfo;
while ( !nCompare && pInfo )
{
if ( pInfo->mbUseOwnCompare )
{
nCompare = CompareImpl( xResultOne, xResultTwo,
nIndexOne, nIndexTwo, pInfo );
}
else
{
Any aOne, aTwo;
Reference < XRow > xRowOne =
Reference< XRow >::query( xResultOne );
Reference < XRow > xRowTwo =
Reference< XRow >::query( xResultTwo );
if ( xResultOne->absolute( nIndexOne ) )
aOne = xRowOne->getObject( pInfo->mnColumn, nullptr );
if ( xResultTwo->absolute( nIndexTwo ) )
aTwo = xRowTwo->getObject( pInfo->mnColumn, nullptr );
nCompare = pInfo->mxCompareFunction->compare( aOne, aTwo );
}
if ( ! pInfo->mbAscending )
nCompare = - nCompare;
pInfo = pInfo->mpNext;
}
return nCompare;
}
sal_Int32 SortedResultSet::Compare( SortListData const *pOne,
SortListData const *pTwo )
{
sal_IntPtr nIndexOne;
sal_IntPtr nIndexTwo;
Reference < XResultSet > xResultOne;
Reference < XResultSet > xResultTwo;
if ( pOne->mbModified )
{
xResultOne = mxOther;
nIndexOne = pOne->mnOldPos;
}
else
{
xResultOne = mxOriginal;
nIndexOne = pOne->mnCurPos;
}
if ( pTwo->mbModified )
{
xResultTwo = mxOther;
nIndexTwo = pTwo->mnOldPos;
}
else
{
xResultTwo = mxOriginal;
nIndexTwo = pTwo->mnCurPos;
}
sal_IntPtr nCompare;
nCompare = CompareImpl( xResultOne, xResultTwo,
nIndexOne, nIndexTwo );
return nCompare;
}
sal_Int32 SortedResultSet::FindPos( SortListData const *pEntry,
sal_IntPtr _nStart, sal_IntPtr _nEnd )
{
if ( _nStart > _nEnd )
return _nStart + 1 ;
sal_IntPtr nStart = _nStart;
sal_IntPtr nEnd = _nEnd;
sal_IntPtr nMid = 0 , nCompare = 0 ;
while ( nStart <= nEnd )
{
nMid = ( nEnd - nStart ) / 2 + nStart;
SortListData *pMid = maS2O.GetData( nMid );
nCompare = Compare( pEntry, pMid );
if ( !nCompare )
nCompare = (pEntry != pMid) ? ((pEntry < pMid) ? -1 : 1 ) : 0 ;
if ( nCompare < 0 ) // pEntry < pMid
nEnd = nMid - 1 ;
else
nStart = nMid + 1 ;
}
if ( nCompare < 0 ) // pEntry < pMid
return nMid;
else
return nMid+1 ;
}
void SortedResultSet::PropertyChangedImpl(std::unique_lock<std::mutex>& rGuard, const PropertyChangeEvent& rEvt)
{
if ( !maPropChangeListeners.hasContainedTypes(rGuard) )
return ;
// Notify listeners interested especially in the changed property.
OInterfaceContainerHelper4<XPropertyChangeListener>* pPropsContainer =
maPropChangeListeners.getContainer( rGuard, rEvt.PropertyName );
if ( pPropsContainer )
pPropsContainer->notifyEach( rGuard, &XPropertyChangeListener::propertyChange, rEvt );
// Notify listeners interested in all properties.
pPropsContainer = maPropChangeListeners.getContainer( rGuard, OUString() );
if ( pPropsContainer )
pPropsContainer->notifyEach( rGuard, &XPropertyChangeListener::propertyChange, rEvt );
}
// public methods
void SortedResultSet::CopyData( SortedResultSet *pSource )
{
std::unique_lock aGuard(maMutex);
std::unique_lock aSrcGuard(pSource->maMutex);
const SortedEntryList& rSrcS2O = pSource->maS2O;
sal_IntPtr i, nCount;
maS2O.Clear();
m_O2S.clear();
m_ModList.clear();
maS2O.Insert( nullptr, 0 );
m_O2S.push_back(0 );
nCount = rSrcS2O.Count();
for ( i=1 ; i<nCount; i++ )
{
maS2O.Insert( std::unique_ptr<SortListData>(new SortListData( rSrcS2O[ i ] )), i );
m_O2S.push_back(pSource->m_O2S[i]);
}
mnLastSort = maS2O.Count();
mxOther = pSource->mxOriginal;
if ( !mpSortInfo )
{
mpSortInfo = pSource->mpSortInfo;
mbIsCopy = true ;
}
}
void SortedResultSet::Initialize(
const Sequence < NumberedSortingInfo > &xSortInfo,
const Reference< XAnyCompareFactory > &xCompFactory )
{
BuildSortInfo( mxOriginal, xSortInfo, xCompFactory );
// Insert dummy at pos 0
maS2O.Insert( std::unique_ptr<SortListData>(new SortListData( 0 )), 0 );
sal_IntPtr nIndex = 1 ;
// now fetch all the elements from the original result set,
// get there new position in the sorted result set and insert
// an entry in the sorted to original mapping list
try {
while ( mxOriginal->absolute( nIndex ) )
{
std::unique_ptr<SortListData> pData(new SortListData( nIndex ));
sal_IntPtr nPos = FindPos( pData.get(), 1 , nIndex-1 );
maS2O.Insert( std::move(pData), nPos );
nIndex++;
}
}
catch (const SQLException&)
{
TOOLS_WARN_EXCEPTION("ucb" , "" );
}
// when we have fetched all the elements, we can create the
// original to sorted mapping list from the s2o list
m_O2S.clear();
m_O2S.push_back(0 );
// insert some dummy entries first and replace then
// the entries with the right ones
size_t i;
for ( i=1 ; i<maS2O.Count(); i++ )
m_O2S.push_back(0 );
for ( i=1 ; i<maS2O.Count(); i++ )
m_O2S[maS2O[i]] = i;
mnCount = maS2O.Count() - 1 ;
}
void SortedResultSet::CheckProperties( sal_Int32 nOldCount, bool bWasFinal )
{
std::unique_lock aGuard( maMutex );
if ( !maPropChangeListeners.hasContainedTypes(aGuard) )
return ;
try {
// check for propertyChangeEvents
if ( nOldCount != GetCount() )
{
bool bIsFinal = false ;
PropertyChangeEvent aEvt;
aEvt.PropertyName = "RowCount" ;
aEvt.Further = false ;
aEvt.PropertyHandle = -1 ;
aEvt.OldValue <<= nOldCount;
aEvt.NewValue <<= GetCount();
PropertyChangedImpl(aGuard, aEvt);
OUString aName = u"IsRowCountFinal" _ustr;
Any aRet = getPropertyValue( aName );
if ( (aRet >>= bIsFinal) && bIsFinal != bWasFinal )
{
aEvt.PropertyName = aName;
aEvt.Further = false ;
aEvt.PropertyHandle = -1 ;
aEvt.OldValue <<= bWasFinal;
aEvt.NewValue <<= bIsFinal;
PropertyChangedImpl(aGuard, aEvt);
}
}
}
catch (const UnknownPropertyException&) {}
catch (const WrappedTargetException&) {}
}
void SortedResultSet::InsertNew( sal_Int32 nPos, sal_Int32 nCount )
{
// for all entries in the msS20-list, which are >= nPos, increase by nCount
sal_IntPtr i, nEnd;
nEnd = maS2O.Count();
for ( i=1 ; i<=nEnd; i++ )
{
SortListData *pData = maS2O.GetData( i );
if ( pData->mnCurPos >= nPos )
{
pData->mnCurPos += nCount;
}
}
// and append the new entries at the end of the maS2O-list or insert at the
// position nPos in the maS2O-list
for ( i=0 ; i<nCount; i++ )
{
nEnd += 1 ;
std::unique_ptr<SortListData> pData(new SortListData( nEnd ));
maS2O.Insert( std::move(pData), nEnd ); // Insert( Value, Position )
m_O2S.insert(m_O2S.begin() + nPos + i, nEnd);
}
mnCount += nCount;
}
void SortedResultSet::Remove( sal_Int32 nPos, sal_Int32 nCount, EventList *pEvents )
{
sal_IntPtr nOldLastSort;
// correct mnLastSort first
nOldLastSort = mnLastSort;
if ( nPos <= mnLastSort )
{
if ( nPos + nCount - 1 <= mnLastSort )
mnLastSort -= nCount;
else
mnLastSort = nPos - 1 ;
}
// remove the entries from the lists and correct the positions
// in the original2sorted list
for ( sal_IntPtr i=0 ; i < nCount; i++ )
{
sal_IntPtr nSortPos = m_O2S[nPos];
m_O2S.erase(m_O2S.begin() + nPos);
for (size_t j=1 ; j < m_O2S.size(); ++j)
{
sal_IntPtr nVal = m_O2S[j];
if ( nVal > nSortPos )
{
--nVal;
m_O2S[j] = nVal;
}
}
std::unique_ptr<SortListData> pData = maS2O.Remove( nSortPos );
if ( pData->mbModified )
m_ModList.erase(std::find(m_ModList.begin(), m_ModList.end(), pData.get()));
// generate remove Event, but not for new entries
if ( nSortPos <= nOldLastSort )
pEvents->AddEvent( ListActionType::REMOVED, nSortPos );
}
// correct the positions in the sorted list
for ( sal_uInt32 i=1 ; i<= maS2O.Count(); i++ )
{
SortListData *pData = maS2O.GetData( i );
if ( pData->mnCurPos > nPos )
pData->mnCurPos -= nCount;
}
mnCount -= nCount;
}
void SortedResultSet::Move( sal_Int32 nPos, sal_Int32 nCount, sal_Int32 nOffset )
{
if ( !nOffset )
return ;
sal_IntPtr i, nSortPos, nTo;
SortListData *pData;
for ( i=0 ; i<nCount; i++ )
{
nSortPos = m_O2S[nPos + i];
pData = maS2O.GetData( nSortPos );
pData->mnCurPos += nOffset;
}
if ( nOffset < 0 )
{
for ( i=nPos+nOffset; i<nPos; i++ )
{
nSortPos = m_O2S[i];
pData = maS2O.GetData( nSortPos );
pData->mnCurPos += nCount;
}
}
else
{
sal_IntPtr nStart = nPos + nCount;
sal_IntPtr nEnd = nStart + nOffset;
for ( i=nStart; i<nEnd; i++ )
{
nSortPos = m_O2S[i];
pData = maS2O.GetData( nSortPos );
pData->mnCurPos -= nCount;
}
}
// remember the to be moved entries
std::unique_ptr<sal_IntPtr[]> pTmpArr(new sal_IntPtr[ nCount ]);
for ( i=0 ; i<nCount; i++ )
pTmpArr[i] = m_O2S[nPos + i];
// now move the entries, which are in the way
if ( nOffset < 0 )
{
// be carefully here, because nOffset is negative here, so an
// addition is a subtraction
sal_IntPtr nFrom = nPos - 1 ;
nTo = nPos + nCount - 1 ;
// same for i here
for ( i=0 ; i>nOffset; i-- )
{
sal_IntPtr const nVal = m_O2S[nFrom + i];
m_O2S[nTo + i] = nVal;
}
}
else
{
sal_IntPtr nStart = nPos + nCount;
for ( i=0 ; i<nOffset; i++ )
{
sal_IntPtr const nVal = m_O2S[nStart + i];
m_O2S[nPos + i] = nVal;
}
}
// finally put the remembered entries at their new location
nTo = nPos + nOffset;
for ( i=0 ; i<nCount; i++ )
{
m_O2S[nTo + i] = pTmpArr[i];
}
}
void SortedResultSet::BuildSortInfo(
const Reference< XResultSet >& aResult,
const Sequence < NumberedSortingInfo > &xSortInfo,
const Reference< XAnyCompareFactory > &xCompFactory )
{
Reference < XResultSetMetaDataSupplier > xMeta ( aResult, UNO_QUERY );
if ( ! xMeta.is() )
{
OSL_FAIL( "No MetaData, No Sorting!" );
return ;
}
Reference < XResultSetMetaData > xData = xMeta->getMetaData();
const NumberedSortingInfo *pSortInfo = xSortInfo.getConstArray();
sal_Int32 nColumn;
OUString aPropName;
SortInfo *pInfo;
for ( sal_Int32 i=xSortInfo.getLength(); i > 0 ; )
{
--i;
nColumn = pSortInfo[ i ].ColumnIndex;
aPropName = xData->getColumnName( nColumn );
pInfo = new SortInfo;
if ( xCompFactory.is() )
pInfo->mxCompareFunction = xCompFactory->createAnyCompareByName(
aPropName );
if ( pInfo->mxCompareFunction.is() )
{
pInfo->mbUseOwnCompare = false ;
pInfo->mnType = 0 ;
}
else
{
pInfo->mbUseOwnCompare = true ;
pInfo->mnType = xData->getColumnType( nColumn );
}
pInfo->mnColumn = nColumn;
pInfo->mbAscending = pSortInfo[ i ].Ascending;
pInfo->mbCaseSensitive = xData->isCaseSensitive( nColumn );
pInfo->mpNext = mpSortInfo;
mpSortInfo = pInfo;
}
}
void SortedResultSet::SetChanged( sal_Int32 nPos, sal_Int32 nCount )
{
for ( sal_IntPtr i=0 ; i<nCount; i++ )
{
sal_IntPtr const nSortPos = m_O2S[nPos];
if ( nSortPos < mnLastSort )
{
SortListData *pData = maS2O.GetData( nSortPos );
if ( ! pData->mbModified )
{
pData->mbModified = true ;
m_ModList.push_back(pData);
}
}
nPos += 1 ;
}
}
void SortedResultSet::ResortModified( EventList* pList )
{
sal_IntPtr nCompare, nCurPos, nNewPos;
sal_IntPtr nStart, nEnd, nOffset, nVal;
try {
for (size_t i = 0 ; i < m_ModList.size(); ++i)
{
SortListData *const pData = m_ModList[i];
nCompare = CompareImpl( mxOther, mxOriginal,
pData->mnOldPos, pData->mnCurPos );
pData->mbModified = false ;
if ( nCompare != 0 )
{
nCurPos = m_O2S[pData->mnCurPos];
if ( nCompare < 0 )
{
nNewPos = FindPos( pData, 1 , nCurPos-1 );
nStart = nNewPos;
nEnd = nCurPos;
nOffset = 1 ;
}
else
{
nNewPos = FindPos( pData, nCurPos+1 , mnLastSort );
nStart = nCurPos;
nEnd = mnLastSort;
nOffset = -1 ;
}
if ( nNewPos != nCurPos )
{
// correct the lists!
maS2O.Move( static_cast <sal_uInt32>(nCurPos), nNewPos );
for (size_t j = 1 ; j < m_O2S.size(); ++j)
{
nVal = m_O2S[j];
if ( ( nStart <= nVal ) && ( nVal <= nEnd ) )
{
nVal += nOffset;
m_O2S[j] = nVal;
}
}
m_O2S[pData->mnCurPos] = nNewPos;
ListAction aAction;
aAction.Position = nCurPos;
aAction.Count = 1 ;
aAction.ListActionType = ListActionType::MOVED;
aAction.ActionInfo <<= nNewPos-nCurPos;
pList->Insert( aAction );
}
pList->AddEvent( ListActionType::PROPERTIES_CHANGED, nNewPos );
}
}
}
catch (const SQLException&)
{
TOOLS_WARN_EXCEPTION("ucb" , "" );
}
m_ModList.clear();
}
void SortedResultSet::ResortNew( EventList* pList )
{
sal_IntPtr i, nNewPos, nVal;
try {
for ( i = mnLastSort; i<static_cast <sal_IntPtr>(maS2O.Count()); i++ )
{
SortListData *const pData = m_ModList[i];
nNewPos = FindPos( pData, 1 , mnLastSort );
if ( nNewPos != i )
{
maS2O.Move( static_cast <sal_uInt32>(i), nNewPos );
for (size_t j=1 ; j< m_O2S.size(); ++j)
{
nVal = m_O2S[j];
if ( nVal >= nNewPos )
m_O2S[j] = nVal + 1 ;
}
m_O2S[pData->mnCurPos] = nNewPos;
}
mnLastSort++;
pList->AddEvent( ListActionType::INSERTED, nNewPos );
}
}
catch (const SQLException&)
{
TOOLS_WARN_EXCEPTION("ucb" , "" );
}
}
// SortListData
SortListData::SortListData( sal_IntPtr nPos )
: mbModified(false )
, mnCurPos(nPos)
, mnOldPos(nPos)
{
};
SortedEntryList::SortedEntryList()
{
}
SortedEntryList::~SortedEntryList()
{
}
void SortedEntryList::Clear()
{
maData.clear();
}
void SortedEntryList::Insert( std::unique_ptr<SortListData> pEntry, sal_Int32 nPos )
{
if ( nPos < static_cast <sal_IntPtr>(maData.size()) )
maData.insert( maData.begin() + nPos, std::move(pEntry) );
else
maData.push_back( std::move(pEntry) );
}
void SortedEntryList::Move( sal_Int32 nOldPos, sal_Int32 nNewPos )
{
auto p = std::move(maData[nOldPos]);
maData.erase( maData.begin() + nOldPos );
maData.insert(maData.begin() + nNewPos, std::move(p));
}
std::unique_ptr<SortListData> SortedEntryList::Remove( sal_Int32 nPos )
{
std::unique_ptr<SortListData> pData;
if ( nPos < static_cast <sal_IntPtr>(maData.size()) )
{
pData = std::move(maData[ nPos ]);
maData.erase( maData.begin() + nPos );
}
return pData;
}
SortListData* SortedEntryList::GetData( sal_Int32 nPos )
{
SortListData *pData;
if ( nPos < static_cast <sal_IntPtr>(maData.size()) )
pData = maData[ nPos ].get();
else
pData = nullptr;
return pData;
}
sal_Int32 SortedEntryList::operator [] ( sal_Int32 nPos ) const
{
SortListData *pData;
if ( nPos < static_cast <sal_IntPtr>(maData.size()) )
pData = maData[ nPos ].get();
else
pData = nullptr;
if ( pData )
if ( ! pData->mbModified )
return pData->mnCurPos;
else
{
OSL_FAIL( "SortedEntryList: Can't get value for modified entry!" );
return 0 ;
}
else
{
OSL_FAIL( "SortedEntryList: invalid pos!" );
return 0 ;
}
}
SRSPropertySetInfo::SRSPropertySetInfo()
{
maProps[0 ].Name = "RowCount" ;
maProps[0 ].Handle = -1 ;
maProps[0 ].Type = cppu::UnoType<OUString>::get();
maProps[0 ].Attributes = -1 ;
maProps[1 ].Name = "IsRowCountFinal" ;
maProps[1 ].Handle = -1 ;
maProps[1 ].Type = cppu::UnoType<bool >::get();
maProps[1 ].Attributes = -1 ;
}
// XPropertySetInfo methods.
Sequence< Property > SAL_CALL
SRSPropertySetInfo::getProperties()
{
return Sequence < Property > ( maProps, 2 );
}
Property SAL_CALL
SRSPropertySetInfo::getPropertyByName( const OUString& Name )
{
if ( Name == "RowCount" )
return maProps[0 ];
else if ( Name == "IsRowCountFinal" )
return maProps[1 ];
else
throw UnknownPropertyException(Name);
}
sal_Bool SAL_CALL
SRSPropertySetInfo::hasPropertyByName( const OUString& Name )
{
if ( Name == "RowCount" )
return true ;
else if ( Name == "IsRowCountFinal" )
return true ;
else
return false ;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=98 H=91 G=94
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet am 2026-10-01)
¤
*© Formatika GbR, Deutschland