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 | |
10 | static inline const char* ifNotEmpty(const char* s) |
11 | { |
12 | return s && *s ? s : nullptr; |
13 | } |
14 | |
15 | namespace mysqlxx |
16 | { |
17 | |
18 | LibrarySingleton::LibrarySingleton() |
19 | { |
20 | if (mysql_library_init(0, nullptr, nullptr)) |
21 | throw Exception("Cannot initialize MySQL library." ); |
22 | } |
23 | |
24 | LibrarySingleton::~LibrarySingleton() |
25 | { |
26 | mysql_library_end(); |
27 | } |
28 | |
29 | auto & LibrarySingleton::instance() |
30 | { |
31 | static LibrarySingleton instance; |
32 | return instance; |
33 | } |
34 | |
35 | Connection::Connection() |
36 | : driver(std::make_unique<MYSQL>()) |
37 | { |
38 | /// MySQL library initialization. |
39 | LibrarySingleton::instance(); |
40 | } |
41 | |
42 | Connection::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 | |
60 | Connection::Connection(const std::string & config_name) |
61 | : Connection() |
62 | { |
63 | connect(config_name); |
64 | } |
65 | |
66 | Connection::~Connection() |
67 | { |
68 | disconnect(); |
69 | mysql_thread_end(); |
70 | } |
71 | |
72 | void 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 | |
126 | bool Connection::connected() const |
127 | { |
128 | return is_connected; |
129 | } |
130 | |
131 | void 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 | |
143 | bool Connection::ping() |
144 | { |
145 | return is_connected && !mysql_ping(driver.get()); |
146 | } |
147 | |
148 | Query Connection::query(const std::string & str) |
149 | { |
150 | return Query(this, str); |
151 | } |
152 | |
153 | MYSQL * Connection::getDriver() |
154 | { |
155 | return driver.get(); |
156 | } |
157 | |
158 | } |
159 | |
160 | |