build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / dbaccess / source / ui / uno / copytablewizard.cxx
blob31f89eb4394d6af1490eb1a89f38a248b714d90b
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 "dbu_reghelper.hxx"
21 #include "dbu_resource.hrc"
22 #include "dbu_uno.hrc"
23 #include "dbustrings.hrc"
24 #include "moduledbu.hxx"
25 #include "sqlmessage.hxx"
26 #include "uiservices.hxx"
27 #include "WCopyTable.hxx"
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/sdb/application/XCopyTableWizard.hpp>
31 #include <com/sun/star/sdb/application/CopyTableContinuation.hpp>
32 #include <com/sun/star/sdb/application/CopyTableOperation.hpp>
33 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
34 #include <com/sun/star/lang/NotInitializedException.hpp>
35 #include <com/sun/star/sdbc/XDataSource.hpp>
36 #include <com/sun/star/sdbc/DataType.hpp>
37 #include <com/sun/star/container/XNameAccess.hpp>
38 #include <com/sun/star/container/XChild.hpp>
39 #include <com/sun/star/task/InteractionHandler.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
41 #include <com/sun/star/sdb/DatabaseContext.hpp>
42 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
43 #include <com/sun/star/sdb/XCompletedConnection.hpp>
44 #include <com/sun/star/sdb/CommandType.hpp>
45 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
46 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
47 #include <com/sun/star/lang/DisposedException.hpp>
48 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
49 #include <com/sun/star/sdbc/XParameters.hpp>
50 #include <com/sun/star/sdbc/XRow.hpp>
51 #include <com/sun/star/sdbcx/XRowLocate.hpp>
52 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
53 #include <com/sun/star/sdb/SQLContext.hpp>
54 #include <com/sun/star/sdbc/DriverManager.hpp>
55 #include <com/sun/star/sdbc/ConnectionPool.hpp>
57 #include <comphelper/processfactory.hxx>
58 #include <comphelper/interaction.hxx>
59 #include <comphelper/namedvaluecollection.hxx>
60 #include <comphelper/proparrhlp.hxx>
61 #include <connectivity/dbexception.hxx>
62 #include <connectivity/dbtools.hxx>
63 #include <cppuhelper/exc_hlp.hxx>
64 #include <cppuhelper/implbase.hxx>
65 #include <comphelper/interfacecontainer2.hxx>
66 #include <rtl/ustrbuf.hxx>
67 #include <svtools/genericunodialog.hxx>
68 #include <tools/diagnose_ex.h>
69 #include <unotools/sharedunocomponent.hxx>
70 #include <vcl/msgbox.hxx>
71 #include <vcl/waitobj.hxx>
73 namespace dbaui
76 using ::com::sun::star::uno::Reference;
77 using ::com::sun::star::uno::XInterface;
78 using ::com::sun::star::uno::UNO_QUERY;
79 using ::com::sun::star::uno::UNO_QUERY_THROW;
80 using ::com::sun::star::uno::UNO_SET_THROW;
81 using ::com::sun::star::uno::Exception;
82 using ::com::sun::star::uno::RuntimeException;
83 using ::com::sun::star::uno::Any;
84 using ::com::sun::star::uno::makeAny;
85 using ::com::sun::star::uno::Sequence;
86 using ::com::sun::star::uno::XComponentContext;
87 using ::com::sun::star::beans::XPropertySetInfo;
88 using ::com::sun::star::lang::XMultiServiceFactory;
89 using ::com::sun::star::beans::Property;
90 using ::com::sun::star::sdb::application::XCopyTableWizard;
91 using ::com::sun::star::sdb::application::XCopyTableListener;
92 using ::com::sun::star::sdb::application::CopyTableRowEvent;
93 using ::com::sun::star::beans::Optional;
94 using ::com::sun::star::lang::IllegalArgumentException;
95 using ::com::sun::star::ucb::AlreadyInitializedException;
96 using ::com::sun::star::beans::XPropertySet;
97 using ::com::sun::star::lang::NotInitializedException;
98 using ::com::sun::star::lang::XServiceInfo;
99 using ::com::sun::star::sdbc::XConnection;
100 using ::com::sun::star::sdbc::XDataSource;
101 using ::com::sun::star::container::XNameAccess;
102 using ::com::sun::star::container::XChild;
103 using ::com::sun::star::task::InteractionHandler;
104 using ::com::sun::star::task::XInteractionHandler;
105 using ::com::sun::star::frame::XModel;
106 using ::com::sun::star::sdb::DatabaseContext;
107 using ::com::sun::star::sdb::XDatabaseContext;
108 using ::com::sun::star::sdb::XDocumentDataSource;
109 using ::com::sun::star::sdb::XCompletedConnection;
110 using ::com::sun::star::lang::WrappedTargetException;
111 using ::com::sun::star::sdbcx::XTablesSupplier;
112 using ::com::sun::star::sdb::XQueriesSupplier;
113 using ::com::sun::star::lang::DisposedException;
114 using ::com::sun::star::sdbc::XPreparedStatement;
115 using ::com::sun::star::sdb::XSingleSelectQueryComposer;
116 using ::com::sun::star::sdbc::XDatabaseMetaData;
117 using ::com::sun::star::sdbcx::XColumnsSupplier;
118 using ::com::sun::star::sdbc::XParameters;
119 using ::com::sun::star::sdbc::XResultSet;
120 using ::com::sun::star::sdbc::XRow;
121 using ::com::sun::star::sdbcx::XRowLocate;
122 using ::com::sun::star::sdbc::XResultSetMetaDataSupplier;
123 using ::com::sun::star::sdbc::XResultSetMetaData;
124 using ::com::sun::star::sdbc::SQLException;
125 using ::com::sun::star::sdb::SQLContext;
126 using ::com::sun::star::sdbc::ConnectionPool;
127 using ::com::sun::star::sdbc::XDriverManager;
128 using ::com::sun::star::sdbc::DriverManager;
129 using ::com::sun::star::beans::PropertyValue;
131 namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
132 namespace CopyTableContinuation = ::com::sun::star::sdb::application::CopyTableContinuation;
133 namespace CommandType = ::com::sun::star::sdb::CommandType;
134 namespace DataType = ::com::sun::star::sdbc::DataType;
136 typedef ::utl::SharedUNOComponent< XConnection > SharedConnection;
138 // CopyTableWizard
139 typedef ::svt::OGenericUnoDialog CopyTableWizard_DialogBase;
140 typedef ::cppu::ImplInheritanceHelper< CopyTableWizard_DialogBase
141 , XCopyTableWizard
142 > CopyTableWizard_Base;
143 class CopyTableWizard
144 :public CopyTableWizard_Base
145 ,public ::comphelper::OPropertyArrayUsageHelper< CopyTableWizard >
147 public:
148 // XServiceInfo
149 virtual OUString SAL_CALL getImplementationName() throw(RuntimeException, std::exception) override;
150 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() throw(RuntimeException, std::exception) override;
152 // XServiceInfo - static methods
153 /// @throws RuntimeException
154 static Sequence< OUString > getSupportedServiceNames_Static() throw( RuntimeException );
155 /// @throws RuntimeException
156 static OUString getImplementationName_Static() throw( RuntimeException );
157 static Reference< XInterface > Create( const Reference< XMultiServiceFactory >& );
159 // XCopyTableWizard
160 virtual ::sal_Int16 SAL_CALL getOperation() throw (RuntimeException, std::exception) override;
161 virtual void SAL_CALL setOperation( ::sal_Int16 _operation ) throw (IllegalArgumentException, RuntimeException, std::exception) override;
162 virtual OUString SAL_CALL getDestinationTableName() throw (RuntimeException, std::exception) override;
163 virtual void SAL_CALL setDestinationTableName( const OUString& _destinationTableName ) throw (RuntimeException, std::exception) override;
164 virtual Optional< OUString > SAL_CALL getCreatePrimaryKey() throw (RuntimeException, std::exception) override;
165 virtual void SAL_CALL setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey ) throw (IllegalArgumentException, SQLException, RuntimeException, std::exception) override;
166 virtual sal_Bool SAL_CALL getUseHeaderLineAsColumnNames() throw (RuntimeException, std::exception) override;
167 virtual void SAL_CALL setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames ) throw (RuntimeException, std::exception) override;
168 virtual void SAL_CALL addCopyTableListener( const Reference< XCopyTableListener >& Listener ) throw (RuntimeException, std::exception) override;
169 virtual void SAL_CALL removeCopyTableListener( const Reference< XCopyTableListener >& Listener ) throw (RuntimeException, std::exception) override;
171 // XCopyTableWizard::XExecutableDialog
172 virtual void SAL_CALL setTitle( const OUString& aTitle ) throw (RuntimeException, std::exception) override;
173 virtual ::sal_Int16 SAL_CALL execute( ) throw (RuntimeException, std::exception) override;
175 // XInitialization
176 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException, std::exception) override;
178 // XPropertySet
179 virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() throw(RuntimeException, std::exception) override;
180 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
182 // OPropertyArrayUsageHelper
183 virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
185 public:
186 ::osl::Mutex& getMutex() { return m_aMutex; }
187 bool isInitialized() const { return m_xSourceConnection.is() && m_pSourceObject.get() && m_xDestConnection.is(); }
189 protected:
190 explicit CopyTableWizard( const Reference< XComponentContext >& _rxORB );
191 virtual ~CopyTableWizard() override;
193 // OGenericUnoDialog overridables
194 virtual VclPtr<Dialog> createDialog( vcl::Window* _pParent ) override;
195 virtual void executedDialog( sal_Int16 _nExecutionResult ) override;
197 private:
198 /// ensures our current attribute values are reflected in the dialog
199 void impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const;
201 /// ensures the current dialog settings are reflected in our attributes
202 void impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog );
204 /** returns our typed dialog
206 @throws css::uno::RuntimeException
207 if we don't have a dialog at the moment the method is called
209 OCopyTableWizard&
210 impl_getDialog_throw();
212 /** ensures the given argument sequence contains a valid data access descriptor at the given position
213 @param _rAllArgs
214 the arguments as passed to ->initialize
215 @param _nArgPos
216 the position within ->_rAllArgs which contains the data access descriptor
217 @param _out_rxConnection
218 will, upon successful return, contain the connection for the data source
219 @param _out_rxDocInteractionHandler
220 will, upon successful return, contain the interaction handler which could
221 be deduced from database document described by the descriptor, if any.
222 (It is possible that the descriptor does not allow to deduce a database document,
223 in which case <code>_out_rxDocInteractionHandler</code> will be <NULL/>.)
224 @return the data access descriptor
226 Reference< XPropertySet >
227 impl_ensureDataAccessDescriptor_throw(
228 const Sequence< Any >& _rAllArgs,
229 const sal_Int16 _nArgPos,
230 SharedConnection& _out_rxConnection,
231 Reference< XInteractionHandler >& _out_rxDocInteractionHandler
232 ) const;
234 /** extracts the source object (table or query) described by the given descriptor,
235 relative to m_xSourceConnection
237 ::std::unique_ptr< ICopyTableSourceObject >
238 impl_extractSourceObject_throw(
239 const Reference< XPropertySet >& _rxDescriptor,
240 sal_Int32& _out_rCommandType
241 ) const;
243 /** extracts the result set to copy records from, and the selection-related aspects, if any.
245 Effectively, this method extracts m_xSourceResultSet, m_aSourceSelection, and m_bSourceSelectionBookmarks.
247 If an inconsistent/insufficient sub set of those properties is present in the descriptor, and exception
248 is thrown.
250 void impl_extractSourceResultSet_throw(
251 const Reference< XPropertySet >& i_rDescriptor
254 /** checks whether the given copy source descriptor contains settings which are not
255 supported (yet)
257 Throws an IllegalArgumentException if the descriptor contains a valid setting, which is
258 not yet supported.
260 void impl_checkForUnsupportedSettings_throw(
261 const Reference< XPropertySet >& _rxSourceDescriptor ) const;
263 /** obtaines the connection described by the given data access descriptor
265 If needed and possible, the method will ask the user, using the interaction
266 handler associated with the database described by the descriptor.
268 All errors are handled with the InteractionHandler associated with the data source,
269 if there is one. Else, they will be silenced (but asserted in non-product builds).
271 @param _rxDataSourceDescriptor
272 the data access descriptor describing the data source whose connection
273 should be obtained. Must not be <NULL/>.
274 @param _out_rxDocInteractionHandler
275 the interaction handler which could be deduced from the descriptor
277 @throws RuntimeException
278 if anything goes seriously wrong.
280 SharedConnection
281 impl_extractConnection_throw(
282 const Reference< XPropertySet >& _rxDataSourceDescriptor,
283 Reference< XInteractionHandler >& _out_rxDocInteractionHandler
284 ) const;
286 /** actually copies the table
288 This method is called after the dialog has been successfully executed.
290 void impl_doCopy_nothrow();
292 /** creates the INSERT INTO statement
293 @param _xTable The destination table.
295 OUString impl_getServerSideCopyStatement_throw( const Reference< XPropertySet >& _xTable );
297 /** creates the statement which, when executed, will produce the source data to copy
299 If the source object refers to a query which contains parameters, those parameters
300 are filled in, using an interaction handler.
302 ::utl::SharedUNOComponent< XPreparedStatement >
303 impl_createSourceStatement_throw() const;
305 /** copies the data rows from the given source result set to the given destination table
307 void impl_copyRows_throw(
308 const Reference< XResultSet >& _rxSourceResultSet,
309 const Reference< XPropertySet >& _rxDestTable
312 /** processes an error which occurred during copying
314 First, all listeners are ask. If a listener tells to cancel or continue copying, this is reported to the
315 method's caller. If a listener tells to ask the user, this is done, and the user's decision is
316 reported to the method's caller.
318 @return
319 <TRUE/> if and only if copying should be continued.
321 bool impl_processCopyError_nothrow(
322 const CopyTableRowEvent& _rEvent );
324 private:
325 Reference<XComponentContext> m_xContext;
327 // attributes
328 sal_Int16 m_nOperation;
329 OUString m_sDestinationTable;
330 Optional< OUString > m_aPrimaryKeyName;
331 bool m_bUseHeaderLineAsColumnNames;
333 // source
334 SharedConnection m_xSourceConnection;
335 sal_Int32 m_nCommandType;
336 ::std::unique_ptr< ICopyTableSourceObject >
337 m_pSourceObject;
338 Reference< XResultSet > m_xSourceResultSet;
339 Sequence< Any > m_aSourceSelection;
340 bool m_bSourceSelectionBookmarks;
342 // destination
343 SharedConnection m_xDestConnection;
345 // other
346 Reference< XInteractionHandler > m_xInteractionHandler;
347 ::comphelper::OInterfaceContainerHelper2
348 m_aCopyTableListeners;
349 sal_Int16 m_nOverrideExecutionResult;
352 // MethodGuard
353 class CopyTableAccessGuard
355 public:
356 explicit CopyTableAccessGuard( CopyTableWizard& _rWizard )
357 :m_rWizard( _rWizard )
359 m_rWizard.getMutex().acquire();
360 if ( !m_rWizard.isInitialized() )
361 throw NotInitializedException();
364 ~CopyTableAccessGuard()
366 m_rWizard.getMutex().release();
369 private:
370 CopyTableWizard& m_rWizard;
373 CopyTableWizard::CopyTableWizard( const Reference< XComponentContext >& _rxORB )
374 :CopyTableWizard_Base( _rxORB )
375 ,m_xContext( _rxORB )
376 ,m_nOperation( CopyTableOperation::CopyDefinitionAndData )
377 ,m_sDestinationTable()
378 ,m_aPrimaryKeyName( false, "ID" )
379 ,m_bUseHeaderLineAsColumnNames( true )
380 ,m_xSourceConnection()
381 ,m_nCommandType( CommandType::COMMAND )
382 ,m_pSourceObject()
383 ,m_xSourceResultSet()
384 ,m_aSourceSelection()
385 ,m_bSourceSelectionBookmarks( true )
386 ,m_xDestConnection()
387 ,m_aCopyTableListeners( m_aMutex )
388 ,m_nOverrideExecutionResult( -1 )
392 CopyTableWizard::~CopyTableWizard()
394 acquire();
396 // protect some members whose dtor might potentially throw
397 try { m_xSourceConnection.clear(); }
398 catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
399 try { m_xDestConnection.clear(); }
400 catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
402 // TODO: shouldn't we have explicit disposal support? If a listener is registered
403 // at our instance, and perhaps holds this our instance by a hard ref, then we'll never
404 // be destroyed.
405 // However, adding XComponent support to the GenericUNODialog probably requires
406 // some thinking - would it break existing clients which do not call a dispose, then?
409 Reference< XInterface > CopyTableWizard::Create( const Reference< XMultiServiceFactory >& _rxFactory )
411 return *( new CopyTableWizard( comphelper::getComponentContext(_rxFactory) ) );
414 OUString SAL_CALL CopyTableWizard::getImplementationName() throw(RuntimeException, std::exception)
416 return getImplementationName_Static();
419 OUString CopyTableWizard::getImplementationName_Static() throw(RuntimeException)
421 return OUString( "org.openoffice.comp.dbu.CopyTableWizard" );
424 css::uno::Sequence<OUString> SAL_CALL CopyTableWizard::getSupportedServiceNames() throw(RuntimeException, std::exception)
426 return getSupportedServiceNames_Static();
429 css::uno::Sequence<OUString> CopyTableWizard::getSupportedServiceNames_Static() throw(RuntimeException)
431 css::uno::Sequence<OUString> aSupported { "com.sun.star.sdb.application.CopyTableWizard" };
432 return aSupported;
435 Reference< XPropertySetInfo > SAL_CALL CopyTableWizard::getPropertySetInfo() throw(RuntimeException, std::exception)
437 Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
438 return xInfo;
441 ::sal_Int16 SAL_CALL CopyTableWizard::getOperation() throw (RuntimeException, std::exception)
443 CopyTableAccessGuard aGuard( *this );
444 return m_nOperation;
447 void SAL_CALL CopyTableWizard::setOperation( ::sal_Int16 _operation ) throw (IllegalArgumentException, RuntimeException, std::exception)
449 CopyTableAccessGuard aGuard( *this );
451 if ( ( _operation != CopyTableOperation::CopyDefinitionAndData )
452 && ( _operation != CopyTableOperation::CopyDefinitionOnly )
453 && ( _operation != CopyTableOperation::CreateAsView )
454 && ( _operation != CopyTableOperation::AppendData )
456 throw IllegalArgumentException( OUString(), *this, 1 );
458 if ( ( _operation == CopyTableOperation::CreateAsView )
459 && !OCopyTableWizard::supportsViews( m_xDestConnection )
461 throw IllegalArgumentException(
462 OUString( ModuleRes( STR_CTW_NO_VIEWS_SUPPORT ) ),
463 *this,
467 m_nOperation = _operation;
470 OUString SAL_CALL CopyTableWizard::getDestinationTableName() throw (RuntimeException, std::exception)
472 CopyTableAccessGuard aGuard( *this );
473 return m_sDestinationTable;
476 void SAL_CALL CopyTableWizard::setDestinationTableName( const OUString& _destinationTableName ) throw (RuntimeException, std::exception)
478 CopyTableAccessGuard aGuard( *this );
479 m_sDestinationTable = _destinationTableName;
482 Optional< OUString > SAL_CALL CopyTableWizard::getCreatePrimaryKey() throw (RuntimeException, std::exception)
484 CopyTableAccessGuard aGuard( *this );
485 return m_aPrimaryKeyName;
488 void SAL_CALL CopyTableWizard::setCreatePrimaryKey( const Optional< OUString >& _newPrimaryKey ) throw (IllegalArgumentException, SQLException, RuntimeException, std::exception)
490 CopyTableAccessGuard aGuard( *this );
492 if ( _newPrimaryKey.IsPresent && !OCopyTableWizard::supportsPrimaryKey( m_xDestConnection ) )
493 throw IllegalArgumentException(
494 OUString( ModuleRes( STR_CTW_NO_PRIMARY_KEY_SUPPORT ) ),
495 *this,
499 m_aPrimaryKeyName = _newPrimaryKey;
502 sal_Bool SAL_CALL CopyTableWizard::getUseHeaderLineAsColumnNames() throw (RuntimeException, std::exception)
504 CopyTableAccessGuard aGuard( *this );
505 return m_bUseHeaderLineAsColumnNames;
508 void SAL_CALL CopyTableWizard::setUseHeaderLineAsColumnNames( sal_Bool _bUseHeaderLineAsColumnNames ) throw (RuntimeException, std::exception)
510 CopyTableAccessGuard aGuard( *this );
511 m_bUseHeaderLineAsColumnNames = _bUseHeaderLineAsColumnNames;
514 void SAL_CALL CopyTableWizard::addCopyTableListener( const Reference< XCopyTableListener >& _rxListener ) throw (RuntimeException, std::exception)
516 CopyTableAccessGuard aGuard( *this );
517 if ( _rxListener.is() )
518 m_aCopyTableListeners.addInterface( _rxListener );
521 void SAL_CALL CopyTableWizard::removeCopyTableListener( const Reference< XCopyTableListener >& _rxListener ) throw (RuntimeException, std::exception)
523 CopyTableAccessGuard aGuard( *this );
524 if ( _rxListener.is() )
525 m_aCopyTableListeners.removeInterface( _rxListener );
528 void SAL_CALL CopyTableWizard::setTitle( const OUString& _rTitle ) throw (RuntimeException, std::exception)
530 CopyTableAccessGuard aGuard( *this );
531 CopyTableWizard_DialogBase::setTitle( _rTitle );
534 ::sal_Int16 SAL_CALL CopyTableWizard::execute( ) throw (RuntimeException, std::exception)
536 CopyTableAccessGuard aGuard( *this );
538 m_nOverrideExecutionResult = -1;
539 sal_Int16 nExecutionResult = CopyTableWizard_DialogBase::execute();
540 if ( m_nOverrideExecutionResult )
541 nExecutionResult = m_nOverrideExecutionResult;
543 return nExecutionResult;
546 OCopyTableWizard& CopyTableWizard::impl_getDialog_throw()
548 OCopyTableWizard* pWizard = dynamic_cast< OCopyTableWizard* >( m_pDialog.get() );
549 if ( !pWizard )
550 throw DisposedException( OUString(), *this );
551 return *pWizard;
554 void CopyTableWizard::impl_attributesToDialog_nothrow( OCopyTableWizard& _rDialog ) const
556 // primary key column
557 _rDialog.setCreatePrimaryKey( m_aPrimaryKeyName.IsPresent, m_aPrimaryKeyName.Value );
558 _rDialog.setUseHeaderLine(m_bUseHeaderLineAsColumnNames);
560 // everything else was passed at construction time already
563 void CopyTableWizard::impl_dialogToAttributes_nothrow( const OCopyTableWizard& _rDialog )
565 m_aPrimaryKeyName.IsPresent = _rDialog.shouldCreatePrimaryKey();
566 if ( m_aPrimaryKeyName.IsPresent )
567 m_aPrimaryKeyName.Value = _rDialog.getPrimaryKeyName();
568 else
569 m_aPrimaryKeyName.Value.clear();
571 m_sDestinationTable = _rDialog.getName();
573 m_nOperation = _rDialog.getOperation();
574 m_bUseHeaderLineAsColumnNames = _rDialog.UseHeaderLine();
577 namespace
579 /** tries to obtain the InteractionHandler associated with a given data source
581 If the data source is a sdb-level data source, it will have a DatabaseDocument associated
582 with it. This document may have an InteractionHandler used while loading it.
584 @throws RuntimeException
585 if it occurs during invoking any of the data source's methods, or if any of the involved
586 components violates its contract by not providing the required interfaces
588 Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XDataSource >& _rxDataSource, const Reference< XInteractionHandler >& _rFallback )
590 Reference< XInteractionHandler > xHandler( _rFallback );
592 // try to obtain the document model
593 Reference< XModel > xDocumentModel;
594 Reference< XDocumentDataSource > xDocDataSource( _rxDataSource, UNO_QUERY );
595 if ( xDocDataSource.is() )
596 xDocumentModel.set( xDocDataSource->getDatabaseDocument(), UNO_QUERY_THROW );
598 // see whether the document model can provide a handler
599 if ( xDocumentModel.is() )
601 ::comphelper::NamedValueCollection aModelArgs( xDocumentModel->getArgs() );
602 xHandler = aModelArgs.getOrDefault( "InteractionHandler", xHandler );
605 return xHandler;
607 /** tries to obtain the InteractionHandler associated with a given connection
609 If the connection belongs to a sdb-level data source, then this data source
610 is examined for an interaction handler. Else, <NULL/> is returned.
612 @throws RuntimeException
613 if it occurs during invoking any of the data source's methods, or if any of the involved
614 components violates its contract by not providing the required interfaces
616 Reference< XInteractionHandler > lcl_getInteractionHandler_throw( const Reference< XConnection >& _rxConnection, const Reference< XInteractionHandler >& _rFallback )
618 // try whether there is a data source which the connection belongs to
619 Reference< XDataSource > xDataSource;
620 Reference< XChild > xAsChild( _rxConnection, UNO_QUERY );
621 if ( xAsChild.is() )
622 xDataSource.set(xAsChild->getParent(), css::uno::UNO_QUERY);
624 if ( xDataSource.is() )
625 return lcl_getInteractionHandler_throw( xDataSource, _rFallback );
627 return _rFallback;
631 Reference< XPropertySet > CopyTableWizard::impl_ensureDataAccessDescriptor_throw(
632 const Sequence< Any >& _rAllArgs, const sal_Int16 _nArgPos, SharedConnection& _out_rxConnection,
633 Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
635 Reference< XPropertySet > xDescriptor;
636 _rAllArgs[ _nArgPos ] >>= xDescriptor;
638 // the descriptor must be non-NULL, of course
639 bool bIsValid = xDescriptor.is();
641 // it must support the proper service
642 if ( bIsValid )
644 Reference< XServiceInfo > xSI( xDescriptor, UNO_QUERY );
645 bIsValid = ( xSI.is()
646 && xSI->supportsService( "com.sun.star.sdb.DataAccessDescriptor" ) );
649 // it must be able to provide a connection
650 if ( bIsValid )
652 _out_rxConnection = impl_extractConnection_throw( xDescriptor, _out_rxDocInteractionHandler );
653 bIsValid = _out_rxConnection.is();
656 if ( !bIsValid )
658 throw IllegalArgumentException(
659 OUString( ModuleRes( STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR ) ),
660 *const_cast< CopyTableWizard* >( this ),
661 _nArgPos + 1
665 return xDescriptor;
668 namespace
670 bool lcl_hasNonEmptyStringValue_throw( const Reference< XPropertySet >& _rxDescriptor,
671 const Reference< XPropertySetInfo >& rxPSI, const OUString& _rPropertyName )
673 OUString sValue;
674 if ( rxPSI->hasPropertyByName( _rPropertyName ) )
676 OSL_VERIFY( _rxDescriptor->getPropertyValue( _rPropertyName ) >>= sValue );
678 return !sValue.isEmpty();
682 void CopyTableWizard::impl_checkForUnsupportedSettings_throw( const Reference< XPropertySet >& _rxSourceDescriptor ) const
684 OSL_PRECOND( _rxSourceDescriptor.is(), "CopyTableWizard::impl_checkForUnsupportedSettings_throw: illegal argument!" );
685 Reference< XPropertySetInfo > xPSI( _rxSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
686 OUString sUnsupportedSetting;
688 const OUString aSettings[] = {
689 OUString(PROPERTY_FILTER), OUString(PROPERTY_ORDER), OUString(PROPERTY_HAVING_CLAUSE), OUString(PROPERTY_GROUP_BY)
691 for (const auto & aSetting : aSettings)
693 if ( lcl_hasNonEmptyStringValue_throw( _rxSourceDescriptor, xPSI, aSetting ) )
695 sUnsupportedSetting = aSetting;
696 break;
700 if ( !sUnsupportedSetting.isEmpty() )
702 OUString sMessage(
703 OUString(ModuleRes(STR_CTW_ERROR_UNSUPPORTED_SETTING)).
704 replaceFirst("$name$", sUnsupportedSetting));
705 throw IllegalArgumentException(
706 sMessage,
707 *const_cast< CopyTableWizard* >( this ),
714 ::std::unique_ptr< ICopyTableSourceObject > CopyTableWizard::impl_extractSourceObject_throw( const Reference< XPropertySet >& _rxDescriptor, sal_Int32& _out_rCommandType ) const
716 OSL_PRECOND( _rxDescriptor.is() && m_xSourceConnection.is(), "CopyTableWizard::impl_extractSourceObject_throw: illegal arguments!" );
718 Reference< XPropertySetInfo > xPSI( _rxDescriptor->getPropertySetInfo(), UNO_SET_THROW );
719 if ( !xPSI->hasPropertyByName( PROPERTY_COMMAND )
720 || !xPSI->hasPropertyByName( PROPERTY_COMMAND_TYPE )
722 throw IllegalArgumentException("Expecting a table or query specification.",
723 // TODO: resource
724 *const_cast< CopyTableWizard* >( this ), 1);
726 OUString sCommand;
727 _out_rCommandType = CommandType::COMMAND;
728 OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand );
729 OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= _out_rCommandType );
731 ::std::unique_ptr< ICopyTableSourceObject > pSourceObject;
732 Reference< XNameAccess > xContainer;
733 switch ( _out_rCommandType )
735 case CommandType::TABLE:
737 Reference< XTablesSupplier > xSuppTables( m_xSourceConnection.getTyped(), UNO_QUERY );
738 if ( xSuppTables.is() )
739 xContainer.set( xSuppTables->getTables(), UNO_SET_THROW );
741 break;
742 case CommandType::QUERY:
744 Reference< XQueriesSupplier > xSuppQueries( m_xSourceConnection.getTyped(), UNO_QUERY );
745 if ( xSuppQueries.is() )
746 xContainer.set( xSuppQueries->getQueries(), UNO_SET_THROW );
748 break;
749 default:
750 throw IllegalArgumentException(
751 OUString( ModuleRes( STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT ) ),
752 *const_cast< CopyTableWizard* >( this ),
757 if ( xContainer.is() )
759 pSourceObject.reset( new ObjectCopySource( m_xSourceConnection,
760 Reference< XPropertySet >( xContainer->getByName( sCommand ), UNO_QUERY_THROW ) ) );
762 else
764 // our source connection is an SDBC level connection only, not a SDBCX level one
765 // Which means it cannot provide the to-be-copied object as component.
767 if ( _out_rCommandType == CommandType::QUERY )
768 // we cannot copy a query if the connection cannot provide it ...
769 throw IllegalArgumentException(
770 OUString(ModuleRes( STR_CTW_ERROR_NO_QUERY )),
771 *const_cast< CopyTableWizard* >( this ),
774 pSourceObject.reset( new NamedTableCopySource( m_xSourceConnection, sCommand ) );
777 return pSourceObject;
780 void CopyTableWizard::impl_extractSourceResultSet_throw( const Reference< XPropertySet >& i_rDescriptor )
782 Reference< XPropertySetInfo > xPSI( i_rDescriptor->getPropertySetInfo(), UNO_SET_THROW );
784 // extract relevant settings
785 if ( xPSI->hasPropertyByName( PROPERTY_RESULT_SET ) )
786 m_xSourceResultSet.set( i_rDescriptor->getPropertyValue( PROPERTY_RESULT_SET ), UNO_QUERY );
788 if ( xPSI->hasPropertyByName( PROPERTY_SELECTION ) )
789 OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_SELECTION ) >>= m_aSourceSelection );
791 if ( xPSI->hasPropertyByName( PROPERTY_BOOKMARK_SELECTION ) )
792 OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_BOOKMARK_SELECTION ) >>= m_bSourceSelectionBookmarks );
794 // sanity checks
795 const bool bHasResultSet = m_xSourceResultSet.is();
796 const bool bHasSelection = ( m_aSourceSelection.getLength() != 0 );
797 if ( bHasSelection && !bHasResultSet )
798 throw IllegalArgumentException("A result set is needed when specifying a selection to copy.",
799 // TODO: resource
800 *this, 1);
802 if ( bHasSelection && m_bSourceSelectionBookmarks )
804 Reference< XRowLocate > xRowLocate( m_xSourceResultSet, UNO_QUERY );
805 if ( !xRowLocate.is() )
807 ::dbtools::throwGenericSQLException(
808 OUString( ModuleRes( STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS ) ),
809 *this
815 SharedConnection CopyTableWizard::impl_extractConnection_throw( const Reference< XPropertySet >& _rxDataSourceDescriptor,
816 Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const
818 SharedConnection xConnection;
820 OSL_PRECOND( _rxDataSourceDescriptor.is(), "CopyTableWizard::impl_extractConnection_throw: no descriptor!" );
821 if ( !_rxDataSourceDescriptor.is() )
822 return xConnection;
824 Reference< XInteractionHandler > xInteractionHandler;
828 Reference< XPropertySetInfo > xPSI( _rxDataSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW );
830 // if there's an ActiveConnection, use it
831 if ( xPSI->hasPropertyByName( PROPERTY_ACTIVE_CONNECTION ) )
833 Reference< XConnection > xPure;
834 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xPure );
835 xConnection.reset( xPure, SharedConnection::NoTakeOwnership );
837 if ( xConnection.is() )
839 xInteractionHandler = lcl_getInteractionHandler_throw( xConnection.getTyped(), m_xInteractionHandler );
840 SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" );
841 break;
844 // there could be a DataSourceName or a DatabaseLocation, describing the css.sdb.DataSource
845 OUString sDataSource, sDatabaseLocation;
846 if ( xPSI->hasPropertyByName( PROPERTY_DATASOURCENAME ) )
847 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sDataSource );
848 if ( xPSI->hasPropertyByName( PROPERTY_DATABASE_LOCATION ) )
849 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATABASE_LOCATION ) >>= sDatabaseLocation );
851 // need a DatabaseContext for loading the data source
852 Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create( m_xContext );
853 Reference< XDataSource > xDataSource;
854 if ( !sDataSource.isEmpty() )
855 xDataSource.set( xDatabaseContext->getByName( sDataSource ), UNO_QUERY_THROW );
856 if ( !xDataSource.is() && !sDatabaseLocation.isEmpty() )
857 xDataSource.set( xDatabaseContext->getByName( sDatabaseLocation ), UNO_QUERY_THROW );
859 if ( xDataSource.is() )
861 // first, try connecting with completion
862 xInteractionHandler = lcl_getInteractionHandler_throw( xDataSource, m_xInteractionHandler );
863 SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" );
864 if ( xInteractionHandler.is() )
866 Reference< XCompletedConnection > xInteractiveConnection( xDataSource, UNO_QUERY );
867 if ( xInteractiveConnection.is() )
868 xConnection.reset( xInteractiveConnection->connectWithCompletion( xInteractionHandler ), SharedConnection::TakeOwnership );
871 // interactively connecting was not successful or possible -> connect without interaction
872 if ( !xConnection.is() )
874 xConnection.reset( xDataSource->getConnection( OUString(), OUString() ), SharedConnection::TakeOwnership );
878 if ( xConnection.is() )
879 break;
881 // finally, there could be a ConnectionResource/ConnectionInfo
882 OUString sConnectionResource;
883 Sequence< PropertyValue > aConnectionInfo;
884 if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_RESOURCE ) )
885 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_RESOURCE ) >>= sConnectionResource );
886 if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_INFO ) )
887 OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_INFO ) >>= aConnectionInfo );
889 Reference< XDriverManager > xDriverManager;
890 try {
891 xDriverManager.set( ConnectionPool::create( m_xContext ), UNO_QUERY_THROW );
892 } catch( const Exception& ) { }
893 if ( !xDriverManager.is() )
894 // no connection pool installed
895 xDriverManager.set( DriverManager::create( m_xContext ), UNO_QUERY_THROW );
897 if ( aConnectionInfo.getLength() )
898 xConnection.set( xDriverManager->getConnectionWithInfo( sConnectionResource, aConnectionInfo ), UNO_SET_THROW );
899 else
900 xConnection.set( xDriverManager->getConnection( sConnectionResource ), UNO_SET_THROW );
902 while ( false );
904 if ( xInteractionHandler != m_xInteractionHandler )
905 _out_rxDocInteractionHandler = xInteractionHandler;
907 return xConnection;
910 ::utl::SharedUNOComponent< XPreparedStatement > CopyTableWizard::impl_createSourceStatement_throw() const
912 OSL_PRECOND( m_xSourceConnection.is(), "CopyTableWizard::impl_createSourceStatement_throw: illegal call!" );
913 if ( !m_xSourceConnection.is() )
914 throw RuntimeException( "CopyTableWizard::impl_createSourceStatement_throw: illegal call!", *const_cast< CopyTableWizard* >( this ));
916 ::utl::SharedUNOComponent< XPreparedStatement > xStatement;
917 switch ( m_nCommandType )
919 case CommandType::TABLE:
920 xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
921 break;
923 case CommandType::QUERY:
925 OUString sQueryCommand( m_pSourceObject->getSelectStatement() );
926 xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW );
928 // check whether we have to fill in parameter values
929 // create and fill a composer
931 Reference< XMultiServiceFactory > xFactory( m_xSourceConnection, UNO_QUERY );
932 ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
933 if ( xFactory.is() )
934 // note: connections below the sdb-level are allowed to not support the XMultiServiceFactory interface
935 xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY );
937 if ( xComposer.is() )
939 xComposer->setQuery( sQueryCommand );
941 Reference< XParameters > xStatementParams( xStatement, UNO_QUERY );
942 OSL_ENSURE( xStatementParams.is(), "CopyTableWizard::impl_createSourceStatement_throw: no access to the statement's parameters!" );
943 // the statement should be a css.sdbc.PreparedStatement (this is what
944 // we created), and a prepared statement is required to support XParameters
945 if ( xStatementParams.is() )
947 OSL_ENSURE( m_xInteractionHandler.is(),
948 "CopyTableWizard::impl_createSourceStatement_throw: no interaction handler for the parameters request!" );
949 // we should always have an interaction handler - as last fallback, we create an own one in ::initialize
951 if ( m_xInteractionHandler.is() )
952 ::dbtools::askForParameters( xComposer, xStatementParams, m_xSourceConnection, m_xInteractionHandler );
956 break;
958 default:
959 // this should not have survived initialization phase
960 throw RuntimeException("No case matched, this should not have survived the initialization phase", *const_cast< CopyTableWizard* >( this ));
963 return xStatement;
966 namespace
968 class ValueTransfer
970 public:
971 ValueTransfer( const sal_Int32& _rSourcePos, const sal_Int32& _rDestPos, const ::std::vector< sal_Int32 >& _rColTypes,
972 const Reference< XRow >& _rxSource, const Reference< XParameters >& _rxDest )
973 :m_rSourcePos( _rSourcePos )
974 ,m_rDestPos( _rDestPos )
975 ,m_rColTypes( _rColTypes )
976 ,m_xSource( _rxSource )
977 ,m_xDest( _rxDest )
981 template< typename VALUE_TYPE >
982 void transferValue( VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ),
983 void (SAL_CALL XParameters::*_pSetter)( sal_Int32, VALUE_TYPE ) )
985 VALUE_TYPE value( (m_xSource.get()->*_pGetter)( m_rSourcePos ) );
986 if ( m_xSource->wasNull() )
987 m_xDest->setNull( m_rDestPos, m_rColTypes[ m_rSourcePos ] );
988 else
989 (m_xDest.get()->*_pSetter)( m_rDestPos, value );
991 template< typename VALUE_TYPE >
992 void transferComplexValue( VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ),
993 void (SAL_CALL XParameters::*_pSetter)( sal_Int32, const VALUE_TYPE& ) )
995 const VALUE_TYPE value( (m_xSource.get()->*_pGetter)( m_rSourcePos ) );
997 if ( m_xSource->wasNull() )
998 m_xDest->setNull( m_rDestPos, m_rColTypes[ m_rSourcePos ] );
999 else
1000 (m_xDest.get()->*_pSetter)( m_rDestPos, value );
1003 private:
1004 const sal_Int32& m_rSourcePos;
1005 const sal_Int32& m_rDestPos;
1006 const ::std::vector< sal_Int32 > m_rColTypes;
1007 const Reference< XRow > m_xSource;
1008 const Reference< XParameters > m_xDest;
1012 bool CopyTableWizard::impl_processCopyError_nothrow( const CopyTableRowEvent& _rEvent )
1014 Reference< XCopyTableListener > xListener;
1017 ::comphelper::OInterfaceIteratorHelper2 aIter( m_aCopyTableListeners );
1018 while ( aIter.hasMoreElements() )
1020 xListener.set( aIter.next(), UNO_QUERY_THROW );
1021 sal_Int16 nListenerChoice = xListener->copyRowError( _rEvent );
1022 switch ( nListenerChoice )
1024 case CopyTableContinuation::Proceed: return true; // continue copying
1025 case CopyTableContinuation::CallNextHandler: continue; // continue the loop, ask next listener
1026 case CopyTableContinuation::Cancel: return false; // cancel copying
1027 case CopyTableContinuation::AskUser: break; // stop asking the listeners, ask the user
1029 default:
1030 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_processCopyError_nothrow: invalid listener response!" );
1031 // ask next listener
1032 continue;
1036 catch( const Exception& )
1038 DBG_UNHANDLED_EXCEPTION();
1041 // no listener felt responsible for the error, or a listener told to ask the user
1045 SQLContext aError;
1046 aError.Context = *this;
1047 aError.Message = OUString( ModuleRes( STR_ERROR_OCCURRED_WHILE_COPYING ) );
1049 ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error );
1050 if ( aInfo.isValid() )
1051 aError.NextException = _rEvent.Error;
1052 else
1054 // a non-SQL exception happened
1055 Exception aException;
1056 OSL_VERIFY( _rEvent.Error >>= aException );
1057 SQLContext aContext;
1058 aContext.Context = aException.Context;
1059 aContext.Message = aException.Message;
1060 aContext.Details = _rEvent.Error.getValueTypeName();
1061 aError.NextException <<= aContext;
1064 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( makeAny( aError ) ) );
1066 ::rtl::Reference< ::comphelper::OInteractionApprove > xYes = new ::comphelper::OInteractionApprove;
1067 xRequest->addContinuation( xYes.get() );
1068 xRequest->addContinuation( new ::comphelper::OInteractionDisapprove );
1070 OSL_ENSURE( m_xInteractionHandler.is(),
1071 "CopyTableWizard::impl_processCopyError_nothrow: we always should have an interaction handler!" );
1072 if ( m_xInteractionHandler.is() )
1073 m_xInteractionHandler->handle( xRequest.get() );
1075 if ( xYes->wasSelected() )
1076 // continue copying
1077 return true;
1079 catch( const Exception& )
1081 DBG_UNHANDLED_EXCEPTION();
1084 // cancel copying
1085 return false;
1088 void CopyTableWizard::impl_copyRows_throw( const Reference< XResultSet >& _rxSourceResultSet,
1089 const Reference< XPropertySet >& _rxDestTable )
1091 OSL_PRECOND( m_xDestConnection.is(), "CopyTableWizard::impl_copyRows_throw: illegal call!" );
1092 if ( !m_xDestConnection.is() )
1093 throw RuntimeException( "m_xDestConnection is set to null, CopyTableWizard::impl_copyRows_throw: illegal call!", *this );
1095 Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_QUERY_THROW );
1097 const OCopyTableWizard& rWizard = impl_getDialog_throw();
1098 ODatabaseExport::TPositions aColumnMapping = rWizard.GetColumnPositions();
1099 bool bAutoIncrement = rWizard.shouldCreatePrimaryKey();
1101 Reference< XRow > xRow ( _rxSourceResultSet, UNO_QUERY_THROW );
1102 Reference< XRowLocate > xRowLocate ( _rxSourceResultSet, UNO_QUERY_THROW );
1104 Reference< XResultSetMetaDataSupplier > xSuppResMeta( _rxSourceResultSet, UNO_QUERY_THROW );
1105 Reference< XResultSetMetaData> xMeta( xSuppResMeta->getMetaData() );
1107 // we need a vector which all types
1108 sal_Int32 nCount = xMeta->getColumnCount();
1109 ::std::vector< sal_Int32 > aSourceColTypes;
1110 aSourceColTypes.reserve( nCount + 1 );
1111 aSourceColTypes.push_back( -1 ); // just to avoid a every time i-1 call
1113 ::std::vector< sal_Int32 > aSourcePrec;
1114 aSourcePrec.reserve( nCount + 1 );
1115 aSourcePrec.push_back( -1 ); // just to avoid a every time i-1 call
1117 for ( sal_Int32 k=1; k <= nCount; ++k )
1119 aSourceColTypes.push_back( xMeta->getColumnType( k ) );
1120 aSourcePrec.push_back( xMeta->getPrecision( k ) );
1123 // now create, fill and execute the prepared statement
1124 Reference< XPreparedStatement > xStatement( ODatabaseExport::createPreparedStatment( xDestMetaData, _rxDestTable, aColumnMapping ), UNO_SET_THROW );
1125 Reference< XParameters > xStatementParams( xStatement, UNO_QUERY_THROW );
1127 const bool bSelectedRecordsOnly = m_aSourceSelection.getLength() != 0;
1128 const Any* pSelectedRow = m_aSourceSelection.getConstArray();
1129 const Any* pSelEnd = pSelectedRow + m_aSourceSelection.getLength();
1131 sal_Int32 nRowCount = 0;
1132 bool bContinue = false;
1134 CopyTableRowEvent aCopyEvent;
1135 aCopyEvent.Source = *this;
1136 aCopyEvent.SourceData = _rxSourceResultSet;
1138 do // loop as long as there are more rows or the selection ends
1140 bContinue = false;
1141 if ( bSelectedRecordsOnly )
1143 if ( pSelectedRow != pSelEnd )
1145 if ( m_bSourceSelectionBookmarks )
1147 bContinue = xRowLocate->moveToBookmark( *pSelectedRow );
1149 else
1151 sal_Int32 nPos = 0;
1152 OSL_VERIFY( *pSelectedRow >>= nPos );
1153 bContinue = _rxSourceResultSet->absolute( nPos );
1155 ++pSelectedRow;
1158 else
1159 bContinue = _rxSourceResultSet->next();
1161 if ( !bContinue )
1163 break;
1166 ++nRowCount;
1167 ODatabaseExport::TPositions::const_iterator aPosIter = aColumnMapping.begin();
1168 ODatabaseExport::TPositions::const_iterator aPosEnd = aColumnMapping.end();
1170 aCopyEvent.Error.clear();
1173 bool bInsertAutoIncrement = true;
1174 // notify listeners
1175 m_aCopyTableListeners.notifyEach( &XCopyTableListener::copyingRow, aCopyEvent );
1177 sal_Int32 nDestColumn( 0 );
1178 sal_Int32 nSourceColumn( 1 );
1179 ValueTransfer aTransfer( nSourceColumn, nDestColumn, aSourceColTypes, xRow, xStatementParams );
1181 for ( ; aPosIter != aPosEnd; ++aPosIter )
1183 nDestColumn = aPosIter->first;
1184 if ( nDestColumn == COLUMN_POSITION_NOT_FOUND )
1186 ++nSourceColumn;
1187 // otherwise we don't get the correct value when only the 2nd source column was selected
1188 continue;
1191 if ( bAutoIncrement && bInsertAutoIncrement )
1193 xStatementParams->setInt( 1, nRowCount );
1194 bInsertAutoIncrement = false;
1195 continue;
1198 if ( ( nSourceColumn < 1 ) || ( nSourceColumn >= (sal_Int32)aSourceColTypes.size() ) )
1199 { // ( we have to check here against 1 because the parameters are 1 based)
1200 ::dbtools::throwSQLException("Internal error: invalid column type index.",
1201 ::dbtools::StandardSQLState::INVALID_DESCRIPTOR_INDEX, *this);
1204 switch ( aSourceColTypes[ nSourceColumn ] )
1206 case DataType::DOUBLE:
1207 case DataType::REAL:
1208 aTransfer.transferValue( &XRow::getDouble, &XParameters::setDouble );
1209 break;
1211 case DataType::CHAR:
1212 case DataType::VARCHAR:
1213 case DataType::LONGVARCHAR:
1214 case DataType::DECIMAL:
1215 case DataType::NUMERIC:
1216 aTransfer.transferComplexValue( &XRow::getString, &XParameters::setString );
1217 break;
1219 case DataType::BIGINT:
1220 aTransfer.transferValue( &XRow::getLong, &XParameters::setLong );
1221 break;
1223 case DataType::FLOAT:
1224 aTransfer.transferValue( &XRow::getFloat, &XParameters::setFloat );
1225 break;
1227 case DataType::LONGVARBINARY:
1228 case DataType::BINARY:
1229 case DataType::VARBINARY:
1230 aTransfer.transferComplexValue( &XRow::getBytes, &XParameters::setBytes );
1231 break;
1233 case DataType::DATE:
1234 aTransfer.transferComplexValue( &XRow::getDate, &XParameters::setDate );
1235 break;
1237 case DataType::TIME:
1238 aTransfer.transferComplexValue( &XRow::getTime, &XParameters::setTime );
1239 break;
1241 case DataType::TIMESTAMP:
1242 aTransfer.transferComplexValue( &XRow::getTimestamp, &XParameters::setTimestamp );
1243 break;
1245 case DataType::BIT:
1246 if ( aSourcePrec[nSourceColumn] > 1 )
1248 aTransfer.transferComplexValue( &XRow::getBytes, &XParameters::setBytes );
1249 break;
1251 SAL_FALLTHROUGH;
1252 case DataType::BOOLEAN:
1253 aTransfer.transferValue( &XRow::getBoolean, &XParameters::setBoolean );
1254 break;
1256 case DataType::TINYINT:
1257 aTransfer.transferValue( &XRow::getByte, &XParameters::setByte );
1258 break;
1260 case DataType::SMALLINT:
1261 aTransfer.transferValue( &XRow::getShort, &XParameters::setShort );
1262 break;
1264 case DataType::INTEGER:
1265 aTransfer.transferValue( &XRow::getInt, &XParameters::setInt );
1266 break;
1268 case DataType::BLOB:
1269 aTransfer.transferComplexValue( &XRow::getBlob, &XParameters::setBlob );
1270 break;
1272 case DataType::CLOB:
1273 aTransfer.transferComplexValue( &XRow::getClob, &XParameters::setClob );
1274 break;
1276 default:
1278 OUString aMessage( ModuleRes( STR_CTW_UNSUPPORTED_COLUMN_TYPE ) );
1280 aMessage = aMessage.replaceFirst( "$type$", OUString::number( aSourceColTypes[ nSourceColumn ] ) );
1281 aMessage = aMessage.replaceFirst( "$pos$", OUString::number( nSourceColumn ) );
1283 ::dbtools::throwSQLException(
1284 aMessage,
1285 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE,
1286 *this
1290 ++nSourceColumn;
1292 xStatement->executeUpdate();
1294 // notify listeners
1295 m_aCopyTableListeners.notifyEach( &XCopyTableListener::copiedRow, aCopyEvent );
1297 catch( const Exception& )
1299 aCopyEvent.Error = ::cppu::getCaughtException();
1302 if ( aCopyEvent.Error.hasValue() )
1303 bContinue = impl_processCopyError_nothrow( aCopyEvent );
1305 while( bContinue );
1308 void CopyTableWizard::impl_doCopy_nothrow()
1310 Any aError;
1314 OCopyTableWizard& rWizard( impl_getDialog_throw() );
1316 WaitObject aWO( rWizard.GetParent() );
1317 Reference< XPropertySet > xTable;
1319 switch ( rWizard.getOperation() )
1321 case CopyTableOperation::CopyDefinitionOnly:
1322 case CopyTableOperation::CopyDefinitionAndData:
1324 xTable = rWizard.createTable();
1326 if( !xTable.is() )
1328 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: createTable should throw here, shouldn't it?" );
1329 break;
1332 if( CopyTableOperation::CopyDefinitionOnly == rWizard.getOperation() )
1333 break;
1335 SAL_FALLTHROUGH;
1338 case CopyTableOperation::AppendData:
1341 if ( !xTable.is() )
1343 xTable = rWizard.createTable();
1344 if ( !xTable.is() )
1346 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: createTable should throw here, shouldn't it?" );
1347 break;
1351 ::utl::SharedUNOComponent< XPreparedStatement > xSourceStatement;
1352 ::utl::SharedUNOComponent< XResultSet > xSourceResultSet;
1354 if ( m_xSourceResultSet.is() )
1356 xSourceResultSet.reset( m_xSourceResultSet, ::utl::SharedUNOComponent< XResultSet >::NoTakeOwnership );
1358 else
1360 const bool bIsSameConnection = ( m_xSourceConnection.getTyped() == m_xDestConnection.getTyped() );
1361 const bool bIsTable = ( CommandType::TABLE == m_nCommandType );
1362 bool bDone = false;
1363 if ( bIsSameConnection && bIsTable )
1365 // try whether the server supports copying via SQL
1368 m_xDestConnection->createStatement()->executeUpdate( impl_getServerSideCopyStatement_throw(xTable) );
1369 bDone = true;
1371 catch( const Exception& )
1373 // this is allowed.
1377 if ( !bDone )
1379 xSourceStatement.set( impl_createSourceStatement_throw(), UNO_SET_THROW );
1380 xSourceResultSet.set( xSourceStatement->executeQuery(), UNO_SET_THROW );
1384 if ( xSourceResultSet.is() )
1385 impl_copyRows_throw( xSourceResultSet, xTable );
1387 break;
1389 case CopyTableOperation::CreateAsView:
1390 rWizard.createView();
1391 break;
1393 default:
1394 SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: What operation, please?" );
1395 break;
1398 catch( const Exception& )
1400 aError = ::cppu::getCaughtException();
1402 // silence the error of the user cancelling the parameter's dialog
1403 SQLException aSQLError;
1404 if ( ( aError >>= aSQLError ) && ( aSQLError.ErrorCode == ::dbtools::ParameterInteractionCancelled ) )
1406 aError.clear();
1407 m_nOverrideExecutionResult = RET_CANCEL;
1411 if ( aError.hasValue() && m_xInteractionHandler.is() )
1415 ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( aError ) );
1416 m_xInteractionHandler->handle( xRequest.get() );
1418 catch( const Exception& )
1420 DBG_UNHANDLED_EXCEPTION();
1425 OUString CopyTableWizard::impl_getServerSideCopyStatement_throw(const Reference< XPropertySet >& _xTable)
1427 const Reference<XColumnsSupplier> xDestColsSup(_xTable,UNO_QUERY_THROW);
1428 const Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames();
1429 const Reference< XDatabaseMetaData > xDestMetaData( m_xDestConnection->getMetaData(), UNO_QUERY_THROW );
1430 const OUString sQuote = xDestMetaData->getIdentifierQuoteString();
1431 OUStringBuffer sColumns;
1432 // 1st check if the columns matching
1433 const OCopyTableWizard& rWizard = impl_getDialog_throw();
1434 ODatabaseExport::TPositions aColumnMapping = rWizard.GetColumnPositions();
1435 ODatabaseExport::TPositions::const_iterator aPosIter = aColumnMapping.begin();
1436 for ( sal_Int32 i = 0; aPosIter != aColumnMapping.end() ; ++aPosIter,++i )
1438 if ( COLUMN_POSITION_NOT_FOUND != aPosIter->second )
1440 if ( !sColumns.isEmpty() )
1441 sColumns.append(",");
1442 sColumns.append(sQuote + aDestColumnNames[aPosIter->second - 1] + sQuote);
1445 const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, _xTable, ::dbtools::EComposeRule::InDataManipulation, false, false, true );
1446 OUString sSql("INSERT INTO " + sComposedTableName + " ( " + sColumns.makeStringAndClear() + " ) ( " + m_pSourceObject->getSelectStatement() + " )");
1448 return sSql;
1451 void SAL_CALL CopyTableWizard::initialize( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException, std::exception)
1453 ::osl::MutexGuard aGuard( m_aMutex );
1454 if ( isInitialized() )
1455 throw AlreadyInitializedException( OUString(), *this );
1457 sal_Int32 nArgCount( _rArguments.getLength() );
1458 if ( ( nArgCount != 2 ) && ( nArgCount != 3 ) )
1459 throw IllegalArgumentException(
1460 OUString( ModuleRes( STR_CTW_ILLEGAL_PARAMETER_COUNT ) ),
1461 *this,
1467 if ( nArgCount == 3 )
1468 { // ->createWithInteractionHandler
1469 if ( !( _rArguments[2] >>= m_xInteractionHandler ) )
1470 throw IllegalArgumentException(
1471 OUString(ModuleRes( STR_CTW_ERROR_INVALID_INTERACTIONHANDLER )),
1472 *this,
1476 if ( !m_xInteractionHandler.is() )
1477 m_xInteractionHandler.set( InteractionHandler::createWithParent(m_xContext, nullptr), UNO_QUERY );
1479 Reference< XInteractionHandler > xSourceDocHandler;
1480 Reference< XPropertySet > xSourceDescriptor( impl_ensureDataAccessDescriptor_throw( _rArguments, 0, m_xSourceConnection, xSourceDocHandler ) );
1481 impl_checkForUnsupportedSettings_throw( xSourceDescriptor );
1482 m_pSourceObject = impl_extractSourceObject_throw( xSourceDescriptor, m_nCommandType );
1483 impl_extractSourceResultSet_throw( xSourceDescriptor );
1485 Reference< XInteractionHandler > xDestDocHandler;
1486 impl_ensureDataAccessDescriptor_throw( _rArguments, 1, m_xDestConnection, xDestDocHandler );
1488 if ( xDestDocHandler.is() && !m_xInteractionHandler.is() )
1489 m_xInteractionHandler = xDestDocHandler;
1491 catch( const RuntimeException& ) { throw; }
1492 catch( const SQLException& ) { throw; }
1493 catch( const Exception& )
1495 throw WrappedTargetException(
1496 OUString( ModuleRes( STR_CTW_ERROR_DURING_INITIALIZATION ) ),
1497 *this,
1498 ::cppu::getCaughtException()
1503 ::cppu::IPropertyArrayHelper& CopyTableWizard::getInfoHelper()
1505 return *getArrayHelper();
1508 ::cppu::IPropertyArrayHelper* CopyTableWizard::createArrayHelper( ) const
1510 Sequence< Property > aProps;
1511 describeProperties( aProps );
1512 return new ::cppu::OPropertyArrayHelper( aProps );
1515 VclPtr<Dialog> CopyTableWizard::createDialog( vcl::Window* _pParent )
1517 OSL_PRECOND( isInitialized(), "CopyTableWizard::createDialog: not initialized!" );
1518 // this should have been prevented in ::execute already
1520 VclPtrInstance<OCopyTableWizard> pWizard(
1521 _pParent,
1522 m_sDestinationTable,
1523 m_nOperation,
1524 *m_pSourceObject,
1525 m_xSourceConnection.getTyped(),
1526 m_xDestConnection.getTyped(),
1527 m_xContext,
1528 m_xInteractionHandler
1531 impl_attributesToDialog_nothrow( *pWizard );
1533 return pWizard;
1536 void CopyTableWizard::executedDialog( sal_Int16 _nExecutionResult )
1538 CopyTableWizard_DialogBase::executedDialog( _nExecutionResult );
1540 if ( _nExecutionResult == RET_OK )
1541 impl_doCopy_nothrow();
1543 // do this after impl_doCopy_nothrow: The attributes may change during copying, for instance
1544 // if the user entered an unqualified table name
1545 impl_dialogToAttributes_nothrow( impl_getDialog_throw() );
1548 } // namespace dbaui
1550 extern "C" void SAL_CALL createRegistryInfo_CopyTableWizard()
1552 static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::CopyTableWizard > aAutoRegistration;
1555 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */