Cleanup
[jmdict-cli.git] / sqlite.h
1 /*
2 jmdict, a frontend to the JMdict file. http://mandrill.fuxx0r.net/jmdict.php
3 Copyright (C) 2004 Florian Bluemel (florian.bluemel@uni-dortmund.de)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19 #include <cstring>
20 #include <string>
21 #include <cctype>
22 #include <stdexcept>
23 #include <sqlite3.h>
24
25 namespace sql {
26         template<typename T> struct query_traits;
27         template<> struct query_traits<const char* const> { static std::string chars() { return "qQs";  } };
28         template<> struct query_traits<char* const>       { static std::string chars() { return "qQs";  } };
29         template<> struct query_traits<const int>         { static std::string chars() { return "cdi";  } };
30         template<> struct query_traits<const unsigned>    { static std::string chars() { return "ouxX"; } };
31         typedef int (*callback)(void*, int, char**, char**);
32
33         class query {
34                 class mem_guard {
35                 public:
36                         mem_guard(char* p) : p(p) {}
37                         ~mem_guard() { sqlite3_free(p); }
38                         operator const char*() const { return p; }
39                 private:
40                         char* p;
41                 };
42
43         public:
44                 explicit query(const std::string& q = "") : q(q), pos(0) {
45                         ff();
46                 }
47
48         query& operator=(const std::string& s) {
49             q = s;
50             pos = 0;
51             ff();
52             return *this;
53         }
54
55         class wrong_format : public std::logic_error {
56         public:
57                 wrong_format(char type, const std::string& format)
58                         : std::logic_error(std::string("wrong format string in sql query, expected one of the following: ") 
59                                           + format + ", got " + type + ".") {}
60         };
61
62         template<typename T> query& operator%(const T& t)
63         {
64                 if(type >= q.size() || query_traits<const T>::chars().find(q[type]) == std::string::npos)
65                         throw wrong_format(q[type], query_traits<const T>::chars());
66                 mem_guard repl(sqlite3_mprintf(q.substr(pos, type - pos + 1).c_str(), t));
67                 put(repl);
68                 return *this;
69         }
70
71         query& operator%(const std::string& s) {
72             return *this % s.c_str();
73         }
74
75         const std::string& str() const {
76             return q;
77         }
78
79     private:
80         void put(const char* repl) {
81             q.replace(pos, type - pos + 1, repl);
82             pos += strlen(repl);
83             ff();
84         }
85
86         void ff() {
87             static const std::string CONV("diouxXeEfFgGaAcsCSPnqQ");
88             pos = q.find('%', pos);
89             while (pos < q.size() - 1 && q[pos + 1] == '%')
90                 pos = q.find('%', pos + 2);
91             type = pos;
92             while (type < q.size() && CONV.find(q[type]) == std::string::npos)
93                 ++type;
94         }
95         
96         std::string q;
97         std::string::size_type pos;
98         std::string::size_type type;
99     };
100
101     struct db {
102         explicit db(const std::string& name) {
103             if (sqlite3_open(name.c_str(), &raw) != SQLITE_OK)
104                 throw std::runtime_error("Could not connect to sqlite database '" + name + "'.");
105         }
106         ~db() {
107             sqlite3_close(raw);
108         }
109
110         void exec(const std::string& query, callback cb = 0, void* arg = 0) {
111             sqlite3_exec(raw, query.c_str(), cb, arg, 0);
112         }
113         
114         void exec(const query& query, callback cb = 0, void* arg = 0) {
115             exec(query.str(), cb, arg);
116         }
117         
118     private:
119         sqlite3* raw;
120     };
121 } // namespace sql