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/platform.h"
23 : #include "taler/taler_util.h"
24 : #include "taler/taler_pq_lib.h"
25 : #include <gnunet/gnunet_pq_lib.h>
26 :
27 :
28 : /**
29 : * Setup prepared statements.
30 : *
31 : * @param db database handle to initialize
32 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
33 : */
34 : static enum GNUNET_GenericReturnValue
35 1 : postgres_prepare (struct GNUNET_PQ_Context *db)
36 : {
37 1 : struct GNUNET_PQ_PreparedStatement ps[] = {
38 1 : GNUNET_PQ_make_prepare ("test_insert",
39 : "INSERT INTO test_pq ("
40 : "tamount"
41 : ",json"
42 : ",aamount"
43 : ",aamountc"
44 : ",tamountc"
45 : ",hash"
46 : ",hashes"
47 : ",cs_r_pubs"
48 : ") VALUES "
49 : "($1, $2, $3, $4, $5, $6, $7, $8);"),
50 1 : GNUNET_PQ_make_prepare ("test_select",
51 : "SELECT"
52 : " tamount"
53 : ",json"
54 : ",aamount"
55 : ",aamountc"
56 : ",aamountn"
57 : ",aamountnc"
58 : ",tamountc"
59 : ",hash"
60 : ",hashes"
61 : ",cs_r_pubs"
62 : " FROM test_pq;"),
63 : GNUNET_PQ_PREPARED_STATEMENT_END
64 : };
65 :
66 1 : return GNUNET_PQ_prepare_statements (db,
67 : ps);
68 : }
69 :
70 :
71 : /**
72 : * Run actual test queries.
73 : *
74 : * @return 0 on success
75 : */
76 : static int
77 1 : run_queries (struct GNUNET_PQ_Context *conn)
78 : {
79 : struct TALER_Amount tamount;
80 : struct TALER_Amount aamount[3];
81 : struct TALER_Amount aamountc[2];
82 : struct TALER_Amount tamountc;
83 1 : struct GNUNET_HashCode hc =
84 : {{0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef,
85 : 0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef,
86 : 0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef,
87 : 0xdeadbeef,0xdeadbeef,0xdeadbeef,0xdeadbeef, }};
88 1 : struct GNUNET_HashCode hcs[2] =
89 : {{{0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,
90 : 0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,
91 : 0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,
92 : 0xc0feec0f,0xc0feec0f,0xc0feec0f,0xc0feec0f,}},
93 : {{0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,
94 : 0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,
95 : 0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,
96 : 0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,0xdeadbeaf,}}};
97 : struct GNUNET_CRYPTO_CSPublicRPairP in_cs_r_pubs[5];
98 : json_t *json;
99 :
100 1 : GNUNET_assert (GNUNET_OK ==
101 : TALER_string_to_amount ("EUR:5.3",
102 : &aamount[0]));
103 1 : GNUNET_assert (GNUNET_OK ==
104 : TALER_string_to_amount ("EUR:6.4",
105 : &aamount[1]));
106 1 : GNUNET_assert (GNUNET_OK ==
107 : TALER_string_to_amount ("EUR:7.5",
108 : &aamount[2]));
109 1 : GNUNET_assert (GNUNET_OK ==
110 : TALER_string_to_amount ("EUR:7.7",
111 : &tamount));
112 1 : GNUNET_assert (GNUNET_OK ==
113 : TALER_string_to_amount ("USD:3.2",
114 : &aamountc[0]));
115 1 : GNUNET_assert (GNUNET_OK ==
116 : TALER_string_to_amount ("CHF:4.5",
117 : &aamountc[1]));
118 1 : GNUNET_assert (GNUNET_OK ==
119 : TALER_string_to_amount ("FOO:8.7",
120 : &tamountc));
121 1 : json = json_object ();
122 1 : GNUNET_assert (NULL != json);
123 1 : GNUNET_assert (0 ==
124 : json_object_set_new (json,
125 : "foo",
126 : json_integer (42)));
127 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
128 : in_cs_r_pubs,
129 : sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * 5);
130 : {
131 1 : struct GNUNET_PQ_QueryParam params_insert[] = {
132 1 : TALER_PQ_query_param_amount (conn,
133 : &tamount),
134 1 : TALER_PQ_query_param_json (json),
135 1 : TALER_PQ_query_param_array_amount (3,
136 : aamount,
137 : conn),
138 1 : TALER_PQ_query_param_array_amount_with_currency (2,
139 : aamountc,
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 : "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 : "aamountnc",
220 : &npamountnc,
221 : &pamountnc),
222 1 : TALER_PQ_result_spec_amount_with_currency ("tamountc",
223 : &tamountc2),
224 1 : GNUNET_PQ_result_spec_auto_from_type ("hash",
225 : &hc2),
226 1 : TALER_PQ_result_spec_array_hash_code (conn,
227 : "hashes",
228 : &nhcs,
229 : &hcs2),
230 1 : TALER_PQ_result_spec_array_cs_r_pub (conn,
231 : "cs_r_pubs",
232 : &n_rpubs,
233 : &out_cs_r_pubs),
234 : GNUNET_PQ_result_spec_end
235 : };
236 :
237 1 : if (1 !=
238 1 : GNUNET_PQ_eval_prepared_singleton_select (conn,
239 : "test_select",
240 : params_select,
241 : results_select))
242 : {
243 0 : GNUNET_break (0);
244 0 : return 1;
245 : }
246 1 : GNUNET_break (0 ==
247 : TALER_amount_cmp (&tamount,
248 : &tamount2));
249 1 : GNUNET_break (42 ==
250 : json_integer_value (json_object_get (json2,
251 : "foo")));
252 1 : GNUNET_break (3 == npamount);
253 4 : for (size_t i = 0; i < 3; i++)
254 : {
255 3 : GNUNET_break (0 ==
256 : TALER_amount_cmp (&aamount[i],
257 : &pamount[i]));
258 : }
259 1 : GNUNET_break (2 == npamountc);
260 3 : for (size_t i = 0; i < npamountc; i++)
261 : {
262 2 : GNUNET_break (0 ==
263 : TALER_amount_cmp (&aamountc[i],
264 : &pamountc[i]));
265 : }
266 1 : GNUNET_break (0 ==
267 : TALER_amount_cmp (&tamountc,
268 : &tamountc2));
269 1 : GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2));
270 3 : for (size_t i = 0; i < 2; i++)
271 : {
272 2 : GNUNET_break (0 ==
273 : GNUNET_memcmp (&hcs[i],
274 : &hcs2[i]));
275 : }
276 1 : GNUNET_break (5 == n_rpubs);
277 6 : for (uint8_t i = 0; i < 5; i++)
278 : {
279 5 : GNUNET_break (0 ==
280 : GNUNET_memcmp (&in_cs_r_pubs[i],
281 : &out_cs_r_pubs[i]));
282 5 : printf ("out_cs_r_pubs[%d]=%s\n",
283 : i,
284 : GNUNET_STRINGS_data_to_string_alloc (
285 5 : &out_cs_r_pubs[i],
286 : sizeof(out_cs_r_pubs[i])));
287 : }
288 1 : GNUNET_PQ_cleanup_result (results_select);
289 : }
290 1 : return 0;
291 : }
292 :
293 :
294 : int
295 1 : main (int argc,
296 : const char *const argv[])
297 : {
298 1 : struct GNUNET_PQ_ExecuteStatement es[] = {
299 1 : GNUNET_PQ_make_execute ("DO $$ "
300 : " BEGIN"
301 : " CREATE DOMAIN gnunet_hashcode AS BYTEA"
302 : " CHECK(length(VALUE)=64);"
303 : " EXCEPTION"
304 : " WHEN duplicate_object THEN null;"
305 : " END "
306 : "$$;"),
307 1 : GNUNET_PQ_make_execute ("DO $$ "
308 : " BEGIN"
309 : " CREATE TYPE taler_amount AS"
310 : " (val INT8, frac INT4);"
311 : " EXCEPTION"
312 : " WHEN duplicate_object THEN null;"
313 : " END "
314 : "$$;"),
315 1 : GNUNET_PQ_make_execute ("DO $$ "
316 : " BEGIN"
317 : " CREATE TYPE taler_amount_currency AS"
318 : " (val INT8, frac INT4, curr VARCHAR(12));"
319 : " EXCEPTION"
320 : " WHEN duplicate_object THEN null;"
321 : " END "
322 : "$$;"),
323 1 : GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
324 : "tamount taler_amount NOT NULL"
325 : ",json VARCHAR NOT NULL"
326 : ",aamount taler_amount[]"
327 : ",aamountc taler_amount_currency[]"
328 : ",aamountn taler_amount[] NOT NULL DEFAULT ARRAY[]::taler_amount[]"
329 : ",aamountnc taler_amount_currency[] NOT NULL DEFAULT ARRAY[]::taler_amount_currency[]"
330 : ",tamountc taler_amount_currency"
331 : ",hash gnunet_hashcode"
332 : ",hashes gnunet_hashcode[]"
333 : ",cs_r_pubs BYTEA[]"
334 : ")"),
335 : GNUNET_PQ_EXECUTE_STATEMENT_END
336 : };
337 : struct GNUNET_PQ_Context *conn;
338 : int ret;
339 :
340 : (void) argc;
341 : (void) argv;
342 1 : GNUNET_log_setup ("test-pq",
343 : "WARNING",
344 : NULL);
345 1 : conn = GNUNET_PQ_connect ("postgres:///talercheck",
346 : NULL,
347 : es,
348 : NULL);
349 1 : if (NULL == conn)
350 0 : return 77;
351 1 : if (GNUNET_OK !=
352 1 : postgres_prepare (conn))
353 : {
354 0 : GNUNET_break (0);
355 0 : GNUNET_PQ_disconnect (conn);
356 0 : return 1;
357 : }
358 :
359 1 : ret = run_queries (conn);
360 : {
361 1 : struct GNUNET_PQ_ExecuteStatement ds[] = {
362 1 : GNUNET_PQ_make_execute ("DROP TABLE test_pq"),
363 : GNUNET_PQ_EXECUTE_STATEMENT_END
364 : };
365 :
366 1 : if (GNUNET_OK !=
367 1 : GNUNET_PQ_exec_statements (conn,
368 : ds))
369 : {
370 0 : fprintf (stderr,
371 : "Failed to drop table\n");
372 0 : GNUNET_PQ_disconnect (conn);
373 0 : return 1;
374 : }
375 : }
376 1 : GNUNET_PQ_disconnect (conn);
377 1 : return ret;
378 : }
379 :
380 :
381 : /* end of test_pq.c */
|