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 <test/bootstrapfixture.hxx>
11 
12 #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
13 #include <com/sun/star/sdbc/XColumnLocate.hpp>
14 #include <com/sun/star/sdbc/XConnection.hpp>
15 #include <com/sun/star/sdbc/XResultSet.hpp>
16 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
17 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
18 #include <com/sun/star/sdbc/XRow.hpp>
19 #include <com/sun/star/sdbc/SQLException.hpp>
20 #include <com/sun/star/sdbc/XParameters.hpp>
21 #include <com/sun/star/sdbc/XStatement.hpp>
22 #include <com/sun/star/sdbc/XDriver.hpp>
23 
24 #include <com/sun/star/util/DateTime.hpp>
25 #include <svtools/miscopt.hxx>
26 #include <osl/process.h>
27 
28 using namespace ::com::sun::star;
29 using namespace ::com::sun::star::sdb;
30 using namespace ::com::sun::star::sdbc;
31 using namespace ::com::sun::star::uno;
32 using namespace ::com::sun::star::beans;
33 
34 class MysqlTestDriver : public test::BootstrapFixture
35 {
36 private:
37     OUString m_sUrl;
38     Reference<XInterface> m_xMysqlcComponent;
39     Reference<XDriver> m_xDriver;
40     Sequence<PropertyValue> m_infos;
41 
42 public:
MysqlTestDriver()43     MysqlTestDriver()
44         : test::BootstrapFixture(false, false)
45     {
46     }
47     virtual void setUp() override;
48     virtual void tearDown() override;
49     void testDBConnection();
50     void testCreateAndDropTable();
51     void testIntegerInsertAndQuery();
52     void testDBPositionChange();
53     void testMultipleResultsets();
54     void testDBMetaData();
55     void testTimestampField();
56     void testNumericConversionPrepared();
57     void testPreparedStmtIsAfterLast();
58     void testGetStringFromBloColumnb();
59 
60     CPPUNIT_TEST_SUITE(MysqlTestDriver);
61     CPPUNIT_TEST(testDBConnection);
62     CPPUNIT_TEST(testCreateAndDropTable);
63     CPPUNIT_TEST(testIntegerInsertAndQuery);
64     CPPUNIT_TEST(testMultipleResultsets);
65     CPPUNIT_TEST(testDBMetaData);
66     CPPUNIT_TEST(testTimestampField);
67     CPPUNIT_TEST(testNumericConversionPrepared);
68     CPPUNIT_TEST(testPreparedStmtIsAfterLast);
69     CPPUNIT_TEST(testGetStringFromBloColumnb);
70     CPPUNIT_TEST_SUITE_END();
71 };
72 
tearDown()73 void MysqlTestDriver::tearDown()
74 {
75     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
76     if (!xConnection.is())
77     {
78         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
79     }
80     uno::Reference<XStatement> xStatement = xConnection->createStatement();
81     CPPUNIT_ASSERT(xStatement.is());
82     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
83     xStatement->executeUpdate("DROP TABLE IF EXISTS otherTable");
84     test::BootstrapFixture::tearDown();
85 }
86 
setUp()87 void MysqlTestDriver::setUp()
88 {
89     test::BootstrapFixture::setUp();
90 
91     /* Get URL from environment variable. This test suite should run only when
92      * there is a URL given. This is because it can be used for testing connection to
93      * external databases as well.
94      *
95      * Example URL:
96      * username/password@sdbc:mysql:mysqlc:localhost:3306/testdatabase
97      */
98     osl_getEnvironment(OUString("CONNECTIVITY_TEST_MYSQL_DRIVER").pData, &m_sUrl.pData);
99     m_xMysqlcComponent
100         = getMultiServiceFactory()->createInstance("com.sun.star.comp.sdbc.mysqlc.MysqlCDriver");
101     CPPUNIT_ASSERT_MESSAGE("no mysqlc component!", m_xMysqlcComponent.is());
102 
103     // set user name and password
104     m_infos = Sequence<PropertyValue>{ 2 };
105     m_infos[0].Name = OUString{ "user" };
106     sal_Int32 nPer = m_sUrl.indexOf("/");
107     m_infos[0].Value = makeAny(m_sUrl.copy(0, nPer));
108     m_sUrl = m_sUrl.copy(nPer + 1);
109     m_infos[1].Name = OUString{ "password" };
110     sal_Int32 nAt = m_sUrl.indexOf("@");
111     m_infos[1].Value = makeAny(m_sUrl.copy(0, nAt));
112     m_sUrl = m_sUrl.copy(nAt + 1);
113 
114     m_xDriver.set(m_xMysqlcComponent, UNO_QUERY);
115     if (!m_xDriver.is())
116     {
117         CPPUNIT_ASSERT_MESSAGE("cannot connect to mysqlc driver!", m_xDriver.is());
118     }
119 }
120 
121 /**
122  * Test database connection. It is assumed that the given URL is correct and
123  * there is a server running at the location.
124  */
testDBConnection()125 void MysqlTestDriver::testDBConnection()
126 {
127     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
128     if (!xConnection.is())
129     {
130         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
131     }
132 
133     uno::Reference<XStatement> xStatement = xConnection->createStatement();
134     CPPUNIT_ASSERT(xStatement.is());
135 
136     Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT 1");
137     CPPUNIT_ASSERT(xResultSet.is());
138     Reference<XRow> xRow(xResultSet, UNO_QUERY);
139     CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
140 
141     sal_Bool result = xResultSet->first();
142     CPPUNIT_ASSERT_MESSAGE("fetch first row failed!", result);
143 }
144 
145 /**
146  * Test creation and removal of a table
147  */
testCreateAndDropTable()148 void MysqlTestDriver::testCreateAndDropTable()
149 {
150     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
151     if (!xConnection.is())
152     {
153         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
154     }
155 
156     uno::Reference<XStatement> xStatement = xConnection->createStatement();
157     CPPUNIT_ASSERT(xStatement.is());
158     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
159 
160     auto nUpdateCount
161         = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
162     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
163 
164     // we can use the same xStatement instance here
165     nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
166     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
167 }
168 
testIntegerInsertAndQuery()169 void MysqlTestDriver::testIntegerInsertAndQuery()
170 {
171     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
172     if (!xConnection.is())
173     {
174         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
175     }
176 
177     Reference<XStatement> xStatement = xConnection->createStatement();
178     CPPUNIT_ASSERT(xStatement.is());
179     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
180 
181     auto nUpdateCount
182         = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
183     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
184 
185     Reference<XPreparedStatement> xPrepared
186         = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
187     Reference<XParameters> xParams(xPrepared, UNO_QUERY);
188     constexpr int ROW_COUNT = 3;
189     for (int i = 0; i < ROW_COUNT; ++i)
190     {
191         xParams->setLong(1, i); // first and only column
192         nUpdateCount = xPrepared->executeUpdate();
193         CPPUNIT_ASSERT_EQUAL(1, nUpdateCount); // one row is inserted at a time
194     }
195 
196     // now let's query the existing data
197     Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
198     CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
199     Reference<XRow> xRow(xResultSet, UNO_QUERY);
200     Reference<XColumnLocate> xColumnLocate(xResultSet, UNO_QUERY);
201     CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
202 
203     for (tools::Long i = 0; i < ROW_COUNT; ++i)
204     {
205         bool hasRow = xResultSet->next();
206         CPPUNIT_ASSERT_MESSAGE("not enough result after query", hasRow);
207         CPPUNIT_ASSERT_EQUAL(i, xRow->getLong(1)); // first and only column
208         CPPUNIT_ASSERT_EQUAL(i, xRow->getLong(xColumnLocate->findColumn("id"))); // test findColumn
209     }
210     CPPUNIT_ASSERT_MESSAGE("Cursor is not on last position.",
211                            xResultSet->isLast()); // cursor is on last position
212     CPPUNIT_ASSERT_EQUAL(ROW_COUNT, xResultSet->getRow()); // which is the last position
213 
214     bool hasRow = xResultSet->next(); // go to afterlast
215     // no more rows, next should return false
216     CPPUNIT_ASSERT_MESSAGE("next returns true after last row", !hasRow);
217     // cursor should be in afterlast position
218     CPPUNIT_ASSERT_EQUAL(ROW_COUNT + 1, xResultSet->getRow());
219     CPPUNIT_ASSERT_MESSAGE("Cursor is not on after-last position.", xResultSet->isAfterLast());
220 
221     nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
222     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
223 }
224 
testDBPositionChange()225 void MysqlTestDriver::testDBPositionChange()
226 {
227     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
228     if (!xConnection.is())
229     {
230         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
231     }
232 
233     Reference<XStatement> xStatement = xConnection->createStatement();
234     CPPUNIT_ASSERT(xStatement.is());
235     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
236 
237     auto nUpdateCount
238         = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
239     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
240     Reference<XPreparedStatement> xPrepared
241         = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
242     Reference<XParameters> xParams(xPrepared, UNO_QUERY);
243     constexpr int ROW_COUNT = 3;
244     for (int i = 1; i <= ROW_COUNT; ++i)
245     {
246         xParams->setLong(1, i); // first and only column
247         nUpdateCount = xPrepared->executeUpdate();
248         CPPUNIT_ASSERT_EQUAL(1, nUpdateCount); // one row is inserted at a time
249     }
250     Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
251     CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
252     Reference<XRow> xRow(xResultSet, UNO_QUERY);
253     CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
254 
255     xResultSet->afterLast();
256     CPPUNIT_ASSERT_EQUAL(ROW_COUNT + 1, xResultSet->getRow());
257     xResultSet->last();
258     CPPUNIT_ASSERT_EQUAL(ROW_COUNT, nUpdateCount);
259     CPPUNIT_ASSERT_EQUAL(ROW_COUNT, xResultSet->getRow());
260     bool successPrevious = xResultSet->previous();
261     CPPUNIT_ASSERT(successPrevious);
262     CPPUNIT_ASSERT_EQUAL(ROW_COUNT - 1, nUpdateCount);
263     xResultSet->beforeFirst();
264     xResultSet->next();
265     CPPUNIT_ASSERT_EQUAL(1, xResultSet->getRow());
266     xResultSet->first();
267     CPPUNIT_ASSERT_EQUAL(1, xResultSet->getRow());
268 
269     // Now previous should put the cursor to before-first position, but it
270     // should return with false.
271     successPrevious = xResultSet->previous();
272     CPPUNIT_ASSERT(!successPrevious);
273     CPPUNIT_ASSERT_EQUAL(0, xResultSet->getRow());
274 
275     nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
276     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
277 }
278 
testMultipleResultsets()279 void MysqlTestDriver::testMultipleResultsets()
280 {
281     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
282     CPPUNIT_ASSERT(xConnection.is());
283     Reference<XStatement> xStatement = xConnection->createStatement();
284     CPPUNIT_ASSERT(xStatement.is());
285     // create two tables
286     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
287     xStatement->executeUpdate("DROP TABLE IF EXISTS otherTable");
288     xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
289     xStatement->executeUpdate("INSERT INTO myTestTable VALUES (1)");
290     xStatement->executeUpdate("CREATE TABLE otherTable (id INTEGER PRIMARY KEY)");
291     xStatement->executeUpdate("INSERT INTO otherTable VALUES (2)");
292 
293     // create first result set
294     Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
295     CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
296     // use it
297     xResultSet->next();
298     Reference<XRow> xRowFirst(xResultSet, UNO_QUERY);
299     CPPUNIT_ASSERT_EQUAL(1l, xRowFirst->getLong(1));
300     // create second result set
301     Reference<XResultSet> xResultSet2 = xStatement->executeQuery("SELECT id from otherTable");
302     // use second result set
303     xResultSet2->next();
304     Reference<XRow> xRowSecond(xResultSet2, UNO_QUERY);
305     CPPUNIT_ASSERT_EQUAL(2l, xRowSecond->getLong(1));
306     // now use the first result set again
307 #if 0
308     // FIXME this was broken by 86c86719782243275b65f1f7f2cfdcc0e56c8cd4 adding closeResultSet() in execute()
309     CPPUNIT_ASSERT_EQUAL(1l, xRowFirst->getLong(1));
310 #endif
311 
312     xStatement->executeUpdate("DROP TABLE myTestTable");
313     xStatement->executeUpdate("DROP TABLE otherTable");
314 }
315 
testDBMetaData()316 void MysqlTestDriver::testDBMetaData()
317 {
318     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
319     if (!xConnection.is())
320         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
321     uno::Reference<XStatement> xStatement = xConnection->createStatement();
322     CPPUNIT_ASSERT(xStatement.is());
323     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
324 
325     xStatement->executeUpdate(
326         "CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, name VARCHAR(20))");
327     Reference<XPreparedStatement> xPrepared
328         = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?, ?)" });
329     Reference<XParameters> xParams(xPrepared, UNO_QUERY);
330     constexpr int ROW_COUNT = 3;
331     for (int i = 0; i < ROW_COUNT; ++i)
332     {
333         xParams->setLong(1, i);
334         xParams->setString(2, "lorem");
335         xPrepared->executeUpdate();
336     }
337 
338     Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT * from myTestTable");
339     Reference<XResultSetMetaDataSupplier> xMetaDataSupplier(xResultSet, UNO_QUERY);
340     Reference<XResultSetMetaData> xMetaData = xMetaDataSupplier->getMetaData();
341     CPPUNIT_ASSERT_EQUAL(OUString{ "id" }, xMetaData->getColumnName(1));
342     CPPUNIT_ASSERT_EQUAL(OUString{ "name" }, xMetaData->getColumnName(2));
343     CPPUNIT_ASSERT(!xMetaData->isAutoIncrement(1));
344     CPPUNIT_ASSERT(!xMetaData->isCaseSensitive(2)); // default collation should be case insensitive
345     xResultSet->next(); // use it
346     // test that meta data is usable even after fetching result set
347     CPPUNIT_ASSERT_EQUAL(OUString{ "name" }, xMetaData->getColumnName(2));
348     CPPUNIT_ASSERT_THROW_MESSAGE("exception expected when indexing out of range",
349                                  xMetaData->getColumnName(3), sdbc::SQLException);
350     xStatement->executeUpdate("DROP TABLE myTestTable");
351 }
352 
testTimestampField()353 void MysqlTestDriver::testTimestampField()
354 {
355     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
356     if (!xConnection.is())
357         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
358     uno::Reference<XStatement> xStatement = xConnection->createStatement();
359     CPPUNIT_ASSERT(xStatement.is());
360     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
361 
362     xStatement->executeUpdate(
363         "CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, mytimestamp timestamp)");
364     xStatement->executeUpdate("INSERT INTO myTestTable VALUES (1, '2008-02-16 20:15:03')");
365 
366     // now let's query
367     Reference<XResultSet> xResultSet
368         = xStatement->executeQuery("SELECT mytimestamp from myTestTable");
369 
370     xResultSet->next(); // use it
371     Reference<XRow> xRow(xResultSet, UNO_QUERY);
372     CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
373     util::DateTime dt = xRow->getTimestamp(1);
374     CPPUNIT_ASSERT_EQUAL(static_cast<short>(2008), dt.Year);
375     CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(2), dt.Month);
376     CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(16), dt.Day);
377 
378     CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(20), dt.Hours);
379     CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(15), dt.Minutes);
380     CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(3), dt.Seconds);
381 
382     xStatement->executeUpdate("DROP TABLE myTestTable");
383 }
384 
385 /**
386  * Test getting value from a decimal type column from a result set of a
387  * prepared statement, getting as a tinyint, string, short, int, long.
388  */
testNumericConversionPrepared()389 void MysqlTestDriver::testNumericConversionPrepared()
390 {
391     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
392     if (!xConnection.is())
393         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
394     uno::Reference<XStatement> xStatement = xConnection->createStatement();
395     CPPUNIT_ASSERT(xStatement.is());
396     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
397 
398     xStatement->executeUpdate("CREATE TABLE myTestTable (myDecimal DECIMAL(4,2))");
399     xStatement->executeUpdate("INSERT INTO myTestTable VALUES (11.22)");
400     Reference<XPreparedStatement> xPrepared
401         = xConnection->prepareStatement("SELECT * from myTestTable");
402     Reference<XResultSet> xResultSet = xPrepared->executeQuery();
403     xResultSet->next(); // use it
404     Reference<XRow> xRow(xResultSet, UNO_QUERY);
405     CPPUNIT_ASSERT_EQUAL(OUString("11.22"), xRow->getString(1));
406     // converting to integer types results in rounding down the number
407     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int8>(11), xRow->getByte(1));
408     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(11), xRow->getShort(1));
409     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11), xRow->getInt(1));
410     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int64>(11), xRow->getLong(1));
411 
412     xStatement->executeUpdate("DROP TABLE myTestTable");
413 }
414 
415 /**
416  * Test cursor positioning method isAfterLast in case of using prepared
417  * statement.
418  */
testPreparedStmtIsAfterLast()419 void MysqlTestDriver::testPreparedStmtIsAfterLast()
420 {
421     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
422     if (!xConnection.is())
423         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
424     uno::Reference<XStatement> xStatement = xConnection->createStatement();
425     CPPUNIT_ASSERT(xStatement.is());
426     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
427 
428     // create test table
429     xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
430     Reference<XPreparedStatement> xPrepared
431         = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
432     Reference<XParameters> xParams(xPrepared, UNO_QUERY);
433     constexpr int ROW_COUNT = 6;
434     for (int i = 0; i < ROW_COUNT; ++i)
435     {
436         xParams->setShort(1, i);
437         xPrepared->executeUpdate();
438     }
439 
440     // query test table
441     xPrepared = xConnection->prepareStatement("SELECT id from myTestTable where id = 3");
442     Reference<XResultSet> xResultSet = xPrepared->executeQuery();
443 
444     // There should be exactly one row, therefore IsAfterLast is false at first.
445     xResultSet->next();
446     CPPUNIT_ASSERT(!xResultSet->isAfterLast());
447 
448     // attempt to fetch more data
449     bool hasData = xResultSet->next();
450     CPPUNIT_ASSERT(!hasData); // now we are on "AfterLast"
451     CPPUNIT_ASSERT(xResultSet->isAfterLast());
452     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
453 }
454 
testGetStringFromBloColumnb()455 void MysqlTestDriver::testGetStringFromBloColumnb()
456 {
457     Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
458     if (!xConnection.is())
459         CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
460     uno::Reference<XStatement> xStatement = xConnection->createStatement();
461     CPPUNIT_ASSERT(xStatement.is());
462     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
463 
464     // create test table
465     xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, tinytexty "
466                               "TINYTEXT, texty TEXT, mediumTexty MEDIUMTEXT, longtexty LONGTEXT)");
467     Reference<XPreparedStatement> xPrepared = xConnection->prepareStatement(
468         OUString{ "INSERT INTO myTestTable VALUES (?, ?, ?, ?, ?)" });
469     Reference<XParameters> xParams(xPrepared, UNO_QUERY);
470     constexpr int ROW_COUNT = 6;
471     for (int i = 0; i < ROW_COUNT; ++i)
472     {
473         xParams->setShort(1, i);
474         xParams->setString(2, OUString::number(i));
475         xParams->setString(3, OUString::number(i));
476         xParams->setString(4, OUString::number(i));
477         xParams->setString(5, OUString::number(i));
478         xPrepared->executeUpdate();
479     }
480 
481     // query test table
482     xPrepared = xConnection->prepareStatement(
483         "SELECT tinytexty, texty, mediumtexty, longtexty from myTestTable where texty LIKE '3'");
484     Reference<XResultSet> xResultSet = xPrepared->executeQuery();
485     xResultSet->next();
486     Reference<XRow> xRow(xResultSet, UNO_QUERY);
487 
488     // all the textual blob types should be able to be queried via getString().
489     CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(1));
490     CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(2));
491     CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(3));
492     CPPUNIT_ASSERT_EQUAL(OUString("3"), xRow->getString(4));
493 
494     xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable");
495 }
496 
497 CPPUNIT_TEST_SUITE_REGISTRATION(MysqlTestDriver);
498 
499 CPPUNIT_PLUGIN_IMPLEMENT();
500 
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
502