db_conn  v0.2.1-alpha
Database Connection API
sqlite_driver.hpp
1 /*
2  * File: sqlite_driver.hpp
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #ifndef SQLITE_DRIVER_HPP
20 #define SQLITE_DRIVER_HPP
21 
22 #include <climits>
23 #include <cstring>
24 #include <sqlite3.h>
25 #include <algorithm>
26 #include <vector>
27 #include "driver.hpp"
28 
29 namespace vgi { namespace dbconn { namespace dbd { namespace sqlite {
30 
31 enum class open_flag : int
32 {
33  READONLY = SQLITE_OPEN_READONLY,
34  READWRITE = SQLITE_OPEN_READWRITE,
35  CREATE = SQLITE_OPEN_CREATE,
36  DELETEONCLOSE = SQLITE_OPEN_DELETEONCLOSE,
37  EXCLUSIVE = SQLITE_OPEN_EXCLUSIVE,
38 #ifdef SQLITE_OPEN_AUTOPROXY
39  AUTOPROXY = SQLITE_OPEN_AUTOPROXY,
40 #endif
41 #ifdef SQLITE_OPEN_URI
42  URI = SQLITE_OPEN_URI,
43 #endif
44 #ifdef SQLITE_OPEN_MEMORY
45  MEMORY = SQLITE_OPEN_MEMORY,
46 #endif
47  MAIN_DB = SQLITE_OPEN_MAIN_DB,
48  TEMP_DB = SQLITE_OPEN_TEMP_DB,
49  TRANSIENT_DB = SQLITE_OPEN_TRANSIENT_DB,
50  MAIN_JOURNAL = SQLITE_OPEN_MAIN_JOURNAL,
51  TEMP_JOURNAL = SQLITE_OPEN_TEMP_JOURNAL,
52  SUBJOURNAL = SQLITE_OPEN_SUBJOURNAL,
53  MASTER_JOURNAL = SQLITE_OPEN_MASTER_JOURNAL,
54  NOMUTEX = SQLITE_OPEN_NOMUTEX,
55  FULLMUTEX = SQLITE_OPEN_FULLMUTEX,
56  SHAREDCACHE = SQLITE_OPEN_SHAREDCACHE,
57  PRIVATECACHE = SQLITE_OPEN_PRIVATECACHE,
58 #ifdef SQLITE_OPEN_WAL
59  WAL = SQLITE_OPEN_WAL
60 #endif
61 };
62 
63 constexpr open_flag operator|(open_flag l, open_flag r) { return open_flag(utils::base_type(l) | utils::base_type(r)); }
64 
65 
66 enum class config_flag : int
67 {
68 #ifdef SQLITE_CONFIG_LOG
69  LOG = SQLITE_CONFIG_LOG,
70 #endif
71 #ifdef SQLITE_CONFIG_URI
72  URI = SQLITE_CONFIG_URI,
73 #endif
74 #ifdef SQLITE_CONFIG_PCACHE2
75  PCACHE2 = SQLITE_CONFIG_PCACHE2,
76 #endif
77 #ifdef SQLITE_CONFIG_GETPCACHE2
78  GETPCACHE2 = SQLITE_CONFIG_GETPCACHE2,
79 #endif
80 #ifdef SQLITE_CONFIG_COVERING_INDEX_SCAN
81  COVERING_INDEX = SQLITE_CONFIG_COVERING_INDEX_SCAN,
82 #endif
83 #ifdef SQLITE_CONFIG_SQLLOG
84  SQLLOG = SQLITE_CONFIG_SQLLOG,
85 #endif
86 #ifdef SQLITE_CONFIG_MMAP_SIZE
87  MMAP_SIZE = SQLITE_CONFIG_MMAP_SIZE,
88 #endif
89 #ifdef SQLITE_CONFIG_WIN32_HEAPSIZE
90  WIN32_HEAPSIZE = SQLITE_CONFIG_WIN32_HEAPSIZE,
91 #endif
92 #ifdef SQLITE_CONFIG_PCACHE_HDRSZ
93  PCACHE_HDRSZ = SQLITE_CONFIG_PCACHE_HDRSZ,
94 #endif
95 #ifdef SQLITE_CONFIG_PMASZ
96  PMASZ = SQLITE_CONFIG_PMASZ,
97 #endif
98 #ifdef SQLITE_CONFIG_STMTJRNL_SPILL
99  STMTJRNL_SPILL = SQLITE_CONFIG_STMTJRNL_SPILL,
100 #endif
101  SINGLETHREAD = SQLITE_CONFIG_SINGLETHREAD,
102  MULTITHREAD = SQLITE_CONFIG_MULTITHREAD,
103  SERIALIZED = SQLITE_CONFIG_SERIALIZED,
104  MALLOC = SQLITE_CONFIG_MALLOC,
105  GETMALLOC = SQLITE_CONFIG_GETMALLOC,
106  SCRATCH = SQLITE_CONFIG_SCRATCH,
107  PAGECACHE = SQLITE_CONFIG_PAGECACHE,
108  HEAP = SQLITE_CONFIG_HEAP,
109  MEMSTATUS = SQLITE_CONFIG_MEMSTATUS,
110  MUTEX = SQLITE_CONFIG_MUTEX,
111  GETMUTEX = SQLITE_CONFIG_GETMUTEX,
112  LOOKASIDE = SQLITE_CONFIG_LOOKASIDE,
113  PCACHE = SQLITE_CONFIG_PCACHE,
114  GETPCACHE = SQLITE_CONFIG_GETPCACHE,
115  // extra flag for functions other than sqlite3_config
116  SOFT_HEAP_LIMIT,
117 };
118 
119 enum class db_config_flag : int
120 {
121 #ifdef SQLITE_DBCONFIG_MAINDBNAME
122  MAINDBNAME = SQLITE_DBCONFIG_MAINDBNAME,
123 #endif
124 #ifdef SQLITE_DBCONFIG_ENABLE_FKEY
125  ENABLE_FKEY = SQLITE_DBCONFIG_ENABLE_FKEY,
126 #endif
127 #ifdef SQLITE_DBCONFIG_ENABLE_TRIGGER
128  ENABLE_TRIGGER = SQLITE_DBCONFIG_ENABLE_TRIGGER,
129 #endif
130 #ifdef SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
131  ENABLE_FTS3_TOKENIZER = SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,
132 #endif
133 #ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
134  ENABLE_LOAD_EXTENSION = SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION,
135 #endif
136 #ifdef SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
137  NO_CKPT_ON_CLOSE = SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE,
138 #endif
139  LOOKASIDE = SQLITE_DBCONFIG_LOOKASIDE
140 };
141 
142 static const char* decode_errcode(int c)
143 {
144  switch (c)
145  {
146  case SQLITE_OK : return "Successful result";
147  case SQLITE_ERROR : return "SQL error or missing database";
148  case SQLITE_INTERNAL : return "Internal logic error in SQLite";
149  case SQLITE_PERM : return "Access permission denied";
150  case SQLITE_ABORT : return "Callback routine requested an abort";
151  case SQLITE_BUSY : return "The database file is locked";
152  case SQLITE_LOCKED : return "A table in the database is locked";
153  case SQLITE_NOMEM : return "A malloc() failed";
154  case SQLITE_READONLY : return "Attempt to write a readonly database";
155  case SQLITE_INTERRUPT : return "Operation terminated by sqlite3_interrupt()";
156  case SQLITE_IOERR : return "Some kind of disk I/O error occurred";
157  case SQLITE_CORRUPT : return "The database disk image is malformed";
158  case SQLITE_NOTFOUND : return "Unknown opcode in sqlite3_file_control()";
159  case SQLITE_FULL : return "Insertion failed because database is full";
160  case SQLITE_CANTOPEN : return "Unable to open the database file";
161  case SQLITE_PROTOCOL : return "Database lock protocol error";
162  case SQLITE_EMPTY : return "Database is empty";
163  case SQLITE_SCHEMA : return "The database schema changed";
164  case SQLITE_TOOBIG : return "String or BLOB exceeds size limit";
165  case SQLITE_CONSTRAINT: return "Abort due to constraint violation";
166  case SQLITE_MISMATCH : return "Data type mismatch";
167  case SQLITE_MISUSE : return "Library used incorrectly";
168  case SQLITE_NOLFS : return "Uses OS features not supported on host";
169  case SQLITE_AUTH : return "Authorization denied";
170  case SQLITE_FORMAT : return "Auxiliary database format error";
171  case SQLITE_RANGE : return "2nd parameter to sqlite3_bind out of range";
172  case SQLITE_NOTADB : return "File opened that is not a database file";
173 #ifdef SQLITE_NOTICE
174  case SQLITE_NOTICE : return "Notifications from sqlite3_log()";
175 #endif
176 #ifdef SQLITE_WARNING
177  case SQLITE_WARNING : return "Warnings from sqlite3_log()";
178 #endif
179  case SQLITE_ROW : return "sqlite3_step() has another row ready";
180  case SQLITE_DONE : return "sqlite3_step() has finished executing";
181  }
182  return "UNKNOWN";
183 }
184 
185 // forward declaration
186 class driver;
187 class statement;
188 class connection;
189 
190 
191 
192 //=====================================================================================
193 
194 
204 {
205 public:
206  void clear()
207  {
208  stepped = false;
209  name2index.clear();
210  row_cnt = 0;
211  column_cnt = 0;
212  affected_rows = 0;
213  }
214 
215  virtual bool has_data()
216  {
217  return column_count();
218  }
219 
220  virtual bool more_results()
221  {
222  return (stmts_index > 0 && (stmts_index < sqlite_stmts.size() || (stmts_index == sqlite_stmts.size() && stepped)));
223  }
224 
225  virtual size_t row_count() const
226  {
227  return std::abs(row_cnt);
228  }
229 
230  virtual size_t rows_affected() const
231  {
232  return affected_rows;
233  }
234 
235  virtual size_t column_count() const
236  {
237  return column_cnt;
238  }
239 
240  virtual std::string column_name(size_t col_idx)
241  {
242  validate();
243  return sqlite3_column_name(sqlite_stmt, col_idx);
244  }
245 
246  virtual int column_index(const std::string& col_name)
247  {
248  auto it = name2index.find(col_name);
249  if (it != name2index.end())
250  return it->second;
251  return -1;
252  }
253 
254  virtual bool prev()
255  {
256  throw std::runtime_error(std::string(__FUNCTION__).append(": Cursors are not supported by database"));
257  }
258 
259  virtual bool first()
260  {
261  throw std::runtime_error(std::string(__FUNCTION__).append(": Cursors are not supported by database"));
262  }
263 
264  virtual bool last()
265  {
266  throw std::runtime_error(std::string(__FUNCTION__).append(": Cursors are not supported by database"));
267  }
268 
269  virtual bool next()
270  {
271  validate();
272  if (stepped && column_cnt > 0)
273  {
274  stepped = false;
275  return true;
276  }
277  auto res = sqlite3_step(sqlite_stmt);
278  switch (res)
279  {
280  case SQLITE_DONE:
281  affected_rows = (row_cnt > 0 ? row_cnt : sqlite3_changes(sqlite_conn));
282  sqlite3_reset(sqlite_stmt);
283  if (stmts_index > 0 && stmts_index < sqlite_stmts.size())
284  {
285  name2index.clear();
286  row_cnt = column_cnt = 0;
287  sqlite_stmt = sqlite_stmts[stmts_index++];
288  int tmp = affected_rows;
289  next();
290  stepped = true;
291  affected_rows = tmp;
292  }
293  break;
294  case SQLITE_ROW:
295  {
296  row_cnt += 1;
297  if (0 == column_cnt)
298  {
299  column_cnt = sqlite3_column_count(sqlite_stmt);
300  for (auto i = 0; i < column_cnt; ++i)
301  name2index[sqlite3_column_name(sqlite_stmt, i)] = i;
302  }
303  }
304  return true;
305  case SQLITE_BUSY:
306  cancel();
307  break;
308  default:
309  cancel();
310  throw std::runtime_error(std::string(__FUNCTION__).append(": ").append(decode_errcode(res)));
311  }
312  return false;
313  }
314 
315  virtual bool is_null(size_t col_idx)
316  {
317  validate();
318  return (SQLITE_NULL == sqlite3_column_type(sqlite_stmt, col_idx));
319  }
320 
321  virtual int16_t get_short(size_t col_idx)
322  {
323  return get_slint<int16_t>(col_idx);
324  }
325 
326  virtual uint16_t get_ushort(size_t col_idx)
327  {
328  return get_slint<uint16_t>(col_idx);
329  }
330 
331  virtual int32_t get_int(size_t col_idx)
332  {
333  return get_slint<int32_t>(col_idx);
334  }
335 
336  virtual uint32_t get_uint(size_t col_idx)
337  {
338  return get_slint<uint32_t>(col_idx);
339  }
340 
341  virtual int64_t get_long(size_t col_idx)
342  {
343  return get_slint64<int64_t>(col_idx);
344  }
345 
346  virtual uint64_t get_ulong(size_t col_idx)
347  {
348  return get_slint64<uint64_t>(col_idx);
349  }
350 
351  virtual float get_float(size_t col_idx)
352  {
353  return static_cast<float>(get_double(col_idx));
354  }
355 
356  virtual double get_double(size_t col_idx)
357  {
358  validate();
359  return sqlite3_column_double(sqlite_stmt, col_idx);
360  }
361 
362  virtual bool get_bool(size_t col_idx)
363  {
364  return get_slint<bool>(col_idx);
365  }
366 
367  virtual char get_char(size_t col_idx)
368  {
369  validate();
370  return *sqlite3_column_text(sqlite_stmt, col_idx);
371  }
372 
373  virtual std::string get_string(size_t col_idx)
374  {
375  validate();
376  auto start = reinterpret_cast<const char*>(sqlite3_column_text(sqlite_stmt, col_idx));
377  return std::move(std::string(start, sqlite3_column_bytes(sqlite_stmt, col_idx)));
378  }
379 
380  virtual int get_date(size_t col_idx)
381  {
382  auto s = get_string(col_idx);
383  s.erase(std::remove(s.begin(), s.end(), '-'), s.end());
384  return std::stoi(s);
385  }
386 
387  virtual double get_time(size_t col_idx)
388  {
389  auto s = get_string(col_idx);
390  s.erase(std::remove(s.begin(), s.end(), ':'), s.end());
391  return std::stod(s);
392  }
393 
394  virtual time_t get_datetime(size_t col_idx)
395  {
396  std::string s = get_string(col_idx);
397  std::memset(&stm, 0, sizeof(stm));
398  std::sscanf(s.c_str(), "%04d-%02d-%02d %02d:%02d:%02d", &stm.tm_year, &stm.tm_mon, &stm.tm_mday, &stm.tm_hour, &stm.tm_min, &stm.tm_sec);
399  stm.tm_year -= 1900;
400  stm.tm_mon -= 1;
401  stm.tm_isdst = -1;
402  return mktime(&stm);
403  }
404 
405  virtual char16_t get_u16char(size_t col_idx)
406  {
407  validate();
408  return *(reinterpret_cast<const char16_t*>(sqlite3_column_text16(sqlite_stmt, col_idx)));
409  }
410 
411  virtual std::u16string get_u16string(size_t col_idx)
412  {
413  validate();
414  auto start = reinterpret_cast<const char16_t*>(sqlite3_column_text16(sqlite_stmt, col_idx));
415  sqlite3_column_bytes16(sqlite_stmt, col_idx);
416  return std::u16string(start);
417  }
418 
419  virtual std::vector<uint8_t> get_binary(size_t col_idx)
420  {
421  validate();
422  auto data = sqlite3_column_blob(sqlite_stmt, col_idx);
423  std::vector<uint8_t> t(sqlite3_column_bytes(sqlite_stmt, col_idx));
424  std::memcpy(reinterpret_cast<void*>(t.data()), data, t.size());
425  return std::move(t);
426  }
427 
428  bool cancel()
429  {
430  clear();
431  if (nullptr != sqlite_conn)
432  sqlite3_interrupt(sqlite_conn);
433  if (nullptr != sqlite_stmt)
434  return (SQLITE_OK == sqlite3_reset(sqlite_stmt));
435  return true;
436  }
437 
438 private:
439  friend class statement;
440 
441  result_set(std::vector<sqlite3_stmt*>& stmts) : sqlite_stmts(stmts) {}
442  result_set(const result_set& rs) = delete;
443  result_set& operator=(const result_set& rs) = delete;
444 
445  template<typename T>
446  T get_slint(size_t col_idx)
447  {
448  validate();
449  return static_cast<T>(sqlite3_column_int(sqlite_stmt, col_idx));
450  }
451 
452  template<typename T>
453  T get_slint64(size_t col_idx)
454  {
455  validate();
456  return static_cast<T>(sqlite3_column_int64(sqlite_stmt, col_idx));
457  }
458 
459  void validate()
460  {
461  if (sqlite_stmt == nullptr)
462  throw std::runtime_error(std::string(__FUNCTION__).append(": Invalid result state object state"));
463  }
464 
465 private:
466  bool stepped = false;
467  long row_cnt = 0;
468  long column_cnt = 0;
469  size_t stmts_index = 0;
470  size_t affected_rows = 0;
471  sqlite3* sqlite_conn = nullptr;
472  sqlite3_stmt* sqlite_stmt = nullptr;
473  struct tm stm;
474  std::vector<sqlite3_stmt*>& sqlite_stmts;
475  std::map<std::string, int> name2index;
476 }; // result_set
477 
478 
479 //=====================================================================================
480 
481 
486 class driver : public idriver
487 {
488 public:
489  dbi::connection get_connection(const std::string& server);
490 
491  driver& version(long& ver)
492  {
493  std::lock_guard<utils::spin_lock> lg(lock);
494  ver = sqlite3_libversion_number();
495  return *this;
496  }
497 
498  driver& version_string(std::string& ver)
499  {
500  std::lock_guard<utils::spin_lock> lg(lock);
501  ver = sqlite3_libversion();
502  return *this;
503  }
504 
505  driver& max_connections(unsigned int conn_num)
506  {
507  std::lock_guard<utils::spin_lock> lg(lock);
508  max_conn = conn_num;
509  return *this;
510  }
511 
512  template <typename... T>
513  driver& config(config_flag flag, T... t)
514  {
515  int ret = SQLITE_OK;
516  std::lock_guard<utils::spin_lock> lg(lock);
517  if (flag == config_flag::SOFT_HEAP_LIMIT)
518  {
519  if (sizeof...(t) != 1)
520  ret = SQLITE_MISUSE;
521  else
522  {
523  int p = {t...};
524  sqlite3_soft_heap_limit(p);
525  }
526  }
527  else
528  {
529  if (conn_cnt > 0)
530  throw std::runtime_error(std::string(__FUNCTION__).append(": This function must be used before any connections are opened"));
531  sqlite3_shutdown();
532  ret = sqlite3_config(utils::base_type(flag), t...);
533  sqlite3_initialize();
534  }
535  if (SQLITE_OK != ret)
536  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set config parameter: ").append(std::to_string(utils::base_type(flag))).append(": ").append(decode_errcode(ret)));
537  return *this;
538  }
539 
540 protected:
541  friend class connection;
542  driver(const driver&) = delete;
543  driver(driver&&) = delete;
544  driver& operator=(const driver&) = delete;
545  driver& operator=(driver&&) = delete;
546 
547  driver()
548  {
549  }
550 
551  void upd_conn_count(int change)
552  {
553  std::lock_guard<utils::spin_lock> lg(lock);
554  conn_cnt += change;
555  }
556 
557  bool is_max_conn()
558  {
559  std::lock_guard<utils::spin_lock> lg(lock);
560  return conn_cnt == max_conn;
561  }
562 
563 private:
564  unsigned int max_conn = UINT_MAX;
565  unsigned int conn_cnt = 0;
566  utils::spin_lock lock;
567 }; // driver
568 
569 
570 //=====================================================================================
571 
581 {
582 public:
583  virtual ~connection()
584  {
585  disconnect();
586  }
587 
588  connection(connection&& conn)
589  : sqlite_conn(conn.sqlite_conn), is_utf16(conn.is_utf16),
590  is_autocommit(conn.is_autocommit), oflag(conn.oflag),
591  vfsname(std::move(conn.vfsname)), server(std::move(conn.server))
592  {
593  conn.sqlite_conn = nullptr;
594  }
595 
596  connection& operator=(connection&& conn)
597  {
598  if (this != &conn)
599  {
600  disconnect();
601  sqlite_conn = conn.sqlite_conn;
602  conn.sqlite_conn = nullptr;
603  is_utf16 = conn.is_utf16;
604  is_autocommit = conn.is_autocommit;
605  oflag = conn.oflag;
606  vfsname = std::move(conn.vfsname);
607  server = std::move(conn.server);
608  }
609  return *this;
610  }
611 
612  template <typename... T>
613  connection& config(db_config_flag flag, T... t)
614  {
615  if (sqlite_conn == nullptr)
616  throw std::runtime_error(std::string(__FUNCTION__).append(": This function must be used after connection is opened"));
617  int ret = sqlite3_db_config(sqlite_conn, utils::base_type(flag), t...);
618  if (SQLITE_OK != ret)
619  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set config parameter: ").append(std::to_string(utils::base_type(flag))).append(": ").append(decode_errcode(ret)));
620  return *this;
621  }
622 
623  virtual bool connect()
624  {
625  if (drv->is_max_conn())
626  throw std::runtime_error(std::string(__FUNCTION__).append(": Can't open new connections, please revise max connections"));
627 
628  if (true == connected())
629  disconnect();
630  if (oflag == 0)
631  {
632  if (SQLITE_OK != (is_utf16 ? sqlite3_open16(server.c_str(), &sqlite_conn) : sqlite3_open(server.c_str(), &sqlite_conn)))
633  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to connect: ").append(server));
634  }
635  else
636  {
637  if (SQLITE_OK != sqlite3_open_v2(server.c_str(), &sqlite_conn, oflag, (vfsname.empty() ? nullptr : vfsname.c_str())))
638  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to connect: ").append(server));
639  }
640  drv->upd_conn_count(1);
641  return alive();
642  }
643 
644  virtual void disconnect()
645  {
646  if (nullptr != sqlite_conn)
647  {
648  sqlite3_close(sqlite_conn);
649  sqlite_conn = nullptr;
650  drv->upd_conn_count(-1);
651  }
652  };
653 
654  virtual bool connected() const
655  {
656  return (nullptr != sqlite_conn);
657  }
658 
659  virtual bool alive() const
660  {
661  return (nullptr != sqlite_conn);
662  }
663 
664  virtual void autocommit(bool ac)
665  {
666  if (nullptr != sqlite_conn)
667  {
668  if (ac != is_autocommit)
669  {
670  is_autocommit = ac;
671  if (ac)
672  sqlite_exec("rollback transaction;");
673  else
674  sqlite_exec("begin transaction;");
675  }
676  }
677  }
678 
679  virtual void commit()
680  {
681  if (false == is_autocommit)
682  {
683  sqlite_exec("commit transaction;");
684  sqlite_exec("begin transaction;");
685  }
686  }
687 
688  virtual void rollback()
689  {
690  if (false == is_autocommit)
691  {
692  sqlite_exec("rollback transaction;");
693  sqlite_exec("begin transaction;");
694  }
695  }
696 
697  virtual dbi::istatement* get_statement(dbi::iconnection& iconn);
698 
699  connection& flags(open_flag flag)
700  {
701  oflag = utils::base_type(flag);
702  return *this;
703  }
704 
705  connection& vfs(const std::string& name)
706  {
707  vfsname = name;
708  return *this;
709  }
710 
711  connection& utf16(bool flag)
712  {
713  is_utf16 = flag;
714  return *this;
715  }
716 
717  sqlite3* native_connection() const
718  {
719  return sqlite_conn;
720  }
721 
722 private:
723  void sqlite_exec(const std::string& sql)
724  {
725  char* err = nullptr;
726  if (SQLITE_OK != sqlite3_exec(sqlite_conn, sql.c_str(), nullptr, nullptr, &err))
727  {
728  std::string s = (err ? err : "unknown error");
729  sqlite3_free(err);
730  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to execute: ").append(sql).append(": ").append(s));
731  }
732  }
733 
734 private:
735  friend class driver;
736  friend class statement;
737 
738  connection() = delete;
739  connection(const connection&) = delete;
740  connection& operator=(const connection&) = delete;
741 
742  connection(driver* drv, const std::string& server)
743  : drv(drv), server(server)
744  {
745  }
746 
747 private:
748  driver* drv = nullptr;
749  sqlite3* sqlite_conn = nullptr;
750  bool is_utf16 = false;
751  bool is_autocommit = true;
752  int oflag = 0;
753  std::string vfsname;
754  std::string server;
755 }; // connection
756 
757 
758 dbi::connection driver::get_connection(const std::string& server)
759 {
760  return create_connection(new connection(this, server));
761 }
762 
763 
764 
765 //=====================================================================================
766 
767 
768 
778 {
779 public:
780  ~statement()
781  {
782  cancel();
783  }
784 
785  virtual bool cancel()
786  {
787  bool res = rs.cancel();
788  for (auto stmt : sqlite_stmts)
789  {
790  if (SQLITE_OK != sqlite3_finalize(stmt))
791  res = false;
792  }
793  sqlite_stmts.clear();
794  rs.sqlite_stmt = nullptr;
795  rs.stmts_index = 0;
796  return res;
797  }
798 
799  virtual dbi::iresult_set* execute()
800  {
801  rs.cancel();
802  return fetch();
803  }
804 
805  virtual dbi::iresult_set* execute(const std::string& cmd, bool usecursor = false, bool scrollable = false)
806  {
807  cancel();
808  command = cmd;
809  command.erase(std::find_if(command.rbegin(), command.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), command.end());
810  size_t plen = 0;
811  while (command.length() > 0 && plen != command.length())
812  {
813  command.erase(command.begin(), std::find_if(command.begin(), command.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
814  sqlite_stmts.push_back(nullptr);
815  prepare(command, &sqlite_stmts[sqlite_stmts.size() - 1]);
816  plen = command.length();
817  command = tail;
818  }
819  return fetch();
820  }
821 
822  virtual void prepare(const std::string& cmd)
823  {
824  if (cmd.empty())
825  throw std::runtime_error(std::string(__FUNCTION__).append(": SQL command is not set"));
826  if (false == conn.alive())
827  throw std::runtime_error(std::string(__FUNCTION__).append(": Database connection is dead"));
828  cancel();
829  sqlite_stmts.resize(1);
830  prepare(cmd, &sqlite_stmts[0]);
831  }
832 
833  virtual void call(const std::string& cmd)
834  {
835  throw std::runtime_error(std::string(__FUNCTION__).append(": Stored procedures are not supported by database"));
836  }
837 
838  virtual int proc_retval()
839  {
840  throw std::runtime_error(std::string(__FUNCTION__).append(": Stored procedures are not supported by database"));
841  }
842 
843  virtual void set_null(size_t param_idx)
844  {
845  validate();
846  if (SQLITE_OK != sqlite3_bind_null(sqlite_stmts.front(), param_idx + 1))
847  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set null at index ").append(std::to_string(param_idx)));
848  }
849 
850  virtual void set_short(size_t param_idx, int16_t val)
851  {
852  set_slint(param_idx, val);
853  }
854 
855  virtual void set_ushort(size_t param_idx, uint16_t val)
856  {
857  set_slint(param_idx, val);
858  }
859 
860  virtual void set_int(size_t param_idx, int32_t val)
861  {
862  set_slint(param_idx, val);
863  }
864 
865  virtual void set_uint(size_t param_idx, uint32_t val)
866  {
867  set_int(param_idx, val);
868  }
869 
870  virtual void set_long(size_t param_idx, int64_t val)
871  {
872  set_slint64(param_idx, val);
873  }
874 
875  virtual void set_ulong(size_t param_idx, uint64_t val)
876  {
877  set_slint64(param_idx, val);
878  }
879 
880  virtual void set_float(size_t param_idx, float val)
881  {
882  set_double(param_idx, val);
883  }
884 
885  virtual void set_double(size_t param_idx, double val)
886  {
887  validate();
888  if (SQLITE_OK != sqlite3_bind_double(sqlite_stmts.front(), param_idx + 1, val))
889  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set double at index ").append(std::to_string(param_idx)));
890  }
891 
892  virtual void set_bool(size_t param_idx, bool val)
893  {
894  set_slint(param_idx, val);
895  }
896 
897  virtual void set_char(size_t param_idx, char val)
898  {
899  set_string(param_idx, std::string(1, val));
900  }
901 
902  virtual void set_string(size_t param_idx, const std::string& val)
903  {
904  validate();
905  if (SQLITE_OK != sqlite3_bind_text(sqlite_stmts.front(), param_idx + 1, val.c_str(), val.size(), SQLITE_TRANSIENT))
906  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set string at index ").append(std::to_string(param_idx)));
907  }
908 
909  virtual void set_date(size_t param_idx, int val)
910  {
911  auto yr = val / 10000;
912  auto mon = (val % 10000) / 100;
913  auto day = val % 100;
914  std::vector<char> dt(11);
915  std::sprintf(dt.data(), "%4d-%02d-%02d", yr, mon, day);
916  set_string(param_idx, dt.data());
917  }
918 
919  virtual void set_time(size_t param_idx, double val)
920  {
921  auto t = static_cast<int>(val);
922  auto hr = t / 10000;
923  auto min = (t % 10000) / 100;
924  auto sec = t % 100;
925  auto ms = static_cast<int>(floor((val - t) * 1000 + 0.5));
926  std::vector<char> dt(13);
927  std::sprintf(dt.data(), "%02d:%02d:%02d.%03d", hr, min, sec, ms);
928  set_string(param_idx, dt.data());
929  }
930 
931  virtual void set_datetime(size_t param_idx, time_t val)
932  {
933 #if defined(_WIN32) || defined(_WIN64)
934  ::localtime_s(&stm, &val);
935 #else
936  ::localtime_r(&val, &stm);
937 #endif
938  stm.tm_year += 1900;
939  std::vector<char> dt(20);
940  std::sprintf(dt.data(), "%04d-%02d-%02d %02d:%02d:%02d", stm.tm_year, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec);
941  set_string(param_idx, dt.data());
942  }
943 
944  virtual void set_u16char(size_t param_idx, char16_t val)
945  {
946  set_u16string(param_idx, std::u16string(1, val));
947  }
948 
949  virtual void set_u16string(size_t param_idx, const std::u16string& val)
950  {
951  validate();
952  if (SQLITE_OK != sqlite3_bind_text16(sqlite_stmts.front(), param_idx + 1, val.data(), val.size() * sizeof(char16_t), SQLITE_TRANSIENT))
953  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set text16 at index ").append(std::to_string(param_idx)));
954  }
955 
956  virtual void set_binary(size_t param_idx, const std::vector<uint8_t>& val)
957  {
958  validate();
959  if (SQLITE_OK != sqlite3_bind_blob(sqlite_stmts.front(), param_idx + 1, val.data(), val.size(), SQLITE_TRANSIENT))
960  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set blob at index ").append(std::to_string(param_idx)));
961  }
962 
963 private:
964  friend class connection;
965  statement() = delete;
966  statement(const statement&) = delete;
967  statement& operator=(const statement&) = delete;
968  statement(connection& conn) : conn(conn), rs(sqlite_stmts)
969  {
970  rs.sqlite_conn = conn.sqlite_conn;
971  }
972 
973  template<typename T>
974  void set_slint(size_t param_idx, T val)
975  {
976  validate();
977  int ret = sqlite3_bind_int(sqlite_stmts.front(), param_idx + 1, val);
978  if (SQLITE_OK != ret)
979  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set int at index ").append(std::to_string(param_idx)).append(": ").append(decode_errcode(ret)));
980  }
981 
982  template<typename T>
983  void set_slint64(size_t param_idx, T val)
984  {
985  validate();
986  int ret = sqlite3_bind_int64(sqlite_stmts.front(), param_idx + 1, val);
987  if (SQLITE_OK != ret)
988  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to set int64 at index ").append(std::to_string(param_idx)).append(": ").append(decode_errcode(ret)));
989  }
990 
991  void prepare(const std::string& cmd, sqlite3_stmt** stmtptr)
992  {
993  auto ret = sqlite3_prepare_v2(conn.sqlite_conn, cmd.c_str(), cmd.length(), stmtptr, &tail);
994  if (SQLITE_OK != ret)
995  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to prepare command, error code: ").append(decode_errcode(ret)));
996  }
997  dbi::iresult_set* fetch()
998  {
999  size_t rows_affected = 0;
1000  int failed_cnt = 0;
1001  std::string err = "";
1002  for (size_t i = 0; i < sqlite_stmts.size(); ++i)
1003  {
1004  rs.clear();
1005  rs.sqlite_stmt = sqlite_stmts[i];
1006  try
1007  {
1008  rs.next();
1009  }
1010  catch (const std::exception& e)
1011  {
1012  failed_cnt += 1;
1013  err.append(e.what()).append("; ");
1014  }
1015  rs.stepped = true;
1016  rows_affected += rs.rows_affected();
1017  if (rs.has_data())
1018  {
1019  rs.stmts_index = i + 1;
1020  break;
1021  }
1022  }
1023  rs.affected_rows = rows_affected;
1024  if (failed_cnt > 0)
1025  throw std::runtime_error(std::string(__FUNCTION__).append(": Failed to execute ").append(std::to_string(failed_cnt)).append(" command(s): ").append(err));
1026  return &rs;
1027  }
1028 
1029  void validate()
1030  {
1031  if (sqlite_stmts.size() == 0)
1032  throw std::runtime_error(std::string(__FUNCTION__).append(": Invalid statement object state"));
1033  }
1034 
1035 private:
1036  const char* tail = nullptr;
1037  std::vector<sqlite3_stmt*> sqlite_stmts;
1038  connection& conn;
1039  bool cursor = false;
1040  std::string command;
1041  result_set rs;
1042  struct tm stm;
1043 }; // statement
1044 
1045 
1046 dbi::istatement* connection::get_statement(dbi::iconnection& iconn)
1047 {
1048  return new statement(dynamic_cast<connection&>(iconn));
1049 }
1050 
1051 
1052 
1053 
1054 
1055 
1056 } } } } // namespace vgi::dbconn::dbd::sqlite
1057 
1058 #endif // SQLITE_DRIVER_HPP
1059 
iresult_set - is an interface that describes common functionality for all concrete native implementat...
Definition: result_set.hpp:32
sqlite driver class based on sqlite3 C++ library.
istatement - is an interface that describes common functionality for all concrete native implementati...
Definition: statement.hpp:32
iconnection - is an interface that describes common functionality for all concrete native implementat...
Definition: connection.hpp:38
result_set - is a class that implements dbi::iresult_set interface and represents results of SQL quer...
statement - is a class that implements dbi::istatement interface and represents native database state...
idriver - is an interface for driver classes which declares function for creating a connection object...
Definition: driver.hpp:33
connection - is a class that implements dbi::iconnection interface and represents native database con...
connection - is a class that manages native driver connection handle.
Definition: connection.hpp:62