test_pq.c (13977B)
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 postgres_prepare (struct GNUNET_PQ_Context *db) 36 { 37 struct GNUNET_PQ_PreparedStatement ps[] = { 38 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 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 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 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 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 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 GNUNET_assert (GNUNET_OK == 101 TALER_string_to_amount ("EUR:5.3", 102 &aamount[0])); 103 GNUNET_assert (GNUNET_OK == 104 TALER_string_to_amount ("EUR:6.4", 105 &aamount[1])); 106 GNUNET_assert (GNUNET_OK == 107 TALER_string_to_amount ("EUR:7.5", 108 &aamount[2])); 109 GNUNET_assert (GNUNET_OK == 110 TALER_string_to_amount ("EUR:7.7", 111 &tamount)); 112 GNUNET_assert (GNUNET_OK == 113 TALER_string_to_amount ("USD:3.2", 114 &aamountc[0])); 115 GNUNET_assert (GNUNET_OK == 116 TALER_string_to_amount ("CHF:4.5", 117 &aamountc[1])); 118 GNUNET_assert (GNUNET_OK == 119 TALER_string_to_amount ("FOO:8.7", 120 &tamountc)); 121 json = json_object (); 122 GNUNET_assert (NULL != json); 123 GNUNET_assert (0 == 124 json_object_set_new (json, 125 "foo", 126 json_integer (42))); 127 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 128 in_cs_r_pubs, 129 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * 5); 130 { 131 struct GNUNET_PQ_QueryParam params_insert[] = { 132 TALER_PQ_query_param_amount (conn, 133 &tamount), 134 TALER_PQ_query_param_json (json), 135 TALER_PQ_query_param_array_amount (3, 136 aamount, 137 conn), 138 TALER_PQ_query_param_array_amount_with_currency (2, 139 aamountc, 140 conn), 141 TALER_PQ_query_param_amount_with_currency (conn, 142 &tamountc), 143 GNUNET_PQ_query_param_fixed_size (&hc, 144 sizeof (hc)), 145 TALER_PQ_query_param_array_hash_code (2, 146 hcs, 147 conn), 148 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 result = GNUNET_PQ_exec_prepared (conn, 156 "test_insert", 157 params_insert); 158 for (uint8_t i = 0; i < 5; i++) 159 { 160 printf (" in_cs_r_pubs[%d]=%s\n", 161 i, 162 GNUNET_STRINGS_data_to_string_alloc ( 163 &in_cs_r_pubs[i], 164 sizeof(in_cs_r_pubs[i]))); 165 } 166 167 if (PGRES_COMMAND_OK != PQresultStatus (result)) 168 { 169 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 170 "Database failure: %s\n", 171 PQresultErrorMessage (result)); 172 PQclear (result); 173 return 1; 174 } 175 PQclear (result); 176 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 struct GNUNET_PQ_QueryParam params_select[] = { 196 GNUNET_PQ_query_param_end 197 }; 198 struct GNUNET_PQ_ResultSpec results_select[] = { 199 TALER_PQ_result_spec_amount ("tamount", 200 "EUR", 201 &tamount2), 202 TALER_PQ_result_spec_json ("json", 203 &json2), 204 TALER_PQ_result_spec_array_amount (conn, 205 "aamount", 206 "EUR", 207 &npamount, 208 &pamount), 209 TALER_PQ_result_spec_array_amount_with_currency (conn, 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 "aamountnc", 220 &npamountnc, 221 &pamountnc), 222 TALER_PQ_result_spec_amount_with_currency ("tamountc", 223 &tamountc2), 224 GNUNET_PQ_result_spec_auto_from_type ("hash", 225 &hc2), 226 TALER_PQ_result_spec_array_hash_code (conn, 227 "hashes", 228 &nhcs, 229 &hcs2), 230 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 if (1 != 238 GNUNET_PQ_eval_prepared_singleton_select (conn, 239 "test_select", 240 params_select, 241 results_select)) 242 { 243 GNUNET_break (0); 244 return 1; 245 } 246 GNUNET_break (0 == 247 TALER_amount_cmp (&tamount, 248 &tamount2)); 249 GNUNET_break (42 == 250 json_integer_value (json_object_get (json2, 251 "foo"))); 252 GNUNET_break (3 == npamount); 253 for (size_t i = 0; i < 3; i++) 254 { 255 GNUNET_break (0 == 256 TALER_amount_cmp (&aamount[i], 257 &pamount[i])); 258 } 259 GNUNET_break (2 == npamountc); 260 for (size_t i = 0; i < npamountc; i++) 261 { 262 GNUNET_break (0 == 263 TALER_amount_cmp (&aamountc[i], 264 &pamountc[i])); 265 } 266 GNUNET_break (0 == 267 TALER_amount_cmp (&tamountc, 268 &tamountc2)); 269 GNUNET_break (0 == GNUNET_memcmp (&hc,&hc2)); 270 for (size_t i = 0; i < 2; i++) 271 { 272 GNUNET_break (0 == 273 GNUNET_memcmp (&hcs[i], 274 &hcs2[i])); 275 } 276 GNUNET_break (5 == n_rpubs); 277 for (uint8_t i = 0; i < 5; i++) 278 { 279 GNUNET_break (0 == 280 GNUNET_memcmp (&in_cs_r_pubs[i], 281 &out_cs_r_pubs[i])); 282 printf ("out_cs_r_pubs[%d]=%s\n", 283 i, 284 GNUNET_STRINGS_data_to_string_alloc ( 285 &out_cs_r_pubs[i], 286 sizeof(out_cs_r_pubs[i]))); 287 } 288 GNUNET_PQ_cleanup_result (results_select); 289 } 290 return 0; 291 } 292 293 294 int 295 main (int argc, 296 const char *const argv[]) 297 { 298 struct GNUNET_PQ_ExecuteStatement es[] = { 299 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 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 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 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 GNUNET_log_setup ("test-pq", 343 "WARNING", 344 NULL); 345 conn = GNUNET_PQ_connect ("postgres:///talercheck", 346 NULL, 347 es, 348 NULL); 349 if (NULL == conn) 350 return 77; 351 if (GNUNET_OK != 352 postgres_prepare (conn)) 353 { 354 GNUNET_break (0); 355 GNUNET_PQ_disconnect (conn); 356 return 1; 357 } 358 359 ret = run_queries (conn); 360 { 361 struct GNUNET_PQ_ExecuteStatement ds[] = { 362 GNUNET_PQ_make_execute ("DROP TABLE test_pq"), 363 GNUNET_PQ_EXECUTE_STATEMENT_END 364 }; 365 366 if (GNUNET_OK != 367 GNUNET_PQ_exec_statements (conn, 368 ds)) 369 { 370 fprintf (stderr, 371 "Failed to drop table\n"); 372 GNUNET_PQ_disconnect (conn); 373 return 1; 374 } 375 } 376 GNUNET_PQ_disconnect (conn); 377 return ret; 378 } 379 380 381 /* end of test_pq.c */