bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / mysqlc / mysqlc_connection.cxx
blob600e131b89b191a7d01c0c8defe8d598bf408fb8
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "mysqlc_connection.hxx"
21 #include "mysqlc_databasemetadata.hxx"
23 #include "mysqlc_driver.hxx"
24 #include "mysqlc_statement.hxx"
25 #include "mysqlc_preparedstatement.hxx"
26 #include "mysqlc_general.hxx"
28 #include <com/sun/star/beans/NamedValue.hpp>
30 #include <osl/diagnose.h>
31 #include <cppuhelper/supportsservice.hxx>
33 using namespace connectivity::mysqlc;
35 using namespace com::sun::star::uno;
36 using namespace com::sun::star::container;
37 using namespace com::sun::star::lang;
38 using namespace com::sun::star::beans;
39 using namespace com::sun::star::sdbc;
40 using ::osl::MutexGuard;
42 #define MYSQLC_URI_PREFIX "sdbc:mysqlc:"
44 namespace
46 void lcl_executeUpdate(MYSQL* pMySql, const OString& sql)
48 mysql_real_query(pMySql, sql.getStr(), sql.getLength());
49 // TODO handle error
53 OConnection::OConnection(MysqlCDriver& _rDriver)
54 : OMetaConnection_BASE(m_aMutex)
55 , m_mysql()
56 , m_xMetaData(nullptr)
57 , m_xDriver(&_rDriver)
61 OConnection::~OConnection()
63 if (!isClosed())
65 close();
69 void OConnection::construct(const OUString& url, const Sequence<PropertyValue>& info)
71 MutexGuard aGuard(m_aMutex);
73 mysql_library_init(0, nullptr, nullptr);
74 mysql_init(&m_mysql);
76 // use TCP as connection
77 mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP;
78 mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol);
79 OString charset_name{ "utf8mb4" };
80 mysql_options(&m_mysql, MYSQL_SET_CHARSET_NAME, charset_name.getStr());
82 sal_Int32 nIndex;
83 OUString token;
84 OUString aHostName("localhost");
85 sal_Int32 nPort = 3306;
86 OUString aDbName;
88 m_settings.encoding = MysqlCDriver::getDefaultEncoding();
90 // parse url. Url has the following format:
91 // external server: sdbc:mysqlc:[hostname]:[port]/[dbname]
93 if (url.startsWith(MYSQLC_URI_PREFIX))
95 nIndex = 12;
97 else
99 // sdbc:mysql:mysqlc:[hostname]:[port]/[dbname]
100 nIndex = 18;
103 token = url.getToken(0, '/', nIndex);
104 if (!token.isEmpty())
106 sal_Int32 nIndex1 = 0;
107 OUString hostandport = token.getToken(0, ':', nIndex1);
108 if (!hostandport.isEmpty())
110 aHostName = hostandport;
111 hostandport = token.getToken(0, ':', nIndex1);
112 if (!hostandport.isEmpty() && nIndex1)
114 nPort = hostandport.toInt32();
116 token = url.getToken(0, '/', nIndex);
117 if (!token.isEmpty() && nIndex)
119 aDbName = token;
124 // get user and password for mysql connection
125 const PropertyValue* pIter = info.getConstArray();
126 const PropertyValue* pEnd = pIter + info.getLength();
127 OUString aUser, aPass, sUnixSocket, sNamedPipe;
128 bool unixSocketPassed = false;
129 bool namedPipePassed = false;
131 m_settings.connectionURL = url;
132 for (; pIter != pEnd; ++pIter)
134 if (pIter->Name == "user")
136 OSL_VERIFY(pIter->Value >>= aUser);
138 else if (pIter->Name == "password")
140 OSL_VERIFY(pIter->Value >>= aPass);
142 else if (pIter->Name == "LocalSocket")
144 OSL_VERIFY(pIter->Value >>= sUnixSocket);
145 unixSocketPassed = !sUnixSocket.isEmpty();
147 else if (pIter->Name == "NamedPipe")
149 OSL_VERIFY(pIter->Value >>= sNamedPipe);
150 namedPipePassed = !sNamedPipe.isEmpty();
152 else if (pIter->Name == "PublicConnectionURL")
154 OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
156 else if (pIter->Name == "NewURL")
157 { // legacy name for "PublicConnectionURL"
158 OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
162 OString host_str = OUStringToOString(aHostName, m_settings.encoding);
163 OString user_str = OUStringToOString(aUser, m_settings.encoding);
164 OString pass_str = OUStringToOString(aPass, m_settings.encoding);
165 OString schema_str = OUStringToOString(aDbName, m_settings.encoding);
166 OString socket_str;
167 if (unixSocketPassed)
169 socket_str = OUStringToOString(sUnixSocket, m_settings.encoding);
171 else if (namedPipePassed)
173 socket_str = OUStringToOString(sNamedPipe, m_settings.encoding);
176 // flags can also be passed as last parameter
177 if (!mysql_real_connect(&m_mysql, host_str.getStr(), user_str.getStr(), pass_str.getStr(),
178 schema_str.getStr(), nPort, socket_str.getStr(),
179 CLIENT_MULTI_STATEMENTS))
180 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
181 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
182 getConnectionEncoding());
184 // Check if the server is 4.1 or above
185 if (getMysqlVersion() < 40100)
187 throw SQLException("MariaDB LibreOffice Connector requires MySQL Server 4.1 or above",
188 *this, OUString(), 0, Any());
191 lcl_executeUpdate(&m_mysql,
192 OString{ "SET session sql_mode='ANSI_QUOTES,NO_AUTO_VALUE_ON_ZERO'" });
193 lcl_executeUpdate(&m_mysql, OString{ "SET NAMES utf8mb4" });
196 OUString OConnection::getImplementationName()
198 return "com.sun.star.sdbc.drivers.mysqlc.OConnection";
201 css::uno::Sequence<OUString> OConnection::getSupportedServiceNames()
203 return { "com.sun.star.sdbc.Connection" };
206 sal_Bool OConnection::supportsService(OUString const& ServiceName)
208 return cppu::supportsService(this, ServiceName);
211 Reference<XStatement> SAL_CALL OConnection::createStatement()
213 MutexGuard aGuard(m_aMutex);
214 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
216 // create a statement
217 // the statement can only be executed once
218 Reference<XStatement> xReturn = new OStatement(this);
219 m_aStatements.push_back(WeakReferenceHelper(xReturn));
221 return xReturn;
224 Reference<XPreparedStatement> SAL_CALL OConnection::prepareStatement(const OUString& _sSql)
226 MutexGuard aGuard(m_aMutex);
227 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
228 const OString sSqlStatement
229 = OUStringToOString(_sSql, getConnectionEncoding()); // FIXME transform statement ?
231 MYSQL_STMT* pStmt = mysql_stmt_init(&m_mysql);
232 mysql_stmt_prepare(pStmt, sSqlStatement.getStr(), sSqlStatement.getLength());
234 unsigned int nErrorNum = mysql_errno(&m_mysql);
235 if (nErrorNum != 0)
236 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql),
237 mysql_sqlstate(&m_mysql), nErrorNum, *this,
238 getConnectionEncoding());
240 Reference<XPreparedStatement> xStatement = new OPreparedStatement(this, pStmt);
241 m_aStatements.push_back(WeakReferenceHelper(xStatement));
242 return xStatement;
245 Reference<XPreparedStatement> SAL_CALL OConnection::prepareCall(const OUString& /*_sSql*/)
247 MutexGuard aGuard(m_aMutex);
248 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
250 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OConnection::prepareCall", *this);
251 return Reference<XPreparedStatement>();
254 OUString SAL_CALL OConnection::nativeSQL(const OUString& /*_sSql*/)
256 MutexGuard aGuard(m_aMutex);
258 // const OUString sSqlStatement = transFormPreparedStatement( _sSql );
259 // TODO
260 return OUString();
263 void SAL_CALL OConnection::setAutoCommit(sal_Bool autoCommit)
265 MutexGuard aGuard(m_aMutex);
266 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
267 if (!mysql_autocommit(&m_mysql, autoCommit))
268 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
269 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
270 getConnectionEncoding());
273 sal_Bool SAL_CALL OConnection::getAutoCommit()
275 // you have to distinguish which if you are in autocommit mode or not
276 // at normal case true should be fine here
278 // TODO use SELECT @@autocommit query for that
279 MutexGuard aGuard(m_aMutex);
280 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
282 return false;
285 void SAL_CALL OConnection::commit()
287 MutexGuard aGuard(m_aMutex);
288 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
290 if (!mysql_commit(&m_mysql))
291 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
292 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
293 getConnectionEncoding());
296 void SAL_CALL OConnection::rollback()
298 MutexGuard aGuard(m_aMutex);
299 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
301 if (!mysql_rollback(&m_mysql))
302 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(
303 mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this,
304 getConnectionEncoding());
307 sal_Bool SAL_CALL OConnection::isClosed()
309 MutexGuard aGuard(m_aMutex);
311 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
312 return OConnection_BASE::rBHelper.bDisposed;
315 Reference<XDatabaseMetaData> SAL_CALL OConnection::getMetaData()
317 MutexGuard aGuard(m_aMutex);
318 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
320 Reference<XDatabaseMetaData> xMetaData = m_xMetaData;
321 if (!xMetaData.is())
323 xMetaData = new ODatabaseMetaData(*this, &m_mysql);
324 m_xMetaData = xMetaData;
327 return xMetaData;
330 void SAL_CALL OConnection::setReadOnly(sal_Bool readOnly)
332 MutexGuard aGuard(m_aMutex);
333 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
335 m_settings.readOnly = readOnly;
338 sal_Bool SAL_CALL OConnection::isReadOnly()
340 MutexGuard aGuard(m_aMutex);
341 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
343 // return if your connection to readonly
344 return m_settings.readOnly;
347 void SAL_CALL OConnection::setCatalog(const OUString& /*catalog*/)
349 MutexGuard aGuard(m_aMutex);
350 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
352 // TODO How?
355 OUString SAL_CALL OConnection::getCatalog()
357 MutexGuard aGuard(m_aMutex);
358 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
360 // TODO How?
361 return OUString{};
364 void SAL_CALL OConnection::setTransactionIsolation(sal_Int32 /*level*/)
366 MutexGuard aGuard(m_aMutex);
367 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
369 // TODO
372 sal_Int32 SAL_CALL OConnection::getTransactionIsolation()
374 MutexGuard aGuard(m_aMutex);
375 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
377 return 0; // TODO
380 Reference<XNameAccess> SAL_CALL OConnection::getTypeMap()
382 MutexGuard aGuard(m_aMutex);
383 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
385 Reference<XNameAccess> t = m_typeMap;
386 return t;
389 void SAL_CALL OConnection::setTypeMap(const Reference<XNameAccess>& typeMap)
391 MutexGuard aGuard(m_aMutex);
392 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
394 m_typeMap = typeMap;
397 // XCloseable
398 void SAL_CALL OConnection::close()
401 we need block, because the mutex is a local variable,
402 which will guard the block
405 // we just dispose us
406 MutexGuard aGuard(m_aMutex);
407 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
409 mysql_close(&m_mysql);
410 mysql_library_end();
411 dispose();
414 // XWarningsSupplier
415 Any SAL_CALL OConnection::getWarnings()
417 Any x;
418 // when you collected some warnings -> return it
419 return x;
422 void SAL_CALL OConnection::clearWarnings()
424 // you should clear your collected warnings here#
427 void OConnection::disposing()
429 // we noticed that we should be destroyed in near future so we have to dispose our statements
430 MutexGuard aGuard(m_aMutex);
432 for (auto const& statement : m_aStatements)
434 Reference<XComponent> xComp(statement.get(), UNO_QUERY);
435 if (xComp.is())
437 xComp->dispose();
440 m_aStatements.clear();
442 m_xMetaData = WeakReference<XDatabaseMetaData>();
444 OConnection_BASE::disposing();
447 sal_Int32 OConnection::getMysqlVersion()
449 MutexGuard aGuard(m_aMutex);
450 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
452 unsigned long version = mysql_get_server_version(&m_mysql);
453 return static_cast<sal_Int32>(version);
456 OUString OConnection::transFormPreparedStatement(const OUString& _sSQL)
458 OUString sSqlStatement = _sSQL;
459 if (!m_xParameterSubstitution.is())
463 Sequence<Any> aArgs(1);
464 Reference<XConnection> xCon = this;
465 aArgs[0] <<= NamedValue("ActiveConnection", makeAny(xCon));
467 m_xParameterSubstitution.set(
468 m_xDriver->getFactory()->createInstanceWithArguments(
469 "org.openoffice.comp.helper.ParameterSubstitution", aArgs),
470 UNO_QUERY);
472 catch (const Exception&)
476 if (m_xParameterSubstitution.is())
480 sSqlStatement = m_xParameterSubstitution->substituteVariables(sSqlStatement, true);
482 catch (const Exception&)
486 return sSqlStatement;
489 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */