libdballe  7.7
mysql/internals.h
1 /*
2  * db/mysql/internals - Implementation infrastructure for the MySQL DB connection
3  *
4  * Copyright (C) 2015 ARPA-SIM <urpsim@smr.arpa.emr.it>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * Author: Enrico Zini <enrico@enricozini.com>
20  */
21 
22 #ifndef DBALLE_DB_MYSQL_INTERNALS_H
23 #define DBALLE_DB_MYSQL_INTERNALS_H
24 
25 #include <dballe/db/db.h>
26 #include <dballe/db/sql.h>
27 #include <cstdlib>
28 #include <mysql.h>
29 
30 namespace dballe {
31 namespace db {
32 struct MySQLStatement;
33 
37 struct error_mysql : public db::error
38 {
39  std::string msg;
40 
45  error_mysql(MYSQL* db, const std::string& msg);
46  error_mysql(const std::string& dbmsg, const std::string& msg);
47  ~error_mysql() throw () {}
48 
49  wreport::ErrorCode code() const throw () { return wreport::WR_ERR_ODBC; }
50 
51  virtual const char* what() const throw () { return msg.c_str(); }
52 
53  static void throwf(MYSQL* db, const char* fmt, ...) WREPORT_THROWF_ATTRS(2, 3);
54 };
55 
56 namespace mysql {
57 
59 {
60  std::string host;
61  std::string user;
62  bool has_passwd = false;
63  std::string passwd;
64  bool has_dbname = false;
65  std::string dbname;
66  unsigned port = 0;
67  std::string unix_socket;
68 
69  // Reset everything to defaults
70  void reset();
71  void parse_url(const std::string& url);
72  // Modeled after http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
73  std::string to_url() const;
74 };
75 
76 struct Row
77 {
78  MYSQL_RES* res = nullptr;
79  MYSQL_ROW row = nullptr;
80 
81  Row(MYSQL_RES* res, MYSQL_ROW row) : res(res), row(row) {}
82 
83  operator bool() const { return row != nullptr; }
84  operator MYSQL_ROW() { return row; }
85  operator const MYSQL_ROW() const { return row; }
86 
87  int as_int(unsigned col) const { return strtol(row[col], 0, 10); }
88  unsigned as_unsigned(unsigned col) const { return strtoul(row[col], 0, 10); }
89  const char* as_cstring(unsigned col) const { return row[col]; }
90  std::string as_string(unsigned col) const { return std::string(row[col], mysql_fetch_lengths(res)[col]); }
91  Datetime as_datetime(int col) const;
92  bool isnull(unsigned col) const { return row[col] == nullptr; }
93 };
94 
95 struct Result
96 {
97  MYSQL_RES* res = nullptr;
98 
99  Result() : res(nullptr) {}
100  Result(MYSQL_RES* res) : res(res) {}
101  ~Result() { if (res) mysql_free_result(res); }
102 
104  Result(Result&& o) : res(o.res) { o.res = nullptr; }
105  Result& operator=(Result&& o)
106  {
107  if (this == &o) return *this;
108  if (res) mysql_free_result(res);
109  res = o.res;
110  o.res = nullptr;
111  return *this;
112  }
113 
114  operator bool() const { return res != nullptr; }
115 
116  operator MYSQL_RES*() { return res; }
117  operator const MYSQL_RES*() const { return res; }
118 
119  unsigned rowcount() const { return mysql_num_rows(res); }
120  unsigned colcount() const { return mysql_num_fields(res); }
121 
123  Row expect_one_result();
124 
134  Row fetch() { return Row(res, mysql_fetch_row(res)); }
135 
136  // Prevent copy
137  Result(const Result&) = delete;
138  Result& operator=(const Result&) = delete;
139 };
140 
141 }
142 
143 
146 {
147 protected:
149  MYSQL* db = nullptr;
150 
151  void send_result(mysql::Result&& res, std::function<void(const mysql::Row&)> dest);
152 
153 protected:
154  void init_after_connect();
155 
156  // See https://dev.mysql.com/doc/refman/5.0/en/mysql-real-connect.html
157  void open(const mysql::ConnectInfo& info);
158 
159 public:
160  MySQLConnection();
161  MySQLConnection(const MySQLConnection&) = delete;
162  MySQLConnection(const MySQLConnection&&) = delete;
163  ~MySQLConnection();
164  MySQLConnection& operator=(const MySQLConnection&) = delete;
165  MySQLConnection& operator=(const MySQLConnection&&) = delete;
166 
167  operator MYSQL*() { return db; }
168 
169  // See http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
170  void open_url(const std::string& url);
171  void open_test();
172 
174  std::string escape(const char* str);
176  std::string escape(const std::string& str);
177 
182  void exec_no_data_nothrow(const char* query) noexcept;
183  // Run a query, checking that it is successful and it gives no results
184  void exec_no_data(const char* query);
185  // Run a query, checking that it is successful and it gives no results
186  void exec_no_data(const std::string& query);
187  // Run a query, with a locally stored result
188  mysql::Result exec_store(const char* query);
189  // Run a query, with a locally stored result
190  mysql::Result exec_store(const std::string& query);
191  // Run a query, with a remotely fetched result
192  void exec_use(const char* query, std::function<void(const mysql::Row&)> dest);
193  // Run a query, with a remotely fetched result
194  void exec_use(const std::string& query, std::function<void(const mysql::Row&)> dest);
195 
196  std::unique_ptr<Transaction> transaction() override;
197 
199  bool has_table(const std::string& name) override;
200 
206  std::string get_setting(const std::string& key) override;
207 
213  void set_setting(const std::string& key, const std::string& value) override;
214 
216  void drop_settings() override;
217 
221  void drop_table_if_exists(const char* name);
222 
229  int get_last_insert_id();
230 
232  //int changes();
233 
234 #if 0
235  void wrap_sqlite3_exec(const std::string& query);
237  void wrap_sqlite3_exec_nothrow(const std::string& query) noexcept;
238 #endif
239 };
240 
241 #if 0
242 struct MySQLStatement
244 {
245  MySQLConnection& conn;
246  sqlite3_stmt *stm = nullptr;
247 
248  MySQLStatement(MySQLConnection& conn, const std::string& query);
249  MySQLStatement(const MySQLStatement&) = delete;
250  MySQLStatement(const MySQLStatement&&) = delete;
251  ~MySQLStatement();
252  MySQLStatement& operator=(const MySQLStatement&) = delete;
253 
261  template<typename... Args> void bind(const Args& ...args)
262  {
263  bindn<sizeof...(args)>(args...);
264  }
265 
266  void bind_null_val(int idx);
267  void bind_val(int idx, int val);
268  void bind_val(int idx, unsigned val);
269  void bind_val(int idx, unsigned short val);
270  void bind_val(int idx, const Datetime& val);
271  void bind_val(int idx, const char* val); // Warning: SQLITE_STATIC is used
272  void bind_val(int idx, const std::string& val); // Warning: SQLITE_STATIC is used
273 
275  void execute();
276 
283  void execute(std::function<void()> on_row);
284 
289  void execute_one(std::function<void()> on_row);
290 
292  int column_int(int col) { return sqlite3_column_int(stm, col); }
293 
295  sqlite3_int64 column_int64(int col) { return sqlite3_column_int64(stm, col); }
296 
298  double column_double(int col) { return sqlite3_column_double(stm, col); }
299 
301  const char* column_string(int col) { return (const char*)sqlite3_column_text(stm, col); }
302 
304  Datetime column_datetime(int col);
305 
307  bool column_isnull(int col) { return sqlite3_column_type(stm, col) == SQLITE_NULL; }
308 
309  void wrap_sqlite3_reset();
310  void wrap_sqlite3_reset_nothrow() noexcept;
315  [[noreturn]] void reset_and_throw(const std::string& errmsg);
316 
317  operator sqlite3_stmt*() { return stm; }
318 #if 0
319  int execute();
322  int exec_direct(const char* query);
324  int exec_direct(const char* query, int qlen);
325 
327  int execute_and_close();
329  int exec_direct_and_close(const char* query);
331  int exec_direct_and_close(const char* query, int qlen);
332 
337  int columns_count();
338  bool fetch();
339  bool fetch_expecting_one();
340  void close_cursor();
341  void close_cursor_if_needed();
343  size_t select_rowcount();
345  size_t rowcount();
346 #endif
347 
348 private:
349  // Implementation of variadic bind: terminating condition
350  template<size_t total> void bindn() {}
351  // Implementation of variadic bind: recursive iteration over the parameter pack
352  template<size_t total, typename ...Args, typename T> void bindn(const T& first, const Args& ...args)
353  {
354  bind_val(total - sizeof...(args), first);
355  bindn<total>(args...);
356  }
357 };
358 #endif
359 
360 }
361 }
362 #endif
363 
error_mysql(MYSQL *db, const std::string &msg)
Copy informations from the ODBC diagnostic record to the dba error report.
void drop_settings() override
Drop the settings table.
Definition: mysql/internals.h:58
Database connection.
Definition: mysql/internals.h:145
Report a MySQL error.
Definition: mysql/internals.h:37
int get_last_insert_id()
Return LAST_INSERT_ID or LAST_INSER_ROWID or whatever is appropriate for the current database...
Base exception for database errors.
Definition: db/defs.h:54
Copyright (C) 2008–2010 ARPA-SIM urpsim@smr.arpa.emr.it
Definition: cmdline.h:17
void drop_table_if_exists(const char *name)
Delete a table in the database if it exists, otherwise do nothing.
Functions used to connect to DB-All.e and insert, query and delete data.
Row expect_one_result()
Check that the function returned only one row, and return that row.
Row fetch()
Fetch one row.
Definition: mysql/internals.h:134
std::string escape(const char *str)
Escape a C string.
Definition: mysql/internals.h:76
Result(Result &&o)
Implement move.
Definition: mysql/internals.h:104
Date and time.
Definition: types.h:147
std::unique_ptr< Transaction > transaction() override
Begin a transaction.
void set_setting(const std::string &key, const std::string &value) override
Set a value in the settings table.
void exec_no_data_nothrow(const char *query) noexcept
Run a query throwing no exceptions, warning on stderr if it is not successful or if it gives a nonemp...
bool has_table(const std::string &name) override
Check if the database contains a table.
MYSQL * db
Database connection.
Definition: mysql/internals.h:149
Definition: sql.h:69
Definition: mysql/internals.h:95
std::string get_setting(const std::string &key) override
Get a value from the settings table.