Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/dataprovider/sqldataprovider.cxx
Line
Count
Source
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
10
#include "sqldataprovider.hxx"
11
#include <datatransformation.hxx>
12
#include <sal/log.hxx>
13
#include <tools/urlobj.hxx>
14
#include <salhelper/thread.hxx>
15
#include <com/sun/star/sdb/DatabaseContext.hpp>
16
#include <com/sun/star/sdb/XCompletedConnection.hpp>
17
#include <com/sun/star/task/InteractionHandler.hpp>
18
#include <com/sun/star/sdbc/XRow.hpp>
19
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
20
#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
21
#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
22
#include <connectivity/dbtools.hxx>
23
#include <dbdocutl.hxx>
24
#include <datamapper.hxx>
25
#include <utility>
26
#include <vcl/svapp.hxx>
27
#include <comphelper/processfactory.hxx>
28
#include <comphelper/diagnose_ex.hxx>
29
30
using namespace css;
31
using namespace ::com::sun::star::sdbc;
32
using namespace ::com::sun::star::uno;
33
34
namespace sc
35
{
36
class SQLFetchThread : public salhelper::Thread
37
{
38
    ScDocument& mrDocument;
39
    OUString maID;
40
    const std::vector<std::shared_ptr<sc::DataTransformation>> maDataTransformations;
41
    std::function<void()> maImportFinishedHdl;
42
43
public:
44
    SQLFetchThread(ScDocument& rDoc, const OUString& rID, std::function<void()> aImportFinishedHdl,
45
                   std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations);
46
47
    virtual void execute() override;
48
};
49
50
SQLFetchThread::SQLFetchThread(
51
    ScDocument& rDoc, const OUString& rID, std::function<void()> aImportFinishedHdl,
52
    std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations)
53
0
    : salhelper::Thread("SQL Fetch Thread")
54
0
    , mrDocument(rDoc)
55
0
    , maID(rID)
56
0
    , maDataTransformations(std::move(rTransformations))
57
0
    , maImportFinishedHdl(std::move(aImportFinishedHdl))
58
0
{
59
0
}
60
61
void SQLFetchThread::execute()
62
0
{
63
0
    sal_Int32 nIndex = maID.indexOf("@");
64
0
    if (nIndex == -1)
65
0
        return;
66
67
0
    OUString aTable = maID.copy(0, nIndex);
68
0
    OUString aDatabase = maID.copy(nIndex + 1);
69
70
0
    if (INetURLObject(aDatabase).IsExoticProtocol())
71
0
    {
72
0
        SAL_WARN("sc.ui",
73
0
                 "SQLFetchThread::execute: blocked exotic protocol: \"" << aDatabase << "\"");
74
0
        return;
75
0
    }
76
77
0
    try
78
0
    {
79
0
        uno::Reference<sdb::XDatabaseContext> xContext
80
0
            = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
81
0
        uno::Any aSourceAny = xContext->getByName(aDatabase);
82
83
0
        uno::Reference<sdb::XCompletedConnection> xSource(aSourceAny, uno::UNO_QUERY);
84
0
        if (!xSource.is())
85
0
            return;
86
87
0
        uno::Reference<task::XInteractionHandler> xHandler(
88
0
            task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(),
89
0
                                                       nullptr),
90
0
            uno::UNO_QUERY_THROW);
91
92
0
        uno::Reference<sdbc::XConnection> xConnection = xSource->connectWithCompletion(xHandler);
93
94
0
        const OUString aQuote = xConnection->getMetaData()->getIdentifierQuoteString();
95
0
        const OUString aQuotedTable = ::dbtools::quoteName(aQuote, aTable);
96
97
0
        uno::Reference<sdbc::XStatement> xStatement = xConnection->createStatement();
98
99
0
        uno::Reference<sdbc::XResultSet> xResult
100
0
            = xStatement->executeQuery("SELECT * FROM " + aQuotedTable);
101
102
0
        if (xResult.is())
103
0
        {
104
0
            Reference<sdbc::XResultSetMetaDataSupplier> xMetaDataSupplier(xResult, UNO_QUERY);
105
106
0
            Reference<sdbc::XResultSetMetaData> xMetaData = xMetaDataSupplier->getMetaData();
107
108
0
            Reference<XRow> xRow(xResult, UNO_QUERY);
109
110
0
            SCCOL nColCount = static_cast<SCCOL>(xMetaData->getColumnCount());
111
112
0
            while (xResult->next())
113
0
            {
114
0
                SCROW nRow = static_cast<SCROW>(xResult->getRow());
115
116
0
                for (SCCOL nCol = 0; nCol < nColCount; nCol++)
117
0
                {
118
0
                    ScDatabaseDocUtil::PutData(mrDocument, nCol, nRow - 1, 0, xRow, nCol + 1,
119
0
                                               xMetaData->getColumnType(nCol + 1), false);
120
0
                }
121
0
            }
122
0
        }
123
0
    }
124
0
    catch (uno::Exception&)
125
0
    {
126
0
        TOOLS_WARN_EXCEPTION("sc", "exception in database");
127
0
    }
128
129
0
    for (auto& itr : maDataTransformations)
130
0
    {
131
0
        itr->Transform(mrDocument);
132
0
    }
133
134
0
    SolarMutexGuard aGuard;
135
0
    maImportFinishedHdl();
136
0
}
137
138
SQLDataProvider::SQLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource)
139
0
    : DataProvider(rDataSource)
140
0
    , mpDocument(pDoc)
141
0
{
142
0
}
143
144
SQLDataProvider::~SQLDataProvider()
145
0
{
146
0
    if (mxSQLFetchThread.is())
147
0
    {
148
0
        SolarMutexReleaser aReleaser;
149
0
        mxSQLFetchThread->join();
150
0
    }
151
0
}
152
153
void SQLDataProvider::Import()
154
0
{
155
    // already importing data
156
0
    if (mpDoc)
157
0
        return;
158
159
0
    mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
160
0
    mpDoc->ResetClip(mpDocument, SCTAB(0));
161
0
    mxSQLFetchThread
162
0
        = new SQLFetchThread(*mpDoc, mrDataSource.getID(), [this]() { this->ImportFinished(); },
163
0
                             std::vector(mrDataSource.getDataTransformation()));
164
165
0
    if (mbDeterministic)
166
0
    {
167
0
        SolarMutexReleaser aReleaser;
168
0
        mxSQLFetchThread->execute();
169
0
    }
170
0
    else
171
0
    {
172
0
        mxSQLFetchThread->launch();
173
0
    }
174
0
}
175
176
void SQLDataProvider::ImportFinished()
177
0
{
178
0
    mrDataSource.getDBManager()->WriteToDoc(*mpDoc);
179
0
    mxSQLFetchThread.clear();
180
0
    mpDoc.reset();
181
0
}
182
183
0
const OUString& SQLDataProvider::GetURL() const { return mrDataSource.getURL(); }
184
}
185
186
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */