summaryrefslogtreecommitdiffabout
path: root/src/db.cc
blob: 2b4a7eb33b517128423e4f750984781b819f0496 (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
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <napkin/exception.h>
#include "db.h"

#include "config.h"

namespace napkin {

    extern const char *sql_bootstrap;

    db_t::db_t() {
	const char *h = getenv("HOME");
	if(h) {
	    datadir = h;
	    datadir += "/."PACKAGE_NAME"/";
	}else{
#if defined(HAVE_GET_CURRENT_DIR_NAME)
	    char *cwd = get_current_dir_name();
	    if(!cwd)
		throw napkin::exception("failed to get_current_dir_name()");
	    datadir = cwd;
	    free(cwd);
#elif defined(HAVE_GETCWD)
	    {
		char cwd[
# if defined(MAXPATH)
		    MAXPATH
# elif defined(MAXPATHLEN)
		    MAXPATHLEN
# else /* maxpath */
		    512
# endif /* maxpath */
		];
		if(!getcwd(cwd,sizeof(cwd)))
		    throw napkin::exception("failed to getcwd()");
		datadir = cwd;
	    }
#else /* get cwd */
# error dunno how to get current workdir
#endif /* get cwd */
	    datadir += "/."PACKAGE_NAME"/";
	}
	if(access(datadir.c_str(),R_OK|W_OK)
		&& mkdir(datadir.c_str(),0700))
	    throw napkin::exception("no access to '"+datadir+"' directory");
	open((datadir+PACKAGE_NAME".db").c_str());
	assert(_D);
	char **resp; int nr,nc; char *errm;
	if(sqlite3_get_table(
		    _D,
		    "SELECT s_tobed FROM sleeps LIMIT 0",
		    &resp,&nr,&nc,&errm)!=SQLITE_OK) {
	    if(sqlite3_exec(_D,sql_bootstrap,NULL,NULL,&errm)!=SQLITE_OK)
		throw napkin::exception(string("failed to bootstrap sqlite database: ")+errm);
	}else
	    sqlite3_free_table(resp);
    }

    void db_t::store(const hypnodata_t& hd) {
	sqlite::mem_t<char*> S = sqlite3_mprintf(
		"INSERT INTO sleeps ("
		 "s_tobed,s_alarm,"
		 "s_window,s_data_a,"
		 "s_almost_awakes,"
		 "s_timezone"
		") VALUES ("
		 "%Q,%Q,%d,%d,%Q,%ld"
		")",
		hd.w3c_to_bed().c_str(),
		hd.w3c_alarm().c_str(),
		hd.window,hd.data_a,
		hd.w3c_almostawakes().c_str(),
		timezone );
	try {
	    exec(S);
	}catch(sqlite::exception& se) {
	    if(se.rcode==SQLITE_CONSTRAINT)
		throw exception_db_already("The record seems to be already in the database");
	    throw exception_db("Well, some error occured");
	}
    }

    void db_t::remove(const hypnodata_t& hd) {
	sqlite::mem_t<char*> S = sqlite3_mprintf(
		"DELETE FROM sleeps"
		" WHERE s_tobed=%Q AND s_alarm=%Q",
		hd.w3c_to_bed().c_str(),
		hd.w3c_alarm().c_str() );
	exec(S);
    }

    void db_t::load(list<hypnodata_ptr_t>& rv,
	    const string& sql) {
	sqlite::table_t T;
	int nr,nc;
	get_table( string(
		    "SELECT"
		     " s_tobed, s_alarm,"
		     " s_window, s_data_a,"
		     " s_almost_awakes"
		    " FROM sleeps"
		    " "+sql).c_str(),T,&nr,&nc );
	if(nr) {
	    assert(nc==5);
	    for(int r=1;r<=nr;++r) {
		hypnodata_ptr_t hd(new hypnodata_t());
		hd->set_to_bed(T.get(r,0,nc));
		hd->set_alarm(T.get(r,1,nc));
		hd->set_window(T.get(r,2,nc));
		hd->set_data_a(T.get(r,3,nc));
		hd->set_almost_awakes(T.get(r,4,nc));
		rv.push_back(hd);
	    }
	}
    }

}