test_pq.c (14071B)
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 postgres_prepare (struct GNUNET_PQ_Context *db) 35 { 36 struct GNUNET_PQ_PreparedStatement ps[] = { 37 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 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 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 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 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 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 GNUNET_assert (GNUNET_OK == 100 TALER_string_to_amount ("EUR:5.3", 101 &aamount[0])); 102 GNUNET_assert (GNUNET_OK == 103 TALER_string_to_amount ("EUR:6.4", 104 &aamount[1])); 105 GNUNET_assert (GNUNET_OK == 106 TALER_string_to_amount ("EUR:7.5", 107 &aamount[2])); 108 GNUNET_assert (GNUNET_OK == 109 TALER_string_to_amount ("EUR:7.7", 110 &tamount)); 111 GNUNET_assert (GNUNET_OK == 112 TALER_string_to_amount ("USD:3.2", 113 &aamountc[0])); 114 GNUNET_assert (GNUNET_OK == 115 TALER_string_to_amount ("CHF:4.5", 116 &aamountc[1])); 117 GNUNET_assert (GNUNET_OK == 118 TALER_string_to_amount ("FOO:8.7", 119 &tamountc)); 120 json = json_object (); 121 GNUNET_assert (NULL != json); 122 GNUNET_assert (0 == 123 json_object_set_new (json, 124 "foo", 125 json_integer (42))); 126 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 127 in_cs_r_pubs, 128 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * 5); 129 { 130 struct GNUNET_PQ_QueryParam params_insert[] = { 131 TALER_PQ_query_param_amount (conn, 132 &tamount), 133 TALER_PQ_query_param_json (json), 134 TALER_PQ_query_param_array_amount (3, 135 aamount, 136 conn), 137 TALER_PQ_query_param_array_amount_with_currency (2, 138 aamountc, 139 conn), 140 TALER_PQ_query_param_amount_with_currency (conn, 141 &tamountc), 142 GNUNET_PQ_query_param_fixed_size (&hc, 143 sizeof (hc)), 144 TALER_PQ_query_param_array_hash_code (2, 145 hcs, 146 conn), 147 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 result = GNUNET_PQ_exec_prepared (conn, 155 "test_insert", 156 params_insert); 157 for (uint8_t i = 0; i < 5; i++) 158 { 159 printf (" in_cs_r_pubs[%d]=%s\n", 160 i, 161 GNUNET_STRINGS_data_to_string_alloc ( 162 &in_cs_r_pubs[i], 163 sizeof(in_cs_r_pubs[i]))); 164 } 165 166 if (PGRES_COMMAND_OK != PQresultStatus (result)) 167 { 168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 169 "Database failure: %s\n", 170 PQresultErrorMessage (result)); 171 PQclear (result); 172 return 1; 173 } 174 PQclear (result); 175 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 struct GNUNET_PQ_QueryParam params_select[] = { 195 GNUNET_PQ_query_param_end 196 }; 197 struct GNUNET_PQ_ResultSpec results_select[] = { 198 TALER_PQ_result_spec_amount ("tamount", 199 "EUR", 200 &tamount2), 201 TALER_PQ_result_spec_json ("json", 202 &json2), 203 TALER_PQ_result_spec_array_amount (conn, 204 "aamount", 205 "EUR", 206 &npamount, 207 &pamount), 208 TALER_PQ_result_spec_array_amount_with_currency (conn, 209 NULL, 210 "aamountc", 211 &npamountc, 212 &pamountc), 213 TALER_PQ_result_spec_array_amount (conn, 214 "aamountn", 215 "EUR", 216 &npamountn, 217 &pamountn), 218 TALER_PQ_result_spec_array_amount_with_currency (conn, 219 NULL, 220 "aamountnc", 221 &npamountnc, 222 &pamountnc), 223 TALER_PQ_result_spec_amount_with_currency ("tamountc", 224 &tamountc2), 225 GNUNET_PQ_result_spec_auto_from_type ("hash", 226 &hc2), 227 TALER_PQ_result_spec_array_hash_code (conn, 228 "hashes", 229 &nhcs, 230 &hcs2), 231 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 if (1 != 239 GNUNET_PQ_eval_prepared_singleton_select (conn, 240 "test_select", 241 params_select, 242 results_select)) 243 { 244 GNUNET_break (0); 245 return 1; 246 } 247 GNUNET_break (0 == 248 TALER_amount_cmp (&tamount, 249 &tamount2)); 250 GNUNET_break (42 == 251 json_integer_value (json_object_get (json2, 252 "foo"))); 253 GNUNET_break (3 == npamount); 254 for (size_t i = 0; i < 3; i++) 255 { 256 GNUNET_break (0 == 257 TALER_amount_cmp (&aamount[i], 258 &pamount[i])); 259 } 260 GNUNET_break (2 == npamountc); 261 for (size_t i = 0; i < npamountc; i++) 262 { 263 GNUNET_break (0 == 264 TALER_amount_cmp (&aamountc[i], 265 &pamountc[i])); 266 } 267 GNUNET_break (0 == 268 TALER_amount_cmp (&tamountc, 269 &tamountc2)); 270 GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2)); 271 for (size_t i = 0; i < 2; i++) 272 { 273 GNUNET_break (0 == 274 GNUNET_memcmp (&hcs[i], 275 &hcs2[i])); 276 } 277 GNUNET_break (5 == n_rpubs); 278 for (uint8_t i = 0; i < 5; i++) 279 { 280 GNUNET_break (0 == 281 GNUNET_memcmp (&in_cs_r_pubs[i], 282 &out_cs_r_pubs[i])); 283 printf ("out_cs_r_pubs[%d]=%s\n", 284 i, 285 GNUNET_STRINGS_data_to_string_alloc ( 286 &out_cs_r_pubs[i], 287 sizeof(out_cs_r_pubs[i]))); 288 } 289 GNUNET_PQ_cleanup_result (results_select); 290 } 291 return 0; 292 } 293 294 295 int 296 main (int argc, 297 const char *const argv[]) 298 { 299 struct GNUNET_PQ_ExecuteStatement es[] = { 300 GNUNET_PQ_make_execute ("DO $$ " 301 " BEGIN" 302 " CREATE DOMAIN gnunet_hashcode AS BYTEA" 303 " CHECK(length(VALUE)=64);" 304 " EXCEPTION" 305 " WHEN duplicate_object THEN null;" 306 " END " 307 "$$;"), 308 GNUNET_PQ_make_execute ("DO $$ " 309 " BEGIN" 310 " CREATE TYPE taler_amount AS" 311 " (val INT8, frac INT4);" 312 " EXCEPTION" 313 " WHEN duplicate_object THEN null;" 314 " END " 315 "$$;"), 316 GNUNET_PQ_make_execute ("DO $$ " 317 " BEGIN" 318 " CREATE TYPE taler_amount_currency AS" 319 " (val INT8, frac INT4, curr VARCHAR(12));" 320 " EXCEPTION" 321 " WHEN duplicate_object THEN null;" 322 " END " 323 "$$;"), 324 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" 325 "tamount taler_amount NOT NULL" 326 ",json VARCHAR NOT NULL" 327 ",aamount taler_amount[]" 328 ",aamountc taler_amount_currency[]" 329 ",aamountn taler_amount[] NOT NULL DEFAULT ARRAY[]::taler_amount[]" 330 ",aamountnc taler_amount_currency[] NOT NULL DEFAULT ARRAY[]::taler_amount_currency[]" 331 ",tamountc taler_amount_currency" 332 ",hash gnunet_hashcode" 333 ",hashes gnunet_hashcode[]" 334 ",cs_r_pubs BYTEA[]" 335 ")"), 336 GNUNET_PQ_EXECUTE_STATEMENT_END 337 }; 338 struct GNUNET_PQ_Context *conn; 339 int ret; 340 341 (void) argc; 342 (void) argv; 343 GNUNET_log_setup ("test-pq", 344 "WARNING", 345 NULL); 346 conn = GNUNET_PQ_connect ("postgres:///talercheck", 347 NULL, 348 es, 349 NULL); 350 if (NULL == conn) 351 return 77; 352 if (GNUNET_OK != 353 postgres_prepare (conn)) 354 { 355 GNUNET_break (0); 356 GNUNET_PQ_disconnect (conn); 357 return 1; 358 } 359 360 ret = run_queries (conn); 361 { 362 struct GNUNET_PQ_ExecuteStatement ds[] = { 363 GNUNET_PQ_make_execute ("DROP TABLE test_pq"), 364 GNUNET_PQ_EXECUTE_STATEMENT_END 365 }; 366 367 if (GNUNET_OK != 368 GNUNET_PQ_exec_statements (conn, 369 ds)) 370 { 371 fprintf (stderr, 372 "Failed to drop table\n"); 373 GNUNET_PQ_disconnect (conn); 374 return 1; 375 } 376 } 377 GNUNET_PQ_disconnect (conn); 378 return ret; 379 } 380 381 382 /* end of test_pq.c */