summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac4
-rw-r--r--pkgconfig/gnunetpq.pc.in12
-rw-r--r--po/POTFILES.in19
-rw-r--r--src/Makefile.am2
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_postgres_lib.h40
-rw-r--r--src/include/gnunet_pq_lib.h454
-rw-r--r--src/postgres/postgres.c61
-rw-r--r--src/pq/Makefile.am39
-rw-r--r--src/pq/pq.c169
-rw-r--r--src/pq/pq_query_helper.c386
-rw-r--r--src/pq/pq_result_helper.c674
-rw-r--r--src/pq/test_pq.c288
13 files changed, 2111 insertions, 38 deletions
diff --git a/configure.ac b/configure.ac
index fcf0e7f4d..42f7f5feb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
1# This file is part of GNUnet. 1# This file is part of GNUnet.
2# (C) 2001--2015 Christian Grothoff (and other contributing authors) 2# (C) 2001--2016 Christian Grothoff (and other contributing authors)
3# 3#
4# GNUnet is free software; you can redistribute it and/or modify 4# GNUnet is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published 5# it under the terms of the GNU General Public License as published
@@ -1566,6 +1566,7 @@ src/peerinfo/peerinfo.conf
1566src/peerinfo-tool/Makefile 1566src/peerinfo-tool/Makefile
1567src/peerstore/Makefile 1567src/peerstore/Makefile
1568src/peerstore/peerstore.conf 1568src/peerstore/peerstore.conf
1569src/pq/Makefile
1569src/postgres/Makefile 1570src/postgres/Makefile
1570src/psycutil/Makefile 1571src/psycutil/Makefile
1571src/psyc/Makefile 1572src/psyc/Makefile
@@ -1635,6 +1636,7 @@ pkgconfig/gnunetnamestore.pc
1635pkgconfig/gnunetnat.pc 1636pkgconfig/gnunetnat.pc
1636pkgconfig/gnunetnse.pc 1637pkgconfig/gnunetnse.pc
1637pkgconfig/gnunetpeerinfo.pc 1638pkgconfig/gnunetpeerinfo.pc
1639pkgconfig/gnunetpq.pc
1638pkgconfig/gnunetpostgres.pc 1640pkgconfig/gnunetpostgres.pc
1639pkgconfig/gnunetpsyc.pc 1641pkgconfig/gnunetpsyc.pc
1640pkgconfig/gnunetpsycstore.pc 1642pkgconfig/gnunetpsycstore.pc
diff --git a/pkgconfig/gnunetpq.pc.in b/pkgconfig/gnunetpq.pc.in
new file mode 100644
index 000000000..b24ea220b
--- /dev/null
+++ b/pkgconfig/gnunetpq.pc.in
@@ -0,0 +1,12 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: GNUnet PQ
7Description: API with common functions for interacting with libpq
8URL: http://gnunet.org
9Version: @VERSION@
10Requires:
11Libs: -L${libdir} -lgnunetpq
12Cflags: -I${includedir}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index afe2b47b3..c4665a775 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -123,7 +123,6 @@ src/dv/dv_api.c
123src/dv/gnunet-dv.c 123src/dv/gnunet-dv.c
124src/dv/gnunet-service-dv.c 124src/dv/gnunet-service-dv.c
125src/dv/plugin_transport_dv.c 125src/dv/plugin_transport_dv.c
126src/env/env.c
127src/exit/gnunet-daemon-exit.c 126src/exit/gnunet-daemon-exit.c
128src/exit/gnunet-helper-exit.c 127src/exit/gnunet-helper-exit.c
129src/exit/gnunet-helper-exit-windows.c 128src/exit/gnunet-helper-exit-windows.c
@@ -203,9 +202,13 @@ src/identity/gnunet-identity.c
203src/identity/gnunet-service-identity.c 202src/identity/gnunet-service-identity.c
204src/identity/identity_api.c 203src/identity/identity_api.c
205src/identity/identity_api_lookup.c 204src/identity/identity_api_lookup.c
205src/identity/plugin_gnsrecord_identity.c
206src/identity/plugin_rest_identity.c 206src/identity/plugin_rest_identity.c
207src/identity-token/gnunet-identity-token.c 207src/identity-provider/gnunet-identity-token.c
208src/identity-token/plugin_rest_identity_token.c 208src/identity-provider/gnunet-service-identity-provider.c
209src/identity-provider/identity_provider_api.c
210src/identity-provider/identity_token.c
211src/identity-provider/plugin_rest_identity_provider.c
209src/multicast/gnunet-multicast.c 212src/multicast/gnunet-multicast.c
210src/multicast/gnunet-service-multicast.c 213src/multicast/gnunet-service-multicast.c
211src/multicast/multicast_api.c 214src/multicast/multicast_api.c
@@ -251,12 +254,17 @@ src/peerstore/peerstore_api.c
251src/peerstore/peerstore_common.c 254src/peerstore/peerstore_common.c
252src/peerstore/plugin_peerstore_sqlite.c 255src/peerstore/plugin_peerstore_sqlite.c
253src/postgres/postgres.c 256src/postgres/postgres.c
257src/pq/pq.c
258src/pq/pq_query_helper.c
259src/pq/pq_result_helper.c
254src/psyc/gnunet-service-psyc.c 260src/psyc/gnunet-service-psyc.c
255src/psyc/psyc_api.c 261src/psyc/psyc_api.c
256src/psycstore/gnunet-service-psycstore.c 262src/psycstore/gnunet-service-psycstore.c
257src/psycstore/plugin_psycstore_sqlite.c 263src/psycstore/plugin_psycstore_sqlite.c
258src/psycstore/psycstore_api.c 264src/psycstore/psycstore_api.c
259src/psycstore/psyc_util_lib.c 265src/psycutil/psyc_env.c
266src/psycutil/psyc_message.c
267src/psycutil/psyc_slicer.c
260src/pt/gnunet-daemon-pt.c 268src/pt/gnunet-daemon-pt.c
261src/regex/gnunet-daemon-regexprofiler.c 269src/regex/gnunet-daemon-regexprofiler.c
262src/regex/gnunet-regex-profiler.c 270src/regex/gnunet-regex-profiler.c
@@ -278,8 +286,11 @@ src/revocation/gnunet-service-revocation.c
278src/revocation/revocation_api.c 286src/revocation/revocation_api.c
279src/rps/gnunet-rps.c 287src/rps/gnunet-rps.c
280src/rps/gnunet-service-rps.c 288src/rps/gnunet-service-rps.c
289src/rps/gnunet-service-rps_custommap.c
290src/rps/gnunet-service-rps_peers.c
281src/rps/gnunet-service-rps_sampler.c 291src/rps/gnunet-service-rps_sampler.c
282src/rps/gnunet-service-rps_sampler_elem.c 292src/rps/gnunet-service-rps_sampler_elem.c
293src/rps/gnunet-service-rps_view.c
283src/rps/rps_api.c 294src/rps/rps_api.c
284src/rps/rps-test_util.c 295src/rps/rps-test_util.c
285src/scalarproduct/gnunet-scalarproduct.c 296src/scalarproduct/gnunet-scalarproduct.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 925d395aa..edfbb6922 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,7 +44,7 @@ if HAVE_MYSQL
44endif 44endif
45 45
46if HAVE_POSTGRESQL 46if HAVE_POSTGRESQL
47 POSTGRES_DIR = postgres 47 POSTGRES_DIR = pq postgres
48endif 48endif
49 49
50if HAVE_REST 50if HAVE_REST
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index dd32da171..626089dbc 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -84,6 +84,7 @@ gnunetinclude_HEADERS = \
84 gnunet_peerstore_plugin.h \ 84 gnunet_peerstore_plugin.h \
85 gnunet_peerstore_service.h \ 85 gnunet_peerstore_service.h \
86 gnunet_plugin_lib.h \ 86 gnunet_plugin_lib.h \
87 gnunet_pq_lib.h \
87 gnunet_postgres_lib.h \ 88 gnunet_postgres_lib.h \
88 gnunet_psycstore_plugin.h \ 89 gnunet_psycstore_plugin.h \
89 gnunet_psycstore_service.h \ 90 gnunet_psycstore_service.h \
diff --git a/src/include/gnunet_postgres_lib.h b/src/include/gnunet_postgres_lib.h
index 79fb66f67..0307df50d 100644
--- a/src/include/gnunet_postgres_lib.h
+++ b/src/include/gnunet_postgres_lib.h
@@ -45,7 +45,7 @@ extern "C"
45/** 45/**
46 * Check if the result obtained from Postgres has 46 * Check if the result obtained from Postgres has
47 * the desired status code. If not, log an error, clear the 47 * the desired status code. If not, log an error, clear the
48 * result and return GNUNET_SYSERR. 48 * result and return #GNUNET_SYSERR.
49 * 49 *
50 * @param dbh database handle 50 * @param dbh database handle
51 * @param ret return value from database operation to check 51 * @param ret return value from database operation to check
@@ -54,25 +54,29 @@ extern "C"
54 * @param args arguments given to the command 54 * @param args arguments given to the command
55 * @param filename name of the source file where the command was run 55 * @param filename name of the source file where the command was run
56 * @param line line number in the source file 56 * @param line line number in the source file
57 * @return GNUNET_OK if the result is acceptable 57 * @return #GNUNET_OK if the result is acceptable
58 */ 58 */
59int 59int
60GNUNET_POSTGRES_check_result_ (PGconn *dbh, PGresult * ret, int expected_status, 60GNUNET_POSTGRES_check_result_ (PGconn *dbh,
61 const char *command, const char *args, 61 PGresult *ret,
62 const char *filename, int line); 62 int expected_status,
63 const char *command,
64 const char *args,
65 const char *filename,
66 int line);
63 67
64 68
65/** 69/**
66 * Check if the result obtained from Postgres has 70 * Check if the result obtained from Postgres has
67 * the desired status code. If not, log an error, clear the 71 * the desired status code. If not, log an error, clear the
68 * result and return GNUNET_SYSERR. 72 * result and return #GNUNET_SYSERR.
69 * 73 *
70 * @param dbh database handle 74 * @param dbh database handle
71 * @param ret return value from database operation to check 75 * @param ret return value from database operation to check
72 * @param expected_status desired status 76 * @param expected_status desired status
73 * @param command description of the command that was run 77 * @param command description of the command that was run
74 * @param args arguments given to the command 78 * @param args arguments given to the command
75 * @return GNUNET_OK if the result is acceptable 79 * @return #GNUNET_OK if the result is acceptable
76 */ 80 */
77#define GNUNET_POSTGRES_check_result(dbh,ret,expected_status,command,args) GNUNET_POSTGRES_check_result_(dbh,ret,expected_status,command,args,__FILE__,__LINE__) 81#define GNUNET_POSTGRES_check_result(dbh,ret,expected_status,command,args) GNUNET_POSTGRES_check_result_(dbh,ret,expected_status,command,args,__FILE__,__LINE__)
78 82
@@ -84,10 +88,13 @@ GNUNET_POSTGRES_check_result_ (PGconn *dbh, PGresult * ret, int expected_status,
84 * @param sql statement to run 88 * @param sql statement to run
85 * @param filename filename for error reporting 89 * @param filename filename for error reporting
86 * @param line code line for error reporting 90 * @param line code line for error reporting
87 * @return GNUNET_OK on success 91 * @return #GNUNET_OK on success
88 */ 92 */
89int 93int
90GNUNET_POSTGRES_exec_ (PGconn *dbh, const char *sql, const char *filename, int line); 94GNUNET_POSTGRES_exec_ (PGconn *dbh,
95 const char *sql,
96 const char *filename,
97 int line);
91 98
92 99
93/** 100/**
@@ -95,7 +102,7 @@ GNUNET_POSTGRES_exec_ (PGconn *dbh, const char *sql, const char *filename, int l
95 * 102 *
96 * @param dbh database handle 103 * @param dbh database handle
97 * @param sql statement to run 104 * @param sql statement to run
98 * @return GNUNET_OK on success 105 * @return #GNUNET_OK on success
99 */ 106 */
100#define GNUNET_POSTGRES_exec(dbh,sql) GNUNET_POSTGRES_exec_(dbh,sql,__FILE__,__LINE__) 107#define GNUNET_POSTGRES_exec(dbh,sql) GNUNET_POSTGRES_exec_(dbh,sql,__FILE__,__LINE__)
101 108
@@ -109,12 +116,15 @@ GNUNET_POSTGRES_exec_ (PGconn *dbh, const char *sql, const char *filename, int l
109 * @param nparams number of parameters in sql 116 * @param nparams number of parameters in sql
110 * @param filename filename for error reporting 117 * @param filename filename for error reporting
111 * @param line code line for error reporting 118 * @param line code line for error reporting
112 * @return GNUNET_OK on success 119 * @return #GNUNET_OK on success
113 */ 120 */
114int 121int
115GNUNET_POSTGRES_prepare_ (PGconn *dbh, const char *name, const char *sql, 122GNUNET_POSTGRES_prepare_ (PGconn *dbh,
123 const char *name,
124 const char *sql,
116 int nparams, 125 int nparams,
117 const char *filename, int line); 126 const char *filename,
127 int line);
118 128
119 129
120/** 130/**
@@ -124,7 +134,7 @@ GNUNET_POSTGRES_prepare_ (PGconn *dbh, const char *name, const char *sql,
124 * @param name name for the prepared SQL statement 134 * @param name name for the prepared SQL statement
125 * @param sql SQL code to prepare 135 * @param sql SQL code to prepare
126 * @param nparams number of parameters in sql 136 * @param nparams number of parameters in sql
127 * @return GNUNET_OK on success 137 * @return #GNUNET_OK on success
128 */ 138 */
129#define GNUNET_POSTGRES_prepare(dbh,name,sql,nparams) GNUNET_POSTGRES_prepare_(dbh,name,sql,nparams,__FILE__,__LINE__) 139#define GNUNET_POSTGRES_prepare(dbh,name,sql,nparams) GNUNET_POSTGRES_prepare_(dbh,name,sql,nparams,__FILE__,__LINE__)
130 140
@@ -148,7 +158,7 @@ GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
148 * @param dbh database handle 158 * @param dbh database handle
149 * @param stmt name of the prepared statement 159 * @param stmt name of the prepared statement
150 * @param rowid which row to delete 160 * @param rowid which row to delete
151 * @return GNUNET_OK on success 161 * @return #GNUNET_OK on success
152 */ 162 */
153int 163int
154GNUNET_POSTGRES_delete_by_rowid (PGconn *dbh, 164GNUNET_POSTGRES_delete_by_rowid (PGconn *dbh,
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
new file mode 100644
index 000000000..dd41406d3
--- /dev/null
+++ b/src/include/gnunet_pq_lib.h
@@ -0,0 +1,454 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file include/gnunet_pq_lib.h
18 * @brief helper functions for DB interactions
19 * @author Christian Grothoff
20 */
21#ifndef GNUNET_PQ_LIB_H_
22#define GNUNET_PQ_LIB_H_
23
24#include <libpq-fe.h>
25#include "gnunet_util_lib.h"
26
27
28/**
29 * Function called to convert input argument into SQL parameters.
30 *
31 * @param cls closure
32 * @param data pointer to input argument
33 * @param data_len number of bytes in @a data (if applicable)
34 * @param[out] param_values SQL data to set
35 * @param[out] param_lengths SQL length data to set
36 * @param[out] param_formats SQL format data to set
37 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
38 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
39 * @param scratch_length number of entries left in @a scratch
40 * @return -1 on error, number of offsets used in @a scratch otherwise
41 */
42typedef int
43(*GNUNET_PQ_QueryConverter)(void *cls,
44 const void *data,
45 size_t data_len,
46 void *param_values[],
47 int param_lengths[],
48 int param_formats[],
49 unsigned int param_length,
50 void *scratch[],
51 unsigned int scratch_length);
52
53
54/**
55 * @brief Description of a DB query parameter.
56 */
57struct GNUNET_PQ_QueryParam
58{
59
60 /**
61 * Format of the rest of the entry, determines the data
62 * type that is being added to the query.
63 */
64 GNUNET_PQ_QueryConverter conv;
65
66 /**
67 * Closure for @e conv.
68 */
69 void *conv_cls;
70
71 /**
72 * Data or NULL.
73 */
74 const void *data;
75
76 /**
77 * Size of @e data
78 */
79 size_t size;
80
81 /**
82 * Number of parameters eaten by this operation.
83 */
84 unsigned int num_params;
85};
86
87
88/**
89 * End of query parameter specification.
90 */
91#define GNUNET_PQ_query_param_end { NULL, NULL, NULL, 0, 0 }
92
93
94/**
95 * Generate query parameter for a buffer @a ptr of
96 * @a ptr_size bytes.
97 *
98 * @param ptr pointer to the query parameter to pass
99 * @oaran ptr_size number of bytes in @a ptr
100 */
101struct GNUNET_PQ_QueryParam
102GNUNET_PQ_query_param_fixed_size (const void *ptr,
103 size_t ptr_size);
104
105
106/**
107 * Generate fixed-size query parameter with size determined
108 * by variable type.
109 *
110 * @param x pointer to the query parameter to pass.
111 */
112#define GNUNET_PQ_query_param_auto_from_type(x) GNUNET_PQ_query_param_fixed_size ((x), sizeof (*(x)))
113
114
115/**
116 * Generate query parameter for an RSA public key. The
117 * database must contain a BLOB type in the respective position.
118 *
119 * @param x the query parameter to pass.
120 */
121struct GNUNET_PQ_QueryParam
122GNUNET_PQ_query_param_rsa_public_key (const struct GNUNET_CRYPTO_rsa_PublicKey *x);
123
124
125/**
126 * Generate query parameter for an RSA signature. The
127 * database must contain a BLOB type in the respective position.
128 *
129 * @param x the query parameter to pass
130 */
131struct GNUNET_PQ_QueryParam
132GNUNET_PQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_rsa_Signature *x);
133
134
135/**
136 * Generate query parameter for an absolute time value.
137 * The database must store a 64-bit integer.
138 *
139 * @param x pointer to the query parameter to pass
140 */
141struct GNUNET_PQ_QueryParam
142GNUNET_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x);
143
144
145/**
146 * Generate query parameter for an absolute time value.
147 * The database must store a 64-bit integer.
148 *
149 * @param x pointer to the query parameter to pass
150 */
151struct GNUNET_PQ_QueryParam
152GNUNET_PQ_query_param_absolute_time_nbo (const struct GNUNET_TIME_AbsoluteNBO *x);
153
154
155/**
156 * Generate query parameter for an uint16_t in host byte order.
157 *
158 * @param x pointer to the query parameter to pass
159 */
160struct GNUNET_PQ_QueryParam
161GNUNET_PQ_query_param_uint16 (const uint16_t *x);
162
163
164/**
165 * Generate query parameter for an uint32_t in host byte order.
166 *
167 * @param x pointer to the query parameter to pass
168 */
169struct GNUNET_PQ_QueryParam
170GNUNET_PQ_query_param_uint32 (const uint32_t *x);
171
172
173/**
174 * Generate query parameter for an uint16_t in host byte order.
175 *
176 * @param x pointer to the query parameter to pass
177 */
178struct GNUNET_PQ_QueryParam
179GNUNET_PQ_query_param_uint64 (const uint64_t *x);
180
181
182/**
183 * Extract data from a Postgres database @a result at row @a row.
184 *
185 * @param cls closure
186 * @param result where to extract data from
187 * @param int row to extract data from
188 * @param fname name (or prefix) of the fields to extract from
189 * @param[in,out] dst_size where to store size of result, may be NULL
190 * @param[out] dst where to store the result
191 * @return
192 * #GNUNET_YES if all results could be extracted
193 * #GNUNET_NO if at least one result was NULL
194 * #GNUNET_SYSERR if a result was invalid (non-existing field)
195 */
196typedef int
197(*GNUNET_PQ_ResultConverter)(void *cls,
198 PGresult *result,
199 int row,
200 const char *fname,
201 size_t *dst_size,
202 void *dst);
203
204
205/**
206 * Function called to clean up memory allocated
207 * by a #GNUNET_PQ_ResultConverter.
208 *
209 * @param cls closure
210 * @param rd result data to clean up
211 */
212typedef void
213(*GNUNET_PQ_ResultCleanup)(void *cls,
214 void *rd);
215
216
217/**
218 * @brief Description of a DB result cell.
219 */
220struct GNUNET_PQ_ResultSpec
221{
222
223 /**
224 * What is the format of the result?
225 */
226 GNUNET_PQ_ResultConverter conv;
227
228 /**
229 * Function to clean up result data, NULL if cleanup is
230 * not necessary.
231 */
232 GNUNET_PQ_ResultCleanup cleaner;
233
234 /**
235 * Closure for @e conv and @e cleaner.
236 */
237 void *cls;
238
239 /**
240 * Destination for the data.
241 */
242 void *dst;
243
244 /**
245 * Allowed size for the data, 0 for variable-size
246 * (in this case, the type of @e dst is a `void **`
247 * and we need to allocate a buffer of the right size).
248 */
249 size_t dst_size;
250
251 /**
252 * Field name of the desired result.
253 */
254 const char *fname;
255
256 /**
257 * Where to store actual size of the result.
258 */
259 size_t *result_size;
260
261};
262
263
264/**
265 * End of result parameter specification.
266 *
267 * @return array last entry for the result specification to use
268 */
269#define GNUNET_PQ_result_spec_end { NULL, NULL, NULL, NULL, 0, NULL, NULL }
270
271
272/**
273 * Variable-size result expected.
274 *
275 * @param name name of the field in the table
276 * @param[out] dst where to store the result, allocated
277 * @param[out] sptr where to store the size of @a dst
278 * @return array entry for the result specification to use
279 */
280struct GNUNET_PQ_ResultSpec
281GNUNET_PQ_result_spec_variable_size (const char *name,
282 void **dst,
283 size_t *sptr);
284
285
286/**
287 * Fixed-size result expected.
288 *
289 * @param name name of the field in the table
290 * @param[out] dst where to store the result
291 * @param dst_size number of bytes in @a dst
292 * @return array entry for the result specification to use
293 */
294struct GNUNET_PQ_ResultSpec
295GNUNET_PQ_result_spec_fixed_size (const char *name,
296 void *dst,
297 size_t dst_size);
298
299
300
301/**
302 * We expect a fixed-size result, with size determined by the type of `* dst`
303 *
304 * @param name name of the field in the table
305 * @param dst point to where to store the result, type fits expected result size
306 * @return array entry for the result specification to use
307 */
308#define GNUNET_PQ_result_spec_auto_from_type(name, dst) GNUNET_PQ_result_spec_fixed_size (name, (dst), sizeof (*(dst)))
309
310
311/**
312 * Variable-size result expected.
313 *
314 * @param name name of the field in the table
315 * @param[out] dst where to store the result, allocated
316 * @param[out] sptr where to store the size of @a dst
317 * @return array entry for the result specification to use
318 */
319struct GNUNET_PQ_ResultSpec
320GNUNET_PQ_result_spec_variable_size (const char *name,
321 void **dst,
322 size_t *sptr);
323
324
325/**
326 * RSA public key expected.
327 *
328 * @param name name of the field in the table
329 * @param[out] rsa where to store the result
330 * @return array entry for the result specification to use
331 */
332struct GNUNET_PQ_ResultSpec
333GNUNET_PQ_result_spec_rsa_public_key (const char *name,
334 struct GNUNET_CRYPTO_rsa_PublicKey **rsa);
335
336
337/**
338 * RSA signature expected.
339 *
340 * @param name name of the field in the table
341 * @param[out] sig where to store the result;
342 * @return array entry for the result specification to use
343 */
344struct GNUNET_PQ_ResultSpec
345GNUNET_PQ_result_spec_rsa_signature (const char *name,
346 struct GNUNET_CRYPTO_rsa_Signature **sig);
347
348
349/**
350 * Absolute time expected.
351 *
352 * @param name name of the field in the table
353 * @param[out] at where to store the result
354 * @return array entry for the result specification to use
355 */
356struct GNUNET_PQ_ResultSpec
357GNUNET_PQ_result_spec_absolute_time (const char *name,
358 struct GNUNET_TIME_Absolute *at);
359
360
361/**
362 * Absolute time expected.
363 *
364 * @param name name of the field in the table
365 * @param[out] at where to store the result
366 * @return array entry for the result specification to use
367 */
368struct GNUNET_PQ_ResultSpec
369GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
370 struct GNUNET_TIME_AbsoluteNBO *at);
371
372
373/**
374 * uint16_t expected.
375 *
376 * @param name name of the field in the table
377 * @param[out] u16 where to store the result
378 * @return array entry for the result specification to use
379 */
380struct GNUNET_PQ_ResultSpec
381GNUNET_PQ_result_spec_uint16 (const char *name,
382 uint16_t *u16);
383
384
385/**
386 * uint32_t expected.
387 *
388 * @param name name of the field in the table
389 * @param[out] u32 where to store the result
390 * @return array entry for the result specification to use
391 */
392struct GNUNET_PQ_ResultSpec
393GNUNET_PQ_result_spec_uint32 (const char *name,
394 uint32_t *u32);
395
396
397/**
398 * uint64_t expected.
399 *
400 * @param name name of the field in the table
401 * @param[out] u64 where to store the result
402 * @return array entry for the result specification to use
403 */
404struct GNUNET_PQ_ResultSpec
405GNUNET_PQ_result_spec_uint64 (const char *name,
406 uint64_t *u64);
407
408
409/**
410 * Execute a prepared statement.
411 *
412 * @param db_conn database connection
413 * @param name name of the prepared statement
414 * @param params parameters to the statement
415 * @return postgres result
416 */
417PGresult *
418GNUNET_PQ_exec_prepared (PGconn *db_conn,
419 const char *name,
420 const struct GNUNET_PQ_QueryParam *params);
421
422
423/**
424 * Extract results from a query result according to the given specification.
425 * If colums are NULL, the destination is not modified, and #GNUNET_NO
426 * is returned.
427 *
428 * @param result result to process
429 * @param[in,out] rs result specification to extract for
430 * @param row row from the result to extract
431 * @return
432 * #GNUNET_YES if all results could be extracted
433 * #GNUNET_NO if at least one result was NULL
434 * #GNUNET_SYSERR if a result was invalid (non-existing field)
435 */
436int
437GNUNET_PQ_extract_result (PGresult *result,
438 struct GNUNET_PQ_ResultSpec *rs,
439 int row);
440
441
442/**
443 * Free all memory that was allocated in @a rs during
444 * #GNUNET_PQ_extract_result().
445 *
446 * @param rs reult specification to clean up
447 */
448void
449GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs);
450
451
452#endif /* GNUNET_PQ_LIB_H_ */
453
454/* end of include/gnunet_pq_lib.h */
diff --git a/src/postgres/postgres.c b/src/postgres/postgres.c
index c03e312a5..856031d75 100644
--- a/src/postgres/postgres.c
+++ b/src/postgres/postgres.c
@@ -38,12 +38,16 @@
38 * @param args arguments given to the command 38 * @param args arguments given to the command
39 * @param filename name of the source file where the command was run 39 * @param filename name of the source file where the command was run
40 * @param line line number in the source file 40 * @param line line number in the source file
41 * @return GNUNET_OK if the result is acceptable 41 * @return #GNUNET_OK if the result is acceptable
42 */ 42 */
43int 43int
44GNUNET_POSTGRES_check_result_ (PGconn * dbh, PGresult * ret, 44GNUNET_POSTGRES_check_result_ (PGconn *dbh,
45 int expected_status, const char *command, 45 PGresult *ret,
46 const char *args, const char *filename, int line) 46 int expected_status,
47 const char *command,
48 const char *args,
49 const char *filename,
50 int line)
47{ 51{
48 if (ret == NULL) 52 if (ret == NULL)
49 { 53 {
@@ -72,10 +76,12 @@ GNUNET_POSTGRES_check_result_ (PGconn * dbh, PGresult * ret,
72 * @param sql statement to run 76 * @param sql statement to run
73 * @param filename filename for error reporting 77 * @param filename filename for error reporting
74 * @param line code line for error reporting 78 * @param line code line for error reporting
75 * @return GNUNET_OK on success 79 * @return #GNUNET_OK on success
76 */ 80 */
77int 81int
78GNUNET_POSTGRES_exec_ (PGconn * dbh, const char *sql, const char *filename, 82GNUNET_POSTGRES_exec_ (PGconn * dbh,
83 const char *sql,
84 const char *filename,
79 int line) 85 int line)
80{ 86{
81 PGresult *ret; 87 PGresult *ret;
@@ -99,18 +105,30 @@ GNUNET_POSTGRES_exec_ (PGconn * dbh, const char *sql, const char *filename,
99 * @param nparams number of parameters in sql 105 * @param nparams number of parameters in sql
100 * @param filename filename for error reporting 106 * @param filename filename for error reporting
101 * @param line code line for error reporting 107 * @param line code line for error reporting
102 * @return GNUNET_OK on success 108 * @return #GNUNET_OK on success
103 */ 109 */
104int 110int
105GNUNET_POSTGRES_prepare_ (PGconn * dbh, const char *name, const char *sql, 111GNUNET_POSTGRES_prepare_ (PGconn *dbh,
106 int nparams, const char *filename, int line) 112 const char *name,
113 const char *sql,
114 int nparams,
115 const char *filename,
116 int line)
107{ 117{
108 PGresult *ret; 118 PGresult *ret;
109 119
110 ret = PQprepare (dbh, name, sql, nparams, NULL); 120 ret = PQprepare (dbh,
121 name,
122 sql,
123 nparams, NULL);
111 if (GNUNET_OK != 124 if (GNUNET_OK !=
112 GNUNET_POSTGRES_check_result_ (dbh, ret, PGRES_COMMAND_OK, "PQprepare", 125 GNUNET_POSTGRES_check_result_ (dbh,
113 sql, filename, line)) 126 ret,
127 PGRES_COMMAND_OK,
128 "PQprepare",
129 sql,
130 filename,
131 line))
114 return GNUNET_SYSERR; 132 return GNUNET_SYSERR;
115 PQclear (ret); 133 PQclear (ret);
116 return GNUNET_OK; 134 return GNUNET_OK;
@@ -161,10 +179,12 @@ GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle * cfg,
161 * @param dbh database handle 179 * @param dbh database handle
162 * @param stmt name of the prepared statement 180 * @param stmt name of the prepared statement
163 * @param rowid which row to delete 181 * @param rowid which row to delete
164 * @return GNUNET_OK on success 182 * @return #GNUNET_OK on success
165 */ 183 */
166int 184int
167GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh, const char *stmt, uint32_t rowid) 185GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh,
186 const char *stmt,
187 uint32_t rowid)
168{ 188{
169 uint32_t brow = htonl (rowid); 189 uint32_t brow = htonl (rowid);
170 const char *paramValues[] = { (const char *) &brow }; 190 const char *paramValues[] = { (const char *) &brow };
@@ -173,10 +193,17 @@ GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh, const char *stmt, uint32_t rowid)
173 PGresult *ret; 193 PGresult *ret;
174 194
175 ret = 195 ret =
176 PQexecPrepared (dbh, stmt, 1, paramValues, paramLengths, paramFormats, 1); 196 PQexecPrepared (dbh, stmt, 1,
197 paramValues,
198 paramLengths,
199 paramFormats,
200 1);
177 if (GNUNET_OK != 201 if (GNUNET_OK !=
178 GNUNET_POSTGRES_check_result_ (dbh, ret, PGRES_COMMAND_OK, 202 GNUNET_POSTGRES_check_result_ (dbh, ret,
179 "PQexecPrepared", "delrow", __FILE__, 203 PGRES_COMMAND_OK,
204 "PQexecPrepared",
205 "delrow",
206 __FILE__,
180 __LINE__)) 207 __LINE__))
181 { 208 {
182 return GNUNET_SYSERR; 209 return GNUNET_SYSERR;
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am
new file mode 100644
index 000000000..66f57838e
--- /dev/null
+++ b/src/pq/Makefile.am
@@ -0,0 +1,39 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
3
4if MINGW
5 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
6endif
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage
10endif
11
12if HAVE_POSTGRESQL
13lib_LTLIBRARIES = libgnunetpq.la
14endif
15
16libgnunetpq_la_SOURCES = \
17 pq.c \
18 pq_query_helper.c \
19 pq_result_helper.c
20libgnunetpq_la_LIBADD = -lpq \
21 $(top_builddir)/src/util/libgnunetutil.la
22libgnunetpq_la_LDFLAGS = \
23 $(POSTGRESQL_LDFLAGS) \
24 $(GN_LIB_LDFLAGS) \
25 -version-info 0:0:0
26
27
28TESTS = \
29 test_pq
30
31check_PROGRAMS= \
32 test_pq
33
34test_pq_SOURCES = \
35 test_pq.c
36test_pq_LDADD = \
37 libgnunetpq.la \
38 $(top_builddir)/src/util/libgnunetutil.la \
39 -lpq $(XLIB)
diff --git a/src/pq/pq.c b/src/pq/pq.c
new file mode 100644
index 000000000..fe796044e
--- /dev/null
+++ b/src/pq/pq.c
@@ -0,0 +1,169 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq.c
18 * @brief helper functions for libpq (PostGres) interactions
19 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
20 * @author Florian Dold
21 * @author Christian Grothoff
22 */
23#include "platform.h"
24#include <gnunet/gnunet_util_lib.h>
25#include "gnunet_pq_lib.h"
26
27
28/**
29 * Execute a prepared statement.
30 *
31 * @param db_conn database connection
32 * @param name name of the prepared statement
33 * @param params parameters to the statement
34 * @return postgres result
35 */
36PGresult *
37GNUNET_PQ_exec_prepared (PGconn *db_conn,
38 const char *name,
39 const struct GNUNET_PQ_QueryParam *params)
40{
41 unsigned int len;
42 unsigned int i;
43
44 /* count the number of parameters */
45 len = 0;
46 for (i=0;0 != params[i].num_params;i++)
47 len += params[i].num_params;
48
49 /* new scope to allow stack allocation without alloca */
50 {
51 /* Scratch buffer for temporary storage */
52 void *scratch[len];
53 /* Parameter array we are building for the query */
54 void *param_values[len];
55 int param_lengths[len];
56 int param_formats[len];
57 unsigned int off;
58 /* How many entries in the scratch buffer are in use? */
59 unsigned int soff;
60 PGresult *res;
61 int ret;
62
63 off = 0;
64 soff = 0;
65 for (i=0;0 != params[i].num_params;i++)
66 {
67 const struct GNUNET_PQ_QueryParam *x = &params[i];
68
69 ret = x->conv (x->conv_cls,
70 x->data,
71 x->size,
72 &param_values[off],
73 &param_lengths[off],
74 &param_formats[off],
75 x->num_params,
76 &scratch[soff],
77 len - soff);
78 if (ret < 0)
79 {
80 for (off = 0; off < soff; off++)
81 GNUNET_free (scratch[off]);
82 return NULL;
83 }
84 soff += ret;
85 off += x->num_params;
86 }
87 GNUNET_assert (off == len);
88 res = PQexecPrepared (db_conn,
89 name,
90 len,
91 (const char **) param_values,
92 param_lengths,
93 param_formats,
94 1);
95 for (off = 0; off < soff; off++)
96 GNUNET_free (scratch[off]);
97 return res;
98 }
99}
100
101
102/**
103 * Free all memory that was allocated in @a rs during
104 * #GNUNET_PQ_extract_result().
105 *
106 * @param rs reult specification to clean up
107 */
108void
109GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs)
110{
111 unsigned int i;
112
113 for (i=0; NULL != rs[i].conv; i++)
114 if (NULL != rs[i].cleaner)
115 rs[i].cleaner (rs[i].cls,
116 rs[i].dst);
117}
118
119
120/**
121 * Extract results from a query result according to the given
122 * specification. If colums are NULL, the destination is not
123 * modified, and #GNUNET_NO is returned.
124 *
125 * @param result result to process
126 * @param[in,out] rs result specification to extract for
127 * @param row row from the result to extract
128 * @return
129 * #GNUNET_YES if all results could be extracted
130 * #GNUNET_NO if at least one result was NULL
131 * #GNUNET_SYSERR if a result was invalid (non-existing field)
132 */
133int
134GNUNET_PQ_extract_result (PGresult *result,
135 struct GNUNET_PQ_ResultSpec *rs,
136 int row)
137{
138 unsigned int i;
139 int had_null = GNUNET_NO;
140 int ret;
141
142 for (i=0; NULL != rs[i].conv; i++)
143 {
144 struct GNUNET_PQ_ResultSpec *spec;
145
146 spec = &rs[i];
147 ret = spec->conv (spec->cls,
148 result,
149 row,
150 spec->fname,
151 &spec->dst_size,
152 spec->dst);
153 if (GNUNET_SYSERR == ret)
154 return GNUNET_SYSERR;
155 if (GNUNET_NO == ret)
156 {
157 had_null = GNUNET_YES;
158 continue;
159 }
160 if (NULL != spec->result_size)
161 *spec->result_size = spec->dst_size;
162 }
163 if (GNUNET_YES == had_null)
164 return GNUNET_NO;
165 return GNUNET_OK;
166}
167
168
169/* end of pq/pq.c */
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
new file mode 100644
index 000000000..5f2764b62
--- /dev/null
+++ b/src/pq/pq_query_helper.c
@@ -0,0 +1,386 @@
1 /*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq_query_helper.c
18 * @brief functions to initialize parameter arrays
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include <gnunet/gnunet_util_lib.h>
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Function called to convert input argument into SQL parameters.
28 *
29 * @param cls closure
30 * @param data pointer to input argument
31 * @param data_len number of bytes in @a data (if applicable)
32 * @param[out] param_values SQL data to set
33 * @param[out] param_lengths SQL length data to set
34 * @param[out] param_formats SQL format data to set
35 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
36 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
37 * @param scratch_length number of entries left in @a scratch
38 * @return -1 on error, number of offsets used in @a scratch otherwise
39 */
40static int
41qconv_fixed (void *cls,
42 const void *data,
43 size_t data_len,
44 void *param_values[],
45 int param_lengths[],
46 int param_formats[],
47 unsigned int param_length,
48 void *scratch[],
49 unsigned int scratch_length)
50{
51 GNUNET_break (NULL == cls);
52 if (1 != param_length)
53 return -1;
54 param_values[0] = (void *) data;
55 param_lengths[0] = data_len;
56 param_formats[0] = 1;
57 return 0;
58}
59
60
61/**
62 * Generate query parameter for a buffer @a ptr of
63 * @a ptr_size bytes.
64 *
65 * @param ptr pointer to the query parameter to pass
66 * @oaran ptr_size number of bytes in @a ptr
67 */
68struct GNUNET_PQ_QueryParam
69GNUNET_PQ_query_param_fixed_size (const void *ptr,
70 size_t ptr_size)
71{
72 struct GNUNET_PQ_QueryParam res =
73 { &qconv_fixed, NULL, ptr, ptr_size, 1 };
74 return res;
75}
76
77
78/**
79 * Function called to convert input argument into SQL parameters.
80 *
81 * @param cls closure
82 * @param data pointer to input argument
83 * @param data_len number of bytes in @a data (if applicable)
84 * @param[out] param_values SQL data to set
85 * @param[out] param_lengths SQL length data to set
86 * @param[out] param_formats SQL format data to set
87 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
88 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
89 * @param scratch_length number of entries left in @a scratch
90 * @return -1 on error, number of offsets used in @a scratch otherwise
91 */
92static int
93qconv_uint16 (void *cls,
94 const void *data,
95 size_t data_len,
96 void *param_values[],
97 int param_lengths[],
98 int param_formats[],
99 unsigned int param_length,
100 void *scratch[],
101 unsigned int scratch_length)
102{
103 const uint16_t *u_hbo = data;
104 uint16_t *u_nbo;
105
106 GNUNET_break (NULL == cls);
107 if (1 != param_length)
108 return -1;
109 u_nbo = GNUNET_new (uint16_t);
110 scratch[0] = u_nbo;
111 *u_nbo = htons (*u_hbo);
112 param_values[0] = (void *) u_nbo;
113 param_lengths[0] = sizeof (uint16_t);
114 param_formats[0] = 1;
115 return 1;
116}
117
118
119/**
120 * Generate query parameter for an uint16_t in host byte order.
121 *
122 * @param x pointer to the query parameter to pass
123 */
124struct GNUNET_PQ_QueryParam
125GNUNET_PQ_query_param_uint16 (const uint16_t *x)
126{
127 struct GNUNET_PQ_QueryParam res =
128 { &qconv_uint16, NULL, x, sizeof (*x), 1 };
129 return res;
130}
131
132
133/**
134 * Function called to convert input argument into SQL parameters.
135 *
136 * @param cls closure
137 * @param data pointer to input argument
138 * @param data_len number of bytes in @a data (if applicable)
139 * @param[out] param_values SQL data to set
140 * @param[out] param_lengths SQL length data to set
141 * @param[out] param_formats SQL format data to set
142 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
143 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
144 * @param scratch_length number of entries left in @a scratch
145 * @return -1 on error, number of offsets used in @a scratch otherwise
146 */
147static int
148qconv_uint32 (void *cls,
149 const void *data,
150 size_t data_len,
151 void *param_values[],
152 int param_lengths[],
153 int param_formats[],
154 unsigned int param_length,
155 void *scratch[],
156 unsigned int scratch_length)
157{
158 const uint32_t *u_hbo = data;
159 uint32_t *u_nbo;
160
161 GNUNET_break (NULL == cls);
162 if (1 != param_length)
163 return -1;
164 u_nbo = GNUNET_new (uint32_t);
165 scratch[0] = u_nbo;
166 *u_nbo = htonl (*u_hbo);
167 param_values[0] = (void *) u_nbo;
168 param_lengths[0] = sizeof (uint32_t);
169 param_formats[0] = 1;
170 return 1;
171}
172
173
174/**
175 * Generate query parameter for an uint32_t in host byte order.
176 *
177 * @param x pointer to the query parameter to pass
178 */
179struct GNUNET_PQ_QueryParam
180GNUNET_PQ_query_param_uint32 (const uint32_t *x)
181{
182 struct GNUNET_PQ_QueryParam res =
183 { &qconv_uint32, NULL, x, sizeof (*x), 1 };
184 return res;
185}
186
187
188/**
189 * Function called to convert input argument into SQL parameters.
190 *
191 * @param cls closure
192 * @param data pointer to input argument
193 * @param data_len number of bytes in @a data (if applicable)
194 * @param[out] param_values SQL data to set
195 * @param[out] param_lengths SQL length data to set
196 * @param[out] param_formats SQL format data to set
197 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
198 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
199 * @param scratch_length number of entries left in @a scratch
200 * @return -1 on error, number of offsets used in @a scratch otherwise
201 */
202static int
203qconv_uint64 (void *cls,
204 const void *data,
205 size_t data_len,
206 void *param_values[],
207 int param_lengths[],
208 int param_formats[],
209 unsigned int param_length,
210 void *scratch[],
211 unsigned int scratch_length)
212{
213 const uint64_t *u_hbo = data;
214 uint64_t *u_nbo;
215
216 GNUNET_break (NULL == cls);
217 if (1 != param_length)
218 return -1;
219 u_nbo = GNUNET_new (uint64_t);
220 scratch[0] = u_nbo;
221 *u_nbo = GNUNET_htonll (*u_hbo);
222 param_values[0] = (void *) u_nbo;
223 param_lengths[0] = sizeof (uint64_t);
224 param_formats[0] = 1;
225 return 1;
226}
227
228
229/**
230 * Generate query parameter for an uint64_t in host byte order.
231 *
232 * @param x pointer to the query parameter to pass
233 */
234struct GNUNET_PQ_QueryParam
235GNUNET_PQ_query_param_uint64 (const uint64_t *x)
236{
237 struct GNUNET_PQ_QueryParam res =
238 { &qconv_uint64, NULL, x, sizeof (*x), 1 };
239 return res;
240}
241
242
243/**
244 * Function called to convert input argument into SQL parameters.
245 *
246 * @param cls closure
247 * @param data pointer to input argument
248 * @param data_len number of bytes in @a data (if applicable)
249 * @param[out] param_values SQL data to set
250 * @param[out] param_lengths SQL length data to set
251 * @param[out] param_formats SQL format data to set
252 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
253 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
254 * @param scratch_length number of entries left in @a scratch
255 * @return -1 on error, number of offsets used in @a scratch otherwise
256 */
257static int
258qconv_rsa_public_key (void *cls,
259 const void *data,
260 size_t data_len,
261 void *param_values[],
262 int param_lengths[],
263 int param_formats[],
264 unsigned int param_length,
265 void *scratch[],
266 unsigned int scratch_length)
267{
268 const struct GNUNET_CRYPTO_rsa_PublicKey *rsa = data;
269 char *buf;
270 size_t buf_size;
271
272 GNUNET_break (NULL == cls);
273 if (1 != param_length)
274 return -1;
275 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rsa,
276 &buf);
277 scratch[0] = buf;
278 param_values[0] = (void *) buf;
279 param_lengths[0] = buf_size - 1; /* DB doesn't like the trailing \0 */
280 param_formats[0] = 1;
281 return 1;
282}
283
284
285/**
286 * Generate query parameter for an RSA public key. The
287 * database must contain a BLOB type in the respective position.
288 *
289 * @param x the query parameter to pass
290 * @return array entry for the query parameters to use
291 */
292struct GNUNET_PQ_QueryParam
293GNUNET_PQ_query_param_rsa_public_key (const struct GNUNET_CRYPTO_rsa_PublicKey *x)
294{
295 struct GNUNET_PQ_QueryParam res =
296 { &qconv_rsa_public_key, NULL, (x), 0, 1 };
297 return res;
298}
299
300
301/**
302 * Function called to convert input argument into SQL parameters.
303 *
304 * @param cls closure
305 * @param data pointer to input argument
306 * @param data_len number of bytes in @a data (if applicable)
307 * @param[out] param_values SQL data to set
308 * @param[out] param_lengths SQL length data to set
309 * @param[out] param_formats SQL format data to set
310 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
311 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
312 * @param scratch_length number of entries left in @a scratch
313 * @return -1 on error, number of offsets used in @a scratch otherwise
314 */
315static int
316qconv_rsa_signature (void *cls,
317 const void *data,
318 size_t data_len,
319 void *param_values[],
320 int param_lengths[],
321 int param_formats[],
322 unsigned int param_length,
323 void *scratch[],
324 unsigned int scratch_length)
325{
326 const struct GNUNET_CRYPTO_rsa_Signature *sig = data;
327 char *buf;
328 size_t buf_size;
329
330 GNUNET_break (NULL == cls);
331 if (1 != param_length)
332 return -1;
333 buf_size = GNUNET_CRYPTO_rsa_signature_encode (sig,
334 &buf);
335 scratch[0] = buf;
336 param_values[0] = (void *) buf;
337 param_lengths[0] = buf_size - 1; /* DB doesn't like the trailing \0 */
338 param_formats[0] = 1;
339 return 1;
340}
341
342
343/**
344 * Generate query parameter for an RSA signature. The
345 * database must contain a BLOB type in the respective position.
346 *
347 * @param x the query parameter to pass
348 * @return array entry for the query parameters to use
349 */
350struct GNUNET_PQ_QueryParam
351GNUNET_PQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_rsa_Signature *x)
352{
353 struct GNUNET_PQ_QueryParam res =
354 { &qconv_rsa_signature, NULL, (x), 0, 1 };
355 return res;
356}
357
358
359/**
360 * Generate query parameter for an absolute time value.
361 * The database must store a 64-bit integer.
362 *
363 * @param x pointer to the query parameter to pass
364 * @return array entry for the query parameters to use
365 */
366struct GNUNET_PQ_QueryParam
367GNUNET_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
368{
369 return GNUNET_PQ_query_param_uint64 (&x->abs_value_us);
370}
371
372
373/**
374 * Generate query parameter for an absolute time value.
375 * The database must store a 64-bit integer.
376 *
377 * @param x pointer to the query parameter to pass
378 */
379struct GNUNET_PQ_QueryParam
380GNUNET_PQ_query_param_absolute_time_nbo(const struct GNUNET_TIME_AbsoluteNBO *x)
381{
382 return GNUNET_PQ_query_param_auto_from_type (&x->abs_value_us__);
383}
384
385
386/* end of pq_query_helper.c */
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
new file mode 100644
index 000000000..dc5700730
--- /dev/null
+++ b/src/pq/pq_result_helper.c
@@ -0,0 +1,674 @@
1 /*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq_result_helper.c
18 * @brief functions to extract result values
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include <gnunet/gnunet_util_lib.h>
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Function called to clean up memory allocated
28 * by a #GNUNET_PQ_ResultConverter.
29 *
30 * @param cls closure
31 * @param rd result data to clean up
32 */
33static void
34clean_varsize_blob (void *cls,
35 void *rd)
36{
37 void **dst = rd;
38
39 if (NULL != *dst)
40 {
41 GNUNET_free (*dst);
42 *dst = NULL;
43 }
44}
45
46
47/**
48 * Extract data from a Postgres database @a result at row @a row.
49 *
50 * @param cls closure
51 * @param result where to extract data from
52 * @param int row to extract data from
53 * @param fname name (or prefix) of the fields to extract from
54 * @param[in,out] dst_size where to store size of result, may be NULL
55 * @param[out] dst where to store the result
56 * @return
57 * #GNUNET_YES if all results could be extracted
58 * #GNUNET_NO if at least one result was NULL
59 * #GNUNET_SYSERR if a result was invalid (non-existing field)
60 */
61static int
62extract_varsize_blob (void *cls,
63 PGresult *result,
64 int row,
65 const char *fname,
66 size_t *dst_size,
67 void *dst)
68{
69 size_t len;
70 const char *res;
71 void *idst;
72 int fnum;
73
74 fnum = PQfnumber (result,
75 fname);
76 if (fnum < 0)
77 {
78 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
79 "Field `%s' does not exist in result\n",
80 fname);
81 return GNUNET_SYSERR;
82 }
83 if (PQgetisnull (result,
84 row,
85 fnum))
86 return GNUNET_NO;
87
88 /* if a field is null, continue but
89 * remember that we now return a different result */
90 len = PQgetlength (result,
91 row,
92 fnum);
93 res = PQgetvalue (result,
94 row,
95 fnum);
96 GNUNET_assert (NULL != res);
97 *dst_size = len;
98 idst = GNUNET_malloc (len);
99 *((void **) dst) = idst;
100 memcpy (idst,
101 res,
102 len);
103 return GNUNET_OK;
104}
105
106
107/**
108 * Variable-size result expected.
109 *
110 * @param name name of the field in the table
111 * @param[out] dst where to store the result, allocated
112 * @param[out] sptr where to store the size of @a dst
113 * @return array entry for the result specification to use
114 */
115struct GNUNET_PQ_ResultSpec
116GNUNET_PQ_result_spec_variable_size (const char *name,
117 void **dst,
118 size_t *sptr)
119{
120 struct GNUNET_PQ_ResultSpec res =
121 { &extract_varsize_blob,
122 &clean_varsize_blob, NULL,
123 (void *) (dst), 0, name, sptr };
124 return res;
125}
126
127
128/**
129 * Extract data from a Postgres database @a result at row @a row.
130 *
131 * @param cls closure
132 * @param result where to extract data from
133 * @param int row to extract data from
134 * @param fname name (or prefix) of the fields to extract from
135 * @param[in] dst_size desired size, never NULL
136 * @param[out] dst where to store the result
137 * @return
138 * #GNUNET_YES if all results could be extracted
139 * #GNUNET_NO if at least one result was NULL
140 * #GNUNET_SYSERR if a result was invalid (non-existing field)
141 */
142static int
143extract_fixed_blob (void *cls,
144 PGresult *result,
145 int row,
146 const char *fname,
147 size_t *dst_size,
148 void *dst)
149{
150 size_t len;
151 const char *res;
152 int fnum;
153
154 fnum = PQfnumber (result,
155 fname);
156 if (fnum < 0)
157 {
158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
159 "Field `%s' does not exist in result\n",
160 fname);
161 return GNUNET_SYSERR;
162 }
163 if (PQgetisnull (result,
164 row,
165 fnum))
166 return GNUNET_NO;
167
168 /* if a field is null, continue but
169 * remember that we now return a different result */
170 len = PQgetlength (result,
171 row,
172 fnum);
173 if (*dst_size != len)
174 {
175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
176 "Field `%s' has wrong size (got %u, expected %u)\n",
177 fname,
178 (unsigned int) len,
179 (unsigned int) *dst_size);
180 return GNUNET_SYSERR;
181 }
182 res = PQgetvalue (result,
183 row,
184 fnum);
185 GNUNET_assert (NULL != res);
186 memcpy (dst,
187 res,
188 len);
189 return GNUNET_OK;
190}
191
192
193/**
194 * Fixed-size result expected.
195 *
196 * @param name name of the field in the table
197 * @param[out] dst where to store the result
198 * @param dst_size number of bytes in @a dst
199 * @return array entry for the result specification to use
200 */
201struct GNUNET_PQ_ResultSpec
202GNUNET_PQ_result_spec_fixed_size (const char *name,
203 void *dst,
204 size_t dst_size)
205{
206 struct GNUNET_PQ_ResultSpec res =
207 { &extract_fixed_blob,
208 NULL, NULL,
209 (dst), dst_size, name, NULL };
210 return res;
211}
212
213
214/**
215 * Extract data from a Postgres database @a result at row @a row.
216 *
217 * @param cls closure
218 * @param result where to extract data from
219 * @param int row to extract data from
220 * @param fname name (or prefix) of the fields to extract from
221 * @param[in,out] dst_size where to store size of result, may be NULL
222 * @param[out] dst where to store the result
223 * @return
224 * #GNUNET_YES if all results could be extracted
225 * #GNUNET_NO if at least one result was NULL
226 * #GNUNET_SYSERR if a result was invalid (non-existing field)
227 */
228static int
229extract_rsa_public_key (void *cls,
230 PGresult *result,
231 int row,
232 const char *fname,
233 size_t *dst_size,
234 void *dst)
235{
236 struct GNUNET_CRYPTO_rsa_PublicKey **pk = dst;
237 size_t len;
238 const char *res;
239 int fnum;
240
241 *pk = NULL;
242 fnum = PQfnumber (result,
243 fname);
244 if (fnum < 0)
245 {
246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
247 "Field `%s' does not exist in result\n",
248 fname);
249 return GNUNET_SYSERR;
250 }
251 if (PQgetisnull (result,
252 row,
253 fnum))
254 return GNUNET_NO;
255
256 /* if a field is null, continue but
257 * remember that we now return a different result */
258 len = PQgetlength (result,
259 row,
260 fnum);
261 res = PQgetvalue (result,
262 row,
263 fnum);
264 *pk = GNUNET_CRYPTO_rsa_public_key_decode (res,
265 len);
266 if (NULL == *pk)
267 {
268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
269 "Field `%s' contains bogus value (fails to decode)\n",
270 fname);
271 return GNUNET_SYSERR;
272 }
273 return GNUNET_OK;
274}
275
276
277/**
278 * Function called to clean up memory allocated
279 * by a #GNUNET_PQ_ResultConverter.
280 *
281 * @param cls closure
282 * @param rd result data to clean up
283 */
284static void
285clean_rsa_public_key (void *cls,
286 void *rd)
287{
288 struct GNUNET_CRYPTO_rsa_PublicKey **pk = rd;
289
290 if (NULL != *pk)
291 {
292 GNUNET_CRYPTO_rsa_public_key_free (*pk);
293 *pk = NULL;
294 }
295}
296
297
298/**
299 * RSA public key expected.
300 *
301 * @param name name of the field in the table
302 * @param[out] rsa where to store the result
303 * @return array entry for the result specification to use
304 */
305struct GNUNET_PQ_ResultSpec
306GNUNET_PQ_result_spec_rsa_public_key (const char *name,
307 struct GNUNET_CRYPTO_rsa_PublicKey **rsa)
308{
309 struct GNUNET_PQ_ResultSpec res =
310 { &extract_rsa_public_key,
311 &clean_rsa_public_key,
312 NULL,
313 (void *) rsa, 0, name, NULL };
314 return res;
315}
316
317
318/**
319 * Extract data from a Postgres database @a result at row @a row.
320 *
321 * @param cls closure
322 * @param result where to extract data from
323 * @param int row to extract data from
324 * @param fname name (or prefix) of the fields to extract from
325 * @param[in,out] dst_size where to store size of result, may be NULL
326 * @param[out] dst where to store the result
327 * @return
328 * #GNUNET_YES if all results could be extracted
329 * #GNUNET_NO if at least one result was NULL
330 * #GNUNET_SYSERR if a result was invalid (non-existing field)
331 */
332static int
333extract_rsa_signature (void *cls,
334 PGresult *result,
335 int row,
336 const char *fname,
337 size_t *dst_size,
338 void *dst)
339{
340 struct GNUNET_CRYPTO_rsa_Signature **sig = dst;
341 size_t len;
342 const char *res;
343 int fnum;
344
345 *sig = NULL;
346 fnum = PQfnumber (result,
347 fname);
348 if (fnum < 0)
349 {
350 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
351 "Field `%s' does not exist in result\n",
352 fname);
353 return GNUNET_SYSERR;
354 }
355 if (PQgetisnull (result,
356 row,
357 fnum))
358 return GNUNET_NO;
359
360 /* if a field is null, continue but
361 * remember that we now return a different result */
362 len = PQgetlength (result,
363 row,
364 fnum);
365 res = PQgetvalue (result,
366 row,
367 fnum);
368 *sig = GNUNET_CRYPTO_rsa_signature_decode (res,
369 len);
370 if (NULL == *sig)
371 {
372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373 "Field `%s' contains bogus value (fails to decode)\n",
374 fname);
375 return GNUNET_SYSERR;
376 }
377 return GNUNET_OK;
378}
379
380
381/**
382 * Function called to clean up memory allocated
383 * by a #GNUNET_PQ_ResultConverter.
384 *
385 * @param cls closure
386 * @param rd result data to clean up
387 */
388static void
389clean_rsa_signature (void *cls,
390 void *rd)
391{
392 struct GNUNET_CRYPTO_rsa_Signature **sig = rd;
393
394 if (NULL != *sig)
395 {
396 GNUNET_CRYPTO_rsa_signature_free (*sig);
397 *sig = NULL;
398 }
399}
400
401
402/**
403 * RSA signature expected.
404 *
405 * @param name name of the field in the table
406 * @param[out] sig where to store the result;
407 * @return array entry for the result specification to use
408 */
409struct GNUNET_PQ_ResultSpec
410GNUNET_PQ_result_spec_rsa_signature (const char *name,
411 struct GNUNET_CRYPTO_rsa_Signature **sig)
412{
413 struct GNUNET_PQ_ResultSpec res =
414 { &extract_rsa_signature,
415 &clean_rsa_signature,
416 NULL,
417 (void *) sig, 0, (name), NULL };
418 return res;
419}
420
421
422/**
423 * Absolute time expected.
424 *
425 * @param name name of the field in the table
426 * @param[out] at where to store the result
427 * @return array entry for the result specification to use
428 */
429struct GNUNET_PQ_ResultSpec
430GNUNET_PQ_result_spec_absolute_time (const char *name,
431 struct GNUNET_TIME_Absolute *at)
432{
433 return GNUNET_PQ_result_spec_uint64 (name,
434 &at->abs_value_us);
435}
436
437
438/**
439 * Absolute time in network byte order expected.
440 *
441 * @param name name of the field in the table
442 * @param[out] at where to store the result
443 * @return array entry for the result specification to use
444 */
445struct GNUNET_PQ_ResultSpec
446GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
447 struct GNUNET_TIME_AbsoluteNBO *at)
448{
449 struct GNUNET_PQ_ResultSpec res =
450 GNUNET_PQ_result_spec_auto_from_type(name, &at->abs_value_us__);
451 return res;
452}
453
454
455/**
456 * Extract data from a Postgres database @a result at row @a row.
457 *
458 * @param cls closure
459 * @param result where to extract data from
460 * @param int row to extract data from
461 * @param fname name (or prefix) of the fields to extract from
462 * @param[in,out] dst_size where to store size of result, may be NULL
463 * @param[out] dst where to store the result
464 * @return
465 * #GNUNET_YES if all results could be extracted
466 * #GNUNET_NO if at least one result was NULL
467 * #GNUNET_SYSERR if a result was invalid (non-existing field)
468 */
469static int
470extract_uint16 (void *cls,
471 PGresult *result,
472 int row,
473 const char *fname,
474 size_t *dst_size,
475 void *dst)
476{
477 uint16_t *udst = dst;
478 const uint16_t *res;
479 int fnum;
480
481 fnum = PQfnumber (result,
482 fname);
483 if (fnum < 0)
484 {
485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
486 "Field `%s' does not exist in result\n",
487 fname);
488 return GNUNET_SYSERR;
489 }
490 if (PQgetisnull (result,
491 row,
492 fnum))
493 return GNUNET_NO;
494 GNUNET_assert (NULL != dst);
495 if (sizeof (uint16_t) != *dst_size)
496 {
497 GNUNET_break (0);
498 return GNUNET_SYSERR;
499 }
500 res = (uint16_t *) PQgetvalue (result,
501 row,
502 fnum);
503 *udst = ntohs (*res);
504 return GNUNET_OK;
505}
506
507
508/**
509 * uint16_t expected.
510 *
511 * @param name name of the field in the table
512 * @param[out] u16 where to store the result
513 * @return array entry for the result specification to use
514 */
515struct GNUNET_PQ_ResultSpec
516GNUNET_PQ_result_spec_uint16 (const char *name,
517 uint16_t *u16)
518{
519 struct GNUNET_PQ_ResultSpec res =
520 { &extract_uint16,
521 NULL,
522 NULL,
523 (void *) u16, sizeof (*u16), (name), NULL };
524 return res;
525}
526
527
528/**
529 * Extract data from a Postgres database @a result at row @a row.
530 *
531 * @param cls closure
532 * @param result where to extract data from
533 * @param int row to extract data from
534 * @param fname name (or prefix) of the fields to extract from
535 * @param[in,out] dst_size where to store size of result, may be NULL
536 * @param[out] dst where to store the result
537 * @return
538 * #GNUNET_YES if all results could be extracted
539 * #GNUNET_NO if at least one result was NULL
540 * #GNUNET_SYSERR if a result was invalid (non-existing field)
541 */
542static int
543extract_uint32 (void *cls,
544 PGresult *result,
545 int row,
546 const char *fname,
547 size_t *dst_size,
548 void *dst)
549{
550 uint32_t *udst = dst;
551 const uint32_t *res;
552 int fnum;
553
554 fnum = PQfnumber (result,
555 fname);
556 if (fnum < 0)
557 {
558 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559 "Field `%s' does not exist in result\n",
560 fname);
561 return GNUNET_SYSERR;
562 }
563 if (PQgetisnull (result,
564 row,
565 fnum))
566 return GNUNET_NO;
567 GNUNET_assert (NULL != dst);
568 if (sizeof (uint32_t) != *dst_size)
569 {
570 GNUNET_break (0);
571 return GNUNET_SYSERR;
572 }
573 res = (uint32_t *) PQgetvalue (result,
574 row,
575 fnum);
576 *udst = ntohl (*res);
577 return GNUNET_OK;
578}
579
580
581/**
582 * uint32_t expected.
583 *
584 * @param name name of the field in the table
585 * @param[out] u32 where to store the result
586 * @return array entry for the result specification to use
587 */
588struct GNUNET_PQ_ResultSpec
589GNUNET_PQ_result_spec_uint32 (const char *name,
590 uint32_t *u32)
591{
592 struct GNUNET_PQ_ResultSpec res =
593 { &extract_uint32,
594 NULL,
595 NULL,
596 (void *) u32, sizeof (*u32), (name), NULL };
597 return res;
598}
599
600
601/**
602 * Extract data from a Postgres database @a result at row @a row.
603 *
604 * @param cls closure
605 * @param result where to extract data from
606 * @param int row to extract data from
607 * @param fname name (or prefix) of the fields to extract from
608 * @param[in,out] dst_size where to store size of result, may be NULL
609 * @param[out] dst where to store the result
610 * @return
611 * #GNUNET_YES if all results could be extracted
612 * #GNUNET_NO if at least one result was NULL
613 * #GNUNET_SYSERR if a result was invalid (non-existing field)
614 */
615static int
616extract_uint64 (void *cls,
617 PGresult *result,
618 int row,
619 const char *fname,
620 size_t *dst_size,
621 void *dst)
622{
623 uint64_t *udst = dst;
624 const uint64_t *res;
625 int fnum;
626
627 fnum = PQfnumber (result,
628 fname);
629 if (fnum < 0)
630 {
631 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
632 "Field `%s' does not exist in result\n",
633 fname);
634 return GNUNET_SYSERR;
635 }
636 if (PQgetisnull (result,
637 row,
638 fnum))
639 return GNUNET_NO;
640 GNUNET_assert (NULL != dst);
641 if (sizeof (uint64_t) != *dst_size)
642 {
643 GNUNET_break (0);
644 return GNUNET_SYSERR;
645 }
646 res = (uint64_t *) PQgetvalue (result,
647 row,
648 fnum);
649 *udst = GNUNET_ntohll (*res);
650 return GNUNET_OK;
651}
652
653
654/**
655 * uint64_t expected.
656 *
657 * @param name name of the field in the table
658 * @param[out] u64 where to store the result
659 * @return array entry for the result specification to use
660 */
661struct GNUNET_PQ_ResultSpec
662GNUNET_PQ_result_spec_uint64 (const char *name,
663 uint64_t *u64)
664{
665 struct GNUNET_PQ_ResultSpec res =
666 { &extract_uint64,
667 NULL,
668 NULL,
669 (void *) u64, sizeof (*u64), (name), NULL };
670 return res;
671}
672
673
674/* end of pq_result_helper.c */
diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c
new file mode 100644
index 000000000..b9bf1be76
--- /dev/null
+++ b/src/pq/test_pq.c
@@ -0,0 +1,288 @@
1/*
2 This file is part of GNUnet
3 (C) 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/test_pq.c
18 * @brief Tests for Postgres convenience API
19 * @author Christian Grothoff <christian@grothoff.org>
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Setup prepared statements.
28 *
29 * @param db_conn connection handle to initialize
30 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
31 */
32static int
33postgres_prepare (PGconn *db_conn)
34{
35 PGresult *result;
36
37#define PREPARE(name, sql, ...) \
38 do { \
39 result = PQprepare (db_conn, name, sql, __VA_ARGS__); \
40 if (PGRES_COMMAND_OK != PQresultStatus (result)) \
41 { \
42 GNUNET_break (0); \
43 PQclear (result); result = NULL; \
44 return GNUNET_SYSERR; \
45 } \
46 PQclear (result); result = NULL; \
47 } while (0);
48
49 PREPARE ("test_insert",
50 "INSERT INTO test_pq ("
51 " pub"
52 ",sig"
53 ",abs_time"
54 ",forever"
55 ",hash"
56 ",vsize"
57 ",u16"
58 ",u32"
59 ",u64"
60 ") VALUES "
61 "($1, $2, $3, $4, $5, $6,"
62 "$7, $8, $9);",
63 9, NULL);
64 PREPARE ("test_select",
65 "SELECT"
66 " pub"
67 ",sig"
68 ",abs_time"
69 ",forever"
70 ",hash"
71 ",vsize"
72 ",u16"
73 ",u32"
74 ",u64"
75 " FROM test_pq"
76 " ORDER BY abs_time DESC "
77 " LIMIT 1;",
78 0, NULL);
79 return GNUNET_OK;
80#undef PREPARE
81}
82
83
84/**
85 * Run actual test queries.
86 *
87 * @return 0 on success
88 */
89static int
90run_queries (PGconn *conn)
91{
92 struct GNUNET_CRYPTO_rsa_PublicKey *pub;
93 struct GNUNET_CRYPTO_rsa_PublicKey *pub2 = NULL;
94 struct GNUNET_CRYPTO_rsa_Signature *sig;
95 struct GNUNET_CRYPTO_rsa_Signature *sig2 = NULL;
96 struct GNUNET_TIME_Absolute abs_time = GNUNET_TIME_absolute_get ();
97 struct GNUNET_TIME_Absolute abs_time2;
98 struct GNUNET_TIME_Absolute forever = GNUNET_TIME_UNIT_FOREVER_ABS;
99 struct GNUNET_TIME_Absolute forever2;
100 struct GNUNET_HashCode hc;
101 struct GNUNET_HashCode hc2;
102 PGresult *result;
103 int ret;
104 struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
105 char msg[] = "Hello";
106 void *msg2;
107 size_t msg2_len;
108 uint16_t u16;
109 uint16_t u162;
110 uint32_t u32;
111 uint32_t u322;
112 uint64_t u64;
113 uint64_t u642;
114
115 priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
116 pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
117 sig = GNUNET_CRYPTO_rsa_sign (priv,
118 msg,
119 sizeof (msg));
120 u16 = 16;
121 u32 = 32;
122 u64 = 64;
123 /* FIXME: test GNUNET_PQ_result_spec_variable_size */
124 {
125 struct GNUNET_PQ_QueryParam params_insert[] = {
126 GNUNET_PQ_query_param_rsa_public_key (pub),
127 GNUNET_PQ_query_param_rsa_signature (sig),
128 GNUNET_PQ_query_param_absolute_time (&abs_time),
129 GNUNET_PQ_query_param_absolute_time (&forever),
130 GNUNET_PQ_query_param_auto_from_type (&hc),
131 GNUNET_PQ_query_param_fixed_size (msg, strlen (msg)),
132 GNUNET_PQ_query_param_uint16 (&u16),
133 GNUNET_PQ_query_param_uint32 (&u32),
134 GNUNET_PQ_query_param_uint64 (&u64),
135 GNUNET_PQ_query_param_end
136 };
137 struct GNUNET_PQ_QueryParam params_select[] = {
138 GNUNET_PQ_query_param_end
139 };
140 struct GNUNET_PQ_ResultSpec results_select[] = {
141 GNUNET_PQ_result_spec_rsa_public_key ("pub", &pub2),
142 GNUNET_PQ_result_spec_rsa_signature ("sig", &sig2),
143 GNUNET_PQ_result_spec_absolute_time ("abs_time", &abs_time2),
144 GNUNET_PQ_result_spec_absolute_time ("forever", &forever2),
145 GNUNET_PQ_result_spec_auto_from_type ("hash", &hc2),
146 GNUNET_PQ_result_spec_variable_size ("vsize", &msg2, &msg2_len),
147 GNUNET_PQ_result_spec_uint16 ("u16", &u162),
148 GNUNET_PQ_result_spec_uint32 ("u32", &u322),
149 GNUNET_PQ_result_spec_uint64 ("u64", &u642),
150 GNUNET_PQ_result_spec_end
151 };
152
153 result = GNUNET_PQ_exec_prepared (conn,
154 "test_insert",
155 params_insert);
156 if (PGRES_COMMAND_OK != PQresultStatus (result))
157 {
158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
159 "Database failure: %s\n",
160 PQresultErrorMessage (result));
161 PQclear (result);
162 GNUNET_CRYPTO_rsa_signature_free (sig);
163 GNUNET_CRYPTO_rsa_private_key_free (priv);
164 GNUNET_CRYPTO_rsa_public_key_free (pub);
165 return 1;
166 }
167
168 PQclear (result);
169 result = GNUNET_PQ_exec_prepared (conn,
170 "test_select",
171 params_select);
172 if (1 !=
173 PQntuples (result))
174 {
175 GNUNET_break (0);
176 PQclear (result);
177 GNUNET_CRYPTO_rsa_signature_free (sig);
178 GNUNET_CRYPTO_rsa_private_key_free (priv);
179 GNUNET_CRYPTO_rsa_public_key_free (pub);
180 return 1;
181 }
182 ret = GNUNET_PQ_extract_result (result,
183 results_select,
184 0);
185 GNUNET_break (GNUNET_YES == ret);
186 GNUNET_break (abs_time.abs_value_us == abs_time2.abs_value_us);
187 GNUNET_break (forever.abs_value_us == forever2.abs_value_us);
188 GNUNET_break (0 ==
189 memcmp (&hc,
190 &hc2,
191 sizeof (struct GNUNET_HashCode)));
192 GNUNET_break (0 ==
193 GNUNET_CRYPTO_rsa_signature_cmp (sig,
194 sig2));
195 GNUNET_break (0 ==
196 GNUNET_CRYPTO_rsa_public_key_cmp (pub,
197 pub2));
198 GNUNET_break (strlen (msg) == msg2_len);
199 GNUNET_break (0 ==
200 strncmp (msg,
201 msg2,
202 msg2_len));
203 GNUNET_break (16 == u162);
204 GNUNET_break (32 == u322);
205 GNUNET_break (64 == u642);
206 GNUNET_PQ_cleanup_result (results_select);
207 PQclear (result);
208 }
209 GNUNET_CRYPTO_rsa_signature_free (sig);
210 GNUNET_CRYPTO_rsa_private_key_free (priv);
211 GNUNET_CRYPTO_rsa_public_key_free (pub);
212 if (GNUNET_OK != ret)
213 return 1;
214
215 return 0;
216}
217
218
219int
220main(int argc,
221 const char *const argv[])
222{
223 PGconn *conn;
224 PGresult *result;
225 int ret;
226
227 GNUNET_log_setup ("test-pq",
228 "WARNING",
229 NULL);
230 conn = PQconnectdb ("postgres:///gnunetcheck");
231 if (CONNECTION_OK != PQstatus (conn))
232 {
233 fprintf (stderr,
234 "Cannot run test, database connection failed: %s\n",
235 PQerrorMessage (conn));
236 GNUNET_break (0);
237 PQfinish (conn);
238 return 0; /* We ignore this type of error... */
239 }
240
241 result = PQexec (conn,
242 "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
243 " pub BYTEA NOT NULL"
244 ",sig BYTEA NOT NULL"
245 ",abs_time INT8 NOT NULL"
246 ",forever INT8 NOT NULL"
247 ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)"
248 ",vsize VARCHAR NOT NULL"
249 ",u16 INT2 NOT NULL"
250 ",u32 INT4 NOT NULL"
251 ",u64 INT8 NOT NULL"
252 ")");
253 if (PGRES_COMMAND_OK != PQresultStatus (result))
254 {
255 fprintf (stderr,
256 "Failed to create table: %s\n",
257 PQerrorMessage (conn));
258 PQclear (result);
259 PQfinish (conn);
260 return 1;
261 }
262 PQclear (result);
263 if (GNUNET_OK !=
264 postgres_prepare (conn))
265 {
266 GNUNET_break (0);
267 PQfinish (conn);
268 return 1;
269 }
270 ret = run_queries (conn);
271 result = PQexec (conn,
272 "DROP TABLE test_pq");
273 if (PGRES_COMMAND_OK != PQresultStatus (result))
274 {
275 fprintf (stderr,
276 "Failed to create table: %s\n",
277 PQerrorMessage (conn));
278 PQclear (result);
279 PQfinish (conn);
280 return 1;
281 }
282 PQclear (result);
283 PQfinish (conn);
284 return ret;
285}
286
287
288/* end of test_pq.c */