Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx
Warning:line 950, column 5
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dbmgr.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx

/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx

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 <sal/config.h>
21
22#include <cassert>
23
24#include <unotxdoc.hxx>
25#include <sfx2/app.hxx>
26#include <com/sun/star/sdb/CommandType.hpp>
27#include <com/sun/star/sdb/XDocumentDataSource.hpp>
28#include <com/sun/star/lang/DisposedException.hpp>
29#include <com/sun/star/lang/XEventListener.hpp>
30#include <com/sun/star/uri/UriReferenceFactory.hpp>
31#include <com/sun/star/uri/VndSunStarPkgUrlReferenceFactory.hpp>
32#include <com/sun/star/util/NumberFormatter.hpp>
33#include <com/sun/star/sdb/DatabaseContext.hpp>
34#include <com/sun/star/sdb/TextConnectionSettings.hpp>
35#include <com/sun/star/sdb/XCompletedConnection.hpp>
36#include <com/sun/star/sdb/XCompletedExecution.hpp>
37#include <com/sun/star/container/XChild.hpp>
38#include <com/sun/star/text/MailMergeEvent.hpp>
39#include <com/sun/star/frame/XStorable.hpp>
40#include <com/sun/star/task/InteractionHandler.hpp>
41#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
42#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
43#include <com/sun/star/beans/XPropertySet.hpp>
44#include <vcl/errinf.hxx>
45#include <vcl/print.hxx>
46#include <vcl/scheduler.hxx>
47#include <sfx2/fcontnr.hxx>
48#include <sfx2/filedlghelper.hxx>
49#include <sfx2/viewfrm.hxx>
50#include <dbconfig.hxx>
51#include <unotools/tempfile.hxx>
52#include <unotools/pathoptions.hxx>
53#include <svl/zforlist.hxx>
54#include <svl/stritem.hxx>
55#include <sfx2/docfile.hxx>
56#include <sfx2/docfilt.hxx>
57#include <sfx2/progress.hxx>
58#include <sfx2/dispatch.hxx>
59#include <cmdid.h>
60#include <swmodule.hxx>
61#include <view.hxx>
62#include <docsh.hxx>
63#include <edtwin.hxx>
64#include <wrtsh.hxx>
65#include <fldbas.hxx>
66#include <dbui.hxx>
67#include <dbmgr.hxx>
68#include <doc.hxx>
69#include <IDocumentLinksAdministration.hxx>
70#include <IDocumentFieldsAccess.hxx>
71#include <IDocumentUndoRedo.hxx>
72#include <swwait.hxx>
73#include <swunohelper.hxx>
74#include <strings.hrc>
75#include <mmconfigitem.hxx>
76#include <com/sun/star/sdbc/XRowSet.hpp>
77#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
78#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
79#include <com/sun/star/sdb/XQueriesSupplier.hpp>
80#include <com/sun/star/sdb/XColumn.hpp>
81#include <com/sun/star/sdbc/DataType.hpp>
82#include <com/sun/star/sdbc/ResultSetType.hpp>
83#include <com/sun/star/sdbc/SQLException.hpp>
84#include <com/sun/star/mail/MailAttachment.hpp>
85#include <comphelper/processfactory.hxx>
86#include <comphelper/property.hxx>
87#include <comphelper/storagehelper.hxx>
88#include <comphelper/string.hxx>
89#include <comphelper/types.hxx>
90#include <mailmergehelper.hxx>
91#include <maildispatcher.hxx>
92#include <svtools/htmlcfg.hxx>
93#include <i18nlangtag/languagetag.hxx>
94#include <com/sun/star/util/XNumberFormatTypes.hpp>
95#include <svl/numuno.hxx>
96#include <connectivity/dbtools.hxx>
97#include <connectivity/dbconversion.hxx>
98#include <unotools/charclass.hxx>
99#include <tools/diagnose_ex.h>
100
101#include <unomailmerge.hxx>
102#include <sfx2/event.hxx>
103#include <svx/dataaccessdescriptor.hxx>
104#include <osl/mutex.hxx>
105#include <rtl/textenc.h>
106#include <rtl/tencinfo.h>
107#include <cppuhelper/implbase.hxx>
108#include <ndindex.hxx>
109#include <swevent.hxx>
110#include <sal/log.hxx>
111#include <swabstdlg.hxx>
112#include <vector>
113#include <section.hxx>
114#include <rootfrm.hxx>
115#include <calc.hxx>
116#include <dbfld.hxx>
117#include <IDocumentState.hxx>
118#include <imaildsplistener.hxx>
119#include <iodetect.hxx>
120#include <IDocumentDeviceAccess.hxx>
121
122#include <memory>
123#include <comphelper/propertysequence.hxx>
124
125using namespace ::com::sun::star;
126using namespace sw;
127
128namespace {
129
130void lcl_emitEvent(SfxEventHintId nEventId, sal_Int32 nStrId, SfxObjectShell* pDocShell)
131{
132 SfxGetpApp()->NotifyEvent(SfxEventHint(nEventId,
133 SwDocShell::GetEventName(nStrId),
134 pDocShell));
135}
136
137}
138
139std::vector<std::pair<SwDocShell*, OUString>> SwDBManager::m_aUncommittedRegistrations;
140
141namespace {
142
143enum class SwDBNextRecord { NEXT, FIRST };
144
145}
146
147static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action = SwDBNextRecord::NEXT );
148
149namespace {
150
151enum class WorkingDocType { SOURCE, TARGET, COPY };
152
153}
154
155static SfxObjectShell* lcl_CreateWorkingDocument(
156 const WorkingDocType aType, const SwWrtShell &rSourceWrtShell,
157 const vcl::Window *pSourceWindow,
158 SwDBManager** const ppDBManager,
159 SwView** const pView, SwWrtShell** const pWrtShell, SwDoc** const pDoc );
160
161static bool lcl_getCountFromResultSet( sal_Int32& rCount, const SwDSParam* pParam )
162{
163 rCount = pParam->aSelection.getLength();
164 if ( rCount > 0 )
165 return true;
166
167 uno::Reference<beans::XPropertySet> xPrSet(pParam->xResultSet, uno::UNO_QUERY);
168 if ( xPrSet.is() )
169 {
170 try
171 {
172 bool bFinal = false;
173 uno::Any aFinal = xPrSet->getPropertyValue("IsRowCountFinal");
174 aFinal >>= bFinal;
175 if(!bFinal)
176 {
177 pParam->xResultSet->last();
178 pParam->xResultSet->first();
179 }
180 uno::Any aCount = xPrSet->getPropertyValue("RowCount");
181 if( aCount >>= rCount )
182 return true;
183 }
184 catch(const uno::Exception&)
185 {
186 }
187 }
188 return false;
189}
190
191class SwDBManager::ConnectionDisposedListener_Impl
192 : public cppu::WeakImplHelper< lang::XEventListener >
193{
194private:
195 SwDBManager * m_pDBManager;
196
197 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
198
199public:
200 explicit ConnectionDisposedListener_Impl(SwDBManager& rMgr);
201
202 void Dispose() { m_pDBManager = nullptr; }
203
204};
205
206namespace {
207
208/// Listens to removed data sources, and if it's one that's embedded into this document, triggers embedding removal.
209class SwDataSourceRemovedListener : public cppu::WeakImplHelper<sdb::XDatabaseRegistrationsListener>
210{
211 uno::Reference<sdb::XDatabaseContext> m_xDatabaseContext;
212 SwDBManager* m_pDBManager;
213
214public:
215 explicit SwDataSourceRemovedListener(SwDBManager& rDBManager);
216 virtual ~SwDataSourceRemovedListener() override;
217 virtual void SAL_CALL registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
218 virtual void SAL_CALL revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
219 virtual void SAL_CALL changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent) override;
220 virtual void SAL_CALL disposing(const lang::EventObject& rObject) override;
221 void Dispose();
222};
223
224}
225
226SwDataSourceRemovedListener::SwDataSourceRemovedListener(SwDBManager& rDBManager)
227 : m_pDBManager(&rDBManager)
228{
229 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
230 m_xDatabaseContext = sdb::DatabaseContext::create(xComponentContext);
231 m_xDatabaseContext->addDatabaseRegistrationsListener(this);
232}
233
234SwDataSourceRemovedListener::~SwDataSourceRemovedListener()
235{
236 if (m_xDatabaseContext.is())
237 m_xDatabaseContext->removeDatabaseRegistrationsListener(this);
238}
239
240void SAL_CALL SwDataSourceRemovedListener::registeredDatabaseLocation(const sdb::DatabaseRegistrationEvent& /*rEvent*/)
241{
242}
243
244void SAL_CALL SwDataSourceRemovedListener::revokedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent)
245{
246 if (!m_pDBManager || m_pDBManager->getEmbeddedName().isEmpty())
247 return;
248
249 SwDoc* pDoc = m_pDBManager->getDoc();
250 if (!pDoc)
251 return;
252
253 SwDocShell* pDocShell = pDoc->GetDocShell();
254 if (!pDocShell)
255 return;
256
257 OUString aOwnURL = pDocShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::WithCharset);
258 OUString sTmpName = "vnd.sun.star.pkg://" +
259 INetURLObject::encode(aOwnURL, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All);
260 sTmpName += "/" + m_pDBManager->getEmbeddedName();
261
262 if (sTmpName != rEvent.OldLocation)
263 return;
264
265 // The revoked database location is inside this document, then remove the
266 // embedding, as otherwise it would be back on the next reload of the
267 // document.
268 pDocShell->GetStorage()->removeElement(m_pDBManager->getEmbeddedName());
269 m_pDBManager->setEmbeddedName(OUString(), *pDocShell);
270}
271
272void SAL_CALL SwDataSourceRemovedListener::changedDatabaseLocation(const sdb::DatabaseRegistrationEvent& rEvent)
273{
274 if (rEvent.OldLocation != rEvent.NewLocation)
275 revokedDatabaseLocation(rEvent);
276}
277
278void SwDataSourceRemovedListener::disposing(const lang::EventObject& /*rObject*/)
279{
280 m_xDatabaseContext.clear();
281}
282
283void SwDataSourceRemovedListener::Dispose()
284{
285 m_pDBManager = nullptr;
286}
287
288struct SwDBManager::SwDBManager_Impl
289{
290 std::unique_ptr<SwDSParam> pMergeData;
291 VclPtr<AbstractMailMergeDlg> pMergeDialog;
292 rtl::Reference<SwDBManager::ConnectionDisposedListener_Impl> m_xDisposeListener;
293 rtl::Reference<SwDataSourceRemovedListener> m_xDataSourceRemovedListener;
294 osl::Mutex m_aAllEmailSendMutex;
295 uno::Reference< mail::XMailMessage> m_xLastMessage;
296
297 explicit SwDBManager_Impl(SwDBManager& rDBManager)
298 : m_xDisposeListener(new ConnectionDisposedListener_Impl(rDBManager))
299 {}
300
301 ~SwDBManager_Impl()
302 {
303 m_xDisposeListener->Dispose();
304 if (m_xDataSourceRemovedListener.is())
305 m_xDataSourceRemovedListener->Dispose();
306 }
307};
308
309static void lcl_InitNumberFormatter(SwDSParam& rParam, uno::Reference<sdbc::XDataSource> const & xSource)
310{
311 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
312 rParam.xFormatter = util::NumberFormatter::create(xContext);
313 uno::Reference<beans::XPropertySet> xSourceProps(
314 (xSource.is()
315 ? xSource
316 : SwDBManager::getDataSourceAsParent(
317 rParam.xConnection, rParam.sDataSource)),
318 uno::UNO_QUERY);
319 if(!xSourceProps.is())
320 return;
321
322 uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
323 if(!aFormats.hasValue())
324 return;
325
326 uno::Reference<util::XNumberFormatsSupplier> xSuppl;
327 aFormats >>= xSuppl;
328 if(xSuppl.is())
329 {
330 uno::Reference< beans::XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
331 uno::Any aNull = xSettings->getPropertyValue("NullDate");
332 aNull >>= rParam.aNullDate;
333 if(rParam.xFormatter.is())
334 rParam.xFormatter->attachNumberFormatsSupplier(xSuppl);
335 }
336}
337
338static bool lcl_MoveAbsolute(SwDSParam* pParam, long nAbsPos)
339{
340 bool bRet = false;
341 try
342 {
343 if(pParam->aSelection.hasElements())
344 {
345 if(pParam->aSelection.getLength() <= nAbsPos)
346 {
347 pParam->bEndOfDB = true;
348 bRet = false;
349 }
350 else
351 {
352 pParam->nSelectionIndex = nAbsPos;
353 sal_Int32 nPos = 0;
354 pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos;
355 pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
356 bRet = !pParam->bEndOfDB;
357 }
358 }
359 else if(pParam->bScrollable)
360 {
361 bRet = pParam->xResultSet->absolute( nAbsPos );
362 }
363 else
364 {
365 OSL_FAIL("no absolute positioning available")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "365" ": "), "%s", "no absolute positioning available");
} } while (false)
;
366 }
367 }
368 catch(const uno::Exception&)
369 {
370 }
371 return bRet;
372}
373
374static void lcl_GetColumnCnt(SwDSParam *pParam,
375 const uno::Reference< beans::XPropertySet > &rColumnProps,
376 LanguageType nLanguage, OUString &rResult, double* pNumber)
377{
378 SwDBFormatData aFormatData;
379 if(!pParam->xFormatter.is())
380 {
381 uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(
382 pParam->xConnection,pParam->sDataSource);
383 lcl_InitNumberFormatter(*pParam, xSource );
384 }
385 aFormatData.aNullDate = pParam->aNullDate;
386 aFormatData.xFormatter = pParam->xFormatter;
387
388 aFormatData.aLocale = LanguageTag( nLanguage ).getLocale();
389
390 rResult = SwDBManager::GetDBField( rColumnProps, aFormatData, pNumber);
391}
392
393static bool lcl_GetColumnCnt(SwDSParam* pParam, const OUString& rColumnName,
394 LanguageType nLanguage, OUString& rResult, double* pNumber)
395{
396 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( pParam->xResultSet, uno::UNO_QUERY );
397 uno::Reference<container::XNameAccess> xCols;
398 try
399 {
400 xCols = xColsSupp->getColumns();
401 }
402 catch(const lang::DisposedException&)
403 {
404 }
405 if(!xCols.is() || !xCols->hasByName(rColumnName))
406 return false;
407 uno::Any aCol = xCols->getByName(rColumnName);
408 uno::Reference< beans::XPropertySet > xColumnProps;
409 aCol >>= xColumnProps;
410 lcl_GetColumnCnt( pParam, xColumnProps, nLanguage, rResult, pNumber );
411 return true;
412};
413
414// import data
415bool SwDBManager::Merge( const SwMergeDescriptor& rMergeDesc )
416{
417 assert( !m_bInMerge && !m_pImpl->pMergeData && "merge already activated!" )(static_cast <bool> (!m_bInMerge && !m_pImpl->
pMergeData && "merge already activated!") ? void (0) :
__assert_fail ("!m_bInMerge && !m_pImpl->pMergeData && \"merge already activated!\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 417, __extension__ __PRETTY_FUNCTION__))
;
3
Assuming field 'm_bInMerge' is false
4
'?' condition is true
418
419 SfxObjectShellLock xWorkObjSh;
420 SwWrtShell *pWorkShell = nullptr;
421 SwDoc *pWorkDoc = nullptr;
422 SwDBManager *pWorkDocOrigDBManager = nullptr;
423
424 switch( rMergeDesc.nMergeType )
5
Control jumps to 'case DBMGR_MERGE_SHELL:' at line 429
425 {
426 case DBMGR_MERGE_PRINTER:
427 case DBMGR_MERGE_EMAIL:
428 case DBMGR_MERGE_FILE:
429 case DBMGR_MERGE_SHELL:
430 {
431 SwDocShell *pSourceDocSh = rMergeDesc.rSh.GetView().GetDocShell();
432 if( pSourceDocSh->IsModified() )
6
Assuming the condition is true
7
Taking true branch
433 {
434 pWorkDocOrigDBManager = this;
435 xWorkObjSh = lcl_CreateWorkingDocument(
8
Calling 'lcl_CreateWorkingDocument'
436 WorkingDocType::SOURCE, rMergeDesc.rSh, nullptr,
437 &pWorkDocOrigDBManager, nullptr, &pWorkShell, &pWorkDoc );
438 }
439 [[fallthrough]];
440 }
441
442 default:
443 if( !xWorkObjSh.Is() )
444 pWorkShell = &rMergeDesc.rSh;
445 break;
446 }
447
448 SwDBData aData;
449 aData.nCommandType = sdb::CommandType::TABLE;
450 uno::Reference<sdbc::XResultSet> xResSet;
451 uno::Sequence<uno::Any> aSelection;
452 uno::Reference< sdbc::XConnection> xConnection;
453
454 aData.sDataSource = rMergeDesc.rDescriptor.getDataSource();
455 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Command] >>= aData.sCommand;
456 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= aData.nCommandType;
457
458 if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Cursor) )
459 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Cursor] >>= xResSet;
460 if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Selection) )
461 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection;
462 if ( rMergeDesc.rDescriptor.has(svx::DataAccessDescriptorProperty::Connection) )
463 rMergeDesc.rDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection;
464
465 if((aData.sDataSource.isEmpty() || aData.sCommand.isEmpty()) && !xResSet.is())
466 {
467 return false;
468 }
469
470 m_pImpl->pMergeData.reset(new SwDSParam(aData, xResSet, aSelection));
471 SwDSParam* pTemp = FindDSData(aData, false);
472 if(pTemp)
473 *pTemp = *m_pImpl->pMergeData;
474 else
475 {
476 // calls from the calculator may have added a connection with an invalid commandtype
477 //"real" data base connections added here have to re-use the already available
478 //DSData and set the correct CommandType
479 aData.nCommandType = -1;
480 pTemp = FindDSData(aData, false);
481 if(pTemp)
482 *pTemp = *m_pImpl->pMergeData;
483 else
484 {
485 m_DataSourceParams.push_back(std::make_unique<SwDSParam>(*m_pImpl->pMergeData));
486 try
487 {
488 uno::Reference<lang::XComponent> xComponent(m_DataSourceParams.back()->xConnection, uno::UNO_QUERY);
489 if(xComponent.is())
490 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
491 }
492 catch(const uno::Exception&)
493 {
494 }
495 }
496 }
497 if(!m_pImpl->pMergeData->xConnection.is())
498 m_pImpl->pMergeData->xConnection = xConnection;
499 // add an XEventListener
500
501 lcl_ToNextRecord(m_pImpl->pMergeData.get(), SwDBNextRecord::FIRST);
502
503 uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection,aData.sDataSource);
504
505 lcl_InitNumberFormatter(*m_pImpl->pMergeData, xSource);
506
507 pWorkShell->ChgDBData(aData);
508 m_bInMerge = true;
509
510 if (IsInitDBFields())
511 {
512 // with database fields without DB-Name, use DB-Name from Doc
513 std::vector<OUString> aDBNames;
514 aDBNames.emplace_back();
515 SwDBData aInsertData = pWorkShell->GetDBData();
516 OUString sDBName = aInsertData.sDataSource
517 + OUStringChar(DB_DELIMu'\x00ff') + aInsertData.sCommand
518 + OUStringChar(DB_DELIMu'\x00ff')
519 + OUString::number(aInsertData.nCommandType);
520 pWorkShell->ChangeDBFields( aDBNames, sDBName);
521 SetInitDBFields(false);
522 }
523
524 bool bRet = true;
525 switch(rMergeDesc.nMergeType)
526 {
527 case DBMGR_MERGE:
528 pWorkShell->StartAllAction();
529 pWorkShell->SwViewShell::UpdateFields( true );
530 pWorkShell->SetModified();
531 pWorkShell->EndAllAction();
532 break;
533
534 case DBMGR_MERGE_PRINTER:
535 case DBMGR_MERGE_EMAIL:
536 case DBMGR_MERGE_FILE:
537 case DBMGR_MERGE_SHELL:
538 // save files and send them as e-Mail if required
539 bRet = MergeMailFiles(pWorkShell, rMergeDesc);
540 break;
541
542 default:
543 // insert selected entries
544 // (was: InsertRecord)
545 ImportFromConnection(pWorkShell);
546 break;
547 }
548
549 m_pImpl->pMergeData.reset();
550
551 if( xWorkObjSh.Is() )
552 {
553 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
554 xWorkObjSh->DoClose();
555 }
556
557 m_bInMerge = false;
558
559 return bRet;
560}
561
562void SwDBManager::ImportFromConnection( SwWrtShell* pSh )
563{
564 if(!m_pImpl->pMergeData || m_pImpl->pMergeData->bEndOfDB)
565 return;
566
567 pSh->StartAllAction();
568 pSh->StartUndo();
569 bool bGroupUndo(pSh->DoesGroupUndo());
570 pSh->DoGroupUndo(false);
571
572 if( pSh->HasSelection() )
573 pSh->DelRight();
574
575 std::unique_ptr<SwWait> pWait;
576
577 {
578 sal_uLong i = 0;
579 do {
580
581 ImportDBEntry(pSh);
582 if( 10 == ++i )
583 pWait.reset(new SwWait( *pSh->GetView().GetDocShell(), true));
584
585 } while(ToNextMergeRecord());
586 }
587
588 pSh->DoGroupUndo(bGroupUndo);
589 pSh->EndUndo();
590 pSh->EndAllAction();
591}
592
593void SwDBManager::ImportDBEntry(SwWrtShell* pSh)
594{
595 if(!m_pImpl->pMergeData || m_pImpl->pMergeData->bEndOfDB)
596 return;
597
598 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
599 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
600 OUStringBuffer sStr;
601 uno::Sequence<OUString> aColNames = xCols->getElementNames();
602 const OUString* pColNames = aColNames.getConstArray();
603 long nLength = aColNames.getLength();
604 for(long i = 0; i < nLength; i++)
605 {
606 uno::Any aCol = xCols->getByName(pColNames[i]);
607 uno::Reference< beans::XPropertySet > xColumnProp;
608 aCol >>= xColumnProp;
609 SwDBFormatData aDBFormat;
610 sStr.append(GetDBField( xColumnProp, aDBFormat));
611 if (i < nLength - 1)
612 sStr.append("\t");
613 }
614 pSh->SwEditShell::Insert2(sStr.makeStringAndClear());
615 pSh->SwFEShell::SplitNode(); // line feed
616}
617
618bool SwDBManager::GetTableNames(weld::ComboBox& rBox, const OUString& rDBName)
619{
620 bool bRet = false;
621 OUString sOldTableName(rBox.get_active_text());
622 rBox.clear();
623 SwDSParam* pParam = FindDSConnection(rDBName, false);
624 uno::Reference< sdbc::XConnection> xConnection;
625 if (pParam && pParam->xConnection.is())
626 xConnection = pParam->xConnection;
627 else
628 {
629 if ( !rDBName.isEmpty() )
630 xConnection = RegisterConnection( rDBName );
631 }
632 if (xConnection.is())
633 {
634 uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY);
635 if(xTSupplier.is())
636 {
637 uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
638 const uno::Sequence<OUString> aTables = xTables->getElementNames();
639 for (const OUString& rTable : aTables)
640 rBox.append("0", rTable);
641 }
642 uno::Reference<sdb::XQueriesSupplier> xQSupplier(xConnection, uno::UNO_QUERY);
643 if(xQSupplier.is())
644 {
645 uno::Reference<container::XNameAccess> xQueries = xQSupplier->getQueries();
646 const uno::Sequence<OUString> aQueries = xQueries->getElementNames();
647 for (const OUString& rQuery : aQueries)
648 rBox.append("1", rQuery);
649 }
650 if (!sOldTableName.isEmpty())
651 rBox.set_active_text(sOldTableName);
652 bRet = true;
653 }
654 return bRet;
655}
656
657// fill Listbox with column names of a database
658void SwDBManager::GetColumnNames(weld::ComboBox& rBox,
659 const OUString& rDBName, const OUString& rTableName)
660{
661 SwDBData aData;
662 aData.sDataSource = rDBName;
663 aData.sCommand = rTableName;
664 aData.nCommandType = -1;
665 SwDSParam* pParam = FindDSData(aData, false);
666 uno::Reference< sdbc::XConnection> xConnection;
667 if(pParam && pParam->xConnection.is())
668 xConnection = pParam->xConnection;
669 else
670 {
671 xConnection = RegisterConnection( rDBName );
672 }
673 GetColumnNames(rBox, xConnection, rTableName);
674}
675
676void SwDBManager::GetColumnNames(weld::ComboBox& rBox,
677 uno::Reference< sdbc::XConnection> const & xConnection,
678 const OUString& rTableName)
679{
680 rBox.clear();
681 uno::Reference< sdbcx::XColumnsSupplier> xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
682 if(xColsSupp.is())
683 {
684 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
685 const uno::Sequence<OUString> aColNames = xCols->getElementNames();
686 for (const OUString& rColName : aColNames)
687 {
688 rBox.append_text(rColName);
689 }
690 ::comphelper::disposeComponent( xColsSupp );
691 }
692}
693
694SwDBManager::SwDBManager(SwDoc* pDoc)
695 : m_aMergeStatus( MergeStatus::Ok )
696 , m_bInitDBFields(false)
697 , m_bInMerge(false)
698 , m_bMergeSilent(false)
699 , m_pImpl(new SwDBManager_Impl(*this))
700 , m_pMergeEvtSrc(nullptr)
701 , m_pDoc(pDoc)
702{
703}
704
705SwDBManager::~SwDBManager() COVERITY_NOEXCEPT_FALSE
706{
707 RevokeLastRegistrations();
708
709 // copy required, m_DataSourceParams can be modified while disposing components
710 std::vector<uno::Reference<sdbc::XConnection>> aCopiedConnections;
711 for (const auto & pParam : m_DataSourceParams)
712 {
713 if(pParam->xConnection.is())
714 {
715 aCopiedConnections.push_back(pParam->xConnection);
716 }
717 }
718 for (const auto & xConnection : aCopiedConnections)
719 {
720 try
721 {
722 uno::Reference<lang::XComponent> xComp(xConnection, uno::UNO_QUERY);
723 if(xComp.is())
724 xComp->dispose();
725 }
726 catch(const uno::RuntimeException&)
727 {
728 //may be disposed already since multiple entries may have used the same connection
729 }
730 }
731}
732
733static void lcl_RemoveSectionLinks( SwWrtShell& rWorkShell )
734{
735 //reset all links of the sections of synchronized labels
736 size_t nSections = rWorkShell.GetSectionFormatCount();
737 for (size_t nSection = 0; nSection < nSections; ++nSection)
738 {
739 SwSectionData aSectionData( *rWorkShell.GetSectionFormat( nSection ).GetSection() );
740 if( aSectionData.GetType() == SectionType::FileLink )
741 {
742 aSectionData.SetType( SectionType::Content );
743 aSectionData.SetLinkFileName( OUString() );
744 rWorkShell.UpdateSection( nSection, aSectionData );
745 }
746 }
747 rWorkShell.SetLabelDoc( false );
748}
749
750static void lcl_SaveDebugDoc( SfxObjectShell *xTargetDocShell,
751 const char *name, int no = 0 )
752{
753 static OUString sTempDirURL;
754 if( sTempDirURL.isEmpty() )
755 {
756 SvtPathOptions aPathOpt;
757 utl::TempFile aTempDir( &aPathOpt.GetTempPath(), true );
758 if( aTempDir.IsValid() )
759 {
760 INetURLObject aTempDirURL( aTempDir.GetURL() );
761 sTempDirURL = aTempDirURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
762 SAL_INFO( "sw.mailmerge", "Dump directory: " << sTempDirURL )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Dump directory: " <<
sTempDirURL) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Dump directory: " << sTempDirURL
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Dump directory: " << sTempDirURL; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Dump directory: " << sTempDirURL) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Dump directory: " << sTempDirURL
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Dump directory: " << sTempDirURL; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "762" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
763 }
764 }
765 if( sTempDirURL.isEmpty() )
766 return;
767
768 const OUString sExt( ".odt" );
769 OUString basename = OUString::createFromAscii( name );
770 if (no > 0)
771 basename += OUString::number(no) + "-";
772 // aTempFile is not deleted, but that seems to be intentional
773 utl::TempFile aTempFile( basename, true, &sExt, &sTempDirURL );
774 INetURLObject aTempFileURL( aTempFile.GetURL() );
775 auto pDstMed = std::make_unique<SfxMedium>(
776 aTempFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
777 StreamMode::STD_READWRITE );
778 bool bAnyError = !xTargetDocShell->DoSaveAs( *pDstMed );
779 // xObjectShell->DoSaveCompleted crashes the mail merge unit tests, so skip it
780 bAnyError |= (ERRCODE_NONEErrCode(0) != xTargetDocShell->GetError());
781 if( bAnyError )
782 SAL_WARN( "sw.mailmerge", "Error saving: " << aTempFile.GetURL() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Error saving: " <<
aTempFile.GetURL()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Error saving: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Error saving: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Error saving: " << aTempFile.GetURL()) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Error saving: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Error saving: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "782" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
783 else
784 SAL_INFO( "sw.mailmerge", "Saved doc as: " << aTempFile.GetURL() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Saved doc as: " <<
aTempFile.GetURL()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Saved doc as: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Saved doc as: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Saved doc as: " << aTempFile.GetURL()) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Saved doc as: " << aTempFile.GetURL
()), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Saved doc as: " << aTempFile.GetURL(); ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "784" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
785}
786
787static bool lcl_SaveDoc(
788 const INetURLObject* pFileURL,
789 const std::shared_ptr<const SfxFilter>& pStoreToFilter,
790 const OUString* pStoreToFilterOptions,
791 const uno::Sequence< beans::PropertyValue >* pSaveToFilterData,
792 const bool bIsPDFexport,
793 SfxObjectShell* xObjectShell,
794 SwWrtShell& rWorkShell,
795 OUString * const decodedURL = nullptr )
796{
797 OUString url = pFileURL->GetMainURL( INetURLObject::DecodeMechanism::NONE );
798 if( decodedURL )
799 (*decodedURL) = url;
800
801 SfxMedium* pDstMed = new SfxMedium( url, StreamMode::STD_READWRITE );
802 pDstMed->SetFilter( pStoreToFilter );
803 if( pDstMed->GetItemSet() )
804 {
805 if( pStoreToFilterOptions )
806 pDstMed->GetItemSet()->Put( SfxStringItem(SID_FILE_FILTEROPTIONS(5000 + 527),
807 *pStoreToFilterOptions));
808 if( pSaveToFilterData->hasElements() )
809 pDstMed->GetItemSet()->Put( SfxUnoAnyItem(SID_FILTER_DATA(5000 + 1375),
810 uno::makeAny(*pSaveToFilterData)));
811 }
812
813 // convert fields to text if we are exporting to PDF.
814 // this prevents a second merge while updating the fields
815 // in SwXTextDocument::getRendererCount()
816 if( bIsPDFexport )
817 rWorkShell.ConvertFieldsToText();
818
819 bool bAnyError = !xObjectShell->DoSaveAs(*pDstMed);
820 // Actually this should be a bool... so in case of email and individual
821 // files, where this is set, we skip the recently used handling
822 bAnyError |= !xObjectShell->DoSaveCompleted( pDstMed, !decodedURL );
823 bAnyError |= (ERRCODE_NONEErrCode(0) != xObjectShell->GetError());
824 if( bAnyError )
825 {
826 // error message ??
827 ErrorHandler::HandleError( xObjectShell->GetError() );
828 }
829 return !bAnyError;
830}
831
832static void lcl_PreparePrinterOptions(
833 const uno::Sequence< beans::PropertyValue >& rInPrintOptions,
834 uno::Sequence< beans::PropertyValue >& rOutPrintOptions)
835{
836 // printing should be done synchronously otherwise the document
837 // might already become invalid during the process
838
839 const sal_Int32 nOffset = 1;
840 rOutPrintOptions.realloc( nOffset );
841 rOutPrintOptions[ 0 ].Name = "Wait";
842 rOutPrintOptions[ 0 ].Value <<= true;
843
844 // copy print options
845 sal_Int32 nIndex = nOffset;
846 for( const beans::PropertyValue& rOption : rInPrintOptions)
847 {
848 if( rOption.Name == "CopyCount" || rOption.Name == "FileName"
849 || rOption.Name == "Collate" || rOption.Name == "Pages"
850 || rOption.Name == "Wait" || rOption.Name == "PrinterName" )
851 {
852 // add an option
853 rOutPrintOptions.realloc( nIndex + 1 );
854 rOutPrintOptions[ nIndex ].Name = rOption.Name;
855 rOutPrintOptions[ nIndex++ ].Value = rOption.Value ;
856 }
857 }
858}
859
860static void lcl_PrepareSaveFilterDataOptions(
861 const uno::Sequence< beans::PropertyValue >& rInSaveFilterDataptions,
862 uno::Sequence< beans::PropertyValue >& rOutSaveFilterDataOptions,
863 const OUString& sPassword)
864{
865 const sal_Int32 nOffset = 2;
866 rOutSaveFilterDataOptions.realloc( nOffset );
867 rOutSaveFilterDataOptions[ 0 ].Name = "EncryptFile";
868 rOutSaveFilterDataOptions[ 0 ].Value <<= true;
869 rOutSaveFilterDataOptions[ 1 ].Name = "DocumentOpenPassword";
870 rOutSaveFilterDataOptions[ 1 ].Value <<= sPassword;
871
872 // copy other options
873 sal_Int32 nIndex = nOffset;
874 for( const beans::PropertyValue& rOption : rInSaveFilterDataptions)
875 {
876 rOutSaveFilterDataOptions.realloc( nIndex + 1 );
877 rOutSaveFilterDataOptions[ nIndex ].Name = rOption.Name;
878 rOutSaveFilterDataOptions[ nIndex++ ].Value = rOption.Value ;
879 }
880
881}
882
883
884static SfxObjectShell* lcl_CreateWorkingDocument(
885 // input
886 const WorkingDocType aType, const SwWrtShell &rSourceWrtShell,
887 // optional input
888 const vcl::Window *pSourceWindow,
889 // optional in and output to swap the DB manager
890 SwDBManager** const ppDBManager,
891 // optional output
892 SwView** const pView, SwWrtShell** const pWrtShell, SwDoc** const pDoc )
893{
894 const SwDoc *pSourceDoc = rSourceWrtShell.GetDoc();
895 SfxObjectShellRef xWorkObjectShell = pSourceDoc->CreateCopy( true, (aType == WorkingDocType::TARGET) );
896 SfxViewFrame* pWorkFrame = SfxViewFrame::LoadHiddenDocument( *xWorkObjectShell, SFX_INTERFACE_NONE );
897
898 if( pSourceWindow
8.1
'pSourceWindow' is null
8.1
'pSourceWindow' is null
)
9
Taking false branch
899 {
900 // the created window has to be located at the same position as the source window
901 vcl::Window& rTargetWindow = pWorkFrame->GetFrame().GetWindow();
902 rTargetWindow.SetPosPixel( pSourceWindow->GetPosPixel() );
903 }
904
905 SwView* pWorkView = static_cast< SwView* >( pWorkFrame->GetViewShell() );
906 SwWrtShell* pWorkWrtShell = pWorkView->GetWrtShellPtr();
907 pWorkWrtShell->GetViewOptions()->SetIdle( false );
908 pWorkView->AttrChangedNotify(nullptr);// in order for SelectShell to be called
909 SwDoc* pWorkDoc = pWorkWrtShell->GetDoc();
910 pWorkDoc->GetIDocumentUndoRedo().DoUndo( false );
911 pWorkDoc->ReplaceDocumentProperties( *pSourceDoc );
912
913 // import print settings
914 const SwPrintData &rPrintData = pSourceDoc->getIDocumentDeviceAccess().getPrintData();
915 pWorkDoc->getIDocumentDeviceAccess().setPrintData(rPrintData);
916 const JobSetup *pJobSetup = pSourceDoc->getIDocumentDeviceAccess().getJobsetup();
917 if (pJobSetup)
10
Assuming 'pJobSetup' is null
11
Taking false branch
918 pWorkDoc->getIDocumentDeviceAccess().setJobsetup(*pJobSetup);
919
920 if( aType
11.1
'aType' is not equal to TARGET
11.1
'aType' is not equal to TARGET
== WorkingDocType::TARGET )
12
Taking false branch
921 {
922 assert( !ppDBManager )(static_cast <bool> (!ppDBManager) ? void (0) : __assert_fail
("!ppDBManager", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 922, __extension__ __PRETTY_FUNCTION__))
;
923 pWorkDoc->SetInMailMerge( true );
924 pWorkWrtShell->SetLabelDoc( false );
925 }
926 else
927 {
928 // We have to swap the DBmanager of the new doc, so we also need input
929 assert(ppDBManager && *ppDBManager)(static_cast <bool> (ppDBManager && *ppDBManager
) ? void (0) : __assert_fail ("ppDBManager && *ppDBManager"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 929, __extension__ __PRETTY_FUNCTION__))
;
13
'?' condition is true
930 SwDBManager *pWorkDBManager = pWorkDoc->GetDBManager();
931 pWorkDoc->SetDBManager( *ppDBManager );
932 *ppDBManager = pWorkDBManager;
933
934 if( aType
13.1
'aType' is equal to SOURCE
13.1
'aType' is equal to SOURCE
== WorkingDocType::SOURCE )
14
Taking true branch
935 {
936 // the GetDBData call constructs the data, if it's missing - kind of const...
937 pWorkWrtShell->ChgDBData( const_cast<SwDoc*>(pSourceDoc)->GetDBData() );
938 // some DocumentSettings are currently not copied by SwDoc::CreateCopy
939 pWorkWrtShell->SetLabelDoc( rSourceWrtShell.IsLabelDoc() );
940 pWorkDoc->getIDocumentState().ResetModified();
941 }
942 else
943 pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks();
944 }
945
946 if( pView
14.1
'pView' is null
14.1
'pView' is null
) *pView = pWorkView;
15
Taking false branch
947 if( pWrtShell
15.1
'pWrtShell' is non-null
15.1
'pWrtShell' is non-null
) *pWrtShell = pWorkWrtShell;
16
Taking true branch
948 if( pDoc
16.1
'pDoc' is non-null
16.1
'pDoc' is non-null
) *pDoc = pWorkDoc;
17
Taking true branch
949
950 return xWorkObjectShell.get();
18
Calling '~SvRef'
26
Returning from '~SvRef'
27
Use of memory after it is freed
951}
952
953static SwMailMessage* lcl_CreateMailFromDoc(
954 const SwMergeDescriptor &rMergeDescriptor,
955 const OUString &sFileURL, const OUString &sMailRecipient,
956 const OUString &sMailBodyMimeType, rtl_TextEncoding sMailEncoding,
957 const OUString &sAttachmentMimeType )
958{
959 SwMailMessage* pMessage = new SwMailMessage;
960 if( rMergeDescriptor.pMailMergeConfigItem->IsMailReplyTo() )
961 pMessage->setReplyToAddress(rMergeDescriptor.pMailMergeConfigItem->GetMailReplyTo());
962 pMessage->addRecipient( sMailRecipient );
963 pMessage->SetSenderAddress( rMergeDescriptor.pMailMergeConfigItem->GetMailAddress() );
964
965 OUStringBuffer sBody;
966 if( rMergeDescriptor.bSendAsAttachment )
967 {
968 sBody = rMergeDescriptor.sMailBody;
969 mail::MailAttachment aAttach;
970 aAttach.Data = new SwMailTransferable( sFileURL,
971 rMergeDescriptor.sAttachmentName, sAttachmentMimeType );
972 aAttach.ReadableName = rMergeDescriptor.sAttachmentName;
973 pMessage->addAttachment( aAttach );
974 }
975 else
976 {
977 //read in the temporary file and use it as mail body
978 SfxMedium aMedium( sFileURL, StreamMode::READ );
979 SvStream* pInStream = aMedium.GetInStream();
980 assert( pInStream && "no output file created?" )(static_cast <bool> (pInStream && "no output file created?"
) ? void (0) : __assert_fail ("pInStream && \"no output file created?\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 980, __extension__ __PRETTY_FUNCTION__))
;
981 if( !pInStream )
982 return pMessage;
983
984 pInStream->SetStreamCharSet( sMailEncoding );
985 OString sLine;
986 while ( pInStream->ReadLine( sLine ) )
987 {
988 sBody.append(OStringToOUString( sLine, sMailEncoding ));
989 sBody.append("\n");
990 }
991 }
992 pMessage->setSubject( rMergeDescriptor.sSubject );
993 uno::Reference< datatransfer::XTransferable> xBody =
994 new SwMailTransferable( sBody.makeStringAndClear(), sMailBodyMimeType );
995 pMessage->setBody( xBody );
996
997 for( const OUString& sCcRecipient : rMergeDescriptor.aCopiesTo )
998 pMessage->addCcRecipient( sCcRecipient );
999 for( const OUString& sBccRecipient : rMergeDescriptor.aBlindCopiesTo )
1000 pMessage->addBccRecipient( sBccRecipient );
1001
1002 return pMessage;
1003}
1004
1005class SwDBManager::MailDispatcherListener_Impl : public IMailDispatcherListener
1006{
1007 SwDBManager &m_rDBManager;
1008
1009public:
1010 explicit MailDispatcherListener_Impl( SwDBManager &rDBManager )
1011 : m_rDBManager( rDBManager ) {}
1012
1013 virtual void idle() override {}
1014
1015 virtual void mailDelivered( uno::Reference< mail::XMailMessage> xMessage ) override
1016 {
1017 osl::MutexGuard aGuard( m_rDBManager.m_pImpl->m_aAllEmailSendMutex );
1018 if ( m_rDBManager.m_pImpl->m_xLastMessage == xMessage )
1019 m_rDBManager.m_pImpl->m_xLastMessage.clear();
1020 }
1021
1022 virtual void mailDeliveryError( ::rtl::Reference<MailDispatcher> xMailDispatcher,
1023 uno::Reference< mail::XMailMessage>, const OUString& ) override
1024 {
1025 osl::MutexGuard aGuard( m_rDBManager.m_pImpl->m_aAllEmailSendMutex );
1026 m_rDBManager.m_aMergeStatus = MergeStatus::Error;
1027 m_rDBManager.m_pImpl->m_xLastMessage.clear();
1028 xMailDispatcher->stop();
1029 }
1030};
1031
1032/**
1033 * Please have a look at the README in the same directory, before you make
1034 * larger changes in this function!
1035 */
1036bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell,
1037 const SwMergeDescriptor& rMergeDescriptor)
1038{
1039 // deconstruct mail merge type for better readability.
1040 // uppercase naming is intentional!
1041 const bool bMT_EMAIL = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL;
1042 const bool bMT_SHELL = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL;
1043 const bool bMT_PRINTER = rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER;
1044 const bool bMT_FILE = rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE;
1045
1046 //check if the doc is synchronized and contains at least one linked section
1047 const bool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFormatCount() > 1;
1048 const bool bNeedsTempFiles = ( bMT_EMAIL || bMT_FILE );
1049 const bool bIsMergeSilent = IsMergeSilent();
1050
1051 bool bCheckSingleFile_ = rMergeDescriptor.bCreateSingleFile;
1052 OUString sPrefix_ = rMergeDescriptor.sPrefix;
1053 if( bMT_EMAIL )
1054 {
1055 assert( !rMergeDescriptor.bPrefixIsFilename )(static_cast <bool> (!rMergeDescriptor.bPrefixIsFilename
) ? void (0) : __assert_fail ("!rMergeDescriptor.bPrefixIsFilename"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1055, __extension__ __PRETTY_FUNCTION__))
;
1056 assert(!bCheckSingleFile_)(static_cast <bool> (!bCheckSingleFile_) ? void (0) : __assert_fail
("!bCheckSingleFile_", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1056, __extension__ __PRETTY_FUNCTION__))
;
1057 bCheckSingleFile_ = false;
1058 }
1059 else if( bMT_SHELL || bMT_PRINTER )
1060 {
1061 assert(bCheckSingleFile_)(static_cast <bool> (bCheckSingleFile_) ? void (0) : __assert_fail
("bCheckSingleFile_", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1061, __extension__ __PRETTY_FUNCTION__))
;
1062 bCheckSingleFile_ = true;
1063 assert(sPrefix_.isEmpty())(static_cast <bool> (sPrefix_.isEmpty()) ? void (0) : __assert_fail
("sPrefix_.isEmpty()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1063, __extension__ __PRETTY_FUNCTION__))
;
1064 sPrefix_.clear();
1065 }
1066 const bool bCreateSingleFile = bCheckSingleFile_;
1067 const OUString sDescriptorPrefix = sPrefix_;
1068
1069 // Setup for dumping debugging documents
1070 static const sal_Int32 nMaxDumpDocs = []() {
1071 if (const char* sEnv = getenv("SW_DEBUG_MAILMERGE_DOCS"))
1072 return OUString(sEnv, strlen(sEnv), osl_getThreadTextEncoding()).toInt32();
1073 else
1074 return sal_Int32(0);
1075 }();
1076
1077 ::rtl::Reference< MailDispatcher > xMailDispatcher;
1078 ::rtl::Reference< IMailDispatcherListener > xMailListener;
1079 OUString sMailBodyMimeType;
1080 rtl_TextEncoding sMailEncoding = ::osl_getThreadTextEncoding();
1081
1082 uno::Reference< beans::XPropertySet > xColumnProp;
1083 uno::Reference< beans::XPropertySet > xPasswordColumnProp;
1084
1085 // Check for (mandatory) email or (optional) filename column
1086 SwDBFormatData aColumnDBFormat;
1087 bool bColumnName = !rMergeDescriptor.sDBcolumn.isEmpty();
1088 bool bPasswordColumnName = !rMergeDescriptor.sDBPasswordColumn.isEmpty();
1089
1090 if( ! bColumnName )
1091 {
1092 if( bMT_EMAIL )
1093 return false;
1094 }
1095 else
1096 {
1097 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
1098 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1099 if( !xCols->hasByName( rMergeDescriptor.sDBcolumn ) )
1100 return false;
1101 uno::Any aCol = xCols->getByName( rMergeDescriptor.sDBcolumn );
1102 aCol >>= xColumnProp;
1103
1104 if(bPasswordColumnName)
1105 {
1106 aCol = xCols->getByName( rMergeDescriptor.sDBPasswordColumn );
1107 aCol >>= xPasswordColumnProp;
1108 }
1109
1110 aColumnDBFormat.xFormatter = m_pImpl->pMergeData->xFormatter;
1111 aColumnDBFormat.aNullDate = m_pImpl->pMergeData->aNullDate;
1112
1113 if( bMT_EMAIL )
1114 {
1115 // Reset internal mail accounting data
1116 m_pImpl->m_xLastMessage.clear();
1117
1118 xMailDispatcher.set( new MailDispatcher(rMergeDescriptor.xSmtpServer) );
1119 xMailListener = new MailDispatcherListener_Impl( *this );
1120 xMailDispatcher->addListener( xMailListener );
1121 if(!rMergeDescriptor.bSendAsAttachment && rMergeDescriptor.bSendAsHTML)
1122 {
1123 sMailBodyMimeType = "text/html; charset=" + OUString::createFromAscii(
1124 rtl_getBestMimeCharsetFromTextEncoding( sMailEncoding ));
1125 SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
1126 sMailEncoding = rHtmlOptions.GetTextEncoding();
1127 }
1128 else
1129 sMailBodyMimeType = "text/plain; charset=UTF-8; format=flowed";
1130 }
1131 }
1132
1133 SwDocShell *pSourceDocSh = pSourceShell->GetView().GetDocShell();
1134
1135 // setup the output format
1136 std::shared_ptr<const SfxFilter> pStoreToFilter = SwIoSystem::GetFileFilter(
1137 pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE));
1138 SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer();
1139 const OUString* pStoreToFilterOptions = nullptr;
1140
1141 // if a save_to filter is set then use it - otherwise use the default
1142 if( bMT_EMAIL && !rMergeDescriptor.bSendAsAttachment )
1143 {
1144 OUString sExtension = rMergeDescriptor.bSendAsHTML ? OUString("html") : OUString("txt");
1145 pStoreToFilter = pFilterContainer->GetFilter4Extension(sExtension, SfxFilterFlags::EXPORT);
1146 }
1147 else if( !rMergeDescriptor.sSaveToFilter.isEmpty())
1148 {
1149 std::shared_ptr<const SfxFilter> pFilter =
1150 pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter );
1151 if(pFilter)
1152 {
1153 pStoreToFilter = pFilter;
1154 if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty())
1155 pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions;
1156 }
1157 }
1158 const bool bIsPDFexport = pStoreToFilter && pStoreToFilter->GetFilterName() == "writer_pdf_Export";
1159
1160 m_aMergeStatus = MergeStatus::Ok;
1161
1162 // in case of creating a single resulting file this has to be created here
1163 SwView* pTargetView = rMergeDescriptor.pMailMergeConfigItem ?
1164 rMergeDescriptor.pMailMergeConfigItem->GetTargetView() : nullptr;
1165 SwWrtShell* pTargetShell = nullptr;
1166 SwDoc* pTargetDoc = nullptr;
1167 SfxObjectShellRef xTargetDocShell;
1168
1169 std::unique_ptr< utl::TempFile > aTempFile;
1170 sal_uInt16 nStartingPageNo = 0;
1171
1172 std::shared_ptr<weld::GenericDialogController> xProgressDlg;
1173
1174 try
1175 {
1176 vcl::Window *pSourceWindow = nullptr;
1177 if( !bIsMergeSilent )
1178 {
1179 // construct the process dialog
1180 pSourceWindow = &pSourceShell->GetView().GetEditWin();
1181 if (!bMT_PRINTER)
1182 xProgressDlg = std::make_shared<CreateMonitor>(pSourceWindow->GetFrameWeld());
1183 else
1184 {
1185 xProgressDlg = std::make_shared<PrintMonitor>(pSourceWindow->GetFrameWeld());
1186 static_cast<PrintMonitor*>(xProgressDlg.get())->set_title(
1187 pSourceDocSh->GetTitle(22));
1188 }
1189 weld::DialogController::runAsync(xProgressDlg, [this, &xProgressDlg](sal_Int32 nResult){
1190 if (nResult == RET_CANCEL)
1191 MergeCancel();
1192 xProgressDlg.reset();
1193 });
1194
1195 Application::Reschedule( true );
1196 }
1197
1198 if( bCreateSingleFile && !pTargetView )
1199 {
1200 // create a target docshell to put the merged document into
1201 xTargetDocShell = lcl_CreateWorkingDocument( WorkingDocType::TARGET,
1202 *pSourceShell, bMT_SHELL ? pSourceWindow : nullptr,
1203 nullptr, &pTargetView, &pTargetShell, &pTargetDoc );
1204
1205 if (nMaxDumpDocs)
1206 lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
1207 }
1208 else if( pTargetView )
1209 {
1210 pTargetShell = pTargetView->GetWrtShellPtr();
1211 pTargetDoc = pTargetShell->GetDoc();
1212 xTargetDocShell = pTargetView->GetDocShell();
1213 }
1214
1215 if( bCreateSingleFile )
1216 {
1217 // determine the page style and number used at the start of the source document
1218 pSourceShell->SttEndDoc(true);
1219 nStartingPageNo = pSourceShell->GetVirtPageNum();
1220 }
1221
1222 // Progress, to prohibit KeyInputs
1223 SfxProgress aProgress(pSourceDocSh, OUString(), 1);
1224
1225 // lock all dispatchers
1226 SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
1227 while (pViewFrame)
1228 {
1229 pViewFrame->GetDispatcher()->Lock(true);
1230 pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
1231 }
1232
1233 sal_Int32 nDocNo = 1;
1234
1235 // For single file mode, the number of pages in the target document so far, which is used
1236 // by AppendDoc() to adjust position of page-bound objects. Getting this information directly
1237 // from the target doc would require repeated layouts of the doc, which is expensive, but
1238 // it can be manually computed from the source documents (for which we do layouts, so the page
1239 // count is known, and there is a blank page between each of them in the target document).
1240 int targetDocPageCount = 0;
1241
1242 if( !bIsMergeSilent && !bMT_PRINTER )
1243 {
1244 sal_Int32 nRecordCount = 1;
1245 lcl_getCountFromResultSet( nRecordCount, m_pImpl->pMergeData.get() );
1246
1247 // Synchronized docs don't auto-advance the record set, but there is a
1248 // "security" check, which will always advance the record set, if there
1249 // is no "next record" field in a synchronized doc => nRecordPerDoc > 0
1250 sal_Int32 nRecordPerDoc = pSourceShell->GetDoc()
1251 ->getIDocumentFieldsAccess().GetRecordsPerDocument();
1252 if ( bSynchronizedDoc && (nRecordPerDoc > 1) )
1253 --nRecordPerDoc;
1254 assert( nRecordPerDoc > 0 )(static_cast <bool> (nRecordPerDoc > 0) ? void (0) :
__assert_fail ("nRecordPerDoc > 0", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1254, __extension__ __PRETTY_FUNCTION__))
;
1255
1256 sal_Int32 nMaxDocs = nRecordCount / nRecordPerDoc;
1257 if ( 0 != nRecordCount % nRecordPerDoc )
1258 nMaxDocs += 1;
1259 static_cast<CreateMonitor*>(xProgressDlg.get())->SetTotalCount(nMaxDocs);
1260 }
1261
1262 long nStartRow, nEndRow;
1263 bool bFreezedLayouts = false;
1264 // to collect temporary email files
1265 std::vector< OUString> aFilesToRemove;
1266
1267 // The SfxObjectShell will be closed explicitly later but
1268 // it is more safe to use SfxObjectShellLock here
1269 SfxObjectShellLock xWorkDocSh;
1270 SwView* pWorkView = nullptr;
1271 SwDoc* pWorkDoc = nullptr;
1272 SwDBManager* pWorkDocOrigDBManager = nullptr;
1273 SwWrtShell* pWorkShell = nullptr;
1274 bool bWorkDocInitialized = false;
1275
1276 do
1277 {
1278 nStartRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
1279
1280 OUString sColumnData;
1281
1282 // Read the indicated data column, which should contain a valid mail
1283 // address or an optional file name
1284 if( bMT_EMAIL || bColumnName )
1285 {
1286 sColumnData = GetDBField( xColumnProp, aColumnDBFormat );
1287 }
1288
1289 // create a new temporary file name - only done once in case of bCreateSingleFile
1290 if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile ))
1291 {
1292 OUString sPrefix = sDescriptorPrefix;
1293 OUString sLeading;
1294
1295 //#i97667# if the name is from a database field then it will be used _as is_
1296 if( bColumnName && !bMT_EMAIL )
1297 {
1298 if (!sColumnData.isEmpty())
1299 sLeading = sColumnData;
1300 else
1301 sLeading = "_";
1302 }
1303 else
1304 {
1305 INetURLObject aEntry( sPrefix );
1306 sLeading = aEntry.GetBase();
1307 aEntry.removeSegment();
1308 sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1309 }
1310
1311 OUString sExt(comphelper::string::stripStart(pStoreToFilter->GetDefaultExtension(), '*'));
1312 aTempFile.reset( new utl::TempFile(sLeading, sColumnData.isEmpty(), &sExt, &sPrefix, true) );
1313 if( !aTempFile->IsValid() )
1314 {
1315 ErrorHandler::HandleError( ERRCODE_IO_NOTSUPPORTEDErrCode( ErrCodeArea::Io, ErrCodeClass::NotSupported, 12 ) );
1316 m_aMergeStatus = MergeStatus::Error;
1317 }
1318 }
1319
1320 uno::Sequence< beans::PropertyValue > aSaveToFilterDataOptions( rMergeDescriptor.aSaveToFilterData );
1321
1322 if( bMT_EMAIL || bPasswordColumnName )
1323 {
1324 OUString sPasswordColumnData = GetDBField( xPasswordColumnProp, aColumnDBFormat );
1325 lcl_PrepareSaveFilterDataOptions( rMergeDescriptor.aSaveToFilterData, aSaveToFilterDataOptions, sPasswordColumnData );
1326 }
1327
1328 if( IsMergeOk() )
1329 {
1330 std::unique_ptr< INetURLObject > aTempFileURL;
1331 if( bNeedsTempFiles )
1332 aTempFileURL.reset( new INetURLObject(aTempFile->GetURL()));
1333 if( !bIsMergeSilent ) {
1334 if( !bMT_PRINTER )
1335 static_cast<CreateMonitor*>(xProgressDlg.get())->SetCurrentPosition(nDocNo);
1336 else {
1337 PrintMonitor *pPrintMonDlg = static_cast<PrintMonitor*>(xProgressDlg.get());
1338 pPrintMonDlg->m_xPrinter->set_label(bNeedsTempFiles
1339 ? aTempFileURL->GetBase() : pSourceDocSh->GetTitle( 2));
1340 OUString sStat = SwResId(STR_STATSTR_LETTERreinterpret_cast<char const *>("STR_STATSTR_LETTER" "\004"
u8"Letter")
) + " " + OUString::number( nDocNo );
1341 pPrintMonDlg->m_xPrintInfo->set_label(sStat);
1342 }
1343 //TODO xProgressDlg->queue_draw();
1344 }
1345
1346 Scheduler::ProcessEventsToIdle();
1347
1348 // Create a copy of the source document and work with that one instead of the source.
1349 // If we're not in the single file mode (which requires modifying the document for the merging),
1350 // it is enough to do this just once. Currently PDF also has to be treated special.
1351 if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport )
1352 {
1353 assert( !xWorkDocSh.Is())(static_cast <bool> (!xWorkDocSh.Is()) ? void (0) : __assert_fail
("!xWorkDocSh.Is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1353, __extension__ __PRETTY_FUNCTION__))
;
1354 pWorkDocOrigDBManager = this;
1355 xWorkDocSh = lcl_CreateWorkingDocument( WorkingDocType::COPY,
1356 *pSourceShell, nullptr, &pWorkDocOrigDBManager,
1357 &pWorkView, &pWorkShell, &pWorkDoc );
1358 if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1359 lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
1360
1361 // #i69458# lock fields to prevent access to the result set while calculating layout
1362 // tdf#92324: and do not unlock: keep document locked during printing to avoid
1363 // ExpFields update during printing, generation of preview, etc.
1364 pWorkShell->LockExpFields();
1365 pWorkShell->CalcLayout();
1366 // tdf#121168: Now force correct page descriptions applied to page frames. Without
1367 // this, e.g., page frames starting with sections could have page descriptions set
1368 // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below.
1369 pWorkShell->GetViewOptions()->SetIdle(true);
1370 for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts())
1371 {
1372 aLayout->FreezeLayout(false);
1373 aLayout->AllCheckPageDescs();
1374 }
1375 }
1376
1377 lcl_emitEvent(SfxEventHintId::SwEventFieldMerge, STR_SW_EVENT_FIELD_MERGE3, xWorkDocSh);
1378
1379 // tdf#92324: Allow ExpFields update only by explicit instruction to avoid
1380 // database cursor movement on any other fields update, for example during
1381 // print preview and other operations
1382 if ( pWorkShell->IsExpFieldsLocked() )
1383 pWorkShell->UnlockExpFields();
1384 pWorkShell->SwViewShell::UpdateFields();
1385 pWorkShell->LockExpFields();
1386
1387 lcl_emitEvent(SfxEventHintId::SwEventFieldMergeFinished, STR_SW_EVENT_FIELD_MERGE_FINISHED4, xWorkDocSh);
1388
1389 // also emit MailMergeEvent on XInterface if possible
1390 const SwXMailMerge *pEvtSrc = GetMailMergeEvtSrc();
1391 if(pEvtSrc)
1392 {
1393 rtl::Reference< SwXMailMerge > xRef(
1394 const_cast<SwXMailMerge*>(pEvtSrc) );
1395 text::MailMergeEvent aEvt( static_cast<text::XMailMergeBroadcaster*>(xRef.get()), xWorkDocSh->GetModel() );
1396 SolarMutexReleaser rel;
1397 xRef->LaunchMailMergeEvent( aEvt );
1398 }
1399
1400 // working copy is merged - prepare final steps depending on merge options
1401
1402 if( bCreateSingleFile )
1403 {
1404 assert( pTargetShell && "no target shell available!" )(static_cast <bool> (pTargetShell && "no target shell available!"
) ? void (0) : __assert_fail ("pTargetShell && \"no target shell available!\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1404, __extension__ __PRETTY_FUNCTION__))
;
1405
1406 // prepare working copy and target to append
1407
1408 pWorkDoc->RemoveInvisibleContent();
1409 // remove of invisible content has influence on page count and so on fields for page count,
1410 // therefore layout has to be updated before fields are converted to text
1411 pWorkShell->CalcLayout();
1412 pWorkShell->ConvertFieldsToText();
1413 pWorkShell->SetNumberingRestart();
1414 if( bSynchronizedDoc )
1415 {
1416 lcl_RemoveSectionLinks( *pWorkShell );
1417 }
1418
1419 if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1420 lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
1421
1422 // append the working document to the target document
1423 if( targetDocPageCount % 2 == 1 )
1424 ++targetDocPageCount; // Docs always start on odd pages (so offset must be even).
1425 SwNodeIndex appendedDocStart = pTargetDoc->AppendDoc( *pWorkDoc,
1426 nStartingPageNo, !bWorkDocInitialized, targetDocPageCount, nDocNo);
1427 targetDocPageCount += pWorkShell->GetPageCnt();
1428
1429 if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
1430 lcl_SaveDebugDoc( xTargetDocShell.get(), "MergeDoc" );
1431
1432 if (bMT_SHELL)
1433 {
1434 SwDocMergeInfo aMergeInfo;
1435 // Name of the mark is actually irrelevant, UNO bookmarks have internals names.
1436 aMergeInfo.startPageInTarget = pTargetDoc->getIDocumentMarkAccess()->makeMark(
1437 appendedDocStart, "", IDocumentMarkAccess::MarkType::UNO_BOOKMARK,
1438 ::sw::mark::InsertMode::New);
1439 aMergeInfo.nDBRow = nStartRow;
1440 rMergeDescriptor.pMailMergeConfigItem->AddMergedDocument( aMergeInfo );
1441 }
1442 }
1443 else
1444 {
1445 assert( bNeedsTempFiles )(static_cast <bool> (bNeedsTempFiles) ? void (0) : __assert_fail
("bNeedsTempFiles", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1445, __extension__ __PRETTY_FUNCTION__))
;
1446 assert( pWorkShell->IsExpFieldsLocked() )(static_cast <bool> (pWorkShell->IsExpFieldsLocked()
) ? void (0) : __assert_fail ("pWorkShell->IsExpFieldsLocked()"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1446, __extension__ __PRETTY_FUNCTION__))
;
1447
1448 // fields are locked, so it's fine to
1449 // restore the old / empty DB manager for save
1450 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1451
1452 // save merged document
1453 OUString sFileURL;
1454 if( !lcl_SaveDoc( aTempFileURL.get(), pStoreToFilter, pStoreToFilterOptions,
1455 &aSaveToFilterDataOptions, bIsPDFexport,
1456 xWorkDocSh, *pWorkShell, &sFileURL ) )
1457 {
1458 m_aMergeStatus = MergeStatus::Error;
1459 }
1460
1461 // back to the MM DB manager
1462 pWorkDoc->SetDBManager( this );
1463
1464 if( bMT_EMAIL && !IsMergeError() )
1465 {
1466 // schedule file for later removal
1467 aFilesToRemove.push_back( sFileURL );
1468
1469 if( !SwMailMergeHelper::CheckMailAddress( sColumnData ) )
1470 {
1471 OSL_FAIL("invalid e-Mail address in database column")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1471" ": "), "%s", "invalid e-Mail address in database column"
); } } while (false)
;
1472 }
1473 else
1474 {
1475 uno::Reference< mail::XMailMessage > xMessage = lcl_CreateMailFromDoc(
1476 rMergeDescriptor, sFileURL, sColumnData, sMailBodyMimeType,
1477 sMailEncoding, pStoreToFilter->GetMimeType() );
1478 if( xMessage.is() )
1479 {
1480 osl::MutexGuard aGuard( m_pImpl->m_aAllEmailSendMutex );
1481 m_pImpl->m_xLastMessage.set( xMessage );
1482 xMailDispatcher->enqueueMailMessage( xMessage );
1483 if( !xMailDispatcher->isStarted() )
1484 xMailDispatcher->start();
1485 }
1486 }
1487 }
1488 }
1489 if( bCreateSingleFile || bIsPDFexport )
1490 {
1491 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1492 xWorkDocSh->DoClose();
1493 xWorkDocSh = nullptr;
1494 }
1495 }
1496
1497 bWorkDocInitialized = true;
1498 nDocNo++;
1499 nEndRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
1500
1501 // Freeze the layouts of the target document after the first inserted
1502 // sub-document, to get the correct PageDesc.
1503 if(!bFreezedLayouts && bCreateSingleFile)
1504 {
1505 for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
1506 aLayout->FreezeLayout(true);
1507 bFreezedLayouts = true;
1508 }
1509 } while( IsMergeOk() &&
1510 ((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord()));
1511
1512 if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() )
1513 {
1514 // Unlock document fields after merge complete
1515 pWorkView->GetWrtShell().UnlockExpFields();
1516 }
1517
1518 if( !bCreateSingleFile )
1519 {
1520 if( bMT_PRINTER )
1521 Printer::FinishPrintJob( pWorkView->GetPrinterController());
1522 if( !bIsPDFexport )
1523 {
1524 pWorkDoc->SetDBManager( pWorkDocOrigDBManager );
1525 xWorkDocSh->DoClose();
1526 }
1527 }
1528 else if( IsMergeOk() ) // && bCreateSingleFile
1529 {
1530 Application::Reschedule( true );
1531
1532 // sw::DocumentLayoutManager::CopyLayoutFormat() did not generate
1533 // unique fly names, do it here once.
1534 pTargetDoc->SetInMailMerge(false);
1535 pTargetDoc->SetAllUniqueFlyNames();
1536
1537 // Unfreeze target document layouts and correct all PageDescs.
1538 SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.pageframe")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "(MergeMailFiles pTargetShell->CalcLayout in"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "(MergeMailFiles pTargetShell->CalcLayout in")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "(MergeMailFiles pTargetShell->CalcLayout in"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "(MergeMailFiles pTargetShell->CalcLayout in"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1538" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1539 pTargetShell->CalcLayout();
1540 SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.pageframe")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "MergeMailFiles pTargetShell->CalcLayout out)"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MergeMailFiles pTargetShell->CalcLayout out)"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "MergeMailFiles pTargetShell->CalcLayout out)"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "MergeMailFiles pTargetShell->CalcLayout out)"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.pageframe"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1540" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1541 pTargetShell->GetViewOptions()->SetIdle( true );
1542 pTargetDoc->GetIDocumentUndoRedo().DoUndo( true );
1543 for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
1544 {
1545 aLayout->FreezeLayout(false);
1546 aLayout->AllCheckPageDescs();
1547 }
1548
1549 Application::Reschedule( true );
1550
1551 if( IsMergeOk() && bMT_FILE )
1552 {
1553 // save merged document
1554 assert( aTempFile )(static_cast <bool> (aTempFile) ? void (0) : __assert_fail
("aTempFile", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1554, __extension__ __PRETTY_FUNCTION__))
;
1555 INetURLObject aTempFileURL;
1556 if (sDescriptorPrefix.isEmpty() || !rMergeDescriptor.bPrefixIsFilename)
1557 aTempFileURL.SetURL( aTempFile->GetURL() );
1558 else
1559 {
1560 aTempFileURL.SetURL(sDescriptorPrefix);
1561 // remove the unneeded temporary file
1562 aTempFile->EnableKillingFile();
1563 }
1564 if( !lcl_SaveDoc( &aTempFileURL, pStoreToFilter,
1565 pStoreToFilterOptions, &rMergeDescriptor.aSaveToFilterData,
1566 bIsPDFexport, xTargetDocShell.get(), *pTargetShell ) )
1567 {
1568 m_aMergeStatus = MergeStatus::Error;
1569 }
1570 }
1571 else if( IsMergeOk() && bMT_PRINTER )
1572 {
1573 // print the target document
1574 uno::Sequence< beans::PropertyValue > aOptions( rMergeDescriptor.aPrintOptions );
1575 lcl_PreparePrinterOptions( rMergeDescriptor.aPrintOptions, aOptions );
1576 pTargetView->ExecPrint( aOptions, bIsMergeSilent, false/*bPrintAsync*/ );
1577 }
1578 }
1579
1580 // we also show canceled documents, as long as there was no error
1581 if( !IsMergeError() && bMT_SHELL )
1582 // leave docshell available for caller (e.g. MM wizard)
1583 rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView );
1584 else if( xTargetDocShell.is() )
1585 xTargetDocShell->DoClose();
1586
1587 Application::Reschedule( true );
1588
1589 if (xProgressDlg)
1590 {
1591 xProgressDlg->response(RET_OK);
1592 }
1593
1594 // unlock all dispatchers
1595 pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh);
1596 while (pViewFrame)
1597 {
1598 pViewFrame->GetDispatcher()->Lock(false);
1599 pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
1600 }
1601
1602 SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->SetView(&pSourceShell->GetView());
1603
1604 if( xMailDispatcher.is() )
1605 {
1606 if( IsMergeOk() )
1607 {
1608 // TODO: Instead of polling via an AutoTimer, post an Idle event,
1609 // if the main loop has been made thread-safe.
1610 AutoTimer aEmailDispatcherPollTimer;
1611 aEmailDispatcherPollTimer.SetDebugName(
1612 "sw::SwDBManager aEmailDispatcherPollTimer" );
1613 aEmailDispatcherPollTimer.SetTimeout( 500 );
1614 aEmailDispatcherPollTimer.Start();
1615 while( IsMergeOk() && m_pImpl->m_xLastMessage.is() )
1616 Application::Yield();
1617 aEmailDispatcherPollTimer.Stop();
1618 }
1619 xMailDispatcher->stop();
1620 xMailDispatcher->shutdown();
1621 }
1622
1623 // remove the temporary files
1624 // has to be done after xMailDispatcher is finished, as mails may be
1625 // delivered as message attachments!
1626 for( const OUString &sFileURL : aFilesToRemove )
1627 SWUnoHelper::UCB_DeleteFile( sFileURL );
1628 }
1629 catch (const uno::Exception&)
1630 {
1631 if (xProgressDlg)
1632 {
1633 xProgressDlg->response(RET_CANCEL);
1634 }
1635 }
1636
1637 return !IsMergeError();
1638}
1639
1640void SwDBManager::MergeCancel()
1641{
1642 if (m_aMergeStatus < MergeStatus::Cancel)
1643 m_aMergeStatus = MergeStatus::Cancel;
1644}
1645
1646// determine the column's Numberformat and transfer to the forwarded Formatter,
1647// if applicable.
1648sal_uLong SwDBManager::GetColumnFormat( const OUString& rDBName,
1649 const OUString& rTableName,
1650 const OUString& rColNm,
1651 SvNumberFormatter* pNFormatr,
1652 LanguageType nLanguage )
1653{
1654 sal_uLong nRet = 0;
1655 if(pNFormatr)
1656 {
1657 uno::Reference< sdbc::XDataSource> xSource;
1658 uno::Reference< sdbc::XConnection> xConnection;
1659 bool bUseMergeData = false;
1660 uno::Reference< sdbcx::XColumnsSupplier> xColsSupp;
1661 bool bDisposeConnection = false;
1662 if(m_pImpl->pMergeData &&
1663 ((m_pImpl->pMergeData->sDataSource == rDBName && m_pImpl->pMergeData->sCommand == rTableName) ||
1664 (rDBName.isEmpty() && rTableName.isEmpty())))
1665 {
1666 xConnection = m_pImpl->pMergeData->xConnection;
1667 xSource = SwDBManager::getDataSourceAsParent(xConnection,rDBName);
1668 bUseMergeData = true;
1669 xColsSupp.set(m_pImpl->pMergeData->xResultSet, css::uno::UNO_QUERY);
1670 }
1671 if(!xConnection.is())
1672 {
1673 SwDBData aData;
1674 aData.sDataSource = rDBName;
1675 aData.sCommand = rTableName;
1676 aData.nCommandType = -1;
1677 SwDSParam* pParam = FindDSData(aData, false);
1678 if(pParam && pParam->xConnection.is())
1679 {
1680 xConnection = pParam->xConnection;
1681 xColsSupp.set(pParam->xResultSet, css::uno::UNO_QUERY);
1682 }
1683 else
1684 {
1685 xConnection = RegisterConnection( rDBName );
1686 bDisposeConnection = true;
1687 }
1688 if(bUseMergeData)
1689 m_pImpl->pMergeData->xConnection = xConnection;
1690 }
1691 bool bDispose = !xColsSupp.is();
1692 if(bDispose)
1693 {
1694 xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1695 }
1696 if(xColsSupp.is())
1697 {
1698 uno::Reference<container::XNameAccess> xCols;
1699 try
1700 {
1701 xCols = xColsSupp->getColumns();
1702 }
1703 catch (const uno::Exception&)
1704 {
1705 TOOLS_WARN_EXCEPTION("sw.mailmerge", "Exception in getColumns()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Exception in getColumns()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in getColumns()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in getColumns()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Exception in getColumns()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in getColumns()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in getColumns()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1705" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1706 }
1707 if(!xCols.is() || !xCols->hasByName(rColNm))
1708 return nRet;
1709 uno::Any aCol = xCols->getByName(rColNm);
1710 uno::Reference< beans::XPropertySet > xColumn;
1711 aCol >>= xColumn;
1712 nRet = GetColumnFormat(xSource, xConnection, xColumn, pNFormatr, nLanguage);
1713 if(bDispose)
1714 {
1715 ::comphelper::disposeComponent( xColsSupp );
1716 }
1717 if(bDisposeConnection)
1718 {
1719 ::comphelper::disposeComponent( xConnection );
1720 }
1721 }
1722 else
1723 nRet = pNFormatr->GetFormatIndex( NF_NUMBER_STANDARD, LANGUAGE_SYSTEMLanguageType(0x0000) );
1724 }
1725 return nRet;
1726}
1727
1728sal_uLong SwDBManager::GetColumnFormat( uno::Reference< sdbc::XDataSource> const & xSource_in,
1729 uno::Reference< sdbc::XConnection> const & xConnection,
1730 uno::Reference< beans::XPropertySet> const & xColumn,
1731 SvNumberFormatter* pNFormatr,
1732 LanguageType nLanguage )
1733{
1734 auto xSource = xSource_in;
1735
1736 // set the NumberFormat in the doc if applicable
1737 sal_uLong nRet = 0;
1738
1739 if(!xSource.is())
1740 {
1741 uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
1742 if ( xChild.is() )
1743 xSource.set(xChild->getParent(), uno::UNO_QUERY);
1744 }
1745 if(xSource.is() && xConnection.is() && xColumn.is() && pNFormatr)
1746 {
1747 SvNumberFormatsSupplierObj* pNumFormat = new SvNumberFormatsSupplierObj( pNFormatr );
1748 uno::Reference< util::XNumberFormatsSupplier > xDocNumFormatsSupplier = pNumFormat;
1749 uno::Reference< util::XNumberFormats > xDocNumberFormats = xDocNumFormatsSupplier->getNumberFormats();
1750 uno::Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, uno::UNO_QUERY);
1751
1752 css::lang::Locale aLocale( LanguageTag( nLanguage ).getLocale());
1753
1754 //get the number formatter of the data source
1755 uno::Reference<beans::XPropertySet> xSourceProps(xSource, uno::UNO_QUERY);
1756 uno::Reference< util::XNumberFormats > xNumberFormats;
1757 if(xSourceProps.is())
1758 {
1759 uno::Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
1760 if(aFormats.hasValue())
1761 {
1762 uno::Reference<util::XNumberFormatsSupplier> xSuppl;
1763 aFormats >>= xSuppl;
1764 if(xSuppl.is())
1765 {
1766 xNumberFormats = xSuppl->getNumberFormats();
1767 }
1768 }
1769 }
1770 bool bUseDefault = true;
1771 try
1772 {
1773 uno::Any aFormatKey = xColumn->getPropertyValue("FormatKey");
1774 if(aFormatKey.hasValue())
1775 {
1776 sal_Int32 nFormat = 0;
1777 aFormatKey >>= nFormat;
1778 if(xNumberFormats.is())
1779 {
1780 try
1781 {
1782 uno::Reference<beans::XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat );
1783 uno::Any aFormatString = xNumProps->getPropertyValue("FormatString");
1784 uno::Any aLocaleVal = xNumProps->getPropertyValue("Locale");
1785 OUString sFormat;
1786 aFormatString >>= sFormat;
1787 lang::Locale aLoc;
1788 aLocaleVal >>= aLoc;
1789 nFormat = xDocNumberFormats->queryKey( sFormat, aLoc, false );
1790 if(NUMBERFORMAT_ENTRY_NOT_FOUND == sal::static_int_cast< sal_uInt32, sal_Int32>(nFormat))
1791 nFormat = xDocNumberFormats->addNew( sFormat, aLoc );
1792 nRet = nFormat;
1793 bUseDefault = false;
1794 }
1795 catch (const uno::Exception&)
1796 {
1797 TOOLS_WARN_EXCEPTION("sw.mailmerge", "illegal number format key")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "illegal number format key"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "illegal number format key" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "illegal number format key" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "illegal number format key" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "illegal number format key" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "illegal number format key" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1797" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1798 }
1799 }
1800 }
1801 }
1802 catch(const uno::Exception&)
1803 {
1804 SAL_WARN("sw.mailmerge", "no FormatKey property found")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "no FormatKey property found"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no FormatKey property found"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "no FormatKey property found"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no FormatKey property found") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no FormatKey property found"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "no FormatKey property found"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1804" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1805 }
1806 if(bUseDefault)
1807 nRet = dbtools::getDefaultNumberFormat(xColumn, xDocNumberFormatTypes, aLocale);
1808 }
1809 return nRet;
1810}
1811
1812sal_Int32 SwDBManager::GetColumnType( const OUString& rDBName,
1813 const OUString& rTableName,
1814 const OUString& rColNm )
1815{
1816 sal_Int32 nRet = sdbc::DataType::SQLNULL;
1817 SwDBData aData;
1818 aData.sDataSource = rDBName;
1819 aData.sCommand = rTableName;
1820 aData.nCommandType = -1;
1821 SwDSParam* pParam = FindDSData(aData, false);
1822 uno::Reference< sdbc::XConnection> xConnection;
1823 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp;
1824 bool bDispose = false;
1825 if(pParam && pParam->xConnection.is())
1826 {
1827 xConnection = pParam->xConnection;
1828 xColsSupp.set( pParam->xResultSet, uno::UNO_QUERY );
1829 }
1830 else
1831 {
1832 xConnection = RegisterConnection( rDBName );
1833 }
1834 if( !xColsSupp.is() )
1835 {
1836 xColsSupp = SwDBManager::GetColumnSupplier(xConnection, rTableName);
1837 bDispose = true;
1838 }
1839 if(xColsSupp.is())
1840 {
1841 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
1842 if(xCols->hasByName(rColNm))
1843 {
1844 uno::Any aCol = xCols->getByName(rColNm);
1845 uno::Reference<beans::XPropertySet> xCol;
1846 aCol >>= xCol;
1847 uno::Any aType = xCol->getPropertyValue("Type");
1848 aType >>= nRet;
1849 }
1850 if(bDispose)
1851 ::comphelper::disposeComponent( xColsSupp );
1852 }
1853 return nRet;
1854}
1855
1856uno::Reference< sdbc::XConnection> SwDBManager::GetConnection(const OUString& rDataSource,
1857 uno::Reference<sdbc::XDataSource>& rxSource, const SwView *pView)
1858{
1859 uno::Reference< sdbc::XConnection> xConnection;
1860 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1861 try
1862 {
1863 uno::Reference<sdb::XCompletedConnection> xComplConnection(dbtools::getDataSource(rDataSource, xContext), uno::UNO_QUERY);
1864 if ( xComplConnection.is() )
1865 {
1866 rxSource.set(xComplConnection, uno::UNO_QUERY);
1867 weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr;
1868 uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(xContext, pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW );
1869 xConnection = xComplConnection->connectWithCompletion( xHandler );
1870 }
1871 }
1872 catch(const uno::Exception&)
1873 {
1874 }
1875
1876 return xConnection;
1877}
1878
1879uno::Reference< sdbcx::XColumnsSupplier> SwDBManager::GetColumnSupplier(uno::Reference<sdbc::XConnection> const & xConnection,
1880 const OUString& rTableOrQuery,
1881 SwDBSelect eTableOrQuery)
1882{
1883 uno::Reference< sdbcx::XColumnsSupplier> xRet;
1884 try
1885 {
1886 if(eTableOrQuery == SwDBSelect::UNKNOWN)
1887 {
1888 //search for a table with the given command name
1889 uno::Reference<sdbcx::XTablesSupplier> xTSupplier(xConnection, uno::UNO_QUERY);
1890 if(xTSupplier.is())
1891 {
1892 uno::Reference<container::XNameAccess> xTables = xTSupplier->getTables();
1893 eTableOrQuery = xTables->hasByName(rTableOrQuery) ?
1894 SwDBSelect::TABLE : SwDBSelect::QUERY;
1895 }
1896 }
1897 sal_Int32 nCommandType = SwDBSelect::TABLE == eTableOrQuery ?
1898 sdb::CommandType::TABLE : sdb::CommandType::QUERY;
1899 uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
1900 uno::Reference<sdbc::XRowSet> xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), uno::UNO_QUERY);
1901
1902 OUString sDataSource;
1903 uno::Reference<sdbc::XDataSource> xSource = SwDBManager::getDataSourceAsParent(xConnection, sDataSource);
1904 uno::Reference<beans::XPropertySet> xSourceProperties(xSource, uno::UNO_QUERY);
1905 if(xSourceProperties.is())
1906 {
1907 xSourceProperties->getPropertyValue("Name") >>= sDataSource;
1908 }
1909
1910 uno::Reference<beans::XPropertySet> xRowProperties(xRowSet, uno::UNO_QUERY);
1911 xRowProperties->setPropertyValue("DataSourceName", uno::makeAny(sDataSource));
1912 xRowProperties->setPropertyValue("Command", uno::makeAny(rTableOrQuery));
1913 xRowProperties->setPropertyValue("CommandType", uno::makeAny(nCommandType));
1914 xRowProperties->setPropertyValue("FetchSize", uno::makeAny(sal_Int32(10)));
1915 xRowProperties->setPropertyValue("ActiveConnection", uno::makeAny(xConnection));
1916 xRowSet->execute();
1917 xRet.set( xRowSet, uno::UNO_QUERY );
1918 }
1919 catch (const uno::Exception&)
1920 {
1921 TOOLS_WARN_EXCEPTION("sw.mailmerge", "Exception in SwDBManager::GetColumnSupplier")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Exception in SwDBManager::GetColumnSupplier"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in SwDBManager::GetColumnSupplier"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in SwDBManager::GetColumnSupplier" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Exception in SwDBManager::GetColumnSupplier" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Exception in SwDBManager::GetColumnSupplier"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Exception in SwDBManager::GetColumnSupplier" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1921" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1922 }
1923
1924 return xRet;
1925}
1926
1927OUString SwDBManager::GetDBField(uno::Reference<beans::XPropertySet> const & xColumnProps,
1928 const SwDBFormatData& rDBFormatData,
1929 double* pNumber)
1930{
1931 uno::Reference< sdb::XColumn > xColumn(xColumnProps, uno::UNO_QUERY);
1932 OUString sRet;
1933 assert( xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments" )(static_cast <bool> (xColumn.is() && "SwDBManager::::ImportDBField: illegal arguments"
) ? void (0) : __assert_fail ("xColumn.is() && \"SwDBManager::::ImportDBField: illegal arguments\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 1933, __extension__ __PRETTY_FUNCTION__))
;
1934 if(!xColumn.is())
1935 return sRet;
1936
1937 uno::Any aType = xColumnProps->getPropertyValue("Type");
1938 sal_Int32 eDataType = sdbc::DataType::SQLNULL;
1939 aType >>= eDataType;
1940 switch(eDataType)
1941 {
1942 case sdbc::DataType::CHAR:
1943 case sdbc::DataType::VARCHAR:
1944 case sdbc::DataType::LONGVARCHAR:
1945 try
1946 {
1947 sRet = xColumn->getString();
1948 sRet = sRet.replace( '\xb', '\n' ); // MSWord uses \xb as a newline
1949 }
1950 catch(const sdbc::SQLException&)
1951 {
1952 }
1953 break;
1954 case sdbc::DataType::BIT:
1955 case sdbc::DataType::BOOLEAN:
1956 case sdbc::DataType::TINYINT:
1957 case sdbc::DataType::SMALLINT:
1958 case sdbc::DataType::INTEGER:
1959 case sdbc::DataType::BIGINT:
1960 case sdbc::DataType::FLOAT:
1961 case sdbc::DataType::REAL:
1962 case sdbc::DataType::DOUBLE:
1963 case sdbc::DataType::NUMERIC:
1964 case sdbc::DataType::DECIMAL:
1965 case sdbc::DataType::DATE:
1966 case sdbc::DataType::TIME:
1967 case sdbc::DataType::TIMESTAMP:
1968 {
1969
1970 try
1971 {
1972 sRet = dbtools::DBTypeConversion::getFormattedValue(
1973 xColumnProps,
1974 rDBFormatData.xFormatter,
1975 rDBFormatData.aLocale,
1976 rDBFormatData.aNullDate);
1977 if (pNumber)
1978 {
1979 double fVal = xColumn->getDouble();
1980 if(!xColumn->wasNull())
1981 {
1982 *pNumber = fVal;
1983 }
1984 }
1985 }
1986 catch (const uno::Exception&)
1987 {
1988 TOOLS_WARN_EXCEPTION("sw.mailmerge", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "1988" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1989 }
1990
1991 }
1992 break;
1993 }
1994
1995 return sRet;
1996}
1997
1998// checks if a desired data source table or query is open
1999bool SwDBManager::IsDataSourceOpen(const OUString& rDataSource,
2000 const OUString& rTableOrQuery, bool bMergeShell)
2001{
2002 if(m_pImpl->pMergeData)
2003 {
2004 return ((rDataSource == m_pImpl->pMergeData->sDataSource
2005 && rTableOrQuery == m_pImpl->pMergeData->sCommand)
2006 || (rDataSource.isEmpty() && rTableOrQuery.isEmpty()))
2007 && m_pImpl->pMergeData->xResultSet.is();
2008 }
2009 else if(!bMergeShell)
2010 {
2011 SwDBData aData;
2012 aData.sDataSource = rDataSource;
2013 aData.sCommand = rTableOrQuery;
2014 aData.nCommandType = -1;
2015 SwDSParam* pFound = FindDSData(aData, false);
2016 return (pFound && pFound->xResultSet.is());
2017 }
2018 return false;
2019}
2020
2021// read column data at a specified position
2022bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
2023 const OUString& rColumnName, sal_uInt32 nAbsRecordId,
2024 LanguageType nLanguage,
2025 OUString& rResult, double* pNumber)
2026{
2027 bool bRet = false;
2028 SwDSParam* pFound = nullptr;
2029 //check if it's the merge data source
2030 if(m_pImpl->pMergeData &&
2031 rSourceName == m_pImpl->pMergeData->sDataSource &&
2032 rTableName == m_pImpl->pMergeData->sCommand)
2033 {
2034 pFound = m_pImpl->pMergeData.get();
2035 }
2036 else
2037 {
2038 SwDBData aData;
2039 aData.sDataSource = rSourceName;
2040 aData.sCommand = rTableName;
2041 aData.nCommandType = -1;
2042 pFound = FindDSData(aData, false);
2043 }
2044 if (!pFound)
2045 return false;
2046 //check validity of supplied record Id
2047 if(pFound->aSelection.hasElements())
2048 {
2049 //the destination has to be an element of the selection
2050 bool bFound = std::any_of(pFound->aSelection.begin(), pFound->aSelection.end(),
2051 [nAbsRecordId](const uno::Any& rSelection) {
2052 sal_Int32 nSelection = 0;
2053 rSelection >>= nSelection;
2054 return nSelection == static_cast<sal_Int32>(nAbsRecordId);
2055 });
2056 if(!bFound)
2057 return false;
2058 }
2059 if( pFound->HasValidRecord() )
2060 {
2061 sal_Int32 nOldRow = 0;
2062 try
2063 {
2064 nOldRow = pFound->xResultSet->getRow();
2065 }
2066 catch(const uno::Exception&)
2067 {
2068 return false;
2069 }
2070 //position to the desired index
2071 bool bMove = true;
2072 if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2073 bMove = lcl_MoveAbsolute(pFound, nAbsRecordId);
2074 if(bMove)
2075 bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber);
2076 if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
2077 lcl_MoveAbsolute(pFound, nOldRow);
2078 }
2079 return bRet;
2080}
2081
2082// reads the column data at the current position
2083bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage,
2084 OUString &rResult, double *pNumber)
2085{
2086 if( !IsValidMergeRecord() )
2087 {
2088 rResult.clear();
2089 return false;
2090 }
2091
2092 bool bRet = lcl_GetColumnCnt(m_pImpl->pMergeData.get(), rColumnName, nLanguage, rResult, pNumber);
2093 return bRet;
2094}
2095
2096bool SwDBManager::ToNextMergeRecord()
2097{
2098 assert( m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2098, __extension__ __PRETTY_FUNCTION__))
;
2099 return lcl_ToNextRecord( m_pImpl->pMergeData.get() );
2100}
2101
2102bool SwDBManager::FillCalcWithMergeData( SvNumberFormatter *pDocFormatter,
2103 LanguageType nLanguage, SwCalc &rCalc )
2104{
2105 if( !IsValidMergeRecord() )
2106 return false;
2107
2108 uno::Reference< sdbcx::XColumnsSupplier > xColsSupp( m_pImpl->pMergeData->xResultSet, uno::UNO_QUERY );
2109 if( !xColsSupp.is() )
2110 return false;
2111
2112 {
2113 uno::Reference<container::XNameAccess> xCols = xColsSupp->getColumns();
2114 const uno::Sequence<OUString> aColNames = xCols->getElementNames();
2115 OUString aString;
2116
2117 // add the "record number" variable, as SwCalc::VarLook would.
2118 rCalc.VarChange( GetAppCharClass().lowercase(
2119 SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber) ), GetSelectedRecordId() );
2120
2121 for( const OUString& rColName : aColNames )
2122 {
2123 // get the column type
2124 sal_Int32 nColumnType = sdbc::DataType::SQLNULL;
2125 uno::Any aCol = xCols->getByName( rColName );
2126 uno::Reference<beans::XPropertySet> xColumnProps;
2127 aCol >>= xColumnProps;
2128 uno::Any aType = xColumnProps->getPropertyValue( "Type" );
2129 aType >>= nColumnType;
2130 double aNumber = DBL_MAX1.7976931348623157e+308;
2131
2132 lcl_GetColumnCnt( m_pImpl->pMergeData.get(), xColumnProps, nLanguage, aString, &aNumber );
2133
2134 sal_uInt32 nFormat = GetColumnFormat( m_pImpl->pMergeData->sDataSource,
2135 m_pImpl->pMergeData->sCommand,
2136 rColName, pDocFormatter, nLanguage );
2137 // aNumber is overwritten by SwDBField::FormatValue, so store initial status
2138 bool colIsNumber = aNumber != DBL_MAX1.7976931348623157e+308;
2139 bool bValidValue = SwDBField::FormatValue( pDocFormatter, aString, nFormat,
2140 aNumber, nColumnType );
2141 if( colIsNumber )
2142 {
2143 if( bValidValue )
2144 {
2145 SwSbxValue aValue;
2146 aValue.PutDouble( aNumber );
2147 aValue.SetDBvalue( true );
2148 SAL_INFO( "sw.ui", "'" << rColName << "': " << aNumber << " / " << aString )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aNumber
<< " / " << aString) == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aNumber << " / " << aString), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"'" << rColName << "': " << aNumber <<
" / " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aNumber
<< " / " << aString) == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aNumber << " / " << aString), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"'" << rColName << "': " << aNumber <<
" / " << aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2148" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2149 rCalc.VarChange( rColName, aValue );
2150 }
2151 }
2152 else
2153 {
2154 SwSbxValue aValue;
2155 aValue.PutString( aString );
2156 aValue.SetDBvalue( true );
2157 SAL_INFO( "sw.ui", "'" << rColName << "': " << aString )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ui")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aString
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aString), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "'" << rColName << "': "
<< aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "'" << rColName << "': " << aString
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ui"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "'" << rColName << "': "
<< aString), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "'" << rColName << "': "
<< aString; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ui"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2157" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2158 rCalc.VarChange( rColName, aValue );
2159 }
2160 }
2161 }
2162
2163 return true;
2164}
2165
2166void SwDBManager::ToNextRecord(
2167 const OUString& rDataSource, const OUString& rCommand)
2168{
2169 SwDSParam* pFound = nullptr;
2170 if(m_pImpl->pMergeData &&
2171 rDataSource == m_pImpl->pMergeData->sDataSource &&
2172 rCommand == m_pImpl->pMergeData->sCommand)
2173 {
2174 pFound = m_pImpl->pMergeData.get();
2175 }
2176 else
2177 {
2178 SwDBData aData;
2179 aData.sDataSource = rDataSource;
2180 aData.sCommand = rCommand;
2181 aData.nCommandType = -1;
2182 pFound = FindDSData(aData, false);
2183 }
2184 lcl_ToNextRecord( pFound );
2185}
2186
2187static bool lcl_ToNextRecord( SwDSParam* pParam, const SwDBNextRecord action )
2188{
2189 bool bRet = true;
2190
2191 assert( SwDBNextRecord::NEXT == action ||(static_cast <bool> (SwDBNextRecord::NEXT == action || (
SwDBNextRecord::FIRST == action && pParam)) ? void (0
) : __assert_fail ("SwDBNextRecord::NEXT == action || (SwDBNextRecord::FIRST == action && pParam)"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2192, __extension__ __PRETTY_FUNCTION__))
2192 (SwDBNextRecord::FIRST == action && pParam) )(static_cast <bool> (SwDBNextRecord::NEXT == action || (
SwDBNextRecord::FIRST == action && pParam)) ? void (0
) : __assert_fail ("SwDBNextRecord::NEXT == action || (SwDBNextRecord::FIRST == action && pParam)"
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2192, __extension__ __PRETTY_FUNCTION__))
;
2193 if( nullptr == pParam )
2194 return false;
2195
2196 if( action == SwDBNextRecord::FIRST )
2197 {
2198 pParam->nSelectionIndex = 0;
2199 pParam->bEndOfDB = false;
2200 }
2201
2202 if( !pParam->HasValidRecord() )
2203 return false;
2204
2205 try
2206 {
2207 if( pParam->aSelection.hasElements() )
2208 {
2209 if( pParam->nSelectionIndex >= pParam->aSelection.getLength() )
2210 pParam->bEndOfDB = true;
2211 else
2212 {
2213 sal_Int32 nPos = 0;
2214 pParam->aSelection.getConstArray()[ pParam->nSelectionIndex ] >>= nPos;
2215 pParam->bEndOfDB = !pParam->xResultSet->absolute( nPos );
2216 }
2217 }
2218 else if( action == SwDBNextRecord::FIRST )
2219 {
2220 pParam->bEndOfDB = !pParam->xResultSet->first();
2221 }
2222 else
2223 {
2224 sal_Int32 nBefore = pParam->xResultSet->getRow();
2225 pParam->bEndOfDB = !pParam->xResultSet->next();
2226 if( !pParam->bEndOfDB && nBefore == pParam->xResultSet->getRow() )
2227 {
2228 // next returned true but it didn't move
2229 ::dbtools::throwFunctionSequenceException( pParam->xResultSet );
2230 }
2231 }
2232
2233 ++pParam->nSelectionIndex;
2234 bRet = !pParam->bEndOfDB;
2235 }
2236 catch( const uno::Exception & )
2237 {
2238 // we allow merging with empty databases, so don't warn on init
2239 TOOLS_WARN_EXCEPTION_IF(action == SwDBNextRecord::NEXT,do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true && (action == SwDBNextRecord::NEXT
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "exception in ToNextRecord()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
2240 "sw.mailmerge", "exception in ToNextRecord()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true && (action == SwDBNextRecord::NEXT
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "exception in ToNextRecord()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "exception in ToNextRecord()" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "exception in ToNextRecord()" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2240" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
2241 pParam->bEndOfDB = true;
2242 bRet = false;
2243 }
2244 return bRet;
2245}
2246
2247// synchronized labels contain a next record field at their end
2248// to assure that the next page can be created in mail merge
2249// the cursor position must be validated
2250bool SwDBManager::IsValidMergeRecord() const
2251{
2252 return( m_pImpl->pMergeData && m_pImpl->pMergeData->HasValidRecord() );
2253}
2254
2255sal_uInt32 SwDBManager::GetSelectedRecordId()
2256{
2257 sal_uInt32 nRet = 0;
2258 assert( m_pImpl->pMergeData &&(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2259, __extension__ __PRETTY_FUNCTION__))
2259 m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2259, __extension__ __PRETTY_FUNCTION__))
;
2260 if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is())
2261 return 0;
2262 try
2263 {
2264 nRet = m_pImpl->pMergeData->xResultSet->getRow();
2265 }
2266 catch(const uno::Exception&)
2267 {
2268 }
2269 return nRet;
2270}
2271
2272bool SwDBManager::ToRecordId(sal_Int32 nSet)
2273{
2274 assert( m_pImpl->pMergeData &&(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2275, __extension__ __PRETTY_FUNCTION__))
2275 m_pImpl->pMergeData->xResultSet.is() && "no data source in merge" )(static_cast <bool> (m_pImpl->pMergeData && m_pImpl
->pMergeData->xResultSet.is() && "no data source in merge"
) ? void (0) : __assert_fail ("m_pImpl->pMergeData && m_pImpl->pMergeData->xResultSet.is() && \"no data source in merge\""
, "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2275, __extension__ __PRETTY_FUNCTION__))
;
2276 if(!m_pImpl->pMergeData || !m_pImpl->pMergeData->xResultSet.is()|| nSet < 0)
2277 return false;
2278 bool bRet = false;
2279 sal_Int32 nAbsPos = nSet;
2280 assert(nAbsPos >= 0)(static_cast <bool> (nAbsPos >= 0) ? void (0) : __assert_fail
("nAbsPos >= 0", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2280, __extension__ __PRETTY_FUNCTION__))
;
2281 bRet = lcl_MoveAbsolute(m_pImpl->pMergeData.get(), nAbsPos);
2282 m_pImpl->pMergeData->bEndOfDB = !bRet;
2283 return bRet;
2284}
2285
2286bool SwDBManager::OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery)
2287{
2288 SwDBData aData;
2289 aData.sDataSource = rDataSource;
2290 aData.sCommand = rTableOrQuery;
2291 aData.nCommandType = -1;
2292
2293 SwDSParam* pFound = FindDSData(aData, true);
2294 if(pFound->xResultSet.is())
2295 return true;
2296 SwDSParam* pParam = FindDSConnection(rDataSource, false);
2297 if(pParam && pParam->xConnection.is())
2298 pFound->xConnection = pParam->xConnection;
2299 if(pFound->xConnection.is())
2300 {
2301 try
2302 {
2303 uno::Reference< sdbc::XDatabaseMetaData > xMetaData = pFound->xConnection->getMetaData();
2304 try
2305 {
2306 pFound->bScrollable = xMetaData
2307 ->supportsResultSetType(sal_Int32(sdbc::ResultSetType::SCROLL_INSENSITIVE));
2308 }
2309 catch(const uno::Exception&)
2310 {
2311 // DB driver may not be ODBC 3.0 compliant
2312 pFound->bScrollable = true;
2313 }
2314 pFound->xStatement = pFound->xConnection->createStatement();
2315 OUString aQuoteChar = xMetaData->getIdentifierQuoteString();
2316 OUString sStatement = "SELECT * FROM " + aQuoteChar + rTableOrQuery + aQuoteChar;
2317 pFound->xResultSet = pFound->xStatement->executeQuery( sStatement );
2318
2319 //after executeQuery the cursor must be positioned
2320 pFound->bEndOfDB = !pFound->xResultSet->next();
2321 ++pFound->nSelectionIndex;
2322 }
2323 catch (const uno::Exception&)
2324 {
2325 pFound->xResultSet = nullptr;
2326 pFound->xStatement = nullptr;
2327 pFound->xConnection = nullptr;
2328 }
2329 }
2330 return pFound->xResultSet.is();
2331}
2332
2333uno::Reference< sdbc::XConnection> const & SwDBManager::RegisterConnection(OUString const& rDataSource)
2334{
2335 SwDSParam* pFound = SwDBManager::FindDSConnection(rDataSource, true);
2336 uno::Reference< sdbc::XDataSource> xSource;
2337 if(!pFound->xConnection.is())
2338 {
2339 SwView* pView = (m_pDoc && m_pDoc->GetDocShell()) ? m_pDoc->GetDocShell()->GetView() : nullptr;
2340 pFound->xConnection = SwDBManager::GetConnection(rDataSource, xSource, pView);
2341 try
2342 {
2343 uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2344 if(xComponent.is())
2345 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2346 }
2347 catch(const uno::Exception&)
2348 {
2349 }
2350 }
2351 return pFound->xConnection;
2352}
2353
2354sal_uInt32 SwDBManager::GetSelectedRecordId(
2355 const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType)
2356{
2357 sal_uInt32 nRet = 0xffffffff;
2358 //check for merge data source first
2359 if(m_pImpl->pMergeData &&
2360 ((rDataSource == m_pImpl->pMergeData->sDataSource &&
2361 rTableOrQuery == m_pImpl->pMergeData->sCommand) ||
2362 (rDataSource.isEmpty() && rTableOrQuery.isEmpty())) &&
2363 (nCommandType == -1 || nCommandType == m_pImpl->pMergeData->nCommandType) &&
2364 m_pImpl->pMergeData->xResultSet.is())
2365 {
2366 nRet = GetSelectedRecordId();
2367 }
2368 else
2369 {
2370 SwDBData aData;
2371 aData.sDataSource = rDataSource;
2372 aData.sCommand = rTableOrQuery;
2373 aData.nCommandType = nCommandType;
2374 SwDSParam* pFound = FindDSData(aData, false);
2375 if(pFound && pFound->xResultSet.is())
2376 {
2377 try
2378 { //if a selection array is set the current row at the result set may not be set yet
2379 if(pFound->aSelection.hasElements())
2380 {
2381 sal_Int32 nSelIndex = pFound->nSelectionIndex;
2382 if(nSelIndex >= pFound->aSelection.getLength())
2383 nSelIndex = pFound->aSelection.getLength() -1;
2384 pFound->aSelection.getConstArray()[nSelIndex] >>= nRet;
2385
2386 }
2387 else
2388 nRet = pFound->xResultSet->getRow();
2389 }
2390 catch(const uno::Exception&)
2391 {
2392 }
2393 }
2394 }
2395 return nRet;
2396}
2397
2398// close all data sources - after fields were updated
2399void SwDBManager::CloseAll(bool bIncludingMerge)
2400{
2401 //the only thing done here is to reset the selection index
2402 //all connections stay open
2403 for (auto & pParam : m_DataSourceParams)
2404 {
2405 if (bIncludingMerge || pParam.get() != m_pImpl->pMergeData.get())
2406 {
2407 pParam->nSelectionIndex = 0;
2408 pParam->bEndOfDB = false;
2409 try
2410 {
2411 if(!m_bInMerge && pParam->xResultSet.is())
2412 pParam->xResultSet->first();
2413 }
2414 catch(const uno::Exception&)
2415 {}
2416 }
2417 }
2418}
2419
2420SwDSParam* SwDBManager::FindDSData(const SwDBData& rData, bool bCreate)
2421{
2422 //prefer merge data if available
2423 if(m_pImpl->pMergeData &&
2424 ((rData.sDataSource == m_pImpl->pMergeData->sDataSource &&
2425 rData.sCommand == m_pImpl->pMergeData->sCommand) ||
2426 (rData.sDataSource.isEmpty() && rData.sCommand.isEmpty())) &&
2427 (rData.nCommandType == -1 || rData.nCommandType == m_pImpl->pMergeData->nCommandType ||
2428 (bCreate && m_pImpl->pMergeData->nCommandType == -1)))
2429 {
2430 return m_pImpl->pMergeData.get();
2431 }
2432
2433 SwDSParam* pFound = nullptr;
2434 for (size_t nPos = m_DataSourceParams.size(); nPos; nPos--)
2435 {
2436 SwDSParam* pParam = m_DataSourceParams[nPos - 1].get();
2437 if(rData.sDataSource == pParam->sDataSource &&
2438 rData.sCommand == pParam->sCommand &&
2439 (rData.nCommandType == -1 || rData.nCommandType == pParam->nCommandType ||
2440 (bCreate && pParam->nCommandType == -1)))
2441 {
2442 // calls from the calculator may add a connection with an invalid commandtype
2443 //later added "real" data base connections have to re-use the already available
2444 //DSData and set the correct CommandType
2445 if(bCreate && pParam->nCommandType == -1)
2446 pParam->nCommandType = rData.nCommandType;
2447 pFound = pParam;
2448 break;
2449 }
2450 }
2451 if(bCreate && !pFound)
2452 {
2453 pFound = new SwDSParam(rData);
2454 m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound));
2455 try
2456 {
2457 uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2458 if(xComponent.is())
2459 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2460 }
2461 catch(const uno::Exception&)
2462 {
2463 }
2464 }
2465 return pFound;
2466}
2467
2468SwDSParam* SwDBManager::FindDSConnection(const OUString& rDataSource, bool bCreate)
2469{
2470 //prefer merge data if available
2471 if(m_pImpl->pMergeData && rDataSource == m_pImpl->pMergeData->sDataSource )
2472 {
2473 SetAsUsed(rDataSource);
2474 return m_pImpl->pMergeData.get();
2475 }
2476 SwDSParam* pFound = nullptr;
2477 for (const auto & pParam : m_DataSourceParams)
2478 {
2479 if(rDataSource == pParam->sDataSource)
2480 {
2481 SetAsUsed(rDataSource);
2482 pFound = pParam.get();
2483 break;
2484 }
2485 }
2486 if(bCreate && !pFound)
2487 {
2488 SwDBData aData;
2489 aData.sDataSource = rDataSource;
2490 pFound = new SwDSParam(aData);
2491 SetAsUsed(rDataSource);
2492 m_DataSourceParams.push_back(std::unique_ptr<SwDSParam>(pFound));
2493 try
2494 {
2495 uno::Reference<lang::XComponent> xComponent(pFound->xConnection, uno::UNO_QUERY);
2496 if(xComponent.is())
2497 xComponent->addEventListener(m_pImpl->m_xDisposeListener.get());
2498 }
2499 catch(const uno::Exception&)
2500 {
2501 }
2502 }
2503 return pFound;
2504}
2505
2506const SwDBData& SwDBManager::GetAddressDBName()
2507{
2508 return SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->GetDBConfig()->GetAddressSource();
2509}
2510
2511uno::Sequence<OUString> SwDBManager::GetExistingDatabaseNames()
2512{
2513 uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2514 uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2515 return xDBContext->getElementNames();
2516}
2517
2518namespace sw
2519{
2520DBConnURIType GetDBunoType(const INetURLObject &rURL)
2521{
2522 OUString sExt(rURL.GetFileExtension());
2523 DBConnURIType type = DBConnURIType::UNKNOWN;
2524
2525 if (sExt == "odb")
2526 {
2527 type = DBConnURIType::ODB;
2528 }
2529 else if (sExt.equalsIgnoreAsciiCase("sxc")
2530 || sExt.equalsIgnoreAsciiCase("ods")
2531 || sExt.equalsIgnoreAsciiCase("xls")
2532 || sExt.equalsIgnoreAsciiCase("xlsx"))
2533 {
2534 type = DBConnURIType::CALC;
2535 }
2536 else if (sExt.equalsIgnoreAsciiCase("sxw") || sExt.equalsIgnoreAsciiCase("odt") || sExt.equalsIgnoreAsciiCase("doc") || sExt.equalsIgnoreAsciiCase("docx"))
2537 {
2538 type = DBConnURIType::WRITER;
2539 }
2540 else if (sExt.equalsIgnoreAsciiCase("dbf"))
2541 {
2542 type = DBConnURIType::DBASE;
2543 }
2544 else if (sExt.equalsIgnoreAsciiCase("csv") || sExt.equalsIgnoreAsciiCase("txt"))
2545 {
2546 type = DBConnURIType::FLAT;
2547 }
2548#ifdef _WIN32
2549 else if (sExt.equalsIgnoreAsciiCase("mdb") || sExt.equalsIgnoreAsciiCase("mde"))
2550 {
2551 type = DBConnURIType::MSJET;
2552 }
2553 else if (sExt.equalsIgnoreAsciiCase("accdb") || sExt.equalsIgnoreAsciiCase("accde"))
2554 {
2555 type = DBConnURIType::MSACE;
2556 }
2557#endif
2558 return type;
2559}
2560}
2561
2562namespace
2563{
2564uno::Any GetDBunoURI(const INetURLObject &rURL, DBConnURIType& rType)
2565{
2566 uno::Any aURLAny;
2567
2568 if (rType == DBConnURIType::UNKNOWN)
2569 rType = GetDBunoType(rURL);
2570
2571 switch (rType) {
2572 case DBConnURIType::UNKNOWN:
2573 case DBConnURIType::ODB:
2574 break;
2575 case DBConnURIType::CALC:
2576 {
2577 OUString sDBURL = "sdbc:calc:" +
2578 rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2579 aURLAny <<= sDBURL;
2580 }
2581 break;
2582 case DBConnURIType::WRITER:
2583 {
2584 OUString sDBURL = "sdbc:writer:" +
2585 rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2586 aURLAny <<= sDBURL;
2587 }
2588 break;
2589 case DBConnURIType::DBASE:
2590 {
2591 INetURLObject aUrlTmp(rURL);
2592 aUrlTmp.removeSegment();
2593 aUrlTmp.removeFinalSlash();
2594 OUString sDBURL = "sdbc:dbase:" +
2595 aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2596 aURLAny <<= sDBURL;
2597 }
2598 break;
2599 case DBConnURIType::FLAT:
2600 {
2601 INetURLObject aUrlTmp(rURL);
2602 aUrlTmp.removeSegment();
2603 aUrlTmp.removeFinalSlash();
2604 OUString sDBURL = "sdbc:flat:" +
2605 //only the 'path' has to be added
2606 aUrlTmp.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2607 aURLAny <<= sDBURL;
2608 }
2609 break;
2610 case DBConnURIType::MSJET:
2611#ifdef _WIN32
2612 {
2613 OUString sDBURL("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" + rURL.PathToFileName());
2614 aURLAny <<= sDBURL;
2615 }
2616#endif
2617 break;
2618 case DBConnURIType::MSACE:
2619#ifdef _WIN32
2620 {
2621 OUString sDBURL("sdbc:ado:PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=" + rURL.PathToFileName());
2622 aURLAny <<= sDBURL;
2623 }
2624#endif
2625 break;
2626 }
2627 return aURLAny;
2628}
2629
2630/// Returns the URL of this SwDoc.
2631OUString getOwnURL(SfxObjectShell const * pDocShell)
2632{
2633 OUString aRet;
2634
2635 if (!pDocShell)
2636 return aRet;
2637
2638 const INetURLObject& rURLObject = pDocShell->GetMedium()->GetURLObject();
2639 aRet = rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2640 return aRet;
2641}
2642
2643/**
2644Loads a data source from file and registers it.
2645
2646In case of success it returns the registered name, otherwise an empty string.
2647Optionally add a prefix to the registered DB name.
2648*/
2649OUString LoadAndRegisterDataSource_Impl(DBConnURIType type, const uno::Reference< beans::XPropertySet > *pSettings,
2650 const INetURLObject &rURL, const OUString *pDestDir, SfxObjectShell* pDocShell)
2651{
2652 OUString sExt(rURL.GetFileExtension());
2653 uno::Any aTableFilterAny;
2654 uno::Any aSuppressVersionsAny;
2655 uno::Any aInfoAny;
2656 bool bStore = true;
2657 OUString sFind;
2658 uno::Sequence<OUString> aFilters(1);
2659
2660 uno::Any aURLAny = GetDBunoURI(rURL, type);
2661 switch (type) {
2662 case DBConnURIType::UNKNOWN:
2663 case DBConnURIType::CALC:
2664 case DBConnURIType::WRITER:
2665 break;
2666 case DBConnURIType::ODB:
2667 bStore = false;
2668 break;
2669 case DBConnURIType::FLAT:
2670 case DBConnURIType::DBASE:
2671 //set the filter to the file name without extension
2672 aFilters[0] = rURL.getBase(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset);
2673 aTableFilterAny <<= aFilters;
2674 break;
2675 case DBConnURIType::MSJET:
2676 case DBConnURIType::MSACE:
2677 aSuppressVersionsAny <<= true;
2678 break;
2679 }
2680
2681 try
2682 {
2683 uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
2684 uno::Reference<sdb::XDatabaseContext> xDBContext = sdb::DatabaseContext::create(xContext);
2685
2686 OUString sNewName = rURL.getName(
2687 INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous);
2688 sal_Int32 nExtLen = sExt.getLength();
2689 sNewName = sNewName.replaceAt(sNewName.getLength() - nExtLen - 1, nExtLen + 1, "");
2690
2691 //find a unique name if sNewName already exists
2692 sFind = sNewName;
2693 sal_Int32 nIndex = 0;
2694 while (xDBContext->hasByName(sFind))
2695 sFind = sNewName + OUString::number(++nIndex);
2696
2697 uno::Reference<uno::XInterface> xNewInstance;
2698 if (!bStore)
2699 {
2700 //odb-file
2701 uno::Any aDataSource = xDBContext->getByName(rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
2702 aDataSource >>= xNewInstance;
2703 }
2704 else
2705 {
2706 xNewInstance = xDBContext->createInstance();
2707 uno::Reference<beans::XPropertySet> xDataProperties(xNewInstance, uno::UNO_QUERY);
2708
2709 if (aURLAny.hasValue())
2710 xDataProperties->setPropertyValue("URL", aURLAny);
2711 if (aTableFilterAny.hasValue())
2712 xDataProperties->setPropertyValue("TableFilter", aTableFilterAny);
2713 if (aSuppressVersionsAny.hasValue())
2714 xDataProperties->setPropertyValue("SuppressVersionColumns", aSuppressVersionsAny);
2715 if (aInfoAny.hasValue())
2716 xDataProperties->setPropertyValue("Info", aInfoAny);
2717
2718 if (DBConnURIType::FLAT == type && pSettings)
2719 {
2720 uno::Any aSettings = xDataProperties->getPropertyValue("Settings");
2721 uno::Reference < beans::XPropertySet > xDSSettings;
2722 aSettings >>= xDSSettings;
2723 ::comphelper::copyProperties(*pSettings, xDSSettings);
2724 xDSSettings->setPropertyValue("Extension", uno::makeAny(sExt));
2725 }
2726
2727 uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, uno::UNO_QUERY_THROW);
2728 uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), uno::UNO_QUERY_THROW);
2729 OUString aOwnURL = getOwnURL(pDocShell);
2730 if (aOwnURL.isEmpty())
2731 {
2732 // Cannot embed, as embedded data source would need the URL of the parent document.
2733 OUString const sOutputExt = ".odb";
2734 OUString sHomePath(SvtPathOptions().GetWorkPath());
2735 utl::TempFile aTempFile(sNewName, true, &sOutputExt, pDestDir ? pDestDir : &sHomePath);
2736 const OUString& sTmpName = aTempFile.GetURL();
2737 xStore->storeAsURL(sTmpName, uno::Sequence<beans::PropertyValue>());
2738 }
2739 else
2740 {
2741 // Embed.
2742 OUString aStreamRelPath = "EmbeddedDatabase";
2743 uno::Reference<embed::XStorage> xStorage = pDocShell->GetStorage();
2744
2745 // Refer to the sub-storage name in the document settings, so
2746 // we can load it again next time the file is imported.
2747 uno::Reference<lang::XMultiServiceFactory> xFactory(pDocShell->GetModel(), uno::UNO_QUERY);
2748 uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
2749 xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::makeAny(aStreamRelPath));
2750
2751 // Store it only after setting the above property, so that only one data source gets registered.
2752 SwDBManager::StoreEmbeddedDataSource(xStore, xStorage, aStreamRelPath, aOwnURL);
2753 }
2754 }
2755 xDBContext->registerObject(sFind, xNewInstance);
2756 }
2757 catch (const uno::Exception&)
2758 {
2759 sFind.clear();
2760 }
2761 return sFind;
2762}
2763
2764// Construct vnd.sun.star.pkg:// URL
2765OUString ConstructVndSunStarPkgUrl(const OUString& rMainURL, const OUString& rStreamRelPath)
2766{
2767 auto xContext(comphelper::getProcessComponentContext());
2768 auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(rMainURL);
2769 assert(xUri.is())(static_cast <bool> (xUri.is()) ? void (0) : __assert_fail
("xUri.is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2769, __extension__ __PRETTY_FUNCTION__))
;
2770 xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)
2771 ->createVndSunStarPkgUrlReference(xUri);
2772 assert(xUri.is())(static_cast <bool> (xUri.is()) ? void (0) : __assert_fail
("xUri.is()", "/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
, 2772, __extension__ __PRETTY_FUNCTION__))
;
2773 return xUri->getUriReference() + "/"
2774 + INetURLObject::encode(
2775 rStreamRelPath, INetURLObject::PART_FPATH,
2776 INetURLObject::EncodeMechanism::All);
2777}
2778}
2779
2780OUString SwDBManager::LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell)
2781{
2782 sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, pParent);
2783 uno::Reference < ui::dialogs::XFilePicker3 > xFP = aDlgHelper.GetFilePicker();
2784
2785 OUString sHomePath(SvtPathOptions().GetWorkPath());
2786 aDlgHelper.SetDisplayDirectory( sHomePath );
2787
2788 OUString sFilterAll(SwResId(STR_FILTER_ALLreinterpret_cast<char const *>("STR_FILTER_ALL" "\004" u8"All files"
)
));
2789 OUString sFilterAllData(SwResId(STR_FILTER_ALL_DATAreinterpret_cast<char const *>("STR_FILTER_ALL_DATA" "\004"
u8"Address lists(*.*)")
));
2790 OUString sFilterSXB(SwResId(STR_FILTER_SXBreinterpret_cast<char const *>("STR_FILTER_SXB" "\004" u8"%PRODUCTNAME Base (*.odb)"
)
));
2791 OUString sFilterSXC(SwResId(STR_FILTER_SXCreinterpret_cast<char const *>("STR_FILTER_SXC" "\004" u8"%PRODUCTNAME Calc (*.ods;*.sxc)"
)
));
2792 OUString sFilterSXW(SwResId(STR_FILTER_SXWreinterpret_cast<char const *>("STR_FILTER_SXW" "\004" u8"%PRODUCTNAME Writer (*.odt;*.sxw)"
)
));
2793 OUString sFilterDBF(SwResId(STR_FILTER_DBFreinterpret_cast<char const *>("STR_FILTER_DBF" "\004" u8"dBase (*.dbf)"
)
));
2794 OUString sFilterXLS(SwResId(STR_FILTER_XLSreinterpret_cast<char const *>("STR_FILTER_XLS" "\004" u8"Microsoft Excel (*.xls;*.xlsx)"
)
));
2795 OUString sFilterDOC(SwResId(STR_FILTER_DOCreinterpret_cast<char const *>("STR_FILTER_DOC" "\004" u8"Microsoft Word (*.doc;*.docx)"
)
));
2796 OUString sFilterTXT(SwResId(STR_FILTER_TXTreinterpret_cast<char const *>("STR_FILTER_TXT" "\004" u8"Plain text (*.txt)"
)
));
2797 OUString sFilterCSV(SwResId(STR_FILTER_CSVreinterpret_cast<char const *>("STR_FILTER_CSV" "\004" u8"Text Comma Separated (*.csv)"
)
));
2798#ifdef _WIN32
2799 OUString sFilterMDB(SwResId(STR_FILTER_MDBreinterpret_cast<char const *>("STR_FILTER_MDB" "\004" u8"Microsoft Access (*.mdb;*.mde)"
)
));
2800 OUString sFilterACCDB(SwResId(STR_FILTER_ACCDBreinterpret_cast<char const *>("STR_FILTER_ACCDB" "\004"
u8"Microsoft Access 2007 (*.accdb,*.accde)")
));
2801#endif
2802 xFP->appendFilter( sFilterAll, "*" );
2803 xFP->appendFilter( sFilterAllData, "*.ods;*.sxc;*.odt;*.sxw;*.dbf;*.xls;*.xlsx;*.doc;*.docx;*.txt;*.csv");
2804
2805 xFP->appendFilter( sFilterSXB, "*.odb" );
2806 xFP->appendFilter( sFilterSXC, "*.ods;*.sxc" );
2807 xFP->appendFilter( sFilterSXW, "*.odt;*.sxw" );
2808 xFP->appendFilter( sFilterDBF, "*.dbf" );
2809 xFP->appendFilter( sFilterXLS, "*.xls;*.xlsx" );
2810 xFP->appendFilter( sFilterDOC, "*.doc;*.docx" );
2811 xFP->appendFilter( sFilterTXT, "*.txt" );
2812 xFP->appendFilter( sFilterCSV, "*.csv" );
2813#ifdef _WIN32
2814 xFP->appendFilter(sFilterMDB, "*.mdb;*.mde");
2815 xFP->appendFilter(sFilterACCDB, "*.accdb;*.accde");
2816#endif
2817
2818 xFP->setCurrentFilter( sFilterAll ) ;
2819 OUString sFind;
2820 if( ERRCODE_NONEErrCode(0) == aDlgHelper.Execute() )
2821 {
2822 uno::Reference< beans::XPropertySet > aSettings;
2823 const INetURLObject aURL( xFP->getSelectedFiles().getConstArray()[0] );
2824 const DBConnURIType type = GetDBunoType( aURL );
2825
2826 if( DBConnURIType::FLAT == type )
2827 {
2828 uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2829 uno::Reference < sdb::XTextConnectionSettings > xSettingsDlg = sdb::TextConnectionSettings::create(xContext);
2830 if( xSettingsDlg->execute() )
2831 aSettings.set( uno::Reference < beans::XPropertySet >( xSettingsDlg, uno::UNO_QUERY_THROW ) );
2832 }
2833 sFind = LoadAndRegisterDataSource_Impl( type, DBConnURIType::FLAT == type ? &aSettings : nullptr, aURL, nullptr, pDocShell );
2834
2835 m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(pDocShell, sFind));
2836 }
2837 return sFind;
2838}
2839
2840void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>& xStorable,
2841 const uno::Reference<embed::XStorage>& xStorage,
2842 const OUString& rStreamRelPath,
2843 const OUString& rOwnURL, bool bCopyTo)
2844{
2845 // Construct vnd.sun.star.pkg:// URL for later loading, and TargetStorage/StreamRelPath for storing.
2846 OUString const sTmpName = ConstructVndSunStarPkgUrl(rOwnURL, rStreamRelPath);
2847
2848 uno::Sequence<beans::PropertyValue> aSequence = comphelper::InitPropertySequence(
2849 {
2850 {"TargetStorage", uno::makeAny(xStorage)},
2851 {"StreamRelPath", uno::makeAny(rStreamRelPath)},
2852 {"BaseURI", uno::makeAny(rOwnURL)}
2853 });
2854 if (bCopyTo)
2855 xStorable->storeToURL(sTmpName, aSequence);
2856 else
2857 xStorable->storeAsURL(sTmpName, aSequence);
2858}
2859
2860OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pDestDir)
2861{
2862 return LoadAndRegisterDataSource_Impl( DBConnURIType::UNKNOWN, nullptr, INetURLObject(rURI), pDestDir, nullptr );
2863}
2864
2865namespace
2866{
2867 // tdf#117824 switch the embedded database away from using its current storage and point it to temporary storage
2868 // which allows the original storage to be deleted
2869 void switchEmbeddedDatabaseStorage(const uno::Reference<sdb::XDatabaseContext>& rDatabaseContext, const OUString& rName)
2870 {
2871 uno::Reference<sdb::XDocumentDataSource> xDS(rDatabaseContext->getByName(rName), uno::UNO_QUERY);
2872 if (!xDS)
2873 return;
2874 uno::Reference<document::XStorageBasedDocument> xStorageDoc(xDS->getDatabaseDocument(), uno::UNO_QUERY);
2875 if (!xStorageDoc)
2876 return;
2877 xStorageDoc->switchToStorage(comphelper::OStorageHelper::GetTemporaryStorage());
2878 }
2879}
2880
2881void SwDBManager::RevokeDataSource(const OUString& rName)
2882{
2883 uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2884 if (xDatabaseContext->hasByName(rName))
2885 {
2886 switchEmbeddedDatabaseStorage(xDatabaseContext, rName);
2887 xDatabaseContext->revokeObject(rName);
2888 }
2889}
2890
2891void SwDBManager::LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell)
2892{
2893 uno::Reference<sdb::XDatabaseContext> xDatabaseContext = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
2894
2895 OUString sDataSource = rData.sDataSource;
2896
2897 // Fallback, just in case the document would contain an embedded data source, but no DB fields.
2898 if (sDataSource.isEmpty())
2899 sDataSource = "EmbeddedDatabase";
2900
2901 SwDBManager::RevokeDataSource( sDataSource );
2902
2903 // Encode the stream name and the real path into a single URL.
2904 const INetURLObject& rURLObject = rDocShell.GetMedium()->GetURLObject();
2905 OUString const aURL = ConstructVndSunStarPkgUrl(
2906 rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE),
2907 m_sEmbeddedName);
2908
2909 uno::Reference<uno::XInterface> xDataSource(xDatabaseContext->getByName(aURL), uno::UNO_QUERY);
2910 xDatabaseContext->registerObject( sDataSource, xDataSource );
2911
2912 // temp file - don't remember connection
2913 if (rData.sDataSource.isEmpty())
2914 m_aUncommittedRegistrations.push_back(std::pair<SwDocShell*, OUString>(nullptr, sDataSource));
2915}
2916
2917void SwDBManager::ExecuteFormLetter( SwWrtShell& rSh,
2918 const uno::Sequence<beans::PropertyValue>& rProperties)
2919{
2920 //prevent second call
2921 if(m_pImpl->pMergeDialog)
2922 return ;
2923 OUString sDataSource, sDataTableOrQuery;
2924 uno::Sequence<uno::Any> aSelection;
2925
2926 sal_Int32 nCmdType = sdb::CommandType::TABLE;
2927 uno::Reference< sdbc::XConnection> xConnection;
2928
2929 svx::ODataAccessDescriptor aDescriptor(rProperties);
2930 sDataSource = aDescriptor.getDataSource();
2931 OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::Command] >>= sDataTableOrQuery)do { if (!(aDescriptor[svx::DataAccessDescriptorProperty::Command
] >>= sDataTableOrQuery)) do { if (true && (!(0
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2931" ": "), "OSL_ASSERT: %s", "0"); } } while (false);
} while (0)
;
2932 OSL_VERIFY(aDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= nCmdType)do { if (!(aDescriptor[svx::DataAccessDescriptorProperty::CommandType
] >>= nCmdType)) do { if (true && (!(0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2932" ": "), "OSL_ASSERT: %s", "0"); } } while (false);
} while (0)
;
2933
2934 if ( aDescriptor.has(svx::DataAccessDescriptorProperty::Selection) )
2935 aDescriptor[svx::DataAccessDescriptorProperty::Selection] >>= aSelection;
2936 if ( aDescriptor.has(svx::DataAccessDescriptorProperty::Connection) )
2937 aDescriptor[svx::DataAccessDescriptorProperty::Connection] >>= xConnection;
2938
2939 if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty())
2940 {
2941 OSL_FAIL("PropertyValues missing or unset")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "2941" ": "), "%s", "PropertyValues missing or unset"); }
} while (false)
;
2942 return;
2943 }
2944
2945 //always create a connection for the dialog and dispose it after the dialog has been closed
2946 SwDSParam* pFound = nullptr;
2947 if(!xConnection.is())
2948 {
2949 xConnection = SwDBManager::RegisterConnection(sDataSource);
2950 pFound = FindDSConnection(sDataSource, true);
2951 }
2952 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
2953 m_pImpl->pMergeDialog = pFact->CreateMailMergeDlg(rSh.GetView().GetViewFrame()->GetWindow().GetFrameWeld(), rSh,
2954 sDataSource,
2955 sDataTableOrQuery,
2956 nCmdType,
2957 xConnection);
2958 if(m_pImpl->pMergeDialog->Execute() == RET_OK)
2959 {
2960 aDescriptor[svx::DataAccessDescriptorProperty::Selection] <<= m_pImpl->pMergeDialog->GetSelection();
2961
2962 uno::Reference<sdbc::XResultSet> xResSet = m_pImpl->pMergeDialog->GetResultSet();
2963 if(xResSet.is())
2964 aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
2965
2966 // SfxObjectShellRef is ok, since there should be no control over the document lifetime here
2967 SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame()->GetObjectShell();
2968
2969 lcl_emitEvent(SfxEventHintId::SwMailMerge, STR_SW_EVENT_MAIL_MERGE1, xDocShell.get());
2970
2971 // prepare mail merge descriptor
2972 SwMergeDescriptor aMergeDesc( m_pImpl->pMergeDialog->GetMergeType(), rSh, aDescriptor );
2973 aMergeDesc.sSaveToFilter = m_pImpl->pMergeDialog->GetSaveFilter();
2974 aMergeDesc.bCreateSingleFile = m_pImpl->pMergeDialog->IsSaveSingleDoc();
2975 aMergeDesc.bPrefixIsFilename = aMergeDesc.bCreateSingleFile;
2976 aMergeDesc.sPrefix = m_pImpl->pMergeDialog->GetTargetURL();
2977
2978 if(!aMergeDesc.bCreateSingleFile)
2979 {
2980 if(m_pImpl->pMergeDialog->IsGenerateFromDataBase())
2981 aMergeDesc.sDBcolumn = m_pImpl->pMergeDialog->GetColumnName();
2982
2983 if(m_pImpl->pMergeDialog->IsFileEncryptedFromDataBase())
2984 aMergeDesc.sDBPasswordColumn = m_pImpl->pMergeDialog->GetPasswordColumnName();
2985 }
2986
2987 Merge( aMergeDesc );
2988
2989 lcl_emitEvent(SfxEventHintId::SwMailMergeEnd, STR_SW_EVENT_MAIL_MERGE_END2, xDocShell.get());
2990
2991 // reset the cursor inside
2992 xResSet = nullptr;
2993 aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
2994 }
2995 if(pFound)
2996 {
2997 for (const auto & pParam : m_DataSourceParams)
2998 {
2999 if (pParam.get() == pFound)
3000 {
3001 try
3002 {
3003 uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY);
3004 if(xComp.is())
3005 xComp->dispose();
3006 }
3007 catch(const uno::RuntimeException&)
3008 {
3009 //may be disposed already since multiple entries may have used the same connection
3010 }
3011 break;
3012 }
3013 //pFound doesn't need to be removed/deleted -
3014 //this has been done by the SwConnectionDisposedListener_Impl already
3015 }
3016 }
3017 m_pImpl->pMergeDialog.disposeAndClear();
3018}
3019
3020void SwDBManager::InsertText(SwWrtShell& rSh,
3021 const uno::Sequence< beans::PropertyValue>& rProperties)
3022{
3023 OUString sDataSource, sDataTableOrQuery;
3024 uno::Reference<sdbc::XResultSet> xResSet;
3025 uno::Sequence<uno::Any> aSelection;
3026 sal_Int16 nCmdType = sdb::CommandType::TABLE;
3027 uno::Reference< sdbc::XConnection> xConnection;
3028 for(const beans::PropertyValue& rValue : rProperties)
3029 {
3030 if ( rValue.Name == "DataSourceName" )
3031 rValue.Value >>= sDataSource;
3032 else if ( rValue.Name == "Command" )
3033 rValue.Value >>= sDataTableOrQuery;
3034 else if ( rValue.Name == "Cursor" )
3035 rValue.Value >>= xResSet;
3036 else if ( rValue.Name == "Selection" )
3037 rValue.Value >>= aSelection;
3038 else if ( rValue.Name == "CommandType" )
3039 rValue.Value >>= nCmdType;
3040 else if ( rValue.Name == "ActiveConnection" )
3041 rValue.Value >>= xConnection;
3042 }
3043 if(sDataSource.isEmpty() || sDataTableOrQuery.isEmpty() || !xResSet.is())
3044 {
3045 OSL_FAIL("PropertyValues missing or unset")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3045" ": "), "%s", "PropertyValues missing or unset"); }
} while (false)
;
3046 return;
3047 }
3048 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
3049 uno::Reference<sdbc::XDataSource> xSource;
3050 uno::Reference<container::XChild> xChild(xConnection, uno::UNO_QUERY);
3051 if(xChild.is())
3052 xSource.set(xChild->getParent(), uno::UNO_QUERY);
3053 if(!xSource.is())
3054 xSource = dbtools::getDataSource(sDataSource, xContext);
3055 uno::Reference< sdbcx::XColumnsSupplier > xColSupp( xResSet, uno::UNO_QUERY );
3056 SwDBData aDBData;
3057 aDBData.sDataSource = sDataSource;
3058 aDBData.sCommand = sDataTableOrQuery;
3059 aDBData.nCommandType = nCmdType;
3060
3061 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
3062 ScopedVclPtr<AbstractSwInsertDBColAutoPilot> pDlg(pFact->CreateSwInsertDBColAutoPilot( rSh.GetView(),
3063 xSource,
3064 xColSupp,
3065 aDBData ));
3066 if( RET_OK != pDlg->Execute() )
3067 return;
3068
3069 OUString sDummy;
3070 if(!xConnection.is())
3071 xConnection = xSource->getConnection(sDummy, sDummy);
3072 try
3073 {
3074 pDlg->DataToDoc( aSelection , xSource, xConnection, xResSet);
3075 }
3076 catch (const uno::Exception&)
3077 {
3078 TOOLS_WARN_EXCEPTION("sw.mailmerge", "")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "" << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "" << " " << exceptionToString
(tools_warn_exception)), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3078" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3079 }
3080}
3081
3082uno::Reference<sdbc::XDataSource> SwDBManager::getDataSourceAsParent(const uno::Reference< sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName)
3083{
3084 uno::Reference<sdbc::XDataSource> xSource;
3085 try
3086 {
3087 uno::Reference<container::XChild> xChild(_xConnection, uno::UNO_QUERY);
3088 if ( xChild.is() )
3089 xSource.set(xChild->getParent(), uno::UNO_QUERY);
3090 if ( !xSource.is() )
3091 xSource = dbtools::getDataSource(_sDataSourceName, ::comphelper::getProcessComponentContext());
3092 }
3093 catch (const uno::Exception&)
3094 {
3095 TOOLS_WARN_EXCEPTION("sw.mailmerge", "getDataSourceAsParent()")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "getDataSourceAsParent()"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getDataSourceAsParent()" << " "
<< exceptionToString(tools_warn_exception)), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"getDataSourceAsParent()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "getDataSourceAsParent()" << " " << exceptionToString
(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "getDataSourceAsParent()" << " "
<< exceptionToString(tools_warn_exception)), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"getDataSourceAsParent()" << " " << exceptionToString
(tools_warn_exception); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3095" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3096 }
3097 return xSource;
3098}
3099
3100uno::Reference<sdbc::XResultSet> SwDBManager::createCursor(const OUString& _sDataSourceName,
3101 const OUString& _sCommand,
3102 sal_Int32 _nCommandType,
3103 const uno::Reference<sdbc::XConnection>& _xConnection,
3104 const SwView* pView)
3105{
3106 uno::Reference<sdbc::XResultSet> xResultSet;
3107 try
3108 {
3109 uno::Reference< lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
3110 if( xMgr.is() )
3111 {
3112 uno::Reference<uno::XInterface> xInstance = xMgr->createInstance("com.sun.star.sdb.RowSet");
3113 uno::Reference<beans::XPropertySet> xRowSetPropSet(xInstance, uno::UNO_QUERY);
3114 if(xRowSetPropSet.is())
3115 {
3116 xRowSetPropSet->setPropertyValue("DataSourceName", uno::makeAny(_sDataSourceName));
3117 xRowSetPropSet->setPropertyValue("ActiveConnection", uno::makeAny(_xConnection));
3118 xRowSetPropSet->setPropertyValue("Command", uno::makeAny(_sCommand));
3119 xRowSetPropSet->setPropertyValue("CommandType", uno::makeAny(_nCommandType));
3120
3121 uno::Reference< sdb::XCompletedExecution > xRowSet(xInstance, uno::UNO_QUERY);
3122
3123 if ( xRowSet.is() )
3124 {
3125 weld::Window* pWindow = pView ? pView->GetFrameWeld() : nullptr;
3126 uno::Reference< task::XInteractionHandler > xHandler( task::InteractionHandler::createWithParent(comphelper::getComponentContext(xMgr), pWindow ? pWindow->GetXWindow() : nullptr), uno::UNO_QUERY_THROW );
3127 xRowSet->executeWithCompletion(xHandler);
3128 }
3129 xResultSet.set(xRowSet, uno::UNO_QUERY);
3130 }
3131 }
3132 }
3133 catch (const uno::Exception&)
3134 {
3135 TOOLS_WARN_EXCEPTION("sw.mailmerge", "Caught exception while creating a new RowSet")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.mailmerge")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Caught exception while creating a new RowSet"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.mailmerge"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Caught exception while creating a new RowSet"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Caught exception while creating a new RowSet" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Caught exception while creating a new RowSet" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Caught exception while creating a new RowSet"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Caught exception while creating a new RowSet" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.mailmerge"),
("/home/maarten/src/libreoffice/core/sw/source/uibase/dbui/dbmgr.cxx"
":" "3135" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3136 }
3137 return xResultSet;
3138}
3139
3140void SwDBManager::setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell)
3141{
3142 bool bLoad = m_sEmbeddedName != rEmbeddedName && !rEmbeddedName.isEmpty();
3143 bool bRegisterListener = m_sEmbeddedName.isEmpty() && !rEmbeddedName.isEmpty();
3144
3145 m_sEmbeddedName = rEmbeddedName;
3146
3147 if (bLoad)
3148 {
3149 uno::Reference<embed::XStorage> xStorage = rDocShell.GetStorage();
3150 // It's OK that we don't have the named sub-storage yet, in case
3151 // we're in the process of creating it.
3152 if (xStorage->hasByName(rEmbeddedName))
3153 LoadAndRegisterEmbeddedDataSource(rDocShell.GetDoc()->GetDBData(), rDocShell);
3154 }
3155
3156 if (bRegisterListener)
3157 // Register a remove listener, so we know when the embedded data source is removed.
3158 m_pImpl->m_xDataSourceRemovedListener = new SwDataSourceRemovedListener(*this);
3159}
3160
3161const OUString& SwDBManager::getEmbeddedName() const
3162{
3163 return m_sEmbeddedName;
3164}
3165
3166SwDoc* SwDBManager::getDoc() const
3167{
3168 return m_pDoc;
3169}
3170
3171void SwDBManager::releaseRevokeListener()
3172{
3173 if (m_pImpl->m_xDataSourceRemovedListener.is())
3174 {
3175 m_pImpl->m_xDataSourceRemovedListener->Dispose();
3176 m_pImpl->m_xDataSourceRemovedListener.clear();
3177 }
3178}
3179
3180SwDBManager::ConnectionDisposedListener_Impl::ConnectionDisposedListener_Impl(SwDBManager& rManager)
3181 : m_pDBManager(&rManager)
3182{
3183}
3184
3185void SwDBManager::ConnectionDisposedListener_Impl::disposing( const lang::EventObject& rSource )
3186{
3187 ::SolarMutexGuard aGuard;
3188
3189 if (!m_pDBManager) return; // we're disposed too!
3190
3191 uno::Reference<sdbc::XConnection> xSource(rSource.Source, uno::UNO_QUERY);
3192 for (size_t nPos = m_pDBManager->m_DataSourceParams.size(); nPos; nPos--)
3193 {
3194 SwDSParam* pParam = m_pDBManager->m_DataSourceParams[nPos - 1].get();
3195 if(pParam->xConnection.is() &&
3196 (xSource == pParam->xConnection))
3197 {
3198 m_pDBManager->m_DataSourceParams.erase(
3199 m_pDBManager->m_DataSourceParams.begin() + nPos - 1);
3200 }
3201 }
3202}
3203
3204std::shared_ptr<SwMailMergeConfigItem> SwDBManager::PerformMailMerge(SwView const * pView)
3205{
3206 std::shared_ptr<SwMailMergeConfigItem> xConfigItem = pView->GetMailMergeConfigItem();
3207 if (!xConfigItem)
1
Taking false branch
3208 return xConfigItem;
3209
3210 svx::ODataAccessDescriptor aDescriptor;
3211 aDescriptor.setDataSource(xConfigItem->GetCurrentDBData().sDataSource);
3212 aDescriptor[ svx::DataAccessDescriptorProperty::Connection ] <<= xConfigItem->GetConnection().getTyped();
3213 aDescriptor[ svx::DataAccessDescriptorProperty::Cursor ] <<= xConfigItem->GetResultSet();
3214 aDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= xConfigItem->GetCurrentDBData().sCommand;
3215 aDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= xConfigItem->GetCurrentDBData().nCommandType;
3216 aDescriptor[ svx::DataAccessDescriptorProperty::Selection ] <<= xConfigItem->GetSelection();
3217
3218 SwWrtShell& rSh = pView->GetWrtShell();
3219 xConfigItem->SetTargetView(nullptr);
3220
3221 SwMergeDescriptor aMergeDesc(DBMGR_MERGE_SHELL, rSh, aDescriptor);
3222 aMergeDesc.pMailMergeConfigItem = xConfigItem.get();
3223 aMergeDesc.bCreateSingleFile = true;
3224 rSh.GetDBManager()->Merge(aMergeDesc);
2
Calling 'SwDBManager::Merge'
3225
3226 return xConfigItem;
3227}
3228
3229void SwDBManager::RevokeLastRegistrations()
3230{
3231 if (m_aUncommittedRegistrations.empty())
3232 return;
3233
3234 SwView* pView = ( m_pDoc && m_pDoc->GetDocShell() ) ? m_pDoc->GetDocShell()->GetView() : nullptr;
3235 if (pView)
3236 {
3237 const std::shared_ptr<SwMailMergeConfigItem>& xConfigItem = pView->GetMailMergeConfigItem();
3238 if (xConfigItem)
3239 {
3240 xConfigItem->DisposeResultSet();
3241 xConfigItem->DocumentReloaded();
3242 }
3243 }
3244
3245 for (auto it = m_aUncommittedRegistrations.begin(); it != m_aUncommittedRegistrations.end();)
3246 {
3247 if ((m_pDoc && it->first == m_pDoc->GetDocShell()) || it->first == nullptr)
3248 {
3249 RevokeDataSource(it->second);
3250 it = m_aUncommittedRegistrations.erase(it);
3251 }
3252 else
3253 ++it;
3254 }
3255}
3256
3257void SwDBManager::CommitLastRegistrations()
3258{
3259 for (auto aIt = m_aUncommittedRegistrations.begin(); aIt != m_aUncommittedRegistrations.end();)
3260 {
3261 if (aIt->first == m_pDoc->GetDocShell() || aIt->first == nullptr)
3262 {
3263 m_aNotUsedConnections.push_back(aIt->second);
3264 aIt = m_aUncommittedRegistrations.erase(aIt);
3265 }
3266 else
3267 aIt++;
3268 }
3269}
3270
3271void SwDBManager::SetAsUsed(const OUString& rName)
3272{
3273 auto aFound = std::find(m_aNotUsedConnections.begin(), m_aNotUsedConnections.end(), rName);
3274 if (aFound != m_aNotUsedConnections.end())
3275 m_aNotUsedConnections.erase(aFound);
3276}
3277
3278void SwDBManager::RevokeNotUsedConnections()
3279{
3280 for (auto aIt = m_aNotUsedConnections.begin(); aIt != m_aNotUsedConnections.end();)
3281 {
3282 RevokeDataSource(*aIt);
3283 aIt = m_aNotUsedConnections.erase(aIt);
3284 }
3285}
3286
3287/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

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#ifndef INCLUDED_TOOLS_REF_HXX
20#define INCLUDED_TOOLS_REF_HXX
21
22#include <sal/config.h>
23#include <cassert>
24#include <tools/toolsdllapi.h>
25#include <utility>
26
27/**
28 This implements similar functionality to boost::intrusive_ptr
29*/
30
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
36 SvRef(): pObj(nullptr) {}
37
38 SvRef(SvRef&& rObj) noexcept
39 {
40 pObj = rObj.pObj;
41 rObj.pObj = nullptr;
42 }
43
44 SvRef(SvRef const & rObj): pObj(rObj.pObj)
45 {
46 if (pObj != nullptr) pObj->AddNextRef();
47 }
48
49 SvRef(T * pObjP): pObj(pObjP)
50 {
51 if (pObj != nullptr) pObj->AddFirstRef();
52 }
53
54 ~SvRef()
55 {
56 if (pObj != nullptr) pObj->ReleaseRef();
19
Taking true branch
20
Calling 'SvRefBase::ReleaseRef'
25
Returning; memory was released
57 }
58
59 void clear()
60 {
61 if (pObj != nullptr) {
62 T * pRefObj = pObj;
63 pObj = nullptr;
64 pRefObj->ReleaseRef();
65 }
66 }
67
68 SvRef & operator =(SvRef const & rObj)
69 {
70 if (rObj.pObj != nullptr) {
71 rObj.pObj->AddNextRef();
72 }
73 T * pRefObj = pObj;
74 pObj = rObj.pObj;
75 if (pRefObj != nullptr) {
76 pRefObj->ReleaseRef();
77 }
78 return *this;
79 }
80
81 SvRef & operator =(SvRef && rObj)
82 {
83 if (pObj != nullptr) {
84 pObj->ReleaseRef();
85 }
86 pObj = rObj.pObj;
87 rObj.pObj = nullptr;
88 return *this;
89 }
90
91 bool is() const { return pObj != nullptr; }
92
93 explicit operator bool() const { return is(); }
94
95 T * get() const { return pObj; }
96
97 T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 97, __extension__ __PRETTY_FUNCTION__))
; return pObj; }
98
99 T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
; return *pObj; }
100
101 bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; }
102 bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); }
103
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<T> make_ref(Args&& ... args)
113{
114 return SvRef<T>(new T(std::forward<Args>(args)...));
115}
116
117}
118
119/** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */
120class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase
121{
122 // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
123 // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
124 unsigned int nRefCount : 31;
125 // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
126 unsigned int bNoDelete : 1;
127
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
132 SvRefBase() : nRefCount(0), bNoDelete(1) {}
133 SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {}
134
135 SvRefBase & operator=(const SvRefBase &) { return *this; }
136
137 void RestoreNoDelete()
138 { bNoDelete = 1; }
139
140 void AddNextRef()
141 {
142 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
142, __extension__ __PRETTY_FUNCTION__))
;
143 ++nRefCount;
144 }
145
146 void AddFirstRef()
147 {
148 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
148, __extension__ __PRETTY_FUNCTION__))
;
149 if( bNoDelete )
150 bNoDelete = 0;
151 ++nRefCount;
152 }
153
154 void ReleaseRef()
155 {
156 assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail
("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 156, __extension__ __PRETTY_FUNCTION__))
;
21
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete
22.1
Field 'bNoDelete' is 0
22.1
Field 'bNoDelete' is 0
)
22
Assuming the condition is true
23
Taking true branch
158 {
159 // I'm not sure about the original purpose of this line, but right now
160 // it serves the purpose that anything that attempts to do an AddRef()
161 // after an object is deleted will trip an assert.
162 nRefCount = 1 << 30;
163 delete this;
24
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
185 void ResetWeakBase( ) { _pObj = nullptr; }
186 T* GetObj() { return _pObj; }
187};
188
189/** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame.
190 Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted.
191*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
198 /** Does not use initializer due to compiler warnings,
199 because the lifetime of the _xHdl object can exceed the lifetime of this class.
200 */
201 SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); }
202
203 ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); }
204
205 SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); }
206};
207
208/** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak.
209*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
215 SvCompatWeakRef( ) {}
216 SvCompatWeakRef( T* pObj )
217 { if( pObj ) _xHdl = pObj->GetHdl(); }
218#if defined(__COVERITY__)
219 ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {}
220#endif
221 SvCompatWeakRef& operator = ( T * pObj )
222 { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; }
223 bool is() const
224 { return _xHdl.is() && _xHdl->GetObj(); }
225 explicit operator bool() const { return is(); }
226 T* operator -> () const
227 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
228 operator T* () const
229 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
230};
231
232#endif
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */