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