libdballe  6.8
internals.h
Go to the documentation of this file.
1 /*
2  * db/internals - Internal support infrastructure for the DB
3  *
4  * Copyright (C) 2005--2013 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_INTERNALS_H
23 #define DBALLE_DB_INTERNALS_H
24 
32 #include <dballe/db/querybuf.h>
34 #include <wreport/error.h>
35 
36 #include <sqltypes.h>
37 
38 /*
39  * Define to true to enable the use of transactions during writes
40  */
41 #define DBA_USE_TRANSACTIONS
42 
43 // Bit values for server/driver quirks
44 #define DBA_DB_QUIRK_NO_ROWCOUNT_IN_DIAG (1 << 0)
45 
46 /* Define this to enable referential integrity */
47 #undef USE_REF_INT
48 
49 namespace dballe {
50 namespace db {
51 struct Statement;
52 
57 // #define TRACE_DB
58 
59 #ifdef TRACE_DB
60 #define TRACE(...) fprintf(stderr, __VA_ARGS__)
61 #define IFTRACE if (1)
62 #else
63 
64 #define TRACE(...) do { } while (0)
65 
66 #define IFTRACE if (0)
67 #endif
68 
71 // Define this to get warnings when a Statement is closed but its data have not
72 // all been read yet
73 // #define DEBUG_WARN_OPEN_TRANSACTIONS
74 
78 struct error_odbc : public wreport::error
79 {
80  std::string msg;
81 
86  error_odbc(SQLSMALLINT handleType, SQLHANDLE handle, const std::string& msg);
87  ~error_odbc() throw () {}
88 
89  wreport::ErrorCode code() const throw () { return wreport::WR_ERR_ODBC; }
90 
91  virtual const char* what() const throw () { return msg.c_str(); }
92 
93  static void throwf(SQLSMALLINT handleType, SQLHANDLE handle, const char* fmt, ...) WREPORT_THROWF_ATTRS(3, 4);
94 };
95 
99 enum ServerType
100 {
101  MYSQL,
102  SQLITE,
103  ORACLE,
104  POSTGRES,
105 };
106 
109 {
110  SQLHENV od_env;
111 
112  Environment();
113  ~Environment();
114 
115  static Environment& get();
116 
117 private:
118  // disallow copy
119  Environment(const Environment&);
120  Environment& operator=(const Environment&);
121 };
122 
125 {
127  SQLHDBC od_conn;
129  bool connected;
131  enum ServerType server_type;
133  unsigned server_quirks;
134 
135 protected:
139  DBALLE_SQL_C_SINT_TYPE m_last_insert_id;
140 
141 public:
142  Connection();
143  ~Connection();
144 
145  void connect(const char* dsn, const char* user, const char* password);
146  void connect_file(const std::string& fname);
147  void driver_connect(const char* config);
148  std::string driver_name();
149  std::string driver_version();
150  void get_info(SQLUSMALLINT info_type, SQLINTEGER& res);
151  void set_autocommit(bool val);
152 
154  void commit();
155 
157  void rollback();
158 
160  bool has_table(const std::string& name);
161 
167  std::string get_setting(const std::string& key);
168 
174  void set_setting(const std::string& key, const std::string& value);
175 
177  void drop_settings();
178 
182  void drop_table_if_exists(const char* name);
183 
187  void drop_sequence_if_exists(const char* name);
188 
195  int get_last_insert_id();
196 
197 protected:
198  void init_after_connect();
199 
200 private:
201  // disallow copy
202  Connection(const Connection&);
203  Connection& operator=(const Connection&);
204 };
205 
208 {
209  Connection& conn;
210  bool fired;
211 
212  Transaction(Connection& conn) : conn(conn), fired(false) {}
213  ~Transaction() { if (!fired) rollback(); }
214 
215  void commit() { conn.commit(); fired = true; }
216  void rollback() { conn.rollback(); fired = true; }
217 };
218 
220 struct Statement
221 {
222  const Connection& conn;
223  SQLHSTMT stm;
225  const char* ignore_error;
226 #ifdef DEBUG_WARN_OPEN_TRANSACTIONS
227  std::string debug_query;
229  bool debug_reached_completion;
230 #endif
231 
232  Statement(Connection& conn);
233  ~Statement();
234 
235  void bind_in(int idx, const DBALLE_SQL_C_SINT_TYPE& val);
236  void bind_in(int idx, const DBALLE_SQL_C_SINT_TYPE& val, const SQLLEN& ind);
237  void bind_in(int idx, const DBALLE_SQL_C_UINT_TYPE& val);
238  void bind_in(int idx, const DBALLE_SQL_C_UINT_TYPE& val, const SQLLEN& ind);
239  void bind_in(int idx, const unsigned short& val);
240  void bind_in(int idx, const char* val);
241  void bind_in(int idx, const char* val, const SQLLEN& ind);
242  void bind_in(int idx, const SQL_TIMESTAMP_STRUCT& val);
243 
244  void bind_out(int idx, DBALLE_SQL_C_SINT_TYPE& val);
245  void bind_out(int idx, DBALLE_SQL_C_SINT_TYPE& val, SQLLEN& ind);
246  void bind_out(int idx, DBALLE_SQL_C_UINT_TYPE& val);
247  void bind_out(int idx, DBALLE_SQL_C_UINT_TYPE& val, SQLLEN& ind);
248  void bind_out(int idx, unsigned short& val);
249  void bind_out(int idx, char* val, SQLLEN buflen);
250  void bind_out(int idx, char* val, SQLLEN buflen, SQLLEN& ind);
251  void bind_out(int idx, SQL_TIMESTAMP_STRUCT& val);
252  void bind_out(int idx, SQL_TIMESTAMP_STRUCT& val, SQLLEN& ind);
253 
254  void prepare(const char* query);
255  void prepare(const char* query, int qlen);
256 
258  int execute();
260  int exec_direct(const char* query);
262  int exec_direct(const char* query, int qlen);
263 
265  int execute_and_close();
267  int exec_direct_and_close(const char* query);
269  int exec_direct_and_close(const char* query, int qlen);
270 
275  int columns_count();
276  bool fetch();
277  bool fetch_expecting_one();
278  void close_cursor();
279  void close_cursor_if_needed();
281  size_t select_rowcount();
283  size_t rowcount();
284 
285  void set_cursor_forward_only();
286  void set_cursor_static();
287 
288 protected:
289  bool error_is_ignored();
290  bool is_error(int sqlres);
291 
292 private:
293  // disallow copy
294  Statement(const Statement&);
295  Statement& operator=(const Statement&);
296 };
297 
299 struct Sequence : public Statement
300 {
301  DBALLE_SQL_C_SINT_TYPE out;
302 
303  Sequence(Connection& conn, const char* name);
304  ~Sequence();
305 
307  const DBALLE_SQL_C_SINT_TYPE& read();
308 
309 private:
310  // disallow copy
311  Sequence(const Sequence&);
312  Sequence& operator=(const Sequence&);
313 };
314 
315 static inline bool operator!=(const SQL_TIMESTAMP_STRUCT& a, const SQL_TIMESTAMP_STRUCT& b)
316 {
317  return a.year != b.year || a.month != b.month || a.day != b.day || a.hour != b.hour || a.minute != b.minute || a.second != b.second || a.fraction != b.fraction;
318 }
319 
320 std::ostream& operator<<(std::ostream& o, const SQL_TIMESTAMP_STRUCT& t);
321 
322 static inline SQL_TIMESTAMP_STRUCT make_sql_timestamp(int year, int month, int day, int hour, int minute, int second)
323 {
324  SQL_TIMESTAMP_STRUCT res;
325  res.year = year;
326  res.month = month;
327  res.day = day;
328  res.hour = hour;
329  res.minute = minute;
330  res.second = second;
331  res.fraction = 0;
332  return res;
333 }
334 
335 
336 } // namespace db
337 } // namespace dballe
338 
339 /* vim:set ts=4 sw=4: */
340 #endif
enum ServerType server_type
Type of SQL server we are connected to.
Definition: internals.h:131
Report an ODBC error, using informations from the ODBC diagnostic record.
Definition: internals.h:78
const DBALLE_SQL_C_SINT_TYPE & read()
Read the current value of the sequence.
error_odbc(SQLSMALLINT handleType, SQLHANDLE handle, const std::string &msg)
Copy informations from the ODBC diagnostic record to the dba error report.
bool connected
True if the connection is open.
Definition: internals.h:129
void rollback()
Rollback a transaction.
Database connection.
Definition: internals.h:124
db::Statement * stm_last_insert_id
Precompiled LAST_INSERT_ID (or equivalent) SQL statement.
Definition: internals.h:137
The ODBC specification is imperfect with regards to integer sizes on 64bit platforms, and different ODBC drivers are currently interpreting it differently.
RAII transaction.
Definition: internals.h:207
Definition: cmdline.h:34
int exec_direct_and_close(const char *query)
const char * ignore_error
If non-NULL, ignore all errors with this code.
Definition: internals.h:225
bool has_table(const std::string &name)
Check if the database contains a table.
void commit()
Commit a transaction.
Implementation of an efficient string buffer for composing database queries.
void drop_settings()
Drop the settings table.
ODBC environment.
Definition: internals.h:108
DBALLE_SQL_C_SINT_TYPE m_last_insert_id
ID of the last autogenerated primary key.
Definition: internals.h:139
ODBC statement.
Definition: internals.h:220
void set_setting(const std::string &key, const std::string &value)
Set a value in the settings table.
SQLHDBC od_conn
ODBC database connection.
Definition: internals.h:127
int get_last_insert_id()
Return LAST_INSERT_ID or LAST_INSER_ROWID or whatever is appropriate for the current database...
unsigned server_quirks
Bitfield of quirks we should be aware of when using ODBC.
Definition: internals.h:133
ODBC statement to read a sequence.
Definition: internals.h:299
void drop_sequence_if_exists(const char *name)
Delete a sequence in the database if it exists, otherwise do nothing.
size_t select_rowcount()
Row count for select operations.
std::string get_setting(const std::string &key)
Get a value from the settings table.
size_t rowcount()
Row count for insert, delete and other non-select operations.
void drop_table_if_exists(const char *name)
Delete a table in the database if it exists, otherwise do nothing.
int exec_direct(const char *query)