1//
2// SesssionHandle.cpp
3//
4// Library: SQL/MySQL
5// Package: MySQL
6// Module: SessionHandle
7//
8// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/SQL/MySQL/SessionHandle.h"
16#include "Poco/SQL/SQLException.h"
17#include "Poco/SingletonHolder.h"
18#ifdef POCO_OS_FAMILY_UNIX
19#include <pthread.h>
20#endif
21
22
23#define POCO_MYSQL_VERSION_NUMBER ((NDB_VERSION_MAJOR<<16) | (NDB_VERSION_MINOR<<8) | (NDB_VERSION_BUILD&0xFF))
24
25
26namespace Poco {
27namespace SQL {
28namespace MySQL {
29
30
31#ifdef POCO_OS_FAMILY_UNIX
32class ThreadCleanupHelper
33{
34public:
35 ThreadCleanupHelper()
36 {
37 if (pthread_key_create(&_key, &ThreadCleanupHelper::cleanup) != 0)
38 throw Poco::SystemException("cannot create TLS key for mysql cleanup");
39 }
40
41 void init()
42 {
43 if (pthread_setspecific(_key, reinterpret_cast<void*>(1)))
44 throw Poco::SystemException("cannot set TLS key for mysql cleanup");
45 }
46
47 static ThreadCleanupHelper& instance()
48 {
49 return *_sh.get();
50 }
51
52 static void cleanup(void* data)
53 {
54 mysql_thread_end();
55 }
56
57private:
58 pthread_key_t _key;
59 static Poco::SingletonHolder<ThreadCleanupHelper> _sh;
60};
61
62
63Poco::SingletonHolder<ThreadCleanupHelper> ThreadCleanupHelper::_sh;
64#endif
65
66
67SessionHandle::SessionHandle(MYSQL* mysql): _pHandle(0)
68{
69 init(mysql);
70#ifdef POCO_OS_FAMILY_UNIX
71 ThreadCleanupHelper::instance().init();
72#endif
73}
74
75
76void SessionHandle::init(MYSQL* mysql)
77{
78 if (!_pHandle)
79 {
80 _pHandle = mysql_init(mysql);
81 if (!_pHandle)
82 throw ConnectionException("mysql_init error");
83 }
84}
85
86
87SessionHandle::~SessionHandle()
88{
89 close();
90}
91
92
93void SessionHandle::options(mysql_option opt)
94{
95 if (mysql_options(_pHandle, opt, 0) != 0)
96 throw ConnectionException("mysql_options error", _pHandle);
97}
98
99
100void SessionHandle::options(mysql_option opt, bool b)
101{
102 my_bool tmp = b;
103 if (mysql_options(_pHandle, opt, &tmp) != 0)
104 throw ConnectionException("mysql_options error", _pHandle);
105}
106
107
108void SessionHandle::options(mysql_option opt, const char* c)
109{
110 if (mysql_options(_pHandle, opt, c) != 0)
111 throw ConnectionException("mysql_options error", _pHandle);
112}
113
114
115void SessionHandle::options(mysql_option opt, unsigned int i)
116{
117#if (POCO_MYSQL_VERSION_NUMBER < 0x050108)
118 const char* tmp = (const char *)&i;
119#else
120 const void* tmp = (const void *)&i;
121#endif
122 if (mysql_options(_pHandle, opt, tmp) != 0)
123 throw ConnectionException("mysql_options error", _pHandle);
124}
125
126
127void SessionHandle::connect(const char* host, const char* user, const char* password, const char* db, unsigned int port)
128{
129#ifdef HAVE_MYSQL_REAL_CONNECT
130 if (!mysql_real_connect(_pHandle, host, user, password, db, port, 0, 0))
131 throw ConnectionFailedException(mysql_error(_pHandle));
132#else
133 if (!mysql_connect(_pHandle, host, user, password))
134 throw ConnectionFailedException(mysql_error(_pHandle))
135#endif
136}
137
138
139void SessionHandle::close()
140{
141 if (_pHandle)
142 {
143 mysql_close(_pHandle);
144 _pHandle = 0;
145 }
146}
147
148
149void SessionHandle::startTransaction()
150{
151 int rc = mysql_autocommit(_pHandle, false);
152 if (rc != 0)
153 {
154 // retry if connection lost
155 int err = mysql_errno(_pHandle);
156 if (err == 2006 /* CR_SERVER_GONE_ERROR */ || err == 2013 /* CR_SERVER_LOST */)
157 {
158 rc = mysql_autocommit(_pHandle, false);
159 }
160 }
161 if (rc != 0) throw TransactionException("Start transaction failed.", _pHandle);
162}
163
164
165void SessionHandle::commit()
166{
167 if (mysql_commit(_pHandle) != 0)
168 throw TransactionException("Commit failed.", _pHandle);
169}
170
171
172void SessionHandle::rollback()
173{
174 if (mysql_rollback(_pHandle) != 0)
175 throw TransactionException("Rollback failed.", _pHandle);
176}
177
178
179void SessionHandle::reset()
180{
181#if ((defined (MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID >= 50700)) || ((defined (MARIADB_PACKAGE_VERSION_ID)) && (MARIADB_PACKAGE_VERSION_ID >= 30000))
182 if (mysql_reset_connection(_pHandle) != 0)
183#else
184 if (mysql_refresh(_pHandle, REFRESH_TABLES | REFRESH_STATUS | REFRESH_THREADS | REFRESH_READ_LOCK) != 0)
185#endif
186 throw TransactionException("Reset connection failed.", _pHandle);
187}
188
189
190}}} // Poco::SQL::MySQL
191