1#pragma once
2
3#include <memory>
4#include <boost/noncopyable.hpp>
5
6#include <Poco/Util/Application.h>
7
8
9#include <mysqlxx/Query.h>
10#include <mysqlxx/Exception.h>
11
12#define MYSQLXX_DEFAULT_TIMEOUT 60
13#define MYSQLXX_DEFAULT_RW_TIMEOUT 1800
14
15/// Disable LOAD DATA LOCAL INFILE because it is insecure
16#define MYSQLXX_DEFAULT_ENABLE_LOCAL_INFILE false
17
18
19namespace mysqlxx
20{
21
22
23/** LibrarySingleton is used for appropriate initialisation and deinitialisation of MySQL library.
24 * Makes single thread-safe call of mysql_library_init().
25 * Usage:
26 * LibrarySingleton::instance();
27 */
28class LibrarySingleton : private boost::noncopyable
29{
30public:
31 static auto & instance();
32
33private:
34 LibrarySingleton();
35 ~LibrarySingleton();
36};
37
38
39/** MySQL connection.
40 * Usage:
41 * mysqlxx::Connection connection("Test", "127.0.0.1", "root", "qwerty", 3306);
42 * std::cout << connection.query("SELECT 'Hello, World!'").store().at(0).at(0).getString() << std::endl;
43 *
44 * Or with Poco library configuration:
45 * mysqlxx::Connection connection("mysql_params");
46 *
47 * Or using socket:
48 * mysqlxx::Connection connection("Test", "localhost", "root", "qwerty", 0, "/path/to/socket/file.sock");
49 *
50 * Or using custom certificate authority file:
51 * mysqlxx::Connection connection("Test", "localhost", "root", "qwerty", 3306, "/path/to/ca/file.pem");
52 *
53 * Or using custom certificate and key file:
54 * mysqlxx::Connection connection("Test", "localhost", "root", "qwerty", 3306, "", "/path/to/cert/file.pem", "/path/to/key/file.pem");
55 *
56 * Attention! It's strictly recommended to use connection in thread where it was created.
57 * In order to use connection in other thread, you should call MySQL C API function mysql_thread_init() before and
58 * mysql_thread_end() after working with it.
59 */
60class Connection final : private boost::noncopyable
61{
62public:
63 /// For delayed initialisation
64 Connection();
65
66 /// Creates connection. Either port either socket should be specified.
67 /// If server is localhost and socket is not empty, than socket is used. Otherwise, server and port is used.
68 Connection(
69 const char * db,
70 const char * server,
71 const char * user = nullptr,
72 const char * password = nullptr,
73 unsigned port = 0,
74 const char * socket = "",
75 const char * ssl_ca = "",
76 const char * ssl_cert = "",
77 const char * ssl_key = "",
78 unsigned timeout = MYSQLXX_DEFAULT_TIMEOUT,
79 unsigned rw_timeout = MYSQLXX_DEFAULT_RW_TIMEOUT,
80 bool enable_local_infile = MYSQLXX_DEFAULT_ENABLE_LOCAL_INFILE);
81
82 /// Creates connection. Can be used if Poco::Util::Application is using.
83 /// All settings will be got from config_name section of configuration.
84 Connection(const std::string & config_name);
85
86 ~Connection();
87
88 /// Provides delayed initialization or reconnection with other settings.
89 void connect(const char * db,
90 const char * server,
91 const char * user,
92 const char * password,
93 unsigned port,
94 const char * socket,
95 const char* ssl_ca,
96 const char* ssl_cert,
97 const char* ssl_key,
98 unsigned timeout = MYSQLXX_DEFAULT_TIMEOUT,
99 unsigned rw_timeout = MYSQLXX_DEFAULT_RW_TIMEOUT,
100 bool enable_local_infile = MYSQLXX_DEFAULT_ENABLE_LOCAL_INFILE);
101
102 void connect(const std::string & config_name)
103 {
104 Poco::Util::LayeredConfiguration & cfg = Poco::Util::Application::instance().config();
105
106 std::string db = cfg.getString(config_name + ".db", "");
107 std::string server = cfg.getString(config_name + ".host");
108 std::string user = cfg.getString(config_name + ".user");
109 std::string password = cfg.getString(config_name + ".password");
110 unsigned port = cfg.getInt(config_name + ".port", 0);
111 std::string socket = cfg.getString(config_name + ".socket", "");
112 std::string ssl_ca = cfg.getString(config_name + ".ssl_ca", "");
113 std::string ssl_cert = cfg.getString(config_name + ".ssl_cert", "");
114 std::string ssl_key = cfg.getString(config_name + ".ssl_key", "");
115 bool enable_local_infile = cfg.getBool(config_name + ".enable_local_infile", MYSQLXX_DEFAULT_ENABLE_LOCAL_INFILE);
116
117 unsigned timeout =
118 cfg.getInt(config_name + ".connect_timeout",
119 cfg.getInt("mysql_connect_timeout",
120 MYSQLXX_DEFAULT_TIMEOUT));
121
122 unsigned rw_timeout =
123 cfg.getInt(config_name + ".rw_timeout",
124 cfg.getInt("mysql_rw_timeout",
125 MYSQLXX_DEFAULT_RW_TIMEOUT));
126
127 connect(
128 db.c_str(),
129 server.c_str(),
130 user.c_str(),
131 password.c_str(),
132 port,
133 socket.c_str(),
134 ssl_ca.c_str(),
135 ssl_cert.c_str(),
136 ssl_key.c_str(),
137 timeout,
138 rw_timeout,
139 enable_local_infile);
140 }
141
142 /// If MySQL connection was established.
143 bool connected() const;
144
145 /// Disconnect from MySQL.
146 void disconnect();
147
148 /// Tries to reconnect if connection was lost. Is true if connection is established after call.
149 bool ping();
150
151 /// Creates query. It can be set with query string or later.
152 Query query(const std::string & str = "");
153
154 /// Get MySQL C API MYSQL object.
155 MYSQL * getDriver();
156
157private:
158 std::unique_ptr<MYSQL> driver;
159 bool is_initialized = false;
160 bool is_connected = false;
161};
162
163
164}
165