/src/libreoffice/connectivity/source/commontools/TTableHelper.cxx
Line | Count | Source |
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 | | |
20 | | #include <sal/config.h> |
21 | | #include <sal/log.hxx> |
22 | | |
23 | | #include <connectivity/TTableHelper.hxx> |
24 | | #include <com/sun/star/sdb/tools/XTableRename.hpp> |
25 | | #include <com/sun/star/sdb/tools/XTableAlteration.hpp> |
26 | | #include <com/sun/star/sdb/tools/XKeyAlteration.hpp> |
27 | | #include <com/sun/star/sdb/tools/XIndexAlteration.hpp> |
28 | | #include <sdbcx/VKey.hxx> |
29 | | #include <com/sun/star/sdbc/XRow.hpp> |
30 | | #include <com/sun/star/sdbc/XResultSet.hpp> |
31 | | #include <com/sun/star/sdbcx/KeyType.hpp> |
32 | | #include <cppuhelper/implbase.hxx> |
33 | | #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
34 | | #include <comphelper/types.hxx> |
35 | | #include <connectivity/dbtools.hxx> |
36 | | #include <connectivity/sdbcx/VCollection.hxx> |
37 | | #include <unotools/sharedunocomponent.hxx> |
38 | | #include <TConnection.hxx> |
39 | | |
40 | | #include <o3tl/functional.hxx> |
41 | | |
42 | | #include <iterator> |
43 | | #include <set> |
44 | | |
45 | | using namespace ::comphelper; |
46 | | using namespace connectivity; |
47 | | using namespace ::com::sun::star::uno; |
48 | | using namespace ::com::sun::star::beans; |
49 | | using namespace ::com::sun::star::sdbcx; |
50 | | using namespace ::com::sun::star::sdbc; |
51 | | using namespace ::com::sun::star::container; |
52 | | using namespace ::com::sun::star::lang; |
53 | | |
54 | | namespace |
55 | | { |
56 | | /// helper class for column property change events which holds the OComponentDefinition weak |
57 | | class OTableContainerListener: |
58 | | public ::cppu::WeakImplHelper< XContainerListener > |
59 | | { |
60 | | OTableHelper* m_pComponent; |
61 | | std::map< OUString,bool> m_aRefNames; |
62 | | |
63 | | protected: |
64 | 0 | virtual ~OTableContainerListener() override {} |
65 | | public: |
66 | 0 | explicit OTableContainerListener(OTableHelper* _pComponent) : m_pComponent(_pComponent){} |
67 | | // noncopyable |
68 | | OTableContainerListener(const OTableContainerListener&) = delete; |
69 | | const OTableContainerListener& operator=(const OTableContainerListener&) = delete; |
70 | | virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& /*Event*/ ) override |
71 | 0 | { |
72 | 0 | } |
73 | | virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override |
74 | 0 | { |
75 | | // tdf#137745, perhaps connectivity::OTableHelper::disposing() has been called |
76 | | // which called OTableContainerListener::clear(), so m_pComponent may be null |
77 | 0 | if (m_pComponent == nullptr) |
78 | 0 | return; |
79 | | |
80 | 0 | OUString sName; |
81 | 0 | Event.Accessor >>= sName; |
82 | 0 | if ( m_aRefNames.contains(sName) ) |
83 | 0 | m_pComponent->refreshKeys(); |
84 | 0 | } |
85 | | virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override |
86 | 0 | { |
87 | 0 | OUString sOldComposedName,sNewComposedName; |
88 | 0 | Event.ReplacedElement >>= sOldComposedName; |
89 | 0 | Event.Accessor >>= sNewComposedName; |
90 | 0 | if ( sOldComposedName != sNewComposedName && m_aRefNames.contains(sOldComposedName) ) |
91 | 0 | m_pComponent->refreshKeys(); |
92 | 0 | } |
93 | | // XEventListener |
94 | | virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) override |
95 | 0 | { |
96 | 0 | } |
97 | 0 | void clear() { m_pComponent = nullptr; } |
98 | 0 | void add(const OUString& _sRefName) { m_aRefNames.emplace(_sRefName,true); } |
99 | | }; |
100 | | } |
101 | | namespace connectivity |
102 | | { |
103 | | static OUString lcl_getServiceNameForSetting(const Reference< css::sdbc::XConnection >& _xConnection,const OUString& i_sSetting) |
104 | 0 | { |
105 | 0 | OUString sSupportService; |
106 | 0 | Any aValue; |
107 | 0 | if ( ::dbtools::getDataSourceSetting(_xConnection,i_sSetting,aValue) ) |
108 | 0 | { |
109 | 0 | aValue >>= sSupportService; |
110 | 0 | } |
111 | 0 | return sSupportService; |
112 | 0 | } |
113 | | struct OTableHelperImpl |
114 | | { |
115 | | TKeyMap m_aKeys; |
116 | | // helper services which can be provided by extensions |
117 | | Reference< css::sdb::tools::XTableRename> m_xRename; |
118 | | Reference< css::sdb::tools::XTableAlteration> m_xAlter; |
119 | | Reference< css::sdb::tools::XKeyAlteration> m_xKeyAlter; |
120 | | Reference< css::sdb::tools::XIndexAlteration> m_xIndexAlter; |
121 | | |
122 | | Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; |
123 | | Reference< css::sdbc::XConnection > m_xConnection; |
124 | | rtl::Reference<OTableContainerListener> m_xTablePropertyListener; |
125 | | std::vector< ColumnDesc > m_aColumnDesc; |
126 | | explicit OTableHelperImpl(const Reference< css::sdbc::XConnection >& _xConnection) |
127 | 0 | : m_xConnection(_xConnection) |
128 | 0 | { |
129 | 0 | try |
130 | 0 | { |
131 | 0 | m_xMetaData = m_xConnection->getMetaData(); |
132 | 0 | Reference<XMultiServiceFactory> xFac(_xConnection,UNO_QUERY); |
133 | 0 | if ( xFac.is() ) |
134 | 0 | { |
135 | 0 | m_xRename.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,u"TableRenameServiceName"_ustr)),UNO_QUERY); |
136 | 0 | m_xAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,u"TableAlterationServiceName"_ustr)),UNO_QUERY); |
137 | 0 | m_xKeyAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,u"KeyAlterationServiceName"_ustr)),UNO_QUERY); |
138 | 0 | m_xIndexAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,u"IndexAlterationServiceName"_ustr)),UNO_QUERY); |
139 | 0 | } |
140 | 0 | } |
141 | 0 | catch(const Exception&) |
142 | 0 | { |
143 | 0 | } |
144 | 0 | } |
145 | | }; |
146 | | } |
147 | | |
148 | | OTableHelper::OTableHelper( sdbcx::OCollection* _pTables, |
149 | | const Reference< XConnection >& _xConnection, |
150 | | bool _bCase) |
151 | 0 | :OTable_TYPEDEF(_pTables,_bCase) |
152 | 0 | ,m_pImpl(new OTableHelperImpl(_xConnection)) |
153 | 0 | { |
154 | 0 | } |
155 | | |
156 | | OTableHelper::OTableHelper( sdbcx::OCollection* _pTables, |
157 | | const Reference< XConnection >& _xConnection, |
158 | | bool _bCase, |
159 | | const OUString& Name, |
160 | | const OUString& Type, |
161 | | const OUString& Description , |
162 | | const OUString& SchemaName, |
163 | | const OUString& CatalogName |
164 | 0 | ) : OTable_TYPEDEF(_pTables, |
165 | 0 | _bCase, |
166 | 0 | Name, |
167 | 0 | Type, |
168 | 0 | Description, |
169 | 0 | SchemaName, |
170 | 0 | CatalogName) |
171 | 0 | ,m_pImpl(new OTableHelperImpl(_xConnection)) |
172 | 0 | { |
173 | 0 | } |
174 | | |
175 | | OTableHelper::~OTableHelper() |
176 | 0 | { |
177 | 0 | } |
178 | | |
179 | | void SAL_CALL OTableHelper::disposing() |
180 | 0 | { |
181 | 0 | ::osl::MutexGuard aGuard(m_aMutex); |
182 | 0 | if ( m_pImpl->m_xTablePropertyListener.is() ) |
183 | 0 | { |
184 | 0 | m_pTables->removeContainerListener(m_pImpl->m_xTablePropertyListener); |
185 | 0 | m_pImpl->m_xTablePropertyListener->clear(); |
186 | 0 | m_pImpl->m_xTablePropertyListener.clear(); |
187 | 0 | } |
188 | 0 | OTable_TYPEDEF::disposing(); |
189 | |
|
190 | 0 | m_pImpl->m_xConnection = nullptr; |
191 | 0 | m_pImpl->m_xMetaData = nullptr; |
192 | |
|
193 | 0 | } |
194 | | |
195 | | |
196 | | namespace |
197 | | { |
198 | | /** collects ColumnDesc's from a resultset produced by XDatabaseMetaData::getColumns |
199 | | */ |
200 | | void lcl_collectColumnDescs_throw( const Reference< XResultSet >& _rxResult, std::vector< ColumnDesc >& _out_rColumns ) |
201 | 0 | { |
202 | 0 | Reference< XRow > xRow( _rxResult, UNO_QUERY_THROW ); |
203 | 0 | while ( _rxResult->next() ) |
204 | 0 | { |
205 | | // tdf#162227: ODBC SQLGetData requires that data must be retrieved in increasing |
206 | | // column number order, unless the driver supports SQL_GD_ANY_ORDER extension (see |
207 | | // https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetdata-function). |
208 | | // We can't emplace_back(getString(4), getInt(5), ..., getString(12), getInt(17)), |
209 | | // because MSVC would reorder calls into getInt(17) -> getString(12) -> ..., and then |
210 | | // MS SQL Server ODBC driver will give error on access of column 12 after column 17. |
211 | 0 | OUString sName = xRow->getString(4); // COLUMN_NAME |
212 | 0 | sal_Int32 nField5 = xRow->getInt(5); |
213 | 0 | OUString aField6 = xRow->getString(6); |
214 | 0 | sal_Int32 nField7 = xRow->getInt(7); |
215 | 0 | sal_Int32 nField9 = xRow->getInt(9); |
216 | 0 | sal_Int32 nField11 = xRow->getInt(11); |
217 | 0 | OUString sField12 = xRow->getString(12); |
218 | 0 | OUString sField13 = xRow->getString(13); |
219 | 0 | OrdinalPosition nOrdinalPosition = xRow->getInt(17); // ORDINAL_POSITION |
220 | 0 | _out_rColumns.emplace_back(sName, nField5, aField6, nField7, nField9, nField11, |
221 | 0 | sField12, sField13, nOrdinalPosition); |
222 | 0 | } |
223 | 0 | } |
224 | | |
225 | | /** checks a given array of ColumnDesc's whether it has reasonable ordinal positions. If not, |
226 | | they will be normalized to be the array index. |
227 | | */ |
228 | | void lcl_sanitizeColumnDescs( std::vector< ColumnDesc >& _rColumns ) |
229 | 0 | { |
230 | 0 | if ( _rColumns.empty() ) |
231 | 0 | return; |
232 | | |
233 | | // collect all used ordinals |
234 | 0 | std::set< OrdinalPosition > aUsedOrdinals; |
235 | 0 | for ( const auto& collect : _rColumns ) |
236 | 0 | aUsedOrdinals.insert( collect.nOrdinalPosition ); |
237 | | |
238 | | // we need to have as much different ordinals as we have different columns |
239 | 0 | bool bDuplicates = aUsedOrdinals.size() != _rColumns.size(); |
240 | | // and it needs to be a continuous range |
241 | 0 | size_t nOrdinalsRange = *aUsedOrdinals.rbegin() - *aUsedOrdinals.begin() + 1; |
242 | 0 | bool bGaps = nOrdinalsRange != _rColumns.size(); |
243 | | |
244 | | // if that's not the case, normalize it |
245 | 0 | if ( bGaps || bDuplicates ) |
246 | 0 | { |
247 | 0 | OSL_FAIL( "lcl_sanitizeColumnDescs: database did provide invalid ORDINAL_POSITION values!" ); |
248 | |
|
249 | 0 | OrdinalPosition nNormalizedPosition = 1; |
250 | 0 | for ( auto& normalize : _rColumns ) |
251 | 0 | normalize.nOrdinalPosition = nNormalizedPosition++; |
252 | 0 | return; |
253 | 0 | } |
254 | | |
255 | | // what's left is that the range might not be from 1 to <column count>, but for instance |
256 | | // 0 to <column count>-1. |
257 | 0 | size_t nOffset = *aUsedOrdinals.begin() - 1; |
258 | 0 | for ( auto& offset : _rColumns ) |
259 | 0 | offset.nOrdinalPosition -= nOffset; |
260 | 0 | } |
261 | | } |
262 | | |
263 | | |
264 | | void OTableHelper::refreshColumns() |
265 | 0 | { |
266 | 0 | ::std::vector< OUString> aVector; |
267 | 0 | if(!isNew()) |
268 | 0 | { |
269 | 0 | Any aCatalog; |
270 | 0 | if ( !m_CatalogName.isEmpty() ) |
271 | 0 | aCatalog <<= m_CatalogName; |
272 | |
|
273 | 0 | ::utl::SharedUNOComponent< XResultSet > xResult( getMetaData()->getColumns( |
274 | 0 | aCatalog, |
275 | 0 | m_SchemaName, |
276 | 0 | m_Name, |
277 | 0 | u"%"_ustr |
278 | 0 | ) ); |
279 | | |
280 | | // collect the column names, together with their ordinal position |
281 | 0 | m_pImpl->m_aColumnDesc.clear(); |
282 | 0 | lcl_collectColumnDescs_throw( xResult, m_pImpl->m_aColumnDesc ); |
283 | | |
284 | | // ensure that the ordinal positions as obtained from the meta data do make sense |
285 | 0 | lcl_sanitizeColumnDescs( m_pImpl->m_aColumnDesc ); |
286 | | |
287 | | // sort by ordinal position |
288 | 0 | std::map< OrdinalPosition, OUString > aSortedColumns; |
289 | 0 | for (const auto& copy : m_pImpl->m_aColumnDesc) |
290 | 0 | aSortedColumns[ copy.nOrdinalPosition ] = copy.sName; |
291 | | |
292 | | // copy them to aVector, now that we have the proper ordering |
293 | 0 | std::transform( |
294 | 0 | aSortedColumns.begin(), |
295 | 0 | aSortedColumns.end(), |
296 | 0 | std::insert_iterator< ::std::vector< OUString> >( aVector, aVector.begin() ), |
297 | 0 | ::o3tl::select2nd< std::map< OrdinalPosition, OUString >::value_type >() |
298 | 0 | ); |
299 | 0 | } |
300 | |
|
301 | 0 | if(m_xColumns) |
302 | 0 | m_xColumns->reFill(aVector); |
303 | 0 | else |
304 | 0 | m_xColumns.reset(createColumns(aVector)); |
305 | 0 | } |
306 | | |
307 | | const ColumnDesc* OTableHelper::getColumnDescription(const OUString& _sName) const |
308 | 0 | { |
309 | 0 | const ColumnDesc* pRet = nullptr; |
310 | 0 | auto aIter = std::find_if(m_pImpl->m_aColumnDesc.begin(), m_pImpl->m_aColumnDesc.end(), |
311 | 0 | [&_sName](const ColumnDesc& rColumnDesc) { return rColumnDesc.sName == _sName; }); |
312 | 0 | if (aIter != m_pImpl->m_aColumnDesc.end()) |
313 | 0 | pRet = &*aIter; |
314 | 0 | return pRet; |
315 | 0 | } |
316 | | |
317 | | void OTableHelper::refreshPrimaryKeys(::std::vector< OUString>& _rNames) |
318 | 0 | { |
319 | 0 | Any aCatalog; |
320 | 0 | if ( !m_CatalogName.isEmpty() ) |
321 | 0 | aCatalog <<= m_CatalogName; |
322 | 0 | Reference< XResultSet > xResult = getMetaData()->getPrimaryKeys(aCatalog,m_SchemaName,m_Name); |
323 | |
|
324 | 0 | if ( xResult.is() ) |
325 | 0 | { |
326 | 0 | auto pKeyProps = std::make_shared<sdbcx::KeyProperties>(OUString(),KeyType::PRIMARY,0,0); |
327 | 0 | OUString aPkName; |
328 | 0 | bool bAlreadyFetched = false; |
329 | 0 | const Reference< XRow > xRow(xResult,UNO_QUERY); |
330 | 0 | while ( xResult->next() ) |
331 | 0 | { |
332 | 0 | pKeyProps->m_aKeyColumnNames.push_back(xRow->getString(4)); |
333 | 0 | if ( !bAlreadyFetched ) |
334 | 0 | { |
335 | 0 | aPkName = xRow->getString(6); |
336 | 0 | SAL_WARN_IF(xRow->wasNull(),"connectivity.commontools", "NULL Primary Key name"); |
337 | 0 | SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name"); |
338 | 0 | bAlreadyFetched = true; |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | 0 | if(bAlreadyFetched) |
343 | 0 | { |
344 | 0 | SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name"); |
345 | 0 | SAL_WARN_IF(pKeyProps->m_aKeyColumnNames.empty(),"connectivity.commontools", "Primary Key has no columns"); |
346 | 0 | m_pImpl->m_aKeys.emplace(aPkName,pKeyProps); |
347 | 0 | _rNames.push_back(aPkName); |
348 | 0 | } |
349 | 0 | } // if ( xResult.is() && xResult->next() ) |
350 | 0 | ::comphelper::disposeComponent(xResult); |
351 | 0 | } |
352 | | |
353 | | void OTableHelper::refreshForeignKeys(::std::vector< OUString>& _rNames) |
354 | 0 | { |
355 | 0 | Any aCatalog; |
356 | 0 | if ( !m_CatalogName.isEmpty() ) |
357 | 0 | aCatalog <<= m_CatalogName; |
358 | 0 | Reference< XResultSet > xResult = getMetaData()->getImportedKeys(aCatalog,m_SchemaName,m_Name); |
359 | 0 | Reference< XRow > xRow(xResult,UNO_QUERY); |
360 | |
|
361 | 0 | if ( !xRow.is() ) |
362 | 0 | return; |
363 | | |
364 | 0 | std::shared_ptr<sdbcx::KeyProperties> pKeyProps; |
365 | 0 | OUString aName,sCatalog,aSchema,sOldFKName; |
366 | 0 | while( xResult->next() ) |
367 | 0 | { |
368 | | // this must be outside the "if" because we have to call in a right order |
369 | 0 | sCatalog = xRow->getString(1); |
370 | 0 | if ( xRow->wasNull() ) |
371 | 0 | sCatalog.clear(); |
372 | 0 | aSchema = xRow->getString(2); |
373 | 0 | aName = xRow->getString(3); |
374 | |
|
375 | 0 | const OUString sForeignKeyColumn = xRow->getString(8); |
376 | 0 | const sal_Int32 nUpdateRule = xRow->getInt(10); |
377 | 0 | const sal_Int32 nDeleteRule = xRow->getInt(11); |
378 | 0 | const OUString sFkName = xRow->getString(12); |
379 | |
|
380 | 0 | if ( !sFkName.isEmpty() && !xRow->wasNull() ) |
381 | 0 | { |
382 | 0 | if ( sOldFKName != sFkName ) |
383 | 0 | { |
384 | 0 | if ( pKeyProps ) |
385 | 0 | m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps); |
386 | |
|
387 | 0 | const OUString sReferencedName = ::dbtools::composeTableName(getMetaData(),sCatalog,aSchema,aName,false,::dbtools::EComposeRule::InDataManipulation); |
388 | 0 | pKeyProps = std::make_shared<sdbcx::KeyProperties>(sReferencedName,KeyType::FOREIGN,nUpdateRule,nDeleteRule); |
389 | 0 | pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn); |
390 | 0 | _rNames.push_back(sFkName); |
391 | 0 | if ( m_pTables->hasByName(sReferencedName) ) |
392 | 0 | { |
393 | 0 | if ( !m_pImpl->m_xTablePropertyListener.is() ) |
394 | 0 | m_pImpl->m_xTablePropertyListener = new OTableContainerListener(this); |
395 | 0 | m_pTables->addContainerListener(m_pImpl->m_xTablePropertyListener); |
396 | 0 | m_pImpl->m_xTablePropertyListener->add(sReferencedName); |
397 | 0 | } // if ( m_pTables->hasByName(sReferencedName) ) |
398 | 0 | sOldFKName = sFkName; |
399 | 0 | } // if ( sOldFKName != sFkName ) |
400 | 0 | else if ( pKeyProps ) |
401 | 0 | { |
402 | 0 | pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn); |
403 | 0 | } |
404 | 0 | } |
405 | 0 | } // while( xResult->next() ) |
406 | 0 | if ( pKeyProps ) |
407 | 0 | m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps); |
408 | 0 | ::comphelper::disposeComponent(xResult); |
409 | 0 | } |
410 | | |
411 | | void OTableHelper::refreshKeys() |
412 | 0 | { |
413 | 0 | m_pImpl->m_aKeys.clear(); |
414 | |
|
415 | 0 | ::std::vector< OUString> aNames; |
416 | |
|
417 | 0 | if(!isNew()) |
418 | 0 | { |
419 | 0 | refreshPrimaryKeys(aNames); |
420 | 0 | refreshForeignKeys(aNames); |
421 | 0 | m_xKeys.reset(createKeys(aNames)); |
422 | 0 | } // if(!isNew()) |
423 | 0 | else if (!m_xKeys ) |
424 | 0 | m_xKeys.reset(createKeys(aNames)); |
425 | | /*if(m_pKeys) |
426 | | m_pKeys->reFill(aVector); |
427 | | else*/ |
428 | |
|
429 | 0 | } |
430 | | |
431 | | void OTableHelper::refreshIndexes() |
432 | 0 | { |
433 | 0 | ::std::vector< OUString> aVector; |
434 | 0 | if(!isNew()) |
435 | 0 | { |
436 | | // fill indexes |
437 | 0 | Any aCatalog; |
438 | 0 | if ( !m_CatalogName.isEmpty() ) |
439 | 0 | aCatalog <<= m_CatalogName; |
440 | 0 | Reference< XResultSet > xResult = getMetaData()->getIndexInfo(aCatalog,m_SchemaName,m_Name,false,false); |
441 | |
|
442 | 0 | if(xResult.is()) |
443 | 0 | { |
444 | 0 | Reference< XRow > xRow(xResult,UNO_QUERY); |
445 | 0 | OUString sCatalogSep = getMetaData()->getCatalogSeparator(); |
446 | 0 | OUString sPreviousRoundName; |
447 | 0 | while( xResult->next() ) |
448 | 0 | { |
449 | 0 | OUString aName = xRow->getString(5); |
450 | 0 | if(!aName.isEmpty()) |
451 | 0 | aName += sCatalogSep; |
452 | 0 | aName += xRow->getString(6); |
453 | 0 | if ( !aName.isEmpty() ) |
454 | 0 | { |
455 | | // don't insert the name if the last one we inserted was the same |
456 | 0 | if (sPreviousRoundName != aName) |
457 | 0 | aVector.push_back(aName); |
458 | 0 | } |
459 | 0 | sPreviousRoundName = aName; |
460 | 0 | } |
461 | 0 | ::comphelper::disposeComponent(xResult); |
462 | 0 | } |
463 | 0 | } |
464 | |
|
465 | 0 | if(m_xIndexes) |
466 | 0 | m_xIndexes->reFill(aVector); |
467 | 0 | else |
468 | 0 | m_xIndexes.reset(createIndexes(aVector)); |
469 | 0 | } |
470 | | |
471 | | OUString OTableHelper::getRenameStart() const |
472 | 0 | { |
473 | 0 | OUString sSql(u"RENAME "_ustr); |
474 | 0 | if ( m_Type == "VIEW" ) |
475 | 0 | sSql += " VIEW "; |
476 | 0 | else |
477 | 0 | sSql += " TABLE "; |
478 | |
|
479 | 0 | return sSql; |
480 | 0 | } |
481 | | |
482 | | // XRename |
483 | | void SAL_CALL OTableHelper::rename( const OUString& newName ) |
484 | 0 | { |
485 | 0 | ::osl::MutexGuard aGuard(m_aMutex); |
486 | 0 | checkDisposed( |
487 | 0 | #ifdef __GNUC__ |
488 | 0 | ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed |
489 | | #else |
490 | | rBHelper.bDisposed |
491 | | #endif |
492 | 0 | ); |
493 | |
|
494 | 0 | if(!isNew()) |
495 | 0 | { |
496 | 0 | if ( m_pImpl->m_xRename.is() ) |
497 | 0 | { |
498 | 0 | m_pImpl->m_xRename->rename(this,newName); |
499 | 0 | } |
500 | 0 | else |
501 | 0 | { |
502 | 0 | OUString sSql = getRenameStart(); |
503 | |
|
504 | 0 | OUString sCatalog,sSchema,sTable; |
505 | 0 | ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); |
506 | |
|
507 | 0 | OUString sComposedName; |
508 | 0 | sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,true,::dbtools::EComposeRule::InDataManipulation); |
509 | 0 | sSql += sComposedName |
510 | 0 | + " TO "; |
511 | 0 | sComposedName = ::dbtools::composeTableName(getMetaData(),sCatalog,sSchema,sTable,true,::dbtools::EComposeRule::InDataManipulation); |
512 | 0 | sSql += sComposedName; |
513 | |
|
514 | 0 | Reference< XStatement > xStmt = m_pImpl->m_xConnection->createStatement( ); |
515 | 0 | if ( xStmt.is() ) |
516 | 0 | { |
517 | 0 | xStmt->execute(sSql); |
518 | 0 | ::comphelper::disposeComponent(xStmt); |
519 | 0 | } |
520 | 0 | } |
521 | |
|
522 | 0 | OTable_TYPEDEF::rename(newName); |
523 | 0 | } |
524 | 0 | else |
525 | 0 | ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions); |
526 | 0 | } |
527 | | |
528 | | Reference< XDatabaseMetaData> OTableHelper::getMetaData() const |
529 | 0 | { |
530 | 0 | return m_pImpl->m_xMetaData; |
531 | 0 | } |
532 | | |
533 | | void SAL_CALL OTableHelper::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor ) |
534 | 0 | { |
535 | 0 | ::osl::MutexGuard aGuard(m_aMutex); |
536 | 0 | checkDisposed( |
537 | 0 | #ifdef __GNUC__ |
538 | 0 | ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed |
539 | | #else |
540 | | rBHelper.bDisposed |
541 | | #endif |
542 | 0 | ); |
543 | |
|
544 | 0 | Reference< XPropertySet > xOld( |
545 | 0 | m_xColumns->getByIndex(index), css::uno::UNO_QUERY); |
546 | 0 | if(xOld.is()) |
547 | 0 | alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor); |
548 | 0 | } |
549 | | |
550 | | |
551 | | OUString SAL_CALL OTableHelper::getName() |
552 | 0 | { |
553 | 0 | OUString sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,false,::dbtools::EComposeRule::InDataManipulation); |
554 | 0 | return sComposedName; |
555 | 0 | } |
556 | | |
557 | | const OUString & OTableHelper::getTableName() |
558 | 0 | { |
559 | 0 | return m_Name; |
560 | 0 | } |
561 | | |
562 | | std::shared_ptr<sdbcx::KeyProperties> OTableHelper::getKeyProperties(const OUString& _sName) const |
563 | 0 | { |
564 | 0 | std::shared_ptr<sdbcx::KeyProperties> pKeyProps; |
565 | 0 | TKeyMap::const_iterator aFind = m_pImpl->m_aKeys.find(_sName); |
566 | 0 | if ( aFind != m_pImpl->m_aKeys.end() ) |
567 | 0 | { |
568 | 0 | pKeyProps = aFind->second; |
569 | 0 | } |
570 | 0 | else // only a fall back |
571 | 0 | { |
572 | 0 | OSL_FAIL("No key with the given name found"); |
573 | 0 | pKeyProps = std::make_shared<sdbcx::KeyProperties>(); |
574 | 0 | } |
575 | |
|
576 | 0 | return pKeyProps; |
577 | 0 | } |
578 | | |
579 | | void OTableHelper::addKey(const OUString& _sName,const std::shared_ptr<sdbcx::KeyProperties>& _aKeyProperties) |
580 | 0 | { |
581 | 0 | m_pImpl->m_aKeys.emplace(_sName,_aKeyProperties); |
582 | 0 | } |
583 | | |
584 | | OUString OTableHelper::getTypeCreatePattern() const |
585 | 0 | { |
586 | 0 | return OUString(); |
587 | 0 | } |
588 | | |
589 | | Reference< XConnection> const & OTableHelper::getConnection() const |
590 | 0 | { |
591 | 0 | return m_pImpl->m_xConnection; |
592 | 0 | } |
593 | | |
594 | | Reference< css::sdb::tools::XTableRename> const & OTableHelper::getRenameService() const |
595 | 0 | { |
596 | 0 | return m_pImpl->m_xRename; |
597 | 0 | } |
598 | | |
599 | | Reference< css::sdb::tools::XTableAlteration> const & OTableHelper::getAlterService() const |
600 | 0 | { |
601 | 0 | return m_pImpl->m_xAlter; |
602 | 0 | } |
603 | | |
604 | | Reference< css::sdb::tools::XKeyAlteration> const & OTableHelper::getKeyService() const |
605 | 0 | { |
606 | 0 | return m_pImpl->m_xKeyAlter; |
607 | 0 | } |
608 | | |
609 | | Reference< css::sdb::tools::XIndexAlteration> const & OTableHelper::getIndexService() const |
610 | 0 | { |
611 | 0 | return m_pImpl->m_xIndexAlter; |
612 | 0 | } |
613 | | |
614 | | |
615 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |