]> git.proxmox.com Git - mirror_frr.git/blob - lib/db.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / db.c
1 // SPDX-License-Identifier: ISC AND GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 Rafael Zalamena <rzalamena@gmail.com>
4 */
5
6 /*
7 * Copyright (c) 2016 Rafael Zalamena <rzalamena@gmail.com>
8 */
9
10 #include <zebra.h>
11
12 #include "db.h"
13 #include "log.h"
14
15 static struct sqlite3 *dbp;
16
17 /*
18 * Initialize the database in path.
19 *
20 * It's possible to use in memory database with ':memory:' path.
21 */
22 int db_init(const char *path_fmt, ...)
23 {
24 char path[BUFSIZ];
25 va_list ap;
26
27 if (dbp)
28 return -1;
29
30 va_start(ap, path_fmt);
31 vsnprintf(path, sizeof(path), path_fmt, ap);
32 va_end(ap);
33
34 if (sqlite3_open_v2(path, &dbp,
35 (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), NULL)
36 != SQLITE_OK) {
37 if (dbp == NULL) {
38 zlog_warn("%s: failed to open database '%s'", __func__,
39 path);
40 return -1;
41 }
42
43 zlog_warn("%s: failed to open database '%s': %s", __func__,
44 path, sqlite3_errmsg(dbp));
45 if (sqlite3_close_v2(dbp) != SQLITE_OK)
46 zlog_warn("%s: failed to terminate database", __func__);
47 dbp = NULL;
48 return -1;
49 }
50
51 return 0;
52 }
53
54 /* Closes the database if open. */
55 int db_close(void)
56 {
57 if (dbp == NULL)
58 return 0;
59
60 if (sqlite3_close_v2(dbp) != SQLITE_OK) {
61 zlog_warn("%s: failed to terminate database", __func__);
62 return -1;
63 }
64 return 0;
65 }
66
67 /* Helper function to handle formating. */
68 static int db_vbindf(struct sqlite3_stmt *ss, const char *fmt, va_list vl)
69 {
70 const char *sptr = fmt;
71 int column = 1;
72 const char *str;
73 void *blob;
74 uint64_t uinteger64;
75 uint32_t uinteger;
76 int vlen;
77
78 while (*sptr) {
79 if (*sptr != '%') {
80 sptr++;
81 continue;
82 }
83 if (sptr++ && *sptr == 0)
84 break;
85
86 switch (*sptr) {
87 case 'i':
88 uinteger = va_arg(vl, uint32_t);
89 if (sqlite3_bind_int(ss, column++, uinteger)
90 != SQLITE_OK)
91 return -1;
92 break;
93 case 'd':
94 uinteger64 = va_arg(vl, uint64_t);
95 if (sqlite3_bind_int64(ss, column++, uinteger64)
96 != SQLITE_OK)
97 return -1;
98 break;
99 case 's':
100 str = va_arg(vl, const char *);
101 vlen = va_arg(vl, int);
102 if (sqlite3_bind_text(ss, column++, str, vlen,
103 SQLITE_STATIC)
104 != SQLITE_OK)
105 return -1;
106 break;
107 case 'b':
108 blob = va_arg(vl, void *);
109 vlen = va_arg(vl, int);
110 if (sqlite3_bind_blob(ss, column++, blob, vlen,
111 SQLITE_STATIC)
112 != SQLITE_OK)
113 return -1;
114 break;
115 case 'n':
116 if (sqlite3_bind_null(ss, column++) != SQLITE_OK)
117 return -1;
118 break;
119 default:
120 zlog_warn("%s: invalid format '%c'", __func__, *sptr);
121 return -1;
122 }
123 }
124
125 return 0;
126 }
127
128 /*
129 * Binds values using format to the database query.
130 *
131 * Might be used to bind variables to a query, insert or update.
132 */
133 int db_bindf(struct sqlite3_stmt *ss, const char *fmt, ...)
134 {
135 va_list vl;
136 int result;
137
138 va_start(vl, fmt);
139 result = db_vbindf(ss, fmt, vl);
140 va_end(vl);
141
142 return result;
143 }
144
145 /* Prepares an statement to the database with the statement length. */
146 struct sqlite3_stmt *db_prepare_len(const char *stmt, int stmtlen)
147 {
148 struct sqlite3_stmt *ss;
149 int c;
150
151 if (dbp == NULL)
152 return NULL;
153
154 c = sqlite3_prepare_v2(dbp, stmt, stmtlen, &ss, NULL);
155 if (ss == NULL) {
156 zlog_warn("%s: failed to prepare (%d:%s)", __func__, c,
157 sqlite3_errmsg(dbp));
158 return NULL;
159 }
160
161 return ss;
162 }
163
164 /* Prepares an statement to the database. */
165 struct sqlite3_stmt *db_prepare(const char *stmt)
166 {
167 return db_prepare_len(stmt, strlen(stmt));
168 }
169
170 /* Run a prepared statement. */
171 int db_run(struct sqlite3_stmt *ss)
172 {
173 int result;
174
175 result = sqlite3_step(ss);
176 switch (result) {
177 case SQLITE_BUSY:
178 /* TODO handle busy database. */
179 break;
180
181 case SQLITE_OK:
182 /*
183 * SQLITE_DONE just causes confusion since it means the query went OK,
184 * but it has a different value.
185 */
186 case SQLITE_DONE:
187 result = SQLITE_OK;
188 break;
189
190 case SQLITE_ROW:
191 /* NOTHING */
192 /* It is expected to receive SQLITE_ROW on search queries. */
193 break;
194
195 default:
196 zlog_warn("%s: step failed (%d:%s)", __func__, result,
197 sqlite3_errstr(result));
198 }
199
200 return result;
201 }
202
203 /* Helper function to load format to variables. */
204 static int db_vloadf(struct sqlite3_stmt *ss, const char *fmt, va_list vl)
205 {
206 const char *sptr = fmt;
207 int column = 0;
208 const char **str;
209 void *blob;
210 const void *blobsrc;
211 uint64_t *uinteger64;
212 uint32_t *uinteger;
213 int vlen;
214 int dlen;
215 int columncount;
216
217 columncount = sqlite3_column_count(ss);
218 if (columncount == 0)
219 return -1;
220
221 while (*sptr) {
222 if (*sptr != '%') {
223 sptr++;
224 continue;
225 }
226 if (sptr++ && *sptr == 0)
227 break;
228
229 switch (*sptr) {
230 case 'i':
231 uinteger = va_arg(vl, uint32_t *);
232 *uinteger = sqlite3_column_int(ss, column);
233 break;
234 case 'd':
235 uinteger64 = va_arg(vl, uint64_t *);
236 *uinteger64 = sqlite3_column_int64(ss, column);
237 break;
238 case 's':
239 str = va_arg(vl, const char **);
240 *str = (const char *)sqlite3_column_text(ss, column);
241 break;
242 case 'b':
243 blob = va_arg(vl, void *);
244 vlen = va_arg(vl, int);
245 dlen = sqlite3_column_bytes(ss, column);
246 blobsrc = sqlite3_column_blob(ss, column);
247 memcpy(blob, blobsrc, MIN(vlen, dlen));
248 break;
249 default:
250 zlog_warn("%s: invalid format '%c'", __func__, *sptr);
251 return -1;
252 }
253
254 column++;
255 }
256
257 return 0;
258 }
259
260 /* Function to load format from database row. */
261 int db_loadf(struct sqlite3_stmt *ss, const char *fmt, ...)
262 {
263 va_list vl;
264 int result;
265
266 va_start(vl, fmt);
267 result = db_vloadf(ss, fmt, vl);
268 va_end(vl);
269
270 return result;
271 }
272
273 /* Finalize query and return memory. */
274 void db_finalize(struct sqlite3_stmt **ss)
275 {
276 sqlite3_finalize(*ss);
277 *ss = NULL;
278 }
279
280 /* Execute one or more statements. */
281 int db_execute(const char *stmt_fmt, ...)
282 {
283 char stmt[BUFSIZ];
284 va_list ap;
285
286 if (dbp == NULL)
287 return -1;
288
289 va_start(ap, stmt_fmt);
290 vsnprintf(stmt, sizeof(stmt), stmt_fmt, ap);
291 va_end(ap);
292
293 if (sqlite3_exec(dbp, stmt, NULL, 0, NULL) != SQLITE_OK) {
294 zlog_warn("%s: failed to execute statement(s): %s", __func__,
295 sqlite3_errmsg(dbp));
296 return -1;
297 }
298
299 return 0;
300 }