diff options
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | pkgconfig/gnunetpq.pc.in | 12 | ||||
-rw-r--r-- | po/POTFILES.in | 19 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/include/Makefile.am | 1 | ||||
-rw-r--r-- | src/include/gnunet_postgres_lib.h | 40 | ||||
-rw-r--r-- | src/include/gnunet_pq_lib.h | 454 | ||||
-rw-r--r-- | src/postgres/postgres.c | 61 | ||||
-rw-r--r-- | src/pq/Makefile.am | 39 | ||||
-rw-r--r-- | src/pq/pq.c | 169 | ||||
-rw-r--r-- | src/pq/pq_query_helper.c | 386 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 674 | ||||
-rw-r--r-- | src/pq/test_pq.c | 288 |
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 | |||
1566 | src/peerinfo-tool/Makefile | 1566 | src/peerinfo-tool/Makefile |
1567 | src/peerstore/Makefile | 1567 | src/peerstore/Makefile |
1568 | src/peerstore/peerstore.conf | 1568 | src/peerstore/peerstore.conf |
1569 | src/pq/Makefile | ||
1569 | src/postgres/Makefile | 1570 | src/postgres/Makefile |
1570 | src/psycutil/Makefile | 1571 | src/psycutil/Makefile |
1571 | src/psyc/Makefile | 1572 | src/psyc/Makefile |
@@ -1635,6 +1636,7 @@ pkgconfig/gnunetnamestore.pc | |||
1635 | pkgconfig/gnunetnat.pc | 1636 | pkgconfig/gnunetnat.pc |
1636 | pkgconfig/gnunetnse.pc | 1637 | pkgconfig/gnunetnse.pc |
1637 | pkgconfig/gnunetpeerinfo.pc | 1638 | pkgconfig/gnunetpeerinfo.pc |
1639 | pkgconfig/gnunetpq.pc | ||
1638 | pkgconfig/gnunetpostgres.pc | 1640 | pkgconfig/gnunetpostgres.pc |
1639 | pkgconfig/gnunetpsyc.pc | 1641 | pkgconfig/gnunetpsyc.pc |
1640 | pkgconfig/gnunetpsycstore.pc | 1642 | pkgconfig/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 @@ | |||
1 | prefix=@prefix@ | ||
2 | exec_prefix=@exec_prefix@ | ||
3 | libdir=@libdir@ | ||
4 | includedir=@includedir@ | ||
5 | |||
6 | Name: GNUnet PQ | ||
7 | Description: API with common functions for interacting with libpq | ||
8 | URL: http://gnunet.org | ||
9 | Version: @VERSION@ | ||
10 | Requires: | ||
11 | Libs: -L${libdir} -lgnunetpq | ||
12 | Cflags: -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 | |||
123 | src/dv/gnunet-dv.c | 123 | src/dv/gnunet-dv.c |
124 | src/dv/gnunet-service-dv.c | 124 | src/dv/gnunet-service-dv.c |
125 | src/dv/plugin_transport_dv.c | 125 | src/dv/plugin_transport_dv.c |
126 | src/env/env.c | ||
127 | src/exit/gnunet-daemon-exit.c | 126 | src/exit/gnunet-daemon-exit.c |
128 | src/exit/gnunet-helper-exit.c | 127 | src/exit/gnunet-helper-exit.c |
129 | src/exit/gnunet-helper-exit-windows.c | 128 | src/exit/gnunet-helper-exit-windows.c |
@@ -203,9 +202,13 @@ src/identity/gnunet-identity.c | |||
203 | src/identity/gnunet-service-identity.c | 202 | src/identity/gnunet-service-identity.c |
204 | src/identity/identity_api.c | 203 | src/identity/identity_api.c |
205 | src/identity/identity_api_lookup.c | 204 | src/identity/identity_api_lookup.c |
205 | src/identity/plugin_gnsrecord_identity.c | ||
206 | src/identity/plugin_rest_identity.c | 206 | src/identity/plugin_rest_identity.c |
207 | src/identity-token/gnunet-identity-token.c | 207 | src/identity-provider/gnunet-identity-token.c |
208 | src/identity-token/plugin_rest_identity_token.c | 208 | src/identity-provider/gnunet-service-identity-provider.c |
209 | src/identity-provider/identity_provider_api.c | ||
210 | src/identity-provider/identity_token.c | ||
211 | src/identity-provider/plugin_rest_identity_provider.c | ||
209 | src/multicast/gnunet-multicast.c | 212 | src/multicast/gnunet-multicast.c |
210 | src/multicast/gnunet-service-multicast.c | 213 | src/multicast/gnunet-service-multicast.c |
211 | src/multicast/multicast_api.c | 214 | src/multicast/multicast_api.c |
@@ -251,12 +254,17 @@ src/peerstore/peerstore_api.c | |||
251 | src/peerstore/peerstore_common.c | 254 | src/peerstore/peerstore_common.c |
252 | src/peerstore/plugin_peerstore_sqlite.c | 255 | src/peerstore/plugin_peerstore_sqlite.c |
253 | src/postgres/postgres.c | 256 | src/postgres/postgres.c |
257 | src/pq/pq.c | ||
258 | src/pq/pq_query_helper.c | ||
259 | src/pq/pq_result_helper.c | ||
254 | src/psyc/gnunet-service-psyc.c | 260 | src/psyc/gnunet-service-psyc.c |
255 | src/psyc/psyc_api.c | 261 | src/psyc/psyc_api.c |
256 | src/psycstore/gnunet-service-psycstore.c | 262 | src/psycstore/gnunet-service-psycstore.c |
257 | src/psycstore/plugin_psycstore_sqlite.c | 263 | src/psycstore/plugin_psycstore_sqlite.c |
258 | src/psycstore/psycstore_api.c | 264 | src/psycstore/psycstore_api.c |
259 | src/psycstore/psyc_util_lib.c | 265 | src/psycutil/psyc_env.c |
266 | src/psycutil/psyc_message.c | ||
267 | src/psycutil/psyc_slicer.c | ||
260 | src/pt/gnunet-daemon-pt.c | 268 | src/pt/gnunet-daemon-pt.c |
261 | src/regex/gnunet-daemon-regexprofiler.c | 269 | src/regex/gnunet-daemon-regexprofiler.c |
262 | src/regex/gnunet-regex-profiler.c | 270 | src/regex/gnunet-regex-profiler.c |
@@ -278,8 +286,11 @@ src/revocation/gnunet-service-revocation.c | |||
278 | src/revocation/revocation_api.c | 286 | src/revocation/revocation_api.c |
279 | src/rps/gnunet-rps.c | 287 | src/rps/gnunet-rps.c |
280 | src/rps/gnunet-service-rps.c | 288 | src/rps/gnunet-service-rps.c |
289 | src/rps/gnunet-service-rps_custommap.c | ||
290 | src/rps/gnunet-service-rps_peers.c | ||
281 | src/rps/gnunet-service-rps_sampler.c | 291 | src/rps/gnunet-service-rps_sampler.c |
282 | src/rps/gnunet-service-rps_sampler_elem.c | 292 | src/rps/gnunet-service-rps_sampler_elem.c |
293 | src/rps/gnunet-service-rps_view.c | ||
283 | src/rps/rps_api.c | 294 | src/rps/rps_api.c |
284 | src/rps/rps-test_util.c | 295 | src/rps/rps-test_util.c |
285 | src/scalarproduct/gnunet-scalarproduct.c | 296 | src/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 | |||
44 | endif | 44 | endif |
45 | 45 | ||
46 | if HAVE_POSTGRESQL | 46 | if HAVE_POSTGRESQL |
47 | POSTGRES_DIR = postgres | 47 | POSTGRES_DIR = pq postgres |
48 | endif | 48 | endif |
49 | 49 | ||
50 | if HAVE_REST | 50 | if 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 | */ |
59 | int | 59 | int |
60 | GNUNET_POSTGRES_check_result_ (PGconn *dbh, PGresult * ret, int expected_status, | 60 | GNUNET_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 | */ |
89 | int | 93 | int |
90 | GNUNET_POSTGRES_exec_ (PGconn *dbh, const char *sql, const char *filename, int line); | 94 | GNUNET_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 | */ |
114 | int | 121 | int |
115 | GNUNET_POSTGRES_prepare_ (PGconn *dbh, const char *name, const char *sql, | 122 | GNUNET_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 | */ |
153 | int | 163 | int |
154 | GNUNET_POSTGRES_delete_by_rowid (PGconn *dbh, | 164 | GNUNET_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 | */ | ||
42 | typedef 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 | */ | ||
57 | struct 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 | */ | ||
101 | struct GNUNET_PQ_QueryParam | ||
102 | GNUNET_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 | */ | ||
121 | struct GNUNET_PQ_QueryParam | ||
122 | GNUNET_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 | */ | ||
131 | struct GNUNET_PQ_QueryParam | ||
132 | GNUNET_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 | */ | ||
141 | struct GNUNET_PQ_QueryParam | ||
142 | GNUNET_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 | */ | ||
151 | struct GNUNET_PQ_QueryParam | ||
152 | GNUNET_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 | */ | ||
160 | struct GNUNET_PQ_QueryParam | ||
161 | GNUNET_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 | */ | ||
169 | struct GNUNET_PQ_QueryParam | ||
170 | GNUNET_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 | */ | ||
178 | struct GNUNET_PQ_QueryParam | ||
179 | GNUNET_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 | */ | ||
196 | typedef 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 | */ | ||
212 | typedef void | ||
213 | (*GNUNET_PQ_ResultCleanup)(void *cls, | ||
214 | void *rd); | ||
215 | |||
216 | |||
217 | /** | ||
218 | * @brief Description of a DB result cell. | ||
219 | */ | ||
220 | struct 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 | */ | ||
280 | struct GNUNET_PQ_ResultSpec | ||
281 | GNUNET_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 | */ | ||
294 | struct GNUNET_PQ_ResultSpec | ||
295 | GNUNET_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 | */ | ||
319 | struct GNUNET_PQ_ResultSpec | ||
320 | GNUNET_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 | */ | ||
332 | struct GNUNET_PQ_ResultSpec | ||
333 | GNUNET_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 | */ | ||
344 | struct GNUNET_PQ_ResultSpec | ||
345 | GNUNET_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 | */ | ||
356 | struct GNUNET_PQ_ResultSpec | ||
357 | GNUNET_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 | */ | ||
368 | struct GNUNET_PQ_ResultSpec | ||
369 | GNUNET_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 | */ | ||
380 | struct GNUNET_PQ_ResultSpec | ||
381 | GNUNET_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 | */ | ||
392 | struct GNUNET_PQ_ResultSpec | ||
393 | GNUNET_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 | */ | ||
404 | struct GNUNET_PQ_ResultSpec | ||
405 | GNUNET_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 | */ | ||
417 | PGresult * | ||
418 | GNUNET_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 | */ | ||
436 | int | ||
437 | GNUNET_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 | */ | ||
448 | void | ||
449 | GNUNET_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 | */ |
43 | int | 43 | int |
44 | GNUNET_POSTGRES_check_result_ (PGconn * dbh, PGresult * ret, | 44 | GNUNET_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 | */ |
77 | int | 81 | int |
78 | GNUNET_POSTGRES_exec_ (PGconn * dbh, const char *sql, const char *filename, | 82 | GNUNET_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 | */ |
104 | int | 110 | int |
105 | GNUNET_POSTGRES_prepare_ (PGconn * dbh, const char *name, const char *sql, | 111 | GNUNET_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 | */ |
166 | int | 184 | int |
167 | GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh, const char *stmt, uint32_t rowid) | 185 | GNUNET_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 | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS) | ||
3 | |||
4 | if MINGW | ||
5 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
6 | endif | ||
7 | |||
8 | if USE_COVERAGE | ||
9 | AM_CFLAGS = --coverage | ||
10 | endif | ||
11 | |||
12 | if HAVE_POSTGRESQL | ||
13 | lib_LTLIBRARIES = libgnunetpq.la | ||
14 | endif | ||
15 | |||
16 | libgnunetpq_la_SOURCES = \ | ||
17 | pq.c \ | ||
18 | pq_query_helper.c \ | ||
19 | pq_result_helper.c | ||
20 | libgnunetpq_la_LIBADD = -lpq \ | ||
21 | $(top_builddir)/src/util/libgnunetutil.la | ||
22 | libgnunetpq_la_LDFLAGS = \ | ||
23 | $(POSTGRESQL_LDFLAGS) \ | ||
24 | $(GN_LIB_LDFLAGS) \ | ||
25 | -version-info 0:0:0 | ||
26 | |||
27 | |||
28 | TESTS = \ | ||
29 | test_pq | ||
30 | |||
31 | check_PROGRAMS= \ | ||
32 | test_pq | ||
33 | |||
34 | test_pq_SOURCES = \ | ||
35 | test_pq.c | ||
36 | test_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 | */ | ||
36 | PGresult * | ||
37 | GNUNET_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 = ¶ms[i]; | ||
68 | |||
69 | ret = x->conv (x->conv_cls, | ||
70 | x->data, | ||
71 | x->size, | ||
72 | ¶m_values[off], | ||
73 | ¶m_lengths[off], | ||
74 | ¶m_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 | */ | ||
108 | void | ||
109 | GNUNET_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 | */ | ||
133 | int | ||
134 | GNUNET_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 | */ | ||
40 | static int | ||
41 | qconv_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 | */ | ||
68 | struct GNUNET_PQ_QueryParam | ||
69 | GNUNET_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 | */ | ||
92 | static int | ||
93 | qconv_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 | */ | ||
124 | struct GNUNET_PQ_QueryParam | ||
125 | GNUNET_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 | */ | ||
147 | static int | ||
148 | qconv_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 | */ | ||
179 | struct GNUNET_PQ_QueryParam | ||
180 | GNUNET_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 | */ | ||
202 | static int | ||
203 | qconv_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 | */ | ||
234 | struct GNUNET_PQ_QueryParam | ||
235 | GNUNET_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 | */ | ||
257 | static int | ||
258 | qconv_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 | */ | ||
292 | struct GNUNET_PQ_QueryParam | ||
293 | GNUNET_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 | */ | ||
315 | static int | ||
316 | qconv_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 | */ | ||
350 | struct GNUNET_PQ_QueryParam | ||
351 | GNUNET_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 | */ | ||
366 | struct GNUNET_PQ_QueryParam | ||
367 | GNUNET_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 | */ | ||
379 | struct GNUNET_PQ_QueryParam | ||
380 | GNUNET_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 | */ | ||
33 | static void | ||
34 | clean_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 | */ | ||
61 | static int | ||
62 | extract_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 | */ | ||
115 | struct GNUNET_PQ_ResultSpec | ||
116 | GNUNET_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 | */ | ||
142 | static int | ||
143 | extract_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 | */ | ||
201 | struct GNUNET_PQ_ResultSpec | ||
202 | GNUNET_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 | */ | ||
228 | static int | ||
229 | extract_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 | */ | ||
284 | static void | ||
285 | clean_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 | */ | ||
305 | struct GNUNET_PQ_ResultSpec | ||
306 | GNUNET_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 | */ | ||
332 | static int | ||
333 | extract_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 | */ | ||
388 | static void | ||
389 | clean_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 | */ | ||
409 | struct GNUNET_PQ_ResultSpec | ||
410 | GNUNET_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 | */ | ||
429 | struct GNUNET_PQ_ResultSpec | ||
430 | GNUNET_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 | */ | ||
445 | struct GNUNET_PQ_ResultSpec | ||
446 | GNUNET_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 | */ | ||
469 | static int | ||
470 | extract_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 | */ | ||
515 | struct GNUNET_PQ_ResultSpec | ||
516 | GNUNET_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 | */ | ||
542 | static int | ||
543 | extract_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 | */ | ||
588 | struct GNUNET_PQ_ResultSpec | ||
589 | GNUNET_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 | */ | ||
615 | static int | ||
616 | extract_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 | */ | ||
661 | struct GNUNET_PQ_ResultSpec | ||
662 | GNUNET_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 | */ | ||
32 | static int | ||
33 | postgres_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 | */ | ||
89 | static int | ||
90 | run_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 | |||
219 | int | ||
220 | main(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 */ | ||