Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / dbaccess / qa / unit / embeddeddb_performancetest.cxx
blob921fc9977d9892c9ef1f5f87bfcc7978015b68f1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "dbtest_base.cxx"
12 #include <memory>
13 #include <osl/process.h>
14 #include <osl/time.h>
15 #include <rtl/ustrbuf.hxx>
16 #include <tools/stream.hxx>
17 #include <unotools/tempfile.hxx>
19 #include <com/sun/star/beans/XPropertySet.hpp>
20 #include <com/sun/star/frame/XStorable.hpp>
21 #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
22 #include <com/sun/star/sdbc/XConnection.hpp>
23 #include <com/sun/star/sdbc/XParameters.hpp>
24 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
25 #include <com/sun/star/sdbc/XResultSet.hpp>
26 #include <com/sun/star/sdbc/XRow.hpp>
27 #include <com/sun/star/sdbc/XStatement.hpp>
29 using namespace ::com::sun::star;
30 using namespace ::com::sun::star::beans;
31 using namespace ::com::sun::star::frame;
32 using namespace ::com::sun::star::lang;
33 using namespace ::com::sun::star::sdb;
34 using namespace ::com::sun::star::sdbc;
35 using namespace ::com::sun::star::uno;
37 static void normaliseTimeValue(TimeValue* pVal)
39 pVal->Seconds += pVal->Nanosec / 1000000000;
40 pVal->Nanosec %= 1000000000;
43 static void getTimeDifference(const TimeValue* pTimeStart,
44 const TimeValue* pTimeEnd,
45 TimeValue* pTimeDifference)
47 // We add 1 second to the nanoseconds to ensure that we get a positive number
48 // We have to normalise anyway so this doesn't cause any harm.
49 // (Seconds/Nanosec are both unsigned)
50 pTimeDifference->Seconds = pTimeEnd->Seconds - pTimeStart->Seconds - 1;
51 pTimeDifference->Nanosec = 1000000000 + pTimeEnd->Nanosec - pTimeStart->Nanosec;
52 normaliseTimeValue(pTimeDifference);
55 static OUString getPrintableTimeValue(const TimeValue* pTimeValue)
57 return OUString::number(
58 (sal_uInt64(pTimeValue->Seconds) * SAL_CONST_UINT64(1000000000)
59 + sal_uInt64(pTimeValue->Nanosec))/ 1000000
64 * The recommended way to run this test is:
65 * 'SAL_LOG="" DBA_PERFTEST=YES make CppunitTest_dbaccess_embeddeddb_performancetest'
66 * This blocks the unnecessary exception output and show only the performance data.
68 * You also need to create the file dbaccess/qa/unit/data/wordlist, this list cannot
69 * contain any unescaped apostrophes (since the words are used directly to assemble
70 * sql statement), apostrophes are escaped using a double apostrophe, i.e. ''.
71 * one easy way of generating a list is using:
72 * 'for WORD in $(aspell dump master); do echo ${WORD//\'/\'\'}; done > dbaccess/qa/unit/data/wordlist'
74 * Note that wordlist cannot have more than 220580 lines, this is due to a hard
75 * limit in our hsqldb version.
77 * Also note that this unit test "fails" when doing performance testing, this is
78 * since by default unit test output is hidden, and thus there is no way of
79 * reading the results.
81 class EmbeddedDBPerformanceTest
82 : public DBTestBase
84 private:
85 static constexpr OUStringLiteral our_sEnableTestEnvVar = u"DBA_PERFTEST";
88 // We store the results and print them at the end due to the amount of warning
89 // noise present which otherwise obscures the results.
90 OUStringBuffer m_aOutputBuffer;
92 void printTimes(const TimeValue* pTime1, const TimeValue* pTime2, const TimeValue* pTime3);
94 void doPerformanceTestOnODB(const OUString& rDriverURL,
95 std::u16string_view rDBName,
96 const bool bUsePreparedStatement);
98 void setupTestTable(uno::Reference< XConnection > const & xConnection);
100 SvFileStream *getWordListStream();
102 // Individual Tests
103 void performPreparedStatementInsertTest(
104 uno::Reference< XConnection > const & xConnection,
105 std::u16string_view rDBName);
106 void performStatementInsertTest(
107 uno::Reference< XConnection > const & xConnection,
108 std::u16string_view rDBName);
109 void performReadTest(
110 uno::Reference< XConnection > const & xConnection,
111 std::u16string_view rDBName);
113 // Perform all tests on a given DB.
114 void testFirebird();
115 void testHSQLDB();
117 public:
118 void testPerformance();
120 CPPUNIT_TEST_SUITE(EmbeddedDBPerformanceTest);
121 CPPUNIT_TEST(testPerformance);
122 CPPUNIT_TEST_SUITE_END();
125 SvFileStream* EmbeddedDBPerformanceTest::getWordListStream()
127 OUString wlPath = createFileURL(u"wordlist");
128 return new SvFileStream(wlPath, StreamMode::READ);
131 void EmbeddedDBPerformanceTest::printTimes(
132 const TimeValue* pTime1,
133 const TimeValue* pTime2,
134 const TimeValue* pTime3)
136 m_aOutputBuffer.append(
137 getPrintableTimeValue(pTime1) + "\t" +
138 getPrintableTimeValue(pTime2) + "\t" +
139 getPrintableTimeValue(pTime3) + "\t"
140 "\n");
143 // TODO: we probably should create a document from scratch instead?
145 void EmbeddedDBPerformanceTest::testPerformance()
147 OUString sEnabled;
148 osl_getEnvironment(OUString(our_sEnableTestEnvVar).pData, &sEnabled.pData);
150 if (sEnabled.isEmpty())
151 return;
153 m_aOutputBuffer.append("---------------------\n");
154 testFirebird();
155 m_aOutputBuffer.append("---------------------\n");
156 testHSQLDB();
157 m_aOutputBuffer.append("---------------------\n");
159 fprintf(stdout, "Performance Test Results:\n");
160 fprintf(stdout, "%s",
161 OUStringToOString(m_aOutputBuffer.makeStringAndClear(),
162 RTL_TEXTENCODING_UTF8)
163 .getStr()
166 // We want the results printed, but unit test output is only printed on failure
167 // Hence we deliberately fail the test.
168 CPPUNIT_ASSERT(false);
171 void EmbeddedDBPerformanceTest::testFirebird()
174 m_aOutputBuffer.append("Standard Insert\n");
175 doPerformanceTestOnODB("sdbc:embedded:firebird", u"Firebird", false);
176 m_aOutputBuffer.append("PreparedStatement Insert\n");
177 doPerformanceTestOnODB("sdbc:embedded:firebird", u"Firebird", true);
180 void EmbeddedDBPerformanceTest::testHSQLDB()
182 m_aOutputBuffer.append("Standard Insert\n");
183 doPerformanceTestOnODB("sdbc:embedded:hsqldb", u"HSQLDB", false);
184 m_aOutputBuffer.append("PreparedStatement Insert\n");
185 doPerformanceTestOnODB("sdbc:embedded:hsqldb", u"HSQLDB", true);
189 * Use an existing .odb to do performance tests on. The database cannot have
190 * a table of the name PFTESTTABLE.
192 void EmbeddedDBPerformanceTest::doPerformanceTestOnODB(
193 const OUString& rDriverURL,
194 std::u16string_view rDBName,
195 const bool bUsePreparedStatement)
197 ::utl::TempFileNamed aFile;
198 aFile.EnableKillingFile();
201 uno::Reference< XOfficeDatabaseDocument > xDocument(
202 m_xSFactory->createInstance("com.sun.star.sdb.OfficeDatabaseDocument"),
203 UNO_QUERY_THROW);
204 uno::Reference< XStorable > xStorable(xDocument, UNO_QUERY_THROW);
206 uno::Reference< XDataSource > xDataSource = xDocument->getDataSource();
207 uno::Reference< XPropertySet > xPropertySet(xDataSource, UNO_QUERY_THROW);
208 xPropertySet->setPropertyValue("URL", Any(rDriverURL));
210 xStorable->storeAsURL(aFile.GetURL(), uno::Sequence< beans::PropertyValue >());
213 uno::Reference< XOfficeDatabaseDocument > xDocument(
214 loadFromDesktop(aFile.GetURL()), UNO_QUERY_THROW);
216 uno::Reference< XConnection > xConnection =
217 getConnectionForDocument(xDocument);
219 setupTestTable(xConnection);
221 if (bUsePreparedStatement)
222 performPreparedStatementInsertTest(xConnection, rDBName);
223 else
224 performStatementInsertTest(xConnection, rDBName);
226 performReadTest(xConnection, rDBName);
229 void EmbeddedDBPerformanceTest::setupTestTable(
230 uno::Reference< XConnection > const & xConnection)
232 uno::Reference< XStatement > xStatement = xConnection->createStatement();
234 // Although not strictly necessary we use quoted identifiers to reflect
235 // the fact that Base always uses quoted identifiers.
236 xStatement->execute(
237 "CREATE TABLE \"PFTESTTABLE\" ( \"ID\" INTEGER NOT NULL PRIMARY KEY "
238 ", \"STRINGCOLUMNA\" VARCHAR (50) "
239 ")");
241 xConnection->commit();
244 void EmbeddedDBPerformanceTest::performPreparedStatementInsertTest(
245 uno::Reference< XConnection > const & xConnection,
246 std::u16string_view rDBName)
248 uno::Reference< XPreparedStatement > xPreparedStatement =
249 xConnection->prepareStatement(
250 "INSERT INTO \"PFTESTTABLE\" ( \"ID\", "
251 "\"STRINGCOLUMNA\" "
252 ") VALUES ( ?, ? )"
255 uno::Reference< XParameters > xParameters(xPreparedStatement, UNO_QUERY_THROW);
257 std::unique_ptr< SvFileStream > pFile(getWordListStream());
259 OUString aWord;
260 sal_Int32 aID = 0;
262 TimeValue aStart, aMiddle, aEnd;
263 osl_getSystemTime(&aStart);
265 while (pFile->ReadByteStringLine(aWord, RTL_TEXTENCODING_UTF8))
267 xParameters->setInt(1, aID++);
268 xParameters->setString(2, aWord);
269 xPreparedStatement->execute();
271 osl_getSystemTime(&aMiddle);
272 xConnection->commit();
273 osl_getSystemTime(&aEnd);
276 TimeValue aTimeInsert, aTimeCommit, aTimeTotal;
277 getTimeDifference(&aStart, &aMiddle, &aTimeInsert);
278 getTimeDifference(&aMiddle, &aEnd, &aTimeCommit);
279 getTimeDifference(&aStart, &aEnd, &aTimeTotal);
280 m_aOutputBuffer.append(OUString::Concat("Insert: ") + rDBName + "\n");
281 printTimes(&aTimeInsert, &aTimeCommit, &aTimeTotal);
283 pFile->Close();
286 void EmbeddedDBPerformanceTest::performStatementInsertTest(
287 uno::Reference< XConnection > const & xConnection,
288 std::u16string_view rDBName)
290 uno::Reference< XStatement > xStatement =
291 xConnection->createStatement();
293 std::unique_ptr< SvFileStream > pFile(getWordListStream());
295 OUString aWord;
296 sal_Int32 aID = 0;
298 TimeValue aStart, aMiddle, aEnd;
299 osl_getSystemTime(&aStart);
301 while (pFile->ReadByteStringLine(aWord, RTL_TEXTENCODING_UTF8))
303 xStatement->execute(
304 "INSERT INTO \"PFTESTTABLE\" ( \"ID\", "
305 "\"STRINGCOLUMNA\" "
306 ") VALUES ( "
307 + OUString::number(aID++) + ", '" + aWord + "' )"
310 osl_getSystemTime(&aMiddle);
311 xConnection->commit();
312 osl_getSystemTime(&aEnd);
314 TimeValue aTimeInsert, aTimeCommit, aTimeTotal;
315 getTimeDifference(&aStart, &aMiddle, &aTimeInsert);
316 getTimeDifference(&aMiddle, &aEnd, &aTimeCommit);
317 getTimeDifference(&aStart, &aEnd, &aTimeTotal);
318 m_aOutputBuffer.append(OUString::Concat("Insert: ") + rDBName + "\n");
319 printTimes(&aTimeInsert, &aTimeCommit, &aTimeTotal);
321 pFile->Close();
324 void EmbeddedDBPerformanceTest::performReadTest(
325 uno::Reference< XConnection > const & xConnection,
326 std::u16string_view rDBName)
328 uno::Reference< XStatement > xStatement = xConnection->createStatement();
330 TimeValue aStart, aMiddle, aEnd;
331 osl_getSystemTime(&aStart);
333 uno::Reference< XResultSet > xResults = xStatement->executeQuery("SELECT * FROM PFTESTTABLE");
335 osl_getSystemTime(&aMiddle);
337 uno::Reference< XRow > xRow(xResults, UNO_QUERY_THROW);
339 while (xResults->next())
341 xRow->getString(2);
343 osl_getSystemTime(&aEnd);
345 TimeValue aTimeSelect, aTimeIterate, aTimeTotal;
346 getTimeDifference(&aStart, &aMiddle, &aTimeSelect);
347 getTimeDifference(&aMiddle, &aEnd, &aTimeIterate);
348 getTimeDifference(&aStart, &aEnd, &aTimeTotal);
349 m_aOutputBuffer.append(OUString::Concat("Read from: ") + rDBName + "\n");
350 printTimes(&aTimeSelect, &aTimeIterate, &aTimeTotal);
353 CPPUNIT_TEST_SUITE_REGISTRATION(EmbeddedDBPerformanceTest);
355 CPPUNIT_PLUGIN_IMPLEMENT();
357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */