]> git.proxmox.com Git - mirror_frr.git/blame - lib/db.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / lib / db.c
CommitLineData
1c2facd1
RW
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
40static 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 */
47int 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. */
80int 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. */
93static 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 */
158int 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. */
171struct 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. */
190struct sqlite3_stmt *db_prepare(const char *stmt)
191{
192 return db_prepare_len(stmt, strlen(stmt));
193}
194
195/* Run a prepared statement. */
196int 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. */
229static 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. */
286int 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. */
299void db_finalize(struct sqlite3_stmt **ss)
300{
301 sqlite3_finalize(*ss);
302 *ss = NULL;
303}
304
305/* Execute one or more statements. */
306int 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}