1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "RTableConnectionData.hxx"
30 #include <tools/debug.hxx>
31 #include <com/sun/star/sdbc/KeyRule.hpp>
32 #include <com/sun/star/sdbcx/KeyType.hpp>
33 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
34 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
35 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
36 #include <com/sun/star/sdbcx/XAppend.hpp>
37 #include <com/sun/star/sdbcx/XDrop.hpp>
38 #include <com/sun/star/container/XIndexAccess.hpp>
39 #include "dbustrings.hrc"
40 #include "dbu_rel.hrc"
41 #include "UITools.hxx"
42 #include "moduledbu.hxx"
43 #include <connectivity/dbexception.hxx>
44 #include <connectivity/dbtools.hxx>
46 using namespace dbaui
;
47 using namespace ::com::sun::star::sdbc
;
48 using namespace ::com::sun::star::sdbcx
;
49 using namespace ::com::sun::star::uno
;
50 using namespace ::com::sun::star::beans
;
51 using namespace ::com::sun::star::container
;
52 using namespace ::com::sun::star::lang
;
54 DBG_NAME(ORelationTableConnectionData
)
55 //========================================================================
56 // class ORelationTableConnectionData
57 //========================================================================
58 //------------------------------------------------------------------------
59 ORelationTableConnectionData::ORelationTableConnectionData()
60 :OTableConnectionData()
61 ,m_nUpdateRules(KeyRule::NO_ACTION
)
62 ,m_nDeleteRules(KeyRule::NO_ACTION
)
63 ,m_nCardinality(CARDINAL_UNDEFINED
)
65 DBG_CTOR(ORelationTableConnectionData
,NULL
);
67 //------------------------------------------------------------------------
68 ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type
& _pReferencingTable
,
69 const TTableWindowData::value_type
& _pReferencedTable
,
70 const ::rtl::OUString
& rConnName
)
71 :OTableConnectionData( _pReferencingTable
, _pReferencedTable
)
72 ,m_nUpdateRules(KeyRule::NO_ACTION
)
73 ,m_nDeleteRules(KeyRule::NO_ACTION
)
74 ,m_nCardinality(CARDINAL_UNDEFINED
)
76 DBG_CTOR(ORelationTableConnectionData
,NULL
);
77 m_aConnName
= rConnName
;
79 if ( m_aConnName
.Len() )
83 //------------------------------------------------------------------------
84 ORelationTableConnectionData::ORelationTableConnectionData( const ORelationTableConnectionData
& rConnData
)
85 :OTableConnectionData( rConnData
)
87 DBG_CTOR(ORelationTableConnectionData
,NULL
);
91 //------------------------------------------------------------------------
92 ORelationTableConnectionData::~ORelationTableConnectionData()
94 DBG_DTOR(ORelationTableConnectionData
,NULL
);
97 //------------------------------------------------------------------------
98 sal_Bool
ORelationTableConnectionData::DropRelation()
100 DBG_CHKTHIS(ORelationTableConnectionData
,NULL
);
101 ::osl::MutexGuard
aGuard( m_aMutex
);
102 ////////////////////////////////////////////////////////////
104 Reference
< XIndexAccess
> xKeys
= getReferencingTable()->getKeys();
105 if( m_aConnName
.Len() && xKeys
.is() )
107 const sal_Int32 nCount
= xKeys
->getCount();
108 for(sal_Int32 i
= 0;i
< nCount
;++i
)
110 Reference
< XPropertySet
> xKey(xKeys
->getByIndex(i
),UNO_QUERY
);
111 OSL_ENSURE(xKey
.is(),"Key is not valid!");
114 ::rtl::OUString sName
;
115 xKey
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
116 if(String(sName
) == m_aConnName
)
118 Reference
< XDrop
> xDrop(xKeys
,UNO_QUERY
);
119 OSL_ENSURE(xDrop
.is(),"can't drop key because we haven't a drop interface!");
121 xDrop
->dropByIndex(i
);
130 //------------------------------------------------------------------------
131 void ORelationTableConnectionData::ChangeOrientation()
133 DBG_CHKTHIS(ORelationTableConnectionData
,NULL
);
134 //////////////////////////////////////////////////////////////////////
135 // Source- und DestFieldName der Linien austauschen
136 ::rtl::OUString sTempString
;
137 OConnectionLineDataVec::iterator aIter
= m_vConnLineData
.begin();
138 OConnectionLineDataVec::iterator aEnd
= m_vConnLineData
.end();
139 for(;aIter
!= aEnd
;++aIter
)
141 sTempString
= (*aIter
)->GetSourceFieldName();
142 (*aIter
)->SetSourceFieldName( (*aIter
)->GetDestFieldName() );
143 (*aIter
)->SetDestFieldName( sTempString
);
146 //////////////////////////////////////////////////////////////////////
148 TTableWindowData::value_type pTemp
= m_pReferencingTable
;
149 m_pReferencingTable
= m_pReferencedTable
;
150 m_pReferencedTable
= pTemp
;
153 //------------------------------------------------------------------------
154 void ORelationTableConnectionData::SetCardinality()
156 DBG_CHKTHIS(ORelationTableConnectionData
,NULL
);
157 ::osl::MutexGuard
aGuard( m_aMutex
);
158 m_nCardinality
= CARDINAL_UNDEFINED
;
160 if( IsSourcePrimKey() )
162 if( IsDestPrimKey() )
163 m_nCardinality
= CARDINAL_ONE_ONE
;
165 m_nCardinality
= CARDINAL_ONE_MANY
;
168 if( IsDestPrimKey() )
170 if( !IsSourcePrimKey() )
171 m_nCardinality
= CARDINAL_MANY_ONE
;
175 // -----------------------------------------------------------------------------
176 sal_Bool
ORelationTableConnectionData::checkPrimaryKey(const Reference
< XPropertySet
>& i_xTable
,EConnectionSide _eEConnectionSide
) const
178 // check if Table has the primary key column dependig on _eEConnectionSide
179 sal_uInt16 nPrimKeysCount
= 0,
180 nValidLinesCount
= 0;
181 const Reference
< XNameAccess
> xKeyColumns
= dbtools::getPrimaryKeyColumns_throw(i_xTable
);
182 if ( xKeyColumns
.is() )
184 Sequence
< ::rtl::OUString
> aKeyColumns
= xKeyColumns
->getElementNames();
185 const ::rtl::OUString
* pKeyIter
= aKeyColumns
.getConstArray();
186 const ::rtl::OUString
* pKeyEnd
= pKeyIter
+ aKeyColumns
.getLength();
188 for(;pKeyIter
!= pKeyEnd
;++pKeyIter
)
190 OConnectionLineDataVec::const_iterator aIter
= m_vConnLineData
.begin();
191 OConnectionLineDataVec::const_iterator aEnd
= m_vConnLineData
.end();
192 for(;aIter
!= aEnd
;++aIter
)
195 if ( (*aIter
)->GetFieldName(_eEConnectionSide
) == *pKeyIter
)
202 if ( nPrimKeysCount
!= aKeyColumns
.getLength() )
205 if ( !nPrimKeysCount
|| nPrimKeysCount
!= nValidLinesCount
)
210 //------------------------------------------------------------------------
211 sal_Bool
ORelationTableConnectionData::IsConnectionPossible()
213 DBG_CHKTHIS(ORelationTableConnectionData
,NULL
);
214 ::osl::MutexGuard
aGuard( m_aMutex
);
216 //////////////////////////////////////////////////////////////////////
217 // Wenn die SourceFelder ein PrimKey sind, ist nur die Orientierung falsch
218 if ( IsSourcePrimKey() && !IsDestPrimKey() )
224 //------------------------------------------------------------------------
225 OConnectionLineDataRef
ORelationTableConnectionData::CreateLineDataObj()
227 return new OConnectionLineData();
230 //------------------------------------------------------------------------
231 OConnectionLineDataRef
ORelationTableConnectionData::CreateLineDataObj( const OConnectionLineData
& rConnLineData
)
233 return new OConnectionLineData( rConnLineData
);
236 //------------------------------------------------------------------------
237 void ORelationTableConnectionData::CopyFrom(const OTableConnectionData
& rSource
)
239 // wie in der Basisklasse zurueckziehen auf das (nicht-virtuelle) operator=
240 *this = *static_cast<const ORelationTableConnectionData
*>(&rSource
);
243 //------------------------------------------------------------------------
244 ORelationTableConnectionData
& ORelationTableConnectionData::operator=( const ORelationTableConnectionData
& rConnData
)
246 if (&rConnData
== this)
249 OTableConnectionData::operator=( rConnData
);
250 m_nUpdateRules
= rConnData
.GetUpdateRules();
251 m_nDeleteRules
= rConnData
.GetDeleteRules();
252 m_nCardinality
= rConnData
.GetCardinality();
258 //-------------------------------------------------------------------------
259 bool operator==(const ORelationTableConnectionData
& lhs
, const ORelationTableConnectionData
& rhs
)
261 bool bEqual
= (lhs
.m_nUpdateRules
== rhs
.m_nUpdateRules
)
262 && (lhs
.m_nDeleteRules
== rhs
.m_nDeleteRules
)
263 && (lhs
.m_nCardinality
== rhs
.m_nCardinality
)
264 && (lhs
.getReferencingTable() == rhs
.getReferencingTable())
265 && (lhs
.getReferencedTable() == rhs
.getReferencedTable())
266 && (lhs
.m_aConnName
== rhs
.m_aConnName
)
267 && (lhs
.m_vConnLineData
.size() == rhs
.m_vConnLineData
.size());
271 std::vector
< OConnectionLineDataRef
>::const_iterator aIter
= lhs
.m_vConnLineData
.begin();
272 std::vector
< OConnectionLineDataRef
>::const_iterator aEnd
= lhs
.m_vConnLineData
.end();
273 for (sal_Int32 i
= 0; aIter
!= aEnd
; ++aIter
,++i
)
275 if ( *(rhs
.m_vConnLineData
[i
]) != **aIter
)
278 bEqual
= aIter
== aEnd
;
283 //------------------------------------------------------------------------
284 sal_Bool
ORelationTableConnectionData::Update()
286 ::osl::MutexGuard
aGuard( m_aMutex
);
287 ////////////////////////////////////////////////////////////
288 // Alte Relation loeschen
291 if( !IsConnectionPossible() )
295 // reassign the keys because the orientaion could be changed
296 Reference
<XPropertySet
> xTableProp(getReferencingTable()->getTable());
297 Reference
< XIndexAccess
> xKeys ( getReferencingTable()->getKeys());
301 ////////////////////////////////////////////////////////////
302 // Neue Relation erzeugen
303 Reference
<XDataDescriptorFactory
> xKeyFactory(xKeys
,UNO_QUERY
);
304 OSL_ENSURE(xKeyFactory
.is(),"No XDataDescriptorFactory Interface!");
305 Reference
<XAppend
> xAppend(xKeyFactory
,UNO_QUERY
);
306 OSL_ENSURE(xAppend
.is(),"No XAppend Interface!");
308 Reference
<XPropertySet
> xKey
= xKeyFactory
->createDataDescriptor();
309 OSL_ENSURE(xKey
.is(),"Key is null!");
310 if ( xKey
.is() && xTableProp
.is() )
312 // build a foreign key name
313 ::rtl::OUString sSourceName
;
314 xTableProp
->getPropertyValue(PROPERTY_NAME
) >>= sSourceName
;
315 ::rtl::OUString sKeyName
= sSourceName
;
316 sKeyName
+= getReferencedTable()->GetTableName();
318 xKey
->setPropertyValue(PROPERTY_NAME
,makeAny(sKeyName
));
319 xKey
->setPropertyValue(PROPERTY_TYPE
,makeAny(KeyType::FOREIGN
));
320 xKey
->setPropertyValue(PROPERTY_REFERENCEDTABLE
,makeAny(::rtl::OUString(getReferencedTable()->GetTableName())));
321 xKey
->setPropertyValue(PROPERTY_UPDATERULE
, makeAny(GetUpdateRules()));
322 xKey
->setPropertyValue(PROPERTY_DELETERULE
, makeAny(GetDeleteRules()));
325 Reference
<XColumnsSupplier
> xColSup(xKey
,UNO_QUERY
);
328 Reference
<XNameAccess
> xColumns
= xColSup
->getColumns();
329 Reference
<XDataDescriptorFactory
> xColumnFactory(xColumns
,UNO_QUERY
);
330 Reference
<XAppend
> xColumnAppend(xColumns
,UNO_QUERY
);
331 if ( xColumnFactory
.is() )
333 OConnectionLineDataVec::iterator aIter
= m_vConnLineData
.begin();
334 OConnectionLineDataVec::iterator aEnd
= m_vConnLineData
.end();
335 for(;aIter
!= aEnd
;++aIter
)
337 if(!((*aIter
)->GetSourceFieldName().isEmpty() || (*aIter
)->GetDestFieldName().isEmpty()))
339 Reference
<XPropertySet
> xColumn
;
340 xColumn
= xColumnFactory
->createDataDescriptor();
343 xColumn
->setPropertyValue(PROPERTY_NAME
,makeAny((*aIter
)->GetSourceFieldName()));
344 xColumn
->setPropertyValue(PROPERTY_RELATEDCOLUMN
,makeAny((*aIter
)->GetDestFieldName()));
345 xColumnAppend
->appendByDescriptor(xColumn
);
350 if ( xColumns
->hasElements() )
351 xAppend
->appendByDescriptor(xKey
);
353 // to get the key we have to reget it because after append it is no longer valid
356 // get the name of foreign key // search for columns
357 m_aConnName
= ::rtl::OUString();
359 bool bDropRelation
= false;
360 for(sal_Int32 i
=0;i
<xKeys
->getCount();++i
)
362 xKeys
->getByIndex(i
) >>= xKey
;
363 OSL_ENSURE(xKey
.is(),"Key is not valid!");
367 xKey
->getPropertyValue(PROPERTY_TYPE
) >>= nType
;
368 ::rtl::OUString sReferencedTable
;
369 xKey
->getPropertyValue(PROPERTY_REFERENCEDTABLE
) >>= sReferencedTable
;
370 if ( sReferencedTable
== ::rtl::OUString(getReferencedTable()->GetTableName()) )
372 xColSup
.set(xKey
,UNO_QUERY_THROW
);
375 Reference
<XNameAccess
> xColumns
= xColSup
->getColumns();
376 Sequence
< ::rtl::OUString
> aNames
= xColumns
->getElementNames();
377 const ::rtl::OUString
* pIter
= aNames
.getConstArray();
378 const ::rtl::OUString
* pEnd
= pIter
+ aNames
.getLength();
380 Reference
<XPropertySet
> xColumn
;
381 ::rtl::OUString sName
,sRelatedColumn
;
382 for ( ; pIter
!= pEnd
; ++pIter
)
384 xColumn
.set(xColumns
->getByName(*pIter
),UNO_QUERY_THROW
);
385 xColumn
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
386 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
388 OConnectionLineDataVec::iterator aIter
= m_vConnLineData
.begin();
389 OConnectionLineDataVec::iterator aEnd
= m_vConnLineData
.end();
390 for(;aIter
!= aEnd
;++aIter
)
392 if( (*aIter
)->GetSourceFieldName() == sName
393 && (*aIter
)->GetDestFieldName() == sRelatedColumn
)
398 if ( aIter
== m_vConnLineData
.end() )
403 xKey
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
405 bDropRelation
= aNames
.getLength() == 0; // the key contains no column, so it isn't valid and we have to drop it
406 //here we already know our column structure so we don't have to recreate the table connection data
421 String
sError(ModuleRes(STR_QUERY_REL_COULD_NOT_CREATE
));
422 ::dbtools::throwGenericSQLException(sError
,NULL
);
425 // The fields the relation marks may not be the same as our LineDatas mark after the relation has been updated
428 OConnectionLineDataVec().swap(m_vConnLineData
);
429 Reference
<XNameAccess
> xColumns
= xColSup
->getColumns();
430 Sequence
< ::rtl::OUString
> aNames
= xColumns
->getElementNames();
431 const ::rtl::OUString
* pIter
= aNames
.getConstArray();
432 const ::rtl::OUString
* pEnd
= pIter
+ aNames
.getLength();
434 m_vConnLineData
.reserve( aNames
.getLength() );
435 Reference
<XPropertySet
> xColumn
;
436 ::rtl::OUString sName
,sRelatedColumn
;
438 for(;pIter
!= pEnd
;++pIter
)
440 xColumns
->getByName(*pIter
) >>= xColumn
;
443 OConnectionLineDataRef pNewData
= CreateLineDataObj();
445 xColumn
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
446 xColumn
->getPropertyValue(PROPERTY_RELATEDCOLUMN
) >>= sRelatedColumn
;
448 pNewData
->SetSourceFieldName(sName
);
449 pNewData
->SetDestFieldName(sRelatedColumn
);
450 m_vConnLineData
.push_back(pNewData
);
454 // NOTE : the caller is responsible for updating any other objects referencing the old LineDatas (for instance a ConnLine)
456 ////////////////////////////////////////////////////////////
457 // Kardinalitaet bestimmen
462 // -----------------------------------------------------------------------------
464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */