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 (in_cs_r_pubs,
127 : sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * 5);
128 : {
129 1 : struct GNUNET_PQ_QueryParam params_insert[] = {
130 1 : TALER_PQ_query_param_amount (conn,
131 : &tamount),
132 1 : TALER_PQ_query_param_json (json),
133 1 : TALER_PQ_query_param_array_amount (3,
134 : aamount,
135 : conn),
136 1 : TALER_PQ_query_param_array_amount_with_currency (2,
137 : aamountc,
138 : "merchant",
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 : "merchant",
210 : "aamountc",
211 : &npamountc,
212 : &pamountc),
213 1 : TALER_PQ_result_spec_array_amount (conn,
214 : "aamountn",
215 : "EUR",
216 : &npamountn,
217 : &pamountn),
218 1 : TALER_PQ_result_spec_array_amount_with_currency (conn,
219 : "merchant",
220 : "aamountnc",
221 : &npamountnc,
222 : &pamountnc),
223 1 : TALER_PQ_result_spec_amount_with_currency ("tamountc",
224 : &tamountc2),
225 1 : GNUNET_PQ_result_spec_auto_from_type ("hash",
226 : &hc2),
227 1 : TALER_PQ_result_spec_array_hash_code (conn,
228 : "hashes",
229 : &nhcs,
230 : &hcs2),
231 1 : TALER_PQ_result_spec_array_cs_r_pub (conn,
232 : "cs_r_pubs",
233 : &n_rpubs,
234 : &out_cs_r_pubs),
235 : GNUNET_PQ_result_spec_end
236 : };
237 :
238 1 : if (1 !=
239 1 : GNUNET_PQ_eval_prepared_singleton_select (conn,
240 : "test_select",
241 : params_select,
242 : results_select))
243 : {
244 0 : GNUNET_break (0);
245 0 : return 1;
246 : }
247 1 : GNUNET_break (0 ==
248 : TALER_amount_cmp (&tamount,
249 : &tamount2));
250 1 : GNUNET_break (42 ==
251 : json_integer_value (json_object_get (json2,
252 : "foo")));
253 1 : GNUNET_break (3 == npamount);
254 4 : for (size_t i = 0; i < 3; i++)
255 : {
256 3 : GNUNET_break (0 ==
257 : TALER_amount_cmp (&aamount[i],
258 : &pamount[i]));
259 : }
260 1 : GNUNET_break (2 == npamountc);
261 3 : for (size_t i = 0; i < npamountc; i++)
262 : {
263 2 : GNUNET_break (0 ==
264 : TALER_amount_cmp (&aamountc[i],
265 : &pamountc[i]));
266 : }
267 1 : GNUNET_break (0 ==
268 : TALER_amount_cmp (&tamountc,
269 : &tamountc2));
270 1 : GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2));
271 3 : for (size_t i = 0; i < 2; i++)
272 : {
273 2 : GNUNET_break (0 ==
274 : GNUNET_memcmp (&hcs[i],
275 : &hcs2[i]));
276 : }
277 1 : GNUNET_break (5 == n_rpubs);
278 6 : for (uint8_t i = 0; i < 5; i++)
279 : {
280 5 : GNUNET_break (0 ==
281 : GNUNET_memcmp (&in_cs_r_pubs[i],
282 : &out_cs_r_pubs[i]));
283 5 : printf ("out_cs_r_pubs[%d]=%s\n",
284 : i,
285 : GNUNET_STRINGS_data_to_string_alloc (
286 5 : &out_cs_r_pubs[i],
287 : sizeof(out_cs_r_pubs[i])));
288 : }
289 1 : GNUNET_PQ_cleanup_result (results_select);
290 : }
291 1 : return 0;
292 : }
293 :
294 :
295 : int
296 1 : main (int argc,
297 : const char *const argv[])
298 : {
299 1 : struct GNUNET_PQ_ExecuteStatement es[] = {
300 1 : GNUNET_PQ_make_execute ("DO $$ "
301 : " BEGIN"
302 : " CREATE SCHEMA IF NOT EXISTS merchant;"
303 : " END "
304 : "$$;"),
305 1 : GNUNET_PQ_make_execute ("DO $$ "
306 : " BEGIN"
307 : " CREATE DOMAIN gnunet_hashcode AS BYTEA"
308 : " CHECK(length(VALUE)=64);"
309 : " EXCEPTION"
310 : " WHEN duplicate_object THEN null;"
311 : " END "
312 : "$$;"),
313 1 : GNUNET_PQ_make_execute ("DO $$ "
314 : " BEGIN"
315 : " CREATE TYPE taler_amount AS"
316 : " (val INT8, frac INT4);"
317 : " EXCEPTION"
318 : " WHEN duplicate_object THEN null;"
319 : " END "
320 : "$$;"),
321 1 : GNUNET_PQ_make_execute ("DO $$ "
322 : " BEGIN"
323 : " CREATE TYPE merchant.taler_amount_currency AS"
324 : " (val INT8, frac INT4, curr VARCHAR(12));"
325 : " EXCEPTION"
326 : " WHEN duplicate_object THEN null;"
327 : " END "
328 : "$$;"),
329 1 : GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
330 : "tamount taler_amount NOT NULL"
331 : ",json VARCHAR NOT NULL"
332 : ",aamount taler_amount[]"
333 : ",aamountc merchant.taler_amount_currency[]"
334 : ",aamountn taler_amount[] NOT NULL DEFAULT ARRAY[]::taler_amount[]"
335 : ",aamountnc merchant.taler_amount_currency[] NOT NULL DEFAULT ARRAY[]::merchant.taler_amount_currency[]"
336 : ",tamountc merchant.taler_amount_currency"
337 : ",hash gnunet_hashcode"
338 : ",hashes gnunet_hashcode[]"
339 : ",cs_r_pubs BYTEA[]"
340 : ")"),
341 : GNUNET_PQ_EXECUTE_STATEMENT_END
342 : };
343 : struct GNUNET_PQ_Context *conn;
344 : int ret;
345 : struct GNUNET_CONFIGURATION_Handle *cfg;
346 :
347 : (void) argc;
348 : (void) argv;
349 1 : GNUNET_log_setup ("test-pq",
350 : "WARNING",
351 : NULL);
352 1 : cfg = GNUNET_CONFIGURATION_create (
353 : TALER_EXCHANGE_project_data ());
354 1 : GNUNET_CONFIGURATION_set_value_string (cfg,
355 : "test-pq",
356 : "CONFIG",
357 : "postgres:///talercheck");
358 : /* just to squash warning */
359 1 : GNUNET_CONFIGURATION_set_value_string (cfg,
360 : "test-pq",
361 : "SQL_DIR",
362 : "none");
363 1 : conn = GNUNET_PQ_init (cfg,
364 : "test-pq",
365 : NULL,
366 : NULL);
367 1 : GNUNET_CONFIGURATION_destroy (cfg);
368 1 : if (NULL == conn)
369 0 : return 77;
370 1 : GNUNET_assert (GNUNET_OK ==
371 : GNUNET_PQ_exec_statements (conn,
372 : es));
373 1 : if (GNUNET_OK !=
374 1 : postgres_prepare (conn))
375 : {
376 0 : GNUNET_break (0);
377 0 : GNUNET_PQ_disconnect (conn);
378 0 : return 1;
379 : }
380 1 : ret = run_queries (conn);
381 : {
382 1 : struct GNUNET_PQ_ExecuteStatement ds[] = {
383 1 : GNUNET_PQ_make_execute ("DROP TABLE test_pq"),
384 : GNUNET_PQ_EXECUTE_STATEMENT_END
385 : };
386 :
387 1 : if (GNUNET_OK !=
388 1 : GNUNET_PQ_exec_statements (conn,
389 : ds))
390 : {
391 0 : fprintf (stderr,
392 : "Failed to drop table\n");
393 0 : GNUNET_PQ_disconnect (conn);
394 0 : return 1;
395 : }
396 : }
397 1 : GNUNET_PQ_disconnect (conn);
398 1 : return ret;
399 : }
400 :
401 :
402 : /* end of test_pq.c */
|