1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "RTableConnectionData.hxx"
21 #include <tools/debug.hxx>
22 #include <com/sun/star/sdbc/KeyRule.hpp>
23 #include <com/sun/star/sdbcx/KeyType.hpp>
24 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
25 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
26 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
27 #include <com/sun/star/sdbcx/XAppend.hpp>
28 #include <com/sun/star/sdbcx/XDrop.hpp>
29 #include <com/sun/star/container/XIndexAccess.hpp>
30 #include "dbustrings.hrc"
31 #include "dbu_rel.hrc"
32 #include "UITools.hxx"
33 #include "moduledbu.hxx"
34 #include <connectivity/dbexception.hxx>
35 #include <connectivity/dbtools.hxx>
37 using namespace dbaui
;
38 using namespace ::com::sun::star::sdbc
;
39 using namespace ::com::sun::star::sdbcx
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::beans
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::lang
;
45 // class ORelationTableConnectionData
46 ORelationTableConnectionData::ORelationTableConnectionData()
47 :OTableConnectionData()
48 ,m_nUpdateRules(KeyRule::NO_ACTION
)
49 ,m_nDeleteRules(KeyRule::NO_ACTION
)
50 ,m_nCardinality(CARDINAL_UNDEFINED
)
54 ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type
& _pReferencingTable
,
55 const TTableWindowData::value_type
& _pReferencedTable
,
56 const OUString
& rConnName
)
57 :OTableConnectionData( _pReferencingTable
, _pReferencedTable
)
58 ,m_nUpdateRules(KeyRule::NO_ACTION
)
59 ,m_nDeleteRules(KeyRule::NO_ACTION
)
60 ,m_nCardinality(CARDINAL_UNDEFINED
)
62 m_aConnName
= rConnName
;
64 if ( !m_aConnName
.isEmpty() )
68 ORelationTableConnectionData::ORelationTableConnectionData( const ORelationTableConnectionData
& rConnData
)
69 :OTableConnectionData( rConnData
)
74 ORelationTableConnectionData::~ORelationTableConnectionData()
78 bool ORelationTableConnectionData::DropRelation()
80 ::osl::MutexGuard
aGuard( m_aMutex
);
82 Reference
< XIndexAccess
> xKeys
= getReferencingTable()->getKeys();
83 if( !m_aConnName
.isEmpty() && xKeys
.is() )
85 const sal_Int32 nCount
= xKeys
->getCount();
86 for(sal_Int32 i
= 0;i
< nCount
;++i
)
88 Reference
< XPropertySet
> xKey(xKeys
->getByIndex(i
),UNO_QUERY
);
89 OSL_ENSURE(xKey
.is(),"Key is not valid!");
93 xKey
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
94 if(sName
== m_aConnName
)
96 Reference
< XDrop
> xDrop(xKeys
,UNO_QUERY
);
97 OSL_ENSURE(xDrop
.is(),"can't drop key because we haven't a drop interface!");
99 xDrop
->dropByIndex(i
);
108 void ORelationTableConnectionData::ChangeOrientation()
110 // exchange Source- and DestFieldName of the lines
111 OUString sTempString
;
112 OConnectionLineDataVec::iterator aIter
= m_vConnLineData
.begin();
113 OConnectionLineDataVec::iterator aEnd
= m_vConnLineData
.end();
114 for(;aIter
!= aEnd
;++aIter
)
116 sTempString
= (*aIter
)->GetSourceFieldName();
117 (*aIter
)->SetSourceFieldName( (*aIter
)->GetDestFieldName() );
118 (*aIter
)->SetDestFieldName( sTempString
);
122 TTableWindowData::value_type pTemp
= m_pReferencingTable
;
123 m_pReferencingTable
= m_pReferencedTable
;
124 m_pReferencedTable
= pTemp
;
127 void ORelationTableConnectionData::SetCardinality()
129 ::osl::MutexGuard
aGuard( m_aMutex
);
130 m_nCardinality
= CARDINAL_UNDEFINED
;
132 if( IsSourcePrimKey() )
134 if( IsDestPrimKey() )
135 m_nCardinality
= CARDINAL_ONE_ONE
;
137 m_nCardinality
= CARDINAL_ONE_MANY
;
140 if( IsDestPrimKey() )
142 if( !IsSourcePrimKey() )
143 m_nCardinality
= CARDINAL_MANY_ONE
;
148 bool ORelationTableConnectionData::checkPrimaryKey(const Reference
< XPropertySet
>& i_xTable
,EConnectionSide _eEConnectionSide
) const
150 // check if Table has the primary key column dependig on _eEConnectionSide
151 sal_uInt16 nPrimKeysCount
= 0,
152 nValidLinesCount
= 0;
153 const Reference
< XNameAccess
> xKeyColumns
= dbtools::getPrimaryKeyColumns_throw(i_xTable
);
154 if ( xKeyColumns
.is() )
156 Sequence
< OUString
> aKeyColumns
= xKeyColumns
->getElementNames();
157 const OUString
* pKeyIter
= aKeyColumns
.getConstArray();
158 const OUString
* pKeyEnd
= pKeyIter
+ aKeyColumns
.getLength();
160 for(;pKeyIter
!= pKeyEnd
;++pKeyIter
)
162 OConnectionLineDataVec::const_iterator aIter
= m_vConnLineData
.begin();
163 OConnectionLineDataVec::const_iterator aEnd
= m_vConnLineData
.end();
164 for(;aIter
!= aEnd
;++aIter
)
167 if ( (*aIter
)->GetFieldName(_eEConnectionSide
) == *pKeyIter
)
174 if ( nPrimKeysCount
!= aKeyColumns
.getLength() )
177 if ( !nPrimKeysCount
|| nPrimKeysCount
!= nValidLinesCount
)
183 bool ORelationTableConnectionData::IsConnectionPossible()
185 ::osl::MutexGuard
aGuard( m_aMutex
);
187 // if the SourceFields are a PrimKey, it's only the orientation which is wrong
188 if ( IsSourcePrimKey() && !IsDestPrimKey() )
194 OConnectionLineDataRef
ORelationTableConnectionData::CreateLineDataObj()
196 return new OConnectionLineData();
199 OConnectionLineDataRef
ORelationTableConnectionData::CreateLineDataObj( const OConnectionLineData
& rConnLineData
)
201 return new OConnectionLineData( rConnLineData
);
204 void ORelationTableConnectionData::CopyFrom(const OTableConnectionData
& rSource
)
206 // retract to the (non-virtual) operator= like in the base class
207 *this = *static_cast<const ORelationTableConnectionData
*>(&rSource
);
210 ORelationTableConnectionData
& ORelationTableConnectionData::operator=( const ORelationTableConnectionData
& rConnData
)
212 if (&rConnData
== this)
215 OTableConnectionData::operator=( rConnData
);
216 m_nUpdateRules
= rConnData
.GetUpdateRules();
217 m_nDeleteRules
= rConnData
.GetDeleteRules();
218 m_nCardinality
= rConnData
.GetCardinality();
225 bool operator==(const ORelationTableConnectionData
& lhs
, const ORelationTableConnectionData
& rhs
)
227 bool bEqual
= (lhs
.m_nUpdateRules
== rhs
.m_nUpdateRules
)
228 && (lhs
.m_nDeleteRules
== rhs
.m_nDeleteRules
)
229 && (lhs
.m_nCardinality
== rhs
.m_nCardinality
)
230 && (lhs
.getReferencingTable() == rhs
.getReferencingTable())
231 && (lhs
.getReferencedTable() == rhs
.getReferencedTable())
232 && (lhs
.m_aConnName
== rhs
.m_aConnName
)
233 && (lhs
.m_vConnLineData
.size() == rhs
.m_vConnLineData
.size());
237 std::vector
< OConnectionLineDataRef
>::const_iterator aIter
= lhs
.m_vConnLineData
.begin();
238 std::vector
< OConnectionLineDataRef
>::const_iterator aEnd
= lhs
.m_vConnLineData
.end();
239 for (sal_Int32 i
= 0; aIter
!= aEnd
; ++aIter
,++i
)
241 if ( *(rhs
.m_vConnLineData
[i
]) != **aIter
)
244 bEqual
= aIter
== aEnd
;
251 bool ORelationTableConnectionData::Update()
253 ::osl::MutexGuard
aGuard( m_aMutex
);
254 // delete old relation
257 if( !IsConnectionPossible() )
261 // reassign the keys because the orientaion could be changed
262 Reference
<XPropertySet
> xTableProp(getReferencingTable()->getTable());
263 Reference
< XIndexAccess
> xKeys ( getReferencingTable()->getKeys());
267 // create new relation
268 Reference
<XDataDescriptorFactory
> xKeyFactory(xKeys
,UNO_QUERY
);
269 OSL_ENSURE(xKeyFactory
.is(),"No XDataDescriptorFactory Interface!");
270 Reference
<XAppend
> xAppend(xKeyFactory
,UNO_QUERY
);
271 OSL_ENSURE(xAppend
.is(),"No XAppend Interface!");
273 Reference
<XPropertySet
> xKey
= xKeyFactory
->createDataDescriptor();
274 OSL_ENSURE(xKey
.is(),"Key is null!");
275 if ( xKey
.is() && xTableProp
.is() )
277 // build a foreign key name
278 OUString sSourceName
;
279 xTableProp
->getPropertyValue(PROPERTY_NAME
) >>= sSourceName
;
280 OUString sKeyName
= sSourceName
;
281 sKeyName
+= getReferencedTable()->GetTableName();
283 xKey
->setPropertyValue(PROPERTY_NAME
,makeAny(sKeyName
));
284 xKey
->setPropertyValue(PROPERTY_TYPE
,makeAny(KeyType::FOREIGN
));
285 xKey
->setPropertyValue(PROPERTY_REFERENCEDTABLE
,makeAny(OUString(getReferencedTable()->GetTableName())));
286 xKey
->setPropertyValue(PROPERTY_UPDATERULE
, makeAny(GetUpdateRules()));
287 xKey
->setPropertyValue(PROPERTY_DELETERULE
, makeAny(GetDeleteRules()));
290 Reference
<XColumnsSupplier
> xColSup(xKey
,UNO_QUERY
);
293 Reference
<XNameAccess
> xColumns
= xColSup
->getColumns();
294 Reference
<XDataDescriptorFactory
> xColumnFactory(xColumns
,UNO_QUERY
);
295 Reference
<XAppend
> xColumnAppend(xColumns
,UNO_QUERY
);
296 if ( xColumnFactory
.is() )
298 OConnectionLineDataVec::iterator aIter
= m_vConnLineData
.begin();
299 OConnectionLineDataVec::iterator aEnd
= m_vConnLineData
.end();
300 for(;aIter
!= aEnd
;++aIter
)
302 if(!((*aIter
)->GetSourceFieldName().isEmpty() || (*aIter
)->GetDestFieldName().isEmpty()))
304 Reference
<XPropertySet
> xColumn
;
305 xColumn
= xColumnFactory
->createDataDescriptor();
308 xColumn
->setPropertyValue(PROPERTY_NAME
,makeAny((*aIter
)->GetSourceFieldName()));
309 xColumn
->setPropertyValue(PROPERTY_RELATEDCOLUMN
,makeAny((*aIter
)->GetDestFieldName()));
310 xColumnAppend
->appendByDescriptor(xColumn
);
315 if ( xColumns
->hasElements() )
316 xAppend
->appendByDescriptor(xKey
);
318 // to get the key we have to reget it because after append it is no longer valid
321 // get the name of foreign key; search for columns
324 bool bDropRelation
= false;
325 for(sal_Int32 i
=0;i
<xKeys
->getCount();++i
)
327 xKeys
->getByIndex(i
) >>= xKey
;
328 OSL_ENSURE(xKey
.is(),"Key is not valid!");
332 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nType
;
333 OUString sReferencedTable
;
334 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
335 if ( sReferencedTable
== getReferencedTable()->GetTableName() )
337 xColSup
.set(xKey
,UNO_QUERY_THROW
);
340 Reference
<XNameAccess
> xColumns
= xColSup
->getColumns();
341 Sequence
< OUString
> aNames
= xColumns
->getElementNames();
342 const OUString
* pIter
= aNames
.getConstArray();
343 const OUString
* pEnd
= pIter
+ aNames
.getLength();
345 Reference
<XPropertySet
> xColumn
;
346 OUString sName
,sRelatedColumn
;
347 for ( ; pIter
!= pEnd
; ++pIter
)
349 xColumn
.set(xColumns
->getByName(*pIter
),UNO_QUERY_THROW
);
350 xColumn
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
351 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
353 OConnectionLineDataVec::iterator aIter
= m_vConnLineData
.begin();
354 OConnectionLineDataVec::iterator aEnd
= m_vConnLineData
.end();
355 for(;aIter
!= aEnd
;++aIter
)
357 if( (*aIter
)->GetSourceFieldName() == sName
358 && (*aIter
)->GetDestFieldName() == sRelatedColumn
)
363 if ( aIter
== m_vConnLineData
.end() )
368 xKey
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
370 bDropRelation
= aNames
.getLength() == 0; // the key contains no column, so it isn't valid and we have to drop it
371 //here we already know our column structure so we don't have to recreate the table connection data
386 OUString
sError(ModuleRes(STR_QUERY_REL_COULD_NOT_CREATE
));
387 ::dbtools::throwGenericSQLException(sError
,NULL
);
390 // The fields the relation marks may not be the same as our LineDatas mark after the relation has been updated
393 OConnectionLineDataVec().swap(m_vConnLineData
);
394 Reference
<XNameAccess
> xColumns
= xColSup
->getColumns();
395 Sequence
< OUString
> aNames
= xColumns
->getElementNames();
396 const OUString
* pIter
= aNames
.getConstArray();
397 const OUString
* pEnd
= pIter
+ aNames
.getLength();
399 m_vConnLineData
.reserve( aNames
.getLength() );
400 Reference
<XPropertySet
> xColumn
;
401 OUString sName
,sRelatedColumn
;
403 for(;pIter
!= pEnd
;++pIter
)
405 xColumns
->getByName(*pIter
) >>= xColumn
;
408 OConnectionLineDataRef pNewData
= CreateLineDataObj();
410 xColumn
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
411 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
413 pNewData
->SetSourceFieldName(sName
);
414 pNewData
->SetDestFieldName(sRelatedColumn
);
415 m_vConnLineData
.push_back(pNewData
);
419 // NOTE : the caller is responsible for updating any other objects referencing the old LineDatas (for instance a ConnLine)
421 // determine cardinality
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */