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 #include "RTableConnectionData.hxx" 31 #include <tools/debug.hxx> 32 #include <com/sun/star/sdbc/KeyRule.hpp> 33 #include <com/sun/star/sdbcx/KeyType.hpp> 34 #include <com/sun/star/sdbcx/XKeysSupplier.hpp> 35 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp> 36 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> 37 #include <com/sun/star/sdbcx/XAppend.hpp> 38 #include <com/sun/star/sdbcx/XDrop.hpp> 39 #include <com/sun/star/container/XIndexAccess.hpp> 40 #include "dbustrings.hrc" 41 #include "dbu_rel.hrc" 42 #include "UITools.hxx" 43 #include "moduledbu.hxx" 44 #include <connectivity/dbexception.hxx> 45 #include <connectivity/dbtools.hxx> 46 47 using namespace dbaui; 48 using namespace ::com::sun::star::sdbc; 49 using namespace ::com::sun::star::sdbcx; 50 using namespace ::com::sun::star::uno; 51 using namespace ::com::sun::star::beans; 52 using namespace ::com::sun::star::container; 53 using namespace ::com::sun::star::lang; 54 55 DBG_NAME(ORelationTableConnectionData) 56 //======================================================================== 57 // class ORelationTableConnectionData 58 //======================================================================== 59 //------------------------------------------------------------------------ 60 ORelationTableConnectionData::ORelationTableConnectionData() 61 :OTableConnectionData() 62 ,m_nUpdateRules(KeyRule::NO_ACTION) 63 ,m_nDeleteRules(KeyRule::NO_ACTION) 64 ,m_nCardinality(CARDINAL_UNDEFINED) 65 { 66 DBG_CTOR(ORelationTableConnectionData,NULL); 67 } 68 //------------------------------------------------------------------------ 69 ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable, 70 const TTableWindowData::value_type& _pReferencedTable, 71 const ::rtl::OUString& rConnName ) 72 :OTableConnectionData( _pReferencingTable, _pReferencedTable ) 73 ,m_nUpdateRules(KeyRule::NO_ACTION) 74 ,m_nDeleteRules(KeyRule::NO_ACTION) 75 ,m_nCardinality(CARDINAL_UNDEFINED) 76 { 77 DBG_CTOR(ORelationTableConnectionData,NULL); 78 m_aConnName = rConnName; 79 80 if ( m_aConnName.Len() ) 81 SetCardinality(); 82 } 83 84 //------------------------------------------------------------------------ 85 ORelationTableConnectionData::ORelationTableConnectionData( const ORelationTableConnectionData& rConnData ) 86 :OTableConnectionData( rConnData ) 87 { 88 DBG_CTOR(ORelationTableConnectionData,NULL); 89 *this = rConnData; 90 } 91 92 //------------------------------------------------------------------------ 93 ORelationTableConnectionData::~ORelationTableConnectionData() 94 { 95 DBG_DTOR(ORelationTableConnectionData,NULL); 96 } 97 98 //------------------------------------------------------------------------ 99 sal_Bool ORelationTableConnectionData::DropRelation() 100 { 101 DBG_CHKTHIS(ORelationTableConnectionData,NULL); 102 ::osl::MutexGuard aGuard( m_aMutex ); 103 //////////////////////////////////////////////////////////// 104 // Relation loeschen 105 Reference< XIndexAccess> xKeys = getReferencingTable()->getKeys(); 106 if( m_aConnName.Len() && xKeys.is() ) 107 { 108 const sal_Int32 nCount = xKeys->getCount(); 109 for(sal_Int32 i = 0;i < nCount;++i) 110 { 111 Reference< XPropertySet> xKey(xKeys->getByIndex(i),UNO_QUERY); 112 OSL_ENSURE(xKey.is(),"Key is not valid!"); 113 if(xKey.is()) 114 { 115 ::rtl::OUString sName; 116 xKey->getPropertyValue(PROPERTY_NAME) >>= sName; 117 if(String(sName) == m_aConnName) 118 { 119 Reference< XDrop> xDrop(xKeys,UNO_QUERY); 120 OSL_ENSURE(xDrop.is(),"can't drop key because we haven't a drop interface!"); 121 if(xDrop.is()) 122 xDrop->dropByIndex(i); 123 break; 124 } 125 } 126 } 127 } 128 return sal_True; 129 } 130 131 //------------------------------------------------------------------------ 132 void ORelationTableConnectionData::ChangeOrientation() 133 { 134 DBG_CHKTHIS(ORelationTableConnectionData,NULL); 135 ////////////////////////////////////////////////////////////////////// 136 // Source- und DestFieldName der Linien austauschen 137 ::rtl::OUString sTempString; 138 OConnectionLineDataVec::iterator aIter = m_vConnLineData.begin(); 139 OConnectionLineDataVec::iterator aEnd = m_vConnLineData.end(); 140 for(;aIter != aEnd;++aIter) 141 { 142 sTempString = (*aIter)->GetSourceFieldName(); 143 (*aIter)->SetSourceFieldName( (*aIter)->GetDestFieldName() ); 144 (*aIter)->SetDestFieldName( sTempString ); 145 } 146 147 ////////////////////////////////////////////////////////////////////// 148 // Member anpassen 149 TTableWindowData::value_type pTemp = m_pReferencingTable; 150 m_pReferencingTable = m_pReferencedTable; 151 m_pReferencedTable = pTemp; 152 } 153 154 //------------------------------------------------------------------------ 155 void ORelationTableConnectionData::SetCardinality() 156 { 157 DBG_CHKTHIS(ORelationTableConnectionData,NULL); 158 ::osl::MutexGuard aGuard( m_aMutex ); 159 m_nCardinality = CARDINAL_UNDEFINED; 160 161 if( IsSourcePrimKey() ) 162 { 163 if( IsDestPrimKey() ) 164 m_nCardinality = CARDINAL_ONE_ONE; 165 else 166 m_nCardinality = CARDINAL_ONE_MANY; 167 } 168 169 if( IsDestPrimKey() ) 170 { 171 if( !IsSourcePrimKey() ) 172 m_nCardinality = CARDINAL_MANY_ONE; 173 } 174 175 } 176 // ----------------------------------------------------------------------------- 177 sal_Bool ORelationTableConnectionData::checkPrimaryKey(const Reference< XPropertySet>& i_xTable,EConnectionSide _eEConnectionSide) const 178 { 179 // check if Table has the primary key column dependig on _eEConnectionSide 180 sal_uInt16 nPrimKeysCount = 0, 181 nValidLinesCount = 0; 182 const Reference< XNameAccess> xKeyColumns = dbtools::getPrimaryKeyColumns_throw(i_xTable); 183 if ( xKeyColumns.is() ) 184 { 185 Sequence< ::rtl::OUString> aKeyColumns = xKeyColumns->getElementNames(); 186 const ::rtl::OUString* pKeyIter = aKeyColumns.getConstArray(); 187 const ::rtl::OUString* pKeyEnd = pKeyIter + aKeyColumns.getLength(); 188 189 for(;pKeyIter != pKeyEnd;++pKeyIter) 190 { 191 OConnectionLineDataVec::const_iterator aIter = m_vConnLineData.begin(); 192 OConnectionLineDataVec::const_iterator aEnd = m_vConnLineData.end(); 193 for(;aIter != aEnd;++aIter) 194 { 195 ++nValidLinesCount; 196 if ( (*aIter)->GetFieldName(_eEConnectionSide) == *pKeyIter ) 197 { 198 ++nPrimKeysCount; 199 break; 200 } 201 } 202 } 203 if ( nPrimKeysCount != aKeyColumns.getLength() ) 204 return sal_False; 205 } 206 if ( !nPrimKeysCount || nPrimKeysCount != nValidLinesCount ) 207 return sal_False; 208 209 return sal_True; 210 } 211 //------------------------------------------------------------------------ 212 sal_Bool ORelationTableConnectionData::IsConnectionPossible() 213 { 214 DBG_CHKTHIS(ORelationTableConnectionData,NULL); 215 ::osl::MutexGuard aGuard( m_aMutex ); 216 217 ////////////////////////////////////////////////////////////////////// 218 // Wenn die SourceFelder ein PrimKey sind, ist nur die Orientierung falsch 219 if ( IsSourcePrimKey() && !IsDestPrimKey() ) 220 ChangeOrientation(); 221 222 return sal_True; 223 } 224 225 //------------------------------------------------------------------------ 226 OConnectionLineDataRef ORelationTableConnectionData::CreateLineDataObj() 227 { 228 return new OConnectionLineData(); 229 } 230 231 //------------------------------------------------------------------------ 232 OConnectionLineDataRef ORelationTableConnectionData::CreateLineDataObj( const OConnectionLineData& rConnLineData ) 233 { 234 return new OConnectionLineData( rConnLineData ); 235 } 236 237 //------------------------------------------------------------------------ 238 void ORelationTableConnectionData::CopyFrom(const OTableConnectionData& rSource) 239 { 240 // wie in der Basisklasse zurueckziehen auf das (nicht-virtuelle) operator= 241 *this = *static_cast<const ORelationTableConnectionData*>(&rSource); 242 } 243 244 //------------------------------------------------------------------------ 245 ORelationTableConnectionData& ORelationTableConnectionData::operator=( const ORelationTableConnectionData& rConnData ) 246 { 247 if (&rConnData == this) 248 return *this; 249 250 OTableConnectionData::operator=( rConnData ); 251 m_nUpdateRules = rConnData.GetUpdateRules(); 252 m_nDeleteRules = rConnData.GetDeleteRules(); 253 m_nCardinality = rConnData.GetCardinality(); 254 255 return *this; 256 } 257 namespace dbaui 258 { 259 //------------------------------------------------------------------------- 260 bool operator==(const ORelationTableConnectionData& lhs, const ORelationTableConnectionData& rhs) 261 { 262 bool bEqual = (lhs.m_nUpdateRules == rhs.m_nUpdateRules) 263 && (lhs.m_nDeleteRules == rhs.m_nDeleteRules) 264 && (lhs.m_nCardinality == rhs.m_nCardinality) 265 && (lhs.getReferencingTable() == rhs.getReferencingTable()) 266 && (lhs.getReferencedTable() == rhs.getReferencedTable()) 267 && (lhs.m_aConnName == rhs.m_aConnName) 268 && (lhs.m_vConnLineData.size() == rhs.m_vConnLineData.size()); 269 270 if ( bEqual ) 271 { 272 std::vector< OConnectionLineDataRef >::const_iterator aIter = lhs.m_vConnLineData.begin(); 273 std::vector< OConnectionLineDataRef >::const_iterator aEnd = lhs.m_vConnLineData.end(); 274 for (sal_Int32 i = 0; aIter != aEnd; ++aIter,++i) 275 { 276 if ( *(rhs.m_vConnLineData[i]) != **aIter ) 277 break; 278 } 279 bEqual = aIter == aEnd; 280 } 281 return bEqual; 282 } 283 } 284 //------------------------------------------------------------------------ 285 sal_Bool ORelationTableConnectionData::Update() 286 { 287 ::osl::MutexGuard aGuard( m_aMutex ); 288 //////////////////////////////////////////////////////////// 289 // Alte Relation loeschen 290 { 291 DropRelation(); 292 if( !IsConnectionPossible() ) 293 return sal_False; 294 } 295 296 // reassign the keys because the orientaion could be changed 297 Reference<XPropertySet> xTableProp(getReferencingTable()->getTable()); 298 Reference< XIndexAccess> xKeys ( getReferencingTable()->getKeys()); 299 300 if ( !xKeys.is() ) 301 return sal_False; 302 //////////////////////////////////////////////////////////// 303 // Neue Relation erzeugen 304 Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY); 305 OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); 306 Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); 307 OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); 308 309 Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); 310 OSL_ENSURE(xKey.is(),"Key is null!"); 311 if ( xKey.is() && xTableProp.is() ) 312 { 313 // build a foreign key name 314 ::rtl::OUString sSourceName; 315 xTableProp->getPropertyValue(PROPERTY_NAME) >>= sSourceName; 316 ::rtl::OUString sKeyName = sSourceName; 317 sKeyName += getReferencedTable()->GetTableName(); 318 319 xKey->setPropertyValue(PROPERTY_NAME,makeAny(sKeyName)); 320 xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::FOREIGN)); 321 xKey->setPropertyValue(PROPERTY_REFERENCEDTABLE,makeAny(::rtl::OUString(getReferencedTable()->GetTableName()))); 322 xKey->setPropertyValue(PROPERTY_UPDATERULE, makeAny(GetUpdateRules())); 323 xKey->setPropertyValue(PROPERTY_DELETERULE, makeAny(GetDeleteRules())); 324 } 325 326 Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); 327 if ( xColSup.is() ) 328 { 329 Reference<XNameAccess> xColumns = xColSup->getColumns(); 330 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); 331 Reference<XAppend> xColumnAppend(xColumns,UNO_QUERY); 332 if ( xColumnFactory.is() ) 333 { 334 OConnectionLineDataVec::iterator aIter = m_vConnLineData.begin(); 335 OConnectionLineDataVec::iterator aEnd = m_vConnLineData.end(); 336 for(;aIter != aEnd;++aIter) 337 { 338 if((*aIter)->GetSourceFieldName().getLength() && (*aIter)->GetDestFieldName().getLength()) 339 { 340 Reference<XPropertySet> xColumn; 341 xColumn = xColumnFactory->createDataDescriptor(); 342 if ( xColumn.is() ) 343 { 344 xColumn->setPropertyValue(PROPERTY_NAME,makeAny((*aIter)->GetSourceFieldName())); 345 xColumn->setPropertyValue(PROPERTY_RELATEDCOLUMN,makeAny((*aIter)->GetDestFieldName())); 346 xColumnAppend->appendByDescriptor(xColumn); 347 } 348 } 349 } 350 351 if ( xColumns->hasElements() ) 352 xAppend->appendByDescriptor(xKey); 353 } 354 // to get the key we have to reget it because after append it is no longer valid 355 } 356 357 // get the name of foreign key // search for columns 358 m_aConnName = ::rtl::OUString(); 359 xKey.clear(); 360 bool bDropRelation = false; 361 for(sal_Int32 i=0;i<xKeys->getCount();++i) 362 { 363 xKeys->getByIndex(i) >>= xKey; 364 OSL_ENSURE(xKey.is(),"Key is not valid!"); 365 if ( xKey.is() ) 366 { 367 sal_Int32 nType = 0; 368 xKey->getPropertyValue(PROPERTY_TYPE) >>= nType; 369 ::rtl::OUString sReferencedTable; 370 xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable; 371 if ( sReferencedTable == ::rtl::OUString(getReferencedTable()->GetTableName()) ) 372 { 373 xColSup.set(xKey,UNO_QUERY_THROW); 374 try 375 { 376 Reference<XNameAccess> xColumns = xColSup->getColumns(); 377 Sequence< ::rtl::OUString> aNames = xColumns->getElementNames(); 378 const ::rtl::OUString* pIter = aNames.getConstArray(); 379 const ::rtl::OUString* pEnd = pIter + aNames.getLength(); 380 381 Reference<XPropertySet> xColumn; 382 ::rtl::OUString sName,sRelatedColumn; 383 for ( ; pIter != pEnd ; ++pIter ) 384 { 385 xColumn.set(xColumns->getByName(*pIter),UNO_QUERY_THROW); 386 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; 387 xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn; 388 389 OConnectionLineDataVec::iterator aIter = m_vConnLineData.begin(); 390 OConnectionLineDataVec::iterator aEnd = m_vConnLineData.end(); 391 for(;aIter != aEnd;++aIter) 392 { 393 if( (*aIter)->GetSourceFieldName() == sName 394 && (*aIter)->GetDestFieldName() == sRelatedColumn ) 395 { 396 break; 397 } 398 } 399 if ( aIter == m_vConnLineData.end() ) 400 break; 401 } 402 if ( pIter == pEnd ) 403 { 404 xKey->getPropertyValue(PROPERTY_NAME) >>= sName; 405 m_aConnName = sName; 406 bDropRelation = aNames.getLength() == 0; // the key contains no column, so it isn't valid and we have to drop it 407 //here we already know our column structure so we don't have to recreate the table connection data 408 xColSup.clear(); 409 break; 410 } 411 } 412 catch(Exception&) 413 { 414 } 415 } 416 } 417 xKey.clear(); 418 } // for(sal_Int32 i=0;i<xKeys->getCount();++i) 419 if ( bDropRelation ) 420 { 421 DropRelation(); 422 String sError(ModuleRes(STR_QUERY_REL_COULD_NOT_CREATE)); 423 ::dbtools::throwGenericSQLException(sError,NULL); 424 } 425 426 // OSL_ENSURE(xKey.is(),"No key found have insertion!"); 427 428 // The fields the relation marks may not be the same as our LineDatas mark after the relation has been updated 429 if ( xColSup.is() ) 430 { 431 OConnectionLineDataVec().swap(m_vConnLineData); 432 Reference<XNameAccess> xColumns = xColSup->getColumns(); 433 Sequence< ::rtl::OUString> aNames = xColumns->getElementNames(); 434 const ::rtl::OUString* pIter = aNames.getConstArray(); 435 const ::rtl::OUString* pEnd = pIter + aNames.getLength(); 436 437 m_vConnLineData.reserve( aNames.getLength() ); 438 Reference<XPropertySet> xColumn; 439 ::rtl::OUString sName,sRelatedColumn; 440 441 for(;pIter != pEnd;++pIter) 442 { 443 xColumns->getByName(*pIter) >>= xColumn; 444 if ( xColumn.is() ) 445 { 446 OConnectionLineDataRef pNewData = CreateLineDataObj(); 447 448 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; 449 xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn; 450 451 pNewData->SetSourceFieldName(sName); 452 pNewData->SetDestFieldName(sRelatedColumn); 453 m_vConnLineData.push_back(pNewData); 454 } 455 } 456 } // if ( xColSup.is() ) 457 // NOTE : the caller is resposible for updating any other objects referencing the old LineDatas (for instance a ConnLine) 458 459 //////////////////////////////////////////////////////////// 460 // Kardinalitaet bestimmen 461 SetCardinality(); 462 463 return sal_True; 464 } 465 // ----------------------------------------------------------------------------- 466 467