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 .
22 #include "dbastrings.hrc"
23 #include <connectivity/warningscontainer.hxx>
24 #include "HelperCollections.hxx"
25 #include "core_resource.hxx"
26 #include "core_resource.hrc"
28 #include <cppuhelper/queryinterface.hxx>
29 #include <tools/debug.hxx>
30 #include <tools/diagnose_ex.h>
31 #include <osl/diagnose.h>
32 #include <comphelper/propagg.hxx>
33 #include <comphelper/sequence.hxx>
35 #include <com/sun/star/sdbc/XConnection.hpp>
36 #include <com/sun/star/lang/DisposedException.hpp>
37 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
38 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
40 #include <comphelper/types.hxx>
41 #include <comphelper/property.hxx>
42 #include <unotools/sharedunocomponent.hxx>
43 #include "definitioncolumn.hxx"
47 #include "sdbcoretools.hxx"
48 #include "querycomposer.hxx"
49 #include <com/sun/star/beans/PropertyAttribute.hpp>
50 #include "ContainerMediator.hxx"
52 using namespace dbaccess
;
53 using namespace ::com::sun::star::uno
;
54 using namespace ::com::sun::star::sdbc
;
55 using namespace ::com::sun::star::sdbcx
;
56 using namespace ::com::sun::star::sdb
;
57 using namespace ::com::sun::star::lang
;
58 using namespace ::com::sun::star::util
;
59 using namespace ::com::sun::star::beans
;
60 using namespace ::com::sun::star::container
;
61 using namespace ::comphelper
;
62 using namespace ::osl
;
63 using namespace ::cppu
;
64 using namespace ::utl
;
69 //==========================================================================
71 //==========================================================================
74 OQuery::OQuery( const Reference
< XPropertySet
>& _rxCommandDefinition
75 ,const Reference
< XConnection
>& _rxConn
76 ,const Reference
< XMultiServiceFactory
>& _xORB
)
77 :OContentHelper(_xORB
,NULL
,TContentPtr(new OContentHelper_Impl
))
78 ,OQueryDescriptor_Base(m_aMutex
,*this)
79 ,ODataSettings(OContentHelper::rBHelper
,sal_True
)
80 ,m_xCommandDefinition(_rxCommandDefinition
)
81 ,m_xConnection(_rxConn
)
82 ,m_pColumnMediator( NULL
)
84 ,m_bCaseSensitiv(sal_True
)
85 ,m_eDoingCurrently(NONE
)
87 DBG_CTOR(OQuery
, NULL
);
89 ODataSettings::registerPropertiesFor(this);
91 osl_atomic_increment(&m_refCount
);
92 OSL_ENSURE(m_xCommandDefinition
.is(), "OQuery::OQuery : invalid CommandDefinition object !");
93 if ( m_xCommandDefinition
.is() )
97 ::comphelper::copyProperties(_rxCommandDefinition
,this);
101 OSL_FAIL("OQueryDescriptor_Base::OQueryDescriptor_Base: caught an exception!");
104 m_xCommandDefinition
->addPropertyChangeListener(::rtl::OUString(), this);
105 // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
106 m_xCommandPropInfo
= m_xCommandDefinition
->getPropertySetInfo();
108 OSL_ENSURE(m_xConnection
.is(), "OQuery::OQuery : invalid connection !");
109 osl_atomic_decrement(&m_refCount
);
114 DBG_DTOR(OQuery
, NULL
);
117 IMPLEMENT_IMPLEMENTATION_ID(OQuery
);
118 IMPLEMENT_GETTYPES3(OQuery
,OQueryDescriptor_Base
,ODataSettings
,OContentHelper
);
119 IMPLEMENT_FORWARD_XINTERFACE3( OQuery
,OContentHelper
,OQueryDescriptor_Base
,ODataSettings
)
121 void OQuery::rebuildColumns()
123 OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
124 // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
128 m_pColumnMediator
= NULL
;
130 Reference
<XColumnsSupplier
> xColSup(m_xCommandDefinition
,UNO_QUERY
);
131 Reference
< XNameAccess
> xColumnDefinitions
;
134 xColumnDefinitions
= xColSup
->getColumns();
135 if ( xColumnDefinitions
.is() )
136 m_pColumnMediator
= new OContainerMediator( m_pColumns
, xColumnDefinitions
, m_xConnection
);
139 // fill the columns with columns from the statement
140 Reference
< XMultiServiceFactory
> xFactory( m_xConnection
, UNO_QUERY_THROW
);
141 SharedUNOComponent
< XSingleSelectQueryComposer
, DisposableComponent
> xComposer(
142 Reference
< XSingleSelectQueryComposer
>( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
) );
144 Reference
< XNameAccess
> xColumns
;
145 Reference
< XIndexAccess
> xColumnsIndexed
;
148 xComposer
->setQuery( m_sCommand
);
149 Reference
< XColumnsSupplier
> xCols( xComposer
, UNO_QUERY_THROW
);
150 xColumns
.set( xCols
->getColumns(), UNO_QUERY_THROW
);
151 xColumnsIndexed
.set( xColumns
, UNO_QUERY_THROW
);
153 catch( const SQLException
& ) { }
155 SharedUNOComponent
< XPreparedStatement
, DisposableComponent
> xPreparedStatement
;
156 if ( !xColumns
.is() || ( xColumnsIndexed
->getCount() == 0 ) )
157 { // the QueryComposer could not parse it. Try a lean version.
158 xPreparedStatement
.set( m_xConnection
->prepareStatement( m_sCommand
), UNO_QUERY_THROW
);
159 Reference
< XResultSetMetaDataSupplier
> xResMetaDataSup( xPreparedStatement
, UNO_QUERY_THROW
);
160 Reference
< XResultSetMetaData
> xResultSetMeta( xResMetaDataSup
->getMetaData() );
161 if ( !xResultSetMeta
.is() )
163 ::rtl::OUString
sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET
) );
164 ::dbtools::throwSQLException( sError
, SQL_GENERAL_ERROR
, *this );
167 Reference
< XDatabaseMetaData
> xDBMeta( m_xConnection
->getMetaData(), UNO_QUERY_THROW
);
168 ::rtl::Reference
< OSQLColumns
> aParseColumns(
169 ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta
, xDBMeta
,xColumnDefinitions
) );
170 xColumns
= OPrivateColumns::createWithIntrinsicNames(
171 aParseColumns
, xDBMeta
->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex
);
172 if ( !xColumns
.is() )
173 throw RuntimeException();
176 Sequence
< ::rtl::OUString
> aNames
= xColumns
->getElementNames();
177 const ::rtl::OUString
* pIter
= aNames
.getConstArray();
178 const ::rtl::OUString
* pEnd
= pIter
+ aNames
.getLength();
179 for ( sal_Int32 i
= 0;pIter
!= pEnd
; ++pIter
,++i
)
181 Reference
<XPropertySet
> xSource(xColumns
->getByName( *pIter
),UNO_QUERY
);
182 ::rtl::OUString sLabel
= *pIter
;
183 if ( xColumnDefinitions
.is() && xColumnDefinitions
->hasByName(*pIter
) )
185 Reference
<XPropertySet
> xCommandColumn(xColumnDefinitions
->getByName( *pIter
),UNO_QUERY
);
186 xCommandColumn
->getPropertyValue(PROPERTY_LABEL
) >>= sLabel
;
188 OQueryColumn
* pColumn
= new OQueryColumn( xSource
, m_xConnection
, sLabel
);
189 Reference
< XChild
> xChild( *pColumn
, UNO_QUERY_THROW
);
190 xChild
->setParent( *this );
192 implAppendColumn( *pIter
, pColumn
);
193 Reference
< XPropertySet
> xDest( *pColumn
, UNO_QUERY_THROW
);
194 if ( m_pColumnMediator
.is() )
195 m_pColumnMediator
->notifyElementCreated( *pIter
, xDest
);
198 catch( const SQLContext
& e
)
201 m_pWarnings
->appendWarning( e
);
203 catch( const SQLWarning
& e
)
206 m_pWarnings
->appendWarning( e
);
208 catch( const SQLException
& e
)
211 m_pWarnings
->appendWarning( e
);
213 catch( const Exception
& )
215 DBG_UNHANDLED_EXCEPTION();
220 IMPLEMENT_SERVICE_INFO3(OQuery
, "com.sun.star.sdb.dbaccess.OQuery", SERVICE_SDB_DATASETTINGS
.ascii
, SERVICE_SDB_QUERY
.ascii
, SERVICE_SDB_QUERYDEFINITION
.ascii
)
222 // ::com::sun::star::beans::XPropertyChangeListener
223 void SAL_CALL
OQuery::propertyChange( const PropertyChangeEvent
& _rSource
) throw(RuntimeException
)
225 sal_Int32 nOwnHandle
= -1;
227 MutexGuard
aGuard(m_aMutex
);
229 OSL_ENSURE(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
230 "OQuery::propertyChange : where did this call come from ?");
232 if (m_eDoingCurrently
== SETTING_PROPERTIES
)
233 // we're setting the property ourself, so we will do the neccessary notifications later
236 // forward this to our own member holding a copy of the property value
237 if (getArrayHelper()->hasPropertyByName(_rSource
.PropertyName
))
239 Property aOwnProp
= getArrayHelper()->getPropertyByName(_rSource
.PropertyName
);
240 nOwnHandle
= aOwnProp
.Handle
;
241 ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle
, _rSource
.NewValue
);
242 // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
244 // and don't use the "real" setPropertyValue, this is to expensive and not sure to succeed
248 OSL_FAIL("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
252 fire(&nOwnHandle
, &_rSource
.NewValue
, &_rSource
.OldValue
, 1, sal_False
);
255 void SAL_CALL
OQuery::disposing( const EventObject
& _rSource
) throw (RuntimeException
)
257 MutexGuard
aGuard(m_aMutex
);
260 OSL_ENSURE(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
261 "OQuery::disposing : where did this call come from ?");
263 m_xCommandDefinition
->removePropertyChangeListener(::rtl::OUString(), this);
264 m_xCommandDefinition
= NULL
;
267 // XDataDescriptorFactory
268 Reference
< XPropertySet
> SAL_CALL
OQuery::createDataDescriptor( ) throw(RuntimeException
)
270 return new OQueryDescriptor(*this);
274 void SAL_CALL
OQuery::disposing()
276 MutexGuard
aGuard(m_aMutex
);
277 if (m_xCommandDefinition
.is())
279 m_xCommandDefinition
->removePropertyChangeListener(::rtl::OUString(), this);
280 m_xCommandDefinition
= NULL
;
287 void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle
, const Any
& _rValue
) throw (Exception
)
289 ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
290 ::rtl::OUString sAggPropName
;
292 if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName
,&nAttr
,_nHandle
) &&
293 m_xCommandPropInfo
.is() &&
294 m_xCommandPropInfo
->hasPropertyByName(sAggPropName
))
295 { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
297 m_eDoingCurrently
= SETTING_PROPERTIES
;
298 OAutoActionReset
aAutoReset(this);
299 m_xCommandDefinition
->setPropertyValue(sAggPropName
, _rValue
);
301 if ( PROPERTY_ID_COMMAND
== _nHandle
)
302 // the columns are out of date if we are based on a new statement ....
303 setColumnsOutOfDate();
307 Reference
< XPropertySetInfo
> SAL_CALL
OQuery::getPropertySetInfo( ) throw(RuntimeException
)
309 return createPropertySetInfo( getInfoHelper() ) ;
312 ::cppu::IPropertyArrayHelper
& OQuery::getInfoHelper()
314 return *getArrayHelper();
317 ::cppu::IPropertyArrayHelper
* OQuery::createArrayHelper( ) const
319 Sequence
< Property
> aProps
;
321 describeProperties(aProps
);
322 return new ::cppu::OPropertyArrayHelper(aProps
);
325 OColumn
* OQuery::createColumn(const ::rtl::OUString
& /*_rName*/) const
330 void SAL_CALL
OQuery::rename( const ::rtl::OUString
& newName
) throw (SQLException
, ElementExistException
, RuntimeException
)
332 MutexGuard
aGuard(m_aMutex
);
333 Reference
<XRename
> xRename(m_xCommandDefinition
,UNO_QUERY
);
334 OSL_ENSURE(xRename
.is(),"No XRename interface!");
336 xRename
->rename(newName
);
339 void OQuery::registerProperties()
341 // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
342 // a OPropertyStateContainer)
343 registerProperty(PROPERTY_NAME
, PROPERTY_ID_NAME
, PropertyAttribute::BOUND
|PropertyAttribute::CONSTRAINED
,
344 &m_sElementName
, ::getCppuType(&m_sElementName
));
346 registerProperty(PROPERTY_COMMAND
, PROPERTY_ID_COMMAND
, PropertyAttribute::BOUND
,
347 &m_sCommand
, ::getCppuType(&m_sCommand
));
349 registerProperty(PROPERTY_ESCAPE_PROCESSING
, PROPERTY_ID_ESCAPE_PROCESSING
, PropertyAttribute::BOUND
,
350 &m_bEscapeProcessing
, ::getBooleanCppuType());
352 registerProperty(PROPERTY_UPDATE_TABLENAME
, PROPERTY_ID_UPDATE_TABLENAME
, PropertyAttribute::BOUND
,
353 &m_sUpdateTableName
, ::getCppuType(&m_sUpdateTableName
));
355 registerProperty(PROPERTY_UPDATE_SCHEMANAME
, PROPERTY_ID_UPDATE_SCHEMANAME
, PropertyAttribute::BOUND
,
356 &m_sUpdateSchemaName
, ::getCppuType(&m_sUpdateSchemaName
));
358 registerProperty(PROPERTY_UPDATE_CATALOGNAME
, PROPERTY_ID_UPDATE_CATALOGNAME
, PropertyAttribute::BOUND
,
359 &m_sUpdateCatalogName
, ::getCppuType(&m_sUpdateCatalogName
));
361 registerProperty(PROPERTY_LAYOUTINFORMATION
, PROPERTY_ID_LAYOUTINFORMATION
, PropertyAttribute::BOUND
,
362 &m_aLayoutInformation
, ::getCppuType(&m_aLayoutInformation
));
365 ::rtl::OUString
OQuery::determineContentType() const
367 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQuery" ) );
370 } // namespace dbaccess
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */