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