aboutsummaryrefslogtreecommitdiff
path: root/src/lib/sq
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/sq')
-rw-r--r--src/lib/sq/.gitignore1
-rw-r--r--src/lib/sq/Makefile.am38
-rw-r--r--src/lib/sq/meson.build30
-rw-r--r--src/lib/sq/sq.c131
-rw-r--r--src/lib/sq/sq_exec.c113
-rw-r--r--src/lib/sq/sq_prepare.c77
-rw-r--r--src/lib/sq/sq_query_helper.c510
-rw-r--r--src/lib/sq/sq_result_helper.c785
-rw-r--r--src/lib/sq/test_sq.c291
9 files changed, 1976 insertions, 0 deletions
diff --git a/src/lib/sq/.gitignore b/src/lib/sq/.gitignore
new file mode 100644
index 000000000..951587047
--- /dev/null
+++ b/src/lib/sq/.gitignore
@@ -0,0 +1 @@
test_sq
diff --git a/src/lib/sq/Makefile.am b/src/lib/sq/Makefile.am
new file mode 100644
index 000000000..a77a380af
--- /dev/null
+++ b/src/lib/sq/Makefile.am
@@ -0,0 +1,38 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage
6endif
7
8if HAVE_SQLITE
9lib_LTLIBRARIES = libgnunetsq.la
10endif
11
12libgnunetsq_la_SOURCES = \
13 sq.c \
14 sq_exec.c \
15 sq_prepare.c \
16 sq_query_helper.c \
17 sq_result_helper.c
18libgnunetsq_la_LIBADD = -lsqlite3 \
19 $(top_builddir)/src/lib/util/libgnunetutil.la
20libgnunetsq_la_LDFLAGS = \
21 $(GN_LIBINTL) \
22 $(GN_LIB_LDFLAGS) \
23 -version-info 0:0:0
24
25if ENABLE_TEST_RUN
26TESTS = \
27 test_sq
28endif
29
30check_PROGRAMS= \
31 test_sq
32
33test_sq_SOURCES = \
34 test_sq.c
35test_sq_LDADD = \
36 libgnunetsq.la \
37 $(top_builddir)/src/lib/util/libgnunetutil.la \
38 -lsqlite3 $(XLIB)
diff --git a/src/lib/sq/meson.build b/src/lib/sq/meson.build
new file mode 100644
index 000000000..69d372cac
--- /dev/null
+++ b/src/lib/sq/meson.build
@@ -0,0 +1,30 @@
1libgnunetsq_src = ['sq.c',
2 'sq_exec.c',
3 'sq_prepare.c',
4 'sq_query_helper.c',
5 'sq_result_helper.c']
6
7libgnunetsq = library('gnunetsq',
8 libgnunetsq_src,
9 soversion: '0',
10 version: '0.0.0',
11 dependencies: [libgnunetutil_dep, sqlite_dep],
12 include_directories: [incdir, configuration_inc],
13 install: true,
14 install_dir: get_option('libdir'))
15pkg.generate(libgnunetsq, url: 'https://www.gnunet.org',
16 description : 'Provides API for accessing the SQ service')
17libgnunetsq_dep = declare_dependency(link_with : libgnunetsq)
18testsq = executable ('test_sq',
19 ['test_sq.c'],
20 dependencies: [libgnunetutil_dep,
21 sqlite_dep,
22 libgnunetsq_dep],
23 include_directories: [incdir, configuration_inc],
24 build_by_default: false,
25 install: false)
26test('test_sq', testsq,
27 workdir: meson.current_build_dir(),
28 suite: ['sq'])
29
30
diff --git a/src/lib/sq/sq.c b/src/lib/sq/sq.c
new file mode 100644
index 000000000..96d1d333d
--- /dev/null
+++ b/src/lib/sq/sq.c
@@ -0,0 +1,131 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file sq/sq.c
22 * @brief helper functions for Sqlite3 DB interactions
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_sq_lib.h"
27
28
29enum GNUNET_GenericReturnValue
30GNUNET_SQ_bind (sqlite3_stmt *stmt,
31 const struct GNUNET_SQ_QueryParam *params)
32{
33 unsigned int j;
34
35 j = 1;
36 for (unsigned int i = 0; NULL != params[i].conv; i++)
37 {
38 if (GNUNET_OK !=
39 params[i].conv (params[i].conv_cls,
40 params[i].data,
41 params[i].size,
42 stmt,
43 j))
44 {
45 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
46 "sq",
47 _ ("Failure to bind %u-th SQL parameter\n"),
48 i);
49 if (SQLITE_OK !=
50 sqlite3_reset (stmt))
51 {
52 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
53 "sq",
54 _ ("Failure in sqlite3_reset (!)\n"));
55 return GNUNET_SYSERR;
56 }
57 }
58 GNUNET_assert (0 != params[i].num_params);
59 j += params[i].num_params;
60 }
61 return GNUNET_OK;
62}
63
64
65/**
66 * Extract results from a query result according to the given specification.
67 *
68 * @param result result to process
69 * @param[in,out] rs result specification to extract for
70 * @return
71 * #GNUNET_OK if all results could be extracted
72 * #GNUNET_SYSERR if a result was invalid (non-existing field)
73 */
74enum GNUNET_GenericReturnValue
75GNUNET_SQ_extract_result (sqlite3_stmt *result,
76 struct GNUNET_SQ_ResultSpec *rs)
77{
78 unsigned int j = 0;
79
80 for (unsigned int i = 0; NULL != rs[i].conv; i++)
81 {
82 if (NULL == rs[i].result_size)
83 rs[i].result_size = &rs[i].dst_size;
84 if (GNUNET_OK !=
85 rs[i].conv (rs[i].cls,
86 result,
87 j,
88 rs[i].result_size,
89 rs[i].dst))
90 {
91 for (unsigned int k = 0; k < i; k++)
92 if (NULL != rs[k].cleaner)
93 rs[k].cleaner (rs[k].cls);
94 return GNUNET_SYSERR;
95 }
96 GNUNET_assert (0 != rs[i].num_params);
97 j += rs[i].num_params;
98 }
99 return GNUNET_OK;
100}
101
102
103void
104GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs)
105{
106 for (unsigned int i = 0; NULL != rs[i].conv; i++)
107 if (NULL != rs[i].cleaner)
108 rs[i].cleaner (rs[i].cls);
109}
110
111
112/**
113 * Reset @a stmt and log error.
114 *
115 * @param dbh database handle
116 * @param stmt statement to reset
117 */
118void
119GNUNET_SQ_reset (sqlite3 *dbh,
120 sqlite3_stmt *stmt)
121{
122 if (SQLITE_OK !=
123 sqlite3_reset (stmt))
124 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
125 "sqlite",
126 _ ("Failed to reset sqlite statement with error: %s\n"),
127 sqlite3_errmsg (dbh));
128}
129
130
131/* end of sq.c */
diff --git a/src/lib/sq/sq_exec.c b/src/lib/sq/sq_exec.c
new file mode 100644
index 000000000..d4690ee99
--- /dev/null
+++ b/src/lib/sq/sq_exec.c
@@ -0,0 +1,113 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file sq/sq_exec.c
22 * @brief helper functions for executing SQL statements
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_sq_lib.h"
27
28
29/**
30 * Create a `struct GNUNET_SQ_ExecuteStatement` where errors are fatal.
31 *
32 * @param sql actual SQL statement
33 * @return initialized struct
34 */
35struct GNUNET_SQ_ExecuteStatement
36GNUNET_SQ_make_execute (const char *sql)
37{
38 struct GNUNET_SQ_ExecuteStatement es = {
39 .sql = sql,
40 .ignore_errors = GNUNET_NO
41 };
42
43 return es;
44}
45
46
47/**
48 * Create a `struct GNUNET_SQ_ExecuteStatement` where errors should
49 * be tolerated.
50 *
51 * @param sql actual SQL statement
52 * @return initialized struct
53 */
54struct GNUNET_SQ_ExecuteStatement
55GNUNET_SQ_make_try_execute (const char *sql)
56{
57 struct GNUNET_SQ_ExecuteStatement es = {
58 .sql = sql,
59 .ignore_errors = GNUNET_YES
60 };
61
62 return es;
63}
64
65
66/**
67 * Request execution of an array of statements @a es from Postgres.
68 *
69 * @param dbh database to execute the statements over
70 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
71 * statements.
72 * @return #GNUNET_OK on success (modulo statements where errors can be ignored)
73 * #GNUNET_SYSERR on error
74 */
75enum GNUNET_GenericReturnValue
76GNUNET_SQ_exec_statements (sqlite3 *dbh,
77 const struct GNUNET_SQ_ExecuteStatement *es)
78{
79 for (unsigned int i = 0; NULL != es[i].sql; i++)
80 {
81 char *emsg = NULL;
82
83 if (SQLITE_OK !=
84 sqlite3_exec (dbh,
85 es[i].sql,
86 NULL,
87 NULL,
88 &emsg))
89 {
90 if (es[i].ignore_errors)
91 {
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "Failed to run SQL `%s': %s\n",
94 es[i].sql,
95 emsg);
96 }
97 else
98 {
99 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
100 "Failed to run SQL `%s': %s\n",
101 es[i].sql,
102 emsg);
103 sqlite3_free (emsg);
104 return GNUNET_SYSERR;
105 }
106 sqlite3_free (emsg);
107 }
108 }
109 return GNUNET_OK;
110}
111
112
113/* end of sq_exec */
diff --git a/src/lib/sq/sq_prepare.c b/src/lib/sq/sq_prepare.c
new file mode 100644
index 000000000..d1ca0e8bd
--- /dev/null
+++ b/src/lib/sq/sq_prepare.c
@@ -0,0 +1,77 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file sq/sq_prepare.c
22 * @brief helper functions for executing SQL statements
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_sq_lib.h"
27
28
29/**
30 * Create a `struct GNUNET_SQ_PrepareStatement`
31 *
32 * @param sql actual SQL statement
33 * @param pstmt where to store the handle
34 * @return initialized struct
35 */
36struct GNUNET_SQ_PrepareStatement
37GNUNET_SQ_make_prepare (const char *sql,
38 sqlite3_stmt **pstmt)
39{
40 struct GNUNET_SQ_PrepareStatement ps = {
41 .sql = sql,
42 .pstmt = pstmt
43 };
44
45 return ps;
46}
47
48
49enum GNUNET_GenericReturnValue
50GNUNET_SQ_prepare (sqlite3 *dbh,
51 const struct GNUNET_SQ_PrepareStatement *ps)
52{
53 for (unsigned int i = 0; NULL != ps[i].sql; i++)
54 {
55 const char *epos = NULL;
56 int ret;
57
58 if (SQLITE_OK !=
59 (ret = sqlite3_prepare_v2 (dbh,
60 ps[i].sql,
61 strlen (ps[i].sql),
62 ps[i].pstmt,
63 &epos)))
64 {
65 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
66 "Failed to prepare SQL `%s': error %d at %s\n",
67 ps[i].sql,
68 ret,
69 epos);
70 return GNUNET_SYSERR;
71 }
72 }
73 return GNUNET_OK;
74}
75
76
77/* end of sq_prepare.c */
diff --git a/src/lib/sq/sq_query_helper.c b/src/lib/sq/sq_query_helper.c
new file mode 100644
index 000000000..ead1b5bdd
--- /dev/null
+++ b/src/lib/sq/sq_query_helper.c
@@ -0,0 +1,510 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file sq/sq_query_helper.c
22 * @brief helper functions for queries
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_sq_lib.h"
27
28
29/**
30 * Function called to convert input argument into SQL parameters.
31 *
32 * @param cls closure
33 * @param data pointer to input argument
34 * @param data_len number of bytes in @a data (if applicable)
35 * @param stmt sqlite statement to bind parameters for
36 * @param off offset of the argument to bind in @a stmt, numbered from 1,
37 * so immediately suitable for passing to `sqlite3_bind`-functions.
38 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
39 */
40static int
41bind_fixed_blob (void *cls,
42 const void *data,
43 size_t data_len,
44 sqlite3_stmt *stmt,
45 unsigned int off)
46{
47 if (SQLITE_OK !=
48 sqlite3_bind_blob64 (stmt,
49 (int) off,
50 data,
51 (sqlite3_uint64) data_len,
52 SQLITE_TRANSIENT))
53 return GNUNET_SYSERR;
54 return GNUNET_OK;
55}
56
57
58/**
59 * Generate query parameter for a buffer @a ptr of
60 * @a ptr_size bytes.
61 *
62 * @param ptr pointer to the query parameter to pass
63 * @param ptr_size number of bytes in @a ptr
64 */
65struct GNUNET_SQ_QueryParam
66GNUNET_SQ_query_param_fixed_size (const void *ptr,
67 size_t ptr_size)
68{
69 struct GNUNET_SQ_QueryParam qp = {
70 .conv = &bind_fixed_blob,
71 .data = ptr,
72 .size = ptr_size,
73 .num_params = 1
74 };
75
76 return qp;
77}
78
79
80/**
81 * Function called to convert input argument into SQL parameters.
82 *
83 * @param cls closure
84 * @param data pointer to input argument
85 * @param data_len number of bytes in @a data (if applicable)
86 * @param stmt sqlite statement to bind parameters for
87 * @param off offset of the argument to bind in @a stmt, numbered from 1,
88 * so immediately suitable for passing to `sqlite3_bind`-functions.
89 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
90 */
91static int
92bind_string (void *cls,
93 const void *data,
94 size_t data_len,
95 sqlite3_stmt *stmt,
96 unsigned int off)
97{
98 if (NULL == data)
99 {
100 if (SQLITE_OK !=
101 sqlite3_bind_null (stmt,
102 (int) off))
103 return GNUNET_SYSERR;
104 return GNUNET_OK;
105 }
106 if (SQLITE_OK !=
107 sqlite3_bind_text (stmt,
108 (int) off,
109 (const char *) data,
110 -1,
111 SQLITE_TRANSIENT))
112 return GNUNET_SYSERR;
113 return GNUNET_OK;
114}
115
116
117/**
118 * Generate query parameter for a string.
119 *
120 * @param ptr pointer to the string query parameter to pass
121 */
122struct GNUNET_SQ_QueryParam
123GNUNET_SQ_query_param_string (const char *ptr)
124{
125 struct GNUNET_SQ_QueryParam qp = {
126 .conv = &bind_string,
127 .data = ptr,
128 .num_params = 1
129 };
130
131 return qp;
132}
133
134
135/**
136 * Function called to convert input argument into SQL parameters.
137 *
138 * @param cls closure
139 * @param data pointer to input argument
140 * @param data_len number of bytes in @a data (if applicable)
141 * @param stmt sqlite statement to bind parameters for
142 * @param off offset of the argument to bind in @a stmt, numbered from 1,
143 * so immediately suitable for passing to `sqlite3_bind`-functions.
144 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
145 */
146static int
147bind_rsa_pub (void *cls,
148 const void *data,
149 size_t data_len,
150 sqlite3_stmt *stmt,
151 unsigned int off)
152{
153 const struct GNUNET_CRYPTO_RsaPublicKey *rsa = data;
154 void *buf;
155 size_t buf_size;
156
157 GNUNET_break (NULL == cls);
158 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rsa,
159 &buf);
160 if (SQLITE_OK !=
161 sqlite3_bind_blob64 (stmt,
162 (int) off,
163 buf,
164 (sqlite3_uint64) buf_size,
165 SQLITE_TRANSIENT))
166 {
167 GNUNET_free (buf);
168 return GNUNET_SYSERR;
169 }
170 GNUNET_free (buf);
171 return GNUNET_OK;
172}
173
174
175/**
176 * Generate query parameter for an RSA public key. The
177 * database must contain a BLOB type in the respective position.
178 *
179 * @param x the query parameter to pass.
180 */
181struct GNUNET_SQ_QueryParam
182GNUNET_SQ_query_param_rsa_public_key (const struct
183 GNUNET_CRYPTO_RsaPublicKey *x)
184{
185 struct GNUNET_SQ_QueryParam qp = {
186 .conv = &bind_rsa_pub,
187 .data = x,
188 .num_params = 1
189 };
190
191 return qp;
192}
193
194
195/**
196 * Function called to convert input argument into SQL parameters.
197 *
198 * @param cls closure
199 * @param data pointer to input argument
200 * @param data_len number of bytes in @a data (if applicable)
201 * @param stmt sqlite statement to bind parameters for
202 * @param off offset of the argument to bind in @a stmt, numbered from 1,
203 * so immediately suitable for passing to `sqlite3_bind`-functions.
204 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
205 */
206static int
207bind_rsa_sig (void *cls,
208 const void *data,
209 size_t data_len,
210 sqlite3_stmt *stmt,
211 unsigned int off)
212{
213 const struct GNUNET_CRYPTO_RsaSignature *sig = data;
214 void *buf;
215 size_t buf_size;
216
217 GNUNET_break (NULL == cls);
218 buf_size = GNUNET_CRYPTO_rsa_signature_encode (sig,
219 &buf);
220 if (SQLITE_OK !=
221 sqlite3_bind_blob64 (stmt,
222 (int) off,
223 buf,
224 (sqlite3_uint64) buf_size,
225 SQLITE_TRANSIENT))
226 {
227 GNUNET_free (buf);
228 return GNUNET_SYSERR;
229 }
230 GNUNET_free (buf);
231 return GNUNET_OK;
232}
233
234
235/**
236 * Generate query parameter for an RSA signature. The
237 * database must contain a BLOB type in the respective position.
238 *
239 * @param x the query parameter to pass
240 */
241struct GNUNET_SQ_QueryParam
242GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
243{
244 struct GNUNET_SQ_QueryParam qp = {
245 .conv = &bind_rsa_sig,
246 .data = x,
247 .num_params = 1
248 };
249
250 return qp;
251}
252
253
254/**
255 * Function called to convert input argument into SQL parameters.
256 *
257 * @param cls closure
258 * @param data pointer to input argument
259 * @param data_len number of bytes in @a data (if applicable)
260 * @param stmt sqlite statement to bind parameters for
261 * @param off offset of the argument to bind in @a stmt, numbered from 1,
262 * so immediately suitable for passing to `sqlite3_bind`-functions.
263 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
264 */
265static int
266bind_abstime (void *cls,
267 const void *data,
268 size_t data_len,
269 sqlite3_stmt *stmt,
270 unsigned int off)
271{
272 const struct GNUNET_TIME_Absolute *u = data;
273 struct GNUNET_TIME_Absolute abs;
274
275 abs = *u;
276 if (abs.abs_value_us > INT64_MAX)
277 abs.abs_value_us = INT64_MAX;
278 GNUNET_assert (sizeof(uint64_t) == data_len);
279 if (SQLITE_OK !=
280 sqlite3_bind_int64 (stmt,
281 (int) off,
282 (sqlite3_int64) abs.abs_value_us))
283 return GNUNET_SYSERR;
284 return GNUNET_OK;
285}
286
287
288/**
289 * Generate query parameter for an absolute time value.
290 * The database must store a 64-bit integer.
291 *
292 * @param x pointer to the query parameter to pass
293 */
294struct GNUNET_SQ_QueryParam
295GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
296{
297 struct GNUNET_SQ_QueryParam qp = {
298 .conv = &bind_abstime,
299 .data = x,
300 .size = sizeof(struct GNUNET_TIME_Absolute),
301 .num_params = 1
302 };
303
304 return qp;
305}
306
307
308/**
309 * Function called to convert input argument into SQL parameters.
310 *
311 * @param cls closure
312 * @param data pointer to input argument
313 * @param data_len number of bytes in @a data (if applicable)
314 * @param stmt sqlite statement to bind parameters for
315 * @param off offset of the argument to bind in @a stmt, numbered from 1,
316 * so immediately suitable for passing to `sqlite3_bind`-functions.
317 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
318 */
319static int
320bind_nbotime (void *cls,
321 const void *data,
322 size_t data_len,
323 sqlite3_stmt *stmt,
324 unsigned int off)
325{
326 const struct GNUNET_TIME_AbsoluteNBO *u = data;
327 struct GNUNET_TIME_Absolute abs;
328
329 abs = GNUNET_TIME_absolute_ntoh (*u);
330 if (abs.abs_value_us > INT64_MAX)
331 abs.abs_value_us = INT64_MAX;
332 GNUNET_assert (sizeof(uint64_t) == data_len);
333 if (SQLITE_OK !=
334 sqlite3_bind_int64 (stmt,
335 (int) off,
336 (sqlite3_int64) abs.abs_value_us))
337 return GNUNET_SYSERR;
338 return GNUNET_OK;
339}
340
341
342/**
343 * Generate query parameter for an absolute time value.
344 * The database must store a 64-bit integer.
345 *
346 * @param x pointer to the query parameter to pass
347 */
348struct GNUNET_SQ_QueryParam
349GNUNET_SQ_query_param_absolute_time_nbo (const struct
350 GNUNET_TIME_AbsoluteNBO *x)
351{
352 struct GNUNET_SQ_QueryParam qp = {
353 .conv = &bind_nbotime,
354 .data = x,
355 .size = sizeof(struct GNUNET_TIME_AbsoluteNBO),
356 .num_params = 1
357 };
358
359 return qp;
360}
361
362
363/**
364 * Function called to convert input argument into SQL parameters.
365 *
366 * @param cls closure
367 * @param data pointer to input argument
368 * @param data_len number of bytes in @a data (if applicable)
369 * @param stmt sqlite statement to bind parameters for
370 * @param off offset of the argument to bind in @a stmt, numbered from 1,
371 * so immediately suitable for passing to `sqlite3_bind`-functions.
372 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
373 */
374static int
375bind_u16 (void *cls,
376 const void *data,
377 size_t data_len,
378 sqlite3_stmt *stmt,
379 unsigned int off)
380{
381 const uint16_t *u = data;
382
383 GNUNET_assert (sizeof(uint16_t) == data_len);
384 if (SQLITE_OK !=
385 sqlite3_bind_int (stmt,
386 (int) off,
387 (int) *u))
388 return GNUNET_SYSERR;
389 return GNUNET_OK;
390}
391
392
393/**
394 * Generate query parameter for an uint16_t in host byte order.
395 *
396 * @param x pointer to the query parameter to pass
397 */
398struct GNUNET_SQ_QueryParam
399GNUNET_SQ_query_param_uint16 (const uint16_t *x)
400{
401 struct GNUNET_SQ_QueryParam qp = {
402 .conv = &bind_u16,
403 .data = x,
404 .size = sizeof(uint16_t),
405 .num_params = 1
406 };
407
408 return qp;
409}
410
411
412/**
413 * Function called to convert input argument into SQL parameters.
414 *
415 * @param cls closure
416 * @param data pointer to input argument
417 * @param data_len number of bytes in @a data (if applicable)
418 * @param stmt sqlite statement to bind parameters for
419 * @param off offset of the argument to bind in @a stmt, numbered from 1,
420 * so immediately suitable for passing to `sqlite3_bind`-functions.
421 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
422 */
423static int
424bind_u32 (void *cls,
425 const void *data,
426 size_t data_len,
427 sqlite3_stmt *stmt,
428 unsigned int off)
429{
430 const uint32_t *u = data;
431
432 GNUNET_assert (sizeof(uint32_t) == data_len);
433 if (SQLITE_OK !=
434 sqlite3_bind_int64 (stmt,
435 (int) off,
436 (sqlite3_int64) * u))
437 return GNUNET_SYSERR;
438 return GNUNET_OK;
439}
440
441
442/**
443 * Generate query parameter for an uint32_t in host byte order.
444 *
445 * @param x pointer to the query parameter to pass
446 */
447struct GNUNET_SQ_QueryParam
448GNUNET_SQ_query_param_uint32 (const uint32_t *x)
449{
450 struct GNUNET_SQ_QueryParam qp = {
451 .conv = &bind_u32,
452 .data = x,
453 .size = sizeof(uint32_t),
454 .num_params = 1
455 };
456
457 return qp;
458}
459
460
461/**
462 * Function called to convert input argument into SQL parameters.
463 *
464 * @param cls closure
465 * @param data pointer to input argument
466 * @param data_len number of bytes in @a data (if applicable)
467 * @param stmt sqlite statement to bind parameters for
468 * @param off offset of the argument to bind in @a stmt, numbered from 1,
469 * so immediately suitable for passing to `sqlite3_bind`-functions.
470 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
471 */
472static int
473bind_u64 (void *cls,
474 const void *data,
475 size_t data_len,
476 sqlite3_stmt *stmt,
477 unsigned int off)
478{
479 const uint64_t *u = data;
480
481 GNUNET_assert (sizeof(uint64_t) == data_len);
482 if (SQLITE_OK !=
483 sqlite3_bind_int64 (stmt,
484 (int) off,
485 (sqlite3_int64) * u))
486 return GNUNET_SYSERR;
487 return GNUNET_OK;
488}
489
490
491/**
492 * Generate query parameter for an uint16_t in host byte order.
493 *
494 * @param x pointer to the query parameter to pass
495 */
496struct GNUNET_SQ_QueryParam
497GNUNET_SQ_query_param_uint64 (const uint64_t *x)
498{
499 struct GNUNET_SQ_QueryParam qp = {
500 .conv = &bind_u64,
501 .data = x,
502 .size = sizeof(uint64_t),
503 .num_params = 1
504 };
505
506 return qp;
507}
508
509
510/* end of sq_query_helper.c */
diff --git a/src/lib/sq/sq_result_helper.c b/src/lib/sq/sq_result_helper.c
new file mode 100644
index 000000000..5ea3f1e56
--- /dev/null
+++ b/src/lib/sq/sq_result_helper.c
@@ -0,0 +1,785 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file sq/sq_result_helper.c
22 * @brief helper functions for queries
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_sq_lib.h"
27
28
29/**
30 * Extract variable-sized binary data from a Postgres database @a result at row @a row.
31 *
32 * @param cls closure
33 * @param result where to extract data from
34 * @param column column to extract data from
35 * @param[in,out] dst_size where to store size of result, may be NULL
36 * @param[out] dst where to store the result (actually a `void **`)
37 * @return
38 * #GNUNET_YES if all results could be extracted
39 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
40 */
41static int
42extract_var_blob (void *cls,
43 sqlite3_stmt *result,
44 unsigned int column,
45 size_t *dst_size,
46 void *dst)
47{
48 int have;
49 const void *ret;
50 void **rdst = (void **) dst;
51
52 if (SQLITE_NULL ==
53 sqlite3_column_type (result,
54 column))
55 {
56 *rdst = NULL;
57 *dst_size = 0;
58 return GNUNET_YES;
59 }
60
61 if (SQLITE_BLOB !=
62 sqlite3_column_type (result,
63 column))
64 {
65 GNUNET_break (0);
66 return GNUNET_SYSERR;
67 }
68 /* sqlite manual says to invoke 'sqlite3_column_blob()'
69 before calling sqlite3_column_bytes() */
70 ret = sqlite3_column_blob (result,
71 column);
72 have = sqlite3_column_bytes (result,
73 column);
74 if (have < 0)
75 {
76 GNUNET_break (0);
77 return GNUNET_SYSERR;
78 }
79 *dst_size = have;
80 if (0 == have)
81 {
82 *rdst = NULL;
83 return GNUNET_OK;
84 }
85 *rdst = GNUNET_malloc (have);
86 GNUNET_memcpy (*rdst,
87 ret,
88 have);
89 return GNUNET_OK;
90}
91
92
93/**
94 * Cleanup memory allocated by #extract_var_blob().
95 *
96 * @param cls pointer to pointer of allocation
97 */
98static void
99clean_var_blob (void *cls)
100{
101 void **dptr = (void **) cls;
102
103 if (NULL != *dptr)
104 {
105 GNUNET_free (*dptr);
106 *dptr = NULL;
107 }
108}
109
110
111/**
112 * Variable-size result expected.
113 *
114 * @param[out] dst where to store the result, allocated
115 * @param[out] sptr where to store the size of @a dst
116 * @return array entry for the result specification to use
117 */
118struct GNUNET_SQ_ResultSpec
119GNUNET_SQ_result_spec_variable_size (void **dst,
120 size_t *sptr)
121{
122 struct GNUNET_SQ_ResultSpec rs = {
123 .conv = &extract_var_blob,
124 .cleaner = &clean_var_blob,
125 .dst = dst,
126 .cls = dst,
127 .result_size = sptr,
128 .num_params = 1
129 };
130
131 return rs;
132}
133
134
135/**
136 * Extract fixed-sized binary data from a Postgres database @a result at row @a row.
137 *
138 * @param cls closure
139 * @param result where to extract data from
140 * @param column column to extract data from
141 * @param[in,out] dst_size where to store size of result, may be NULL
142 * @param[out] dst where to store the result
143 * @return
144 * #GNUNET_YES if all results could be extracted
145 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
146 */
147static int
148extract_fixed_blob (void *cls,
149 sqlite3_stmt *result,
150 unsigned int column,
151 size_t *dst_size,
152 void *dst)
153{
154 int have;
155 const void *ret;
156
157 if ((0 == *dst_size) &&
158 (SQLITE_NULL ==
159 sqlite3_column_type (result,
160 column)))
161 {
162 return GNUNET_YES;
163 }
164
165 if (SQLITE_BLOB !=
166 sqlite3_column_type (result,
167 column))
168 {
169 GNUNET_break (0);
170 return GNUNET_SYSERR;
171 }
172 /* sqlite manual says to invoke 'sqlite3_column_blob()'
173 before calling sqlite3_column_bytes() */
174 ret = sqlite3_column_blob (result,
175 column);
176 have = sqlite3_column_bytes (result,
177 column);
178 if (*dst_size != have)
179 {
180 GNUNET_break (0);
181 return GNUNET_SYSERR;
182 }
183 GNUNET_memcpy (dst,
184 ret,
185 have);
186 return GNUNET_OK;
187}
188
189
190/**
191 * Fixed-size result expected.
192 *
193 * @param[out] dst where to store the result
194 * @param dst_size number of bytes in @a dst
195 * @return array entry for the result specification to use
196 */
197struct GNUNET_SQ_ResultSpec
198GNUNET_SQ_result_spec_fixed_size (void *dst,
199 size_t dst_size)
200{
201 struct GNUNET_SQ_ResultSpec rs = {
202 .conv = &extract_fixed_blob,
203 .dst = dst,
204 .dst_size = dst_size,
205 .num_params = 1
206 };
207
208 return rs;
209}
210
211
212/**
213 * Extract fixed-sized binary data from a Postgres database @a result at row @a row.
214 *
215 * @param cls closure
216 * @param result where to extract data from
217 * @param column column to extract data from
218 * @param[in,out] dst_size where to store size of result, may be NULL
219 * @param[out] dst where to store the result
220 * @return
221 * #GNUNET_YES if all results could be extracted
222 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
223 */
224static int
225extract_utf8_string (void *cls,
226 sqlite3_stmt *result,
227 unsigned int column,
228 size_t *dst_size,
229 void *dst)
230{
231 const char *text;
232 char **rdst = dst;
233
234 if (SQLITE_NULL ==
235 sqlite3_column_type (result,
236 column))
237 {
238 *rdst = NULL;
239 return GNUNET_OK;
240 }
241 if (SQLITE_TEXT !=
242 sqlite3_column_type (result,
243 column))
244 {
245 GNUNET_break (0);
246 return GNUNET_SYSERR;
247 }
248 /* sqlite manual guarantees that 'sqlite3_column_text()'
249 is 0-terminated */
250 text = (const char *) sqlite3_column_text (result,
251 column);
252 if (NULL == text)
253 {
254 GNUNET_break (0);
255 return GNUNET_SYSERR;
256 }
257 *dst_size = strlen (text) + 1;
258 *rdst = GNUNET_strdup (text);
259 return GNUNET_OK;
260}
261
262
263/**
264 * Cleanup memory allocated by #extract_var_blob().
265 *
266 * @param cls pointer to pointer of allocation
267 */
268static void
269clean_utf8_string (void *cls)
270{
271 char **dptr = (char **) cls;
272
273 if (NULL != *dptr)
274 {
275 GNUNET_free (*dptr);
276 *dptr = NULL;
277 }
278}
279
280
281/**
282 * 0-terminated string expected.
283 *
284 * @param[out] dst where to store the result, allocated
285 * @return array entry for the result specification to use
286 */
287struct GNUNET_SQ_ResultSpec
288GNUNET_SQ_result_spec_string (char **dst)
289{
290 struct GNUNET_SQ_ResultSpec rs = {
291 .conv = &extract_utf8_string,
292 .cleaner = &clean_utf8_string,
293 .cls = dst,
294 .dst = dst,
295 .num_params = 1
296 };
297
298 return rs;
299}
300
301
302/**
303 * Extract data from a Postgres database @a result at row @a row.
304 *
305 * @param cls closure
306 * @param result where to extract data from
307 * @param column column to extract data from
308 * @param[in,out] dst_size where to store size of result, may be NULL
309 * @param[out] dst where to store the result
310 * @return
311 * #GNUNET_YES if all results could be extracted
312 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
313 */
314static int
315extract_rsa_pub (void *cls,
316 sqlite3_stmt *result,
317 unsigned int column,
318 size_t *dst_size,
319 void *dst)
320{
321 struct GNUNET_CRYPTO_RsaPublicKey **pk = dst;
322 int have;
323 const void *ret;
324
325 if (SQLITE_BLOB !=
326 sqlite3_column_type (result,
327 column))
328 {
329 GNUNET_break (0);
330 return GNUNET_SYSERR;
331 }
332 /* sqlite manual says to invoke 'sqlite3_column_blob()'
333 before calling sqlite3_column_bytes() */
334 ret = sqlite3_column_blob (result,
335 column);
336 have = sqlite3_column_bytes (result,
337 column);
338 if (have < 0)
339 {
340 GNUNET_break (0);
341 return GNUNET_SYSERR;
342 }
343
344 *pk = GNUNET_CRYPTO_rsa_public_key_decode (ret,
345 have);
346 if (NULL == *pk)
347 {
348 GNUNET_break (0);
349 return GNUNET_SYSERR;
350 }
351 return GNUNET_OK;
352}
353
354
355/**
356 * Function called to clean up memory allocated
357 * by a #GNUNET_PQ_ResultConverter.
358 *
359 * @param cls closure
360 */
361static void
362clean_rsa_pub (void *cls)
363{
364 struct GNUNET_CRYPTO_RsaPublicKey **pk = cls;
365
366 if (NULL != *pk)
367 {
368 GNUNET_CRYPTO_rsa_public_key_free (*pk);
369 *pk = NULL;
370 }
371}
372
373
374/**
375 * RSA public key expected.
376 *
377 * @param[out] rsa where to store the result
378 * @return array entry for the result specification to use
379 */
380struct GNUNET_SQ_ResultSpec
381GNUNET_SQ_result_spec_rsa_public_key (struct GNUNET_CRYPTO_RsaPublicKey **rsa)
382{
383 struct GNUNET_SQ_ResultSpec rs = {
384 .conv = &extract_rsa_pub,
385 .cleaner = &clean_rsa_pub,
386 .dst = rsa,
387 .cls = rsa,
388 .num_params = 1
389 };
390
391 return rs;
392}
393
394
395/**
396 * Extract data from a Postgres database @a result at row @a row.
397 *
398 * @param cls closure
399 * @param result where to extract data from
400 * @param column column to extract data from
401 * @param[in,out] dst_size where to store size of result, may be NULL
402 * @param[out] dst where to store the result
403 * @return
404 * #GNUNET_YES if all results could be extracted
405 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
406 */
407static int
408extract_rsa_sig (void *cls,
409 sqlite3_stmt *result,
410 unsigned int column,
411 size_t *dst_size,
412 void *dst)
413{
414 struct GNUNET_CRYPTO_RsaSignature **sig = dst;
415 int have;
416 const void *ret;
417
418 if (SQLITE_BLOB !=
419 sqlite3_column_type (result,
420 column))
421 {
422 GNUNET_break (0);
423 return GNUNET_SYSERR;
424 }
425 /* sqlite manual says to invoke 'sqlite3_column_blob()'
426 before calling sqlite3_column_bytes() */
427 ret = sqlite3_column_blob (result,
428 column);
429 have = sqlite3_column_bytes (result,
430 column);
431 if (have < 0)
432 {
433 GNUNET_break (0);
434 return GNUNET_SYSERR;
435 }
436
437 *sig = GNUNET_CRYPTO_rsa_signature_decode (ret,
438 have);
439 if (NULL == *sig)
440 {
441 GNUNET_break (0);
442 return GNUNET_SYSERR;
443 }
444 return GNUNET_OK;
445}
446
447
448/**
449 * Function called to clean up memory allocated
450 * by a #GNUNET_PQ_ResultConverter.
451 *
452 * @param cls result data to clean up
453 */
454static void
455clean_rsa_sig (void *cls)
456{
457 struct GNUNET_CRYPTO_RsaSignature **sig = cls;
458
459 if (NULL != *sig)
460 {
461 GNUNET_CRYPTO_rsa_signature_free (*sig);
462 *sig = NULL;
463 }
464}
465
466
467/**
468 * RSA signature expected.
469 *
470 * @param[out] sig where to store the result;
471 * @return array entry for the result specification to use
472 */
473struct GNUNET_SQ_ResultSpec
474GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
475{
476 struct GNUNET_SQ_ResultSpec rs = {
477 .conv = &extract_rsa_sig,
478 .cleaner = &clean_rsa_sig,
479 .dst = sig,
480 .cls = sig,
481 .num_params = 1
482 };
483
484 return rs;
485}
486
487
488/**
489 * Extract absolute time value from a Postgres database @a result at row @a row.
490 *
491 * @param cls closure
492 * @param result where to extract data from
493 * @param column column to extract data from
494 * @param[in,out] dst_size where to store size of result, may be NULL
495 * @param[out] dst where to store the result
496 * @return
497 * #GNUNET_YES if all results could be extracted
498 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
499 */
500static int
501extract_abs_time (void *cls,
502 sqlite3_stmt *result,
503 unsigned int column,
504 size_t *dst_size,
505 void *dst)
506{
507 struct GNUNET_TIME_Absolute *u = dst;
508 struct GNUNET_TIME_Absolute t;
509
510 GNUNET_assert (sizeof(uint64_t) == *dst_size);
511 if (SQLITE_INTEGER !=
512 sqlite3_column_type (result,
513 column))
514 {
515 GNUNET_break (0);
516 return GNUNET_SYSERR;
517 }
518 t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
519 column);
520 if (INT64_MAX == t.abs_value_us)
521 t = GNUNET_TIME_UNIT_FOREVER_ABS;
522 *u = t;
523 return GNUNET_OK;
524}
525
526
527/**
528 * Absolute time expected.
529 *
530 * @param[out] at where to store the result
531 * @return array entry for the result specification to use
532 */
533struct GNUNET_SQ_ResultSpec
534GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at)
535{
536 struct GNUNET_SQ_ResultSpec rs = {
537 .conv = &extract_abs_time,
538 .dst = at,
539 .dst_size = sizeof(struct GNUNET_TIME_Absolute),
540 .num_params = 1
541 };
542
543 return rs;
544}
545
546
547/**
548 * Extract absolute time value in NBO from a Postgres database @a result at row @a row.
549 *
550 * @param cls closure
551 * @param result where to extract data from
552 * @param column column to extract data from
553 * @param[in,out] dst_size where to store size of result, may be NULL
554 * @param[out] dst where to store the result
555 * @return
556 * #GNUNET_YES if all results could be extracted
557 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
558 */
559static int
560extract_abs_time_nbo (void *cls,
561 sqlite3_stmt *result,
562 unsigned int column,
563 size_t *dst_size,
564 void *dst)
565{
566 struct GNUNET_TIME_AbsoluteNBO *u = dst;
567 struct GNUNET_TIME_Absolute t;
568
569 GNUNET_assert (sizeof(uint64_t) == *dst_size);
570 if (SQLITE_INTEGER !=
571 sqlite3_column_type (result,
572 column))
573 {
574 GNUNET_break (0);
575 return GNUNET_SYSERR;
576 }
577 t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
578 column);
579 if (INT64_MAX == t.abs_value_us)
580 t = GNUNET_TIME_UNIT_FOREVER_ABS;
581 *u = GNUNET_TIME_absolute_hton (t);
582 return GNUNET_OK;
583}
584
585
586/**
587 * Absolute time expected.
588 *
589 * @param[out] at where to store the result
590 * @return array entry for the result specification to use
591 */
592struct GNUNET_SQ_ResultSpec
593GNUNET_SQ_result_spec_absolute_time_nbo (struct GNUNET_TIME_AbsoluteNBO *at)
594{
595 struct GNUNET_SQ_ResultSpec rs = {
596 .conv = &extract_abs_time_nbo,
597 .dst = at,
598 .dst_size = sizeof(struct GNUNET_TIME_AbsoluteNBO),
599 .num_params = 1
600 };
601
602 return rs;
603}
604
605
606/**
607 * Extract 16-bit integer from a Postgres database @a result at row @a row.
608 *
609 * @param cls closure
610 * @param result where to extract data from
611 * @param column column to extract data from
612 * @param[in,out] dst_size where to store size of result, may be NULL
613 * @param[out] dst where to store the result
614 * @return
615 * #GNUNET_YES if all results could be extracted
616 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
617 */
618static int
619extract_uint16 (void *cls,
620 sqlite3_stmt *result,
621 unsigned int column,
622 size_t *dst_size,
623 void *dst)
624{
625 uint64_t v;
626 uint16_t *u = dst;
627
628 GNUNET_assert (sizeof(uint16_t) == *dst_size);
629 if (SQLITE_INTEGER !=
630 sqlite3_column_type (result,
631 column))
632 {
633 GNUNET_break (0);
634 return GNUNET_SYSERR;
635 }
636 v = (uint64_t) sqlite3_column_int64 (result,
637 column);
638 if (v > UINT16_MAX)
639 {
640 GNUNET_break (0);
641 return GNUNET_SYSERR;
642 }
643 *u = (uint16_t) v;
644 return GNUNET_OK;
645}
646
647
648/**
649 * uint16_t expected.
650 *
651 * @param[out] u16 where to store the result
652 * @return array entry for the result specification to use
653 */
654struct GNUNET_SQ_ResultSpec
655GNUNET_SQ_result_spec_uint16 (uint16_t *u16)
656{
657 struct GNUNET_SQ_ResultSpec rs = {
658 .conv = &extract_uint16,
659 .dst = u16,
660 .dst_size = sizeof(uint16_t),
661 .num_params = 1
662 };
663
664 return rs;
665}
666
667
668/**
669 * Extract 32-bit integer from a Postgres database @a result at row @a row.
670 *
671 * @param cls closure
672 * @param result where to extract data from
673 * @param column column to extract data from
674 * @param[in,out] dst_size where to store size of result, may be NULL
675 * @param[out] dst where to store the result
676 * @return
677 * #GNUNET_YES if all results could be extracted
678 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
679 */
680static int
681extract_uint32 (void *cls,
682 sqlite3_stmt *result,
683 unsigned int column,
684 size_t *dst_size,
685 void *dst)
686{
687 uint64_t v;
688 uint32_t *u = dst;
689
690 GNUNET_assert (sizeof(uint32_t) == *dst_size);
691 if (SQLITE_INTEGER !=
692 sqlite3_column_type (result,
693 column))
694 {
695 GNUNET_break (0);
696 return GNUNET_SYSERR;
697 }
698 v = (uint64_t) sqlite3_column_int64 (result,
699 column);
700 if (v > UINT32_MAX)
701 {
702 GNUNET_break (0);
703 return GNUNET_SYSERR;
704 }
705 *u = (uint32_t) v;
706 return GNUNET_OK;
707}
708
709
710/**
711 * uint32_t expected.
712 *
713 * @param[out] u32 where to store the result
714 * @return array entry for the result specification to use
715 */
716struct GNUNET_SQ_ResultSpec
717GNUNET_SQ_result_spec_uint32 (uint32_t *u32)
718{
719 struct GNUNET_SQ_ResultSpec rs = {
720 .conv = &extract_uint32,
721 .dst = u32,
722 .dst_size = sizeof(uint32_t),
723 .num_params = 1
724 };
725
726 return rs;
727}
728
729
730/**
731 * Extract 64-bit integer from a Postgres database @a result at row @a row.
732 *
733 * @param cls closure
734 * @param result where to extract data from
735 * @param column column to extract data from
736 * @param[in,out] dst_size where to store size of result, may be NULL
737 * @param[out] dst where to store the result
738 * @return
739 * #GNUNET_YES if all results could be extracted
740 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
741 */
742static int
743extract_uint64 (void *cls,
744 sqlite3_stmt *result,
745 unsigned int column,
746 size_t *dst_size,
747 void *dst)
748{
749 uint64_t *u = dst;
750
751 GNUNET_assert (sizeof(uint64_t) == *dst_size);
752 if (SQLITE_INTEGER !=
753 sqlite3_column_type (result,
754 column))
755 {
756 GNUNET_break (0);
757 return GNUNET_SYSERR;
758 }
759 *u = (uint64_t) sqlite3_column_int64 (result,
760 column);
761 return GNUNET_OK;
762}
763
764
765/**
766 * uint64_t expected.
767 *
768 * @param[out] u64 where to store the result
769 * @return array entry for the result specification to use
770 */
771struct GNUNET_SQ_ResultSpec
772GNUNET_SQ_result_spec_uint64 (uint64_t *u64)
773{
774 struct GNUNET_SQ_ResultSpec rs = {
775 .conv = &extract_uint64,
776 .dst = u64,
777 .dst_size = sizeof(uint64_t),
778 .num_params = 1
779 };
780
781 return rs;
782}
783
784
785/* end of sq_result_helper.c */
diff --git a/src/lib/sq/test_sq.c b/src/lib/sq/test_sq.c
new file mode 100644
index 000000000..292de5f34
--- /dev/null
+++ b/src/lib/sq/test_sq.c
@@ -0,0 +1,291 @@
1/*
2 This file is part of GNUnet
3 (C) 2015, 2016, 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file sq/test_sq.c
22 * @brief Tests for sqlite3 convenience API
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_sq_lib.h"
28
29
30/**
31 * @brief Prepare a SQL statement
32 *
33 * @param dbh handle to the database
34 * @param zSql SQL statement, UTF-8 encoded
35 * @param[out] ppStmt set to the prepared statement
36 * @return 0 on success
37 */
38static int
39sq_prepare (sqlite3 *dbh,
40 const char *zSql,
41 sqlite3_stmt **ppStmt)
42{
43 char *dummy;
44 int result;
45
46 result = sqlite3_prepare_v2 (dbh,
47 zSql,
48 strlen (zSql),
49 ppStmt,
50 (const char **) &dummy);
51 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
52 "Prepared `%s' / %p: %d\n",
53 zSql,
54 *ppStmt,
55 result);
56 return result;
57}
58
59
60/**
61 * Run actual test queries.
62 *
63 * @return 0 on success
64 */
65static int
66run_queries (sqlite3 *dbh)
67{
68 struct GNUNET_CRYPTO_RsaPublicKey *pub;
69 struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL;
70 struct GNUNET_CRYPTO_RsaSignature *sig;
71 struct GNUNET_CRYPTO_RsaSignature *sig2 = NULL;
72 struct GNUNET_TIME_Absolute abs_time = GNUNET_TIME_absolute_get ();
73 struct GNUNET_TIME_Absolute abs_time2;
74 struct GNUNET_TIME_Absolute forever = GNUNET_TIME_UNIT_FOREVER_ABS;
75 struct GNUNET_TIME_Absolute forever2;
76 struct GNUNET_HashCode hc;
77 struct GNUNET_HashCode hc2;
78 sqlite3_stmt *stmt;
79 struct GNUNET_CRYPTO_RsaPrivateKey *priv;
80 const char msg[] = "hello";
81 void *msg2;
82 struct GNUNET_HashCode hmsg;
83 size_t msg2_len;
84 uint16_t u16;
85 uint16_t u162;
86 uint32_t u32;
87 uint32_t u322;
88 uint64_t u64;
89 uint64_t u642;
90
91 priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
92 pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
93 memset (&hmsg, 42, sizeof(hmsg));
94 sig = GNUNET_CRYPTO_rsa_sign_fdh (priv,
95 &hmsg,
96 sizeof (hmsg));
97 u16 = 16;
98 u32 = 32;
99 u64 = 64;
100 /* FIXME: test GNUNET_SQ_result_spec_variable_size */
101
102 sq_prepare (dbh,
103 "INSERT INTO test_sq ("
104 " pub"
105 ",sig"
106 ",abs_time"
107 ",forever"
108 ",hash"
109 ",vsize"
110 ",u16"
111 ",u32"
112 ",u64"
113 ") VALUES "
114 "($1, $2, $3, $4, $5, $6,"
115 "$7, $8, $9);",
116 &stmt);
117 {
118 struct GNUNET_SQ_QueryParam params_insert[] = {
119 GNUNET_SQ_query_param_rsa_public_key (pub),
120 GNUNET_SQ_query_param_rsa_signature (sig),
121 GNUNET_SQ_query_param_absolute_time (&abs_time),
122 GNUNET_SQ_query_param_absolute_time (&forever),
123 GNUNET_SQ_query_param_auto_from_type (&hc),
124 GNUNET_SQ_query_param_fixed_size (msg, strlen (msg)),
125 GNUNET_SQ_query_param_uint16 (&u16),
126 GNUNET_SQ_query_param_uint32 (&u32),
127 GNUNET_SQ_query_param_uint64 (&u64),
128 GNUNET_SQ_query_param_end
129 };
130
131 GNUNET_assert (GNUNET_OK ==
132 GNUNET_SQ_bind (stmt,
133 params_insert));
134 if (SQLITE_DONE !=
135 sqlite3_step (stmt))
136 {
137 GNUNET_CRYPTO_rsa_signature_free (sig);
138 GNUNET_CRYPTO_rsa_private_key_free (priv);
139 GNUNET_CRYPTO_rsa_public_key_free (pub);
140 return 1;
141 }
142 sqlite3_reset (stmt);
143 }
144 sqlite3_finalize (stmt);
145
146 sq_prepare (dbh,
147 "SELECT"
148 " pub"
149 ",sig"
150 ",abs_time"
151 ",forever"
152 ",hash"
153 ",vsize"
154 ",u16"
155 ",u32"
156 ",u64"
157 " FROM test_sq"
158 " ORDER BY abs_time DESC "
159 " LIMIT 1;",
160 &stmt);
161 {
162 struct GNUNET_SQ_QueryParam params_select[] = {
163 GNUNET_SQ_query_param_end
164 };
165 struct GNUNET_SQ_ResultSpec results_select[] = {
166 GNUNET_SQ_result_spec_rsa_public_key (&pub2),
167 GNUNET_SQ_result_spec_rsa_signature (&sig2),
168 GNUNET_SQ_result_spec_absolute_time (&abs_time2),
169 GNUNET_SQ_result_spec_absolute_time (&forever2),
170 GNUNET_SQ_result_spec_auto_from_type (&hc2),
171 GNUNET_SQ_result_spec_variable_size (&msg2, &msg2_len),
172 GNUNET_SQ_result_spec_uint16 (&u162),
173 GNUNET_SQ_result_spec_uint32 (&u322),
174 GNUNET_SQ_result_spec_uint64 (&u642),
175 GNUNET_SQ_result_spec_end
176 };
177
178 GNUNET_assert (GNUNET_OK ==
179 GNUNET_SQ_bind (stmt,
180 params_select));
181 if (SQLITE_ROW !=
182 sqlite3_step (stmt))
183 {
184 GNUNET_break (0);
185 sqlite3_finalize (stmt);
186 GNUNET_CRYPTO_rsa_signature_free (sig);
187 GNUNET_CRYPTO_rsa_private_key_free (priv);
188 GNUNET_CRYPTO_rsa_public_key_free (pub);
189 return 1;
190 }
191 GNUNET_assert (GNUNET_OK ==
192 GNUNET_SQ_extract_result (stmt,
193 results_select));
194 GNUNET_break (abs_time.abs_value_us == abs_time2.abs_value_us);
195 GNUNET_break (forever.abs_value_us == forever2.abs_value_us);
196 GNUNET_break (0 ==
197 GNUNET_memcmp (&hc,
198 &hc2));
199 GNUNET_break (0 ==
200 GNUNET_CRYPTO_rsa_signature_cmp (sig,
201 sig2));
202 GNUNET_break (0 ==
203 GNUNET_CRYPTO_rsa_public_key_cmp (pub,
204 pub2));
205 GNUNET_break (strlen (msg) == msg2_len);
206 GNUNET_break (0 ==
207 strncmp (msg,
208 msg2,
209 msg2_len));
210 GNUNET_break (16 == u162);
211 GNUNET_break (32 == u322);
212 GNUNET_break (64 == u642);
213 GNUNET_SQ_cleanup_result (results_select);
214 sqlite3_reset (stmt);
215 }
216 sqlite3_finalize (stmt);
217
218 GNUNET_CRYPTO_rsa_signature_free (sig);
219 GNUNET_CRYPTO_rsa_private_key_free (priv);
220 GNUNET_CRYPTO_rsa_public_key_free (pub);
221 return 0;
222}
223
224
225int
226main (int argc,
227 const char *const argv[])
228{
229 sqlite3 *dbh;
230 int ret;
231
232 GNUNET_log_setup ("test-sq",
233 "WARNING",
234 NULL);
235 if (SQLITE_OK !=
236 sqlite3_open ("test.db",
237 &dbh))
238 {
239 fprintf (stderr,
240 "Cannot run test, sqlite3 initialization failed\n");
241 GNUNET_break (0);
242 return 77; /* Signal test was skipped... */
243 }
244
245 if (SQLITE_OK !=
246 sqlite3_exec (dbh,
247 "CREATE TEMPORARY TABLE IF NOT EXISTS test_sq ("
248 " pub BYTEA NOT NULL"
249 ",sig BYTEA NOT NULL"
250 ",abs_time INT8 NOT NULL"
251 ",forever INT8 NOT NULL"
252 ",hash BYTEA NOT NULL"
253 ",vsize VARCHAR NOT NULL"
254 ",u16 INT2 NOT NULL"
255 ",u32 INT4 NOT NULL"
256 ",u64 INT8 NOT NULL"
257 ")",
258 NULL, NULL, NULL))
259 {
260 fprintf (stderr,
261 "Failed to create table\n");
262 GNUNET_break (SQLITE_OK ==
263 sqlite3_close (dbh));
264 if (0 != unlink ("test.db"))
265 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
266 "unlink",
267 "test.db");
268 return 1;
269 }
270
271 ret = run_queries (dbh);
272 if (SQLITE_OK !=
273 sqlite3_exec (dbh,
274 "DROP TABLE test_sq",
275 NULL, NULL, NULL))
276 {
277 fprintf (stderr,
278 "Failed to drop table\n");
279 ret = 1;
280 }
281 GNUNET_break (SQLITE_OK ==
282 sqlite3_close (dbh));
283 if (0 != unlink ("test.db"))
284 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
285 "unlink",
286 "test.db");
287 return ret;
288}
289
290
291/* end of test_sq.c */