LibreOffice Module dbaccess (master) 1
copytablewizard.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
20#include <memory>
21#include <strings.hrc>
22#include <strings.hxx>
23#include <core_resource.hxx>
24#include <WCopyTable.hxx>
25
26#include <com/sun/star/lang/XMultiServiceFactory.hpp>
27#include <com/sun/star/sdb/application/XCopyTableWizard.hpp>
28#include <com/sun/star/sdb/application/CopyTableContinuation.hpp>
29#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
30#include <com/sun/star/ucb/AlreadyInitializedException.hpp>
31#include <com/sun/star/lang/NotInitializedException.hpp>
32#include <com/sun/star/sdbc/XDataSource.hpp>
33#include <com/sun/star/sdbc/DataType.hpp>
34#include <com/sun/star/container/XNameAccess.hpp>
35#include <com/sun/star/container/XChild.hpp>
36#include <com/sun/star/task/InteractionHandler.hpp>
37#include <com/sun/star/frame/XModel.hpp>
38#include <com/sun/star/sdb/DatabaseContext.hpp>
39#include <com/sun/star/sdb/XDocumentDataSource.hpp>
40#include <com/sun/star/sdb/XCompletedConnection.hpp>
41#include <com/sun/star/sdb/CommandType.hpp>
42#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
43#include <com/sun/star/sdb/XQueriesSupplier.hpp>
44#include <com/sun/star/lang/DisposedException.hpp>
45#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
46#include <com/sun/star/sdbc/XParameters.hpp>
47#include <com/sun/star/sdbc/XRow.hpp>
48#include <com/sun/star/sdbcx/XRowLocate.hpp>
49#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
50#include <com/sun/star/sdb/SQLContext.hpp>
51#include <com/sun/star/sdbc/DriverManager.hpp>
52#include <com/sun/star/sdbc/ConnectionPool.hpp>
53
63#include <o3tl/safeint.hxx>
64#include <rtl/ustrbuf.hxx>
65#include <sal/log.hxx>
70#include <vcl/svapp.hxx>
71
72namespace dbaui
73{
74
75 using ::com::sun::star::uno::Reference;
76 using ::com::sun::star::uno::XInterface;
77 using ::com::sun::star::uno::UNO_QUERY;
78 using ::com::sun::star::uno::UNO_QUERY_THROW;
79 using ::com::sun::star::uno::UNO_SET_THROW;
80 using ::com::sun::star::uno::Exception;
81 using ::com::sun::star::uno::RuntimeException;
82 using ::com::sun::star::uno::Any;
83 using ::com::sun::star::uno::Sequence;
84 using ::com::sun::star::uno::XComponentContext;
85 using ::com::sun::star::beans::XPropertySetInfo;
86 using ::com::sun::star::lang::XMultiServiceFactory;
87 using ::com::sun::star::beans::Property;
88 using ::com::sun::star::sdb::application::XCopyTableWizard;
89 using ::com::sun::star::sdb::application::XCopyTableListener;
90 using ::com::sun::star::sdb::application::CopyTableRowEvent;
91 using ::com::sun::star::beans::Optional;
92 using ::com::sun::star::lang::IllegalArgumentException;
93 using ::com::sun::star::ucb::AlreadyInitializedException;
94 using ::com::sun::star::beans::XPropertySet;
95 using ::com::sun::star::lang::NotInitializedException;
96 using ::com::sun::star::lang::XServiceInfo;
97 using ::com::sun::star::sdbc::XConnection;
98 using ::com::sun::star::sdbc::XDataSource;
99 using ::com::sun::star::container::XNameAccess;
100 using ::com::sun::star::container::XChild;
101 using ::com::sun::star::task::InteractionHandler;
102 using ::com::sun::star::task::XInteractionHandler;
103 using ::com::sun::star::frame::XModel;
104 using ::com::sun::star::sdb::DatabaseContext;
105 using ::com::sun::star::sdb::XDatabaseContext;
106 using ::com::sun::star::sdb::XDocumentDataSource;
107 using ::com::sun::star::sdb::XCompletedConnection;
108 using ::com::sun::star::lang::WrappedTargetException;
109 using ::com::sun::star::sdbcx::XTablesSupplier;
110 using ::com::sun::star::sdb::XQueriesSupplier;
111 using ::com::sun::star::lang::DisposedException;
112 using ::com::sun::star::sdbc::XPreparedStatement;
113 using ::com::sun::star::sdb::XSingleSelectQueryComposer;
114 using ::com::sun::star::sdbc::XDatabaseMetaData;
115 using ::com::sun::star::sdbcx::XColumnsSupplier;
116 using ::com::sun::star::sdbc::XParameters;
117 using ::com::sun::star::sdbc::XResultSet;
118 using ::com::sun::star::sdbc::XRow;
119 using ::com::sun::star::sdbcx::XRowLocate;
120 using ::com::sun::star::sdbc::XResultSetMetaDataSupplier;
121 using ::com::sun::star::sdbc::XResultSetMetaData;
122 using ::com::sun::star::sdbc::SQLException;
123 using ::com::sun::star::sdb::SQLContext;
124 using ::com::sun::star::sdbc::ConnectionPool;
125 using ::com::sun::star::sdbc::XDriverManager;
126 using ::com::sun::star::sdbc::DriverManager;
127 using ::com::sun::star::beans::PropertyValue;
128
129 namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
130 namespace CopyTableContinuation = ::com::sun::star::sdb::application::CopyTableContinuation;
131 namespace CommandType = ::com::sun::star::sdb::CommandType;
132 namespace DataType = ::com::sun::star::sdbc::DataType;
133
134 typedef ::utl::SharedUNOComponent< XConnection > SharedConnection;
135
136 // CopyTableWizard
138 typedef ::cppu::ImplInheritanceHelper< CopyTableWizard_DialogBase
139 , XCopyTableWizard
141
142 namespace {
143
144 class CopyTableWizard
146 ,public ::comphelper::OPropertyArrayUsageHelper< CopyTableWizard >
147 {
148 public:
149 // XServiceInfo
150 virtual OUString SAL_CALL getImplementationName() override;
151 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
152
153 // XCopyTableWizard
154 virtual ::sal_Int16 SAL_CALL getOperation() override;
155 virtual void SAL_CALL setOperation( ::sal_Int16 _operation ) override;
156 virtual OUString SAL_CALL getDestinationTableName() override;
157 virtual void SAL_CALL setDestinationTableName( const OUString& _destinationTableName ) override;
158 virtual Optional< OUString > SAL_CALL getCreatePrimaryKey() override;
159 virtual void SAL_CALL setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey ) override;
160 virtual sal_Bool SAL_CALL getUseHeaderLineAsColumnNames() override;
161 virtual void SAL_CALL setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames ) override;
162 virtual void SAL_CALL addCopyTableListener( const Reference< XCopyTableListener >& Listener ) override;
163 virtual void SAL_CALL removeCopyTableListener( const Reference< XCopyTableListener >& Listener ) override;
164
165 // XCopyTableWizard::XExecutableDialog
166 virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
167 virtual ::sal_Int16 SAL_CALL execute( ) override;
168
169 // XInitialization
170 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
171
172 // XPropertySet
173 virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
174 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
175
176 // OPropertyArrayUsageHelper
177 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
178
179 public:
180 ::osl::Mutex& getMutex() { return m_aMutex; }
181 bool isInitialized() const { return m_xSourceConnection.is() && m_pSourceObject && m_xDestConnection.is(); }
182
183 explicit CopyTableWizard( const Reference< XComponentContext >& _rxORB );
184 virtual ~CopyTableWizard() override;
185
186 protected:
187 // OGenericUnoDialog overridables
188 virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override;
189 virtual void executedDialog( sal_Int16 _nExecutionResult ) override;
190
191 private:
193 void impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const;
194
196 void impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog );
197
204 impl_getDialog_throw();
205
221 impl_ensureDataAccessDescriptor_throw(
222 const Sequence< Any >& _rAllArgs,
223 const sal_Int16 _nArgPos,
224 SharedConnection& _out_rxConnection,
225 Reference< XInteractionHandler >& _out_rxDocInteractionHandler
226 ) const;
227
231 std::unique_ptr< ICopyTableSourceObject >
232 impl_extractSourceObject_throw(
233 const Reference< XPropertySet >& _rxDescriptor,
234 sal_Int32& _out_rCommandType
235 ) const;
236
244 void impl_extractSourceResultSet_throw(
245 const Reference< XPropertySet >& i_rDescriptor
246 );
247
254 void impl_checkForUnsupportedSettings_throw(
255 const Reference< XPropertySet >& _rxSourceDescriptor ) const;
256
275 impl_extractConnection_throw(
276 const Reference< XPropertySet >& _rxDataSourceDescriptor,
277 Reference< XInteractionHandler >& _out_rxDocInteractionHandler
278 ) const;
279
284 void impl_doCopy_nothrow();
285
289 OUString impl_getServerSideCopyStatement_throw( const Reference< XPropertySet >& _xTable );
290
297 impl_createSourceStatement_throw() const;
298
301 void impl_copyRows_throw(
302 const Reference< XResultSet >& _rxSourceResultSet,
303 const Reference< XPropertySet >& _rxDestTable
304 );
305
315 bool impl_processCopyError_nothrow(
316 const CopyTableRowEvent& _rEvent );
317
318private:
319 Reference<XComponentContext> m_xContext;
320
321 // attributes
322 sal_Int16 m_nOperation;
324 Optional< OUString > m_aPrimaryKeyName;
326
327 // source
329 sal_Int32 m_nCommandType;
330 std::unique_ptr< ICopyTableSourceObject >
332 Reference< XResultSet > m_xSourceResultSet;
333 Sequence< Any > m_aSourceSelection;
335
336 // destination
338
339 // other
340 Reference< XInteractionHandler > m_xInteractionHandler;
344 };
345
346// MethodGuard
347class CopyTableAccessGuard
348{
349public:
350 explicit CopyTableAccessGuard( CopyTableWizard& _rWizard )
351 :m_rWizard( _rWizard )
352 {
353 m_rWizard.getMutex().acquire();
354 if ( !m_rWizard.isInitialized() )
355 throw NotInitializedException();
356 }
357
358 ~CopyTableAccessGuard()
359 {
360 m_rWizard.getMutex().release();
361 }
362
363private:
364 CopyTableWizard& m_rWizard;
365};
366
367}
368
369CopyTableWizard::CopyTableWizard( const Reference< XComponentContext >& _rxORB )
370 :CopyTableWizard_Base( _rxORB )
371 ,m_xContext( _rxORB )
372 ,m_nOperation( CopyTableOperation::CopyDefinitionAndData )
373 ,m_aPrimaryKeyName( false, "ID" )
379{
380}
381
382CopyTableWizard::~CopyTableWizard()
383{
384 acquire();
385
386 // protect some members whose dtor might potentially throw
387 try { m_xSourceConnection.clear(); }
388 catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
389 try { m_xDestConnection.clear(); }
390 catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
391
392 // TODO: shouldn't we have explicit disposal support? If a listener is registered
393 // at our instance, and perhaps holds this our instance by a hard ref, then we'll never
394 // be destroyed.
395 // However, adding XComponent support to the GenericUNODialog probably requires
396 // some thinking - would it break existing clients which do not call a dispose, then?
397}
398
399OUString SAL_CALL CopyTableWizard::getImplementationName()
400{
401 return "org.openoffice.comp.dbu.CopyTableWizard";
402}
403
404css::uno::Sequence<OUString> SAL_CALL CopyTableWizard::getSupportedServiceNames()
405{
406 return { "com.sun.star.sdb.application.CopyTableWizard" };
407}
408
409Reference< XPropertySetInfo > SAL_CALL CopyTableWizard::getPropertySetInfo()
410{
411 Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
412 return xInfo;
413}
414
415::sal_Int16 SAL_CALL CopyTableWizard::getOperation()
416{
417 CopyTableAccessGuard aGuard( *this );
418 return m_nOperation;
419}
420
421void SAL_CALL CopyTableWizard::setOperation( ::sal_Int16 _operation )
422{
423 CopyTableAccessGuard aGuard( *this );
424
425 if ( ( _operation != CopyTableOperation::CopyDefinitionAndData )
426 && ( _operation != CopyTableOperation::CopyDefinitionOnly )
427 && ( _operation != CopyTableOperation::CreateAsView )
428 && ( _operation != CopyTableOperation::AppendData )
429 )
430 throw IllegalArgumentException( OUString(), *this, 1 );
431
432 if ( ( _operation == CopyTableOperation::CreateAsView )
433 && !OCopyTableWizard::supportsViews( m_xDestConnection )
434 )
435 throw IllegalArgumentException(
436 DBA_RES( STR_CTW_NO_VIEWS_SUPPORT ),
437 *this,
438 1
439 );
440
441 m_nOperation = _operation;
442}
443
444OUString SAL_CALL CopyTableWizard::getDestinationTableName()
445{
446 CopyTableAccessGuard aGuard( *this );
447 return m_sDestinationTable;
448}
449
450void SAL_CALL CopyTableWizard::setDestinationTableName( const OUString& _destinationTableName )
451{
452 CopyTableAccessGuard aGuard( *this );
453 m_sDestinationTable = _destinationTableName;
454}
455
456Optional< OUString > SAL_CALL CopyTableWizard::getCreatePrimaryKey()
457{
458 CopyTableAccessGuard aGuard( *this );
459 return m_aPrimaryKeyName;
460}
461
462void SAL_CALL CopyTableWizard::setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey )
463{
464 CopyTableAccessGuard aGuard( *this );
465
466 if ( _newPrimaryKey.IsPresent && !OCopyTableWizard::supportsPrimaryKey( m_xDestConnection ) )
467 throw IllegalArgumentException(
468 DBA_RES( STR_CTW_NO_PRIMARY_KEY_SUPPORT ),
469 *this,
470 1
471 );
472
473 m_aPrimaryKeyName = _newPrimaryKey;
474}
475
476sal_Bool SAL_CALL CopyTableWizard::getUseHeaderLineAsColumnNames()
477{
478 CopyTableAccessGuard aGuard( *this );
480}
481
482void SAL_CALL CopyTableWizard::setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames )
483{
484 CopyTableAccessGuard aGuard( *this );
485 m_bUseHeaderLineAsColumnNames = _bUseHeaderLineAsColumnNames;
486}
487
488void SAL_CALL CopyTableWizard::addCopyTableListener( const Reference< XCopyTableListener >& _rxListener )
489{
490 CopyTableAccessGuard aGuard( *this );
491 if ( _rxListener.is() )
492 m_aCopyTableListeners.addInterface( _rxListener );
493}
494
495void SAL_CALL CopyTableWizard::removeCopyTableListener( const Reference< XCopyTableListener >& _rxListener )
496{
497 CopyTableAccessGuard aGuard( *this );
498 if ( _rxListener.is() )
499 m_aCopyTableListeners.removeInterface( _rxListener );
500}
501
502void SAL_CALL CopyTableWizard::setTitle( const OUString& _rTitle )
503{
504 CopyTableAccessGuard aGuard( *this );
505 CopyTableWizard_DialogBase::setTitle( _rTitle );
506}
507
508::sal_Int16 SAL_CALL CopyTableWizard::execute( )
509{
510 CopyTableAccessGuard aGuard( *this );
511
513 sal_Int16 nExecutionResult = CopyTableWizard_DialogBase::execute();
515 nExecutionResult = m_nOverrideExecutionResult;
516
517 return nExecutionResult;
518}
519
520OCopyTableWizard& CopyTableWizard::impl_getDialog_throw()
521{
522 OCopyTableWizard* pWizard = dynamic_cast<OCopyTableWizard*>(m_xDialog.get());
523 if ( !pWizard )
524 throw DisposedException( OUString(), *this );
525 return *pWizard;
526}
527
528void CopyTableWizard::impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const
529{
530 // primary key column
531 _rDialog.setCreatePrimaryKey( m_aPrimaryKeyName.IsPresent, m_aPrimaryKeyName.Value );
532 _rDialog.setUseHeaderLine(m_bUseHeaderLineAsColumnNames);
533
534 // everything else was passed at construction time already
535}
536
537void CopyTableWizard::impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog )
538{
539 m_aPrimaryKeyName.IsPresent = _rDialog.shouldCreatePrimaryKey();
540 if ( m_aPrimaryKeyName.IsPresent )
541 m_aPrimaryKeyName.Value = _rDialog.getPrimaryKeyName();
542 else
543 m_aPrimaryKeyName.Value.clear();
544
545 m_sDestinationTable = _rDialog.getName();
546
547 m_nOperation = _rDialog.getOperation();
548 m_bUseHeaderLineAsColumnNames = _rDialog.UseHeaderLine();
549}
550
551namespace
552{
562 Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XDataSource >& _rxDataSource, const Reference< XInteractionHandler >& _rFallback )
563 {
564 Reference< XInteractionHandler > xHandler( _rFallback );
565
566 // try to obtain the document model
567 Reference< XModel > xDocumentModel;
568 Reference< XDocumentDataSource > xDocDataSource( _rxDataSource, UNO_QUERY );
569 if ( xDocDataSource.is() )
570 xDocumentModel.set( xDocDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
571
572 // see whether the document model can provide a handler
573 if ( xDocumentModel.is() )
574 {
575 xHandler = ::comphelper::NamedValueCollection::getOrDefault( xDocumentModel->getArgs(), u"InteractionHandler", xHandler );
576 }
577
578 return xHandler;
579 }
589 Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XConnection >& _rxConnection, const Reference< XInteractionHandler >& _rFallback )
590 {
591 // try whether there is a data source which the connection belongs to
592 Reference< XDataSource > xDataSource;
593 Reference< XChild > xAsChild( _rxConnection, UNO_QUERY );
594 if ( xAsChild.is() )
595 xDataSource.set(xAsChild->getParent(), css::uno::UNO_QUERY);
596
597 if ( xDataSource.is() )
598 return lcl_getInteractionHandler_throw( xDataSource, _rFallback );
599
600 return _rFallback;
601 }
602}
603
604Reference< XPropertySet > CopyTableWizard::impl_ensureDataAccessDescriptor_throw(
605 const Sequence< Any >& _rAllArgs, const sal_Int16 _nArgPos, SharedConnection& _out_rxConnection,
606 Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
607{
608 Reference< XPropertySet > xDescriptor;
609 _rAllArgs[ _nArgPos ] >>= xDescriptor;
610
611 // the descriptor must be non-NULL, of course
612 bool bIsValid = xDescriptor.is();
613
614 // it must support the proper service
615 if ( bIsValid )
616 {
617 Reference< XServiceInfo > xSI( xDescriptor, UNO_QUERY );
618 bIsValid = ( xSI.is()
619 && xSI->supportsService( "com.sun.star.sdb.DataAccessDescriptor" ) );
620 }
621
622 // it must be able to provide a connection
623 if ( bIsValid )
624 {
625 _out_rxConnection = impl_extractConnection_throw( xDescriptor, _out_rxDocInteractionHandler );
626 bIsValid = _out_rxConnection.is();
627 }
628
629 if ( !bIsValid )
630 {
631 throw IllegalArgumentException(
632 DBA_RES( STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR ),
633 *const_cast< CopyTableWizard* >( this ),
634 _nArgPos + 1
635 );
636 }
637
638 return xDescriptor;
639}
640
641namespace
642{
643 bool lcl_hasNonEmptyStringValue_throw( const Reference< XPropertySet >& _rxDescriptor,
644 const Reference< XPropertySetInfo >& rxPSI, const OUString& _rPropertyName )
645 {
646 OUString sValue;
647 if ( rxPSI->hasPropertyByName( _rPropertyName ) )
648 {
649 OSL_VERIFY( _rxDescriptor->getPropertyValue( _rPropertyName ) >>= sValue );
650 }
651 return !sValue.isEmpty();
652 }
653}
654
655void CopyTableWizard::impl_checkForUnsupportedSettings_throw( const Reference< XPropertySet >& _rxSourceDescriptor ) const
656{
657 OSL_PRECOND( _rxSourceDescriptor.is(), "CopyTableWizard::impl_checkForUnsupportedSettings_throw: illegal argument!" );
658 Reference< XPropertySetInfo > xPSI( _rxSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
659 OUString sUnsupportedSetting;
660
661 const OUString aSettings[] = {
662 OUString(PROPERTY_FILTER), OUString(PROPERTY_ORDER), OUString(PROPERTY_HAVING_CLAUSE), OUString(PROPERTY_GROUP_BY)
663 };
664 for (const auto & aSetting : aSettings)
665 {
666 if ( lcl_hasNonEmptyStringValue_throw( _rxSourceDescriptor, xPSI, aSetting ) )
667 {
668 sUnsupportedSetting = aSetting;
669 break;
670 }
671 }
672
673 if ( !sUnsupportedSetting.isEmpty() )
674 {
675 OUString sMessage(
676 DBA_RES(STR_CTW_ERROR_UNSUPPORTED_SETTING).
677 replaceFirst("$name$", sUnsupportedSetting));
678 throw IllegalArgumentException(
679 sMessage,
680 *const_cast< CopyTableWizard* >( this ),
681 1
682 );
683 }
684
685}
686
687std::unique_ptr< ICopyTableSourceObject > CopyTableWizard::impl_extractSourceObject_throw( const Reference< XPropertySet >& _rxDescriptor, sal_Int32& _out_rCommandType ) const
688{
689 OSL_PRECOND( _rxDescriptor.is() && m_xSourceConnection.is(), "CopyTableWizard::impl_extractSourceObject_throw: illegal arguments!" );
690
691 Reference< XPropertySetInfo > xPSI( _rxDescriptor->getPropertySetInfo(), UNO_SET_THROW );
692 if ( !xPSI->hasPropertyByName( PROPERTY_COMMAND )
693 || !xPSI->hasPropertyByName( PROPERTY_COMMAND_TYPE )
694 )
695 throw IllegalArgumentException("Expecting a table or query specification.",
696 // TODO: resource
697 *const_cast< CopyTableWizard* >( this ), 1);
698
699 OUString sCommand;
700 _out_rCommandType = CommandType::COMMAND;
701 OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand );
702 OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= _out_rCommandType );
703
704 std::unique_ptr< ICopyTableSourceObject > pSourceObject;
705 Reference< XNameAccess > xContainer;
706 switch ( _out_rCommandType )
707 {
709 {
710 Reference< XTablesSupplier > xSuppTables( m_xSourceConnection.getTyped(), UNO_QUERY );
711 if ( xSuppTables.is() )
712 xContainer.set( xSuppTables->getTables(), UNO_SET_THROW );
713 }
714 break;
716 {
717 Reference< XQueriesSupplier > xSuppQueries( m_xSourceConnection.getTyped(), UNO_QUERY );
718 if ( xSuppQueries.is() )
719 xContainer.set( xSuppQueries->getQueries(), UNO_SET_THROW );
720 }
721 break;
722 default:
723 throw IllegalArgumentException(
724 DBA_RES( STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT ),
725 *const_cast< CopyTableWizard* >( this ),
726 1
727 );
728 }
729
730 if ( xContainer.is() )
731 {
732 pSourceObject.reset( new ObjectCopySource( m_xSourceConnection,
733 Reference< XPropertySet >( xContainer->getByName( sCommand ), UNO_QUERY_THROW ) ) );
734 }
735 else
736 {
737 // our source connection is an SDBC level connection only, not a SDBCX level one
738 // Which means it cannot provide the to-be-copied object as component.
739
740 if ( _out_rCommandType == CommandType::QUERY )
741 // we cannot copy a query if the connection cannot provide it ...
742 throw IllegalArgumentException(
743 DBA_RES( STR_CTW_ERROR_NO_QUERY ),
744 *const_cast< CopyTableWizard* >( this ),
745 1
746 );
747 pSourceObject.reset( new NamedTableCopySource( m_xSourceConnection, sCommand ) );
748 }
749
750 return pSourceObject;
751}
752
753void CopyTableWizard::impl_extractSourceResultSet_throw( const Reference< XPropertySet >& i_rDescriptor )
754{
755 Reference< XPropertySetInfo > xPSI( i_rDescriptor->getPropertySetInfo(), UNO_SET_THROW );
756
757 // extract relevant settings
758 if ( xPSI->hasPropertyByName( PROPERTY_RESULT_SET ) )
759 m_xSourceResultSet.set( i_rDescriptor->getPropertyValue( PROPERTY_RESULT_SET ), UNO_QUERY );
760
761 if ( xPSI->hasPropertyByName( PROPERTY_SELECTION ) )
762 OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_SELECTION ) >>= m_aSourceSelection );
763
764 if ( xPSI->hasPropertyByName( PROPERTY_BOOKMARK_SELECTION ) )
765 OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_BOOKMARK_SELECTION ) >>= m_bSourceSelectionBookmarks );
766
767 // sanity checks
768 const bool bHasResultSet = m_xSourceResultSet.is();
769 const bool bHasSelection = m_aSourceSelection.hasElements();
770 if ( bHasSelection && !bHasResultSet )
771 throw IllegalArgumentException("A result set is needed when specifying a selection to copy.",
772 // TODO: resource
773 *this, 1);
774
775 if ( bHasSelection && m_bSourceSelectionBookmarks )
776 {
777 Reference< XRowLocate > xRowLocate( m_xSourceResultSet, UNO_QUERY );
778 if ( !xRowLocate.is() )
779 {
780 ::dbtools::throwGenericSQLException(
781 DBA_RES(STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS),
782 *this
783 );
784 }
785 }
786}
787
788SharedConnection CopyTableWizard::impl_extractConnection_throw( const Reference< XPropertySet >& _rxDataSourceDescriptor,
789 Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
790{
791 SharedConnection xConnection;
792
793 OSL_PRECOND( _rxDataSourceDescriptor.is(), "CopyTableWizard::impl_extractConnection_throw: no descriptor!" );
794 if ( !_rxDataSourceDescriptor.is() )
795 return xConnection;
796
797 Reference< XInteractionHandler > xInteractionHandler;
798
799 do
800 {
801 Reference< XPropertySetInfo > xPSI( _rxDataSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
802
803 // if there's an ActiveConnection, use it
804 if ( xPSI->hasPropertyByName( PROPERTY_ACTIVE_CONNECTION ) )
805 {
806 Reference< XConnection > xPure;
807 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xPure );
808 xConnection.reset( xPure, SharedConnection::NoTakeOwnership );
809 }
810 if ( xConnection.is() )
811 {
812 xInteractionHandler = lcl_getInteractionHandler_throw( xConnection.getTyped(), m_xInteractionHandler );
813 SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" );
814 break;
815 }
816
817 // there could be a DataSourceName or a DatabaseLocation, describing the css.sdb.DataSource
818 OUString sDataSource, sDatabaseLocation;
819 if ( xPSI->hasPropertyByName( PROPERTY_DATASOURCENAME ) )
820 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sDataSource );
821 if ( xPSI->hasPropertyByName( PROPERTY_DATABASE_LOCATION ) )
822 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATABASE_LOCATION ) >>= sDatabaseLocation );
823
824 // need a DatabaseContext for loading the data source
825 Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create( m_xContext );
826 Reference< XDataSource > xDataSource;
827 if ( !sDataSource.isEmpty() )
828 xDataSource.set( xDatabaseContext->getByName( sDataSource ), UNO_QUERY_THROW );
829 if ( !xDataSource.is() && !sDatabaseLocation.isEmpty() )
830 xDataSource.set( xDatabaseContext->getByName( sDatabaseLocation ), UNO_QUERY_THROW );
831
832 if ( xDataSource.is() )
833 {
834 // first, try connecting with completion
835 xInteractionHandler = lcl_getInteractionHandler_throw( xDataSource, m_xInteractionHandler );
836 SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" );
837 if ( xInteractionHandler.is() )
838 {
839 Reference< XCompletedConnection > xInteractiveConnection( xDataSource, UNO_QUERY );
840 if ( xInteractiveConnection.is() )
841 xConnection.reset( xInteractiveConnection->connectWithCompletion( xInteractionHandler ), SharedConnection::TakeOwnership );
842 }
843
844 // interactively connecting was not successful or possible -> connect without interaction
845 if ( !xConnection.is() )
846 {
847 xConnection.reset( xDataSource->getConnection( OUString(), OUString() ), SharedConnection::TakeOwnership );
848 }
849 }
850
851 if ( xConnection.is() )
852 break;
853
854 // finally, there could be a ConnectionResource/ConnectionInfo
855 OUString sConnectionResource;
856 Sequence< PropertyValue > aConnectionInfo;
857 if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_RESOURCE ) )
858 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_RESOURCE ) >>= sConnectionResource );
859 if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_INFO ) )
860 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_INFO ) >>= aConnectionInfo );
861
862 Reference< XDriverManager > xDriverManager;
863 try {
864 xDriverManager.set( ConnectionPool::create( m_xContext ), UNO_QUERY_THROW );
865 } catch( const Exception& ) { }
866 if ( !xDriverManager.is() )
867 // no connection pool installed
868 xDriverManager.set( DriverManager::create( m_xContext ), UNO_QUERY_THROW );
869
870 if ( aConnectionInfo.hasElements() )
871 xConnection.set( xDriverManager->getConnectionWithInfo( sConnectionResource, aConnectionInfo ), UNO_SET_THROW );
872 else
873 xConnection.set( xDriverManager->getConnection( sConnectionResource ), UNO_SET_THROW );
874 }
875 while ( false );
876
877 if ( xInteractionHandler != m_xInteractionHandler )
878 _out_rxDocInteractionHandler = xInteractionHandler;
879
880 return xConnection;
881}
882
883::utl::SharedUNOComponent< XPreparedStatement > CopyTableWizard::impl_createSourceStatement_throw() const
884{
885 OSL_PRECOND( m_xSourceConnection.is(), "CopyTableWizard::impl_createSourceStatement_throw: illegal call!" );
886 if ( !m_xSourceConnection.is() )
887 throw RuntimeException( "CopyTableWizard::impl_createSourceStatement_throw: illegal call!", *const_cast< CopyTableWizard* >( this ));
888
890 switch ( m_nCommandType )
891 {
893 xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
894 break;
895
897 {
898 OUString sQueryCommand( m_pSourceObject->getSelectStatement() );
899 xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
900
901 // check whether we have to fill in parameter values
902 // create and fill a composer
903
904 Reference< XMultiServiceFactory > xFactory( m_xSourceConnection, UNO_QUERY );
906 if ( xFactory.is() )
907 // note: connections below the sdb-level are allowed to not support the XMultiServiceFactory interface
908 xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY );
909
910 if ( xComposer.is() )
911 {
912 xComposer->setQuery( sQueryCommand );
913
914 Reference< XParameters > xStatementParams( xStatement, UNO_QUERY );
915 OSL_ENSURE( xStatementParams.is(), "CopyTableWizard::impl_createSourceStatement_throw: no access to the statement's parameters!" );
916 // the statement should be a css.sdbc.PreparedStatement (this is what
917 // we created), and a prepared statement is required to support XParameters
918 if ( xStatementParams.is() )
919 {
920 OSL_ENSURE( m_xInteractionHandler.is(),
921 "CopyTableWizard::impl_createSourceStatement_throw: no interaction handler for the parameters request!" );
922 // we should always have an interaction handler - as last fallback, we create an own one in ::initialize
923
924 if ( m_xInteractionHandler.is() )
925 ::dbtools::askForParameters( xComposer, xStatementParams, m_xSourceConnection, m_xInteractionHandler );
926 }
927 }
928 }
929 break;
930
931 default:
932 // this should not have survived initialization phase
933 throw RuntimeException("No case matched, this should not have survived the initialization phase", *const_cast< CopyTableWizard* >( this ));
934 }
935
936 return xStatement;
937}
938
939namespace
940{
941 class ValueTransfer
942 {
943 public:
944 ValueTransfer( std::vector< sal_Int32 > _rColTypes,
945 const Reference< XRow >& _rxSource, const Reference< XParameters >& _rxDest )
946 :m_ColTypes( std::move(_rColTypes) )
947 ,m_xSource( _rxSource )
948 ,m_xDest( _rxDest )
949 {
950 }
951
952 template< typename VALUE_TYPE >
953 void transferValue( sal_Int32 _nSourcePos, sal_Int32 _nDestPos,
954 VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ),
955 void (SAL_CALL XParameters::*_pSetter)( sal_Int32, VALUE_TYPE ) )
956 {
957 VALUE_TYPE value( (m_xSource.get()->*_pGetter)( _nSourcePos ) );
958 if ( m_xSource->wasNull() )
959 m_xDest->setNull( _nDestPos, m_ColTypes[ _nSourcePos ] );
960 else
961 (m_xDest.get()->*_pSetter)( _nDestPos, value );
962 }
963
964 template< typename VALUE_TYPE >
965 void transferComplexValue( sal_Int32 _nSourcePos, sal_Int32 _nDestPos,
966 VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ),
967 void (SAL_CALL XParameters::*_pSetter)( sal_Int32, const VALUE_TYPE& ) )
968 {
969 const VALUE_TYPE value( (m_xSource.get()->*_pGetter)( _nSourcePos ) );
970 if ( m_xSource->wasNull() )
971 m_xDest->setNull( _nDestPos, m_ColTypes[ _nSourcePos ] );
972 else
973 (m_xDest.get()->*_pSetter)( _nDestPos, value );
974 }
975 private:
976 const std::vector< sal_Int32 > m_ColTypes;
977 const Reference< XRow > m_xSource;
978 const Reference< XParameters > m_xDest;
979 };
980}
981
982bool CopyTableWizard::impl_processCopyError_nothrow( const CopyTableRowEvent& _rEvent )
983{
984 try
985 {
987 while ( aIter.hasMoreElements() )
988 {
989 Reference< XCopyTableListener > xListener( aIter.next() );
990 sal_Int16 nListenerChoice = xListener->copyRowError( _rEvent );
991 switch ( nListenerChoice )
992 {
993 case CopyTableContinuation::Proceed: return true; // continue copying
994 case CopyTableContinuation::CallNextHandler: continue; // continue the loop, ask next listener
995 case CopyTableContinuation::Cancel: return false; // cancel copying
996 case CopyTableContinuation::AskUser: break; // stop asking the listeners, ask the user
997
998 default:
999 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_processCopyError_nothrow: invalid listener response!" );
1000 // ask next listener
1001 continue;
1002 }
1003 }
1004 }
1005 catch( const Exception& )
1006 {
1007 DBG_UNHANDLED_EXCEPTION("dbaccess");
1008 }
1009
1010 // no listener felt responsible for the error, or a listener told to ask the user
1011
1012 try
1013 {
1014 SQLContext aError;
1015 aError.Context = *this;
1016 aError.Message = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING);
1017
1018 ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error );
1019 if ( aInfo.isValid() )
1020 aError.NextException = _rEvent.Error;
1021 else
1022 {
1023 // a non-SQL exception happened
1024 Exception aException;
1025 OSL_VERIFY( _rEvent.Error >>= aException );
1026 SQLContext aContext;
1027 aContext.Context = aException.Context;
1028 aContext.Message = aException.Message;
1029 aContext.Details = _rEvent.Error.getValueTypeName();
1030 aError.NextException <<= aContext;
1031 }
1032
1033 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) );
1034
1035 ::rtl::Reference< ::comphelper::OInteractionApprove > xYes = new ::comphelper::OInteractionApprove;
1036 xRequest->addContinuation( xYes );
1037 xRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
1038
1039 OSL_ENSURE( m_xInteractionHandler.is(),
1040 "CopyTableWizard::impl_processCopyError_nothrow: we always should have an interaction handler!" );
1041 if ( m_xInteractionHandler.is() )
1042 m_xInteractionHandler->handle( xRequest );
1043
1044 if ( xYes->wasSelected() )
1045 // continue copying
1046 return true;
1047 }
1048 catch( const Exception& )
1049 {
1050 DBG_UNHANDLED_EXCEPTION("dbaccess");
1051 }
1052
1053 // cancel copying
1054 return false;
1055}
1056
1057void CopyTableWizard::impl_copyRows_throw( const Reference< XResultSet >& _rxSourceResultSet,
1058 const Reference< XPropertySet >& _rxDestTable )
1059{
1060 OSL_PRECOND( m_xDestConnection.is(), "CopyTableWizard::impl_copyRows_throw: illegal call!" );
1061 if ( !m_xDestConnection.is() )
1062 throw RuntimeException( "m_xDestConnection is set to null, CopyTableWizard::impl_copyRows_throw: illegal call!", *this );
1063
1064 Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
1065
1066 const OCopyTableWizard& rWizard = impl_getDialog_throw();
1067 ODatabaseExport::TPositions aColumnPositions = rWizard.GetColumnPositions();
1068 const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey();
1069
1070 Reference< XRow > xRow ( _rxSourceResultSet, UNO_QUERY_THROW );
1071 Reference< XRowLocate > xRowLocate ( _rxSourceResultSet, UNO_QUERY_THROW );
1072
1073 Reference< XResultSetMetaDataSupplier > xSuppResMeta( _rxSourceResultSet, UNO_QUERY_THROW );
1074 Reference< XResultSetMetaData> xMeta( xSuppResMeta->getMetaData() );
1075
1076 // we need a vector which all types
1077 sal_Int32 nCount = xMeta->getColumnCount();
1078 std::vector< sal_Int32 > aSourceColTypes;
1079 aSourceColTypes.reserve( nCount + 1 );
1080 aSourceColTypes.push_back( -1 ); // just to avoid an every time i-1 call
1081
1082 std::vector< sal_Int32 > aSourcePrec;
1083 aSourcePrec.reserve( nCount + 1 );
1084 aSourcePrec.push_back( -1 ); // just to avoid an every time i-1 call
1085
1086 for ( sal_Int32 k=1; k <= nCount; ++k )
1087 {
1088 aSourceColTypes.push_back( xMeta->getColumnType( k ) );
1089 aSourcePrec.push_back( xMeta->getPrecision( k ) );
1090 }
1091
1092 // now create, fill and execute the prepared statement
1093 Reference< XPreparedStatement > xStatement( ODatabaseExport::createPreparedStatement( xDestMetaData, _rxDestTable, aColumnPositions ), UNO_SET_THROW );
1094 Reference< XParameters > xStatementParams( xStatement, UNO_QUERY_THROW );
1095
1096 const bool bSelectedRecordsOnly = m_aSourceSelection.hasElements();
1097 const Any* pSelectedRow = m_aSourceSelection.getConstArray();
1098 const Any* pSelEnd = pSelectedRow + m_aSourceSelection.getLength();
1099
1100 sal_Int32 nRowCount = 0;
1101 bool bContinue = false;
1102
1103 CopyTableRowEvent aCopyEvent;
1104 aCopyEvent.Source = *this;
1105 aCopyEvent.SourceData = _rxSourceResultSet;
1106
1107 do // loop as long as there are more rows or the selection ends
1108 {
1109 bContinue = false;
1110 if ( bSelectedRecordsOnly )
1111 {
1112 if ( pSelectedRow != pSelEnd )
1113 {
1115 {
1116 bContinue = xRowLocate->moveToBookmark( *pSelectedRow );
1117 }
1118 else
1119 {
1120 sal_Int32 nPos = 0;
1121 OSL_VERIFY( *pSelectedRow >>= nPos );
1122 bContinue = _rxSourceResultSet->absolute( nPos );
1123 }
1124 ++pSelectedRow;
1125 }
1126 }
1127 else
1128 bContinue = _rxSourceResultSet->next();
1129
1130 if ( !bContinue )
1131 {
1132 break;
1133 }
1134
1135 ++nRowCount;
1136
1137 aCopyEvent.Error.clear();
1138 try
1139 {
1140 bool bInsertedPrimaryKey = false;
1141 // notify listeners
1142 m_aCopyTableListeners.notifyEach( &XCopyTableListener::copyingRow, aCopyEvent );
1143
1144 sal_Int32 nSourceColumn( 1 );
1145 ValueTransfer aTransfer( aSourceColTypes, xRow, xStatementParams );
1146
1147 for ( auto const& rColumnPos : aColumnPositions )
1148 {
1149 sal_Int32 nDestColumn = rColumnPos.first;
1150 if ( nDestColumn == COLUMN_POSITION_NOT_FOUND )
1151 {
1152 ++nSourceColumn;
1153 // otherwise we don't get the correct value when only the 2nd source column was selected
1154 continue;
1155 }
1156
1157 if ( bShouldCreatePrimaryKey && !bInsertedPrimaryKey )
1158 {
1159 xStatementParams->setInt( 1, nRowCount );
1160 ++nSourceColumn;
1161 bInsertedPrimaryKey = true;
1162 continue;
1163 }
1164
1165 if ( ( nSourceColumn < 1 ) || ( o3tl::make_unsigned(nSourceColumn) >= aSourceColTypes.size() ) )
1166 { // ( we have to check here against 1 because the parameters are 1 based)
1167 ::dbtools::throwSQLException("Internal error: invalid column type index.",
1168 ::dbtools::StandardSQLState::INVALID_DESCRIPTOR_INDEX, *this);
1169 }
1170
1171 switch ( aSourceColTypes[ nSourceColumn ] )
1172 {
1173 case DataType::DOUBLE:
1174 case DataType::REAL:
1175 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getDouble, &XParameters::setDouble );
1176 break;
1177
1178 case DataType::CHAR:
1179 case DataType::VARCHAR:
1180 case DataType::LONGVARCHAR:
1181 case DataType::DECIMAL:
1182 case DataType::NUMERIC:
1183 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getString, &XParameters::setString );
1184 break;
1185
1186 case DataType::BIGINT:
1187 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getLong, &XParameters::setLong );
1188 break;
1189
1190 case DataType::FLOAT:
1191 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getFloat, &XParameters::setFloat );
1192 break;
1193
1194 case DataType::LONGVARBINARY:
1195 case DataType::BINARY:
1196 case DataType::VARBINARY:
1197 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes );
1198 break;
1199
1200 case DataType::DATE:
1201 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getDate, &XParameters::setDate );
1202 break;
1203
1204 case DataType::TIME:
1205 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTime, &XParameters::setTime );
1206 break;
1207
1208 case DataType::TIMESTAMP:
1209 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTimestamp, &XParameters::setTimestamp );
1210 break;
1211
1212 case DataType::BIT:
1213 if ( aSourcePrec[nSourceColumn] > 1 )
1214 {
1215 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes );
1216 break;
1217 }
1218 [[fallthrough]];
1219 case DataType::BOOLEAN:
1220 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getBoolean, &XParameters::setBoolean );
1221 break;
1222
1223 case DataType::TINYINT:
1224 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getByte, &XParameters::setByte );
1225 break;
1226
1227 case DataType::SMALLINT:
1228 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getShort, &XParameters::setShort );
1229 break;
1230
1231 case DataType::INTEGER:
1232 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getInt, &XParameters::setInt );
1233 break;
1234
1235 case DataType::BLOB:
1236 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBlob, &XParameters::setBlob );
1237 break;
1238
1239 case DataType::CLOB:
1240 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getClob, &XParameters::setClob );
1241 break;
1242
1243 default:
1244 {
1245 OUString aMessage( DBA_RES( STR_CTW_UNSUPPORTED_COLUMN_TYPE ) );
1246
1247 aMessage = aMessage.replaceFirst( "$type$", OUString::number( aSourceColTypes[ nSourceColumn ] ) );
1248 aMessage = aMessage.replaceFirst( "$pos$", OUString::number( nSourceColumn ) );
1249
1250 ::dbtools::throwSQLException(
1251 aMessage,
1252 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
1253 *this
1254 );
1255 }
1256 }
1257 ++nSourceColumn;
1258 }
1259 xStatement->executeUpdate();
1260
1261 // notify listeners
1262 m_aCopyTableListeners.notifyEach( &XCopyTableListener::copiedRow, aCopyEvent );
1263 }
1264 catch( const Exception& )
1265 {
1266 TOOLS_WARN_EXCEPTION("dbaccess", "");
1267 aCopyEvent.Error = ::cppu::getCaughtException();
1268 }
1269
1270 if ( aCopyEvent.Error.hasValue() )
1271 bContinue = impl_processCopyError_nothrow( aCopyEvent );
1272 }
1273 while( bContinue );
1274}
1275
1276void CopyTableWizard::impl_doCopy_nothrow()
1277{
1278 Any aError;
1279
1280 try
1281 {
1282 OCopyTableWizard& rWizard( impl_getDialog_throw() );
1283
1284 weld::WaitObject aWO(rWizard.getDialog());
1285 Reference< XPropertySet > xTable;
1286
1287 switch ( rWizard.getOperation() )
1288 {
1289 case CopyTableOperation::CopyDefinitionOnly:
1290 case CopyTableOperation::CopyDefinitionAndData:
1291 {
1292 xTable = rWizard.createTable();
1293
1294 if( !xTable.is() )
1295 {
1296 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: createTable should throw here, shouldn't it?" );
1297 break;
1298 }
1299
1300 if( CopyTableOperation::CopyDefinitionOnly == rWizard.getOperation() )
1301 break;
1302
1303 [[fallthrough]];
1304 }
1305
1306 case CopyTableOperation::AppendData:
1307 {
1308 // note that the CopyDefinitionAndData case falls through to here.
1309 assert((rWizard.getOperation() == CopyTableOperation::CopyDefinitionAndData) ||
1310 (rWizard.getOperation() == CopyTableOperation::AppendData));
1311 assert((rWizard.getOperation() == CopyTableOperation::CopyDefinitionAndData) == xTable.is());
1312 if ( !xTable.is() )
1313 {
1314 assert(rWizard.getOperation() == CopyTableOperation::AppendData);
1315 xTable = rWizard.getTable();
1316 if ( !xTable.is() )
1317 {
1318 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: getTable should throw here, shouldn't it?" );
1319 break;
1320 }
1321 }
1322
1325
1326 if ( m_xSourceResultSet.is() )
1327 {
1329 }
1330 else
1331 {
1332 const bool bIsSameConnection = ( m_xSourceConnection.getTyped() == m_xDestConnection.getTyped() );
1333 const bool bIsTable = ( CommandType::TABLE == m_nCommandType );
1334 bool bDone = false;
1335 if ( bIsSameConnection && bIsTable )
1336 {
1337 // try whether the server supports copying via SQL
1338 try
1339 {
1340 m_xDestConnection->createStatement()->executeUpdate( impl_getServerSideCopyStatement_throw(xTable) );
1341 bDone = true;
1342 }
1343 catch( const Exception& )
1344 {
1345 // this is allowed.
1346 }
1347 }
1348
1349 if ( !bDone )
1350 {
1351 xSourceStatement.set( impl_createSourceStatement_throw(), UNO_SET_THROW );
1352 xSourceResultSet.set( xSourceStatement->executeQuery(), UNO_SET_THROW );
1353 }
1354 }
1355
1356 if ( xSourceResultSet.is() )
1357 impl_copyRows_throw( xSourceResultSet, xTable );
1358
1359 // tdf#119962
1360 const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
1361 OUString sDatabaseDest = xDestMetaData->getDatabaseProductName().toAsciiLowerCase();
1362 // If we created a new primary key, then it won't necessarily be an IDENTITY column
1363 const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey();
1364 if ( !bShouldCreatePrimaryKey && (sDatabaseDest.indexOf("firebird") != -1) )
1365 {
1366 const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, xTable, ::dbtools::EComposeRule::InDataManipulation, true );
1367
1368 OUString aSchema,aTable;
1369 xTable->getPropertyValue("SchemaName") >>= aSchema;
1370 xTable->getPropertyValue("Name") >>= aTable;
1371 Any aCatalog = xTable->getPropertyValue("CatalogName");
1372
1373 const Reference< XResultSet > xResultPKCL(xDestMetaData->getPrimaryKeys(aCatalog,aSchema,aTable));
1374 Reference< XRow > xRowPKCL(xResultPKCL, UNO_QUERY_THROW);
1375 OUString sPKCL;
1376 if ( xRowPKCL.is() )
1377 {
1378 if (xResultPKCL->next())
1379 {
1380 sPKCL = xRowPKCL->getString(4);
1381 }
1382 }
1383
1384 if (!sPKCL.isEmpty())
1385 {
1386 OUString strSql = "SELECT MAX(\"" + sPKCL + "\") FROM " + sComposedTableName;
1387
1388 Reference< XResultSet > xResultMAXNUM(m_xDestConnection->createStatement()->executeQuery(strSql));
1389 Reference< XRow > xRow(xResultMAXNUM, UNO_QUERY_THROW);
1390
1391 sal_Int64 maxVal = -1L;
1392 if (xResultMAXNUM->next())
1393 {
1394 maxVal = xRow->getLong(1);
1395 }
1396
1397 if (maxVal > 0L)
1398 {
1399 strSql = "ALTER TABLE " + sComposedTableName + " ALTER \"" + sPKCL + "\" RESTART WITH " + OUString::number(maxVal + 1);
1400
1401 m_xDestConnection->createStatement()->execute(strSql);
1402 }
1403 }
1404 }
1405 }
1406 break;
1407
1408 case CopyTableOperation::CreateAsView:
1409 rWizard.createView();
1410 break;
1411
1412 default:
1413 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: What operation, please?" );
1414 break;
1415 }
1416 }
1417 catch( const Exception& )
1418 {
1419 aError = ::cppu::getCaughtException();
1420 SAL_WARN("dbaccess", exceptionToString(aError));
1421
1422 // silence the error of the user cancelling the parameter's dialog
1423 SQLException aSQLError;
1424 if ( ( aError >>= aSQLError ) && ( aSQLError.ErrorCode == ::dbtools::ParameterInteractionCancelled ) )
1425 {
1426 aError.clear();
1428 }
1429 }
1430
1431 if ( aError.hasValue() && m_xInteractionHandler.is() )
1432 {
1433 try
1434 {
1435 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( aError ) );
1436 m_xInteractionHandler->handle( xRequest );
1437 }
1438 catch( const Exception& )
1439 {
1440 DBG_UNHANDLED_EXCEPTION("dbaccess");
1441 }
1442 }
1443}
1444
1445OUString CopyTableWizard::impl_getServerSideCopyStatement_throw(const Reference< XPropertySet >& _xTable)
1446{
1447 const Reference<XColumnsSupplier> xDestColsSup(_xTable,UNO_QUERY_THROW);
1448 const Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames();
1449 const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
1450 const OUString sQuote = xDestMetaData->getIdentifierQuoteString();
1451 OUStringBuffer sColumns;
1452 // 1st check if the columns matching
1453 for ( auto const & rColumnPositionPair : impl_getDialog_throw().GetColumnPositions() )
1454 {
1455 if ( COLUMN_POSITION_NOT_FOUND != rColumnPositionPair.second )
1456 {
1457 if ( !sColumns.isEmpty() )
1458 sColumns.append(",");
1459 sColumns.append(sQuote + aDestColumnNames[rColumnPositionPair.second - 1] + sQuote);
1460 }
1461 }
1462 const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, _xTable, ::dbtools::EComposeRule::InDataManipulation, true );
1463 OUString sSql("INSERT INTO " + sComposedTableName + " ( " + sColumns + " ) " + m_pSourceObject->getSelectStatement());
1464
1465 return sSql;
1466}
1467
1468void SAL_CALL CopyTableWizard::initialize( const Sequence< Any >& _rArguments )
1469{
1470 ::osl::MutexGuard aGuard( m_aMutex );
1471 if ( isInitialized() )
1472 throw AlreadyInitializedException( OUString(), *this );
1473
1474 sal_Int32 nArgCount( _rArguments.getLength() );
1475 if ( ( nArgCount != 2 ) && ( nArgCount != 3 ) )
1476 throw IllegalArgumentException(
1477 DBA_RES( STR_CTW_ILLEGAL_PARAMETER_COUNT ),
1478 *this,
1479 1
1480 );
1481
1482 try
1483 {
1484 if ( nArgCount == 3 )
1485 { // ->createWithInteractionHandler
1486 if ( !( _rArguments[2] >>= m_xInteractionHandler ) )
1487 throw IllegalArgumentException(
1488 DBA_RES( STR_CTW_ERROR_INVALID_INTERACTIONHANDLER ),
1489 *this,
1490 3
1491 );
1492 }
1493 if ( !m_xInteractionHandler.is() )
1494 m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr);
1495
1496 Reference< XInteractionHandler > xSourceDocHandler;
1497 Reference< XPropertySet > xSourceDescriptor( impl_ensureDataAccessDescriptor_throw( _rArguments, 0, m_xSourceConnection, xSourceDocHandler ) );
1498 impl_checkForUnsupportedSettings_throw( xSourceDescriptor );
1499 m_pSourceObject = impl_extractSourceObject_throw( xSourceDescriptor, m_nCommandType );
1500 impl_extractSourceResultSet_throw( xSourceDescriptor );
1501
1502 Reference< XInteractionHandler > xDestDocHandler;
1503 impl_ensureDataAccessDescriptor_throw( _rArguments, 1, m_xDestConnection, xDestDocHandler );
1504
1505 if ( xDestDocHandler.is() && !m_xInteractionHandler.is() )
1506 m_xInteractionHandler = xDestDocHandler;
1507
1508 Reference< XPropertySet > xInteractionHandler(m_xInteractionHandler, UNO_QUERY);
1509 if (xInteractionHandler.is())
1510 {
1511 Any aParentWindow(xInteractionHandler->getPropertyValue("ParentWindow"));
1512 aParentWindow >>= m_xParent;
1513 }
1514 }
1515 catch( const RuntimeException& ) { throw; }
1516 catch( const SQLException& ) { throw; }
1517 catch( const Exception& )
1518 {
1519 throw WrappedTargetException(
1520 DBA_RES( STR_CTW_ERROR_DURING_INITIALIZATION ),
1521 *this,
1522 ::cppu::getCaughtException()
1523 );
1524 }
1525}
1526
1527::cppu::IPropertyArrayHelper& CopyTableWizard::getInfoHelper()
1528{
1529 return *getArrayHelper();
1530}
1531
1532::cppu::IPropertyArrayHelper* CopyTableWizard::createArrayHelper( ) const
1533{
1534 Sequence< Property > aProps;
1535 describeProperties( aProps );
1536 return new ::cppu::OPropertyArrayHelper( aProps );
1537}
1538
1539std::unique_ptr<weld::DialogController> CopyTableWizard::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
1540{
1541 OSL_PRECOND( isInitialized(), "CopyTableWizard::createDialog: not initialized!" );
1542 // this should have been prevented in ::execute already
1543
1544 auto xWizard = std::make_unique<OCopyTableWizard>(
1551 m_xContext,
1553
1554 impl_attributesToDialog_nothrow(*xWizard);
1555
1556 return xWizard;
1557}
1558
1559void CopyTableWizard::executedDialog( sal_Int16 _nExecutionResult )
1560{
1561 CopyTableWizard_DialogBase::executedDialog( _nExecutionResult );
1562
1563 if ( _nExecutionResult == RET_OK )
1564 impl_doCopy_nothrow();
1565
1566 // do this after impl_doCopy_nothrow: The attributes may change during copying, for instance
1567 // if the user entered an unqualified table name
1568 impl_dialogToAttributes_nothrow( impl_getDialog_throw() );
1569}
1570
1571} // namespace dbaui
1572
1573extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1575 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
1576{
1577 return cppu::acquire(new ::dbaui::CopyTableWizard(context));
1578}
1579
1580/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define COLUMN_POSITION_NOT_FOUND
Definition: DExport.hxx:48
Reference< XExecutableDialog > m_xDialog
static weld::Window * GetFrameWeld(const css::uno::Reference< css::awt::XWindow > &rWindow)
VALUE_TYPE getOrDefault(const OUString &_rValueName, const VALUE_TYPE &_rDefault) const
css::uno::Reference< ListenerT > const & next()
const css::uno::Reference< INTERFACE > & getTyped() const
void reset(const css::uno::Reference< INTERFACE > &_rxComponent, AssignmentMode _eMode=TakeOwnership)
bool set(const css::uno::BaseReference &_rRef, css::uno::UnoReference_Query _query)
Any value
Optional< OUString > m_aPrimaryKeyName
const Reference< XParameters > m_xDest
const Reference< XRow > m_xSource
::comphelper::OInterfaceContainerHelper3< XCopyTableListener > m_aCopyTableListeners
sal_Int16 m_nOverrideExecutionResult
SharedConnection m_xSourceConnection
std::unique_ptr< ICopyTableSourceObject > m_pSourceObject
Reference< XComponentContext > m_xContext
const std::vector< sal_Int32 > m_ColTypes
OUString m_sDestinationTable
Reference< XInteractionHandler > m_xInteractionHandler
CopyTableWizard & m_rWizard
Reference< XResultSet > m_xSourceResultSet
bool m_bSourceSelectionBookmarks
Sequence< Any > m_aSourceSelection
sal_Int16 m_nOperation
SharedConnection m_xDestConnection
sal_Int32 m_nCommandType
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * org_openoffice_comp_dbu_CopyTableWizard_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
bool m_bUseHeaderLineAsColumnNames
#define DBA_RES(id)
int nCount
OString exceptionToString(const css::uno::Any &caught)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
Reference< XSingleServiceFactory > xFactory
const char sQuote[]
std::mutex m_aMutex
Sequence< PropertyValue > aArguments
Definition: intercept.cxx:88
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
@ Exception
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
::svt::OGenericUnoDialog CopyTableWizard_DialogBase
::utl::SharedUNOComponent< css::sdbc::XConnection > SharedConnection
Definition: commontypes.hxx:35
::cppu::ImplInheritanceHelper< CopyTableWizard_DialogBase, XCopyTableWizard > CopyTableWizard_Base
::osl::Mutex & getMutex()
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
DataType
OUString sMessage
Definition: sqlmessage.cxx:159
constexpr OUStringLiteral PROPERTY_COMMAND(u"Command")
constexpr OUStringLiteral PROPERTY_CONNECTION_RESOURCE(u"ConnectionResource")
constexpr OUStringLiteral PROPERTY_HAVING_CLAUSE(u"HavingClause")
constexpr OUStringLiteral PROPERTY_BOOKMARK_SELECTION(u"BookmarkSelection")
constexpr OUStringLiteral PROPERTY_CONNECTION_INFO(u"ConnectionInfo")
constexpr OUStringLiteral PROPERTY_RESULT_SET(u"ResultSet")
constexpr OUStringLiteral SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
Definition: strings.hxx:201
constexpr OUStringLiteral PROPERTY_GROUP_BY(u"GroupBy")
constexpr OUStringLiteral PROPERTY_SELECTION(u"Selection")
constexpr OUStringLiteral PROPERTY_FILTER(u"Filter")
constexpr OUStringLiteral PROPERTY_ACTIVE_CONNECTION(u"ActiveConnection")
constexpr OUStringLiteral PROPERTY_DATABASE_LOCATION(u"DatabaseLocation")
constexpr OUStringLiteral PROPERTY_DATASOURCENAME(u"DataSourceName")
constexpr OUStringLiteral PROPERTY_COMMAND_TYPE(u"CommandType")
constexpr OUStringLiteral PROPERTY_ORDER(u"Order")
unsigned char sal_Bool
RET_CANCEL