test_pq.c (13949B)
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 "aamountc", 210 &npamountc, 211 &pamountc), 212 TALER_PQ_result_spec_array_amount (conn, 213 "aamountn", 214 "EUR", 215 &npamountn, 216 &pamountn), 217 TALER_PQ_result_spec_array_amount_with_currency (conn, 218 "aamountnc", 219 &npamountnc, 220 &pamountnc), 221 TALER_PQ_result_spec_amount_with_currency ("tamountc", 222 &tamountc2), 223 GNUNET_PQ_result_spec_auto_from_type ("hash", 224 &hc2), 225 TALER_PQ_result_spec_array_hash_code (conn, 226 "hashes", 227 &nhcs, 228 &hcs2), 229 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 if (1 != 237 GNUNET_PQ_eval_prepared_singleton_select (conn, 238 "test_select", 239 params_select, 240 results_select)) 241 { 242 GNUNET_break (0); 243 return 1; 244 } 245 GNUNET_break (0 == 246 TALER_amount_cmp (&tamount, 247 &tamount2)); 248 GNUNET_break (42 == 249 json_integer_value (json_object_get (json2, 250 "foo"))); 251 GNUNET_break (3 == npamount); 252 for (size_t i = 0; i < 3; i++) 253 { 254 GNUNET_break (0 == 255 TALER_amount_cmp (&aamount[i], 256 &pamount[i])); 257 } 258 GNUNET_break (2 == npamountc); 259 for (size_t i = 0; i < npamountc; i++) 260 { 261 GNUNET_break (0 == 262 TALER_amount_cmp (&aamountc[i], 263 &pamountc[i])); 264 } 265 GNUNET_break (0 == 266 TALER_amount_cmp (&tamountc, 267 &tamountc2)); 268 GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2)); 269 for (size_t i = 0; i < 2; i++) 270 { 271 GNUNET_break (0 == 272 GNUNET_memcmp (&hcs[i], 273 &hcs2[i])); 274 } 275 GNUNET_break (5 == n_rpubs); 276 for (uint8_t i = 0; i < 5; i++) 277 { 278 GNUNET_break (0 == 279 GNUNET_memcmp (&in_cs_r_pubs[i], 280 &out_cs_r_pubs[i])); 281 printf ("out_cs_r_pubs[%d]=%s\n", 282 i, 283 GNUNET_STRINGS_data_to_string_alloc ( 284 &out_cs_r_pubs[i], 285 sizeof(out_cs_r_pubs[i]))); 286 } 287 GNUNET_PQ_cleanup_result (results_select); 288 } 289 return 0; 290 } 291 292 293 int 294 main (int argc, 295 const char *const argv[]) 296 { 297 struct GNUNET_PQ_ExecuteStatement es[] = { 298 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 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 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 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 GNUNET_log_setup ("test-pq", 342 "WARNING", 343 NULL); 344 conn = GNUNET_PQ_connect ("postgres:///talercheck", 345 NULL, 346 es, 347 NULL); 348 if (NULL == conn) 349 return 77; 350 if (GNUNET_OK != 351 postgres_prepare (conn)) 352 { 353 GNUNET_break (0); 354 GNUNET_PQ_disconnect (conn); 355 return 1; 356 } 357 358 ret = run_queries (conn); 359 { 360 struct GNUNET_PQ_ExecuteStatement ds[] = { 361 GNUNET_PQ_make_execute ("DROP TABLE test_pq"), 362 GNUNET_PQ_EXECUTE_STATEMENT_END 363 }; 364 365 if (GNUNET_OK != 366 GNUNET_PQ_exec_statements (conn, 367 ds)) 368 { 369 fprintf (stderr, 370 "Failed to drop table\n"); 371 GNUNET_PQ_disconnect (conn); 372 return 1; 373 } 374 } 375 GNUNET_PQ_disconnect (conn); 376 return ret; 377 } 378 379 380 /* end of test_pq.c */