summaryrefslogtreecommitdiffabout
path: root/src/seclude.h
blob: cab36995f12d7506e8bd5992b58dd89dffb8ca4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#ifndef __SECLUDE_H
#define __SECLUDE_H

#include <sqlite3.h>
#include <stdexcept>
#include <tr1/memory>
#include <cstdarg>

namespace seclude {
    using std::tr1::shared_ptr;

    static struct sql_null_type { } sql_null;


    struct sqlite3_error : public std::runtime_error {
	int code, ecode;
	sqlite3_error(sqlite3 *s,const std::string& m)
	    : std::runtime_error(m+": "+(s?sqlite3_errmsg(s):"unknown error")),
	      code(s?sqlite3_errcode(s):-1), ecode(s?sqlite3_extended_errcode(s):-1) { }
	sqlite3_error(sqlite3_stmt *s,const std::string& m)
	    : std::runtime_error(m+": "+(s?sqlite3_errmsg(sqlite3_db_handle(s)):"unknown error")),
	      code(s?sqlite3_errcode(sqlite3_db_handle(s)):-1),
	      ecode(s?sqlite3_extended_errcode(sqlite3_db_handle(s)):-1) { }
    };


    static void sqlite3_stmt_deleter(sqlite3_stmt* s) { s && sqlite3_finalize(s); }
    struct stmt_t : public shared_ptr<sqlite3_stmt> {
	stmt_t(sqlite3_stmt *s) : shared_ptr<sqlite3_stmt>(s,sqlite3_stmt_deleter) { }

	bool step() {
	    switch(sqlite3_step(get())) {
		case SQLITE_DONE: return false;
		case SQLITE_ROW: return true;
	    }
	    panic("failed to sqlite3_step()");
	}
	stmt_t& reset() {
	    return worry(sqlite3_reset(get()),"failed to sqlite3_reset()");
	}
	stmt_t& clear_bindings() {
	    return worry(sqlite3_clear_bindings(get()),"failed to sqlite3_clear_bindings()");
	}
	int data_count() { return sqlite3_data_count(get()); }
	int column_count() { return sqlite3_column_count(get()); }
	template<typename T> T column(int i);
	std::string column_name(int i) { return sqlite3_column_name(get(),i); }
	int column_type(int i) { return sqlite3_column_type(get(),i); }
	bool is_column_null(int i) { return column_type(i)==SQLITE_NULL; }

	template<typename T> int bind_(int i,T v);
	template<typename T>
	stmt_t& bind(int i,T v) {
	    return worry(bind_(i,v),"failed to perform binding");
	}
	template<typename T>
	stmt_t& bind(const char *n,T v) { return bind(bind_parameter_index(n),v); }
	int bind_parameter_index(const char *n) {
	    int rv = sqlite3_bind_parameter_index(get(),n);
	    if(!rv) throw std::invalid_argument("failed to sqlite3_bind_parameter_index()");
	    return rv;
	}


	stmt_t& worry(int c,const char *m) { if(c!=SQLITE_OK) panic(m); return *this;}
	stmt_t& panic(const std::string& m) { throw sqlite3_error(get(),m); return *this;}
    };

    template<> inline int stmt_t::bind_<int>(int i,int v) {
	return sqlite3_bind_int(get(),i,v); }
    template<> inline int stmt_t::bind_<long>(int i,long v) {
	return sqlite3_bind_int64(get(),i,v); }
    template<> inline int stmt_t::bind_<sqlite3_int64>(int i,sqlite3_int64 v) {
	return sqlite3_bind_int64(get(),i,v); }
    template<> inline int stmt_t::bind_<double>(int i,double v) {
	return sqlite3_bind_double(get(),i,v); }
    template<> inline int stmt_t::bind_<const std::string&>(int i,const std::string& v) {
	return sqlite3_bind_text(get(),i,v.c_str(),-1,SQLITE_TRANSIENT); }
    template<> inline int stmt_t::bind_<std::string>(int i,std::string v) {
	return sqlite3_bind_text(get(),i,v.c_str(),-1,SQLITE_TRANSIENT); }
    template<> inline int stmt_t::bind_<const char *>(int i,const char *v) {
	return sqlite3_bind_text(get(),i,v,-1,SQLITE_TRANSIENT); }
    template<> inline int stmt_t::bind_<sql_null_type>(int i,sql_null_type) {
	return sqlite3_bind_null(get(),i); }

    template<> int stmt_t::column<int>(int i) { return sqlite3_column_int(get(),i); }
    template<> long stmt_t::column<long>(int i) { return sqlite3_column_int64(get(),i); }
    template<> sqlite3_int64 stmt_t::column<sqlite3_int64>(int i) { return sqlite3_column_int64(get(),i); }
    template<> double stmt_t::column<double>(int i) { return sqlite3_column_double(get(),i); }
    template<> std::string stmt_t::column<std::string>(int i) { return (const char*)sqlite3_column_text(get(),i); }


    static void sqlite3_deleter(sqlite3* s) { s && sqlite3_close(s); }
    struct db_t : public shared_ptr<sqlite3> {
	db_t(const char *f) {
	    sqlite3 *s=0;
	    int c = sqlite3_open(f,&s);
	    reset(s,sqlite3_deleter);
	    worry(c,"failed to sqlite3_open()");
	}

	void exec(const char *s) {
	    char *e = 0;
	    int c = sqlite3_exec(get(),s,NULL,NULL,&e);
	    if(e) sqlite3_free(e);
	    worry(c,"failed to sqlite3_exec()");
	}

	stmt_t prepare(const char *s) {
	    sqlite3_stmt *r=0;
	    int c = sqlite3_prepare(get(),s,-1,&r,0);
	    stmt_t rv(r);
	    worry(c,"failed to sqlite3_prepare()");
	    return rv;
	}

	int changes() { return sqlite3_changes(get()); }

	void worry(int c,const char *m) { if(c!=SQLITE_OK) throw sqlite3_error(get(),m); }
    };

}

#endif /* __SECLUDE_H */