android: Update app icon to new startcenter icon
[LibreOffice.git] / dbaccess / source / ui / uno / copytablewizard.cxx
blob85000f2dc9f83eb1cacc4d175e98314678ed3363
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <strings.hrc>
22 #include <strings.hxx>
23 #include <core_resource.hxx>
24 #include <WCopyTable.hxx>
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>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/interaction.hxx>
56 #include <comphelper/namedvaluecollection.hxx>
57 #include <comphelper/proparrhlp.hxx>
58 #include <connectivity/dbexception.hxx>
59 #include <connectivity/dbtools.hxx>
60 #include <cppuhelper/exc_hlp.hxx>
61 #include <cppuhelper/implbase.hxx>
62 #include <comphelper/interfacecontainer3.hxx>
63 #include <o3tl/safeint.hxx>
64 #include <rtl/ustrbuf.hxx>
65 #include <sal/log.hxx>
66 #include <svtools/genericunodialog.hxx>
67 #include <toolkit/helper/vclunohelper.hxx>
68 #include <comphelper/diagnose_ex.hxx>
69 #include <unotools/sharedunocomponent.hxx>
70 #include <vcl/svapp.hxx>
72 namespace dbaui
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;
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;
134 typedef ::utl::SharedUNOComponent< XConnection > SharedConnection;
136 // CopyTableWizard
137 typedef ::svt::OGenericUnoDialog CopyTableWizard_DialogBase;
138 typedef ::cppu::ImplInheritanceHelper< CopyTableWizard_DialogBase
139 , XCopyTableWizard
140 > CopyTableWizard_Base;
142 namespace {
144 class CopyTableWizard
145 :public CopyTableWizard_Base
146 ,public ::comphelper::OPropertyArrayUsageHelper< CopyTableWizard >
148 public:
149 // XServiceInfo
150 virtual OUString SAL_CALL getImplementationName() override;
151 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
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;
165 // XCopyTableWizard::XExecutableDialog
166 virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
167 virtual ::sal_Int16 SAL_CALL execute( ) override;
169 // XInitialization
170 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
172 // XPropertySet
173 virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
174 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
176 // OPropertyArrayUsageHelper
177 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
179 public:
180 ::osl::Mutex& getMutex() { return m_aMutex; }
181 bool isInitialized() const { return m_xSourceConnection.is() && m_pSourceObject && m_xDestConnection.is(); }
183 explicit CopyTableWizard( const Reference< XComponentContext >& _rxORB );
184 virtual ~CopyTableWizard() override;
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;
191 private:
192 /// ensures our current attribute values are reflected in the dialog
193 void impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const;
195 /// ensures the current dialog settings are reflected in our attributes
196 void impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog );
198 /** returns our typed dialog
200 @throws css::uno::RuntimeException
201 if we don't have a dialog at the moment the method is called
203 OCopyTableWizard&
204 impl_getDialog_throw();
206 /** ensures the given argument sequence contains a valid data access descriptor at the given position
207 @param _rAllArgs
208 the arguments as passed to ->initialize
209 @param _nArgPos
210 the position within ->_rAllArgs which contains the data access descriptor
211 @param _out_rxConnection
212 will, upon successful return, contain the connection for the data source
213 @param _out_rxDocInteractionHandler
214 will, upon successful return, contain the interaction handler which could
215 be deduced from database document described by the descriptor, if any.
216 (It is possible that the descriptor does not allow to deduce a database document,
217 in which case <code>_out_rxDocInteractionHandler</code> will be <NULL/>.)
218 @return the data access descriptor
220 Reference< XPropertySet >
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;
228 /** extracts the source object (table or query) described by the given descriptor,
229 relative to m_xSourceConnection
231 std::unique_ptr< ICopyTableSourceObject >
232 impl_extractSourceObject_throw(
233 const Reference< XPropertySet >& _rxDescriptor,
234 sal_Int32& _out_rCommandType
235 ) const;
237 /** extracts the result set to copy records from, and the selection-related aspects, if any.
239 Effectively, this method extracts m_xSourceResultSet, m_aSourceSelection, and m_bSourceSelectionBookmarks.
241 If an inconsistent/insufficient sub set of those properties is present in the descriptor, and exception
242 is thrown.
244 void impl_extractSourceResultSet_throw(
245 const Reference< XPropertySet >& i_rDescriptor
248 /** checks whether the given copy source descriptor contains settings which are not
249 supported (yet)
251 Throws an IllegalArgumentException if the descriptor contains a valid setting, which is
252 not yet supported.
254 void impl_checkForUnsupportedSettings_throw(
255 const Reference< XPropertySet >& _rxSourceDescriptor ) const;
257 /** obtains the connection described by the given data access descriptor
259 If needed and possible, the method will ask the user, using the interaction
260 handler associated with the database described by the descriptor.
262 All errors are handled with the InteractionHandler associated with the data source,
263 if there is one. Else, they will be silenced (but asserted in non-product builds).
265 @param _rxDataSourceDescriptor
266 the data access descriptor describing the data source whose connection
267 should be obtained. Must not be <NULL/>.
268 @param _out_rxDocInteractionHandler
269 the interaction handler which could be deduced from the descriptor
271 @throws RuntimeException
272 if anything goes seriously wrong.
274 SharedConnection
275 impl_extractConnection_throw(
276 const Reference< XPropertySet >& _rxDataSourceDescriptor,
277 Reference< XInteractionHandler >& _out_rxDocInteractionHandler
278 ) const;
280 /** actually copies the table
282 This method is called after the dialog has been successfully executed.
284 void impl_doCopy_nothrow();
286 /** creates the INSERT INTO statement
287 @param _xTable The destination table.
289 OUString impl_getServerSideCopyStatement_throw( const Reference< XPropertySet >& _xTable );
291 /** creates the statement which, when executed, will produce the source data to copy
293 If the source object refers to a query which contains parameters, those parameters
294 are filled in, using an interaction handler.
296 ::utl::SharedUNOComponent< XPreparedStatement >
297 impl_createSourceStatement_throw() const;
299 /** copies the data rows from the given source result set to the given destination table
301 void impl_copyRows_throw(
302 const Reference< XResultSet >& _rxSourceResultSet,
303 const Reference< XPropertySet >& _rxDestTable
306 /** processes an error which occurred during copying
308 First, all listeners are ask. If a listener tells to cancel or continue copying, this is reported to the
309 method's caller. If a listener tells to ask the user, this is done, and the user's decision is
310 reported to the method's caller.
312 @return
313 <TRUE/> if and only if copying should be continued.
315 bool impl_processCopyError_nothrow(
316 const CopyTableRowEvent& _rEvent );
318 private:
319 Reference<XComponentContext> m_xContext;
321 // attributes
322 sal_Int16 m_nOperation;
323 OUString m_sDestinationTable;
324 Optional< OUString > m_aPrimaryKeyName;
325 bool m_bUseHeaderLineAsColumnNames;
327 // source
328 SharedConnection m_xSourceConnection;
329 sal_Int32 m_nCommandType;
330 std::unique_ptr< ICopyTableSourceObject >
331 m_pSourceObject;
332 Reference< XResultSet > m_xSourceResultSet;
333 Sequence< Any > m_aSourceSelection;
334 bool m_bSourceSelectionBookmarks;
336 // destination
337 SharedConnection m_xDestConnection;
339 // other
340 Reference< XInteractionHandler > m_xInteractionHandler;
341 ::comphelper::OInterfaceContainerHelper3<XCopyTableListener>
342 m_aCopyTableListeners;
343 sal_Int16 m_nOverrideExecutionResult;
346 // MethodGuard
347 class CopyTableAccessGuard
349 public:
350 explicit CopyTableAccessGuard( CopyTableWizard& _rWizard )
351 :m_rWizard( _rWizard )
353 m_rWizard.getMutex().acquire();
354 if ( !m_rWizard.isInitialized() )
355 throw NotInitializedException();
358 ~CopyTableAccessGuard()
360 m_rWizard.getMutex().release();
363 private:
364 CopyTableWizard& m_rWizard;
369 CopyTableWizard::CopyTableWizard( const Reference< XComponentContext >& _rxORB )
370 :CopyTableWizard_Base( _rxORB )
371 ,m_xContext( _rxORB )
372 ,m_nOperation( CopyTableOperation::CopyDefinitionAndData )
373 ,m_aPrimaryKeyName( false, "ID" )
374 ,m_bUseHeaderLineAsColumnNames( true )
375 ,m_nCommandType( CommandType::COMMAND )
376 ,m_bSourceSelectionBookmarks( true )
377 ,m_aCopyTableListeners( m_aMutex )
378 ,m_nOverrideExecutionResult( -1 )
382 CopyTableWizard::~CopyTableWizard()
384 acquire();
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"); }
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?
399 OUString SAL_CALL CopyTableWizard::getImplementationName()
401 return "org.openoffice.comp.dbu.CopyTableWizard";
404 css::uno::Sequence<OUString> SAL_CALL CopyTableWizard::getSupportedServiceNames()
406 return { "com.sun.star.sdb.application.CopyTableWizard" };
409 Reference< XPropertySetInfo > SAL_CALL CopyTableWizard::getPropertySetInfo()
411 Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
412 return xInfo;
415 ::sal_Int16 SAL_CALL CopyTableWizard::getOperation()
417 CopyTableAccessGuard aGuard( *this );
418 return m_nOperation;
421 void SAL_CALL CopyTableWizard::setOperation( ::sal_Int16 _operation )
423 CopyTableAccessGuard aGuard( *this );
425 if ( ( _operation != CopyTableOperation::CopyDefinitionAndData )
426 && ( _operation != CopyTableOperation::CopyDefinitionOnly )
427 && ( _operation != CopyTableOperation::CreateAsView )
428 && ( _operation != CopyTableOperation::AppendData )
430 throw IllegalArgumentException( OUString(), *this, 1 );
432 if ( ( _operation == CopyTableOperation::CreateAsView )
433 && !OCopyTableWizard::supportsViews( m_xDestConnection )
435 throw IllegalArgumentException(
436 DBA_RES( STR_CTW_NO_VIEWS_SUPPORT ),
437 *this,
441 m_nOperation = _operation;
444 OUString SAL_CALL CopyTableWizard::getDestinationTableName()
446 CopyTableAccessGuard aGuard( *this );
447 return m_sDestinationTable;
450 void SAL_CALL CopyTableWizard::setDestinationTableName( const OUString& _destinationTableName )
452 CopyTableAccessGuard aGuard( *this );
453 m_sDestinationTable = _destinationTableName;
456 Optional< OUString > SAL_CALL CopyTableWizard::getCreatePrimaryKey()
458 CopyTableAccessGuard aGuard( *this );
459 return m_aPrimaryKeyName;
462 void SAL_CALL CopyTableWizard::setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey )
464 CopyTableAccessGuard aGuard( *this );
466 if ( _newPrimaryKey.IsPresent && !OCopyTableWizard::supportsPrimaryKey( m_xDestConnection ) )
467 throw IllegalArgumentException(
468 DBA_RES( STR_CTW_NO_PRIMARY_KEY_SUPPORT ),
469 *this,
473 m_aPrimaryKeyName = _newPrimaryKey;
476 sal_Bool SAL_CALL CopyTableWizard::getUseHeaderLineAsColumnNames()
478 CopyTableAccessGuard aGuard( *this );
479 return m_bUseHeaderLineAsColumnNames;
482 void SAL_CALL CopyTableWizard::setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames )
484 CopyTableAccessGuard aGuard( *this );
485 m_bUseHeaderLineAsColumnNames = _bUseHeaderLineAsColumnNames;
488 void SAL_CALL CopyTableWizard::addCopyTableListener( const Reference< XCopyTableListener >& _rxListener )
490 CopyTableAccessGuard aGuard( *this );
491 if ( _rxListener.is() )
492 m_aCopyTableListeners.addInterface( _rxListener );
495 void SAL_CALL CopyTableWizard::removeCopyTableListener( const Reference< XCopyTableListener >& _rxListener )
497 CopyTableAccessGuard aGuard( *this );
498 if ( _rxListener.is() )
499 m_aCopyTableListeners.removeInterface( _rxListener );
502 void SAL_CALL CopyTableWizard::setTitle( const OUString& _rTitle )
504 CopyTableAccessGuard aGuard( *this );
505 CopyTableWizard_DialogBase::setTitle( _rTitle );
508 ::sal_Int16 SAL_CALL CopyTableWizard::execute( )
510 CopyTableAccessGuard aGuard( *this );
512 m_nOverrideExecutionResult = -1;
513 sal_Int16 nExecutionResult = CopyTableWizard_DialogBase::execute();
514 if ( m_nOverrideExecutionResult )
515 nExecutionResult = m_nOverrideExecutionResult;
517 return nExecutionResult;
520 OCopyTableWizard& CopyTableWizard::impl_getDialog_throw()
522 OCopyTableWizard* pWizard = dynamic_cast<OCopyTableWizard*>(m_xDialog.get());
523 if ( !pWizard )
524 throw DisposedException( OUString(), *this );
525 return *pWizard;
528 void CopyTableWizard::impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const
530 // primary key column
531 _rDialog.setCreatePrimaryKey( m_aPrimaryKeyName.IsPresent, m_aPrimaryKeyName.Value );
532 _rDialog.setUseHeaderLine(m_bUseHeaderLineAsColumnNames);
534 // everything else was passed at construction time already
537 void CopyTableWizard::impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog )
539 m_aPrimaryKeyName.IsPresent = _rDialog.shouldCreatePrimaryKey();
540 if ( m_aPrimaryKeyName.IsPresent )
541 m_aPrimaryKeyName.Value = _rDialog.getPrimaryKeyName();
542 else
543 m_aPrimaryKeyName.Value.clear();
545 m_sDestinationTable = _rDialog.getName();
547 m_nOperation = _rDialog.getOperation();
548 m_bUseHeaderLineAsColumnNames = _rDialog.UseHeaderLine();
551 namespace
553 /** tries to obtain the InteractionHandler associated with a given data source
555 If the data source is a sdb-level data source, it will have a DatabaseDocument associated
556 with it. This document may have an InteractionHandler used while loading it.
558 @throws RuntimeException
559 if it occurs during invoking any of the data source's methods, or if any of the involved
560 components violates its contract by not providing the required interfaces
562 Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XDataSource >& _rxDataSource, const Reference< XInteractionHandler >& _rFallback )
564 Reference< XInteractionHandler > xHandler( _rFallback );
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 );
572 // see whether the document model can provide a handler
573 if ( xDocumentModel.is() )
575 xHandler = ::comphelper::NamedValueCollection::getOrDefault( xDocumentModel->getArgs(), u"InteractionHandler", xHandler );
578 return xHandler;
580 /** tries to obtain the InteractionHandler associated with a given connection
582 If the connection belongs to a sdb-level data source, then this data source
583 is examined for an interaction handler. Else, <NULL/> is returned.
585 @throws RuntimeException
586 if it occurs during invoking any of the data source's methods, or if any of the involved
587 components violates its contract by not providing the required interfaces
589 Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XConnection >& _rxConnection, const Reference< XInteractionHandler >& _rFallback )
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);
597 if ( xDataSource.is() )
598 return lcl_getInteractionHandler_throw( xDataSource, _rFallback );
600 return _rFallback;
604 Reference< XPropertySet > CopyTableWizard::impl_ensureDataAccessDescriptor_throw(
605 const Sequence< Any >& _rAllArgs, const sal_Int16 _nArgPos, SharedConnection& _out_rxConnection,
606 Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
608 Reference< XPropertySet > xDescriptor;
609 _rAllArgs[ _nArgPos ] >>= xDescriptor;
611 // the descriptor must be non-NULL, of course
612 bool bIsValid = xDescriptor.is();
614 // it must support the proper service
615 if ( bIsValid )
617 Reference< XServiceInfo > xSI( xDescriptor, UNO_QUERY );
618 bIsValid = ( xSI.is()
619 && xSI->supportsService( "com.sun.star.sdb.DataAccessDescriptor" ) );
622 // it must be able to provide a connection
623 if ( bIsValid )
625 _out_rxConnection = impl_extractConnection_throw( xDescriptor, _out_rxDocInteractionHandler );
626 bIsValid = _out_rxConnection.is();
629 if ( !bIsValid )
631 throw IllegalArgumentException(
632 DBA_RES( STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR ),
633 *const_cast< CopyTableWizard* >( this ),
634 _nArgPos + 1
638 return xDescriptor;
641 namespace
643 bool lcl_hasNonEmptyStringValue_throw( const Reference< XPropertySet >& _rxDescriptor,
644 const Reference< XPropertySetInfo >& rxPSI, const OUString& _rPropertyName )
646 OUString sValue;
647 if ( rxPSI->hasPropertyByName( _rPropertyName ) )
649 OSL_VERIFY( _rxDescriptor->getPropertyValue( _rPropertyName ) >>= sValue );
651 return !sValue.isEmpty();
655 void CopyTableWizard::impl_checkForUnsupportedSettings_throw( const Reference< XPropertySet >& _rxSourceDescriptor ) const
657 OSL_PRECOND( _rxSourceDescriptor.is(), "CopyTableWizard::impl_checkForUnsupportedSettings_throw: illegal argument!" );
658 Reference< XPropertySetInfo > xPSI( _rxSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
659 OUString sUnsupportedSetting;
661 const OUString aSettings[] = {
662 OUString(PROPERTY_FILTER), OUString(PROPERTY_ORDER), OUString(PROPERTY_HAVING_CLAUSE), OUString(PROPERTY_GROUP_BY)
664 for (const auto & aSetting : aSettings)
666 if ( lcl_hasNonEmptyStringValue_throw( _rxSourceDescriptor, xPSI, aSetting ) )
668 sUnsupportedSetting = aSetting;
669 break;
673 if ( !sUnsupportedSetting.isEmpty() )
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 ),
687 std::unique_ptr< ICopyTableSourceObject > CopyTableWizard::impl_extractSourceObject_throw( const Reference< XPropertySet >& _rxDescriptor, sal_Int32& _out_rCommandType ) const
689 OSL_PRECOND( _rxDescriptor.is() && m_xSourceConnection.is(), "CopyTableWizard::impl_extractSourceObject_throw: illegal arguments!" );
691 Reference< XPropertySetInfo > xPSI( _rxDescriptor->getPropertySetInfo(), UNO_SET_THROW );
692 if ( !xPSI->hasPropertyByName( PROPERTY_COMMAND )
693 || !xPSI->hasPropertyByName( PROPERTY_COMMAND_TYPE )
695 throw IllegalArgumentException("Expecting a table or query specification.",
696 // TODO: resource
697 *const_cast< CopyTableWizard* >( this ), 1);
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 );
704 std::unique_ptr< ICopyTableSourceObject > pSourceObject;
705 Reference< XNameAccess > xContainer;
706 switch ( _out_rCommandType )
708 case CommandType::TABLE:
710 Reference< XTablesSupplier > xSuppTables( m_xSourceConnection.getTyped(), UNO_QUERY );
711 if ( xSuppTables.is() )
712 xContainer.set( xSuppTables->getTables(), UNO_SET_THROW );
714 break;
715 case CommandType::QUERY:
717 Reference< XQueriesSupplier > xSuppQueries( m_xSourceConnection.getTyped(), UNO_QUERY );
718 if ( xSuppQueries.is() )
719 xContainer.set( xSuppQueries->getQueries(), UNO_SET_THROW );
721 break;
722 default:
723 throw IllegalArgumentException(
724 DBA_RES( STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT ),
725 *const_cast< CopyTableWizard* >( this ),
730 if ( xContainer.is() )
732 pSourceObject.reset( new ObjectCopySource( m_xSourceConnection,
733 Reference< XPropertySet >( xContainer->getByName( sCommand ), UNO_QUERY_THROW ) ) );
735 else
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.
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 ),
747 pSourceObject.reset( new NamedTableCopySource( m_xSourceConnection, sCommand ) );
750 return pSourceObject;
753 void CopyTableWizard::impl_extractSourceResultSet_throw( const Reference< XPropertySet >& i_rDescriptor )
755 Reference< XPropertySetInfo > xPSI( i_rDescriptor->getPropertySetInfo(), UNO_SET_THROW );
757 // extract relevant settings
758 if ( xPSI->hasPropertyByName( PROPERTY_RESULT_SET ) )
759 m_xSourceResultSet.set( i_rDescriptor->getPropertyValue( PROPERTY_RESULT_SET ), UNO_QUERY );
761 if ( xPSI->hasPropertyByName( PROPERTY_SELECTION ) )
762 OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_SELECTION ) >>= m_aSourceSelection );
764 if ( xPSI->hasPropertyByName( PROPERTY_BOOKMARK_SELECTION ) )
765 OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_BOOKMARK_SELECTION ) >>= m_bSourceSelectionBookmarks );
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);
775 if ( bHasSelection && m_bSourceSelectionBookmarks )
777 Reference< XRowLocate > xRowLocate( m_xSourceResultSet, UNO_QUERY );
778 if ( !xRowLocate.is() )
780 ::dbtools::throwGenericSQLException(
781 DBA_RES(STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS),
782 *this
788 SharedConnection CopyTableWizard::impl_extractConnection_throw( const Reference< XPropertySet >& _rxDataSourceDescriptor,
789 Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
791 SharedConnection xConnection;
793 OSL_PRECOND( _rxDataSourceDescriptor.is(), "CopyTableWizard::impl_extractConnection_throw: no descriptor!" );
794 if ( !_rxDataSourceDescriptor.is() )
795 return xConnection;
797 Reference< XInteractionHandler > xInteractionHandler;
801 Reference< XPropertySetInfo > xPSI( _rxDataSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
803 // if there's an ActiveConnection, use it
804 if ( xPSI->hasPropertyByName( PROPERTY_ACTIVE_CONNECTION ) )
806 Reference< XConnection > xPure;
807 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xPure );
808 xConnection.reset( xPure, SharedConnection::NoTakeOwnership );
810 if ( xConnection.is() )
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;
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 );
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 );
832 if ( xDataSource.is() )
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() )
839 Reference< XCompletedConnection > xInteractiveConnection( xDataSource, UNO_QUERY );
840 if ( xInteractiveConnection.is() )
841 xConnection.reset( xInteractiveConnection->connectWithCompletion( xInteractionHandler ), SharedConnection::TakeOwnership );
844 // interactively connecting was not successful or possible -> connect without interaction
845 if ( !xConnection.is() )
847 xConnection.reset( xDataSource->getConnection( OUString(), OUString() ), SharedConnection::TakeOwnership );
851 if ( xConnection.is() )
852 break;
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 );
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 );
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 );
875 while ( false );
877 if ( xInteractionHandler != m_xInteractionHandler )
878 _out_rxDocInteractionHandler = xInteractionHandler;
880 return xConnection;
883 ::utl::SharedUNOComponent< XPreparedStatement > CopyTableWizard::impl_createSourceStatement_throw() const
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 ));
889 ::utl::SharedUNOComponent< XPreparedStatement > xStatement;
890 switch ( m_nCommandType )
892 case CommandType::TABLE:
893 xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
894 break;
896 case CommandType::QUERY:
898 OUString sQueryCommand( m_pSourceObject->getSelectStatement() );
899 xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
901 // check whether we have to fill in parameter values
902 // create and fill a composer
904 Reference< XMultiServiceFactory > xFactory( m_xSourceConnection, UNO_QUERY );
905 ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
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 );
910 if ( xComposer.is() )
912 xComposer->setQuery( sQueryCommand );
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() )
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
924 if ( m_xInteractionHandler.is() )
925 ::dbtools::askForParameters( xComposer, xStatementParams, m_xSourceConnection, m_xInteractionHandler );
929 break;
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 ));
936 return xStatement;
939 namespace
941 class ValueTransfer
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 )
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 ) )
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 );
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& ) )
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 );
975 private:
976 const std::vector< sal_Int32 > m_ColTypes;
977 const Reference< XRow > m_xSource;
978 const Reference< XParameters > m_xDest;
982 bool CopyTableWizard::impl_processCopyError_nothrow( const CopyTableRowEvent& _rEvent )
986 ::comphelper::OInterfaceIteratorHelper3 aIter( m_aCopyTableListeners );
987 while ( aIter.hasMoreElements() )
989 Reference< XCopyTableListener > xListener( aIter.next() );
990 sal_Int16 nListenerChoice = xListener->copyRowError( _rEvent );
991 switch ( nListenerChoice )
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
998 default:
999 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_processCopyError_nothrow: invalid listener response!" );
1000 // ask next listener
1001 continue;
1005 catch( const Exception& )
1007 DBG_UNHANDLED_EXCEPTION("dbaccess");
1010 // no listener felt responsible for the error, or a listener told to ask the user
1014 SQLContext aError;
1015 aError.Context = *this;
1016 aError.Message = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING);
1018 ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error );
1019 if ( aInfo.isValid() )
1020 aError.NextException = _rEvent.Error;
1021 else
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;
1033 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) );
1035 ::rtl::Reference< ::comphelper::OInteractionApprove > xYes = new ::comphelper::OInteractionApprove;
1036 xRequest->addContinuation( xYes );
1037 xRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
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 );
1044 if ( xYes->wasSelected() )
1045 // continue copying
1046 return true;
1048 catch( const Exception& )
1050 DBG_UNHANDLED_EXCEPTION("dbaccess");
1053 // cancel copying
1054 return false;
1057 void CopyTableWizard::impl_copyRows_throw( const Reference< XResultSet >& _rxSourceResultSet,
1058 const Reference< XPropertySet >& _rxDestTable )
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 );
1064 Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW );
1066 const OCopyTableWizard& rWizard = impl_getDialog_throw();
1067 ODatabaseExport::TPositions aColumnPositions = rWizard.GetColumnPositions();
1068 const bool bShouldCreatePrimaryKey = rWizard.shouldCreatePrimaryKey();
1070 Reference< XRow > xRow ( _rxSourceResultSet, UNO_QUERY_THROW );
1071 Reference< XRowLocate > xRowLocate ( _rxSourceResultSet, UNO_QUERY_THROW );
1073 Reference< XResultSetMetaDataSupplier > xSuppResMeta( _rxSourceResultSet, UNO_QUERY_THROW );
1074 Reference< XResultSetMetaData> xMeta( xSuppResMeta->getMetaData() );
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
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
1086 for ( sal_Int32 k=1; k <= nCount; ++k )
1088 aSourceColTypes.push_back( xMeta->getColumnType( k ) );
1089 aSourcePrec.push_back( xMeta->getPrecision( k ) );
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 );
1096 const bool bSelectedRecordsOnly = m_aSourceSelection.hasElements();
1097 const Any* pSelectedRow = m_aSourceSelection.getConstArray();
1098 const Any* pSelEnd = pSelectedRow + m_aSourceSelection.getLength();
1100 sal_Int32 nRowCount = 0;
1101 bool bContinue = false;
1103 CopyTableRowEvent aCopyEvent;
1104 aCopyEvent.Source = *this;
1105 aCopyEvent.SourceData = _rxSourceResultSet;
1107 do // loop as long as there are more rows or the selection ends
1109 bContinue = false;
1110 if ( bSelectedRecordsOnly )
1112 if ( pSelectedRow != pSelEnd )
1114 if ( m_bSourceSelectionBookmarks )
1116 bContinue = xRowLocate->moveToBookmark( *pSelectedRow );
1118 else
1120 sal_Int32 nPos = 0;
1121 OSL_VERIFY( *pSelectedRow >>= nPos );
1122 bContinue = _rxSourceResultSet->absolute( nPos );
1124 ++pSelectedRow;
1127 else
1128 bContinue = _rxSourceResultSet->next();
1130 if ( !bContinue )
1132 break;
1135 ++nRowCount;
1137 aCopyEvent.Error.clear();
1140 bool bInsertedPrimaryKey = false;
1141 // notify listeners
1142 m_aCopyTableListeners.notifyEach( &XCopyTableListener::copyingRow, aCopyEvent );
1144 sal_Int32 nSourceColumn( 1 );
1145 ValueTransfer aTransfer( aSourceColTypes, xRow, xStatementParams );
1147 for ( auto const& rColumnPos : aColumnPositions )
1149 sal_Int32 nDestColumn = rColumnPos.first;
1150 if ( nDestColumn == COLUMN_POSITION_NOT_FOUND )
1152 ++nSourceColumn;
1153 // otherwise we don't get the correct value when only the 2nd source column was selected
1154 continue;
1157 if ( bShouldCreatePrimaryKey && !bInsertedPrimaryKey )
1159 xStatementParams->setInt( 1, nRowCount );
1160 ++nSourceColumn;
1161 bInsertedPrimaryKey = true;
1162 continue;
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);
1171 switch ( aSourceColTypes[ nSourceColumn ] )
1173 case DataType::DOUBLE:
1174 case DataType::REAL:
1175 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getDouble, &XParameters::setDouble );
1176 break;
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;
1186 case DataType::BIGINT:
1187 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getLong, &XParameters::setLong );
1188 break;
1190 case DataType::FLOAT:
1191 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getFloat, &XParameters::setFloat );
1192 break;
1194 case DataType::LONGVARBINARY:
1195 case DataType::BINARY:
1196 case DataType::VARBINARY:
1197 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes );
1198 break;
1200 case DataType::DATE:
1201 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getDate, &XParameters::setDate );
1202 break;
1204 case DataType::TIME:
1205 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTime, &XParameters::setTime );
1206 break;
1208 case DataType::TIMESTAMP:
1209 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getTimestamp, &XParameters::setTimestamp );
1210 break;
1212 case DataType::BIT:
1213 if ( aSourcePrec[nSourceColumn] > 1 )
1215 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBytes, &XParameters::setBytes );
1216 break;
1218 [[fallthrough]];
1219 case DataType::BOOLEAN:
1220 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getBoolean, &XParameters::setBoolean );
1221 break;
1223 case DataType::TINYINT:
1224 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getByte, &XParameters::setByte );
1225 break;
1227 case DataType::SMALLINT:
1228 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getShort, &XParameters::setShort );
1229 break;
1231 case DataType::INTEGER:
1232 aTransfer.transferValue( nSourceColumn, nDestColumn, &XRow::getInt, &XParameters::setInt );
1233 break;
1235 case DataType::BLOB:
1236 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getBlob, &XParameters::setBlob );
1237 break;
1239 case DataType::CLOB:
1240 aTransfer.transferComplexValue( nSourceColumn, nDestColumn, &XRow::getClob, &XParameters::setClob );
1241 break;
1243 default:
1245 OUString aMessage( DBA_RES( STR_CTW_UNSUPPORTED_COLUMN_TYPE ) );
1247 aMessage = aMessage.replaceFirst( "$type$", OUString::number( aSourceColTypes[ nSourceColumn ] ) );
1248 aMessage = aMessage.replaceFirst( "$pos$", OUString::number( nSourceColumn ) );
1250 ::dbtools::throwSQLException(
1251 aMessage,
1252 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
1253 *this
1257 ++nSourceColumn;
1259 xStatement->executeUpdate();
1261 // notify listeners
1262 m_aCopyTableListeners.notifyEach( &XCopyTableListener::copiedRow, aCopyEvent );
1264 catch( const Exception& )
1266 TOOLS_WARN_EXCEPTION("dbaccess", "");
1267 aCopyEvent.Error = ::cppu::getCaughtException();
1270 if ( aCopyEvent.Error.hasValue() )
1271 bContinue = impl_processCopyError_nothrow( aCopyEvent );
1273 while( bContinue );
1276 void CopyTableWizard::impl_doCopy_nothrow()
1278 Any aError;
1282 OCopyTableWizard& rWizard( impl_getDialog_throw() );
1284 weld::WaitObject aWO(rWizard.getDialog());
1285 Reference< XPropertySet > xTable;
1287 switch ( rWizard.getOperation() )
1289 case CopyTableOperation::CopyDefinitionOnly:
1290 case CopyTableOperation::CopyDefinitionAndData:
1292 xTable = rWizard.createTable();
1294 if( !xTable.is() )
1296 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: createTable should throw here, shouldn't it?" );
1297 break;
1300 if( CopyTableOperation::CopyDefinitionOnly == rWizard.getOperation() )
1301 break;
1303 [[fallthrough]];
1306 case CopyTableOperation::AppendData:
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() )
1314 assert(rWizard.getOperation() == CopyTableOperation::AppendData);
1315 xTable = rWizard.getTable();
1316 if ( !xTable.is() )
1318 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: getTable should throw here, shouldn't it?" );
1319 break;
1323 ::utl::SharedUNOComponent< XPreparedStatement > xSourceStatement;
1324 ::utl::SharedUNOComponent< XResultSet > xSourceResultSet;
1326 if ( m_xSourceResultSet.is() )
1328 xSourceResultSet.reset( m_xSourceResultSet, ::utl::SharedUNOComponent< XResultSet >::NoTakeOwnership );
1330 else
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 )
1337 // try whether the server supports copying via SQL
1340 m_xDestConnection->createStatement()->executeUpdate( impl_getServerSideCopyStatement_throw(xTable) );
1341 bDone = true;
1343 catch( const Exception& )
1345 // this is allowed.
1349 if ( !bDone )
1351 xSourceStatement.set( impl_createSourceStatement_throw(), UNO_SET_THROW );
1352 xSourceResultSet.set( xSourceStatement->executeQuery(), UNO_SET_THROW );
1356 if ( xSourceResultSet.is() )
1357 impl_copyRows_throw( xSourceResultSet, xTable );
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) )
1366 const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, xTable, ::dbtools::EComposeRule::InDataManipulation, true );
1368 OUString aSchema,aTable;
1369 xTable->getPropertyValue("SchemaName") >>= aSchema;
1370 xTable->getPropertyValue("Name") >>= aTable;
1371 Any aCatalog = xTable->getPropertyValue("CatalogName");
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() )
1378 if (xResultPKCL->next())
1380 sPKCL = xRowPKCL->getString(4);
1384 if (!sPKCL.isEmpty())
1386 OUString strSql = "SELECT MAX(\"" + sPKCL + "\") FROM " + sComposedTableName;
1388 Reference< XResultSet > xResultMAXNUM(m_xDestConnection->createStatement()->executeQuery(strSql));
1389 Reference< XRow > xRow(xResultMAXNUM, UNO_QUERY_THROW);
1391 sal_Int64 maxVal = -1L;
1392 if (xResultMAXNUM->next())
1394 maxVal = xRow->getLong(1);
1397 if (maxVal > 0L)
1399 strSql = "ALTER TABLE " + sComposedTableName + " ALTER \"" + sPKCL + "\" RESTART WITH " + OUString::number(maxVal + 1);
1401 m_xDestConnection->createStatement()->execute(strSql);
1406 break;
1408 case CopyTableOperation::CreateAsView:
1409 rWizard.createView();
1410 break;
1412 default:
1413 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: What operation, please?" );
1414 break;
1417 catch( const Exception& )
1419 aError = ::cppu::getCaughtException();
1420 SAL_WARN("dbaccess", exceptionToString(aError));
1422 // silence the error of the user cancelling the parameter's dialog
1423 SQLException aSQLError;
1424 if ( ( aError >>= aSQLError ) && ( aSQLError.ErrorCode == ::dbtools::ParameterInteractionCancelled ) )
1426 aError.clear();
1427 m_nOverrideExecutionResult = RET_CANCEL;
1431 if ( aError.hasValue() && m_xInteractionHandler.is() )
1435 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( aError ) );
1436 m_xInteractionHandler->handle( xRequest );
1438 catch( const Exception& )
1440 DBG_UNHANDLED_EXCEPTION("dbaccess");
1445 OUString CopyTableWizard::impl_getServerSideCopyStatement_throw(const Reference< XPropertySet >& _xTable)
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() )
1455 if ( COLUMN_POSITION_NOT_FOUND != rColumnPositionPair.second )
1457 if ( !sColumns.isEmpty() )
1458 sColumns.append(",");
1459 sColumns.append(sQuote + aDestColumnNames[rColumnPositionPair.second - 1] + sQuote);
1462 const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, _xTable, ::dbtools::EComposeRule::InDataManipulation, true );
1463 OUString sSql("INSERT INTO " + sComposedTableName + " ( " + sColumns + " ) " + m_pSourceObject->getSelectStatement());
1465 return sSql;
1468 void SAL_CALL CopyTableWizard::initialize( const Sequence< Any >& _rArguments )
1470 ::osl::MutexGuard aGuard( m_aMutex );
1471 if ( isInitialized() )
1472 throw AlreadyInitializedException( OUString(), *this );
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,
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,
1493 if ( !m_xInteractionHandler.is() )
1494 m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr);
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 );
1502 Reference< XInteractionHandler > xDestDocHandler;
1503 impl_ensureDataAccessDescriptor_throw( _rArguments, 1, m_xDestConnection, xDestDocHandler );
1505 if ( xDestDocHandler.is() && !m_xInteractionHandler.is() )
1506 m_xInteractionHandler = xDestDocHandler;
1508 Reference< XPropertySet > xInteractionHandler(m_xInteractionHandler, UNO_QUERY);
1509 if (xInteractionHandler.is())
1511 Any aParentWindow(xInteractionHandler->getPropertyValue("ParentWindow"));
1512 aParentWindow >>= m_xParent;
1515 catch( const RuntimeException& ) { throw; }
1516 catch( const SQLException& ) { throw; }
1517 catch( const Exception& )
1519 throw WrappedTargetException(
1520 DBA_RES( STR_CTW_ERROR_DURING_INITIALIZATION ),
1521 *this,
1522 ::cppu::getCaughtException()
1527 ::cppu::IPropertyArrayHelper& CopyTableWizard::getInfoHelper()
1529 return *getArrayHelper();
1532 ::cppu::IPropertyArrayHelper* CopyTableWizard::createArrayHelper( ) const
1534 Sequence< Property > aProps;
1535 describeProperties( aProps );
1536 return new ::cppu::OPropertyArrayHelper( aProps );
1539 std::unique_ptr<weld::DialogController> CopyTableWizard::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent)
1541 OSL_PRECOND( isInitialized(), "CopyTableWizard::createDialog: not initialized!" );
1542 // this should have been prevented in ::execute already
1544 auto xWizard = std::make_unique<OCopyTableWizard>(
1545 Application::GetFrameWeld(rParent),
1546 m_sDestinationTable,
1547 m_nOperation,
1548 *m_pSourceObject,
1549 m_xSourceConnection.getTyped(),
1550 m_xDestConnection.getTyped(),
1551 m_xContext,
1552 m_xInteractionHandler);
1554 impl_attributesToDialog_nothrow(*xWizard);
1556 return xWizard;
1559 void CopyTableWizard::executedDialog( sal_Int16 _nExecutionResult )
1561 CopyTableWizard_DialogBase::executedDialog( _nExecutionResult );
1563 if ( _nExecutionResult == RET_OK )
1564 impl_doCopy_nothrow();
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() );
1571 } // namespace dbaui
1573 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1574 org_openoffice_comp_dbu_CopyTableWizard_get_implementation(
1575 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
1577 return cppu::acquire(new ::dbaui::CopyTableWizard(context));
1580 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */