LibreOffice Module connectivity (master) 1
mysqlc_connection.cxx
Go to the documentation of this file.
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 "mysqlc_catalog.hxx"
21#include "mysqlc_connection.hxx"
23#include <com/sun/star/sdbc/SQLException.hpp>
24
25#include "mysqlc_driver.hxx"
26#include "mysqlc_statement.hxx"
28#include "mysqlc_general.hxx"
29
30#include <com/sun/star/beans/NamedValue.hpp>
31
33
34using namespace connectivity::mysqlc;
35
36using namespace com::sun::star::uno;
37using namespace com::sun::star::container;
38using namespace com::sun::star::beans;
39using namespace com::sun::star::sdbc;
40using namespace com::sun::star::sdbcx;
41using ::osl::MutexGuard;
42
43namespace
44{
45void lcl_executeUpdate(MYSQL* pMySql, const OString& sql)
46{
47 mysql_real_query(pMySql, sql.getStr(), sql.getLength());
48 // TODO handle error
49}
50}
51
52OConnection::OConnection(MysqlCDriver& _rDriver)
54 , m_mysql()
55 , m_xCatalog(nullptr)
56 , m_xMetaData(nullptr)
57 , m_xDriver(&_rDriver)
58{
59}
60
62{
63 if (!isClosed())
64 {
65 close();
66 }
67}
68
69void OConnection::construct(const OUString& url, const Sequence<PropertyValue>& info)
70{
71 MutexGuard aGuard(m_aMutex);
72
73 mysql_library_init(0, nullptr, nullptr);
74 mysql_init(&m_mysql);
75
76 OString charset_name{ "utf8mb4" };
77 mysql_options(&m_mysql, MYSQL_SET_CHARSET_NAME, charset_name.getStr());
78
79 sal_Int32 nIndex;
80 OUString token;
81 OUString aHostName("localhost");
82 sal_Int32 nPort = 3306;
83 OUString aDbName;
84
86
87 // parse url. Url has the following format:
88 // external server: sdbc:mysqlc:[hostname]:[port]/[dbname]
89
90 if (url.startsWith("sdbc:mysqlc:"))
91 {
92 nIndex = 12;
93 }
94 else
95 {
96 // sdbc:mysql:mysqlc:[hostname]:[port]/[dbname]
97 nIndex = 18;
98 }
99
100 token = url.getToken(0, '/', nIndex);
101 if (!token.isEmpty())
102 {
103 sal_Int32 nIndex1 = 0;
104 OUString hostandport = token.getToken(0, ':', nIndex1);
105 if (!hostandport.isEmpty())
106 {
107 aHostName = hostandport;
108 hostandport = token.getToken(0, ':', nIndex1);
109 if (!hostandport.isEmpty() && nIndex1)
110 {
111 nPort = hostandport.toInt32();
112 }
113 token = url.getToken(0, '/', nIndex);
114 if (!token.isEmpty() && nIndex)
115 {
116 aDbName = token;
117 }
118 }
119 }
120
121 // get user and password for mysql connection
122 const PropertyValue* pIter = info.getConstArray();
123 const PropertyValue* pEnd = pIter + info.getLength();
124 OUString aUser, aPass, sUnixSocket, sNamedPipe;
125 bool unixSocketPassed = false;
126 bool namedPipePassed = false;
127
129 for (; pIter != pEnd; ++pIter)
130 {
131 if (pIter->Name == "user")
132 {
133 OSL_VERIFY(pIter->Value >>= aUser);
134 }
135 else if (pIter->Name == "password")
136 {
137 OSL_VERIFY(pIter->Value >>= aPass);
138 }
139 else if (pIter->Name == "LocalSocket")
140 {
141 OSL_VERIFY(pIter->Value >>= sUnixSocket);
142 unixSocketPassed = !sUnixSocket.isEmpty();
143 }
144 else if (pIter->Name == "NamedPipe")
145 {
146 OSL_VERIFY(pIter->Value >>= sNamedPipe);
147 namedPipePassed = !sNamedPipe.isEmpty();
148 }
149 else if (pIter->Name == "PublicConnectionURL")
150 {
151 OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
152 }
153 else if (pIter->Name == "NewURL")
154 { // legacy name for "PublicConnectionURL"
155 OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
156 }
157 }
158
159 OString host_str = OUStringToOString(aHostName, m_settings.encoding);
160 OString user_str = OUStringToOString(aUser, m_settings.encoding);
161 OString pass_str = OUStringToOString(aPass, m_settings.encoding);
162 OString schema_str = OUStringToOString(aDbName, m_settings.encoding);
163 OString socket_str;
164
165 // use TCP as connection by default
166 mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP;
167 if (unixSocketPassed)
168 {
169 socket_str = OUStringToOString(sUnixSocket, m_settings.encoding);
170 protocol = MYSQL_PROTOCOL_SOCKET;
171 }
172 else if (namedPipePassed)
173 {
174 socket_str = OUStringToOString(sNamedPipe, m_settings.encoding);
175 protocol = MYSQL_PROTOCOL_PIPE;
176 }
177
178 mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol);
179
180 // flags can also be passed as last parameter
181 if (!mysql_real_connect(&m_mysql, host_str.getStr(), user_str.getStr(), pass_str.getStr(),
182 schema_str.getStr(), nPort, socket_str.getStr(),
183 CLIENT_MULTI_STATEMENTS))
185 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
187
188 // Check if the server is 4.1 or above
189 if (getMysqlVersion() < 40100)
190 {
191 throw SQLException("MariaDB LibreOffice Connector requires MySQL Server 4.1 or above",
192 *this, OUString(), 0, Any());
193 }
194
195 lcl_executeUpdate(&m_mysql,
196 OString{ "SET session sql_mode='ANSI_QUOTES,NO_AUTO_VALUE_ON_ZERO'" });
197 lcl_executeUpdate(&m_mysql, OString{ "SET NAMES utf8mb4" });
198}
199
201{
202 return "com.sun.star.sdbc.drivers.mysqlc.OConnection";
203}
204
205css::uno::Sequence<OUString> OConnection::getSupportedServiceNames()
206{
207 return { "com.sun.star.sdbc.Connection" };
208}
209
210sal_Bool OConnection::supportsService(OUString const& ServiceName)
211{
213}
214
215Reference<XStatement> SAL_CALL OConnection::createStatement()
216{
217 MutexGuard aGuard(m_aMutex);
218 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
219
220 // create a statement
221 // the statement can only be executed once
222 Reference<XStatement> xReturn = new OStatement(this);
223 m_aStatements.push_back(WeakReferenceHelper(xReturn));
224
225 return xReturn;
226}
227
228Reference<XPreparedStatement> SAL_CALL OConnection::prepareStatement(const OUString& _sSql)
229{
230 MutexGuard aGuard(m_aMutex);
231 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
232 const OString sSqlStatement
233 = OUStringToOString(_sSql, getConnectionEncoding()); // FIXME transform statement ?
234
235 MYSQL_STMT* pStmt = mysql_stmt_init(&m_mysql);
236 mysql_stmt_prepare(pStmt, sSqlStatement.getStr(), sSqlStatement.getLength());
237
238 unsigned int nErrorNum = mysql_errno(&m_mysql);
239 if (nErrorNum != 0)
241 mysql_sqlstate(&m_mysql), nErrorNum, *this,
243
244 Reference<XPreparedStatement> xStatement = new OPreparedStatement(this, pStmt);
245 m_aStatements.push_back(WeakReferenceHelper(xStatement));
246 return xStatement;
247}
248
249Reference<XPreparedStatement> SAL_CALL OConnection::prepareCall(const OUString& /*_sSql*/)
250{
251 MutexGuard aGuard(m_aMutex);
252 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
253
254 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OConnection::prepareCall", *this);
255 return Reference<XPreparedStatement>();
256}
257
258OUString SAL_CALL OConnection::nativeSQL(const OUString& /*_sSql*/)
259{
260 // const OUString sSqlStatement = transFormPreparedStatement( _sSql );
261 // TODO
262 return OUString();
263}
264
265void SAL_CALL OConnection::setAutoCommit(sal_Bool autoCommit)
266{
267 MutexGuard aGuard(m_aMutex);
268 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
269 if (!mysql_autocommit(&m_mysql, autoCommit))
271 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
273}
274
276{
277 // you have to distinguish which if you are in autocommit mode or not
278 // at normal case true should be fine here
279
280 // TODO use SELECT @@autocommit query for that
281 MutexGuard aGuard(m_aMutex);
282 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
283
284 return false;
285}
286
287void SAL_CALL OConnection::commit()
288{
289 MutexGuard aGuard(m_aMutex);
290 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
291
292 if (!mysql_commit(&m_mysql))
294 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
296}
297
299{
300 MutexGuard aGuard(m_aMutex);
301 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
302
303 if (!mysql_rollback(&m_mysql))
305 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
307}
308
310{
311 MutexGuard aGuard(m_aMutex);
312
313 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
314 return OConnection_BASE::rBHelper.bDisposed;
315}
316
317Reference<XDatabaseMetaData> SAL_CALL OConnection::getMetaData()
318{
319 MutexGuard aGuard(m_aMutex);
320 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
321
322 Reference<XDatabaseMetaData> xMetaData = m_xMetaData;
323 if (!xMetaData.is())
324 {
325 xMetaData = new ODatabaseMetaData(*this, &m_mysql);
326 m_xMetaData = xMetaData;
327 }
328
329 return xMetaData;
330}
331
332void SAL_CALL OConnection::setReadOnly(sal_Bool readOnly)
333{
334 MutexGuard aGuard(m_aMutex);
335 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
336
337 m_settings.readOnly = readOnly;
338}
339
341{
342 MutexGuard aGuard(m_aMutex);
343 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
344
345 // return if your connection to readonly
346 return m_settings.readOnly;
347}
348
349void SAL_CALL OConnection::setCatalog(const OUString& /*catalog*/)
350{
351 MutexGuard aGuard(m_aMutex);
352 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
353
354 // TODO How?
355}
356
357OUString SAL_CALL OConnection::getCatalog()
358{
359 MutexGuard aGuard(m_aMutex);
360 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
361
362 // TODO How?
363 return OUString{};
364}
365
366void SAL_CALL OConnection::setTransactionIsolation(sal_Int32 /*level*/)
367{
368 MutexGuard aGuard(m_aMutex);
369 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
370
371 // TODO
372}
373
375{
376 MutexGuard aGuard(m_aMutex);
377 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
378
379 return 0; // TODO
380}
381
382Reference<XNameAccess> SAL_CALL OConnection::getTypeMap()
383{
384 MutexGuard aGuard(m_aMutex);
385 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
386
387 Reference<XNameAccess> t = m_typeMap;
388 return t;
389}
390
391void SAL_CALL OConnection::setTypeMap(const Reference<XNameAccess>& typeMap)
392{
393 MutexGuard aGuard(m_aMutex);
394 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
395
396 m_typeMap = typeMap;
397}
398
399// XCloseable
400void SAL_CALL OConnection::close()
401{
402 /*
403 we need block, because the mutex is a local variable,
404 which will guard the block
405 */
406 {
407 // we just dispose us
408 MutexGuard aGuard(m_aMutex);
409 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
410 }
411 mysql_close(&m_mysql);
412 mysql_library_end();
413 dispose();
414}
415
416// XWarningsSupplier
418{
419 Any x;
420 // when you collected some warnings -> return it
421 return x;
422}
423
425{
426 // you should clear your collected warnings here#
427}
428
430{
431 // we noticed that we should be destroyed in near future so we have to dispose our statements
432 MutexGuard aGuard(m_aMutex);
433
434 for (auto const& statement : m_aStatements)
435 {
436 Reference<XComponent> xComp(statement.get(), UNO_QUERY);
437 if (xComp.is())
438 {
439 xComp->dispose();
440 }
441 }
442 m_aStatements.clear();
443
445
447}
448
450{
451 MutexGuard aGuard(m_aMutex);
452 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
453
454 unsigned long version = mysql_get_server_version(&m_mysql);
455 return static_cast<sal_Int32>(version);
456}
457
458OUString OConnection::transFormPreparedStatement(const OUString& _sSQL)
459{
460 OUString sSqlStatement = _sSQL;
461 if (!m_xParameterSubstitution.is())
462 {
463 try
464 {
465 Reference<XConnection> xCon = this;
466 Sequence<Any> aArgs{ Any(NamedValue("ActiveConnection", Any(xCon))) };
467
469 m_xDriver->getFactory()->createInstanceWithArguments(
470 "org.openoffice.comp.helper.ParameterSubstitution", aArgs),
471 UNO_QUERY);
472 }
473 catch (const Exception&)
474 {
475 }
476 }
478 {
479 try
480 {
481 sSqlStatement = m_xParameterSubstitution->substituteVariables(sSqlStatement, true);
482 }
483 catch (const Exception&)
484 {
485 }
486 }
487 return sSqlStatement;
488}
489
490//----- XUnoTunnel ----------------------------------------------------------
491// virtual
492sal_Int64 SAL_CALL OConnection::getSomething(const css::uno::Sequence<sal_Int8>& rId)
493{
494 return comphelper::getSomethingImpl(rId, this);
495}
496
497// static
498const Sequence<sal_Int8>& OConnection::getUnoTunnelId()
499{
500 static const comphelper::UnoIdInit implId;
501 return implId.getSeq();
502}
503
504Reference<XTablesSupplier> OConnection::createCatalog()
505{
506 MutexGuard aGuard(m_aMutex);
507
508 // m_xCatalog is a weak reference. Reuse it if it still exists.
509 Reference<XTablesSupplier> xCatalog = m_xCatalog;
510 if (xCatalog.is())
511 {
512 return xCatalog;
513 }
514 else
515 {
516 xCatalog = new Catalog(this);
517 m_xCatalog = xCatalog;
518 return m_xCatalog;
519 }
520}
521
522/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
const css::uno::Sequence< sal_Int8 > & getSeq() const
virtual void SAL_CALL disposing() override
static rtl_TextEncoding getDefaultEncoding()
sal_Int32 SAL_CALL getTransactionIsolation() override
void SAL_CALL setCatalog(const OUString &catalog) override
void SAL_CALL setAutoCommit(sal_Bool autoCommit) override
void SAL_CALL setTransactionIsolation(sal_Int32 level) override
virtual void SAL_CALL disposing() override
css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData() override
css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog()
Create and/or connect to the sdbcx Catalog.
void SAL_CALL setTypeMap(const css::uno::Reference< css::container::XNameAccess > &typeMap) override
OUString SAL_CALL nativeSQL(const OUString &sql) override
sal_Bool SAL_CALL isClosed() override
css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall(const OUString &sql) override
rtl_TextEncoding getConnectionEncoding() const
void construct(const OUString &url, const css::uno::Sequence< css::beans::PropertyValue > &info)
css::uno::Reference< css::container::XNameAccess > m_typeMap
OUString transFormPreparedStatement(const OUString &_sSQL)
void SAL_CALL clearWarnings() override
css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement(const OUString &sql) override
sal_Bool SAL_CALL getAutoCommit() override
void SAL_CALL setReadOnly(sal_Bool readOnly) override
rtl::Reference< MysqlCDriver > m_xDriver
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &rId) override
css::uno::WeakReference< css::sdbcx::XTablesSupplier > m_xCatalog
css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap() override
sal_Bool SAL_CALL isReadOnly() override
virtual OUString SAL_CALL getImplementationName() override
css::uno::Reference< css::util::XStringSubstitution > m_xParameterSubstitution
css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement() override
OUString SAL_CALL getCatalog() override
css::uno::Any SAL_CALL getWarnings() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::uno::WeakReference< css::sdbc::XDatabaseMetaData > m_xMetaData
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
virtual sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
mutable::osl::Mutex m_aMutex
float x
std::mutex m_aMutex
sal_Int32 nIndex
@ Exception
sal_Int64 getSomethingImpl(const css::uno::Sequence< sal_Int8 > &rId, T *pThis, FallbackToGetSomethingOf< Base >={})
void checkDisposed(bool _bThrow)
::cppu::WeakComponentImplHelper< css::sdbc::XConnection, css::sdbc::XWarningsSupplier, css::lang::XUnoTunnel, css::lang::XServiceInfo > OMetaConnection_BASE
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
void throwSQLExceptionWithMsg(const char *msg, const char *SQLSTATE, unsigned int errorNum, const css::uno::Reference< css::uno::XInterface > &_context, const rtl_TextEncoding encoding)
void throwFeatureNotImplementedException(const char *_pAsciiFeatureName, const css::uno::Reference< XInterface > &_rxContext)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:100
void dispose()
unsigned char sal_Bool