LibreOffice Module dbaccess (master) 1
RTableConnectionData.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21#include <com/sun/star/sdbc/KeyRule.hpp>
22#include <com/sun/star/sdbcx/KeyType.hpp>
23#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
24#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
25#include <com/sun/star/sdbcx/XAppend.hpp>
26#include <com/sun/star/sdbcx/XDrop.hpp>
27#include <com/sun/star/container/XIndexAccess.hpp>
28#include <strings.hrc>
29#include <strings.hxx>
30#include <core_resource.hxx>
33#include <osl/diagnose.h>
34
35using namespace dbaui;
36using namespace ::com::sun::star::sdbc;
37using namespace ::com::sun::star::sdbcx;
38using namespace ::com::sun::star::uno;
39using namespace ::com::sun::star::beans;
40using namespace ::com::sun::star::container;
41using namespace ::com::sun::star::lang;
42
43ORelationTableConnectionData::ORelationTableConnectionData()
44 :m_nUpdateRules(KeyRule::NO_ACTION)
45 ,m_nDeleteRules(KeyRule::NO_ACTION)
46 ,m_nCardinality(Cardinality::Undefined)
47{
48}
49
50ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable,
51 const TTableWindowData::value_type& _pReferencedTable,
52 const OUString& rConnName )
53 :OTableConnectionData( _pReferencingTable, _pReferencedTable )
54 ,m_nUpdateRules(KeyRule::NO_ACTION)
55 ,m_nDeleteRules(KeyRule::NO_ACTION)
56 ,m_nCardinality(Cardinality::Undefined)
57{
58 m_aConnName = rConnName;
59
60 if ( !m_aConnName.isEmpty() )
62}
63
65 :OTableConnectionData( rConnData )
66{
67 *this = rConnData;
68}
69
71{
72}
73
75{
76 ::osl::MutexGuard aGuard( m_aMutex );
77 // delete relation
79 if( m_aConnName.isEmpty() || !xKeys.is() )
80 return;
81
82 const sal_Int32 nCount = xKeys->getCount();
83 for(sal_Int32 i = 0;i < nCount;++i)
84 {
85 Reference< XPropertySet> xKey(xKeys->getByIndex(i),UNO_QUERY);
86 OSL_ENSURE(xKey.is(),"Key is not valid!");
87 if(xKey.is())
88 {
89 OUString sName;
90 xKey->getPropertyValue(PROPERTY_NAME) >>= sName;
91 if(sName == m_aConnName)
92 {
93 Reference< XDrop> xDrop(xKeys,UNO_QUERY);
94 OSL_ENSURE(xDrop.is(),"can't drop key because we haven't a drop interface!");
95 if(xDrop.is())
96 xDrop->dropByIndex(i);
97 break;
98 }
99 }
100 }
101}
102
104{
105 // exchange Source- and DestFieldName of the lines
106 OUString sTempString;
107 for (auto const& elem : m_vConnLineData)
108 {
109 sTempString = elem->GetSourceFieldName();
110 elem->SetSourceFieldName( elem->GetDestFieldName() );
111 elem->SetDestFieldName( sTempString );
112 }
113
114 // adapt member
116}
117
119{
120 ::osl::MutexGuard aGuard( m_aMutex );
122
123 if( IsSourcePrimKey() )
124 {
125 if( IsDestPrimKey() )
127 else
129 }
130
131 if( IsDestPrimKey() )
132 {
133 if( !IsSourcePrimKey() )
135 }
136
137}
138
140{
141 // check if Table has the primary key column depending on _eEConnectionSide
142 sal_uInt16 nPrimKeysCount = 0,
143 nValidLinesCount = 0;
145 if ( xKeyColumns.is() )
146 {
147 Sequence< OUString> aKeyColumns = xKeyColumns->getElementNames();
148 const OUString* pKeyIter = aKeyColumns.getConstArray();
149 const OUString* pKeyEnd = pKeyIter + aKeyColumns.getLength();
150
151 for(;pKeyIter != pKeyEnd;++pKeyIter)
152 {
153 for (auto const& elem : m_vConnLineData)
154 {
155 ++nValidLinesCount;
156 if ( elem->GetFieldName(_eEConnectionSide) == *pKeyIter )
157 {
158 ++nPrimKeysCount;
159 break;
160 }
161 }
162 }
163 if ( nPrimKeysCount != aKeyColumns.getLength() )
164 return false;
165 }
166 return nPrimKeysCount && nPrimKeysCount == nValidLinesCount;
167}
168
170{
171 ::osl::MutexGuard aGuard( m_aMutex );
172
173 // if the SourceFields are a PrimKey, it's only the orientation which is wrong
174 if ( IsSourcePrimKey() && !IsDestPrimKey() )
176}
177
179{
180 // retract to the (non-virtual) operator= like in the base class
181 *this = *static_cast<const ORelationTableConnectionData*>(&rSource);
182}
183
185{
186 if (&rConnData == this)
187 return *this;
188
190 m_nUpdateRules = rConnData.GetUpdateRules();
191 m_nDeleteRules = rConnData.GetDeleteRules();
192 m_nCardinality = rConnData.GetCardinality();
193
194 return *this;
195}
196
197namespace dbaui
198{
200{
201 bool bEqual = (lhs.m_nUpdateRules == rhs.m_nUpdateRules)
202 && (lhs.m_nDeleteRules == rhs.m_nDeleteRules)
203 && (lhs.m_nCardinality == rhs.m_nCardinality)
204 && (lhs.getReferencingTable() == rhs.getReferencingTable())
205 && (lhs.getReferencedTable() == rhs.getReferencedTable())
206 && (lhs.m_aConnName == rhs.m_aConnName)
207 && (lhs.m_vConnLineData.size() == rhs.m_vConnLineData.size());
208
209 if ( bEqual )
210 {
211 sal_Int32 i = 0;
212 for (auto const& elem : lhs.m_vConnLineData)
213 {
214 if ( *(rhs.m_vConnLineData[i]) != *elem )
215 {
216 bEqual = false;
217 break;
218 }
219 ++i;
220 }
221 }
222 return bEqual;
223}
224
225}
226
228{
229 ::osl::MutexGuard aGuard( m_aMutex );
230 // delete old relation
231 {
232 DropRelation();
234 }
235
236 // reassign the keys because the orientation could be changed
237 Reference<XPropertySet> xTableProp(getReferencingTable()->getTable());
238 Reference< XIndexAccess> xKeys ( getReferencingTable()->getKeys());
239
240 if ( !xKeys.is() )
241 return false;
242 // create new relation
243 Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY);
244 OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
245 Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
246 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
247
248 Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
249 OSL_ENSURE(xKey.is(),"Key is null!");
250 if ( xKey.is() && xTableProp.is() )
251 {
252 // build a foreign key name
253 OUString sSourceName;
254 xTableProp->getPropertyValue(PROPERTY_NAME) >>= sSourceName;
255 OUString sKeyName = sSourceName + getReferencedTable()->GetTableName();
256
257 xKey->setPropertyValue(PROPERTY_NAME,Any(sKeyName));
258 xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::FOREIGN));
259 xKey->setPropertyValue(PROPERTY_REFERENCEDTABLE,Any(getReferencedTable()->GetTableName()));
260 xKey->setPropertyValue(PROPERTY_UPDATERULE, Any(GetUpdateRules()));
261 xKey->setPropertyValue(PROPERTY_DELETERULE, Any(GetDeleteRules()));
262 }
263
264 Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
265 if ( xColSup.is() )
266 {
267 Reference<XNameAccess> xColumns = xColSup->getColumns();
268 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
269 Reference<XAppend> xColumnAppend(xColumns,UNO_QUERY);
270 if ( xColumnFactory.is() )
271 {
272 for (auto const& elem : m_vConnLineData)
273 {
274 if(!(elem->GetSourceFieldName().isEmpty() || elem->GetDestFieldName().isEmpty()))
275 {
276 Reference<XPropertySet> xColumn = xColumnFactory->createDataDescriptor();
277 if ( xColumn.is() )
278 {
279 xColumn->setPropertyValue(PROPERTY_NAME,Any(elem->GetSourceFieldName()));
280 xColumn->setPropertyValue(PROPERTY_RELATEDCOLUMN,Any(elem->GetDestFieldName()));
281 xColumnAppend->appendByDescriptor(xColumn);
282 }
283 }
284 }
285
286 if ( xColumns->hasElements() )
287 xAppend->appendByDescriptor(xKey);
288 }
289 // to get the key we have to reget it because after append it is no longer valid
290 }
291
292 // get the name of foreign key; search for columns
293 m_aConnName.clear();
294 xKey.clear();
295 bool bDropRelation = false;
296 for(sal_Int32 i=0;i<xKeys->getCount();++i)
297 {
298 xKeys->getByIndex(i) >>= xKey;
299 OSL_ENSURE(xKey.is(),"Key is not valid!");
300 if ( xKey.is() )
301 {
302 OUString sReferencedTable;
303 xKey->getPropertyValue(PROPERTY_REFERENCEDTABLE) >>= sReferencedTable;
304 if ( sReferencedTable == getReferencedTable()->GetTableName() )
305 {
306 xColSup.set(xKey,UNO_QUERY_THROW);
307 try
308 {
309 Reference<XNameAccess> xColumns = xColSup->getColumns();
310 Sequence< OUString> aNames = xColumns->getElementNames();
311 const OUString* pIter = aNames.getConstArray();
312 const OUString* pEnd = pIter + aNames.getLength();
313
315 OUString sName,sRelatedColumn;
316 for ( ; pIter != pEnd ; ++pIter )
317 {
318 xColumn.set(xColumns->getByName(*pIter),UNO_QUERY_THROW);
319 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
320 xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
321
322 bool bFoundElem = false;
323 for (auto const& elem : m_vConnLineData)
324 {
325 if( elem->GetSourceFieldName() == sName
326 && elem->GetDestFieldName() == sRelatedColumn )
327 {
328 bFoundElem = true;
329 break;
330 }
331 }
332 if (!bFoundElem)
333 break;
334 }
335 if ( pIter == pEnd )
336 {
337 xKey->getPropertyValue(PROPERTY_NAME) >>= sName;
339 bDropRelation = !aNames.hasElements(); // the key contains no column, so it isn't valid and we have to drop it
340 //here we already know our column structure so we don't have to recreate the table connection data
341 xColSup.clear();
342 break;
343 }
344 }
345 catch(Exception&)
346 {
347 }
348 }
349 }
350 xKey.clear();
351 }
352 if ( bDropRelation )
353 {
354 DropRelation();
355 OUString sError(DBA_RES(STR_QUERY_REL_COULD_NOT_CREATE));
356 ::dbtools::throwGenericSQLException(sError,nullptr);
357 }
358
359 // The fields the relation marks may not be the same as our LineDatas mark after the relation has been updated
360 if ( xColSup.is() )
361 {
363 Reference<XNameAccess> xColumns = xColSup->getColumns();
364 Sequence< OUString> aNames = xColumns->getElementNames();
365 const OUString* pIter = aNames.getConstArray();
366 const OUString* pEnd = pIter + aNames.getLength();
367
368 m_vConnLineData.reserve( aNames.getLength() );
370 OUString sName,sRelatedColumn;
371
372 for(;pIter != pEnd;++pIter)
373 {
374 xColumns->getByName(*pIter) >>= xColumn;
375 if ( xColumn.is() )
376 {
378
379 xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
380 xColumn->getPropertyValue(PROPERTY_RELATEDCOLUMN) >>= sRelatedColumn;
381
382 pNewData->SetSourceFieldName(sName);
383 pNewData->SetDestFieldName(sRelatedColumn);
384 m_vConnLineData.push_back(pNewData);
385 }
386 }
387 }
388 // NOTE : the caller is responsible for updating any other objects referencing the old LineDatas (for instance a ConnLine)
389
390 // determine cardinality
392
393 return true;
394}
395
396/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sName
the class OConnectionLineData contains the data of a connection e.g.
ORelationTableConnectionData & operator=(const ORelationTableConnectionData &rConnData)
virtual bool Update() override
Update create a new relation.
bool checkPrimaryKey(const css::uno::Reference< css::beans::XPropertySet > &i_xTable, EConnectionSide _eEConnectionSide) const
virtual void CopyFrom(const OTableConnectionData &rSource) override
initialise from a source (more comfortable than a virtual assignment operator)
Contains all connection data which exists between two windows.
const TTableWindowData::value_type & getReferencingTable() const
TTableWindowData::value_type m_pReferencedTable
TTableWindowData::value_type m_pReferencingTable
const TTableWindowData::value_type & getReferencedTable() const
OConnectionLineDataVec m_vConnLineData
OTableConnectionData & operator=(const OTableConnectionData &rConnData)
#define DBA_RES(id)
int nCount
Reference< XColumn > xColumn
@ Exception
std::vector< OConnectionLineDataRef > OConnectionLineDataVec
EConnectionSide
Definition: QEnumTypes.hxx:42
static bool operator==(const OIndexField &_rLHS, const OIndexField &_rRHS)
Definition: indexdialog.cxx:47
Reference< XNameAccess > getPrimaryKeyColumns_throw(const Any &i_aTable)
int i
constexpr OUStringLiteral PROPERTY_UPDATERULE(u"UpdateRule")
constexpr OUStringLiteral PROPERTY_DELETERULE(u"DeleteRule")
constexpr OUStringLiteral PROPERTY_RELATEDCOLUMN(u"RelatedColumn")
constexpr OUStringLiteral PROPERTY_TYPE(u"Type")
constexpr OUStringLiteral PROPERTY_REFERENCEDTABLE(u"ReferencedTable")
constexpr OUStringLiteral PROPERTY_NAME(u"Name")