xref: /trunk/main/dbaccess/source/core/api/query.cxx (revision 96de5490)
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 //==========================================================================
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 //--------------------------------------------------------------------------
168 OQuery::~OQuery()
169 {
170 	DBG_DTOR(OQuery, NULL);
171 }
172 // -----------------------------------------------------------------------------
173 IMPLEMENT_IMPLEMENTATION_ID(OQuery);
174 IMPLEMENT_GETTYPES3(OQuery,OQueryDescriptor_Base,ODataSettings,OContentHelper);
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 //--------------------------------------------------------------------------
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 neccessary 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 //--------------------------------------------------------------------------
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 //--------------------------------------------------------------------------
328 Reference< XPropertySet > SAL_CALL OQuery::createDataDescriptor(  ) throw(RuntimeException)
329 {
330 	return new OQueryDescriptor(*this);
331 }
332 
333 // pseudo-XComponent
334 //--------------------------------------------------------------------------
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 //--------------------------------------------------------------------------
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 //--------------------------------------------------------------------------
371 Reference< XPropertySetInfo > SAL_CALL OQuery::getPropertySetInfo(	) throw(RuntimeException)
372 {
373 	return createPropertySetInfo( getInfoHelper() ) ;
374 }
375 
376 //------------------------------------------------------------------------------
377 ::cppu::IPropertyArrayHelper& OQuery::getInfoHelper()
378 {
379 	return *getArrayHelper();
380 }
381 
382 //--------------------------------------------------------------------------
383 ::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 // -----------------------------------------------------------------------------
391 OColumn* OQuery::createColumn(const ::rtl::OUString& /*_rName*/) const
392 {
393 	return NULL;
394 }
395 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
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 // -----------------------------------------------------------------------------
432 ::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