]> git.proxmox.com Git - mirror_frr.git/blob - lib/db.c
Merge pull request #5778 from ton31337/fix/add_doc_for_ebgp_connected_route_check
[mirror_frr.git] / lib / db.c
1 /*
2 * Copyright (c) 2018 Rafael Zalamena <rzalamena@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /*
20 * Copyright (c) 2016 Rafael Zalamena <rzalamena@gmail.com>
21 *
22 * Permission to use, copy, modify, and/or distribute this software for any
23 * purpose with or without fee is hereby granted, provided that the above
24 * copyright notice and this permission notice appear in all copies.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
27 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
29 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
30 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
31 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 */
34
35 #include <zebra.h>
36
37 #include "db.h"
38 #include "log.h"
39
40 static struct sqlite3 *dbp;
41
42 /*
43 * Initialize the database in path.
44 *
45 * It's possible to use in memory database with ':memory:' path.
46 */
47 int db_init(const char *path_fmt, ...)
48 {
49 char path[BUFSIZ];
50 va_list ap;
51
52 if (dbp)
53 return -1;
54
55 va_start(ap, path_fmt);
56 vsnprintf(path, sizeof(path), path_fmt, ap);
57 va_end(ap);
58
59 if (sqlite3_open_v2(path, &dbp,
60 (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), NULL)
61 != SQLITE_OK) {
62 if (dbp == NULL) {
63 zlog_warn("%s: failed to open dabatase '%s'", __func__,
64 path);
65 return -1;
66 }
67
68 zlog_warn("%s: failed to open database '%s': %s", __func__,
69 path, sqlite3_errmsg(dbp));
70 if (sqlite3_close_v2(dbp) != SQLITE_OK)
71 zlog_warn("%s: failed to terminate database", __func__);
72 dbp = NULL;
73 return -1;
74 }
75
76 return 0;
77 }
78
79 /* Closes the database if open. */
80 int db_close(void)
81 {
82 if (dbp == NULL)
83 return 0;
84
85 if (sqlite3_close_v2(dbp) != SQLITE_OK) {
86 zlog_warn("%s: failed to terminate database", __func__);
87 return -1;
88 }
89 return 0;
90 }
91
92 /* Helper function to handle formating. */
93 static int db_vbindf(struct sqlite3_stmt *ss, const char *fmt, va_list vl)
94 {
95 const char *sptr = fmt;
96 int column = 1;
97 const char *str;
98 void *blob;
99 uint64_t uinteger64;
100 uint32_t uinteger;
101 int vlen;
102
103 while (*sptr) {
104 if (*sptr != '%') {
105 sptr++;
106 continue;
107 }
108 if (sptr++ && *sptr == 0)
109 break;
110
111 switch (*sptr) {
112 case 'i':
113 uinteger = va_arg(vl, uint32_t);
114 if (sqlite3_bind_int(ss, column++, uinteger)
115 != SQLITE_OK)
116 return -1;
117 break;
118 case 'd':
119 uinteger64 = va_arg(vl, uint64_t);
120 if (sqlite3_bind_int64(ss, column++, uinteger64)
121 != SQLITE_OK)
122 return -1;
123 break;
124 case 's':
125 str = va_arg(vl, const char *);
126 vlen = va_arg(vl, int);
127 if (sqlite3_bind_text(ss, column++, str, vlen,
128 SQLITE_STATIC)
129 != SQLITE_OK)
130 return -1;
131 break;
132 case 'b':
133 blob = va_arg(vl, void *);
134 vlen = va_arg(vl, int);
135 if (sqlite3_bind_blob(ss, column++, blob, vlen,
136 SQLITE_STATIC)
137 != SQLITE_OK)
138 return -1;
139 break;
140 case 'n':
141 if (sqlite3_bind_null(ss, column++) != SQLITE_OK)
142 return -1;
143 break;
144 default:
145 zlog_warn("%s: invalid format '%c'", __func__, *sptr);
146 return -1;
147 }
148 }
149
150 return 0;
151 }
152
153 /*
154 * Binds values using format to the database query.
155 *
156 * Might be used to bind variables to a query, insert or update.
157 */
158 int db_bindf(struct sqlite3_stmt *ss, const char *fmt, ...)
159 {
160 va_list vl;
161 int result;
162
163 va_start(vl, fmt);
164 result = db_vbindf(ss, fmt, vl);
165 va_end(vl);
166
167 return result;
168 }
169
170 /* Prepares an statement to the database with the statement length. */
171 struct sqlite3_stmt *db_prepare_len(const char *stmt, int stmtlen)
172 {
173 struct sqlite3_stmt *ss;
174 int c;
175
176 if (dbp == NULL)
177 return NULL;
178
179 c = sqlite3_prepare_v2(dbp, stmt, stmtlen, &ss, NULL);
180 if (ss == NULL) {
181 zlog_warn("%s: failed to prepare (%d:%s)", __func__, c,
182 sqlite3_errmsg(dbp));
183 return NULL;
184 }
185
186 return ss;
187 }
188
189 /* Prepares an statement to the database. */
190 struct sqlite3_stmt *db_prepare(const char *stmt)
191 {
192 return db_prepare_len(stmt, strlen(stmt));
193 }
194
195 /* Run a prepared statement. */
196 int db_run(struct sqlite3_stmt *ss)
197 {
198 int result;
199
200 result = sqlite3_step(ss);
201 switch (result) {
202 case SQLITE_BUSY:
203 /* TODO handle busy database. */
204 break;
205
206 case SQLITE_OK:
207 /*
208 * SQLITE_DONE just causes confusion since it means the query went OK,
209 * but it has a different value.
210 */
211 case SQLITE_DONE:
212 result = SQLITE_OK;
213 break;
214
215 case SQLITE_ROW:
216 /* NOTHING */
217 /* It is expected to receive SQLITE_ROW on search queries. */
218 break;
219
220 default:
221 zlog_warn("%s: step failed (%d:%s)", __func__, result,
222 sqlite3_errstr(result));
223 }
224
225 return result;
226 }
227
228 /* Helper function to load format to variables. */
229 static int db_vloadf(struct sqlite3_stmt *ss, const char *fmt, va_list vl)
230 {
231 const char *sptr = fmt;
232 int column = 0;
233 const char **str;
234 void *blob;
235 const void *blobsrc;
236 uint64_t *uinteger64;
237 uint32_t *uinteger;
238 int vlen;
239 int dlen;
240 int columncount;
241
242 columncount = sqlite3_column_count(ss);
243 if (columncount == 0)
244 return -1;
245
246 while (*sptr) {
247 if (*sptr != '%') {
248 sptr++;
249 continue;
250 }
251 if (sptr++ && *sptr == 0)
252 break;
253
254 switch (*sptr) {
255 case 'i':
256 uinteger = va_arg(vl, uint32_t *);
257 *uinteger = sqlite3_column_int(ss, column);
258 break;
259 case 'd':
260 uinteger64 = va_arg(vl, uint64_t *);
261 *uinteger64 = sqlite3_column_int64(ss, column);
262 break;
263 case 's':
264 str = va_arg(vl, const char **);
265 *str = (const char *)sqlite3_column_text(ss, column);
266 break;
267 case 'b':
268 blob = va_arg(vl, void *);
269 vlen = va_arg(vl, int);
270 dlen = sqlite3_column_bytes(ss, column);
271 blobsrc = sqlite3_column_blob(ss, column);
272 memcpy(blob, blobsrc, MIN(vlen, dlen));
273 break;
274 default:
275 zlog_warn("%s: invalid format '%c'", __func__, *sptr);
276 return -1;
277 }
278
279 column++;
280 }
281
282 return 0;
283 }
284
285 /* Function to load format from database row. */
286 int db_loadf(struct sqlite3_stmt *ss, const char *fmt, ...)
287 {
288 va_list vl;
289 int result;
290
291 va_start(vl, fmt);
292 result = db_vloadf(ss, fmt, vl);
293 va_end(vl);
294
295 return result;
296 }
297
298 /* Finalize query and return memory. */
299 void db_finalize(struct sqlite3_stmt **ss)
300 {
301 sqlite3_finalize(*ss);
302 *ss = NULL;
303 }
304
305 /* Execute one or more statements. */
306 int db_execute(const char *stmt_fmt, ...)
307 {
308 char stmt[BUFSIZ];
309 va_list ap;
310
311 if (dbp == NULL)
312 return -1;
313
314 va_start(ap, stmt_fmt);
315 vsnprintf(stmt, sizeof(stmt), stmt_fmt, ap);
316 va_end(ap);
317
318 if (sqlite3_exec(dbp, stmt, NULL, 0, NULL) != SQLITE_OK) {
319 zlog_warn("%s: failed to execute statement(s): %s", __func__,
320 sqlite3_errmsg(dbp));
321 return -1;
322 }
323
324 return 0;
325 }