1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26
27 #ifndef _DBA_COREAPI_QUERY_HXX_
28 #include "query.hxx"
29 #endif
30 #ifndef DBACCESS_SHARED_DBASTRINGS_HRC
31 #include "dbastrings.hrc"
32 #endif
33 #ifndef DBTOOLS_WARNINGSCONTAINER_HXX
34 #include <connectivity/warningscontainer.hxx>
35 #endif
36 #ifndef DBA_HELPERCOLLECTIONS_HXX
37 #include "HelperCollections.hxx"
38 #endif
39 #ifndef _DBA_CORE_RESOURCE_HXX_
40 #include "core_resource.hxx"
41 #endif
42 #ifndef _DBA_CORE_RESOURCE_HRC_
43 #include "core_resource.hrc"
44 #endif
45
46 #ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
47 #include <cppuhelper/queryinterface.hxx>
48 #endif
49 #ifndef _TOOLS_DEBUG_HXX
50 #include <tools/debug.hxx>
51 #endif
52 #ifndef TOOLS_DIAGNOSE_EX_H
53 #include <tools/diagnose_ex.h>
54 #endif
55 #ifndef _COMPHELPER_PROPERTY_AGGREGATION_HXX_
56 #include <comphelper/propagg.hxx>
57 #endif
58 #ifndef _COMPHELPER_SEQUENCE_HXX_
59 #include <comphelper/sequence.hxx>
60 #endif
61
62 /** === begin UNO includes === **/
63 #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_
64 #include <com/sun/star/sdbc/XConnection.hpp>
65 #endif
66 #ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
67 #include <com/sun/star/lang/DisposedException.hpp>
68 #endif
69 #ifndef _COM_SUN_STAR_SDB_XSINGLESELECTQUERYCOMPOSER_HPP_
70 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
71 #endif
72 #ifndef _COM_SUN_STAR_SDBC_XRESULTSETMETADATASUPPLIER_HPP_
73 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
74 #endif
75 /** === end UNO includes === **/
76
77 #ifndef _COMPHELPER_TYPES_HXX_
78 #include <comphelper/types.hxx>
79 #endif
80 #ifndef _COMPHELPER_PROPERTY_HXX_
81 #include <comphelper/property.hxx>
82 #endif
83 #ifndef UNOTOOLS_INC_SHAREDUNOCOMPONENT_HXX
84 #include <unotools/sharedunocomponent.hxx>
85 #endif
86 #ifndef _DBACORE_DEFINITIONCOLUMN_HXX_
87 #include "definitioncolumn.hxx"
88 #endif
89
90 #include <functional>
91
92 #ifndef DBACORE_SDBCORETOOLS_HXX
93 #include "sdbcoretools.hxx"
94 #endif
95 #ifndef DBACCESS_CORE_API_QUERYCOMPOSER_HXX
96 #include "querycomposer.hxx"
97 #endif
98 #ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
99 #include <com/sun/star/beans/PropertyAttribute.hpp>
100 #endif
101 #ifndef DBA_CONTAINERMEDIATOR_HXX
102 #include "ContainerMediator.hxx"
103 #endif
104
105 using namespace dbaccess;
106 using namespace ::com::sun::star::uno;
107 using namespace ::com::sun::star::sdbc;
108 using namespace ::com::sun::star::sdbcx;
109 using namespace ::com::sun::star::sdb;
110 using namespace ::com::sun::star::lang;
111 using namespace ::com::sun::star::util;
112 using namespace ::com::sun::star::beans;
113 using namespace ::com::sun::star::container;
114 using namespace ::comphelper;
115 using namespace ::osl;
116 using namespace ::cppu;
117 using namespace ::utl;
118
119 //........................................................................
120 namespace dbaccess
121 {
122 //........................................................................
123
124 //==========================================================================
125 //= OQuery
126 //==========================================================================
DBG_NAME(OQuery)127 DBG_NAME(OQuery)
128 //--------------------------------------------------------------------------
129 OQuery::OQuery( const Reference< XPropertySet >& _rxCommandDefinition
130 ,const Reference< XConnection >& _rxConn
131 ,const Reference< XMultiServiceFactory >& _xORB)
132 :OContentHelper(_xORB,NULL,TContentPtr(new OContentHelper_Impl))
133 ,OQueryDescriptor_Base(m_aMutex,*this)
134 ,ODataSettings(OContentHelper::rBHelper,sal_True)
135 ,m_xCommandDefinition(_rxCommandDefinition)
136 ,m_xConnection(_rxConn)
137 ,m_pColumnMediator( NULL )
138 ,m_pWarnings( NULL )
139 ,m_bCaseSensitiv(sal_True)
140 ,m_eDoingCurrently(NONE)
141 {
142 DBG_CTOR(OQuery, NULL);
143 registerProperties();
144 ODataSettings::registerPropertiesFor(this);
145
146 osl_incrementInterlockedCount(&m_refCount);
147 DBG_ASSERT(m_xCommandDefinition.is(), "OQuery::OQuery : invalid CommandDefinition object !");
148 if ( m_xCommandDefinition.is() )
149 {
150 try
151 {
152 ::comphelper::copyProperties(_rxCommandDefinition,this);
153 }
154 catch(Exception&)
155 {
156 OSL_ENSURE(sal_False, "OQueryDescriptor_Base::OQueryDescriptor_Base: caught an exception!");
157 }
158
159 m_xCommandDefinition->addPropertyChangeListener(::rtl::OUString(), this);
160 // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
161 m_xCommandPropInfo = m_xCommandDefinition->getPropertySetInfo();
162 }
163 DBG_ASSERT(m_xConnection.is(), "OQuery::OQuery : invalid connection !");
164 osl_decrementInterlockedCount(&m_refCount);
165 }
166
167 //--------------------------------------------------------------------------
~OQuery()168 OQuery::~OQuery()
169 {
170 DBG_DTOR(OQuery, NULL);
171 }
172 // -----------------------------------------------------------------------------
173 IMPLEMENT_IMPLEMENTATION_ID(OQuery);
174 IMPLEMENT_GETTYPES3(OQuery,OQueryDescriptor_Base,ODataSettings,OContentHelper);
IMPLEMENT_FORWARD_XINTERFACE3(OQuery,OContentHelper,OQueryDescriptor_Base,ODataSettings)175 IMPLEMENT_FORWARD_XINTERFACE3( OQuery,OContentHelper,OQueryDescriptor_Base,ODataSettings)
176 //--------------------------------------------------------------------------
177 void OQuery::rebuildColumns()
178 {
179 OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
180 // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
181
182 try
183 {
184 m_pColumnMediator = NULL;
185
186 Reference<XColumnsSupplier> xColSup(m_xCommandDefinition,UNO_QUERY);
187 Reference< XNameAccess > xColumnDefinitions;
188 if ( xColSup.is() )
189 {
190 xColumnDefinitions = xColSup->getColumns();
191 if ( xColumnDefinitions.is() )
192 m_pColumnMediator = new OContainerMediator( m_pColumns, xColumnDefinitions, m_xConnection, OContainerMediator::eColumns );
193 }
194
195 // fill the columns with columns from the statement
196 Reference< XMultiServiceFactory > xFactory( m_xConnection, UNO_QUERY_THROW );
197 SharedUNOComponent< XSingleSelectQueryComposer, DisposableComponent > xComposer(
198 Reference< XSingleSelectQueryComposer >( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ) );
199
200 Reference< XNameAccess > xColumns;
201 Reference< XIndexAccess > xColumnsIndexed;
202 try
203 {
204 xComposer->setQuery( m_sCommand );
205 Reference< XColumnsSupplier > xCols( xComposer, UNO_QUERY_THROW );
206 xColumns.set( xCols->getColumns(), UNO_QUERY_THROW );
207 xColumnsIndexed.set( xColumns, UNO_QUERY_THROW );
208 }
209 catch( const SQLException& ) { }
210
211 SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
212 if ( !xColumns.is() || ( xColumnsIndexed->getCount() == 0 ) )
213 { // the QueryComposer could not parse it. Try a lean version.
214 xPreparedStatement.set( m_xConnection->prepareStatement( m_sCommand ), UNO_QUERY_THROW );
215 Reference< XResultSetMetaDataSupplier > xResMetaDataSup( xPreparedStatement, UNO_QUERY_THROW );
216 Reference< XResultSetMetaData > xResultSetMeta( xResMetaDataSup->getMetaData() );
217 if ( !xResultSetMeta.is() )
218 {
219 ::rtl::OUString sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET ) );
220 ::dbtools::throwSQLException( sError, SQL_GENERAL_ERROR, *this );
221 }
222
223 Reference< XDatabaseMetaData > xDBMeta( m_xConnection->getMetaData(), UNO_QUERY_THROW );
224 ::vos::ORef< OSQLColumns > aParseColumns(
225 ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, xDBMeta,xColumnDefinitions ) );
226 xColumns = OPrivateColumns::createWithIntrinsicNames(
227 aParseColumns, xDBMeta->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex );
228 if ( !xColumns.is() )
229 throw RuntimeException();
230 }
231
232 Sequence< ::rtl::OUString> aNames = xColumns->getElementNames();
233 const ::rtl::OUString* pIter = aNames.getConstArray();
234 const ::rtl::OUString* pEnd = pIter + aNames.getLength();
235 for ( sal_Int32 i = 0;pIter != pEnd; ++pIter,++i)
236 {
237 Reference<XPropertySet> xSource(xColumns->getByName( *pIter ),UNO_QUERY);
238 ::rtl::OUString sLabel = *pIter;
239 if ( xColumnDefinitions.is() && xColumnDefinitions->hasByName(*pIter) )
240 {
241 Reference<XPropertySet> xCommandColumn(xColumnDefinitions->getByName( *pIter ),UNO_QUERY);
242 xCommandColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
243 }
244 OQueryColumn* pColumn = new OQueryColumn( xSource, m_xConnection, sLabel);
245 Reference< XChild > xChild( *pColumn, UNO_QUERY_THROW );
246 xChild->setParent( *this );
247
248 implAppendColumn( *pIter, pColumn );
249 Reference< XPropertySet > xDest( *pColumn, UNO_QUERY_THROW );
250 if ( m_pColumnMediator.is() )
251 m_pColumnMediator->notifyElementCreated( *pIter, xDest );
252 }
253 }
254 catch( const SQLContext& e )
255 {
256 if ( m_pWarnings )
257 m_pWarnings->appendWarning( e );
258 }
259 catch( const SQLWarning& e )
260 {
261 if ( m_pWarnings )
262 m_pWarnings->appendWarning( e );
263 }
264 catch( const SQLException& e )
265 {
266 if ( m_pWarnings )
267 m_pWarnings->appendWarning( e );
268 }
269 catch( const Exception& )
270 {
271 DBG_UNHANDLED_EXCEPTION();
272 }
273 }
274
275 // XServiceInfo
276 //--------------------------------------------------------------------------
277 IMPLEMENT_SERVICE_INFO3(OQuery, "com.sun.star.sdb.dbaccess.OQuery", SERVICE_SDB_DATASETTINGS, SERVICE_SDB_QUERY, SERVICE_SDB_QUERYDEFINITION)
278
279 // ::com::sun::star::beans::XPropertyChangeListener
280 //--------------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & _rSource)281 void SAL_CALL OQuery::propertyChange( const PropertyChangeEvent& _rSource ) throw(RuntimeException)
282 {
283 sal_Int32 nOwnHandle = -1;
284 {
285 MutexGuard aGuard(m_aMutex);
286
287 DBG_ASSERT(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
288 "OQuery::propertyChange : where did this call come from ?");
289
290 if (m_eDoingCurrently == SETTING_PROPERTIES)
291 // we're setting the property ourself, so we will do the necessary notifications later
292 return;
293
294 // forward this to our own member holding a copy of the property value
295 if (getArrayHelper()->hasPropertyByName(_rSource.PropertyName))
296 {
297 Property aOwnProp = getArrayHelper()->getPropertyByName(_rSource.PropertyName);
298 nOwnHandle = aOwnProp.Handle;
299 ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle, _rSource.NewValue);
300 // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
301 // again
302 // and don't use the "real" setPropertyValue, this is to expensive and not sure to succeed
303 }
304 else
305 {
306 DBG_ERROR("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
307 }
308 }
309
310 fire(&nOwnHandle, &_rSource.NewValue, &_rSource.OldValue, 1, sal_False);
311 }
312
313 //--------------------------------------------------------------------------
disposing(const EventObject & _rSource)314 void SAL_CALL OQuery::disposing( const EventObject& _rSource ) throw (RuntimeException)
315 {
316 MutexGuard aGuard(m_aMutex);
317
318 (void)_rSource;
319 DBG_ASSERT(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
320 "OQuery::disposing : where did this call come from ?");
321
322 m_xCommandDefinition->removePropertyChangeListener(::rtl::OUString(), this);
323 m_xCommandDefinition = NULL;
324 }
325
326 // XDataDescriptorFactory
327 //--------------------------------------------------------------------------
createDataDescriptor()328 Reference< XPropertySet > SAL_CALL OQuery::createDataDescriptor( ) throw(RuntimeException)
329 {
330 return new OQueryDescriptor(*this);
331 }
332
333 // pseudo-XComponent
334 //--------------------------------------------------------------------------
disposing()335 void SAL_CALL OQuery::disposing()
336 {
337 MutexGuard aGuard(m_aMutex);
338 if (m_xCommandDefinition.is())
339 {
340 m_xCommandDefinition->removePropertyChangeListener(::rtl::OUString(), this);
341 m_xCommandDefinition = NULL;
342 }
343 disposeColumns();
344
345 m_pWarnings = NULL;
346 }
347
348 //--------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle,const Any & _rValue)349 void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception)
350 {
351 ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
352 ::rtl::OUString sAggPropName;
353 sal_Int16 nAttr = 0;
354 if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName,&nAttr,_nHandle) &&
355 m_xCommandPropInfo.is() &&
356 m_xCommandPropInfo->hasPropertyByName(sAggPropName))
357 { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
358
359 m_eDoingCurrently = SETTING_PROPERTIES;
360 OAutoActionReset aActionResetter(this);
361 m_xCommandDefinition->setPropertyValue(sAggPropName, _rValue);
362
363 if ( PROPERTY_ID_COMMAND == _nHandle )
364 // the columns are out of date if we are based on a new statement ....
365 // 90573 - 16.08.2001 - frank.schoenheit@sun.com
366 setColumnsOutOfDate();
367 }
368 }
369
370 //--------------------------------------------------------------------------
getPropertySetInfo()371 Reference< XPropertySetInfo > SAL_CALL OQuery::getPropertySetInfo( ) throw(RuntimeException)
372 {
373 return createPropertySetInfo( getInfoHelper() ) ;
374 }
375
376 //------------------------------------------------------------------------------
getInfoHelper()377 ::cppu::IPropertyArrayHelper& OQuery::getInfoHelper()
378 {
379 return *getArrayHelper();
380 }
381
382 //--------------------------------------------------------------------------
createArrayHelper() const383 ::cppu::IPropertyArrayHelper* OQuery::createArrayHelper( ) const
384 {
385 Sequence< Property > aProps;
386 // our own props
387 describeProperties(aProps);
388 return new ::cppu::OPropertyArrayHelper(aProps);
389 }
390 // -----------------------------------------------------------------------------
createColumn(const::rtl::OUString &) const391 OColumn* OQuery::createColumn(const ::rtl::OUString& /*_rName*/) const
392 {
393 return NULL;
394 }
395 // -----------------------------------------------------------------------------
rename(const::rtl::OUString & newName)396 void SAL_CALL OQuery::rename( const ::rtl::OUString& newName ) throw (SQLException, ElementExistException, RuntimeException)
397 {
398 MutexGuard aGuard(m_aMutex);
399 Reference<XRename> xRename(m_xCommandDefinition,UNO_QUERY);
400 OSL_ENSURE(xRename.is(),"No XRename interface!");
401 if(xRename.is())
402 xRename->rename(newName);
403 }
404 // -----------------------------------------------------------------------------
registerProperties()405 void OQuery::registerProperties()
406 {
407 // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
408 // a OPropertyStateContainer)
409 registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND|PropertyAttribute::CONSTRAINED,
410 &m_sElementName, ::getCppuType(&m_sElementName));
411
412 registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
413 &m_sCommand, ::getCppuType(&m_sCommand));
414
415 registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
416 &m_bEscapeProcessing, ::getBooleanCppuType());
417
418 registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
419 &m_sUpdateTableName, ::getCppuType(&m_sUpdateTableName));
420
421 registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
422 &m_sUpdateSchemaName, ::getCppuType(&m_sUpdateSchemaName));
423
424 registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
425 &m_sUpdateCatalogName, ::getCppuType(&m_sUpdateCatalogName));
426
427 registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
428 &m_aLayoutInformation, ::getCppuType(&m_aLayoutInformation));
429 }
430
431 // -----------------------------------------------------------------------------
determineContentType() const432 ::rtl::OUString OQuery::determineContentType() const
433 {
434 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQuery" ) );
435 }
436
437 // -----------------------------------------------------------------------------
438 //........................................................................
439 } // namespace dbaccess
440 //........................................................................
441
442