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