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 <strings.hrc>
21 #include <strings.hxx>
22 #include <core_resource.hxx>
23 #include <sqlmessage.hxx>
24 #include <UITools.hxx>
25 #include <WColumnSelect.hxx>
26 #include <WCopyTable.hxx>
27 #include <WCPage.hxx>
28 #include <WExtendPages.hxx>
29 #include <WNameMatch.hxx>
30 #include <WTypeSelect.hxx>
31
32 #include <com/sun/star/sdb/application/CopyTableOperation.hpp>
33 #include <com/sun/star/sdb/SQLContext.hpp>
34 #include <com/sun/star/sdbc/ColumnValue.hpp>
35 #include <com/sun/star/sdbc/DataType.hpp>
36 #include <com/sun/star/sdbc/XResultSet.hpp>
37 #include <com/sun/star/sdbc/XStatement.hpp>
38 #include <com/sun/star/sdbc/XRow.hpp>
39 #include <com/sun/star/sdbcx/KeyType.hpp>
40 #include <com/sun/star/sdbcx/XAppend.hpp>
41 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
42 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
43 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
44 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
45 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
46 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
47 #include <com/sun/star/task/InteractionHandler.hpp>
48
49 #include <comphelper/interaction.hxx>
50 #include <connectivity/dbtools.hxx>
51 #include <connectivity/dbmetadata.hxx>
52 #include <connectivity/dbexception.hxx>
53 #include <o3tl/safeint.hxx>
54 #include <rtl/ustrbuf.hxx>
55 #include <sal/log.hxx>
56 #include <comphelper/diagnose_ex.hxx>
57
58 #include <algorithm>
59 #include <utility>
60
61 using namespace ::dbaui;
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::beans;
64 using namespace ::com::sun::star::container;
65 using namespace ::com::sun::star::util;
66 using namespace ::com::sun::star::sdb;
67 using namespace ::com::sun::star::sdbc;
68 using namespace ::com::sun::star::sdbcx;
69 using namespace ::com::sun::star::lang;
70 using namespace ::com::sun::star::task;
71 using namespace dbtools;
72
73 namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
74
75 #define MAX_PAGES 4 // max. number of pages, which are shown
76
77 namespace
78 {
clearColumns(ODatabaseExport::TColumns & _rColumns,ODatabaseExport::TColumnVector & _rColumnsVec)79 void clearColumns(ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColumnsVec)
80 {
81 for (auto const& column : _rColumns)
82 delete column.second;
83
84 _rColumnsVec.clear();
85 _rColumns.clear();
86 }
87 }
88
89 // ICopyTableSourceObject
~ICopyTableSourceObject()90 ICopyTableSourceObject::~ICopyTableSourceObject()
91 {
92 }
93
94 // ObjectCopySource
ObjectCopySource(const Reference<XConnection> & _rxConnection,const Reference<XPropertySet> & _rxObject)95 ObjectCopySource::ObjectCopySource( const Reference< XConnection >& _rxConnection, const Reference< XPropertySet >& _rxObject )
96 :m_xConnection( _rxConnection, UNO_SET_THROW )
97 ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW )
98 ,m_xObject( _rxObject, UNO_SET_THROW )
99 ,m_xObjectPSI( _rxObject->getPropertySetInfo(), UNO_SET_THROW )
100 ,m_xObjectColumns( Reference< XColumnsSupplier >( _rxObject, UNO_QUERY_THROW )->getColumns(), UNO_SET_THROW )
101 {
102 }
103
getQualifiedObjectName() const104 OUString ObjectCopySource::getQualifiedObjectName() const
105 {
106 OUString sName;
107
108 if ( !m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) )
109 sName = ::dbtools::composeTableName( m_xMetaData, m_xObject, ::dbtools::EComposeRule::InDataManipulation, false );
110 else
111 m_xObject->getPropertyValue( PROPERTY_NAME ) >>= sName;
112 return sName;
113 }
114
isView() const115 bool ObjectCopySource::isView() const
116 {
117 bool bIsView = false;
118 try
119 {
120 if ( m_xObjectPSI->hasPropertyByName( PROPERTY_TYPE ) )
121 {
122 OUString sObjectType;
123 OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_TYPE ) >>= sObjectType );
124 bIsView = sObjectType == "VIEW";
125 }
126 }
127 catch( const Exception& )
128 {
129 DBG_UNHANDLED_EXCEPTION("dbaccess");
130 }
131 return bIsView;
132 }
133
copyUISettingsTo(const Reference<XPropertySet> & _rxObject) const134 void ObjectCopySource::copyUISettingsTo( const Reference< XPropertySet >& _rxObject ) const
135 {
136 static constexpr OUString aCopyProperties[] {
137 PROPERTY_FONT, PROPERTY_ROW_HEIGHT, PROPERTY_TEXTCOLOR,PROPERTY_TEXTLINECOLOR,PROPERTY_TEXTEMPHASIS,PROPERTY_TEXTRELIEF
138 };
139 for (const auto & aCopyProperty : aCopyProperties)
140 {
141 if ( m_xObjectPSI->hasPropertyByName( aCopyProperty ) )
142 _rxObject->setPropertyValue( aCopyProperty, m_xObject->getPropertyValue( aCopyProperty ) );
143 }
144 }
145
copyFilterAndSortingTo(const Reference<XConnection> & _xConnection,const Reference<XPropertySet> & _rxObject) const146 void ObjectCopySource::copyFilterAndSortingTo( const Reference< XConnection >& _xConnection,const Reference< XPropertySet >& _rxObject ) const
147 {
148 static constexpr std::pair< OUString, OUString > aProperties[] {
149 std::pair< OUString, OUString >(PROPERTY_FILTER,u" AND "_ustr)
150 ,std::pair< OUString, OUString >(PROPERTY_ORDER,u" ORDER BY "_ustr)
151 };
152
153 try
154 {
155 const OUString sSourceName = ::dbtools::composeTableNameForSelect(m_xConnection,m_xObject) + ".";
156 const OUString sTargetName = ::dbtools::composeTableNameForSelect(_xConnection,_rxObject);
157 const OUString sTargetNameTemp = sTargetName + ".";
158
159 OUStringBuffer sStatement = "SELECT * FROM " + sTargetName + " WHERE 0=1";
160
161 for (const std::pair<OUString,OUString> & aProperty : aProperties)
162 {
163 if ( m_xObjectPSI->hasPropertyByName( aProperty.first ) )
164 {
165 OUString sFilter;
166 m_xObject->getPropertyValue( aProperty.first ) >>= sFilter;
167 if ( !sFilter.isEmpty() )
168 {
169 sStatement.append(aProperty.second);
170 sFilter = sFilter.replaceFirst(sSourceName,sTargetNameTemp);
171 _rxObject->setPropertyValue( aProperty.first, Any(sFilter) );
172 sStatement.append(sFilter);
173 }
174 }
175 }
176
177 _xConnection->createStatement()->executeQuery(sStatement.makeStringAndClear());
178
179 if ( m_xObjectPSI->hasPropertyByName( PROPERTY_APPLYFILTER ) )
180 _rxObject->setPropertyValue( PROPERTY_APPLYFILTER, m_xObject->getPropertyValue( PROPERTY_APPLYFILTER ) );
181 }
182 catch(Exception&)
183 {
184 }
185 }
186
getColumnNames() const187 Sequence< OUString > ObjectCopySource::getColumnNames() const
188 {
189 return m_xObjectColumns->getElementNames();
190 }
191
getPrimaryKeyColumnNames() const192 Sequence< OUString > ObjectCopySource::getPrimaryKeyColumnNames() const
193 {
194 const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(m_xObject);
195 Sequence< OUString > aKeyColNames;
196 if ( xPrimaryKeyColumns.is() )
197 aKeyColNames = xPrimaryKeyColumns->getElementNames();
198 return aKeyColNames;
199 }
200
createFieldDescription(const OUString & _rColumnName) const201 OFieldDescription* ObjectCopySource::createFieldDescription( const OUString& _rColumnName ) const
202 {
203 Reference< XPropertySet > xColumn( m_xObjectColumns->getByName( _rColumnName ), UNO_QUERY_THROW );
204 return new OFieldDescription( xColumn );
205 }
206
getSelectStatement() const207 OUString ObjectCopySource::getSelectStatement() const
208 {
209 OUString sSelectStatement;
210 if ( m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) )
211 { // query
212 OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_COMMAND ) >>= sSelectStatement );
213 }
214 else
215 { // table
216 OUStringBuffer aSQL( "SELECT " );
217
218 // we need to create the sql stmt with column names
219 // otherwise it is possible that names don't match
220 const OUString sQuote = m_xMetaData->getIdentifierQuoteString();
221
222 Sequence< OUString > aColumnNames = getColumnNames();
223 for (sal_Int32 i = 0; i < aColumnNames.getLength(); ++i)
224 {
225 if (i > 0)
226 aSQL.append(", ");
227 aSQL.append(::dbtools::quoteName(sQuote, aColumnNames[i]));
228 }
229
230 aSQL.append( " FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, m_xObject ) );
231
232 sSelectStatement = aSQL.makeStringAndClear();
233 }
234
235 return sSelectStatement;
236 }
237
getPreparedSelectStatement() const238 ::utl::SharedUNOComponent< XPreparedStatement > ObjectCopySource::getPreparedSelectStatement() const
239 {
240 ::utl::SharedUNOComponent< XPreparedStatement > xStatement(
241 m_xConnection->prepareStatement( getSelectStatement() ),
242 ::utl::SharedUNOComponent< XPreparedStatement >::TakeOwnership
243 );
244 return xStatement;
245 }
246
247 // NamedTableCopySource
NamedTableCopySource(const Reference<XConnection> & _rxConnection,OUString _sTableName)248 NamedTableCopySource::NamedTableCopySource( const Reference< XConnection >& _rxConnection, OUString _sTableName )
249 :m_xConnection( _rxConnection, UNO_SET_THROW )
250 ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW )
251 ,m_sTableName(std::move( _sTableName ))
252 {
253 ::dbtools::qualifiedNameComponents( m_xMetaData, m_sTableName, m_sTableCatalog, m_sTableSchema, m_sTableBareName, ::dbtools::EComposeRule::Complete );
254 impl_ensureColumnInfo_throw();
255 }
256
getQualifiedObjectName() const257 OUString NamedTableCopySource::getQualifiedObjectName() const
258 {
259 return m_sTableName;
260 }
261
isView() const262 bool NamedTableCopySource::isView() const
263 {
264 OUString sTableType;
265 try
266 {
267 Reference< XResultSet > xTableDesc( m_xMetaData->getTables( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName,
268 Sequence< OUString >() ) );
269 Reference< XRow > xTableDescRow( xTableDesc, UNO_QUERY_THROW );
270 OSL_VERIFY( xTableDesc->next() );
271 sTableType = xTableDescRow->getString( 4 );
272 OSL_ENSURE( !xTableDescRow->wasNull(), "NamedTableCopySource::isView: invalid table type!" );
273 }
274 catch( const Exception& )
275 {
276 DBG_UNHANDLED_EXCEPTION("dbaccess");
277 }
278 return sTableType == "VIEW";
279 }
280
copyUISettingsTo(const Reference<XPropertySet> &) const281 void NamedTableCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const
282 {
283 // not supported: we do not have UI settings to copy
284 }
285
copyFilterAndSortingTo(const Reference<XConnection> &,const Reference<XPropertySet> &) const286 void NamedTableCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const
287 {
288 }
289
impl_ensureColumnInfo_throw()290 void NamedTableCopySource::impl_ensureColumnInfo_throw()
291 {
292 if ( !m_aColumnInfo.empty() )
293 return;
294
295 Reference< XResultSetMetaDataSupplier > xStatementMetaSupp( impl_ensureStatement_throw().getTyped(), UNO_QUERY_THROW );
296 Reference< XResultSetMetaData > xStatementMeta( xStatementMetaSupp->getMetaData(), UNO_SET_THROW );
297
298 sal_Int32 nColCount( xStatementMeta->getColumnCount() );
299 for ( sal_Int32 i = 1; i <= nColCount; ++i )
300 {
301 OFieldDescription aDesc;
302
303 aDesc.SetName( xStatementMeta->getColumnName( i ) );
304 aDesc.SetHelpText( xStatementMeta->getColumnLabel( i ) );
305 aDesc.SetTypeValue( xStatementMeta->getColumnType( i ) );
306 aDesc.SetTypeName( xStatementMeta->getColumnTypeName( i ) );
307 aDesc.SetPrecision( xStatementMeta->getPrecision( i ) );
308 aDesc.SetScale( xStatementMeta->getScale( i ) );
309 aDesc.SetIsNullable( xStatementMeta->isNullable( i ) );
310 aDesc.SetCurrency( xStatementMeta->isCurrency( i ) );
311 aDesc.SetAutoIncrement( xStatementMeta->isAutoIncrement( i ) );
312
313 m_aColumnInfo.push_back( aDesc );
314 }
315 }
316
impl_ensureStatement_throw()317 ::utl::SharedUNOComponent< XPreparedStatement > const & NamedTableCopySource::impl_ensureStatement_throw()
318 {
319 if ( !m_xStatement.is() )
320 m_xStatement.set( m_xConnection->prepareStatement( getSelectStatement() ), UNO_SET_THROW );
321 return m_xStatement;
322 }
323
getColumnNames() const324 Sequence< OUString > NamedTableCopySource::getColumnNames() const
325 {
326 Sequence< OUString > aNames( m_aColumnInfo.size() );
327 std::transform(m_aColumnInfo.begin(), m_aColumnInfo.end(), aNames.getArray(),
328 [](const auto& elem) { return elem.GetName(); });
329
330 return aNames;
331 }
332
getPrimaryKeyColumnNames() const333 Sequence< OUString > NamedTableCopySource::getPrimaryKeyColumnNames() const
334 {
335 Sequence< OUString > aPKColNames;
336
337 try
338 {
339 Reference< XResultSet > xPKDesc( m_xMetaData->getPrimaryKeys( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName ) );
340 Reference< XRow > xPKDescRow( xPKDesc, UNO_QUERY_THROW );
341 while ( xPKDesc->next() )
342 {
343 sal_Int32 len( aPKColNames.getLength() );
344 aPKColNames.realloc( len + 1 );
345 aPKColNames.getArray()[ len ] = xPKDescRow->getString( 4 ); // COLUMN_NAME
346 }
347 }
348 catch( const Exception& )
349 {
350 DBG_UNHANDLED_EXCEPTION("dbaccess");
351 }
352
353 return aPKColNames;
354 }
355
createFieldDescription(const OUString & _rColumnName) const356 OFieldDescription* NamedTableCopySource::createFieldDescription( const OUString& _rColumnName ) const
357 {
358 for (auto const& elem : m_aColumnInfo)
359 if ( elem.GetName() == _rColumnName )
360 return new OFieldDescription(elem);
361
362 return nullptr;
363 }
364
getSelectStatement() const365 OUString NamedTableCopySource::getSelectStatement() const
366 {
367 return "SELECT * FROM " +
368 ::dbtools::composeTableNameForSelect( m_xConnection, m_sTableCatalog, m_sTableSchema, m_sTableBareName );
369 }
370
getPreparedSelectStatement() const371 ::utl::SharedUNOComponent< XPreparedStatement > NamedTableCopySource::getPreparedSelectStatement() const
372 {
373 return const_cast< NamedTableCopySource* >( this )->impl_ensureStatement_throw();
374 }
375
376 namespace {
377
378 // DummyCopySource
379 class DummyCopySource : public ICopyTableSourceObject
380 {
381 public:
DummyCopySource()382 DummyCopySource() { }
383
384 static const DummyCopySource& Instance();
385
386 // ICopyTableSourceObject overridables
387 virtual OUString getQualifiedObjectName() const override;
388 virtual bool isView() const override;
389 virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
390 virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override;
391 virtual css::uno::Sequence< OUString >
392 getColumnNames() const override;
393 virtual css::uno::Sequence< OUString >
394 getPrimaryKeyColumnNames() const override;
395 virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override;
396 virtual OUString getSelectStatement() const override;
397 virtual ::utl::SharedUNOComponent< XPreparedStatement >
398 getPreparedSelectStatement() const override;
399 };
400
401 }
402
Instance()403 const DummyCopySource& DummyCopySource::Instance()
404 {
405 static DummyCopySource s_aTheInstance;
406 return s_aTheInstance;
407 }
408
getQualifiedObjectName() const409 OUString DummyCopySource::getQualifiedObjectName() const
410 {
411 SAL_WARN("dbaccess.ui", "DummyCopySource::getQualifiedObjectName: not to be called!" );
412 return OUString();
413 }
414
isView() const415 bool DummyCopySource::isView() const
416 {
417 SAL_WARN("dbaccess.ui", "DummyCopySource::isView: not to be called!" );
418 return false;
419 }
420
copyUISettingsTo(const Reference<XPropertySet> &) const421 void DummyCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const
422 {
423 // no support
424 }
425
copyFilterAndSortingTo(const Reference<XConnection> &,const Reference<XPropertySet> &) const426 void DummyCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const
427 {
428 }
429
getColumnNames() const430 Sequence< OUString > DummyCopySource::getColumnNames() const
431 {
432 return Sequence< OUString >();
433 }
434
getPrimaryKeyColumnNames() const435 Sequence< OUString > DummyCopySource::getPrimaryKeyColumnNames() const
436 {
437 SAL_WARN("dbaccess.ui", "DummyCopySource::getPrimaryKeyColumnNames: not to be called!" );
438 return Sequence< OUString >();
439 }
440
createFieldDescription(const OUString &) const441 OFieldDescription* DummyCopySource::createFieldDescription( const OUString& /*_rColumnName*/ ) const
442 {
443 SAL_WARN("dbaccess.ui", "DummyCopySource::createFieldDescription: not to be called!" );
444 return nullptr;
445 }
446
getSelectStatement() const447 OUString DummyCopySource::getSelectStatement() const
448 {
449 SAL_WARN("dbaccess.ui", "DummyCopySource::getSelectStatement: not to be called!" );
450 return OUString();
451 }
452
getPreparedSelectStatement() const453 ::utl::SharedUNOComponent< XPreparedStatement > DummyCopySource::getPreparedSelectStatement() const
454 {
455 SAL_WARN("dbaccess.ui", "DummyCopySource::getPreparedSelectStatement: not to be called!" );
456 return ::utl::SharedUNOComponent< XPreparedStatement >();
457 }
458
459 namespace
460 {
lcl_canCreateViewFor_nothrow(const Reference<XConnection> & _rxConnection)461 bool lcl_canCreateViewFor_nothrow( const Reference< XConnection >& _rxConnection )
462 {
463 Reference< XViewsSupplier > xSup( _rxConnection, UNO_QUERY );
464 Reference< XDataDescriptorFactory > xViewFac;
465 if ( xSup.is() )
466 xViewFac.set( xSup->getViews(), UNO_QUERY );
467 return xViewFac.is();
468 }
469
lcl_sameConnection_throw(const Reference<XConnection> & _rxLHS,const Reference<XConnection> & _rxRHS)470 bool lcl_sameConnection_throw( const Reference< XConnection >& _rxLHS, const Reference< XConnection >& _rxRHS )
471 {
472 Reference< XDatabaseMetaData > xMetaLHS( _rxLHS->getMetaData(), UNO_SET_THROW );
473 Reference< XDatabaseMetaData > xMetaRHS( _rxRHS->getMetaData(), UNO_SET_THROW );
474 return xMetaLHS->getURL() == xMetaRHS->getURL();
475 }
476 }
477
478 // OCopyTableWizard
OCopyTableWizard(weld::Window * pParent,const OUString & _rDefaultName,sal_Int16 _nOperation,const ICopyTableSourceObject & _rSourceObject,const Reference<XConnection> & _xSourceConnection,const Reference<XConnection> & _xConnection,const Reference<XComponentContext> & _rxContext,const Reference<XInteractionHandler> & _xInteractionHandler)479 OCopyTableWizard::OCopyTableWizard(weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation,
480 const ICopyTableSourceObject& _rSourceObject, const Reference< XConnection >& _xSourceConnection,
481 const Reference< XConnection >& _xConnection, const Reference< XComponentContext >& _rxContext,
482 const Reference< XInteractionHandler>& _xInteractionHandler)
483 : vcl::RoadmapWizardMachine(pParent)
484 , m_mNameMapping(comphelper::UStringMixLess(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()))
485 , m_xDestConnection( _xConnection )
486 , m_rSourceObject( _rSourceObject )
487 , m_xFormatter( getNumberFormatter( _xConnection, _rxContext ) )
488 , m_xContext(_rxContext)
489 , m_xInteractionHandler(_xInteractionHandler)
490 , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
491 , m_nPageCount(0)
492 , m_bDeleteSourceColumns(true)
493 , m_bInterConnectionCopy( _xSourceConnection != _xConnection )
494 , m_sName( _rDefaultName )
495 , m_nOperation( _nOperation )
496 , m_ePressed( WIZARD_NONE )
497 , m_bCreatePrimaryKeyColumn(false)
498 , m_bUseHeaderLine(false)
499 {
500 construct();
501
502 // extract table name
503 OUString sInitialTableName( _rDefaultName );
504 try
505 {
506 m_sSourceName = m_rSourceObject.getQualifiedObjectName();
507 OSL_ENSURE( !m_sSourceName.isEmpty(), "OCopyTableWizard::OCopyTableWizard: unable to retrieve the source object's name!" );
508
509 if ( sInitialTableName.isEmpty() )
510 sInitialTableName = m_sSourceName;
511
512 if ( m_sName.isEmpty() )
513 {
514 if ( _xSourceConnection == m_xDestConnection )
515 {
516 Reference< XTablesSupplier > xSup( m_xDestConnection, UNO_QUERY_THROW );
517 m_sName = ::dbtools::createUniqueName( xSup->getTables(), sInitialTableName, false );
518 }
519 else
520 m_sName = sInitialTableName;
521 }
522 }
523 catch ( const Exception& )
524 {
525 m_sName = sInitialTableName;
526 }
527
528 ::dbaui::fillTypeInfo( _xSourceConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex );
529 ::dbaui::fillTypeInfo( m_xDestConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex );
530 loadData( m_rSourceObject, m_vSourceColumns, m_vSourceVec );
531
532 bool bAllowViews = true;
533 // if the source is a, don't allow creating views
534 if ( m_rSourceObject.isView() )
535 bAllowViews = false;
536 // no views if the target connection does not support creating them
537 if ( !lcl_canCreateViewFor_nothrow( m_xDestConnection ) )
538 bAllowViews = false;
539 // no views if we're copying to a different database
540 if ( !lcl_sameConnection_throw( _xSourceConnection, m_xDestConnection ) )
541 bAllowViews = false;
542
543 if ( m_bInterConnectionCopy )
544 {
545 Reference< XDatabaseMetaData > xSrcMeta = _xSourceConnection->getMetaData();
546 OUString sCatalog;
547 OUString sSchema;
548 OUString sTable;
549 ::dbtools::qualifiedNameComponents( xSrcMeta,
550 m_sName,
551 sCatalog,
552 sSchema,
553 sTable,
554 ::dbtools::EComposeRule::InDataManipulation);
555
556 m_sName = ::dbtools::composeTableName(m_xDestConnection->getMetaData(),sCatalog,sSchema,sTable,false,::dbtools::EComposeRule::InTableDefinitions);
557 }
558
559 std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this));
560 xPage1->disallowUseHeaderLine();
561 if ( !bAllowViews )
562 xPage1->disallowViews();
563 xPage1->setCreateStyleAction();
564 AddWizardPage(std::move(xPage1));
565
566 AddWizardPage( std::make_unique<OWizNameMatching>(CreatePageContainer(), this));
567 AddWizardPage( std::make_unique<OWizColumnSelect>(CreatePageContainer(), this));
568 AddWizardPage( std::make_unique<OWizNormalExtend>(CreatePageContainer(), this));
569 ActivatePage();
570
571 m_xAssistant->set_current_page(0);
572 }
573
CreatePageContainer()574 weld::Container* OCopyTableWizard::CreatePageContainer()
575 {
576 OUString sIdent(OUString::number(m_nPageCount));
577 weld::Container* pPageContainer = m_xAssistant->append_page(sIdent);
578 return pPageContainer;
579 }
580
OCopyTableWizard(weld::Window * pParent,OUString _sDefaultName,sal_Int16 _nOperation,ODatabaseExport::TColumns && _rSourceColumns,const ODatabaseExport::TColumnVector & _rSourceColVec,const Reference<XConnection> & _xConnection,const Reference<XNumberFormatter> & _xFormatter,TypeSelectionPageFactory _pTypeSelectionPageFactory,SvStream & _rTypeSelectionPageArg,const Reference<XComponentContext> & _rxContext)581 OCopyTableWizard::OCopyTableWizard( weld::Window* pParent, OUString _sDefaultName, sal_Int16 _nOperation,
582 ODatabaseExport::TColumns&& _rSourceColumns, const ODatabaseExport::TColumnVector& _rSourceColVec,
583 const Reference< XConnection >& _xConnection, const Reference< XNumberFormatter >& _xFormatter,
584 TypeSelectionPageFactory _pTypeSelectionPageFactory, SvStream& _rTypeSelectionPageArg, const Reference< XComponentContext >& _rxContext )
585 : vcl::RoadmapWizardMachine(pParent)
586 , m_vSourceColumns(std::move(_rSourceColumns))
587 , m_mNameMapping(comphelper::UStringMixLess(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()))
588 , m_xDestConnection( _xConnection )
589 , m_rSourceObject( DummyCopySource::Instance() )
590 , m_xFormatter(_xFormatter)
591 , m_xContext(_rxContext)
592 , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES))
593 , m_nPageCount(0)
594 , m_bDeleteSourceColumns(false)
595 , m_bInterConnectionCopy( false )
596 , m_sName(std::move(_sDefaultName))
597 , m_nOperation( _nOperation )
598 , m_ePressed( WIZARD_NONE )
599 , m_bCreatePrimaryKeyColumn(false)
600 , m_bUseHeaderLine(false)
601 {
602 construct();
603 for (auto const& sourceCol : _rSourceColVec)
604 {
605 m_vSourceVec.emplace_back(m_vSourceColumns.find(sourceCol->first));
606 }
607
608 ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex );
609 ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex );
610
611 m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr);
612
613 std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this));
614 xPage1->disallowViews();
615 xPage1->setCreateStyleAction();
616 AddWizardPage(std::move(xPage1));
617
618 AddWizardPage(std::make_unique<OWizNameMatching>(CreatePageContainer(), this));
619 AddWizardPage(std::make_unique<OWizColumnSelect>(CreatePageContainer(), this));
620 AddWizardPage((*_pTypeSelectionPageFactory)(CreatePageContainer(), this, _rTypeSelectionPageArg));
621
622 ActivatePage();
623
624 m_xAssistant->set_current_page(0);
625 }
626
construct()627 void OCopyTableWizard::construct()
628 {
629 m_xAssistant->set_size_request(700, 350);
630
631 m_xPrevPage->set_label(DBA_RES(STR_WIZ_PB_PREV));
632 m_xNextPage->set_label(DBA_RES(STR_WIZ_PB_NEXT));
633 m_xFinish->set_label(DBA_RES(STR_WIZ_PB_OK));
634
635 m_xHelp->show();
636 m_xCancel->show();
637 m_xPrevPage->show();
638 m_xNextPage->show();
639 m_xFinish->show();
640
641 m_xPrevPage->connect_clicked( LINK( this, OCopyTableWizard, ImplPrevHdl ) );
642 m_xNextPage->connect_clicked( LINK( this, OCopyTableWizard, ImplNextHdl ) );
643 m_xFinish->connect_clicked( LINK( this, OCopyTableWizard, ImplOKHdl ) );
644
645 m_xNextPage->grab_focus();
646
647 if (!m_vDestColumns.empty())
648 // source is a html or rtf table
649 m_xAssistant->change_default_button(nullptr, m_xNextPage.get());
650 else
651 m_xAssistant->change_default_button(nullptr, m_xFinish.get());
652
653 m_pTypeInfo = std::make_shared<OTypeInfo>();
654 m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';');
655 m_bAddPKFirstTime = true;
656 }
657
~OCopyTableWizard()658 OCopyTableWizard::~OCopyTableWizard()
659 {
660 if ( m_bDeleteSourceColumns )
661 clearColumns(m_vSourceColumns,m_vSourceVec);
662
663 clearColumns(m_vDestColumns,m_aDestVec);
664
665 // clear the type information
666 m_aTypeInfoIndex.clear();
667 m_aTypeInfo.clear();
668 m_aDestTypeInfoIndex.clear();
669 m_aDestTypeInfo.clear();
670 }
671
IMPL_LINK_NOARG(OCopyTableWizard,ImplPrevHdl,weld::Button &,void)672 IMPL_LINK_NOARG(OCopyTableWizard, ImplPrevHdl, weld::Button&, void)
673 {
674 m_ePressed = WIZARD_PREV;
675 if ( GetCurLevel() )
676 {
677 if ( getOperation() != CopyTableOperation::AppendData )
678 {
679 if(GetCurLevel() == 2)
680 ShowPage(GetCurLevel()-2);
681 else
682 ShowPrevPage();
683 }
684 else
685 ShowPrevPage();
686 }
687 }
688
IMPL_LINK_NOARG(OCopyTableWizard,ImplNextHdl,weld::Button &,void)689 IMPL_LINK_NOARG(OCopyTableWizard, ImplNextHdl, weld::Button&, void)
690 {
691 m_ePressed = WIZARD_NEXT;
692 if ( GetCurLevel() < MAX_PAGES )
693 {
694 if ( getOperation() != CopyTableOperation::AppendData )
695 {
696 if(GetCurLevel() == 0)
697 ShowPage(GetCurLevel()+2);
698 else
699 ShowNextPage();
700 }
701 else
702 ShowNextPage();
703 }
704 }
705
CheckColumns(sal_Int32 & _rnBreakPos)706 bool OCopyTableWizard::CheckColumns(sal_Int32& _rnBreakPos)
707 {
708 bool bRet = true;
709 m_vColumnPositions.clear();
710 m_vColumnTypes.clear();
711
712 OSL_ENSURE( m_xDestConnection.is(), "OCopyTableWizard::CheckColumns: No connection!" );
713 // If database is able to process PrimaryKeys, set PrimaryKey
714 if ( m_xDestConnection.is() )
715 {
716 bool bPKeyAllowed = supportsPrimaryKey();
717
718 bool bContainsColumns = !m_vDestColumns.empty();
719
720 if ( bPKeyAllowed && shouldCreatePrimaryKey() )
721 {
722 // add extra column for the primary key
723 TOTypeInfoSP pTypeInfo = queryPrimaryKeyType(m_aDestTypeInfo);
724 if ( pTypeInfo )
725 {
726 if ( m_bAddPKFirstTime )
727 {
728 // tdf#114955: since we chose to create a primary key
729 // be sure all other columns won't be in primary key
730 for (auto const& elem : m_vDestColumns)
731 elem.second->SetPrimaryKey(false);
732 OFieldDescription* pField = new OFieldDescription();
733 pField->SetName(m_aKeyName);
734 pField->FillFromTypeInfo(pTypeInfo,true,true);
735 pField->SetAutoIncrement(pTypeInfo->bAutoIncrement);
736 pField->SetPrimaryKey(true);
737 m_bAddPKFirstTime = false;
738 insertColumn(0,pField);
739 }
740 m_vColumnPositions.emplace_back(1,1);
741 m_vColumnTypes.push_back(pTypeInfo->nType);
742 }
743 }
744
745 if ( bContainsColumns )
746 { // we have dest columns so look for the matching column
747 for (auto const& elemSource : m_vSourceVec)
748 {
749 ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(m_mNameMapping[elemSource->first]);
750
751 if ( aDestIter != m_vDestColumns.end() )
752 {
753 ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter);
754 assert(aFind != m_aDestVec.end());
755 sal_Int32 nPos = (aFind - m_aDestVec.begin())+1;
756 m_vColumnPositions.emplace_back(nPos,nPos);
757 m_vColumnTypes.push_back((*aFind)->second->GetType());
758 }
759 else
760 {
761 m_vColumnPositions.emplace_back( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND );
762 m_vColumnTypes.push_back(0);
763 }
764 }
765 }
766 else
767 {
768 Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData() );
769 OUString sExtraChars = xMetaData->getExtraNameCharacters();
770 sal_Int32 nMaxNameLen = getMaxColumnNameLength();
771
772 _rnBreakPos=0;
773 for (auto const& elemSource : m_vSourceVec)
774 {
775 OFieldDescription* pField = new OFieldDescription(*elemSource->second);
776 pField->SetName(convertColumnName(TExportColumnFindFunctor(&m_vDestColumns),elemSource->first,sExtraChars,nMaxNameLen));
777 TOTypeInfoSP pType = convertType(elemSource->second->getSpecialTypeInfo(),bRet);
778 pField->SetType(pType);
779 if ( !bPKeyAllowed )
780 pField->SetPrimaryKey(false);
781
782 // now create a column
783 insertColumn(m_vDestColumns.size(),pField);
784 m_vColumnPositions.emplace_back(m_vDestColumns.size(),m_vDestColumns.size());
785 m_vColumnTypes.push_back(elemSource->second->GetType());
786 ++_rnBreakPos;
787 if (!bRet)
788 break;
789 }
790 }
791 }
792 return bRet;
793 }
794
IMPL_LINK_NOARG(OCopyTableWizard,ImplOKHdl,weld::Button &,void)795 IMPL_LINK_NOARG(OCopyTableWizard, ImplOKHdl, weld::Button&, void)
796 {
797 m_ePressed = WIZARD_FINISH;
798 bool bFinish = DeactivatePage();
799
800 if(!bFinish)
801 return;
802
803 weld::WaitObject aWait(m_xAssistant.get());
804 switch(getOperation())
805 {
806 case CopyTableOperation::CopyDefinitionAndData:
807 case CopyTableOperation::CopyDefinitionOnly:
808 {
809 bool bOnFirstPage = GetCurLevel() == 0;
810 if ( bOnFirstPage )
811 {
812 // we came from the first page so we have to clear
813 // all column information already collected
814 clearDestColumns();
815 m_mNameMapping.clear();
816 }
817 sal_Int32 nBreakPos = 0;
818 bool bCheckOk = CheckColumns(nBreakPos);
819 if ( bOnFirstPage && !bCheckOk )
820 {
821 showColumnTypeNotSupported(m_vSourceVec[nBreakPos-1]->first);
822 OWizTypeSelect* pPage = static_cast<OWizTypeSelect*>(GetPage(3));
823 if ( pPage )
824 {
825 m_mNameMapping.clear();
826 pPage->setDisplayRow(nBreakPos);
827 ShowPage(3);
828 return;
829 }
830 }
831 if ( m_xDestConnection.is() )
832 {
833 if ( supportsPrimaryKey() )
834 {
835 bool noPrimaryKey = std::none_of(m_vDestColumns.begin(),m_vDestColumns.end(),
836 [] (const ODatabaseExport::TColumns::value_type& tCol) { return tCol.second->IsPrimaryKey(); });
837 if ( noPrimaryKey && m_xInteractionHandler.is() )
838 {
839
840 OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY));
841 SQLContext aError(sMsg, {}, {}, 0, {}, {});
842 ::rtl::Reference xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) );
843 ::rtl::Reference xYes = new ::comphelper::OInteractionApprove;
844 xRequest->addContinuation( xYes );
845 xRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
846 ::rtl::Reference< ::comphelper::OInteractionAbort > xAbort = new ::comphelper::OInteractionAbort;
847 xRequest->addContinuation( xAbort );
848
849 m_xInteractionHandler->handle( xRequest );
850
851 if ( xYes->wasSelected() )
852 {
853 OCopyTable* pPage = static_cast<OCopyTable*>(GetPage(0));
854 m_bCreatePrimaryKeyColumn = true;
855 m_aKeyName = pPage->GetKeyName();
856 if ( m_aKeyName.isEmpty() )
857 m_aKeyName = "ID";
858 m_aKeyName = createUniqueName( m_aKeyName );
859 sal_Int32 nBreakPos2 = 0;
860 CheckColumns(nBreakPos2);
861 }
862 else if ( xAbort->wasSelected() )
863 {
864 ShowPage(3);
865 return;
866 }
867 }
868 }
869 }
870 break;
871 }
872 case CopyTableOperation::AppendData:
873 case CopyTableOperation::CreateAsView:
874 break;
875 default:
876 {
877 SAL_WARN("dbaccess.ui", "OCopyTableWizard::ImplOKHdl: invalid creation style!");
878 }
879 }
880
881 m_xAssistant->response(RET_OK);
882 }
883
setCreatePrimaryKey(bool _bDoCreate,const OUString & _rSuggestedName)884 void OCopyTableWizard::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName )
885 {
886 m_bCreatePrimaryKeyColumn = _bDoCreate;
887 if ( !_rSuggestedName.isEmpty() )
888 m_aKeyName = _rSuggestedName;
889
890 OCopyTable* pSettingsPage = dynamic_cast< OCopyTable* >( GetPage( 0 ) );
891 OSL_ENSURE( pSettingsPage, "OCopyTableWizard::setCreatePrimaryKey: page should have been added in the ctor!" );
892 if ( pSettingsPage )
893 pSettingsPage->setCreatePrimaryKey( _bDoCreate, _rSuggestedName );
894 }
895
ActivatePage()896 void OCopyTableWizard::ActivatePage()
897 {
898 OWizardPage* pCurrent = static_cast<OWizardPage*>(GetPage(GetCurLevel()));
899 if (pCurrent)
900 {
901 bool bFirstTime = pCurrent->IsFirstTime();
902 if(bFirstTime)
903 pCurrent->Reset();
904
905 CheckButtons();
906
907 m_xAssistant->set_title(pCurrent->GetTitle());
908 }
909 }
910
CheckButtons()911 void OCopyTableWizard::CheckButtons()
912 {
913 if(GetCurLevel() == 0) // the first page has no back button
914 {
915 if(m_nPageCount > 1)
916 m_xNextPage->set_sensitive(true);
917 else
918 m_xNextPage->set_sensitive(false);
919
920 m_xPrevPage->set_sensitive(false);
921 }
922 else if(GetCurLevel() == m_nPageCount-1) // the last page has no next button
923 {
924 m_xNextPage->set_sensitive(false);
925 m_xPrevPage->set_sensitive(true);
926 }
927 else
928 {
929 m_xPrevPage->set_sensitive(true);
930 // next already has its state
931 }
932 }
933
EnableNextButton(bool bEnable)934 void OCopyTableWizard::EnableNextButton(bool bEnable)
935 {
936 m_xNextPage->set_sensitive(bEnable);
937 }
938
DeactivatePage()939 bool OCopyTableWizard::DeactivatePage()
940 {
941 OWizardPage* pPage = static_cast<OWizardPage*>(GetPage(GetCurLevel()));
942 return pPage && pPage->LeavePage();
943 }
944
AddWizardPage(std::unique_ptr<OWizardPage> xPage)945 void OCopyTableWizard::AddWizardPage(std::unique_ptr<OWizardPage> xPage)
946 {
947 AddPage(std::move(xPage));
948 ++m_nPageCount;
949 }
950
insertColumn(sal_Int32 _nPos,OFieldDescription * _pField)951 void OCopyTableWizard::insertColumn(sal_Int32 _nPos,OFieldDescription* _pField)
952 {
953 OSL_ENSURE(_pField,"FieldDescrioption is null!");
954 if ( !_pField )
955 return;
956
957 ODatabaseExport::TColumns::const_iterator aFind = m_vDestColumns.find(_pField->GetName());
958 if ( aFind != m_vDestColumns.end() )
959 {
960 delete aFind->second;
961 m_vDestColumns.erase(aFind);
962 }
963
964 m_aDestVec.insert(m_aDestVec.begin() + _nPos,
965 m_vDestColumns.emplace(_pField->GetName(),_pField).first);
966 m_mNameMapping[_pField->GetName()] = _pField->GetName();
967 }
968
replaceColumn(sal_Int32 _nPos,OFieldDescription * _pField,const OUString & _sOldName)969 void OCopyTableWizard::replaceColumn(sal_Int32 _nPos,OFieldDescription* _pField,const OUString& _sOldName)
970 {
971 OSL_ENSURE(_pField,"FieldDescrioption is null!");
972 if ( _pField )
973 {
974 m_vDestColumns.erase(_sOldName);
975 OSL_ENSURE( m_vDestColumns.find(_pField->GetName()) == m_vDestColumns.end(),"Column with that name already exist!");
976
977 m_aDestVec[_nPos] = m_vDestColumns.emplace(_pField->GetName(),_pField).first;
978 }
979 }
980
loadData(const ICopyTableSourceObject & _rSourceObject,ODatabaseExport::TColumns & _rColumns,ODatabaseExport::TColumnVector & _rColVector)981 void OCopyTableWizard::loadData( const ICopyTableSourceObject& _rSourceObject, ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColVector )
982 {
983 for (auto const& column : _rColumns)
984 delete column.second;
985
986 _rColVector.clear();
987 _rColumns.clear();
988
989 OFieldDescription* pActFieldDescr = nullptr;
990 static constexpr OUStringLiteral sCreateParam(u"x");
991 // ReadOnly-Flag
992 // On drop no line must be editable.
993 // On add only empty lines must be editable.
994 // On Add and Drop all lines can be edited.
995 for (auto& column : _rSourceObject.getColumnNames())
996 {
997 // get the properties of the column
998 pActFieldDescr = _rSourceObject.createFieldDescription(column);
999 OSL_ENSURE( pActFieldDescr, "OCopyTableWizard::loadData: illegal field description!" );
1000 if ( !pActFieldDescr )
1001 continue;
1002
1003 sal_Int32 nType = pActFieldDescr->GetType();
1004 sal_Int32 nScale = pActFieldDescr->GetScale();
1005 sal_Int32 nPrecision = pActFieldDescr->GetPrecision();
1006 bool bAutoIncrement = pActFieldDescr->IsAutoIncrement();
1007 OUString sTypeName = pActFieldDescr->GetTypeName();
1008
1009 // search for type
1010 bool bForce;
1011 TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreateParam,nPrecision,nScale,bAutoIncrement,bForce);
1012 if ( !pTypeInfo )
1013 pTypeInfo = m_pTypeInfo;
1014
1015 pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false);
1016 _rColVector.emplace_back(_rColumns.emplace(pActFieldDescr->GetName(),pActFieldDescr).first);
1017 }
1018
1019 // determine which columns belong to the primary key
1020 for (auto& keyColName : _rSourceObject.getPrimaryKeyColumnNames())
1021 {
1022 ODatabaseExport::TColumns::const_iterator keyPos = _rColumns.find(keyColName);
1023 if ( keyPos != _rColumns.end() )
1024 {
1025 keyPos->second->SetPrimaryKey( true );
1026 keyPos->second->SetIsNullable( ColumnValue::NO_NULLS );
1027 }
1028 }
1029 }
1030
clearDestColumns()1031 void OCopyTableWizard::clearDestColumns()
1032 {
1033 clearColumns(m_vDestColumns,m_aDestVec);
1034 m_bAddPKFirstTime = true;
1035 m_mNameMapping.clear();
1036 }
1037
appendColumns(Reference<XColumnsSupplier> const & _rxColSup,const ODatabaseExport::TColumnVector * _pVec,bool _bKeyColumns)1038 void OCopyTableWizard::appendColumns( Reference<XColumnsSupplier> const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns)
1039 {
1040 // now append the columns
1041 OSL_ENSURE(_rxColSup.is(),"No columns supplier");
1042 if(!_rxColSup.is())
1043 return;
1044 Reference<XNameAccess> xColumns = _rxColSup->getColumns();
1045 OSL_ENSURE(xColumns.is(),"No columns");
1046 Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY);
1047
1048 Reference<XAppend> xAppend(xColumns,UNO_QUERY);
1049 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
1050
1051 for (auto const& elem : *_pVec)
1052 {
1053 OFieldDescription* pField = elem->second;
1054 if(!pField)
1055 continue;
1056
1057 Reference<XPropertySet> xColumn;
1058 if(pField->IsPrimaryKey() || !_bKeyColumns)
1059 xColumn = xColumnFactory->createDataDescriptor();
1060 if(xColumn.is())
1061 {
1062 if(!_bKeyColumns)
1063 dbaui::setColumnProperties(xColumn,pField);
1064 else
1065 xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName()));
1066
1067 xAppend->appendByDescriptor(xColumn);
1068 xColumn = nullptr;
1069 // now only the settings are missing
1070 if(xColumns->hasByName(pField->GetName()))
1071 {
1072 xColumn.set(xColumns->getByName(pField->GetName()),UNO_QUERY);
1073 OSL_ENSURE(xColumn.is(),"OCopyTableWizard::appendColumns: Column is NULL!");
1074 if ( xColumn.is() )
1075 pField->copyColumnSettingsTo(xColumn);
1076 }
1077 else
1078 {
1079 SAL_WARN("dbaccess.ui", "OCopyTableWizard::appendColumns: invalid field name!");
1080 }
1081
1082 }
1083 }
1084 }
1085
appendKey(Reference<XKeysSupplier> const & _rxSup,const ODatabaseExport::TColumnVector * _pVec)1086 void OCopyTableWizard::appendKey( Reference<XKeysSupplier> const & _rxSup, const ODatabaseExport::TColumnVector* _pVec)
1087 {
1088 if(!_rxSup.is())
1089 return; // the database doesn't support keys
1090 OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!");
1091 Reference<XDataDescriptorFactory> xKeyFactory(_rxSup->getKeys(),UNO_QUERY);
1092 OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!");
1093 if ( !xKeyFactory.is() )
1094 return;
1095 Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY);
1096 OSL_ENSURE(xAppend.is(),"No XAppend Interface!");
1097
1098 Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor();
1099 OSL_ENSURE(xKey.is(),"Key is null!");
1100 xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY));
1101
1102 Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY);
1103 if(xColSup.is())
1104 {
1105 appendColumns(xColSup,_pVec,true);
1106 Reference<XNameAccess> xColumns = xColSup->getColumns();
1107 if(xColumns.is() && xColumns->getElementNames().hasElements())
1108 xAppend->appendByDescriptor(xKey);
1109 }
1110
1111 }
1112
createView() const1113 Reference< XPropertySet > OCopyTableWizard::createView() const
1114 {
1115 OUString sCommand( m_rSourceObject.getSelectStatement() );
1116 OSL_ENSURE( !sCommand.isEmpty(), "OCopyTableWizard::createView: no statement in the source object!" );
1117 // there are legitimate cases in which getSelectStatement does not provide a statement,
1118 // but in all those cases, this method here should never be called.
1119 return ::dbaui::createView( m_sName, m_xDestConnection, sCommand );
1120 }
1121
returnTable()1122 Reference< XPropertySet > OCopyTableWizard::returnTable()
1123 {
1124 if ( getOperation() == CopyTableOperation::AppendData )
1125 return getTable();
1126 else
1127 return createTable();
1128 }
1129
getTable() const1130 Reference< XPropertySet > OCopyTableWizard::getTable() const
1131 {
1132 Reference< XPropertySet > xTable;
1133
1134 Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY );
1135 Reference< XNameAccess > xTables;
1136 if(xSup.is())
1137 xTables = xSup->getTables();
1138 if(xTables.is() && xTables->hasByName(m_sName))
1139 xTables->getByName(m_sName) >>= xTable;
1140
1141 return xTable;
1142 }
1143
createTable()1144 Reference< XPropertySet > OCopyTableWizard::createTable()
1145 {
1146 Reference< XPropertySet > xTable;
1147
1148 Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY );
1149 Reference< XNameAccess > xTables;
1150 if(xSup.is())
1151 xTables = xSup->getTables();
1152 Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY);
1153 OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!");
1154 if(!xFact.is())
1155 return nullptr;
1156
1157 xTable = xFact->createDataDescriptor();
1158 OSL_ENSURE(xTable.is(),"Could not create a new object!");
1159 if(!xTable.is())
1160 return nullptr;
1161
1162 OUString sCatalog,sSchema,sTable;
1163 Reference< XDatabaseMetaData> xMetaData = m_xDestConnection->getMetaData();
1164 ::dbtools::qualifiedNameComponents(xMetaData,
1165 m_sName,
1166 sCatalog,
1167 sSchema,
1168 sTable,
1169 ::dbtools::EComposeRule::InDataManipulation);
1170
1171 if ( sCatalog.isEmpty() && xMetaData->supportsCatalogsInTableDefinitions() )
1172 {
1173 sCatalog = m_xDestConnection->getCatalog();
1174 }
1175
1176 if ( sSchema.isEmpty() && xMetaData->supportsSchemasInTableDefinitions() )
1177 {
1178 // query of current schema is quite inconsistent. In case of some
1179 // DBMS's each user has their own schema.
1180 sSchema = xMetaData->getUserName();
1181 // In case of mysql it is not that simple
1182 if(xMetaData->getDatabaseProductName() == "MySQL")
1183 {
1184 Reference< XStatement > xSelect = m_xDestConnection->createStatement();
1185 Reference< XResultSet > xRs = xSelect->executeQuery(u"select database()"_ustr);
1186 (void)xRs->next(); // first and only result
1187 Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
1188 sSchema = xRow->getString(1);
1189 }
1190 }
1191
1192 xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog));
1193 xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema));
1194 xTable->setPropertyValue(PROPERTY_NAME,Any(sTable));
1195
1196 Reference< XColumnsSupplier > xSuppDestinationColumns( xTable, UNO_QUERY );
1197 // now append the columns
1198 const ODatabaseExport::TColumnVector& rVec = getDestVector();
1199 appendColumns( xSuppDestinationColumns, &rVec );
1200 // now append the primary key
1201 Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY);
1202 appendKey(xKeySup, &rVec);
1203
1204 Reference<XAppend> xAppend(xTables,UNO_QUERY);
1205 if(xAppend.is())
1206 xAppend->appendByDescriptor(xTable);
1207
1208 // xTable = NULL;
1209 // we need to reget the table because after appending it, it is no longer valid
1210 if(xTables->hasByName(m_sName))
1211 xTables->getByName(m_sName) >>= xTable;
1212 else
1213 {
1214 OUString sComposedName(
1215 ::dbtools::composeTableName( m_xDestConnection->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false ) );
1216 if(xTables->hasByName(sComposedName))
1217 {
1218 xTables->getByName(sComposedName) >>= xTable;
1219 m_sName = sComposedName;
1220 }
1221 else
1222 xTable = nullptr;
1223 }
1224
1225 if(xTable.is())
1226 {
1227 xSuppDestinationColumns.set( xTable, UNO_QUERY_THROW );
1228 // insert new table name into table filter
1229 ::dbaui::appendToFilter(m_xDestConnection, m_sName, GetComponentContext(), m_xAssistant.get());
1230
1231 // copy ui settings
1232 m_rSourceObject.copyUISettingsTo( xTable );
1233 //copy filter and sorting
1234 m_rSourceObject.copyFilterAndSortingTo(m_xDestConnection,xTable);
1235 // set column mappings
1236 Reference<XNameAccess> xNameAccess = xSuppDestinationColumns->getColumns();
1237 Sequence< OUString> aSeq = xNameAccess->getElementNames();
1238
1239 for (sal_Int32 i = 0; i < aSeq.getLength(); ++i)
1240 {
1241 ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(aSeq[i]);
1242
1243 if ( aDestIter != m_vDestColumns.end() )
1244 {
1245 ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter);
1246 sal_Int32 nPos = (aFind - m_aDestVec.begin())+1;
1247
1248 ODatabaseExport::TPositions::iterator aPosFind = std::find_if(
1249 m_vColumnPositions.begin(),
1250 m_vColumnPositions.end(),
1251 [nPos] (const ODatabaseExport::TPositions::value_type& tPos) {
1252 return tPos.first == nPos;
1253 }
1254 );
1255
1256 if ( m_vColumnPositions.end() != aPosFind )
1257 {
1258 aPosFind->second = i + 1;
1259 OSL_ENSURE( m_vColumnTypes.size() > o3tl::make_unsigned( aPosFind - m_vColumnPositions.begin() ),
1260 "Invalid index for vector!" );
1261 m_vColumnTypes[ aPosFind - m_vColumnPositions.begin() ] = (*aFind)->second->GetType();
1262 }
1263 }
1264 }
1265 }
1266
1267 return xTable;
1268 }
1269
supportsPrimaryKey(const Reference<XConnection> & _rxConnection)1270 bool OCopyTableWizard::supportsPrimaryKey( const Reference< XConnection >& _rxConnection )
1271 {
1272 OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsPrimaryKey: invalid connection!" );
1273 if ( !_rxConnection.is() )
1274 return false;
1275
1276 ::dbtools::DatabaseMetaData aMetaData( _rxConnection );
1277 return aMetaData.supportsPrimaryKeys();
1278 }
1279
supportsViews(const Reference<XConnection> & _rxConnection)1280 bool OCopyTableWizard::supportsViews( const Reference< XConnection >& _rxConnection )
1281 {
1282 OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsViews: invalid connection!" );
1283 if ( !_rxConnection.is() )
1284 return false;
1285
1286 bool bSupportsViews( false );
1287 try
1288 {
1289 Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW );
1290 Reference< XViewsSupplier > xViewSups( _rxConnection, UNO_QUERY );
1291 bSupportsViews = xViewSups.is();
1292 if ( !bSupportsViews )
1293 {
1294 try
1295 {
1296 Reference< XResultSet > xRs( xMetaData->getTableTypes(), UNO_SET_THROW );
1297 Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
1298 while ( xRs->next() )
1299 {
1300 OUString sValue = xRow->getString( 1 );
1301 if ( !xRow->wasNull() && sValue.equalsIgnoreAsciiCase("View") )
1302 {
1303 bSupportsViews = true;
1304 break;
1305 }
1306 }
1307 }
1308 catch( const SQLException& )
1309 {
1310 DBG_UNHANDLED_EXCEPTION("dbaccess");
1311 }
1312 }
1313 }
1314 catch( const Exception& )
1315 {
1316 DBG_UNHANDLED_EXCEPTION("dbaccess");
1317 }
1318 return bSupportsViews;
1319 }
1320
getMaxColumnNameLength() const1321 sal_Int32 OCopyTableWizard::getMaxColumnNameLength() const
1322 {
1323 sal_Int32 nLen = 0;
1324 if ( m_xDestConnection.is() )
1325 {
1326 try
1327 {
1328 Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
1329 nLen = xMetaData->getMaxColumnNameLength();
1330 }
1331 catch(const Exception&)
1332 {
1333 DBG_UNHANDLED_EXCEPTION("dbaccess");
1334 }
1335 }
1336 return nLen;
1337 }
1338
setOperation(const sal_Int16 _nOperation)1339 void OCopyTableWizard::setOperation( const sal_Int16 _nOperation )
1340 {
1341 m_nOperation = _nOperation;
1342 }
1343
1344
convertColumnName(const TColumnFindFunctor & _rCmpFunctor,const OUString & _sColumnName,std::u16string_view _sExtraChars,sal_Int32 _nMaxNameLen)1345 OUString OCopyTableWizard::convertColumnName(const TColumnFindFunctor& _rCmpFunctor,
1346 const OUString& _sColumnName,
1347 std::u16string_view _sExtraChars,
1348 sal_Int32 _nMaxNameLen)
1349 {
1350 OUString sAlias = _sColumnName;
1351 if ( isSQL92CheckEnabled( m_xDestConnection ) )
1352 sAlias = ::dbtools::convertName2SQLName(_sColumnName,_sExtraChars);
1353 if((_nMaxNameLen && sAlias.getLength() > _nMaxNameLen) || _rCmpFunctor(sAlias))
1354 {
1355 sal_Int32 nDiff = 1;
1356 do
1357 {
1358 ++nDiff;
1359 if(_nMaxNameLen && sAlias.getLength() >= _nMaxNameLen)
1360 sAlias = sAlias.copy(0,sAlias.getLength() - (sAlias.getLength()-_nMaxNameLen+nDiff));
1361
1362 OUString sName(sAlias);
1363 sal_Int32 nPos = 1;
1364 sName += OUString::number(nPos);
1365
1366 while(_rCmpFunctor(sName))
1367 {
1368 sName = sAlias + OUString::number(++nPos);
1369 }
1370 sAlias = sName;
1371 // we have to check again, it could happen that the name is already too long
1372 }
1373 while(_nMaxNameLen && sAlias.getLength() > _nMaxNameLen);
1374 }
1375 OSL_ENSURE(m_mNameMapping.find(_sColumnName) == m_mNameMapping.end(),"name doubled!");
1376 m_mNameMapping[_sColumnName] = sAlias;
1377 return sAlias;
1378 }
1379
removeColumnNameFromNameMap(const OUString & _sName)1380 void OCopyTableWizard::removeColumnNameFromNameMap(const OUString& _sName)
1381 {
1382 m_mNameMapping.erase(_sName);
1383 }
1384
supportsType(sal_Int32 _nDataType,sal_Int32 & _rNewDataType)1385 bool OCopyTableWizard::supportsType(sal_Int32 _nDataType, sal_Int32& _rNewDataType)
1386 {
1387 bool bRet = m_aDestTypeInfo.find(_nDataType) != m_aDestTypeInfo.end();
1388 if ( bRet )
1389 _rNewDataType = _nDataType;
1390 return bRet;
1391 }
1392
convertType(const TOTypeInfoSP & _pType,bool & _bNotConvert)1393 TOTypeInfoSP OCopyTableWizard::convertType(const TOTypeInfoSP& _pType, bool& _bNotConvert)
1394 {
1395 if ( !m_bInterConnectionCopy )
1396 // no need to convert if the source and destination connection are the same
1397 return _pType;
1398
1399 bool bForce;
1400 TOTypeInfoSP pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,_pType->nType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce);
1401 if ( !pType || bForce )
1402 { // no type found so we have to find the correct one ourself
1403 sal_Int32 nDefaultType = DataType::VARCHAR;
1404 switch(_pType->nType)
1405 {
1406 case DataType::TINYINT:
1407 if(supportsType(DataType::SMALLINT,nDefaultType))
1408 break;
1409 [[fallthrough]];
1410 case DataType::SMALLINT:
1411 if(supportsType(DataType::INTEGER,nDefaultType))
1412 break;
1413 [[fallthrough]];
1414 case DataType::INTEGER:
1415 if(supportsType(DataType::FLOAT,nDefaultType))
1416 break;
1417 [[fallthrough]];
1418 case DataType::FLOAT:
1419 if(supportsType(DataType::REAL,nDefaultType))
1420 break;
1421 [[fallthrough]];
1422 case DataType::DATE:
1423 case DataType::TIME:
1424 if( DataType::DATE == _pType->nType || DataType::TIME == _pType->nType )
1425 {
1426 if(supportsType(DataType::TIMESTAMP,nDefaultType))
1427 break;
1428 }
1429 [[fallthrough]];
1430 case DataType::TIMESTAMP:
1431 case DataType::REAL:
1432 case DataType::BIGINT:
1433 if ( supportsType(DataType::DOUBLE,nDefaultType) )
1434 break;
1435 [[fallthrough]];
1436 case DataType::DOUBLE:
1437 if ( supportsType(DataType::NUMERIC,nDefaultType) )
1438 break;
1439 [[fallthrough]];
1440 case DataType::NUMERIC:
1441 supportsType(DataType::DECIMAL,nDefaultType);
1442 break;
1443 case DataType::DECIMAL:
1444 if ( supportsType(DataType::NUMERIC,nDefaultType) )
1445 break;
1446 if ( supportsType(DataType::DOUBLE,nDefaultType) )
1447 break;
1448 break;
1449 case DataType::VARCHAR:
1450 if ( supportsType(DataType::LONGVARCHAR,nDefaultType) )
1451 break;
1452 break;
1453 case DataType::LONGVARCHAR:
1454 if ( supportsType(DataType::CLOB,nDefaultType) )
1455 break;
1456 break;
1457 case DataType::BINARY:
1458 if ( supportsType(DataType::VARBINARY,nDefaultType) )
1459 break;
1460 break;
1461 case DataType::VARBINARY:
1462 if ( supportsType(DataType::LONGVARBINARY,nDefaultType) )
1463 break;
1464 break;
1465 case DataType::LONGVARBINARY:
1466 if ( supportsType(DataType::BLOB,nDefaultType) )
1467 break;
1468 if ( supportsType(DataType::LONGVARCHAR,nDefaultType) )
1469 break;
1470 if ( supportsType(DataType::CLOB,nDefaultType) )
1471 break;
1472 break;
1473 default:
1474 nDefaultType = DataType::VARCHAR;
1475 }
1476 pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,nDefaultType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce);
1477 if ( !pType )
1478 {
1479 _bNotConvert = false;
1480 pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,DataType::VARCHAR,_pType->aTypeName,u"x"_ustr,50,0,false,bForce);
1481 if ( !pType )
1482 pType = m_pTypeInfo;
1483 }
1484 else if ( bForce )
1485 _bNotConvert = false;
1486 }
1487 return pType;
1488 }
1489
createUniqueName(const OUString & _sName)1490 OUString OCopyTableWizard::createUniqueName(const OUString& _sName)
1491 {
1492 OUString sName = _sName;
1493 Sequence< OUString > aColumnNames( m_rSourceObject.getColumnNames() );
1494 if ( aColumnNames.hasElements() )
1495 sName = ::dbtools::createUniqueName( aColumnNames, sName, false );
1496 else
1497 {
1498 if ( m_vSourceColumns.find(sName) != m_vSourceColumns.end())
1499 {
1500 sal_Int32 nPos = 0;
1501 while(m_vSourceColumns.find(sName) != m_vSourceColumns.end())
1502 {
1503 sName = _sName + OUString::number(++nPos);
1504 }
1505 }
1506 }
1507 return sName;
1508 }
1509
showColumnTypeNotSupported(std::u16string_view _rColumnName)1510 void OCopyTableWizard::showColumnTypeNotSupported(std::u16string_view _rColumnName)
1511 {
1512 OUString sMessage( DBA_RES( STR_UNKNOWN_TYPE_FOUND ) );
1513 sMessage = sMessage.replaceFirst("#1",_rColumnName);
1514 showError(sMessage);
1515 }
1516
showError(const OUString & _sErrorMessage)1517 void OCopyTableWizard::showError(const OUString& _sErrorMessage)
1518 {
1519 SQLExceptionInfo aInfo(_sErrorMessage);
1520 showError(aInfo.get());
1521 }
1522
showError(const Any & _aError)1523 void OCopyTableWizard::showError(const Any& _aError)
1524 {
1525 if ( _aError.hasValue() && m_xInteractionHandler.is() )
1526 {
1527 try
1528 {
1529 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( _aError ) );
1530 m_xInteractionHandler->handle( xRequest );
1531 }
1532 catch( const Exception& )
1533 {
1534 DBG_UNHANDLED_EXCEPTION("dbaccess");
1535 }
1536 }
1537 }
1538
1539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1540