1#if __has_include(<mysql.h>)
2#include <mysql.h>
3#else
4#include <mysql/mysql.h>
5#endif
6
7#include <mysqlxx/Connection.h>
8#include <mysqlxx/Exception.h>
9
10static inline const char* ifNotEmpty(const char* s)
11{
12 return s && *s ? s : nullptr;
13}
14
15namespace mysqlxx
16{
17
18LibrarySingleton::LibrarySingleton()
19{
20 if (mysql_library_init(0, nullptr, nullptr))
21 throw Exception("Cannot initialize MySQL library.");
22}
23
24LibrarySingleton::~LibrarySingleton()
25{
26 mysql_library_end();
27}
28
29auto & LibrarySingleton::instance()
30{
31 static LibrarySingleton instance;
32 return instance;
33}
34
35Connection::Connection()
36 : driver(std::make_unique<MYSQL>())
37{
38 /// MySQL library initialization.
39 LibrarySingleton::instance();
40}
41
42Connection::Connection(
43 const char* db,
44 const char* server,
45 const char* user,
46 const char* password,
47 unsigned port,
48 const char * socket,
49 const char* ssl_ca,
50 const char* ssl_cert,
51 const char* ssl_key,
52 unsigned timeout,
53 unsigned rw_timeout,
54 bool enable_local_infile)
55 : Connection()
56{
57 connect(db, server, user, password, port, socket, ssl_ca, ssl_cert, ssl_key, timeout, rw_timeout, enable_local_infile);
58}
59
60Connection::Connection(const std::string & config_name)
61 : Connection()
62{
63 connect(config_name);
64}
65
66Connection::~Connection()
67{
68 disconnect();
69 mysql_thread_end();
70}
71
72void Connection::connect(const char* db,
73 const char * server,
74 const char * user,
75 const char * password,
76 unsigned port,
77 const char * socket,
78 const char * ssl_ca,
79 const char * ssl_cert,
80 const char * ssl_key,
81 unsigned timeout,
82 unsigned rw_timeout,
83 bool enable_local_infile)
84{
85 if (is_connected)
86 disconnect();
87
88 if (!mysql_init(driver.get()))
89 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
90 is_initialized = true;
91
92 /// Set timeouts.
93 if (mysql_options(driver.get(), MYSQL_OPT_CONNECT_TIMEOUT, &timeout))
94 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
95
96 if (mysql_options(driver.get(), MYSQL_OPT_READ_TIMEOUT, &rw_timeout))
97 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
98
99 if (mysql_options(driver.get(), MYSQL_OPT_WRITE_TIMEOUT, &rw_timeout))
100 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
101
102 /// Disable LOAD DATA LOCAL INFILE because it is insecure if necessary.
103 unsigned enable_local_infile_arg = static_cast<unsigned>(enable_local_infile);
104 if (mysql_options(driver.get(), MYSQL_OPT_LOCAL_INFILE, &enable_local_infile_arg))
105 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
106
107 /// Specifies particular ssl key and certificate if it needs
108 if (mysql_ssl_set(driver.get(), ifNotEmpty(ssl_key), ifNotEmpty(ssl_cert), ifNotEmpty(ssl_ca), nullptr, nullptr))
109 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
110
111 if (!mysql_real_connect(driver.get(), server, user, password, db, port, ifNotEmpty(socket), driver->client_flag))
112 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
113
114 /// Sets UTF-8 as default encoding.
115 if (mysql_set_character_set(driver.get(), "UTF8"))
116 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
117
118 /// Enables auto-reconnect.
119 my_bool reconnect = true;
120 if (mysql_options(driver.get(), MYSQL_OPT_RECONNECT, reinterpret_cast<const char *>(&reconnect)))
121 throw ConnectionFailed(errorMessage(driver.get()), mysql_errno(driver.get()));
122
123 is_connected = true;
124}
125
126bool Connection::connected() const
127{
128 return is_connected;
129}
130
131void Connection::disconnect()
132{
133 if (!is_initialized)
134 return;
135
136 mysql_close(driver.get());
137 memset(driver.get(), 0, sizeof(*driver));
138
139 is_initialized = false;
140 is_connected = false;
141}
142
143bool Connection::ping()
144{
145 return is_connected && !mysql_ping(driver.get());
146}
147
148Query Connection::query(const std::string & str)
149{
150 return Query(this, str);
151}
152
153MYSQL * Connection::getDriver()
154{
155 return driver.get();
156}
157
158}
159
160