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