1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: query.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dbaccess.hxx"
34 #ifndef _DBA_COREAPI_QUERY_HXX_
37 #ifndef DBACCESS_SHARED_DBASTRINGS_HRC
38 #include "dbastrings.hrc"
40 #ifndef DBTOOLS_WARNINGSCONTAINER_HXX
41 #include <connectivity/warningscontainer.hxx>
43 #ifndef DBA_HELPERCOLLECTIONS_HXX
44 #include "HelperCollections.hxx"
46 #ifndef _DBA_CORE_RESOURCE_HXX_
47 #include "core_resource.hxx"
49 #ifndef _DBA_CORE_RESOURCE_HRC_
50 #include "core_resource.hrc"
53 #ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
54 #include <cppuhelper/queryinterface.hxx>
56 #ifndef _TOOLS_DEBUG_HXX
57 #include <tools/debug.hxx>
59 #ifndef TOOLS_DIAGNOSE_EX_H
60 #include <tools/diagnose_ex.h>
62 #ifndef _COMPHELPER_PROPERTY_AGGREGATION_HXX_
63 #include <comphelper/propagg.hxx>
65 #ifndef _COMPHELPER_SEQUENCE_HXX_
66 #include <comphelper/sequence.hxx>
69 /** === begin UNO includes === **/
70 #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_
71 #include <com/sun/star/sdbc/XConnection.hpp>
73 #ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
74 #include <com/sun/star/lang/DisposedException.hpp>
76 #ifndef _COM_SUN_STAR_SDB_XSINGLESELECTQUERYCOMPOSER_HPP_
77 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
79 #ifndef _COM_SUN_STAR_SDBC_XRESULTSETMETADATASUPPLIER_HPP_
80 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
82 /** === end UNO includes === **/
84 #ifndef _COMPHELPER_TYPES_HXX_
85 #include <comphelper/types.hxx>
87 #ifndef _COMPHELPER_PROPERTY_HXX_
88 #include <comphelper/property.hxx>
90 #ifndef UNOTOOLS_INC_SHAREDUNOCOMPONENT_HXX
91 #include <unotools/sharedunocomponent.hxx>
93 #ifndef _DBACORE_DEFINITIONCOLUMN_HXX_
94 #include "definitioncolumn.hxx"
99 #ifndef DBACORE_SDBCORETOOLS_HXX
100 #include "sdbcoretools.hxx"
102 #ifndef DBACCESS_CORE_API_QUERYCOMPOSER_HXX
103 #include "querycomposer.hxx"
105 #ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
106 #include <com/sun/star/beans/PropertyAttribute.hpp>
108 #ifndef DBA_CONTAINERMEDIATOR_HXX
109 #include "ContainerMediator.hxx"
112 using namespace dbaccess
;
113 using namespace ::com::sun::star::uno
;
114 using namespace ::com::sun::star::sdbc
;
115 using namespace ::com::sun::star::sdbcx
;
116 using namespace ::com::sun::star::sdb
;
117 using namespace ::com::sun::star::lang
;
118 using namespace ::com::sun::star::util
;
119 using namespace ::com::sun::star::beans
;
120 using namespace ::com::sun::star::container
;
121 using namespace ::comphelper
;
122 using namespace ::osl
;
123 using namespace ::cppu
;
124 using namespace ::utl
;
126 //........................................................................
129 //........................................................................
131 //==========================================================================
133 //==========================================================================
135 //--------------------------------------------------------------------------
136 OQuery::OQuery( const Reference
< XPropertySet
>& _rxCommandDefinition
137 ,const Reference
< XConnection
>& _rxConn
138 ,const Reference
< XMultiServiceFactory
>& _xORB
)
139 :OContentHelper(_xORB
,NULL
,TContentPtr(new OContentHelper_Impl
))
140 ,OQueryDescriptor_Base(m_aMutex
,*this)
141 ,ODataSettings(OContentHelper::rBHelper
,sal_True
)
142 ,m_xCommandDefinition(_rxCommandDefinition
)
143 ,m_xConnection(_rxConn
)
144 ,m_pColumnMediator( NULL
)
146 ,m_bCaseSensitiv(sal_True
)
147 ,m_eDoingCurrently(NONE
)
149 DBG_CTOR(OQuery
, NULL
);
150 registerProperties();
151 ODataSettings::registerPropertiesFor(this);
153 osl_incrementInterlockedCount(&m_refCount
);
154 DBG_ASSERT(m_xCommandDefinition
.is(), "OQuery::OQuery : invalid CommandDefinition object !");
155 if ( m_xCommandDefinition
.is() )
159 ::comphelper::copyProperties(_rxCommandDefinition
,this);
163 OSL_ENSURE(sal_False
, "OQueryDescriptor_Base::OQueryDescriptor_Base: caught an exception!");
166 m_xCommandDefinition
->addPropertyChangeListener(::rtl::OUString(), this);
167 // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
168 m_xCommandPropInfo
= m_xCommandDefinition
->getPropertySetInfo();
170 DBG_ASSERT(m_xConnection
.is(), "OQuery::OQuery : invalid connection !");
171 osl_decrementInterlockedCount(&m_refCount
);
174 //--------------------------------------------------------------------------
177 DBG_DTOR(OQuery
, NULL
);
179 // -----------------------------------------------------------------------------
180 IMPLEMENT_IMPLEMENTATION_ID(OQuery
);
181 IMPLEMENT_GETTYPES3(OQuery
,OQueryDescriptor_Base
,ODataSettings
,OContentHelper
);
182 IMPLEMENT_FORWARD_XINTERFACE3( OQuery
,OContentHelper
,OQueryDescriptor_Base
,ODataSettings
)
183 //--------------------------------------------------------------------------
184 void OQuery::rebuildColumns()
186 OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
187 // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
191 m_pColumnMediator
= NULL
;
193 Reference
<XColumnsSupplier
> xColSup(m_xCommandDefinition
,UNO_QUERY
);
196 Reference
< XNameAccess
> xColumnDefinitions
= xColSup
->getColumns();
197 if ( xColumnDefinitions
.is() )
198 m_pColumnMediator
= new OContainerMediator( m_pColumns
, xColumnDefinitions
, m_xConnection
, OContainerMediator::eColumns
);
201 // fill the columns with columns from the statement
202 Reference
< XMultiServiceFactory
> xFactory( m_xConnection
, UNO_QUERY_THROW
);
203 SharedUNOComponent
< XSingleSelectQueryComposer
, DisposableComponent
> xComposer(
204 Reference
< XSingleSelectQueryComposer
>( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
) );
206 Reference
< XNameAccess
> xColumns
;
207 Reference
< XIndexAccess
> xColumnsIndexed
;
210 xComposer
->setQuery( m_sCommand
);
211 Reference
< XColumnsSupplier
> xCols( xComposer
, UNO_QUERY_THROW
);
212 xColumns
.set( xCols
->getColumns(), UNO_QUERY_THROW
);
213 xColumnsIndexed
.set( xColumns
, UNO_QUERY_THROW
);
215 catch( const SQLException
& ) { }
217 SharedUNOComponent
< XPreparedStatement
, DisposableComponent
> xPreparedStatement
;
218 if ( !xColumns
.is() || ( xColumnsIndexed
->getCount() == 0 ) )
219 { // the QueryComposer could not parse it. Try a lean version.
220 xPreparedStatement
.set( m_xConnection
->prepareStatement( m_sCommand
), UNO_QUERY_THROW
);
221 Reference
< XResultSetMetaDataSupplier
> xResMetaDataSup( xPreparedStatement
, UNO_QUERY_THROW
);
222 Reference
< XResultSetMetaData
> xResultSetMeta( xResMetaDataSup
->getMetaData() );
223 if ( !xResultSetMeta
.is() )
225 ::rtl::OUString
sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET
) );
226 ::dbtools::throwSQLException( sError
, SQL_GENERAL_ERROR
, *this );
229 Reference
< XDatabaseMetaData
> xDBMeta( m_xConnection
->getMetaData(), UNO_QUERY_THROW
);
230 ::vos::ORef
< OSQLColumns
> aParseColumns(
231 ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta
, xDBMeta
) );
232 xColumns
= OPrivateColumns::createWithIntrinsicNames(
233 aParseColumns
, xDBMeta
->storesMixedCaseQuotedIdentifiers(), *this, m_aMutex
);
234 if ( !xColumns
.is() )
235 throw RuntimeException();
238 Sequence
< ::rtl::OUString
> aNames
= xColumns
->getElementNames();
239 const ::rtl::OUString
* pBegin
= aNames
.getConstArray();
240 const ::rtl::OUString
* pEnd
= pBegin
+ aNames
.getLength();
241 for ( ;pBegin
!= pEnd
; ++pBegin
)
243 Reference
<XPropertySet
> xSource(xColumns
->getByName( *pBegin
),UNO_QUERY
);
244 OTableColumn
* pColumn
= new OTableColumn( xSource
);
245 Reference
<XChild
> xChild(*pColumn
,UNO_QUERY
);
247 xChild
->setParent(*this);
249 implAppendColumn( *pBegin
, pColumn
);
250 Reference
<XPropertySet
> xDest(*pColumn
,UNO_QUERY
);
251 if ( m_pColumnMediator
.is() )
252 m_pColumnMediator
->notifyElementCreated( *pBegin
, xDest
);
255 catch( const SQLContext
& e
)
258 m_pWarnings
->appendWarning( e
);
260 catch( const SQLWarning
& e
)
263 m_pWarnings
->appendWarning( e
);
265 catch( const SQLException
& e
)
268 m_pWarnings
->appendWarning( e
);
270 catch( const Exception
& )
272 DBG_UNHANDLED_EXCEPTION();
277 //--------------------------------------------------------------------------
278 IMPLEMENT_SERVICE_INFO3(OQuery
, "com.sun.star.sdb.dbaccess.OQuery", SERVICE_SDB_DATASETTINGS
, SERVICE_SDB_QUERY
, SERVICE_SDB_QUERYDEFINITION
)
280 // ::com::sun::star::beans::XPropertyChangeListener
281 //--------------------------------------------------------------------------
282 void SAL_CALL
OQuery::propertyChange( const PropertyChangeEvent
& _rSource
) throw(RuntimeException
)
284 sal_Int32 nOwnHandle
= -1;
286 MutexGuard
aGuard(m_aMutex
);
288 DBG_ASSERT(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
289 "OQuery::propertyChange : where did this call come from ?");
291 if (m_eDoingCurrently
== SETTING_PROPERTIES
)
292 // we're setting the property ourself, so we will do the neccessary notifications later
295 // forward this to our own member holding a copy of the property value
296 if (getArrayHelper()->hasPropertyByName(_rSource
.PropertyName
))
298 Property aOwnProp
= getArrayHelper()->getPropertyByName(_rSource
.PropertyName
);
299 nOwnHandle
= aOwnProp
.Handle
;
300 ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle
, _rSource
.NewValue
);
301 // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
303 // and don't use the "real" setPropertyValue, this is to expensive and not sure to succeed
307 DBG_ERROR("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
311 fire(&nOwnHandle
, &_rSource
.NewValue
, &_rSource
.OldValue
, 1, sal_False
);
314 //--------------------------------------------------------------------------
315 void SAL_CALL
OQuery::disposing( const EventObject
& _rSource
) throw (RuntimeException
)
317 MutexGuard
aGuard(m_aMutex
);
320 DBG_ASSERT(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
321 "OQuery::disposing : where did this call come from ?");
323 m_xCommandDefinition
->removePropertyChangeListener(::rtl::OUString(), this);
324 m_xCommandDefinition
= NULL
;
327 // XDataDescriptorFactory
328 //--------------------------------------------------------------------------
329 Reference
< XPropertySet
> SAL_CALL
OQuery::createDataDescriptor( ) throw(RuntimeException
)
331 return new OQueryDescriptor(*this);
335 //--------------------------------------------------------------------------
336 void SAL_CALL
OQuery::disposing()
338 MutexGuard
aGuard(m_aMutex
);
339 if (m_xCommandDefinition
.is())
341 m_xCommandDefinition
->removePropertyChangeListener(::rtl::OUString(), this);
342 m_xCommandDefinition
= NULL
;
349 //--------------------------------------------------------------------------
350 void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle
, const Any
& _rValue
) throw (Exception
)
352 ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
353 ::rtl::OUString sAggPropName
;
355 if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName
,&nAttr
,_nHandle
) &&
356 m_xCommandPropInfo
.is() &&
357 m_xCommandPropInfo
->hasPropertyByName(sAggPropName
))
358 { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
360 m_eDoingCurrently
= SETTING_PROPERTIES
;
361 OAutoActionReset(this);
362 m_xCommandDefinition
->setPropertyValue(sAggPropName
, _rValue
);
364 if ( PROPERTY_ID_COMMAND
== _nHandle
)
365 // the columns are out of date if we are based on a new statement ....
366 // 90573 - 16.08.2001 - frank.schoenheit@sun.com
367 setColumnsOutOfDate();
371 //--------------------------------------------------------------------------
372 Reference
< XPropertySetInfo
> SAL_CALL
OQuery::getPropertySetInfo( ) throw(RuntimeException
)
374 return createPropertySetInfo( getInfoHelper() ) ;
377 //------------------------------------------------------------------------------
378 ::cppu::IPropertyArrayHelper
& OQuery::getInfoHelper()
380 return *getArrayHelper();
383 //--------------------------------------------------------------------------
384 ::cppu::IPropertyArrayHelper
* OQuery::createArrayHelper( ) const
386 Sequence
< Property
> aProps
;
388 describeProperties(aProps
);
389 return new ::cppu::OPropertyArrayHelper(aProps
);
391 // -----------------------------------------------------------------------------
392 OColumn
* OQuery::createColumn(const ::rtl::OUString
& /*_rName*/) const
396 // -----------------------------------------------------------------------------
397 void SAL_CALL
OQuery::rename( const ::rtl::OUString
& newName
) throw (SQLException
, ElementExistException
, RuntimeException
)
399 MutexGuard
aGuard(m_aMutex
);
400 Reference
<XRename
> xRename(m_xCommandDefinition
,UNO_QUERY
);
401 OSL_ENSURE(xRename
.is(),"No XRename interface!");
403 xRename
->rename(newName
);
405 // -----------------------------------------------------------------------------
406 void OQuery::registerProperties()
408 // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
409 // a OPropertyStateContainer)
410 registerProperty(PROPERTY_NAME
, PROPERTY_ID_NAME
, PropertyAttribute::BOUND
|PropertyAttribute::CONSTRAINED
,
411 &m_sElementName
, ::getCppuType(&m_sElementName
));
413 registerProperty(PROPERTY_COMMAND
, PROPERTY_ID_COMMAND
, PropertyAttribute::BOUND
,
414 &m_sCommand
, ::getCppuType(&m_sCommand
));
416 registerProperty(PROPERTY_ESCAPE_PROCESSING
, PROPERTY_ID_ESCAPE_PROCESSING
, PropertyAttribute::BOUND
,
417 &m_bEscapeProcessing
, ::getBooleanCppuType());
419 registerProperty(PROPERTY_UPDATE_TABLENAME
, PROPERTY_ID_UPDATE_TABLENAME
, PropertyAttribute::BOUND
,
420 &m_sUpdateTableName
, ::getCppuType(&m_sUpdateTableName
));
422 registerProperty(PROPERTY_UPDATE_SCHEMANAME
, PROPERTY_ID_UPDATE_SCHEMANAME
, PropertyAttribute::BOUND
,
423 &m_sUpdateSchemaName
, ::getCppuType(&m_sUpdateSchemaName
));
425 registerProperty(PROPERTY_UPDATE_CATALOGNAME
, PROPERTY_ID_UPDATE_CATALOGNAME
, PropertyAttribute::BOUND
,
426 &m_sUpdateCatalogName
, ::getCppuType(&m_sUpdateCatalogName
));
428 registerProperty(PROPERTY_LAYOUTINFORMATION
, PROPERTY_ID_LAYOUTINFORMATION
, PropertyAttribute::BOUND
,
429 &m_aLayoutInformation
, ::getCppuType(&m_aLayoutInformation
));
432 // -----------------------------------------------------------------------------
433 ::rtl::OUString
OQuery::determineContentType() const
435 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQuery" ) );
438 // -----------------------------------------------------------------------------
439 //........................................................................
440 } // namespace dbaccess
441 //........................................................................