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