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 #include "tablecontainer.hxx" 32 #include "dbastrings.hrc" 33 #include "table.hxx" 34 #include <comphelper/property.hxx> 35 #include <comphelper/processfactory.hxx> 36 #include <tools/debug.hxx> 37 #include <comphelper/enumhelper.hxx> 38 #include "core_resource.hxx" 39 #include "core_resource.hrc" 40 #include <com/sun/star/sdb/CommandType.hpp> 41 #include <com/sun/star/beans/XPropertySet.hpp> 42 #include <com/sun/star/beans/PropertyState.hpp> 43 #include <com/sun/star/beans/XPropertyState.hpp> 44 #include <com/sun/star/sdbc/XConnection.hpp> 45 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp> 46 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp> 48 #include <com/sun/star/sdbc/KeyRule.hpp> 49 #include <com/sun/star/sdbcx/KeyType.hpp> 50 #include <com/sun/star/sdbc/ColumnValue.hpp> 51 #include <com/sun/star/sdbc/XRow.hpp> 52 #include <comphelper/types.hxx> 53 #include <connectivity/dbtools.hxx> 54 #include <comphelper/extract.hxx> 55 #include <connectivity/dbexception.hxx> 56 #include "TableDeco.hxx" 57 #include "sdbcoretools.hxx" 58 #include "ContainerMediator.hxx" 59 #include "definitioncolumn.hxx" 60 #include "objectnameapproval.hxx" 61 #include <tools/string.hxx> 62 #include <rtl/logfile.hxx> 63 #ifndef TOOLS_DIAGNOSE_EX_H 64 #include <tools/diagnose_ex.h> 65 #endif 66 #ifndef TOOLS_DIAGNOSE_EX_H 67 #include <tools/diagnose_ex.h> 68 #endif 69 70 using namespace dbaccess; 71 using namespace dbtools; 72 using namespace ::com::sun::star::uno; 73 using namespace ::com::sun::star::lang; 74 using namespace ::com::sun::star::beans; 75 using namespace ::com::sun::star::sdbc; 76 using namespace ::com::sun::star::sdb; 77 using namespace ::com::sun::star::sdbcx; 78 using namespace ::com::sun::star::container; 79 using namespace ::com::sun::star::util; 80 using namespace ::osl; 81 using namespace ::comphelper; 82 using namespace ::cppu; 83 using namespace ::connectivity::sdbcx; 84 85 namespace 86 { 87 sal_Bool lcl_isPropertySetDefaulted(const Sequence< ::rtl::OUString>& _aNames,const Reference<XPropertySet>& _xProp) 88 { 89 Reference<XPropertyState> xState(_xProp,UNO_QUERY); 90 if ( xState.is() ) 91 { 92 const ::rtl::OUString* pIter = _aNames.getConstArray(); 93 const ::rtl::OUString* pEnd = pIter + _aNames.getLength(); 94 for(;pIter != pEnd;++pIter) 95 { 96 try 97 { 98 PropertyState aState = xState->getPropertyState(*pIter); 99 if ( aState != PropertyState_DEFAULT_VALUE ) 100 break; 101 } 102 catch(Exception) 103 { 104 OSL_ENSURE( 0, "lcl_isPropertySetDefaulted: Exception caught!" ); 105 } 106 } 107 return ( pIter == pEnd ); 108 } 109 return sal_False; 110 } 111 } 112 //========================================================================== 113 //= OTableContainer 114 //========================================================================== 115 DBG_NAME(OTableContainer) 116 //------------------------------------------------------------------------------ 117 OTableContainer::OTableContainer(::cppu::OWeakObject& _rParent, 118 ::osl::Mutex& _rMutex, 119 const Reference< XConnection >& _xCon, 120 sal_Bool _bCase, 121 const Reference< XNameContainer >& _xTableDefinitions, 122 IRefreshListener* _pRefreshListener, 123 ::dbtools::IWarningsContainer* _pWarningsContainer 124 ,oslInterlockedCount& _nInAppend) 125 :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_pWarningsContainer,_nInAppend) 126 ,m_xTableDefinitions(_xTableDefinitions) 127 ,m_pTableMediator( NULL ) 128 ,m_bInDrop(sal_False) 129 { 130 DBG_CTOR(OTableContainer, NULL); 131 } 132 133 //------------------------------------------------------------------------------ 134 OTableContainer::~OTableContainer() 135 { 136 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::OTableContainer" ); 137 // dispose(); 138 DBG_DTOR(OTableContainer, NULL); 139 } 140 141 // ----------------------------------------------------------------------------- 142 void OTableContainer::removeMasterContainerListener() 143 { 144 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::removeMasterContainerListener" ); 145 try 146 { 147 Reference<XContainer> xCont( m_xMasterContainer, UNO_QUERY_THROW ); 148 xCont->removeContainerListener( this ); 149 } 150 catch( const Exception& ) 151 { 152 DBG_UNHANDLED_EXCEPTION(); 153 } 154 } 155 156 // ----------------------------------------------------------------------------- 157 ::rtl::OUString OTableContainer::getTableTypeRestriction() const 158 { 159 // no restriction at all (other than the ones provided externally) 160 return ::rtl::OUString(); 161 } 162 163 // ----------------------------------------------------------------------------- 164 // XServiceInfo 165 //------------------------------------------------------------------------------ 166 IMPLEMENT_SERVICE_INFO2(OTableContainer, "com.sun.star.sdb.dbaccess.OTableContainer", SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES) 167 168 // ----------------------------------------------------------------------------- 169 namespace 170 { 171 void lcl_createDefintionObject(const ::rtl::OUString& _rName 172 ,const Reference< XNameContainer >& _xTableDefinitions 173 ,Reference<XPropertySet>& _xTableDefinition 174 ,Reference<XNameAccess>& _xColumnDefinitions 175 ,sal_Bool _bModified) 176 { 177 if ( _xTableDefinitions.is() ) 178 { 179 if ( _xTableDefinitions->hasByName(_rName) ) 180 _xTableDefinition.set(_xTableDefinitions->getByName(_rName),UNO_QUERY); 181 else 182 { 183 Sequence< Any > aArguments(1); 184 PropertyValue aValue; 185 // set as folder 186 aValue.Name = PROPERTY_NAME; 187 aValue.Value <<= _rName; 188 aArguments[0] <<= aValue; 189 _xTableDefinition.set(::comphelper::getProcessServiceFactory()->createInstanceWithArguments(SERVICE_SDB_TABLEDEFINITION,aArguments),UNO_QUERY); 190 _xTableDefinitions->insertByName(_rName,makeAny(_xTableDefinition)); 191 ::dbaccess::notifyDataSourceModified(_xTableDefinitions,_bModified); 192 } 193 Reference<XColumnsSupplier> xColumnsSupplier(_xTableDefinition,UNO_QUERY); 194 if ( xColumnsSupplier.is() ) 195 _xColumnDefinitions = xColumnsSupplier->getColumns(); 196 } 197 } 198 // ------------------------------------------------------------------------- 199 } 200 // ------------------------------------------------------------------------- 201 connectivity::sdbcx::ObjectType OTableContainer::createObject(const ::rtl::OUString& _rName) 202 { 203 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::createObject" ); 204 Reference<XColumnsSupplier > xSup; 205 if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(_rName)) 206 xSup.set(m_xMasterContainer->getByName(_rName),UNO_QUERY); 207 208 connectivity::sdbcx::ObjectType xRet; 209 if ( m_xMetaData.is() ) 210 { 211 Reference<XPropertySet> xTableDefinition; 212 Reference<XNameAccess> xColumnDefinitions; 213 lcl_createDefintionObject(_rName,m_xTableDefinitions,xTableDefinition,xColumnDefinitions,sal_False); 214 215 if ( xSup.is() ) 216 { 217 ODBTableDecorator* pTable = new ODBTableDecorator( m_xConnection, xSup, ::dbtools::getNumberFormats( m_xConnection ) ,xColumnDefinitions); 218 xRet = pTable; 219 pTable->construct(); 220 } 221 else 222 { 223 ::rtl::OUString sCatalog,sSchema,sTable; 224 ::dbtools::qualifiedNameComponents(m_xMetaData, 225 _rName, 226 sCatalog, 227 sSchema, 228 sTable, 229 ::dbtools::eInDataManipulation); 230 Any aCatalog; 231 if(sCatalog.getLength()) 232 aCatalog <<= sCatalog; 233 ::rtl::OUString sType,sDescription; 234 Sequence< ::rtl::OUString> aTypeFilter; 235 getAllTableTypeFilter( aTypeFilter ); 236 237 Reference< XResultSet > xRes = m_xMetaData.is() ? m_xMetaData->getTables(aCatalog,sSchema,sTable,aTypeFilter) : Reference< XResultSet >(); 238 if(xRes.is() && xRes->next()) 239 { 240 Reference< XRow > xRow(xRes,UNO_QUERY); 241 if(xRow.is()) 242 { 243 sType = xRow->getString(4); 244 sDescription = xRow->getString(5); 245 } 246 } 247 ::comphelper::disposeComponent(xRes); 248 ODBTable* pTable = new ODBTable(this 249 ,m_xConnection 250 ,sCatalog 251 ,sSchema 252 ,sTable 253 ,sType 254 ,sDescription 255 ,xColumnDefinitions); 256 xRet = pTable; 257 pTable->construct(); 258 } 259 Reference<XPropertySet> xDest(xRet,UNO_QUERY); 260 if ( xTableDefinition.is() ) 261 ::comphelper::copyProperties(xTableDefinition,xDest); 262 263 if ( !m_pTableMediator.is() ) 264 m_pTableMediator = new OContainerMediator( 265 this, m_xTableDefinitions.get(), m_xConnection, OContainerMediator::eTables ); 266 if ( m_pTableMediator.is() ) 267 m_pTableMediator->notifyElementCreated(_rName,xDest); 268 } 269 270 return xRet; 271 } 272 // ----------------------------------------------------------------------------- 273 Reference< XPropertySet > OTableContainer::createDescriptor() 274 { 275 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::createDescriptor" ); 276 Reference< XPropertySet > xRet; 277 278 // frist we have to look if the master tables does support this 279 // and if then create a table object as well with the master tables 280 Reference<XColumnsSupplier > xMasterColumnsSup; 281 Reference<XDataDescriptorFactory> xDataFactory(m_xMasterContainer,UNO_QUERY); 282 if ( xDataFactory.is() && m_xMetaData.is() ) 283 { 284 xMasterColumnsSup = Reference< XColumnsSupplier >( xDataFactory->createDataDescriptor(), UNO_QUERY ); 285 ODBTableDecorator* pTable = new ODBTableDecorator( m_xConnection, xMasterColumnsSup, ::dbtools::getNumberFormats( m_xConnection ) ,NULL); 286 xRet = pTable; 287 pTable->construct(); 288 } 289 else 290 { 291 ODBTable* pTable = new ODBTable(this, m_xConnection); 292 xRet = pTable; 293 pTable->construct(); 294 } 295 return xRet; 296 } 297 // ----------------------------------------------------------------------------- 298 // XAppend 299 ObjectType OTableContainer::appendObject( const ::rtl::OUString& _rForName, const Reference< XPropertySet >& descriptor ) 300 { 301 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::appendObject" ); 302 // append the new table with a create stmt 303 ::rtl::OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME)); 304 if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(aName)) 305 { 306 String sMessage(DBACORE_RESSTRING(RID_STR_TABLE_IS_FILTERED)); 307 sMessage.SearchAndReplaceAscii("$name$", aName); 308 throw SQLException(sMessage,static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)),SQLSTATE_GENERAL,1000,Any()); 309 } 310 311 Reference< XConnection > xConnection( m_xConnection.get(), UNO_QUERY ); 312 PContainerApprove pApprove( new ObjectNameApproval( xConnection, ObjectNameApproval::TypeTable ) ); 313 pApprove->approveElement( aName, descriptor ); 314 315 try 316 { 317 EnsureReset aReset(m_nInAppend); 318 Reference<XAppend> xAppend(m_xMasterContainer,UNO_QUERY); 319 if(xAppend.is()) 320 { 321 xAppend->appendByDescriptor(descriptor); 322 } 323 else 324 { 325 ::rtl::OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,m_xConnection); 326 327 Reference<XConnection> xCon = m_xConnection; 328 OSL_ENSURE(xCon.is(),"Connection is null!"); 329 if ( xCon.is() ) 330 { 331 Reference< XStatement > xStmt = xCon->createStatement( ); 332 if ( xStmt.is() ) 333 xStmt->execute(aSql); 334 ::comphelper::disposeComponent(xStmt); 335 } 336 } 337 } 338 catch(Exception&) 339 { 340 throw; 341 } 342 343 Reference<XPropertySet> xTableDefinition; 344 Reference<XNameAccess> xColumnDefinitions; 345 lcl_createDefintionObject(getNameForObject(descriptor),m_xTableDefinitions,xTableDefinition,xColumnDefinitions,sal_False); 346 Reference<XColumnsSupplier> xSup(descriptor,UNO_QUERY); 347 Reference<XDataDescriptorFactory> xFac(xColumnDefinitions,UNO_QUERY); 348 Reference<XAppend> xAppend(xColumnDefinitions,UNO_QUERY); 349 sal_Bool bModified = sal_False; 350 if ( xSup.is() && xColumnDefinitions.is() && xFac.is() && xAppend.is() ) 351 { 352 Reference<XNameAccess> xNames = xSup->getColumns(); 353 if ( xNames.is() ) 354 { 355 Reference<XPropertySet> xProp = xFac->createDataDescriptor(); 356 Sequence< ::rtl::OUString> aSeq = xNames->getElementNames(); 357 const ::rtl::OUString* pIter = aSeq.getConstArray(); 358 const ::rtl::OUString* pEnd = pIter + aSeq.getLength(); 359 for(;pIter != pEnd;++pIter) 360 { 361 if ( !xColumnDefinitions->hasByName(*pIter) ) 362 { 363 Reference<XPropertySet> xColumn(xNames->getByName(*pIter),UNO_QUERY); 364 if ( !OColumnSettings::hasDefaultSettings( xColumn ) ) 365 { 366 ::comphelper::copyProperties( xColumn, xProp ); 367 xAppend->appendByDescriptor( xProp ); 368 bModified = sal_True; 369 } 370 } 371 } 372 } 373 } 374 const static ::rtl::OUString s_pTableProps[] = { ::rtl::OUString(PROPERTY_FILTER), ::rtl::OUString(PROPERTY_ORDER) 375 , ::rtl::OUString(PROPERTY_APPLYFILTER), ::rtl::OUString(PROPERTY_FONT) 376 , ::rtl::OUString(PROPERTY_ROW_HEIGHT), ::rtl::OUString(PROPERTY_TEXTCOLOR) 377 , ::rtl::OUString(PROPERTY_TEXTLINECOLOR), ::rtl::OUString(PROPERTY_TEXTEMPHASIS) 378 , ::rtl::OUString(PROPERTY_TEXTRELIEF) }; 379 Sequence< ::rtl::OUString> aNames(s_pTableProps,sizeof(s_pTableProps)/sizeof(s_pTableProps[0])); 380 if ( bModified || !lcl_isPropertySetDefaulted(aNames,xTableDefinition) ) 381 ::dbaccess::notifyDataSourceModified(m_xTableDefinitions,sal_True); 382 383 return createObject( _rForName ); 384 } 385 // ------------------------------------------------------------------------- 386 // XDrop 387 void OTableContainer::dropObject(sal_Int32 _nPos,const ::rtl::OUString _sElementName) 388 { 389 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::dropObject" ); 390 m_bInDrop = sal_True; 391 try 392 { 393 Reference< XDrop > xDrop(m_xMasterContainer,UNO_QUERY); 394 if(xDrop.is()) 395 xDrop->dropByName(_sElementName); 396 else 397 { 398 ::rtl::OUString sCatalog,sSchema,sTable,sComposedName; 399 400 sal_Bool bIsView = sal_False; 401 Reference<XPropertySet> xTable(getObject(_nPos),UNO_QUERY); 402 if ( xTable.is() && m_xMetaData.is() ) 403 { 404 if( m_xMetaData.is() && m_xMetaData->supportsCatalogsInTableDefinitions() ) 405 xTable->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog; 406 if( m_xMetaData.is() && m_xMetaData->supportsSchemasInTableDefinitions() ) 407 xTable->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema; 408 xTable->getPropertyValue(PROPERTY_NAME) >>= sTable; 409 410 sComposedName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, sal_True, ::dbtools::eInTableDefinitions ); 411 412 ::rtl::OUString sType; 413 xTable->getPropertyValue(PROPERTY_TYPE) >>= sType; 414 bIsView = sType.equalsIgnoreAsciiCase(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW"))); 415 } 416 417 if(!sComposedName.getLength()) 418 ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this))); 419 420 ::rtl::OUString aSql = ::rtl::OUString::createFromAscii("DROP "); 421 422 // #104282# OJ 423 if ( bIsView ) // here we have a view 424 aSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VIEW ")); 425 else 426 aSql += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TABLE ")); 427 aSql += sComposedName; 428 Reference<XConnection> xCon = m_xConnection; 429 OSL_ENSURE(xCon.is(),"Connection is null!"); 430 if ( xCon.is() ) 431 { 432 Reference< XStatement > xStmt = xCon->createStatement( ); 433 if(xStmt.is()) 434 xStmt->execute(aSql); 435 ::comphelper::disposeComponent(xStmt); 436 } 437 } 438 439 if ( m_xTableDefinitions.is() && m_xTableDefinitions->hasByName(_sElementName) ) 440 { 441 m_xTableDefinitions->removeByName(_sElementName); 442 } 443 } 444 catch(Exception&) 445 { 446 m_bInDrop = sal_False; 447 throw; 448 } 449 m_bInDrop = sal_False; 450 } 451 // ----------------------------------------------------------------------------- 452 void SAL_CALL OTableContainer::elementInserted( const ContainerEvent& Event ) throw (RuntimeException) 453 { 454 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::elementInserted" ); 455 ::osl::MutexGuard aGuard(m_rMutex); 456 ::rtl::OUString sName; 457 Event.Accessor >>= sName; 458 if ( !m_nInAppend && !hasByName(sName) ) 459 { 460 if(!m_xMasterContainer.is() || m_xMasterContainer->hasByName(sName)) 461 { 462 ObjectType xName = createObject(sName); 463 insertElement(sName,xName); 464 // and notify our listeners 465 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xName), Any()); 466 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent ); 467 } 468 } 469 } 470 // ----------------------------------------------------------------------------- 471 void SAL_CALL OTableContainer::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException) 472 { 473 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::elementRemoved" ); 474 } 475 // ----------------------------------------------------------------------------- 476 void SAL_CALL OTableContainer::elementReplaced( const ContainerEvent& Event ) throw (RuntimeException) 477 { 478 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::elementReplaced" ); 479 // create a new config entry 480 { 481 ::rtl::OUString sOldComposedName,sNewComposedName; 482 Event.ReplacedElement >>= sOldComposedName; 483 Event.Accessor >>= sNewComposedName; 484 485 renameObject(sOldComposedName,sNewComposedName); 486 } 487 } 488 // ----------------------------------------------------------------------------- 489 void SAL_CALL OTableContainer::disposing() 490 { 491 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::disposing" ); 492 OFilteredContainer::disposing(); 493 // say our listeners goobye 494 m_xTableDefinitions = NULL; 495 m_pTableMediator = NULL; 496 } 497 // ----------------------------------------------------------------------------- 498 void SAL_CALL OTableContainer::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ ) throw (::com::sun::star::uno::RuntimeException) 499 { 500 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "api", "Ocke.Janssen@sun.com", "OTableContainer::disposing" ); 501 } 502 503 // ----------------------------------------------------------------------------- 504 void OTableContainer::addMasterContainerListener() 505 { 506 try 507 { 508 Reference< XContainer > xCont( m_xMasterContainer, UNO_QUERY_THROW ); 509 xCont->addContainerListener( this ); 510 } 511 catch( const Exception& ) 512 { 513 DBG_UNHANDLED_EXCEPTION(); 514 } 515 } 516 517