summaryrefslogtreecommitdiffstatsabout
path: root/utility/database.c
diff options
context:
space:
mode:
Diffstat (limited to 'utility/database.c')
-rw-r--r--utility/database.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/utility/database.c b/utility/database.c
new file mode 100644
index 0000000..ff81caa
--- /dev/null
+++ b/utility/database.c
@@ -0,0 +1,212 @@
1#include "database.h"
2#include "apu.h"
3#include "apr_dbd.h"
4#include "apr_strings.h"
5
6#include "util.h"
7#include "autoconfig.h"
8
9struct config_dbd_t {
10 const apr_dbd_driver_t *driver;
11 apr_dbd_t *dbd;
12 apr_dbd_prepared_t *stmt;
13 apr_dbd_transaction_t *txn;
14 const char **args;
15};
16
17void database_init(apr_pool_t *p)
18{
19 apr_dbd_init(p);
20}
21
22/** @todo split this into load and connect */
23apr_status_t database_connect(config_t *cfg, config_dbd_t **dbconn)
24{
25 apr_status_t rv;
26 if (!cfg->dbdriver || !cfg->dbparams)
27 return APR_EINVAL;
28 if (!*dbconn) {
29 *dbconn = apr_pcalloc(cfg->pool, sizeof(config_dbd_t));
30 }
31 rv = apr_dbd_get_driver(cfg->pool, cfg->dbdriver, &((*dbconn)->driver));
32 if (rv) {
33
34 logging_log(cfg, LOGLEVEL_ERROR,
35 "DB: Could not load database driver %s. Error %s",
36 cfg->dbdriver, logging_strerror(rv));
37 return rv;
38 }
39
40 rv = apr_dbd_open((*dbconn)->driver, cfg->pool, cfg->dbparams,
41 &((*dbconn)->dbd));
42 if (rv) {
43 logging_log(cfg, LOGLEVEL_ERROR,
44 "DB: Could not connect to database. Error (%d)%s", rv,
45 logging_strerror(rv));
46 return rv;
47 }
48
49 return APR_SUCCESS;
50}
51
52apr_status_t database_disconnect(config_dbd_t *dbconn)
53{
54 return apr_dbd_close(dbconn->driver, dbconn->dbd);
55}
56
57static apr_dbd_prepared_t *database_prepare_insert(config_t *cfg,
58 config_dbd_t *dbconn, apr_pool_t *p)
59{
60 apr_status_t rv;
61 char *sql;
62 int i, f;
63 struct iovec *vec;
64 apr_dbd_prepared_t *stmt= NULL;
65 int nfs = cfg->output_fields->nelts;
66 config_output_field_t *ofields;
67
68 ofields = (config_output_field_t *)cfg->output_fields->elts;
69
70 vec = apr_palloc(p, (nfs*2 + 5) * sizeof(struct iovec));
71 sql = apr_palloc(p, (nfs*3));
72
73 vec[0].iov_base = "INSERT INTO ";
74 vec[0].iov_len = 12;
75 vec[1].iov_base = (void *)cfg->table;
76 vec[1].iov_len = strlen(cfg->table);
77 vec[2].iov_base = " (";
78 vec[2].iov_len = 2;
79 for (i=3, f=0; f<nfs; f++, i+=2) {
80 vec[i].iov_base = (void *)ofields[f].field;
81 vec[i].iov_len = strlen(vec[i].iov_base);
82 vec[i+1].iov_base = ",";
83 vec[i+1].iov_len = 1;
84 memcpy(&sql[f*3], "%s,", 3);
85 }
86 sql[nfs*3-1] = '\0';
87 vec[i-1].iov_base = ") VALUES (";
88 vec[i-1].iov_len = 10;
89 vec[i].iov_base = sql;
90 vec[i].iov_len = nfs*3-1;
91 vec[i+1].iov_base = ")";
92 vec[i+1].iov_len = 1;
93
94 sql = apr_pstrcatv(p, vec, i+2, NULL);
95
96 logging_log(cfg, LOGLEVEL_DEBUG, "DB: Generated SQL: %s", sql);
97
98 rv = apr_dbd_prepare(dbconn->driver, cfg->pool, dbconn->dbd, sql,
99 "INSERT", &stmt);
100
101 if (rv) {
102 logging_log(cfg, LOGLEVEL_NOISE,
103 "DB: Unable to Prepare SQL insert: %s", apr_dbd_error(
104 dbconn->driver, dbconn->dbd, rv));
105 return NULL;
106 }
107 return stmt;
108}
109
110apr_status_t database_insert(config_t *cfg, config_dbd_t *dbconn,
111 apr_pool_t *p, apr_table_t *data)
112{
113 apr_status_t rv;
114 int f, nfs;
115 config_output_field_t *ofields;
116 ofields = (config_output_field_t *)cfg->output_fields->elts;
117 nfs = cfg->output_fields->nelts;
118 // Prepare statement
119 if (!dbconn->stmt) {
120 dbconn->stmt = database_prepare_insert(cfg, dbconn, p);
121 if (!dbconn->stmt) {
122 return APR_EINVAL;
123 }
124 dbconn->args = apr_palloc(cfg->pool, nfs * sizeof(char *));
125 }
126 for (f=0; f<nfs; f++) {
127 dbconn->args[f] = apr_table_get(data, ofields[f].field);
128 }
129 rv = apr_dbd_pquery(dbconn->driver, p, dbconn->dbd, &f,
130 dbconn->stmt, nfs, dbconn->args);
131 if (rv) {
132 logging_log(cfg, LOGLEVEL_ERROR, "DB: Unable to Insert SQL: %s",
133 apr_dbd_error(dbconn->driver, dbconn->dbd, rv));
134 return rv;
135 }
136 return APR_SUCCESS;
137}
138
139apr_status_t database_trans_start(config_t *cfg, config_dbd_t *dbconn,
140 apr_pool_t *p)
141{
142#if HAVE_APR_DBD_TRANSACTION_MODE_GET
143 apr_status_t rv;
144 if (!cfg->transactions)
145 return APR_SUCCESS;
146 if (dbconn->txn) {
147 logging_log(cfg, LOGLEVEL_NOISE,
148 "Transaction Already Started. Something is BROKE");
149 return APR_EINVAL;
150 }
151 logging_log(cfg, LOGLEVEL_DEBUG, "DB: Starting Transaction");
152 rv = apr_dbd_transaction_start(dbconn->driver, p, dbconn->dbd,
153 &dbconn->txn);
154 if (rv)
155 logging_log(cfg, LOGLEVEL_NOISE,
156 "DB: Error Starting Transaction: (%d)%s", rv, apr_dbd_error(
157 dbconn->driver, dbconn->dbd, rv));
158 return rv;
159#else
160 return APR_SUCCESS;
161#endif
162}
163
164apr_status_t database_trans_stop(config_t *cfg, config_dbd_t *dbconn,
165 apr_pool_t *p)
166{
167#if HAVE_APR_DBD_TRANSACTION_MODE_GET
168 apr_status_t rv;
169 if (!cfg->transactions)
170 return APR_SUCCESS;
171 if (!dbconn->txn) {
172 logging_log(cfg, LOGLEVEL_NOISE,
173 "No Transaction Started. Something is BROKE");
174 return APR_EINVAL;
175 }
176 logging_log(cfg, LOGLEVEL_DEBUG, "DB: Stopping Transaction");
177 rv = apr_dbd_transaction_end(dbconn->driver, p, dbconn->txn);
178 if (rv)
179 logging_log(cfg, LOGLEVEL_NOISE,
180 "DB: Error Stopping Transaction: (%d)%s", rv, apr_dbd_error(
181 dbconn->driver, dbconn->dbd, rv));
182
183 dbconn->txn = NULL;
184 return rv;
185#else
186 return APR_SUCCESS;
187#endif
188}
189
190apr_status_t database_trans_abort(config_t *cfg, config_dbd_t *dbconn)
191{
192#if HAVE_APR_DBD_TRANSACTION_MODE_GET
193 apr_status_t rv;
194 if (!cfg->transactions)
195 return APR_SUCCESS;
196 if (!dbconn->txn) {
197 logging_log(cfg, LOGLEVEL_NOISE,
198 "No Transaction Started. Something is BROKE");
199 return APR_EINVAL;
200 }
201 logging_log(cfg, LOGLEVEL_NOTICE, "DB: Aborting Transaction");
202 rv = apr_dbd_transaction_mode_set(dbconn->driver, dbconn->txn,
203 APR_DBD_TRANSACTION_ROLLBACK);
204 if (rv)
205 logging_log(cfg, LOGLEVEL_NOISE,
206 "DB: Error Aborting Transaction: (%d)%s", rv, apr_dbd_error(
207 dbconn->driver, dbconn->dbd, rv));
208 return rv;
209#else
210 return APR_SUCCESS;
211#endif
212}