bump product version to 6.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / mysqlc / mysqlc_connection.cxx
blob74613a733a3a86e52b1261c788c520421e11db01
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 <memory>
21 #include "mysqlc_connection.hxx"
22 #include "mysqlc_databasemetadata.hxx"
24 #include "mysqlc_driver.hxx"
25 #include "mysqlc_statement.hxx"
26 #include "mysqlc_preparedstatement.hxx"
27 #include "mysqlc_general.hxx"
29 #include <com/sun/star/sdbc/ColumnValue.hpp>
30 #include <com/sun/star/sdbc/XRow.hpp>
31 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <osl/module.hxx>
36 #include <osl/thread.h>
37 #include <osl/file.h>
38 #include <sal/log.hxx>
39 #include <osl/diagnose.h>
40 #include <rtl/uri.hxx>
41 #include <rtl/ustrbuf.hxx>
43 using namespace connectivity::mysqlc;
45 #include <stdio.h>
47 using namespace com::sun::star::uno;
48 using namespace com::sun::star::container;
49 using namespace com::sun::star::lang;
50 using namespace com::sun::star::beans;
51 using namespace com::sun::star::sdbc;
52 using ::osl::MutexGuard;
54 #define MYSQLC_URI_PREFIX "sdbc:mysqlc:"
56 namespace
58 void lcl_executeUpdate(MYSQL* pMySql, const OString& sql)
60 mysql_real_query(pMySql, sql.getStr(), sql.getLength());
61 // TODO handle error
65 OConnection::OConnection(MysqlCDriver& _rDriver)
66 : OMetaConnection_BASE(m_aMutex)
67 , m_mysql()
68 , m_xMetaData(nullptr)
69 , m_xDriver(&_rDriver)
73 OConnection::~OConnection()
75 if (!isClosed())
77 close();
81 void OConnection::construct(const OUString& url, const Sequence<PropertyValue>& info)
83 MutexGuard aGuard(m_aMutex);
85 mysql_library_init(0, nullptr, nullptr);
86 mysql_init(&m_mysql);
88 // use TCP as connection
89 mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP;
90 mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol);
92 sal_Int32 nIndex;
93 OUString token;
94 OUString aHostName("localhost");
95 sal_Int32 nPort = 3306;
96 OUString aDbName;
98 m_settings.encoding = MysqlCDriver::getDefaultEncoding();
100 // parse url. Url has the following format:
101 // external server: sdbc:mysqlc:[hostname]:[port]/[dbname]
103 if (url.startsWith(MYSQLC_URI_PREFIX))
105 nIndex = 12;
107 else
109 // sdbc:mysql:mysqlc:[hostname]:[port]/[dbname]
110 nIndex = 18;
113 token = url.getToken(0, '/', nIndex);
114 if (!token.isEmpty())
116 sal_Int32 nIndex1 = 0;
117 OUString hostandport = token.getToken(0, ':', nIndex1);
118 if (!hostandport.isEmpty())
120 aHostName = hostandport;
121 hostandport = token.getToken(0, ':', nIndex1);
122 if (!hostandport.isEmpty() && nIndex1)
124 nPort = hostandport.toInt32();
126 token = url.getToken(0, '/', nIndex);
127 if (!token.isEmpty() && nIndex)
129 aDbName = token;
134 // get user and password for mysql connection
135 const PropertyValue* pIter = info.getConstArray();
136 const PropertyValue* pEnd = pIter + info.getLength();
137 OUString aUser, aPass, sUnixSocket, sNamedPipe;
138 bool unixSocketPassed = false;
139 bool namedPipePassed = false;
141 m_settings.connectionURL = url;
142 for (; pIter != pEnd; ++pIter)
144 if (pIter->Name == "user")
146 OSL_VERIFY(pIter->Value >>= aUser);
148 else if (pIter->Name == "password")
150 OSL_VERIFY(pIter->Value >>= aPass);
152 else if (pIter->Name == "LocalSocket")
154 OSL_VERIFY(pIter->Value >>= sUnixSocket);
155 unixSocketPassed = !sUnixSocket.isEmpty();
157 else if (pIter->Name == "NamedPipe")
159 OSL_VERIFY(pIter->Value >>= sNamedPipe);
160 namedPipePassed = !sNamedPipe.isEmpty();
162 else if (pIter->Name == "PublicConnectionURL")
164 OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
166 else if (pIter->Name == "NewURL")
167 { // legacy name for "PublicConnectionURL"
168 OSL_VERIFY(pIter->Value >>= m_settings.connectionURL);
172 OString host_str = OUStringToOString(aHostName, m_settings.encoding);
173 OString user_str = OUStringToOString(aUser, m_settings.encoding);
174 OString pass_str = OUStringToOString(aPass, m_settings.encoding);
175 OString schema_str = OUStringToOString(aDbName, m_settings.encoding);
176 OString socket_str;
177 if (unixSocketPassed)
179 socket_str = OUStringToOString(sUnixSocket, m_settings.encoding);
181 else if (namedPipePassed)
183 socket_str = OUStringToOString(sNamedPipe, m_settings.encoding);
186 // flags can also be passed as last parameter
187 if (!mysql_real_connect(&m_mysql, host_str.getStr(), user_str.getStr(), pass_str.getStr(),
188 schema_str.getStr(), nPort, socket_str.getStr(), 0))
189 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), mysql_errno(&m_mysql),
190 *this, getConnectionEncoding());
192 // Check if the server is 4.1 or above
193 if (getMysqlVersion() < 40100)
195 throw SQLException("MariaDB LibreOffice Connector requires MySQL Server 4.1 or above",
196 *this, OUString(), 0, Any());
199 lcl_executeUpdate(&m_mysql, OString{ "SET session sql_mode='ANSI_QUOTES'" });
200 lcl_executeUpdate(&m_mysql, OString{ "SET NAMES utf8" });
203 OUString OConnection::getImplementationName()
205 return OUString("com.sun.star.sdbc.drivers.mysqlc.OConnection");
208 css::uno::Sequence<OUString> OConnection::getSupportedServiceNames()
210 css::uno::Sequence<OUString> s(1);
211 s[0] = "com.sun.star.sdbc.Connection";
212 return s;
215 sal_Bool OConnection::supportsService(OUString const& ServiceName)
217 return cppu::supportsService(this, ServiceName);
220 Reference<XStatement> SAL_CALL OConnection::createStatement()
222 MutexGuard aGuard(m_aMutex);
223 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
225 // create a statement
226 // the statement can only be executed once
227 Reference<XStatement> xReturn = new OStatement(this);
228 m_aStatements.push_back(WeakReferenceHelper(xReturn));
230 return xReturn;
233 Reference<XPreparedStatement> SAL_CALL OConnection::prepareStatement(const OUString& _sSql)
235 MutexGuard aGuard(m_aMutex);
236 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
237 const OString sSqlStatement
238 = OUStringToOString(_sSql, getConnectionEncoding()); // FIXME transform statement ?
240 MYSQL_STMT* pStmt = mysql_stmt_init(&m_mysql);
241 mysql_stmt_prepare(pStmt, sSqlStatement.getStr(), sSqlStatement.getLength());
243 unsigned int nErrorNum = mysql_errno(&m_mysql);
244 if (nErrorNum != 0)
245 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), nErrorNum, *this,
246 getConnectionEncoding());
248 Reference<XPreparedStatement> xStatement = new OPreparedStatement(this, pStmt);
249 m_aStatements.push_back(WeakReferenceHelper(xStatement));
250 return xStatement;
253 Reference<XPreparedStatement> SAL_CALL OConnection::prepareCall(const OUString& /*_sSql*/)
255 MutexGuard aGuard(m_aMutex);
256 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
258 mysqlc_sdbc_driver::throwFeatureNotImplementedException("OConnection::prepareCall", *this);
259 return Reference<XPreparedStatement>();
262 OUString SAL_CALL OConnection::nativeSQL(const OUString& /*_sSql*/)
264 MutexGuard aGuard(m_aMutex);
266 // const OUString sSqlStatement = transFormPreparedStatement( _sSql );
267 // TODO
268 return OUString();
271 void SAL_CALL OConnection::setAutoCommit(sal_Bool autoCommit)
273 MutexGuard aGuard(m_aMutex);
274 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
275 if (!mysql_autocommit(&m_mysql, autoCommit))
276 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), mysql_errno(&m_mysql),
277 *this, getConnectionEncoding());
280 sal_Bool SAL_CALL OConnection::getAutoCommit()
282 // you have to distinguish which if you are in autocommit mode or not
283 // at normal case true should be fine here
285 // TODO use SELECT @@autocommit query for that
286 MutexGuard aGuard(m_aMutex);
287 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
289 return false;
292 void SAL_CALL OConnection::commit()
294 MutexGuard aGuard(m_aMutex);
295 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
297 if (!mysql_commit(&m_mysql))
298 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), mysql_errno(&m_mysql),
299 *this, getConnectionEncoding());
302 void SAL_CALL OConnection::rollback()
304 MutexGuard aGuard(m_aMutex);
305 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
307 if (!mysql_rollback(&m_mysql))
308 mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), mysql_errno(&m_mysql),
309 *this, getConnectionEncoding());
312 sal_Bool SAL_CALL OConnection::isClosed()
314 MutexGuard aGuard(m_aMutex);
316 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
317 return OConnection_BASE::rBHelper.bDisposed;
320 Reference<XDatabaseMetaData> SAL_CALL OConnection::getMetaData()
322 MutexGuard aGuard(m_aMutex);
323 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
325 Reference<XDatabaseMetaData> xMetaData = m_xMetaData;
326 if (!xMetaData.is())
328 xMetaData = new ODatabaseMetaData(*this, &m_mysql);
329 m_xMetaData = xMetaData;
332 return xMetaData;
335 void SAL_CALL OConnection::setReadOnly(sal_Bool readOnly)
337 MutexGuard aGuard(m_aMutex);
338 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
340 m_settings.readOnly = readOnly;
343 sal_Bool SAL_CALL OConnection::isReadOnly()
345 MutexGuard aGuard(m_aMutex);
346 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
348 // return if your connection to readonly
349 return m_settings.readOnly;
352 void SAL_CALL OConnection::setCatalog(const OUString& /*catalog*/)
354 MutexGuard aGuard(m_aMutex);
355 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
357 // TODO How?
360 OUString SAL_CALL OConnection::getCatalog()
362 MutexGuard aGuard(m_aMutex);
363 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
365 // TODO How?
366 return OUString{};
369 void SAL_CALL OConnection::setTransactionIsolation(sal_Int32 /*level*/)
371 MutexGuard aGuard(m_aMutex);
372 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
374 // TODO
377 sal_Int32 SAL_CALL OConnection::getTransactionIsolation()
379 MutexGuard aGuard(m_aMutex);
380 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
382 return 0; // TODO
385 Reference<XNameAccess> SAL_CALL OConnection::getTypeMap()
387 MutexGuard aGuard(m_aMutex);
388 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
390 Reference<XNameAccess> t = m_typeMap;
391 return t;
394 void SAL_CALL OConnection::setTypeMap(const Reference<XNameAccess>& typeMap)
396 MutexGuard aGuard(m_aMutex);
397 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
399 m_typeMap = typeMap;
402 // XCloseable
403 void SAL_CALL OConnection::close()
406 we need block, because the mutex is a local variable,
407 which will guard the block
410 // we just dispose us
411 MutexGuard aGuard(m_aMutex);
412 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
414 mysql_close(&m_mysql);
415 mysql_library_end();
416 dispose();
419 // XWarningsSupplier
420 Any SAL_CALL OConnection::getWarnings()
422 Any x = Any();
423 // when you collected some warnings -> return it
424 return x;
427 void SAL_CALL OConnection::clearWarnings()
429 // you should clear your collected warnings here#
432 void OConnection::disposing()
434 // we noticed that we should be destroyed in near future so we have to dispose our statements
435 MutexGuard aGuard(m_aMutex);
437 for (auto const& statement : m_aStatements)
439 Reference<XComponent> xComp(statement.get(), UNO_QUERY);
440 if (xComp.is())
442 xComp->dispose();
445 m_aStatements.clear();
447 m_xMetaData = WeakReference<XDatabaseMetaData>();
449 OConnection_BASE::disposing();
452 sal_Int32 OConnection::getMysqlVersion()
454 MutexGuard aGuard(m_aMutex);
455 checkDisposed(OConnection_BASE::rBHelper.bDisposed);
457 unsigned long version = mysql_get_server_version(&m_mysql);
458 return static_cast<sal_Int32>(version);
461 OUString OConnection::transFormPreparedStatement(const OUString& _sSQL)
463 OUString sSqlStatement = _sSQL;
464 if (!m_xParameterSubstitution.is())
468 Sequence<Any> aArgs(1);
469 Reference<XConnection> xCon = this;
470 aArgs[0] <<= NamedValue("ActiveConnection", makeAny(xCon));
472 m_xParameterSubstitution.set(
473 m_xDriver->getFactory()->createInstanceWithArguments(
474 "org.openoffice.comp.helper.ParameterSubstitution", aArgs),
475 UNO_QUERY);
477 catch (const Exception&)
481 if (m_xParameterSubstitution.is())
485 sSqlStatement = m_xParameterSubstitution->substituteVariables(sSqlStatement, true);
487 catch (const Exception&)
491 return sSqlStatement;
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */