summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--connectivity/source/commontools/dbtools2.cxx35
-rw-r--r--connectivity/source/commontools/filtermanager.cxx108
-rw-r--r--connectivity/source/commontools/parameters.cxx37
-rw-r--r--dbaccess/source/core/misc/DatabaseDataProvider.cxx2
-rw-r--r--dbaccess/source/ui/browser/brwctrlr.cxx16
-rw-r--r--dbaccess/source/ui/dlg/queryfilter.cxx14
-rw-r--r--dbaccess/source/ui/inc/queryfilter.hxx4
-rw-r--r--forms/source/component/DatabaseForm.cxx42
-rw-r--r--forms/source/inc/frm_strings.hxx1
-rw-r--r--forms/source/inc/property.hxx2
-rw-r--r--forms/source/runtime/formoperations.cxx51
-rw-r--r--forms/source/runtime/formoperations.hxx14
-rw-r--r--include/connectivity/dbtools.hxx39
-rw-r--r--include/connectivity/filtermanager.hxx12
-rw-r--r--include/connectivity/parameters.hxx8
15 files changed, 329 insertions, 56 deletions
diff --git a/connectivity/source/commontools/dbtools2.cxx b/connectivity/source/commontools/dbtools2.cxx
index 3db5b431bd35..43f4aaef2774 100644
--- a/connectivity/source/commontools/dbtools2.cxx
+++ b/connectivity/source/commontools/dbtools2.cxx
@@ -52,6 +52,7 @@ namespace dbtools
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::lang;
@@ -1007,6 +1008,40 @@ OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >&
return OUString();
}
+bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField, bool whenNotFound)
+{
+ OUString sName;
+ _xField->getPropertyValue("Name") >>= sName;
+ Reference< XColumnsSupplier > xColumnsSupplier(_xParser, UNO_QUERY);
+ Reference< css::container::XNameAccess > xCols;
+ if (xColumnsSupplier.is())
+ xCols = xColumnsSupplier->getColumns();
+
+ return isAggregateColumn(xCols, sName, whenNotFound);
+}
+
+bool isAggregateColumn(const Reference< XNameAccess > &_xColumns, const OUString &_sName, bool whenNotFound)
+{
+ if ( _xColumns.is() && _xColumns->hasByName(_sName) )
+ {
+ Reference<XPropertySet> xProp(_xColumns->getByName(_sName),UNO_QUERY);
+ assert(xProp.is());
+ return isAggregateColumn( xProp );
+ }
+ return whenNotFound;
+}
+
+bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
+{
+ bool bAgg(false);
+
+ static const char sAgg[] = "AggregateFunction";
+ if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
+ _xColumn->getPropertyValue(sAgg) >>= bAgg;
+
+ return bAgg;
+}
+
} // namespace dbtools
diff --git a/connectivity/source/commontools/filtermanager.cxx b/connectivity/source/commontools/filtermanager.cxx
index ba2d2df20878..5894872625fa 100644
--- a/connectivity/source/commontools/filtermanager.cxx
+++ b/connectivity/source/commontools/filtermanager.cxx
@@ -62,20 +62,64 @@ namespace dbtools
const OUString& FilterManager::getFilterComponent( FilterComponent _eWhich ) const
{
- return _eWhich == FilterComponent::PublicFilter ? m_aPublicFilterComponent : m_aLinkFilterComponent;
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ return m_aPublicFilterComponent;
+ case FilterComponent::PublicHaving:
+ return m_aPublicHavingComponent;
+ case FilterComponent::LinkFilter:
+ return m_aLinkFilterComponent;
+ case FilterComponent::LinkHaving:
+ return m_aLinkHavingComponent;
+ }
+ assert(false);
+
+ static OUString sErr("#FilterManager::getFilterComponent unknown component#");
+ return sErr;
}
void FilterManager::setFilterComponent( FilterComponent _eWhich, const OUString& _rComponent )
{
- if (_eWhich == FilterComponent::PublicFilter)
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
m_aPublicFilterComponent = _rComponent;
- else
+ break;
+ case FilterComponent::PublicHaving:
+ m_aPublicHavingComponent = _rComponent;
+ break;
+ case FilterComponent::LinkFilter:
m_aLinkFilterComponent = _rComponent;
+ break;
+ case FilterComponent::LinkHaving:
+ m_aLinkHavingComponent = _rComponent;
+ break;
+ }
try
{
- if ( m_xComponentAggregate.is() && (( _eWhich != FilterComponent::PublicFilter ) || m_bApplyPublicFilter ) )
- m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
+ if ( m_xComponentAggregate.is() )
+ {
+ bool propagate(true);
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ propagate = propagate && m_bApplyPublicFilter;
+ SAL_FALLTHROUGH;
+ case FilterComponent::LinkFilter:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
+ break;
+ case FilterComponent::PublicHaving:
+ propagate = propagate && m_bApplyPublicFilter;
+ SAL_FALLTHROUGH;
+ case FilterComponent::LinkHaving:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), makeAny( getComposedHaving() ) );
+ break;
+ }
+ }
}
catch( const Exception& )
{
@@ -93,9 +137,13 @@ namespace dbtools
try
{
- if ( m_xComponentAggregate.is() && !getFilterComponent( FilterComponent::PublicFilter ).isEmpty() )
- { // only if there changed something
- m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
+ if ( m_xComponentAggregate.is())
+ {
+ // only where/if something changed
+ if (!getFilterComponent( FilterComponent::PublicFilter ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), makeAny( getComposedFilter() ) );
+ if (!getFilterComponent( FilterComponent::PublicHaving ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), makeAny( getComposedHaving() ) );
}
}
catch( const Exception& )
@@ -120,7 +168,7 @@ namespace dbtools
}
- bool FilterManager::isThereAtMostOneComponent( OUString& o_singleComponent ) const
+ bool FilterManager::isThereAtMostOneFilterComponent( OUString& o_singleComponent ) const
{
if (m_bApplyPublicFilter) {
if (!m_aPublicFilterComponent.isEmpty() && !m_aLinkFilterComponent.isEmpty())
@@ -143,12 +191,35 @@ namespace dbtools
}
}
+ bool FilterManager::isThereAtMostOneHavingComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicHavingComponent.isEmpty() && !m_aLinkHavingComponent.isEmpty())
+ return false;
+ if (!m_aPublicHavingComponent.isEmpty())
+ o_singleComponent = m_aPublicHavingComponent;
+ else if (!m_aLinkHavingComponent.isEmpty())
+ o_singleComponent = m_aLinkHavingComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkHavingComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkHavingComponent;
+ return true;
+ }
+ }
+
OUString FilterManager::getComposedFilter( ) const
{
// if we have only one non-empty component, then there's no need to compose anything
OUString singleComponent;
- if ( isThereAtMostOneComponent( singleComponent ) )
+ if ( isThereAtMostOneFilterComponent( singleComponent ) )
{
return singleComponent;
}
@@ -161,6 +232,23 @@ namespace dbtools
}
+ OUString FilterManager::getComposedHaving( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneHavingComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicHavingComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkHavingComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
} // namespace dbtools
diff --git a/connectivity/source/commontools/parameters.cxx b/connectivity/source/commontools/parameters.cxx
index 37f6a6bbd2f6..30311ba22aa4 100644
--- a/connectivity/source/commontools/parameters.cxx
+++ b/connectivity/source/commontools/parameters.cxx
@@ -245,7 +245,9 @@ namespace dbtools
void ParameterManager::classifyLinks( const Reference< XNameAccess >& _rxParentColumns,
- const Reference< XNameAccess >& _rxColumns, std::vector< OUString >& _out_rAdditionalFilterComponents )
+ const Reference< XNameAccess >& _rxColumns,
+ std::vector< OUString >& _out_rAdditionalFilterComponents,
+ std::vector< OUString >& _out_rAdditionalHavingComponents )
{
OSL_PRECOND( m_aMasterFields.size() == m_aDetailFields.size(),
"ParameterManager::classifyLinks: master and detail fields should have the same length!" );
@@ -309,7 +311,10 @@ namespace dbtools
aInsertionPos.first->second.eType = ParameterClassification::LinkedByColumnName;
// remember the filter component
- _out_rAdditionalFilterComponents.push_back( sFilterCondition );
+ if (isAggregateColumn(xDetailField))
+ _out_rAdditionalHavingComponents.push_back( sFilterCondition );
+ else
+ _out_rAdditionalFilterComponents.push_back( sFilterCondition );
// remember the new "detail field" for this link
aStrippedDetailFields.push_back( sNewParamName );
@@ -381,7 +386,8 @@ namespace dbtools
// classify the links - depending on what the detail fields in each link pair denotes
std::vector< OUString > aAdditionalFilterComponents;
- classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents );
+ std::vector< OUString > aAdditionalHavingComponents;
+ classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents, aAdditionalHavingComponents );
// did we find links where the detail field refers to a detail column (instead of a parameter name)?
if ( !aAdditionalFilterComponents.empty() )
@@ -401,11 +407,34 @@ namespace dbtools
sAdditionalFilter.append(" )");
}
- // now set this filter at the 's filter manager
+ // now set this filter at the filter manager
_rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkFilter, sAdditionalFilter.makeStringAndClear() );
_rColumnsInLinkDetails = true;
}
+
+ if ( !aAdditionalHavingComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalHaving;
+ for ( std::vector< OUString >::const_iterator aComponent = aAdditionalHavingComponents.begin();
+ aComponent != aAdditionalHavingComponents.end();
+ ++aComponent
+ )
+ {
+ if ( !sAdditionalHaving.isEmpty() )
+ sAdditionalHaving.append(" AND ");
+
+ sAdditionalHaving.append("( ");
+ sAdditionalHaving.append(*aComponent);
+ sAdditionalHaving.append(" )");
+ }
+
+ // now set this having clause at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkHaving, sAdditionalHaving.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
}
catch( const Exception& )
{
diff --git a/dbaccess/source/core/misc/DatabaseDataProvider.cxx b/dbaccess/source/core/misc/DatabaseDataProvider.cxx
index 0d8b9805c033..d3a823b93a80 100644
--- a/dbaccess/source/core/misc/DatabaseDataProvider.cxx
+++ b/dbaccess/source/core/misc/DatabaseDataProvider.cxx
@@ -47,6 +47,8 @@
#include <vector>
#include <list>
+// TODO: update for new HavingClause-aware FilterManager
+
namespace dbaccess
{
using namespace ::com::sun::star;
diff --git a/dbaccess/source/ui/browser/brwctrlr.cxx b/dbaccess/source/ui/browser/brwctrlr.cxx
index af094e97620d..4cc6913b0866 100644
--- a/dbaccess/source/ui/browser/brwctrlr.cxx
+++ b/dbaccess/source/ui/browser/brwctrlr.cxx
@@ -2006,18 +2006,7 @@ void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< Property
break;
// check if the column is a aggregate function
- bool bHaving = false;
- OUString sName;
- xField->getPropertyValue(PROPERTY_NAME) >>= sName;
- Reference< XColumnsSupplier > xColumnsSupplier(m_xParser, UNO_QUERY);
- Reference< css::container::XNameAccess > xCols = xColumnsSupplier.is() ? xColumnsSupplier->getColumns() : Reference< css::container::XNameAccess > ();
- if ( xCols.is() && xCols->hasByName(sName) )
- {
- Reference<XPropertySet> xProp(xCols->getByName(sName),UNO_QUERY);
- static const char sAgg[] = "AggregateFunction";
- if ( xProp->getPropertySetInfo()->hasPropertyByName(sAgg) )
- xProp->getPropertyValue(sAgg) >>= bHaving;
- }
+ const bool bHaving(isAggregateColumn(m_xParser, xField));
Reference< XSingleSelectQueryComposer > xParser = createParser_nothrow();
const OUString sOldFilter = xParser->getFilter();
@@ -2029,7 +2018,8 @@ void SbaXDataBrowserController::Execute(sal_uInt16 nId, const Sequence< Property
// -> completely overwrite it, else append one
if (!bApplied)
{
- DO_SAFE( (bHaving ? xParser->setHavingClause(OUString()) : xParser->setFilter(::OUString())), "SbaXDataBrowserController::Execute : caught an exception while resetting the new filter !" );
+ DO_SAFE( xParser->setFilter( OUString()), "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied filter !" );
+ DO_SAFE( xParser->setHavingClause(OUString()), "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied HAVING clause !" );
}
bool bParserSuccess = false;
diff --git a/dbaccess/source/ui/dlg/queryfilter.cxx b/dbaccess/source/ui/dlg/queryfilter.cxx
index c9678ac2bfda..f7d04f0f0a4b 100644
--- a/dbaccess/source/ui/dlg/queryfilter.cxx
+++ b/dbaccess/source/ui/dlg/queryfilter.cxx
@@ -169,9 +169,10 @@ DlgFilterCrit::DlgFilterCrit(vcl::Window * pParent,
// insert the criteria into the dialog
Sequence<Sequence<PropertyValue > > aValues = m_xQueryComposer->getStructuredFilter();
- fillLines(aValues);
+ int i(0);
+ fillLines(i, aValues);
aValues = m_xQueryComposer->getStructuredHavingClause();
- fillLines(aValues);
+ fillLines(i, aValues);
EnableLines();
@@ -467,7 +468,7 @@ IMPL_LINK( DlgFilterCrit, PredicateLoseFocus, Control&, rControl, void )
}
}
-void DlgFilterCrit::SetLine( sal_uInt16 nIdx,const PropertyValue& _rItem,bool _bOr )
+void DlgFilterCrit::SetLine( int nIdx, const PropertyValue& _rItem, bool _bOr )
{
OUString aStr;
_rItem.Value >>= aStr;
@@ -785,13 +786,13 @@ void DlgFilterCrit::BuildWherePart()
}
}
-void DlgFilterCrit::fillLines(const Sequence<Sequence<PropertyValue > >& _aValues)
+void DlgFilterCrit::fillLines(int &i, const Sequence< Sequence< PropertyValue > >& _aValues)
{
const Sequence<PropertyValue >* pOrIter = _aValues.getConstArray();
const Sequence<PropertyValue >* pOrEnd = pOrIter + _aValues.getLength();
- for(sal_uInt16 i=0;pOrIter != pOrEnd; ++pOrIter)
+ bool bOr(i != 0); // WHERE clause and HAVING clause are always ANDed, nor ORed
+ for(; pOrIter != pOrEnd; ++pOrIter)
{
- bool bOr = true;
const PropertyValue* pAndIter = pOrIter->getConstArray();
const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength();
for(;pAndIter != pAndEnd; ++pAndIter)
@@ -799,6 +800,7 @@ void DlgFilterCrit::fillLines(const Sequence<Sequence<PropertyValue > >& _aValue
SetLine( i++,*pAndIter,bOr);
bOr = false;
}
+ bOr=true;
}
}
diff --git a/dbaccess/source/ui/inc/queryfilter.hxx b/dbaccess/source/ui/inc/queryfilter.hxx
index f7253f1fa76a..5dd72f1e40ef 100644
--- a/dbaccess/source/ui/inc/queryfilter.hxx
+++ b/dbaccess/source/ui/inc/queryfilter.hxx
@@ -94,12 +94,12 @@ namespace dbaui
DECL_LINK( ListSelectHdl, ListBox&, void );
DECL_LINK( ListSelectCompHdl, ListBox&, void );
- void SetLine( sal_uInt16 nIdx,const css::beans::PropertyValue& _rItem,bool _bOr );
+ void SetLine( int nIdx, const css::beans::PropertyValue& _rItem, bool _bOr );
void EnableLines();
sal_Int32 GetOSQLPredicateType( const OUString& _rSelectedPredicate ) const;
static sal_Int32 GetSelectionPos(sal_Int32 eType,const ListBox& rListBox);
bool getCondition(const ListBox& _rField,const ListBox& _rComp,const Edit& _rValue,css::beans::PropertyValue& _rFilter) const;
- void fillLines(const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& _aValues);
+ void fillLines(int &i, const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& _aValues);
css::uno::Reference< css::beans::XPropertySet > getMatchingColumn( const Edit& _rValueInput ) const;
css::uno::Reference< css::beans::XPropertySet > getColumn( const OUString& _rFieldName ) const;
diff --git a/forms/source/component/DatabaseForm.cxx b/forms/source/component/DatabaseForm.cxx
index 925d8a8fa3f2..1aae5d88aa39 100644
--- a/forms/source/component/DatabaseForm.cxx
+++ b/forms/source/component/DatabaseForm.cxx
@@ -1288,7 +1288,7 @@ void ODatabaseForm::describeFixedAndAggregateProperties(
Sequence< Property >& _rProps,
Sequence< Property >& _rAggregateProps ) const
{
- _rProps.realloc( 22 );
+ _rProps.realloc( 23 );
css::beans::Property* pProperties = _rProps.getArray();
if (m_xAggregateSet.is())
@@ -1312,6 +1312,7 @@ void ODatabaseForm::describeFixedAndAggregateProperties(
// (e.g. the ones which result from linking master fields to detail fields
// via column names instead of parameters)
RemoveProperty( _rAggregateProps, PROPERTY_FILTER );
+ RemoveProperty( _rAggregateProps, PROPERTY_HAVINGCLAUSE );
RemoveProperty( _rAggregateProps, PROPERTY_APPLYFILTER );
DECL_IFACE_PROP4( ACTIVE_CONNECTION,XConnection, BOUND, TRANSIENT, MAYBEVOID, CONSTRAINED);
@@ -1322,6 +1323,7 @@ void ODatabaseForm::describeFixedAndAggregateProperties(
DECL_PROP2 ( DATASOURCE, OUString, BOUND, CONSTRAINED );
DECL_PROP3 ( CYCLE, TabulatorCycle, BOUND, MAYBEVOID, MAYBEDEFAULT );
DECL_PROP2 ( FILTER, OUString, BOUND, MAYBEDEFAULT );
+ DECL_PROP2 ( HAVINGCLAUSE, OUString, BOUND, MAYBEDEFAULT );
DECL_BOOL_PROP2 ( INSERTONLY, BOUND, MAYBEDEFAULT );
DECL_PROP1 ( NAVIGATION, NavigationBarMode, BOUND );
DECL_BOOL_PROP1 ( ALLOWADDITIONS, BOUND );
@@ -1464,6 +1466,10 @@ void ODatabaseForm::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter );
break;
+ case PROPERTY_ID_HAVINGCLAUSE:
+ rValue <<= m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving );
+ break;
+
case PROPERTY_ID_APPLYFILTER:
rValue <<= m_aFilterManager.isApplyPublicFilter();
break;
@@ -1546,6 +1552,10 @@ sal_Bool ODatabaseForm::convertFastPropertyValue( Any& rConvertedValue, Any& rOl
bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicFilter ) );
break;
+ case PROPERTY_ID_HAVINGCLAUSE:
+ bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ) );
+ break;
+
case PROPERTY_ID_APPLYFILTER:
bModified = tryPropertyValue( rConvertedValue, rOldValue, rValue, m_aFilterManager.isApplyPublicFilter() );
break;
@@ -1635,6 +1645,14 @@ void ODatabaseForm::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const A
}
break;
+ case PROPERTY_ID_HAVINGCLAUSE:
+ {
+ OUString sNewFilter;
+ rValue >>= sNewFilter;
+ m_aFilterManager.setFilterComponent( FilterManager::FilterComponent::PublicHaving, sNewFilter );
+ }
+ break;
+
case PROPERTY_ID_APPLYFILTER:
{
bool bApply = true;
@@ -1780,6 +1798,13 @@ PropertyState ODatabaseForm::getPropertyStateByHandle(sal_Int32 nHandle)
eState = PropertyState_DIRECT_VALUE;
break;
+ case PROPERTY_ID_HAVINGCLAUSE:
+ if ( m_aFilterManager.getFilterComponent( FilterManager::FilterComponent::PublicHaving ).isEmpty() )
+ eState = PropertyState_DEFAULT_VALUE;
+ else
+ eState = PropertyState_DIRECT_VALUE;
+ break;
+
case PROPERTY_ID_APPLYFILTER:
eState = m_aFilterManager.isApplyPublicFilter() ? PropertyState_DEFAULT_VALUE : PropertyState_DIRECT_VALUE;
break;
@@ -1813,6 +1838,7 @@ void ODatabaseForm::setPropertyToDefaultByHandle(sal_Int32 nHandle)
{
case PROPERTY_ID_INSERTONLY:
case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_HAVINGCLAUSE:
case PROPERTY_ID_APPLYFILTER:
case PROPERTY_ID_NAVIGATION:
case PROPERTY_ID_CYCLE:
@@ -1843,6 +1869,10 @@ Any ODatabaseForm::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
aReturn <<= OUString();
break;
+ case PROPERTY_ID_HAVINGCLAUSE:
+ aReturn <<= OUString();
+ break;
+
case PROPERTY_ID_APPLYFILTER:
aReturn <<= true;
break;
@@ -3741,7 +3771,7 @@ void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutS
OFormComponents::write(_rxOutStream);
// version
- _rxOutStream->writeShort(0x0003);
+ _rxOutStream->writeShort(0x0004);
// Name
_rxOutStream << m_sName;
@@ -3819,10 +3849,13 @@ void SAL_CALL ODatabaseForm::write(const Reference<XObjectOutputStream>& _rxOutS
_rxOutStream->writeShort((sal_Int16)m_eNavigation);
OUString sFilter;
+ OUString sHaving;
OUString sOrder;
if (m_xAggregateSet.is())
{
m_xAggregateSet->getPropertyValue(PROPERTY_FILTER) >>= sFilter;
+ // version 4
+ m_xAggregateSet->getPropertyValue(PROPERTY_HAVINGCLAUSE) >>= sHaving;
m_xAggregateSet->getPropertyValue(PROPERTY_SORT) >>= sOrder;
}
_rxOutStream << sFilter;
@@ -3922,6 +3955,11 @@ void SAL_CALL ODatabaseForm::read(const Reference<XObjectInputStream>& _rxInStre
_rxInStream >> sAggregateProp;
setPropertyValue(PROPERTY_FILTER, makeAny(sAggregateProp));
+ if(nVersion > 3)
+ {
+ _rxInStream >> sAggregateProp;
+ setPropertyValue(PROPERTY_HAVINGCLAUSE, makeAny(sAggregateProp));
+ }
_rxInStream >> sAggregateProp;
if (m_xAggregateSet.is())
diff --git a/forms/source/inc/frm_strings.hxx b/forms/source/inc/frm_strings.hxx
index 868772abc744..790f279b1206 100644
--- a/forms/source/inc/frm_strings.hxx
+++ b/forms/source/inc/frm_strings.hxx
@@ -53,6 +53,7 @@ namespace frm
#define PROPERTY_RELEVANT "Relevant"
#define PROPERTY_ISREADONLY "IsReadOnly"
#define PROPERTY_FILTER "Filter"
+ #define PROPERTY_HAVINGCLAUSE "HavingClause"
#define PROPERTY_WIDTH "Width"
#define PROPERTY_SEARCHABLE "IsSearchable"
#define PROPERTY_MULTILINE "MultiLine"
diff --git a/forms/source/inc/property.hxx b/forms/source/inc/property.hxx
index b5d879a9e7a6..ea2ffca31e5d 100644
--- a/forms/source/inc/property.hxx
+++ b/forms/source/inc/property.hxx
@@ -173,7 +173,7 @@ namespace frm
#define PROPERTY_ID_AUTOINCREMENT (PROPERTY_ID_START +133) // UINT16
// free
#define PROPERTY_ID_FILTER (PROPERTY_ID_START +135) // ::rtl::OUString
- // free
+#define PROPERTY_ID_HAVINGCLAUSE (PROPERTY_ID_START +136) // ::rtl::OUString
#define PROPERTY_ID_QUERY (PROPERTY_ID_START +137) // ::rtl::OUString
#define PROPERTY_ID_DEFAULT_LONG_VALUE (PROPERTY_ID_START +138) // Double
#define PROPERTY_ID_DEFAULT_DATE (PROPERTY_ID_START +139) // UINT32
diff --git a/forms/source/runtime/formoperations.cxx b/forms/source/runtime/formoperations.cxx
index 340b4518f7d9..e5f9df54af20 100644
--- a/forms/source/runtime/formoperations.cxx
+++ b/forms/source/runtime/formoperations.cxx
@@ -307,8 +307,10 @@ namespace frm
case FormFeature::ToggleApplyFilter:
{
OUString sFilter;
- m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
- if ( !sFilter.isEmpty() )
+ OUString sHaving;
+ m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
+ m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
+ if ( ! (sFilter.isEmpty() && sHaving.isEmpty()) )
{
aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
aState.Enabled = !impl_isInsertOnlyForm_throw();
@@ -718,13 +720,15 @@ namespace frm
OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
if ( xProperties.is() )
{
- Sequence< OUString > aNames( 2 );
+ Sequence< OUString > aNames( 3 );
aNames[0] = PROPERTY_FILTER;
- aNames[1] = PROPERTY_SORT;
+ aNames[1] = PROPERTY_HAVINGCLAUSE;
+ aNames[2] = PROPERTY_SORT;
- Sequence< Any> aValues( 2 );
+ Sequence< Any> aValues( 3 );
aValues[0] <<= OUString();
aValues[1] <<= OUString();
+ aValues[2] <<= OUString();
WaitObject aWO( nullptr );
xProperties->setPropertyValues( aNames, aValues );
@@ -1034,6 +1038,11 @@ namespace frm
if ( m_xParser->getFilter() != sNewValue )
m_xParser->setFilter( sNewValue );
}
+ else if ( _rEvent.PropertyName == PROPERTY_HAVINGCLAUSE )
+ {
+ if ( m_xParser->getHavingClause() != sNewValue )
+ m_xParser->setHavingClause( sNewValue );
+ }
else if ( _rEvent.PropertyName == PROPERTY_SORT )
{
_rEvent.NewValue >>= sNewValue;
@@ -1221,14 +1230,17 @@ namespace frm
{
OUString sStatement;
OUString sFilter;
+ OUString sHaving;
OUString sSort;
m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
+ m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
m_xParser->setElementaryQuery( sStatement );
m_xParser->setFilter ( sFilter );
+ m_xParser->setHavingClause ( sHaving );
m_xParser->setOrder ( sSort );
}
@@ -1236,6 +1248,7 @@ namespace frm
// we can keep our parser in sync
m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
+ m_xCursorProperties->addPropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
}
}
@@ -1257,6 +1270,7 @@ namespace frm
if ( m_xParser.is() && m_xCursorProperties.is() )
{
m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
+ m_xCursorProperties->removePropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
}
@@ -1337,7 +1351,9 @@ namespace frm
bool FormOperations::impl_hasFilterOrOrder_throw() const
{
- return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() || !m_xParser->getOrder().isEmpty() );
+ return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() ||
+ !m_xParser->getHavingClause().isEmpty() ||
+ !m_xParser->getOrder().isEmpty() );
}
@@ -1600,21 +1616,27 @@ namespace frm
return;
OUString sOriginalFilter;
- m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
+ OUString sOriginalHaving;
+ m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
+ m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sOriginalHaving;
bool bApplied = true;
m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
// if we have a filter, but it's not applied, then we have to overwrite it, else append one
if ( !bApplied )
+ {
m_xParser->setFilter( OUString() );
+ m_xParser->setHavingClause( OUString() );
+ }
- impl_appendFilterByColumn_throw aAction(this, xBoundField);
+ impl_appendFilterByColumn_throw aAction(this, m_xParser, xBoundField);
impl_doActionInSQLContext_throw( aAction, RID_STR_COULD_NOT_SET_FILTER );
WaitObject aWO( nullptr );
try
{
- m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( true ) );
m_xLoadableForm->reload();
@@ -1629,9 +1651,11 @@ namespace frm
{ // something went wrong -> restore the original state
try
{
- m_xParser->setOrder( sOriginalFilter );
+ m_xParser->setFilter ( sOriginalFilter );
+ m_xParser->setHavingClause( sOriginalHaving );
m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( bApplied ) );
- m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
m_xLoadableForm->reload();
}
catch( const Exception& )
@@ -1678,7 +1702,10 @@ namespace frm
{
WaitObject aWO( nullptr );
if ( _bFilter )
- m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
+ {
+ m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
+ m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
+ }
else
m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
m_xLoadableForm->reload();
diff --git a/forms/source/runtime/formoperations.hxx b/forms/source/runtime/formoperations.hxx
index 425e789f8419..ad1494fecf64 100644
--- a/forms/source/runtime/formoperations.hxx
+++ b/forms/source/runtime/formoperations.hxx
@@ -25,8 +25,10 @@
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/form/XForm.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/form/XLoadable.hpp>
#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/util/XModifyListener.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
@@ -35,7 +37,7 @@
#include <cppuhelper/basemutex.hxx>
#include <cppuhelper/compbase.hxx>
-
+#include <connectivity/dbtools.hxx>
namespace frm
{
@@ -320,14 +322,22 @@ namespace frm
{
public:
impl_appendFilterByColumn_throw(const FormOperations *pFO,
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > const & xParser,
css::uno::Reference< css::beans::XPropertySet > const & xField)
: m_pFO(pFO)
+ , m_xParser(xParser)
, m_xField(xField)
{};
- void operator()() { m_pFO->m_xParser->appendFilterByColumn( m_xField, true, css::sdb::SQLFilterOperator::EQUAL ); }
+ void operator()() {
+ if (dbtools::isAggregateColumn( m_xParser, m_xField ))
+ m_pFO->m_xParser->appendHavingClauseByColumn( m_xField, true, css::sdb::SQLFilterOperator::EQUAL );
+ else
+ m_pFO->m_xParser->appendFilterByColumn( m_xField, true, css::sdb::SQLFilterOperator::EQUAL );
+ }
private:
const FormOperations *m_pFO;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xParser;
css::uno::Reference< css::beans::XPropertySet > m_xField;
};
diff --git a/include/connectivity/dbtools.hxx b/include/connectivity/dbtools.hxx
index f771ae9f3fbe..e0bf5ca8f022 100644
--- a/include/connectivity/dbtools.hxx
+++ b/include/connectivity/dbtools.hxx
@@ -20,6 +20,7 @@
#ifndef INCLUDED_CONNECTIVITY_DBTOOLS_HXX
#define INCLUDED_CONNECTIVITY_DBTOOLS_HXX
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
#include <connectivity/dbexception.hxx>
#include <comphelper/types.hxx>
#include <com/sun/star/sdbc/DataType.hpp>
@@ -787,6 +788,44 @@ namespace dbtools
OUStringBuffer& _out_rSQLPredicate
);
+ /** is this field an aggregate?
+
+ @param _xComposer
+ a query composer that knows the field by name
+ @param _xField
+ the field
+ @param whenNotFound
+ value returned when _sName is not known by _xComposer
+ */
+ OOO_DLLPUBLIC_DBTOOLS bool isAggregateColumn(
+ const css::uno::Reference< css::sdb::XSingleSelectQueryComposer > &_xComposer,
+ const css::uno::Reference< css::beans::XPropertySet > &_xField,
+ bool whenNotFound = false
+ );
+
+ /** is this column an aggregate?
+
+ @param _xColumns collection of columns
+ look for column sName in there
+ @param _sName
+ name of the column
+ @param whenNotFound
+ value returned when _sName is not in _xColumns
+ */
+ OOO_DLLPUBLIC_DBTOOLS bool isAggregateColumn(
+ const css::uno::Reference< css::container::XNameAccess > &_xColumns,
+ const OUString &_sName,
+ bool whenNotFound = false
+ );
+
+ /** is this column an aggregate?
+
+ @param _xColumn
+ */
+ OOO_DLLPUBLIC_DBTOOLS bool isAggregateColumn(
+ const css::uno::Reference< css::beans::XPropertySet > &_xColumn
+ );
+
} // namespace dbtools
namespace connectivity
diff --git a/include/connectivity/filtermanager.hxx b/include/connectivity/filtermanager.hxx
index 41df1c61b9f0..45b58a6183f9 100644
--- a/include/connectivity/filtermanager.hxx
+++ b/include/connectivity/filtermanager.hxx
@@ -61,14 +61,18 @@ namespace dbtools
enum class FilterComponent
{
PublicFilter, // The filter which is to be published as "Filter" property of the database component.
- LinkFilter // The filter part which is implicitly created for a database component when connecting
+ LinkFilter, // The filter part which is implicitly created for a database component when connecting
// master and detail database components via column names.
+ PublicHaving, // the same, but should go in HAVING clause instead of WHERE clause
+ LinkHaving
};
private:
css::uno::Reference< css::beans::XPropertySet > m_xComponentAggregate;
OUString m_aPublicFilterComponent;
+ OUString m_aPublicHavingComponent;
OUString m_aLinkFilterComponent;
+ OUString m_aLinkHavingComponent;
bool m_bApplyPublicFilter;
public:
@@ -85,19 +89,21 @@ namespace dbtools
void setFilterComponent( FilterComponent _eWhich, const OUString& _rComponent );
bool isApplyPublicFilter( ) const { return m_bApplyPublicFilter; }
- void setApplyPublicFilter( bool _bApply );
+ void setApplyPublicFilter( bool _bApply );
private:
/** retrieves a filter which is a conjunction of all single filter components
*/
OUString getComposedFilter( ) const;
+ OUString getComposedHaving( ) const;
/** appends one filter component to the statement in our composer
*/
static void appendFilterComponent( OUStringBuffer& io_appendTo, const OUString& i_component );
/// checks whether there is only one (or even no) non-empty filter component
- bool isThereAtMostOneComponent( OUString& o_singleComponent ) const;
+ bool isThereAtMostOneFilterComponent( OUString& o_singleComponent ) const;
+ bool isThereAtMostOneHavingComponent( OUString& o_singleComponent ) const;
};
diff --git a/include/connectivity/parameters.hxx b/include/connectivity/parameters.hxx
index 49eebb93665a..e5ba530bfcc4 100644
--- a/include/connectivity/parameters.hxx
+++ b/include/connectivity/parameters.hxx
@@ -296,13 +296,19 @@ namespace dbtools
the detail part denotes a column name. In such a case, an additional filter needs to be created,
containing a new parameter.
+ @param _out_rAdditionalHavingComponents
+ the additional having clause components which are required for master-detail relationships where
+ the detail part denotes a column name. In such a case, an additional filter needs to be created,
+ containing a new parameter.
+
@precond
<member>m_aMasterFields</member> and <member>m_aDetailFields</member> have the same length
*/
void classifyLinks(
const css::uno::Reference< css::container::XNameAccess >& _rxParentColumns,
const css::uno::Reference< css::container::XNameAccess >& _rxColumns,
- ::std::vector< OUString >& _out_rAdditionalFilterComponents
+ ::std::vector< OUString >& _out_rAdditionalFilterComponents,
+ ::std::vector< OUString >& _out_rAdditionalHavingComponents
);
/** finalizes our <member>m_pOuterParameters</member> so that it can be used for