1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "dbastrings.hrc"
22 #include <connectivity/warningscontainer.hxx>
23 #include "HelperCollections.hxx"
24 #include "core_resource.hxx"
25 #include "core_resource.hrc"
27 #include <cppuhelper/queryinterface.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/diagnose_ex.h>
30 #include <osl/diagnose.h>
31 #include <comphelper/propagg.hxx>
32 #include <comphelper/sequence.hxx>
34 #include <com/sun/star/sdbc/XConnection.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
37 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
39 #include <comphelper/types.hxx>
40 #include <comphelper/property.hxx>
41 #include <unotools/sharedunocomponent.hxx>
42 #include "definitioncolumn.hxx"
46 #include "sdbcoretools.hxx"
47 #include "querycomposer.hxx"
48 #include <com/sun/star/beans/PropertyAttribute.hpp>
49 #include "ContainerMediator.hxx"
51 using namespace dbaccess
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::sdbc
;
54 using namespace ::com::sun::star::sdbcx
;
55 using namespace ::com::sun::star::sdb
;
56 using namespace ::com::sun::star::lang
;
57 using namespace ::com::sun::star::util
;
58 using namespace ::com::sun::star::beans
;
59 using namespace ::com::sun::star::container
;
60 using namespace ::comphelper
;
61 using namespace ::osl
;
62 using namespace ::cppu
;
63 using namespace ::utl
;
70 OQuery::OQuery( const Reference
< XPropertySet
>& _rxCommandDefinition
71 ,const Reference
< XConnection
>& _rxConn
72 ,const Reference
< XComponentContext
>& _xORB
)
73 :OContentHelper(_xORB
,NULL
,TContentPtr(new OContentHelper_Impl
))
74 ,OQueryDescriptor_Base(m_aMutex
,*this)
75 ,ODataSettings(OContentHelper::rBHelper
,true)
76 ,m_xCommandDefinition(_rxCommandDefinition
)
77 ,m_xConnection(_rxConn
)
78 ,m_pColumnMediator( NULL
)
80 ,m_bCaseSensitiv(true)
81 ,m_eDoingCurrently(NONE
)
84 ODataSettings::registerPropertiesFor(this);
86 osl_atomic_increment(&m_refCount
);
87 OSL_ENSURE(m_xCommandDefinition
.is(), "OQuery::OQuery : invalid CommandDefinition object !");
88 if ( m_xCommandDefinition
.is() )
92 ::comphelper::copyProperties(_rxCommandDefinition
,this);
96 OSL_FAIL("OQueryDescriptor_Base::OQueryDescriptor_Base: caught an exception!");
99 m_xCommandDefinition
->addPropertyChangeListener(OUString(), this);
100 // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
101 m_xCommandPropInfo
= m_xCommandDefinition
->getPropertySetInfo();
103 OSL_ENSURE(m_xConnection
.is(), "OQuery::OQuery : invalid connection !");
104 osl_atomic_decrement(&m_refCount
);
111 css::uno::Sequence
<sal_Int8
> OQuery::getImplementationId()
112 throw (css::uno::RuntimeException
, std::exception
)
114 return css::uno::Sequence
<sal_Int8
>();
117 IMPLEMENT_GETTYPES3(OQuery
,OQueryDescriptor_Base
,ODataSettings
,OContentHelper
);
118 IMPLEMENT_FORWARD_XINTERFACE3( OQuery
,OContentHelper
,OQueryDescriptor_Base
,ODataSettings
)
120 void OQuery::rebuildColumns()
122 OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
123 // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
127 m_pColumnMediator
= NULL
;
129 Reference
<XColumnsSupplier
> xColSup(m_xCommandDefinition
,UNO_QUERY
);
130 Reference
< XNameAccess
> xColumnDefinitions
;
133 xColumnDefinitions
= xColSup
->getColumns();
134 if ( xColumnDefinitions
.is() )
135 m_pColumnMediator
= new OContainerMediator( m_pColumns
, xColumnDefinitions
, m_xConnection
);
138 // fill the columns with columns from the statement
139 Reference
< XMultiServiceFactory
> xFactory( m_xConnection
, UNO_QUERY_THROW
);
140 SharedUNOComponent
< XSingleSelectQueryComposer
, DisposableComponent
> xComposer(
141 Reference
< XSingleSelectQueryComposer
>( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
) );
143 Reference
< XNameAccess
> xColumns
;
144 Reference
< XIndexAccess
> xColumnsIndexed
;
147 xComposer
->setQuery( m_sCommand
);
148 Reference
< XColumnsSupplier
> xCols( xComposer
, UNO_QUERY_THROW
);
149 xColumns
.set( xCols
->getColumns(), UNO_QUERY_THROW
);
150 xColumnsIndexed
.set( xColumns
, UNO_QUERY_THROW
);
152 catch( const SQLException
& ) { }
154 SharedUNOComponent
< XPreparedStatement
, DisposableComponent
> xPreparedStatement
;
155 if ( !xColumns
.is() || ( xColumnsIndexed
->getCount() == 0 ) )
156 { // the QueryComposer could not parse it. Try a lean version.
157 xPreparedStatement
.set( m_xConnection
->prepareStatement( m_sCommand
), UNO_QUERY_THROW
);
158 Reference
< XResultSetMetaDataSupplier
> xResMetaDataSup( xPreparedStatement
, UNO_QUERY_THROW
);
159 Reference
< XResultSetMetaData
> xResultSetMeta( xResMetaDataSup
->getMetaData() );
160 if ( !xResultSetMeta
.is() )
162 OUString
sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET
) );
163 ::dbtools::throwSQLException( sError
, SQL_GENERAL_ERROR
, *this );
166 Reference
< XDatabaseMetaData
> xDBMeta( m_xConnection
->getMetaData(), UNO_QUERY_THROW
);
167 ::rtl::Reference
< OSQLColumns
> aParseColumns(
168 ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta
, xDBMeta
,xColumnDefinitions
) );
169 xColumns
= OPrivateColumns::createWithIntrinsicNames(
170 aParseColumns
, xDBMeta
->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex
);
171 if ( !xColumns
.is() )
172 throw RuntimeException();
175 Sequence
< OUString
> aNames
= xColumns
->getElementNames();
176 const OUString
* pIter
= aNames
.getConstArray();
177 const OUString
* pEnd
= pIter
+ aNames
.getLength();
178 for ( sal_Int32 i
= 0;pIter
!= pEnd
; ++pIter
,++i
)
180 Reference
<XPropertySet
> xSource(xColumns
->getByName( *pIter
),UNO_QUERY
);
181 OUString sLabel
= *pIter
;
182 if ( xColumnDefinitions
.is() && xColumnDefinitions
->hasByName(*pIter
) )
184 Reference
<XPropertySet
> xCommandColumn(xColumnDefinitions
->getByName( *pIter
),UNO_QUERY
);
185 xCommandColumn
->getPropertyValue(PROPERTY_LABEL
) >>= sLabel
;
187 OQueryColumn
* pColumn
= new OQueryColumn( xSource
, m_xConnection
, sLabel
);
188 Reference
< XChild
> xChild( *pColumn
, UNO_QUERY_THROW
);
189 xChild
->setParent( *this );
191 implAppendColumn( *pIter
, pColumn
);
192 Reference
< XPropertySet
> xDest( *pColumn
, UNO_QUERY_THROW
);
193 if ( m_pColumnMediator
.is() )
194 m_pColumnMediator
->notifyElementCreated( *pIter
, xDest
);
197 catch( const SQLContext
& e
)
200 m_pWarnings
->appendWarning( e
);
202 catch( const SQLWarning
& e
)
205 m_pWarnings
->appendWarning( e
);
207 catch( const SQLException
& e
)
210 m_pWarnings
->appendWarning( e
);
212 catch( const Exception
& )
214 DBG_UNHANDLED_EXCEPTION();
219 IMPLEMENT_SERVICE_INFO3(OQuery
, "com.sun.star.sdb.dbaccess.OQuery", SERVICE_SDB_DATASETTINGS
, SERVICE_SDB_QUERY
, "com.sun.star.sdb.QueryDefinition")
221 // ::com::sun::star::beans::XPropertyChangeListener
222 void SAL_CALL
OQuery::propertyChange( const PropertyChangeEvent
& _rSource
) throw(RuntimeException
, std::exception
)
224 sal_Int32 nOwnHandle
= -1;
226 MutexGuard
aGuard(m_aMutex
);
228 OSL_ENSURE(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
229 "OQuery::propertyChange : where did this call come from ?");
231 if (m_eDoingCurrently
== SETTING_PROPERTIES
)
232 // we're setting the property ourself, so we will do the necessary notifications later
235 // forward this to our own member holding a copy of the property value
236 if (getArrayHelper()->hasPropertyByName(_rSource
.PropertyName
))
238 Property aOwnProp
= getArrayHelper()->getPropertyByName(_rSource
.PropertyName
);
239 nOwnHandle
= aOwnProp
.Handle
;
240 ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle
, _rSource
.NewValue
);
241 // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
243 // and don't use the "real" setPropertyValue, this is to expensive and not sure to succeed
247 OSL_FAIL("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
251 fire(&nOwnHandle
, &_rSource
.NewValue
, &_rSource
.OldValue
, 1, sal_False
);
254 void SAL_CALL
OQuery::disposing( const EventObject
& _rSource
) throw (RuntimeException
, std::exception
)
256 MutexGuard
aGuard(m_aMutex
);
259 OSL_ENSURE(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
260 "OQuery::disposing : where did this call come from ?");
262 m_xCommandDefinition
->removePropertyChangeListener(OUString(), this);
263 m_xCommandDefinition
= NULL
;
266 // XDataDescriptorFactory
267 Reference
< XPropertySet
> SAL_CALL
OQuery::createDataDescriptor( ) throw(RuntimeException
, std::exception
)
269 return new OQueryDescriptor(*this);
273 void SAL_CALL
OQuery::disposing()
275 MutexGuard
aGuard(m_aMutex
);
276 if (m_xCommandDefinition
.is())
278 m_xCommandDefinition
->removePropertyChangeListener(OUString(), this);
279 m_xCommandDefinition
= NULL
;
286 void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle
, const Any
& _rValue
) throw (Exception
, std::exception
)
288 ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
289 OUString sAggPropName
;
291 if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName
,&nAttr
,_nHandle
) &&
292 m_xCommandPropInfo
.is() &&
293 m_xCommandPropInfo
->hasPropertyByName(sAggPropName
))
294 { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
296 m_eDoingCurrently
= SETTING_PROPERTIES
;
297 OAutoActionReset
aAutoReset(this);
298 m_xCommandDefinition
->setPropertyValue(sAggPropName
, _rValue
);
300 if ( PROPERTY_ID_COMMAND
== _nHandle
)
301 // the columns are out of date if we are based on a new statement ....
302 setColumnsOutOfDate();
306 Reference
< XPropertySetInfo
> SAL_CALL
OQuery::getPropertySetInfo( ) throw(RuntimeException
, std::exception
)
308 return createPropertySetInfo( getInfoHelper() ) ;
311 ::cppu::IPropertyArrayHelper
& OQuery::getInfoHelper()
313 return *getArrayHelper();
316 ::cppu::IPropertyArrayHelper
* OQuery::createArrayHelper( ) const
318 Sequence
< Property
> aProps
;
320 describeProperties(aProps
);
321 return new ::cppu::OPropertyArrayHelper(aProps
);
324 OColumn
* OQuery::createColumn(const OUString
& /*_rName*/) const
329 void SAL_CALL
OQuery::rename( const OUString
& newName
) throw (SQLException
, ElementExistException
, RuntimeException
, std::exception
)
331 MutexGuard
aGuard(m_aMutex
);
332 Reference
<XRename
> xRename(m_xCommandDefinition
,UNO_QUERY
);
333 OSL_ENSURE(xRename
.is(),"No XRename interface!");
335 xRename
->rename(newName
);
338 void OQuery::registerProperties()
340 // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
341 // a OPropertyStateContainer)
342 registerProperty(PROPERTY_NAME
, PROPERTY_ID_NAME
, PropertyAttribute::BOUND
|PropertyAttribute::CONSTRAINED
,
343 &m_sElementName
, cppu::UnoType
<decltype(m_sElementName
)>::get());
345 registerProperty(PROPERTY_COMMAND
, PROPERTY_ID_COMMAND
, PropertyAttribute::BOUND
,
346 &m_sCommand
, cppu::UnoType
<decltype(m_sCommand
)>::get());
348 registerProperty(PROPERTY_ESCAPE_PROCESSING
, PROPERTY_ID_ESCAPE_PROCESSING
, PropertyAttribute::BOUND
,
349 &m_bEscapeProcessing
, cppu::UnoType
<bool>::get());
351 registerProperty(PROPERTY_UPDATE_TABLENAME
, PROPERTY_ID_UPDATE_TABLENAME
, PropertyAttribute::BOUND
,
352 &m_sUpdateTableName
, cppu::UnoType
<decltype(m_sUpdateTableName
)>::get());
354 registerProperty(PROPERTY_UPDATE_SCHEMANAME
, PROPERTY_ID_UPDATE_SCHEMANAME
, PropertyAttribute::BOUND
,
355 &m_sUpdateSchemaName
, cppu::UnoType
<decltype(m_sUpdateSchemaName
)>::get());
357 registerProperty(PROPERTY_UPDATE_CATALOGNAME
, PROPERTY_ID_UPDATE_CATALOGNAME
, PropertyAttribute::BOUND
,
358 &m_sUpdateCatalogName
, cppu::UnoType
<decltype(m_sUpdateCatalogName
)>::get());
360 registerProperty(PROPERTY_LAYOUTINFORMATION
, PROPERTY_ID_LAYOUTINFORMATION
, PropertyAttribute::BOUND
,
361 &m_aLayoutInformation
, cppu::UnoType
<decltype(m_aLayoutInformation
)>::get());
364 OUString
OQuery::determineContentType() const
366 return OUString( "application/vnd.org.openoffice.DatabaseQuery" );
369 } // namespace dbaccess
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */