Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2015, 2016, 2023, 2026 Taler Systems SA
4 :
5 : TALER 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 : TALER 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 : TALER; see the file COPYING. 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 : * @author Özgür Kesim <oec-taler@kesim.org>
21 : */
22 : #include "taler/taler_util.h"
23 : #include "taler/taler_pq_lib.h"
24 : #include <gnunet/gnunet_pq_lib.h>
25 :
26 :
27 : /**
28 : * Setup prepared statements.
29 : *
30 : * @param db database handle to initialize
31 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
32 : */
33 : static enum GNUNET_GenericReturnValue
34 1 : postgres_prepare (struct GNUNET_PQ_Context *db)
35 : {
36 1 : struct GNUNET_PQ_PreparedStatement ps[] = {
37 1 : GNUNET_PQ_make_prepare ("test_insert",
38 : "INSERT INTO test_pq ("
39 : "tamount"
40 : ",json"
41 : ",aamount"
42 : ",aamountc"
43 : ",tamountc"
44 : ",hash"
45 : ",hashes"
46 : ",cs_r_pubs"
47 : ") VALUES "
48 : "($1, $2, $3, $4, $5, $6, $7, $8);"),
49 1 : GNUNET_PQ_make_prepare ("test_select",
50 : "SELECT"
51 : " tamount"
52 : ",json"
53 : ",aamount"
54 : ",aamountc"
55 : ",aamountn"
56 : ",aamountnc"
57 : ",tamountc"
58 : ",hash"
59 : ",hashes"
60 : ",cs_r_pubs"
61 : " FROM test_pq;"),
62 : GNUNET_PQ_PREPARED_STATEMENT_END
63 : };
64 :
65 1 : return GNUNET_PQ_prepare_statements (db,
66 : ps);
67 : }
68 :
69 :
70 : /**
71 : * Run actual test queries.
72 : *
73 : * @return 0 on success
74 : */
75 : static int
76 1 : run_queries (struct GNUNET_PQ_Context *conn)
77 : {
78 : struct TALER_Amount tamount;
79 : struct TALER_Amount aamount[3];
80 : struct TALER_Amount aamountc[2];
81 : struct TALER_Amount tamountc;
82 1 : struct GNUNET_HashCode hc =
83 : {{0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef,
84 : 0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef,
85 : 0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef,
86 : 0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef, }};
87 1 : struct GNUNET_HashCode hcs[2] =
88 : {{{0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,
89 : 0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,
90 : 0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,
91 : 0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,}},
92 : {{0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,
93 : 0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,
94 : 0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,
95 : 0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,}}};
96 : struct GNUNET_CRYPTO_CSPublicRPairP in_cs_r_pubs[5];
97 : json_t *json;
98 :
99 1 : GNUNET_assert (GNUNET_OK ==
100 : TALER_string_to_amount ("EUR:5.3",
101 : &aamount[0]));
102 1 : GNUNET_assert (GNUNET_OK ==
103 : TALER_string_to_amount ("EUR:6.4",
104 : &aamount[1]));
105 1 : GNUNET_assert (GNUNET_OK ==
106 : TALER_string_to_amount ("EUR:7.5",
107 : &aamount[2]));
108 1 : GNUNET_assert (GNUNET_OK ==
109 : TALER_string_to_amount ("EUR:7.7",
110 : &tamount));
111 1 : GNUNET_assert (GNUNET_OK ==
112 : TALER_string_to_amount ("USD:3.2",
113 : &aamountc[0]));
114 1 : GNUNET_assert (GNUNET_OK ==
115 : TALER_string_to_amount ("CHF:4.5",
116 : &aamountc[1]));
117 1 : GNUNET_assert (GNUNET_OK ==
118 : TALER_string_to_amount ("FOO:8.7",
119 : &tamountc));
120 1 : json = json_object ();
121 1 : GNUNET_assert (NULL != json);
122 1 : GNUNET_assert (0 ==
123 : json_object_set_new (json,
124 : "foo",
125 : json_integer (42)));
126 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
127 : in_cs_r_pubs,
128 : sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * 5);
129 : {
130 1 : struct GNUNET_PQ_QueryParam params_insert[] = {
131 1 : TALER_PQ_query_param_amount (conn,
132 : &tamount),
133 1 : TALER_PQ_query_param_json (json),
134 1 : TALER_PQ_query_param_array_amount (3,
135 : aamount,
136 : conn),
137 1 : TALER_PQ_query_param_array_amount_with_currency (2,
138 : aamountc,
139 : conn),
140 1 : TALER_PQ_query_param_amount_with_currency (conn,
141 : &tamountc),
142 1 : GNUNET_PQ_query_param_fixed_size (&hc,
143 : sizeof (hc)),
144 1 : TALER_PQ_query_param_array_hash_code (2,
145 : hcs,
146 : conn),
147 1 : TALER_PQ_query_param_array_cs_r_pub (5,
148 : in_cs_r_pubs,
149 : conn),
150 : GNUNET_PQ_query_param_end
151 : };
152 : PGresult *result;
153 :
154 1 : result = GNUNET_PQ_exec_prepared (conn,
155 : "test_insert",
156 : params_insert);
157 6 : for (uint8_t i = 0; i < 5; i++)
158 : {
159 5 : printf (" in_cs_r_pubs[%d]=%s\n",
160 : i,
161 : GNUNET_STRINGS_data_to_string_alloc (
162 5 : &in_cs_r_pubs[i],
163 : sizeof(in_cs_r_pubs[i])));
164 : }
165 :
166 1 : if (PGRES_COMMAND_OK != PQresultStatus (result))
167 : {
168 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169 : "Database failure: %s\n",
170 : PQresultErrorMessage (result));
171 0 : PQclear (result);
172 0 : return 1;
173 : }
174 1 : PQclear (result);
175 1 : json_decref (json);
176 : }
177 : {
178 : struct TALER_Amount tamount2;
179 : struct TALER_Amount tamountc2;
180 : struct TALER_Amount *pamount;
181 : struct TALER_Amount *pamountc;
182 : struct TALER_Amount *pamountn;
183 : struct TALER_Amount *pamountnc;
184 : struct GNUNET_HashCode hc2;
185 : struct GNUNET_HashCode *hcs2;
186 : struct GNUNET_CRYPTO_CSPublicRPairP *out_cs_r_pubs;
187 : size_t npamount;
188 : size_t npamountc;
189 : size_t npamountn;
190 : size_t npamountnc;
191 : size_t nhcs;
192 : size_t n_rpubs;
193 : json_t *json2;
194 1 : struct GNUNET_PQ_QueryParam params_select[] = {
195 : GNUNET_PQ_query_param_end
196 : };
197 1 : struct GNUNET_PQ_ResultSpec results_select[] = {
198 1 : TALER_PQ_result_spec_amount ("tamount",
199 : "EUR",
200 : &tamount2),
201 1 : TALER_PQ_result_spec_json ("json",
202 : &json2),
203 1 : TALER_PQ_result_spec_array_amount (conn,
204 : "aamount",
205 : "EUR",
206 : &npamount,
207 : &pamount),
208 1 : TALER_PQ_result_spec_array_amount_with_currency (conn,
209 : "aamountc",
210 : &npamountc,
211 : &pamountc),
212 1 : TALER_PQ_result_spec_array_amount (conn,
213 : "aamountn",
214 : "EUR",
215 : &npamountn,
216 : &pamountn),
217 1 : TALER_PQ_result_spec_array_amount_with_currency (conn,
218 : "aamountnc",
219 : &npamountnc,
220 : &pamountnc),
221 1 : TALER_PQ_result_spec_amount_with_currency ("tamountc",
222 : &tamountc2),
223 1 : GNUNET_PQ_result_spec_auto_from_type ("hash",
224 : &hc2),
225 1 : TALER_PQ_result_spec_array_hash_code (conn,
226 : "hashes",
227 : &nhcs,
228 : &hcs2),
229 1 : TALER_PQ_result_spec_array_cs_r_pub (conn,
230 : "cs_r_pubs",
231 : &n_rpubs,
232 : &out_cs_r_pubs),
233 : GNUNET_PQ_result_spec_end
234 : };
235 :
236 1 : if (1 !=
237 1 : GNUNET_PQ_eval_prepared_singleton_select (conn,
238 : "test_select",
239 : params_select,
240 : results_select))
241 : {
242 0 : GNUNET_break (0);
243 0 : return 1;
244 : }
245 1 : GNUNET_break (0 ==
246 : TALER_amount_cmp (&tamount,
247 : &tamount2));
248 1 : GNUNET_break (42 ==
249 : json_integer_value (json_object_get (json2,
250 : "foo")));
251 1 : GNUNET_break (3 == npamount);
252 4 : for (size_t i = 0; i < 3; i++)
253 : {
254 3 : GNUNET_break (0 ==
255 : TALER_amount_cmp (&aamount[i],
256 : &pamount[i]));
257 : }
258 1 : GNUNET_break (2 == npamountc);
259 3 : for (size_t i = 0; i < npamountc; i++)
260 : {
261 2 : GNUNET_break (0 ==
262 : TALER_amount_cmp (&aamountc[i],
263 : &pamountc[i]));
264 : }
265 1 : GNUNET_break (0 ==
266 : TALER_amount_cmp (&tamountc,
267 : &tamountc2));
268 1 : GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2));
269 3 : for (size_t i = 0; i < 2; i++)
270 : {
271 2 : GNUNET_break (0 ==
272 : GNUNET_memcmp (&hcs[i],
273 : &hcs2[i]));
274 : }
275 1 : GNUNET_break (5 == n_rpubs);
276 6 : for (uint8_t i = 0; i < 5; i++)
277 : {
278 5 : GNUNET_break (0 ==
279 : GNUNET_memcmp (&in_cs_r_pubs[i],
280 : &out_cs_r_pubs[i]));
281 5 : printf ("out_cs_r_pubs[%d]=%s\n",
282 : i,
283 : GNUNET_STRINGS_data_to_string_alloc (
284 5 : &out_cs_r_pubs[i],
285 : sizeof(out_cs_r_pubs[i])));
286 : }
287 1 : GNUNET_PQ_cleanup_result (results_select);
288 : }
289 1 : return 0;
290 : }
291 :
292 :
293 : int
294 1 : main (int argc,
295 : const char *const argv[])
296 : {
297 1 : struct GNUNET_PQ_ExecuteStatement es[] = {
298 1 : GNUNET_PQ_make_execute ("DO $$ "
299 : " BEGIN"
300 : " CREATE DOMAIN gnunet_hashcode AS BYTEA"
301 : " CHECK(length(VALUE)=64);"
302 : " EXCEPTION"
303 : " WHEN duplicate_object THEN null;"
304 : " END "
305 : "$$;"),
306 1 : GNUNET_PQ_make_execute ("DO $$ "
307 : " BEGIN"
308 : " CREATE TYPE taler_amount AS"
309 : " (val INT8, frac INT4);"
310 : " EXCEPTION"
311 : " WHEN duplicate_object THEN null;"
312 : " END "
313 : "$$;"),
314 1 : GNUNET_PQ_make_execute ("DO $$ "
315 : " BEGIN"
316 : " CREATE TYPE taler_amount_currency AS"
317 : " (val INT8, frac INT4, curr VARCHAR(12));"
318 : " EXCEPTION"
319 : " WHEN duplicate_object THEN null;"
320 : " END "
321 : "$$;"),
322 1 : GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
323 : "tamount taler_amount NOT NULL"
324 : ",json VARCHAR NOT NULL"
325 : ",aamount taler_amount[]"
326 : ",aamountc taler_amount_currency[]"
327 : ",aamountn taler_amount[] NOT NULL DEFAULT ARRAY[]::taler_amount[]"
328 : ",aamountnc taler_amount_currency[] NOT NULL DEFAULT ARRAY[]::taler_amount_currency[]"
329 : ",tamountc taler_amount_currency"
330 : ",hash gnunet_hashcode"
331 : ",hashes gnunet_hashcode[]"
332 : ",cs_r_pubs BYTEA[]"
333 : ")"),
334 : GNUNET_PQ_EXECUTE_STATEMENT_END
335 : };
336 : struct GNUNET_PQ_Context *conn;
337 : int ret;
338 :
339 : (void) argc;
340 : (void) argv;
341 1 : GNUNET_log_setup ("test-pq",
342 : "WARNING",
343 : NULL);
344 1 : conn = GNUNET_PQ_connect ("postgres:///talercheck",
345 : NULL,
346 : es,
347 : NULL);
348 1 : if (NULL == conn)
349 0 : return 77;
350 1 : if (GNUNET_OK !=
351 1 : postgres_prepare (conn))
352 : {
353 0 : GNUNET_break (0);
354 0 : GNUNET_PQ_disconnect (conn);
355 0 : return 1;
356 : }
357 :
358 1 : ret = run_queries (conn);
359 : {
360 1 : struct GNUNET_PQ_ExecuteStatement ds[] = {
361 1 : GNUNET_PQ_make_execute ("DROP TABLE test_pq"),
362 : GNUNET_PQ_EXECUTE_STATEMENT_END
363 : };
364 :
365 1 : if (GNUNET_OK !=
366 1 : GNUNET_PQ_exec_statements (conn,
367 : ds))
368 : {
369 0 : fprintf (stderr,
370 : "Failed to drop table\n");
371 0 : GNUNET_PQ_disconnect (conn);
372 0 : return 1;
373 : }
374 : }
375 1 : GNUNET_PQ_disconnect (conn);
376 1 : return ret;
377 : }
378 :
379 :
380 : /* end of test_pq.c */
|