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 | |
26 | namespace Poco { |
27 | namespace SQL { |
28 | namespace MySQL { |
29 | |
30 | |
31 | #ifdef POCO_OS_FAMILY_UNIX |
32 | class ThreadCleanupHelper |
33 | { |
34 | public: |
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 | |
57 | private: |
58 | pthread_key_t _key; |
59 | static Poco::SingletonHolder<ThreadCleanupHelper> _sh; |
60 | }; |
61 | |
62 | |
63 | Poco::SingletonHolder<ThreadCleanupHelper> ThreadCleanupHelper::_sh; |
64 | #endif |
65 | |
66 | |
67 | SessionHandle::SessionHandle(MYSQL* mysql): _pHandle(0) |
68 | { |
69 | init(mysql); |
70 | #ifdef POCO_OS_FAMILY_UNIX |
71 | ThreadCleanupHelper::instance().init(); |
72 | #endif |
73 | } |
74 | |
75 | |
76 | void 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 | |
87 | SessionHandle::~SessionHandle() |
88 | { |
89 | close(); |
90 | } |
91 | |
92 | |
93 | void SessionHandle::options(mysql_option opt) |
94 | { |
95 | if (mysql_options(_pHandle, opt, 0) != 0) |
96 | throw ConnectionException("mysql_options error" , _pHandle); |
97 | } |
98 | |
99 | |
100 | void 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 | |
108 | void 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 | |
115 | void 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 | |
127 | void 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 | |
139 | void SessionHandle::close() |
140 | { |
141 | if (_pHandle) |
142 | { |
143 | mysql_close(_pHandle); |
144 | _pHandle = 0; |
145 | } |
146 | } |
147 | |
148 | |
149 | void 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 | |
165 | void SessionHandle::commit() |
166 | { |
167 | if (mysql_commit(_pHandle) != 0) |
168 | throw TransactionException("Commit failed." , _pHandle); |
169 | } |
170 | |
171 | |
172 | void SessionHandle::rollback() |
173 | { |
174 | if (mysql_rollback(_pHandle) != 0) |
175 | throw TransactionException("Rollback failed." , _pHandle); |
176 | } |
177 | |
178 | |
179 | void 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 | |