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 : "merchant",
140 : conn),
141 1 : TALER_PQ_query_param_amount_with_currency (conn,
142 : &tamountc),
143 1 : GNUNET_PQ_query_param_fixed_size (&hc,
144 : sizeof (hc)),
145 1 : TALER_PQ_query_param_array_hash_code (2,
146 : hcs,
147 : conn),
148 1 : TALER_PQ_query_param_array_cs_r_pub (5,
149 : in_cs_r_pubs,
150 : conn),
151 : GNUNET_PQ_query_param_end
152 : };
153 : PGresult *result;
154 :
155 1 : result = GNUNET_PQ_exec_prepared (conn,
156 : "test_insert",
157 : params_insert);
158 6 : for (uint8_t i = 0; i < 5; i++)
159 : {
160 5 : printf (" in_cs_r_pubs[%d]=%s\n",
161 : i,
162 : GNUNET_STRINGS_data_to_string_alloc (
163 5 : &in_cs_r_pubs[i],
164 : sizeof(in_cs_r_pubs[i])));
165 : }
166 :
167 1 : if (PGRES_COMMAND_OK != PQresultStatus (result))
168 : {
169 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
170 : "Database failure: %s\n",
171 : PQresultErrorMessage (result));
172 0 : PQclear (result);
173 0 : return 1;
174 : }
175 1 : PQclear (result);
176 1 : json_decref (json);
177 : }
178 : {
179 : struct TALER_Amount tamount2;
180 : struct TALER_Amount tamountc2;
181 : struct TALER_Amount *pamount;
182 : struct TALER_Amount *pamountc;
183 : struct TALER_Amount *pamountn;
184 : struct TALER_Amount *pamountnc;
185 : struct GNUNET_HashCode hc2;
186 : struct GNUNET_HashCode *hcs2;
187 : struct GNUNET_CRYPTO_CSPublicRPairP *out_cs_r_pubs;
188 : size_t npamount;
189 : size_t npamountc;
190 : size_t npamountn;
191 : size_t npamountnc;
192 : size_t nhcs;
193 : size_t n_rpubs;
194 : json_t *json2;
195 1 : struct GNUNET_PQ_QueryParam params_select[] = {
196 : GNUNET_PQ_query_param_end
197 : };
198 1 : struct GNUNET_PQ_ResultSpec results_select[] = {
199 1 : TALER_PQ_result_spec_amount ("tamount",
200 : "EUR",
201 : &tamount2),
202 1 : TALER_PQ_result_spec_json ("json",
203 : &json2),
204 1 : TALER_PQ_result_spec_array_amount (conn,
205 : "aamount",
206 : "EUR",
207 : &npamount,
208 : &pamount),
209 1 : TALER_PQ_result_spec_array_amount_with_currency (conn,
210 : "merchant",
211 : "aamountc",
212 : &npamountc,
213 : &pamountc),
214 1 : TALER_PQ_result_spec_array_amount (conn,
215 : "aamountn",
216 : "EUR",
217 : &npamountn,
218 : &pamountn),
219 1 : TALER_PQ_result_spec_array_amount_with_currency (conn,
220 : "merchant",
221 : "aamountnc",
222 : &npamountnc,
223 : &pamountnc),
224 1 : TALER_PQ_result_spec_amount_with_currency ("tamountc",
225 : &tamountc2),
226 1 : GNUNET_PQ_result_spec_auto_from_type ("hash",
227 : &hc2),
228 1 : TALER_PQ_result_spec_array_hash_code (conn,
229 : "hashes",
230 : &nhcs,
231 : &hcs2),
232 1 : TALER_PQ_result_spec_array_cs_r_pub (conn,
233 : "cs_r_pubs",
234 : &n_rpubs,
235 : &out_cs_r_pubs),
236 : GNUNET_PQ_result_spec_end
237 : };
238 :
239 1 : if (1 !=
240 1 : GNUNET_PQ_eval_prepared_singleton_select (conn,
241 : "test_select",
242 : params_select,
243 : results_select))
244 : {
245 0 : GNUNET_break (0);
246 0 : return 1;
247 : }
248 1 : GNUNET_break (0 ==
249 : TALER_amount_cmp (&tamount,
250 : &tamount2));
251 1 : GNUNET_break (42 ==
252 : json_integer_value (json_object_get (json2,
253 : "foo")));
254 1 : GNUNET_break (3 == npamount);
255 4 : for (size_t i = 0; i < 3; i++)
256 : {
257 3 : GNUNET_break (0 ==
258 : TALER_amount_cmp (&aamount[i],
259 : &pamount[i]));
260 : }
261 1 : GNUNET_break (2 == npamountc);
262 3 : for (size_t i = 0; i < npamountc; i++)
263 : {
264 2 : GNUNET_break (0 ==
265 : TALER_amount_cmp (&aamountc[i],
266 : &pamountc[i]));
267 : }
268 1 : GNUNET_break (0 ==
269 : TALER_amount_cmp (&tamountc,
270 : &tamountc2));
271 1 : GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2));
272 3 : for (size_t i = 0; i < 2; i++)
273 : {
274 2 : GNUNET_break (0 ==
275 : GNUNET_memcmp (&hcs[i],
276 : &hcs2[i]));
277 : }
278 1 : GNUNET_break (5 == n_rpubs);
279 6 : for (uint8_t i = 0; i < 5; i++)
280 : {
281 5 : GNUNET_break (0 ==
282 : GNUNET_memcmp (&in_cs_r_pubs[i],
283 : &out_cs_r_pubs[i]));
284 5 : printf ("out_cs_r_pubs[%d]=%s\n",
285 : i,
286 : GNUNET_STRINGS_data_to_string_alloc (
287 5 : &out_cs_r_pubs[i],
288 : sizeof(out_cs_r_pubs[i])));
289 : }
290 1 : GNUNET_PQ_cleanup_result (results_select);
291 : }
292 1 : return 0;
293 : }
294 :
295 :
296 : int
297 1 : main (int argc,
298 : const char *const argv[])
299 : {
300 1 : struct GNUNET_PQ_ExecuteStatement es[] = {
301 1 : GNUNET_PQ_make_execute ("DO $$ "
302 : " BEGIN"
303 : " CREATE SCHEMA IF NOT EXISTS merchant;"
304 : " END "
305 : "$$;"),
306 1 : GNUNET_PQ_make_execute ("DO $$ "
307 : " BEGIN"
308 : " CREATE DOMAIN gnunet_hashcode AS BYTEA"
309 : " CHECK(length(VALUE)=64);"
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 AS"
317 : " (val INT8, frac INT4);"
318 : " EXCEPTION"
319 : " WHEN duplicate_object THEN null;"
320 : " END "
321 : "$$;"),
322 1 : GNUNET_PQ_make_execute ("DO $$ "
323 : " BEGIN"
324 : " CREATE TYPE merchant.taler_amount_currency AS"
325 : " (val INT8, frac INT4, curr VARCHAR(12));"
326 : " EXCEPTION"
327 : " WHEN duplicate_object THEN null;"
328 : " END "
329 : "$$;"),
330 1 : GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
331 : "tamount taler_amount NOT NULL"
332 : ",json VARCHAR NOT NULL"
333 : ",aamount taler_amount[]"
334 : ",aamountc merchant.taler_amount_currency[]"
335 : ",aamountn taler_amount[] NOT NULL DEFAULT ARRAY[]::taler_amount[]"
336 : ",aamountnc merchant.taler_amount_currency[] NOT NULL DEFAULT ARRAY[]::merchant.taler_amount_currency[]"
337 : ",tamountc merchant.taler_amount_currency"
338 : ",hash gnunet_hashcode"
339 : ",hashes gnunet_hashcode[]"
340 : ",cs_r_pubs BYTEA[]"
341 : ")"),
342 : GNUNET_PQ_EXECUTE_STATEMENT_END
343 : };
344 : struct GNUNET_PQ_Context *conn;
345 : int ret;
346 : struct GNUNET_CONFIGURATION_Handle *cfg;
347 :
348 : (void) argc;
349 : (void) argv;
350 1 : GNUNET_log_setup ("test-pq",
351 : "WARNING",
352 : NULL);
353 1 : cfg = GNUNET_CONFIGURATION_create (
354 : TALER_EXCHANGE_project_data ());
355 1 : GNUNET_CONFIGURATION_set_value_string (cfg,
356 : "test-pq",
357 : "CONFIG",
358 : "postgres:///talercheck");
359 : /* just to squash warning */
360 1 : GNUNET_CONFIGURATION_set_value_string (cfg,
361 : "test-pq",
362 : "SQL_DIR",
363 : "none");
364 1 : conn = GNUNET_PQ_init (cfg,
365 : "test-pq",
366 : NULL,
367 : NULL);
368 1 : GNUNET_CONFIGURATION_destroy (cfg);
369 1 : if (NULL == conn)
370 0 : return 77;
371 1 : GNUNET_assert (GNUNET_OK ==
372 : GNUNET_PQ_exec_statements (conn,
373 : es));
374 1 : if (GNUNET_OK !=
375 1 : postgres_prepare (conn))
376 : {
377 0 : GNUNET_break (0);
378 0 : GNUNET_PQ_disconnect (conn);
379 0 : return 1;
380 : }
381 1 : ret = run_queries (conn);
382 : {
383 1 : struct GNUNET_PQ_ExecuteStatement ds[] = {
384 1 : GNUNET_PQ_make_execute ("DROP TABLE test_pq"),
385 : GNUNET_PQ_EXECUTE_STATEMENT_END
386 : };
387 :
388 1 : if (GNUNET_OK !=
389 1 : GNUNET_PQ_exec_statements (conn,
390 : ds))
391 : {
392 0 : fprintf (stderr,
393 : "Failed to drop table\n");
394 0 : GNUNET_PQ_disconnect (conn);
395 0 : return 1;
396 : }
397 : }
398 1 : GNUNET_PQ_disconnect (conn);
399 1 : return ret;
400 : }
401 :
402 :
403 : /* end of test_pq.c */
|