Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2014--2021 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Lesser 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 ANASTASISABILITY 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 sync/plugin_syncdb_postgres.c
18 : * @brief database helper functions for postgres used by sync
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include <gnunet/gnunet_db_lib.h>
24 : #include <gnunet/gnunet_pq_lib.h>
25 : #include <taler/taler_pq_lib.h>
26 : #include "sync_database_plugin.h"
27 : #include "sync_database_lib.h"
28 :
29 : /**
30 : * Type of the "cls" argument given to each of the functions in
31 : * our API.
32 : */
33 : struct PostgresClosure
34 : {
35 :
36 : /**
37 : * Postgres connection handle.
38 : */
39 : struct GNUNET_PQ_Context *conn;
40 :
41 : /**
42 : * Directory with SQL statements to run to create tables.
43 : */
44 : char *sql_dir;
45 :
46 : /**
47 : * Underlying configuration.
48 : */
49 : const struct GNUNET_CONFIGURATION_Handle *cfg;
50 :
51 : /**
52 : * Name of the currently active transaction, NULL if none is active.
53 : */
54 : const char *transaction_name;
55 :
56 : /**
57 : * Currency we accept payments in.
58 : */
59 : char *currency;
60 :
61 : /**
62 : * Did we initialize the prepared statements
63 : * for this session?
64 : */
65 : bool init;
66 :
67 : };
68 :
69 :
70 : /**
71 : * Drop sync tables
72 : *
73 : * @param cls closure our `struct Plugin`
74 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
75 : */
76 : static enum GNUNET_GenericReturnValue
77 0 : postgres_drop_tables (void *cls)
78 : {
79 0 : struct PostgresClosure *pg = cls;
80 : struct GNUNET_PQ_Context *conn;
81 : enum GNUNET_GenericReturnValue ret;
82 :
83 0 : if (NULL != pg->conn)
84 : {
85 0 : GNUNET_PQ_disconnect (pg->conn);
86 0 : pg->conn = NULL;
87 0 : pg->init = false;
88 : }
89 0 : conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
90 : "syncdb-postgres",
91 : NULL,
92 : NULL,
93 : NULL);
94 0 : if (NULL == conn)
95 0 : return GNUNET_SYSERR;
96 0 : ret = GNUNET_PQ_exec_sql (conn,
97 : "drop");
98 0 : GNUNET_PQ_disconnect (conn);
99 0 : return ret;
100 : }
101 :
102 :
103 : /**
104 : * Establish connection to the database.
105 : *
106 : * @param cls plugin context
107 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
108 : */
109 : static enum GNUNET_GenericReturnValue
110 0 : prepare_statements (void *cls)
111 : {
112 0 : struct PostgresClosure *pg = cls;
113 0 : struct GNUNET_PQ_PreparedStatement ps[] = {
114 0 : GNUNET_PQ_make_prepare ("account_insert",
115 : "INSERT INTO accounts "
116 : "(account_pub"
117 : ",expiration_date"
118 : ") VALUES "
119 : "($1,$2);",
120 : 2),
121 0 : GNUNET_PQ_make_prepare ("payment_insert",
122 : "INSERT INTO payments "
123 : "(account_pub"
124 : ",order_id"
125 : ",token"
126 : ",timestamp"
127 : ",amount_val"
128 : ",amount_frac"
129 : ") VALUES "
130 : "($1,$2,$3,$4,$5,$6);",
131 : 6),
132 0 : GNUNET_PQ_make_prepare ("payment_done",
133 : "UPDATE payments "
134 : "SET"
135 : " paid=TRUE "
136 : "WHERE"
137 : " order_id=$1"
138 : " AND"
139 : " account_pub=$2"
140 : " AND"
141 : " paid=FALSE;",
142 : 2),
143 0 : GNUNET_PQ_make_prepare ("account_update",
144 : "UPDATE accounts "
145 : "SET"
146 : " expiration_date=$1 "
147 : "WHERE"
148 : " account_pub=$2;",
149 : 2),
150 0 : GNUNET_PQ_make_prepare ("account_select",
151 : "SELECT"
152 : " expiration_date "
153 : "FROM"
154 : " accounts "
155 : "WHERE"
156 : " account_pub=$1;",
157 : 1),
158 0 : GNUNET_PQ_make_prepare ("payments_select",
159 : "SELECT"
160 : " account_pub"
161 : ",order_id"
162 : ",amount_val"
163 : ",amount_frac"
164 : " FROM payments"
165 : " WHERE paid=FALSE;",
166 : 0),
167 0 : GNUNET_PQ_make_prepare ("payments_select_by_account",
168 : "SELECT"
169 : " timestamp"
170 : ",order_id"
171 : ",token"
172 : ",amount_val"
173 : ",amount_frac"
174 : " FROM payments"
175 : " WHERE"
176 : " paid=FALSE"
177 : " AND"
178 : " account_pub=$1;",
179 : 1),
180 0 : GNUNET_PQ_make_prepare ("gc_accounts",
181 : "DELETE FROM accounts "
182 : "WHERE"
183 : " expiration_date < $1;",
184 : 1),
185 0 : GNUNET_PQ_make_prepare ("gc_pending_payments",
186 : "DELETE FROM payments "
187 : "WHERE"
188 : " paid=FALSE"
189 : " AND"
190 : " timestamp < $1;",
191 : 1),
192 0 : GNUNET_PQ_make_prepare ("backup_insert",
193 : "INSERT INTO backups "
194 : "(account_pub"
195 : ",account_sig"
196 : ",prev_hash"
197 : ",backup_hash"
198 : ",data"
199 : ") VALUES "
200 : "($1,$2,$3,$4,$5);",
201 : 5),
202 0 : GNUNET_PQ_make_prepare ("backup_update",
203 : "UPDATE backups "
204 : " SET"
205 : " backup_hash=$1"
206 : ",account_sig=$2"
207 : ",prev_hash=$3"
208 : ",data=$4"
209 : " WHERE"
210 : " account_pub=$5"
211 : " AND"
212 : " backup_hash=$6;",
213 : 6),
214 0 : GNUNET_PQ_make_prepare ("backup_select_hash",
215 : "SELECT "
216 : " backup_hash "
217 : "FROM"
218 : " backups "
219 : "WHERE"
220 : " account_pub=$1;",
221 : 1),
222 0 : GNUNET_PQ_make_prepare ("backup_select",
223 : "SELECT "
224 : " account_sig"
225 : ",prev_hash"
226 : ",backup_hash"
227 : ",data "
228 : "FROM"
229 : " backups "
230 : "WHERE"
231 : " account_pub=$1;",
232 : 1),
233 0 : GNUNET_PQ_make_prepare ("do_commit",
234 : "COMMIT",
235 : 0),
236 : GNUNET_PQ_PREPARED_STATEMENT_END
237 : };
238 : enum GNUNET_GenericReturnValue ret;
239 :
240 0 : ret = GNUNET_PQ_prepare_statements (pg->conn,
241 : ps);
242 0 : if (GNUNET_OK != ret)
243 0 : return ret;
244 0 : pg->init = true;
245 0 : return GNUNET_OK;
246 : }
247 :
248 :
249 : /**
250 : * Connect to the database if the connection does not exist yet.
251 : *
252 : * @param pg the plugin-specific state
253 : * @param skip_prepare true if we should skip prepared statement setup
254 : * @return #GNUNET_OK on success
255 : */
256 : static enum GNUNET_GenericReturnValue
257 1 : internal_setup (struct PostgresClosure *pg,
258 : bool skip_prepare)
259 : {
260 1 : if (NULL == pg->conn)
261 : {
262 : #if AUTO_EXPLAIN
263 : /* Enable verbose logging to see where queries do not
264 : properly use indices */
265 : struct GNUNET_PQ_ExecuteStatement es[] = {
266 : GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
267 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
268 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
269 : GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
270 : /* https://wiki.postgresql.org/wiki/Serializable suggests to really
271 : force the default to 'serializable' if SSI is to be used. */
272 : GNUNET_PQ_make_try_execute (
273 : "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
274 : GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
275 : GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
276 : GNUNET_PQ_EXECUTE_STATEMENT_END
277 : };
278 : #else
279 1 : struct GNUNET_PQ_ExecuteStatement *es = NULL;
280 : #endif
281 : struct GNUNET_PQ_Context *db_conn;
282 :
283 1 : db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
284 : "syncdb-postgres",
285 : NULL,
286 : es,
287 : NULL);
288 1 : if (NULL == db_conn)
289 1 : return GNUNET_SYSERR;
290 0 : pg->conn = db_conn;
291 : }
292 0 : if (NULL == pg->transaction_name)
293 0 : GNUNET_PQ_reconnect_if_down (pg->conn);
294 0 : if (pg->init)
295 0 : return GNUNET_OK;
296 0 : if (skip_prepare)
297 0 : return GNUNET_OK;
298 0 : return prepare_statements (pg);
299 : }
300 :
301 :
302 : /**
303 : * Do a pre-flight check that we are not in an uncommitted transaction.
304 : * If we are, try to commit the previous transaction and output a warning.
305 : * Does not return anything, as we will continue regardless of the outcome.
306 : *
307 : * @param cls the `struct PostgresClosure` with the plugin-specific state
308 : * @return #GNUNET_OK if everything is fine
309 : * #GNUNET_NO if a transaction was rolled back
310 : * #GNUNET_SYSERR on hard errors
311 : */
312 : static enum GNUNET_GenericReturnValue
313 0 : postgres_preflight (void *cls)
314 : {
315 0 : struct PostgresClosure *pg = cls;
316 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
317 0 : GNUNET_PQ_make_execute ("ROLLBACK"),
318 : GNUNET_PQ_EXECUTE_STATEMENT_END
319 : };
320 :
321 0 : if (! pg->init)
322 : {
323 0 : if (GNUNET_OK !=
324 0 : internal_setup (pg,
325 : false))
326 : {
327 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328 : "Failed to ensure DB is initialized\n");
329 0 : return GNUNET_SYSERR;
330 : }
331 : }
332 0 : if (NULL == pg->transaction_name)
333 0 : return GNUNET_OK; /* all good */
334 0 : if (GNUNET_OK ==
335 0 : GNUNET_PQ_exec_statements (pg->conn,
336 : es))
337 : {
338 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
339 : "BUG: Preflight check rolled back transaction `%s'!\n",
340 : pg->transaction_name);
341 : }
342 : else
343 : {
344 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
345 : "BUG: Preflight check failed to rollback transaction `%s'!\n",
346 : pg->transaction_name);
347 : }
348 0 : pg->transaction_name = NULL;
349 0 : return GNUNET_NO;
350 : }
351 :
352 :
353 : /**
354 : * Check that the database connection is still up.
355 : *
356 : * @param cls a `struct PostgresClosure` with connection to check
357 : */
358 : static void
359 0 : check_connection (void *cls)
360 : {
361 0 : struct PostgresClosure *pg = cls;
362 :
363 0 : GNUNET_PQ_reconnect_if_down (pg->conn);
364 0 : }
365 :
366 :
367 : /**
368 : * Start a transaction.
369 : *
370 : * @param cls the `struct PostgresClosure` with the plugin-specific state
371 : * @param name unique name identifying the transaction (for debugging),
372 : * must point to a constant
373 : * @return #GNUNET_OK on success
374 : */
375 : static enum GNUNET_GenericReturnValue
376 0 : begin_transaction (void *cls,
377 : const char *name)
378 : {
379 0 : struct PostgresClosure *pg = cls;
380 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
381 0 : GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
382 : GNUNET_PQ_EXECUTE_STATEMENT_END
383 : };
384 :
385 0 : check_connection (pg);
386 0 : postgres_preflight (pg);
387 0 : pg->transaction_name = name;
388 0 : if (GNUNET_OK !=
389 0 : GNUNET_PQ_exec_statements (pg->conn,
390 : es))
391 : {
392 0 : TALER_LOG_ERROR ("Failed to start transaction\n");
393 0 : GNUNET_break (0);
394 0 : return GNUNET_SYSERR;
395 : }
396 0 : return GNUNET_OK;
397 : }
398 :
399 :
400 : /**
401 : * Roll back the current transaction of a database connection.
402 : *
403 : * @param cls the `struct PostgresClosure` with the plugin-specific state
404 : */
405 : static void
406 0 : rollback (void *cls)
407 : {
408 0 : struct PostgresClosure *pg = cls;
409 0 : struct GNUNET_PQ_ExecuteStatement es[] = {
410 0 : GNUNET_PQ_make_execute ("ROLLBACK"),
411 : GNUNET_PQ_EXECUTE_STATEMENT_END
412 : };
413 :
414 0 : if (GNUNET_OK !=
415 0 : GNUNET_PQ_exec_statements (pg->conn,
416 : es))
417 : {
418 0 : TALER_LOG_ERROR ("Failed to rollback transaction\n");
419 0 : GNUNET_break (0);
420 : }
421 0 : pg->transaction_name = NULL;
422 0 : }
423 :
424 :
425 : /**
426 : * Commit the current transaction of a database connection.
427 : *
428 : * @param cls the `struct PostgresClosure` with the plugin-specific state
429 : * @return transaction status code
430 : */
431 : static enum GNUNET_DB_QueryStatus
432 0 : commit_transaction (void *cls)
433 : {
434 0 : struct PostgresClosure *pg = cls;
435 : enum GNUNET_DB_QueryStatus qs;
436 0 : struct GNUNET_PQ_QueryParam no_params[] = {
437 : GNUNET_PQ_query_param_end
438 : };
439 :
440 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
441 : "do_commit",
442 : no_params);
443 0 : pg->transaction_name = NULL;
444 0 : return qs;
445 : }
446 :
447 :
448 : /**
449 : * Function called to perform "garbage collection" on the
450 : * database, expiring records we no longer require. Deletes
451 : * all user records that are not paid up (and by cascade deletes
452 : * the associated recovery documents). Also deletes expired
453 : * truth and financial records older than @a fin_expire.
454 : *
455 : * @param cls closure
456 : * @param expire_backups backups older than the given time stamp should be garbage collected
457 : * @param expire_pending_payments payments still pending from since before
458 : * this value should be garbage collected
459 : * @return transaction status
460 : */
461 : static enum GNUNET_DB_QueryStatus
462 0 : postgres_gc (void *cls,
463 : struct GNUNET_TIME_Absolute expire_backups,
464 : struct GNUNET_TIME_Absolute expire_pending_payments)
465 : {
466 0 : struct PostgresClosure *pg = cls;
467 0 : struct GNUNET_PQ_QueryParam params[] = {
468 0 : GNUNET_PQ_query_param_absolute_time (&expire_backups),
469 : GNUNET_PQ_query_param_end
470 : };
471 0 : struct GNUNET_PQ_QueryParam params2[] = {
472 0 : GNUNET_PQ_query_param_absolute_time (&expire_pending_payments),
473 : GNUNET_PQ_query_param_end
474 : };
475 : enum GNUNET_DB_QueryStatus qs;
476 :
477 0 : check_connection (pg);
478 0 : postgres_preflight (pg);
479 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
480 : "gc_accounts",
481 : params);
482 0 : if (qs < 0)
483 0 : return qs;
484 0 : return GNUNET_PQ_eval_prepared_non_select (pg->conn,
485 : "gc_pending_payments",
486 : params2);
487 : }
488 :
489 :
490 : /**
491 : * Store payment. Used to begin a payment, not indicative
492 : * that the payment actually was made. (That is done
493 : * when we increment the account's lifetime.)
494 : *
495 : * @param cls closure
496 : * @param account_pub account to store @a backup under
497 : * @param order_id order we create
498 : * @param token claim token to use, NULL for none
499 : * @param amount how much we asked for
500 : * @return transaction status
501 : */
502 : static enum SYNC_DB_QueryStatus
503 0 : postgres_store_payment (void *cls,
504 : const struct SYNC_AccountPublicKeyP *account_pub,
505 : const char *order_id,
506 : const struct TALER_ClaimTokenP *token,
507 : const struct TALER_Amount *amount)
508 : {
509 0 : struct PostgresClosure *pg = cls;
510 : enum GNUNET_DB_QueryStatus qs;
511 : struct TALER_ClaimTokenP tok;
512 0 : struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
513 0 : struct GNUNET_PQ_QueryParam params[] = {
514 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
515 0 : GNUNET_PQ_query_param_string (order_id),
516 0 : GNUNET_PQ_query_param_auto_from_type (&tok),
517 0 : GNUNET_PQ_query_param_timestamp (&now),
518 0 : TALER_PQ_query_param_amount (amount),
519 : GNUNET_PQ_query_param_end
520 : };
521 :
522 0 : if (NULL == token)
523 0 : memset (&tok, 0, sizeof (tok));
524 : else
525 0 : tok = *token;
526 0 : check_connection (pg);
527 0 : postgres_preflight (pg);
528 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
529 : "payment_insert",
530 : params);
531 0 : switch (qs)
532 : {
533 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
534 0 : GNUNET_break (0);
535 0 : return SYNC_DB_SOFT_ERROR;
536 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
537 0 : GNUNET_break (0);
538 0 : return SYNC_DB_NO_RESULTS;
539 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
540 0 : return SYNC_DB_ONE_RESULT;
541 0 : case GNUNET_DB_STATUS_HARD_ERROR:
542 0 : GNUNET_break (0);
543 0 : return SYNC_DB_HARD_ERROR;
544 0 : default:
545 0 : GNUNET_break (0);
546 0 : return SYNC_DB_HARD_ERROR;
547 : }
548 : }
549 :
550 :
551 : /**
552 : * Closure for #payment_by_account_cb.
553 : */
554 : struct PaymentIteratorContext
555 : {
556 : /**
557 : * Function to call on each result
558 : */
559 : SYNC_DB_PaymentPendingIterator it;
560 :
561 : /**
562 : * Closure for @e it.
563 : */
564 : void *it_cls;
565 :
566 : /**
567 : * Plugin context.
568 : */
569 : struct PostgresClosure *pg;
570 :
571 : /**
572 : * Query status to return.
573 : */
574 : enum GNUNET_DB_QueryStatus qs;
575 :
576 : };
577 :
578 :
579 : /**
580 : * Helper function for #postgres_lookup_pending_payments_by_account().
581 : * To be called with the results of a SELECT statement
582 : * that has returned @a num_results results.
583 : *
584 : * @param cls closure of type `struct PaymentIteratorContext *`
585 : * @param result the postgres result
586 : * @param num_result the number of results in @a result
587 : */
588 : static void
589 0 : payment_by_account_cb (void *cls,
590 : PGresult *result,
591 : unsigned int num_results)
592 : {
593 0 : struct PaymentIteratorContext *pic = cls;
594 :
595 0 : for (unsigned int i = 0; i < num_results; i++)
596 : {
597 : struct GNUNET_TIME_Timestamp timestamp;
598 : char *order_id;
599 : struct TALER_Amount amount;
600 : struct TALER_ClaimTokenP token;
601 0 : struct GNUNET_PQ_ResultSpec rs[] = {
602 0 : GNUNET_PQ_result_spec_timestamp ("timestamp",
603 : ×tamp),
604 0 : GNUNET_PQ_result_spec_string ("order_id",
605 : &order_id),
606 0 : GNUNET_PQ_result_spec_auto_from_type ("token",
607 : &token),
608 0 : TALER_PQ_result_spec_amount ("amount",
609 0 : pic->pg->currency,
610 : &amount),
611 : GNUNET_PQ_result_spec_end
612 : };
613 :
614 0 : if (GNUNET_OK !=
615 0 : GNUNET_PQ_extract_result (result,
616 : rs,
617 : i))
618 : {
619 0 : GNUNET_break (0);
620 0 : pic->qs = GNUNET_DB_STATUS_HARD_ERROR;
621 0 : return;
622 : }
623 0 : pic->qs = i + 1;
624 0 : pic->it (pic->it_cls,
625 : timestamp,
626 : order_id,
627 : &token,
628 : &amount);
629 0 : GNUNET_PQ_cleanup_result (rs);
630 : }
631 : }
632 :
633 :
634 : /**
635 : * Lookup pending payments by account.
636 : *
637 : * @param cls closure
638 : * @param account_pub account to look for pending payments under
639 : * @param it iterator to call on all pending payments
640 : * @param it_cls closure for @a it
641 : * @return transaction status
642 : */
643 : static enum GNUNET_DB_QueryStatus
644 0 : postgres_lookup_pending_payments_by_account (void *cls,
645 : const struct
646 : SYNC_AccountPublicKeyP *account_pub,
647 : SYNC_DB_PaymentPendingIterator it,
648 : void *it_cls)
649 : {
650 0 : struct PostgresClosure *pg = cls;
651 0 : struct GNUNET_PQ_QueryParam params[] = {
652 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
653 : GNUNET_PQ_query_param_end
654 : };
655 0 : struct PaymentIteratorContext pic = {
656 : .it = it,
657 : .it_cls = it_cls,
658 : .pg = pg
659 : };
660 : enum GNUNET_DB_QueryStatus qs;
661 :
662 0 : check_connection (pg);
663 0 : postgres_preflight (pg);
664 0 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
665 : "payments_select_by_account",
666 : params,
667 : &payment_by_account_cb,
668 : &pic);
669 0 : if (qs > 0)
670 0 : return pic.qs;
671 0 : GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
672 0 : return qs;
673 : }
674 :
675 :
676 : /**
677 : * Store backup. Only applicable for the FIRST backup under
678 : * an @a account_pub. Use @e update_backup_TR to update an
679 : * existing backup.
680 : *
681 : * @param cls closure
682 : * @param account_pub account to store @a backup under
683 : * @param account_sig signature affirming storage request
684 : * @param backup_hash hash of @a backup
685 : * @param backup_size number of bytes in @a backup
686 : * @param backup raw data to backup
687 : * @return transaction status
688 : */
689 : static enum SYNC_DB_QueryStatus
690 0 : postgres_store_backup (void *cls,
691 : const struct SYNC_AccountPublicKeyP *account_pub,
692 : const struct SYNC_AccountSignatureP *account_sig,
693 : const struct GNUNET_HashCode *backup_hash,
694 : size_t backup_size,
695 : const void *backup)
696 : {
697 0 : struct PostgresClosure *pg = cls;
698 : enum GNUNET_DB_QueryStatus qs;
699 : struct GNUNET_HashCode bh;
700 : static struct GNUNET_HashCode no_previous_hash;
701 :
702 0 : check_connection (pg);
703 0 : postgres_preflight (pg);
704 : {
705 0 : struct GNUNET_PQ_QueryParam params[] = {
706 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
707 0 : GNUNET_PQ_query_param_auto_from_type (account_sig),
708 0 : GNUNET_PQ_query_param_auto_from_type (&no_previous_hash),
709 0 : GNUNET_PQ_query_param_auto_from_type (backup_hash),
710 0 : GNUNET_PQ_query_param_fixed_size (backup,
711 : backup_size),
712 : GNUNET_PQ_query_param_end
713 : };
714 :
715 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
716 : "backup_insert",
717 : params);
718 : }
719 0 : switch (qs)
720 : {
721 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
722 0 : GNUNET_break (0);
723 0 : return SYNC_DB_SOFT_ERROR;
724 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
725 0 : GNUNET_break (0);
726 0 : return SYNC_DB_NO_RESULTS;
727 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
728 0 : return SYNC_DB_ONE_RESULT;
729 0 : case GNUNET_DB_STATUS_HARD_ERROR:
730 : /* handle interesting case below */
731 0 : break;
732 0 : default:
733 0 : GNUNET_break (0);
734 0 : return SYNC_DB_HARD_ERROR;
735 : }
736 :
737 : /* First, check if account exists */
738 : {
739 : struct GNUNET_TIME_Timestamp ed;
740 0 : struct GNUNET_PQ_QueryParam params[] = {
741 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
742 : GNUNET_PQ_query_param_end
743 : };
744 0 : struct GNUNET_PQ_ResultSpec rs[] = {
745 0 : GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
746 : &ed),
747 : GNUNET_PQ_result_spec_end
748 : };
749 :
750 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
751 : "account_select",
752 : params,
753 : rs);
754 : }
755 0 : switch (qs)
756 : {
757 0 : case GNUNET_DB_STATUS_HARD_ERROR:
758 0 : return SYNC_DB_HARD_ERROR;
759 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
760 0 : GNUNET_break (0);
761 0 : return SYNC_DB_SOFT_ERROR;
762 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
763 0 : return SYNC_DB_PAYMENT_REQUIRED;
764 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
765 : /* handle interesting case below */
766 0 : break;
767 0 : default:
768 0 : GNUNET_break (0);
769 0 : return SYNC_DB_HARD_ERROR;
770 : }
771 :
772 : /* account exists, check if existing backup conflicts */
773 : {
774 0 : struct GNUNET_PQ_QueryParam params[] = {
775 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
776 : GNUNET_PQ_query_param_end
777 : };
778 0 : struct GNUNET_PQ_ResultSpec rs[] = {
779 0 : GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
780 : &bh),
781 : GNUNET_PQ_result_spec_end
782 : };
783 :
784 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
785 : "backup_select_hash",
786 : params,
787 : rs);
788 : }
789 0 : switch (qs)
790 : {
791 0 : case GNUNET_DB_STATUS_HARD_ERROR:
792 0 : return SYNC_DB_HARD_ERROR;
793 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
794 0 : GNUNET_break (0);
795 0 : return SYNC_DB_SOFT_ERROR;
796 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
797 : /* original error must have been a hard error, oddly enough */
798 0 : return SYNC_DB_HARD_ERROR;
799 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
800 : /* handle interesting case below */
801 0 : break;
802 0 : default:
803 0 : GNUNET_break (0);
804 0 : return SYNC_DB_HARD_ERROR;
805 : }
806 :
807 : /* had an existing backup, is it identical? */
808 0 : if (0 != GNUNET_memcmp (&bh,
809 : backup_hash))
810 : /* previous conflicting backup exists */
811 0 : return SYNC_DB_OLD_BACKUP_MISMATCH;
812 : /* backup identical to what was provided, no change */
813 0 : return SYNC_DB_NO_RESULTS;
814 : }
815 :
816 :
817 : /**
818 : * Update backup.
819 : *
820 : * @param cls closure
821 : * @param account_pub account to store @a backup under
822 : * @param account_sig signature affirming storage request
823 : * @param old_backup_hash hash of the previous backup (must match)
824 : * @param backup_hash hash of @a backup
825 : * @param backup_size number of bytes in @a backup
826 : * @param backup raw data to backup
827 : * @return transaction status
828 : */
829 : static enum SYNC_DB_QueryStatus
830 0 : postgres_update_backup (void *cls,
831 : const struct SYNC_AccountPublicKeyP *account_pub,
832 : const struct GNUNET_HashCode *old_backup_hash,
833 : const struct SYNC_AccountSignatureP *account_sig,
834 : const struct GNUNET_HashCode *backup_hash,
835 : size_t backup_size,
836 : const void *backup)
837 : {
838 0 : struct PostgresClosure *pg = cls;
839 : enum GNUNET_DB_QueryStatus qs;
840 : struct GNUNET_HashCode bh;
841 :
842 0 : check_connection (pg);
843 0 : postgres_preflight (pg);
844 : {
845 0 : struct GNUNET_PQ_QueryParam params[] = {
846 0 : GNUNET_PQ_query_param_auto_from_type (backup_hash),
847 0 : GNUNET_PQ_query_param_auto_from_type (account_sig),
848 0 : GNUNET_PQ_query_param_auto_from_type (old_backup_hash),
849 0 : GNUNET_PQ_query_param_fixed_size (backup,
850 : backup_size),
851 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
852 0 : GNUNET_PQ_query_param_auto_from_type (old_backup_hash),
853 : GNUNET_PQ_query_param_end
854 : };
855 :
856 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
857 : "backup_update",
858 : params);
859 : }
860 0 : switch (qs)
861 : {
862 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
863 0 : GNUNET_break (0);
864 0 : return SYNC_DB_SOFT_ERROR;
865 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
866 : /* handle interesting case below */
867 0 : break;
868 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
869 0 : return SYNC_DB_ONE_RESULT;
870 0 : case GNUNET_DB_STATUS_HARD_ERROR:
871 0 : GNUNET_break (0);
872 0 : return SYNC_DB_HARD_ERROR;
873 0 : default:
874 0 : GNUNET_break (0);
875 0 : return SYNC_DB_HARD_ERROR;
876 : }
877 :
878 : /* First, check if account exists */
879 : {
880 : struct GNUNET_TIME_Timestamp ed;
881 0 : struct GNUNET_PQ_QueryParam params[] = {
882 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
883 : GNUNET_PQ_query_param_end
884 : };
885 0 : struct GNUNET_PQ_ResultSpec rs[] = {
886 0 : GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
887 : &ed),
888 : GNUNET_PQ_result_spec_end
889 : };
890 :
891 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
892 : "account_select",
893 : params,
894 : rs);
895 : }
896 0 : switch (qs)
897 : {
898 0 : case GNUNET_DB_STATUS_HARD_ERROR:
899 0 : return SYNC_DB_HARD_ERROR;
900 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
901 0 : GNUNET_break (0);
902 0 : return SYNC_DB_SOFT_ERROR;
903 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
904 0 : return SYNC_DB_PAYMENT_REQUIRED;
905 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
906 : /* handle interesting case below */
907 0 : break;
908 0 : default:
909 0 : GNUNET_break (0);
910 0 : return SYNC_DB_HARD_ERROR;
911 : }
912 :
913 : /* account exists, check if existing backup conflicts */
914 : {
915 0 : struct GNUNET_PQ_QueryParam params[] = {
916 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
917 : GNUNET_PQ_query_param_end
918 : };
919 0 : struct GNUNET_PQ_ResultSpec rs[] = {
920 0 : GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
921 : &bh),
922 : GNUNET_PQ_result_spec_end
923 : };
924 :
925 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
926 : "backup_select_hash",
927 : params,
928 : rs);
929 : }
930 0 : switch (qs)
931 : {
932 0 : case GNUNET_DB_STATUS_HARD_ERROR:
933 0 : return SYNC_DB_HARD_ERROR;
934 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
935 0 : GNUNET_break (0);
936 0 : return SYNC_DB_SOFT_ERROR;
937 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
938 0 : return SYNC_DB_OLD_BACKUP_MISSING;
939 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
940 : /* handle interesting case below */
941 0 : break;
942 0 : default:
943 0 : GNUNET_break (0);
944 0 : return SYNC_DB_HARD_ERROR;
945 : }
946 :
947 : /* had an existing backup, is it identical? */
948 0 : if (0 == GNUNET_memcmp (&bh,
949 : backup_hash))
950 : {
951 : /* backup identical to what was provided, no change */
952 0 : return SYNC_DB_NO_RESULTS;
953 : }
954 0 : if (0 == GNUNET_memcmp (&bh,
955 : old_backup_hash))
956 : /* all constraints seem satisfied, original error must
957 : have been a hard error */
958 0 : return SYNC_DB_HARD_ERROR;
959 : /* previous backup does not match old_backup_hash */
960 0 : return SYNC_DB_OLD_BACKUP_MISMATCH;
961 : }
962 :
963 :
964 : /**
965 : * Lookup an account and associated backup meta data.
966 : *
967 : * @param cls closure
968 : * @param account_pub account to store @a backup under
969 : * @param backup_hash[OUT] set to hash of @a backup
970 : * @return transaction status
971 : */
972 : static enum SYNC_DB_QueryStatus
973 0 : postgres_lookup_account (void *cls,
974 : const struct SYNC_AccountPublicKeyP *account_pub,
975 : struct GNUNET_HashCode *backup_hash)
976 : {
977 0 : struct PostgresClosure *pg = cls;
978 : enum GNUNET_DB_QueryStatus qs;
979 0 : struct GNUNET_PQ_QueryParam params[] = {
980 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
981 : GNUNET_PQ_query_param_end
982 : };
983 :
984 0 : check_connection (pg);
985 0 : postgres_preflight (pg);
986 : {
987 0 : struct GNUNET_PQ_ResultSpec rs[] = {
988 0 : GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
989 : backup_hash),
990 : GNUNET_PQ_result_spec_end
991 : };
992 :
993 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
994 : "backup_select_hash",
995 : params,
996 : rs);
997 : }
998 0 : switch (qs)
999 : {
1000 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1001 0 : return SYNC_DB_HARD_ERROR;
1002 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1003 0 : GNUNET_break (0);
1004 0 : return SYNC_DB_SOFT_ERROR;
1005 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1006 0 : break; /* handle interesting case below */
1007 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1008 0 : return SYNC_DB_ONE_RESULT;
1009 0 : default:
1010 0 : GNUNET_break (0);
1011 0 : return SYNC_DB_HARD_ERROR;
1012 : }
1013 :
1014 : /* check if account exists */
1015 : {
1016 : struct GNUNET_TIME_Timestamp expiration;
1017 0 : struct GNUNET_PQ_ResultSpec rs[] = {
1018 0 : GNUNET_PQ_result_spec_auto_from_type ("expiration_date",
1019 : &expiration),
1020 : GNUNET_PQ_result_spec_end
1021 : };
1022 :
1023 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
1024 : "account_select",
1025 : params,
1026 : rs);
1027 : }
1028 0 : switch (qs)
1029 : {
1030 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1031 0 : return SYNC_DB_HARD_ERROR;
1032 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1033 0 : GNUNET_break (0);
1034 0 : return SYNC_DB_SOFT_ERROR;
1035 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1036 : /* indicates: no account */
1037 0 : return SYNC_DB_PAYMENT_REQUIRED;
1038 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1039 : /* indicates: no backup */
1040 0 : return SYNC_DB_NO_RESULTS;
1041 0 : default:
1042 0 : GNUNET_break (0);
1043 0 : return SYNC_DB_HARD_ERROR;
1044 : }
1045 : }
1046 :
1047 :
1048 : /**
1049 : * Obtain backup.
1050 : *
1051 : * @param cls closure
1052 : * @param account_pub account to store @a backup under
1053 : * @param account_sig[OUT] set to signature affirming storage request
1054 : * @param prev_hash[OUT] set to hash of previous @a backup, all zeros if none
1055 : * @param backup_hash[OUT] set to hash of @a backup
1056 : * @param backup_size[OUT] set to number of bytes in @a backup
1057 : * @param backup[OUT] set to raw data to backup, caller MUST FREE
1058 : */
1059 : static enum SYNC_DB_QueryStatus
1060 0 : postgres_lookup_backup (void *cls,
1061 : const struct SYNC_AccountPublicKeyP *account_pub,
1062 : struct SYNC_AccountSignatureP *account_sig,
1063 : struct GNUNET_HashCode *prev_hash,
1064 : struct GNUNET_HashCode *backup_hash,
1065 : size_t *backup_size,
1066 : void **backup)
1067 : {
1068 0 : struct PostgresClosure *pg = cls;
1069 : enum GNUNET_DB_QueryStatus qs;
1070 0 : struct GNUNET_PQ_QueryParam params[] = {
1071 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
1072 : GNUNET_PQ_query_param_end
1073 : };
1074 0 : struct GNUNET_PQ_ResultSpec rs[] = {
1075 0 : GNUNET_PQ_result_spec_auto_from_type ("account_sig",
1076 : account_sig),
1077 0 : GNUNET_PQ_result_spec_auto_from_type ("prev_hash",
1078 : prev_hash),
1079 0 : GNUNET_PQ_result_spec_auto_from_type ("backup_hash",
1080 : backup_hash),
1081 0 : GNUNET_PQ_result_spec_variable_size ("data",
1082 : backup,
1083 : backup_size),
1084 : GNUNET_PQ_result_spec_end
1085 : };
1086 :
1087 0 : check_connection (pg);
1088 0 : postgres_preflight (pg);
1089 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
1090 : "backup_select",
1091 : params,
1092 : rs);
1093 0 : switch (qs)
1094 : {
1095 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1096 0 : return SYNC_DB_HARD_ERROR;
1097 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1098 0 : GNUNET_break (0);
1099 0 : return SYNC_DB_SOFT_ERROR;
1100 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1101 0 : return SYNC_DB_NO_RESULTS;
1102 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1103 0 : return SYNC_DB_ONE_RESULT;
1104 0 : default:
1105 0 : GNUNET_break (0);
1106 0 : return SYNC_DB_HARD_ERROR;
1107 : }
1108 : }
1109 :
1110 :
1111 : /**
1112 : * Increment account lifetime.
1113 : *
1114 : * @param cls closure
1115 : * @param account_pub which account received a payment
1116 : * @param order_id order which was paid, must be unique and match pending payment
1117 : * @param lifetime for how long is the account now paid (increment)
1118 : * @return transaction status
1119 : */
1120 : static enum SYNC_DB_QueryStatus
1121 0 : postgres_increment_lifetime (void *cls,
1122 : const struct SYNC_AccountPublicKeyP *account_pub,
1123 : const char *order_id,
1124 : struct GNUNET_TIME_Relative lifetime)
1125 : {
1126 0 : struct PostgresClosure *pg = cls;
1127 : struct GNUNET_TIME_Timestamp expiration;
1128 : enum GNUNET_DB_QueryStatus qs;
1129 :
1130 0 : check_connection (pg);
1131 0 : if (GNUNET_OK !=
1132 0 : begin_transaction (pg,
1133 : "increment lifetime"))
1134 : {
1135 0 : GNUNET_break (0);
1136 0 : return SYNC_DB_HARD_ERROR;
1137 : }
1138 :
1139 : {
1140 0 : struct GNUNET_PQ_QueryParam params[] = {
1141 0 : GNUNET_PQ_query_param_string (order_id),
1142 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
1143 : GNUNET_PQ_query_param_end
1144 : };
1145 :
1146 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
1147 : "payment_done",
1148 : params);
1149 0 : switch (qs)
1150 : {
1151 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1152 0 : GNUNET_break (0);
1153 0 : rollback (pg);
1154 0 : return SYNC_DB_HARD_ERROR;
1155 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1156 0 : GNUNET_break (0);
1157 0 : rollback (pg);
1158 0 : return SYNC_DB_SOFT_ERROR;
1159 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1160 0 : rollback (pg);
1161 0 : return SYNC_DB_NO_RESULTS;
1162 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1163 0 : break;
1164 : }
1165 0 : }
1166 :
1167 : {
1168 0 : struct GNUNET_PQ_QueryParam params[] = {
1169 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
1170 : GNUNET_PQ_query_param_end
1171 : };
1172 0 : struct GNUNET_PQ_ResultSpec rs[] = {
1173 0 : GNUNET_PQ_result_spec_timestamp ("expiration_date",
1174 : &expiration),
1175 : GNUNET_PQ_result_spec_end
1176 : };
1177 :
1178 0 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
1179 : "account_select",
1180 : params,
1181 : rs);
1182 : }
1183 :
1184 0 : switch (qs)
1185 : {
1186 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1187 0 : rollback (pg);
1188 0 : return SYNC_DB_HARD_ERROR;
1189 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1190 0 : rollback (pg);
1191 0 : return SYNC_DB_SOFT_ERROR;
1192 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1193 : {
1194 0 : struct GNUNET_PQ_QueryParam params[] = {
1195 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
1196 0 : GNUNET_PQ_query_param_timestamp (&expiration),
1197 : GNUNET_PQ_query_param_end
1198 : };
1199 :
1200 0 : expiration = GNUNET_TIME_relative_to_timestamp (lifetime);
1201 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
1202 : "account_insert",
1203 : params);
1204 : }
1205 0 : break;
1206 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1207 : {
1208 0 : struct GNUNET_PQ_QueryParam params[] = {
1209 0 : GNUNET_PQ_query_param_timestamp (&expiration),
1210 0 : GNUNET_PQ_query_param_auto_from_type (account_pub),
1211 : GNUNET_PQ_query_param_end
1212 : };
1213 :
1214 0 : expiration = GNUNET_TIME_absolute_to_timestamp (
1215 : GNUNET_TIME_absolute_add (expiration.abs_time,
1216 : lifetime));
1217 0 : qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
1218 : "account_update",
1219 : params);
1220 : }
1221 0 : break;
1222 0 : default:
1223 0 : GNUNET_break (0);
1224 0 : return SYNC_DB_HARD_ERROR;
1225 : }
1226 0 : switch (qs)
1227 : {
1228 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1229 0 : rollback (pg);
1230 0 : return SYNC_DB_HARD_ERROR;
1231 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1232 0 : rollback (pg);
1233 0 : GNUNET_break (0);
1234 0 : return SYNC_DB_SOFT_ERROR;
1235 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1236 0 : GNUNET_break (0);
1237 0 : rollback (pg);
1238 0 : return SYNC_DB_NO_RESULTS;
1239 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1240 0 : break;
1241 0 : default:
1242 0 : GNUNET_break (0);
1243 0 : return SYNC_DB_HARD_ERROR;
1244 : }
1245 0 : qs = commit_transaction (pg);
1246 0 : switch (qs)
1247 : {
1248 0 : case GNUNET_DB_STATUS_HARD_ERROR:
1249 0 : return SYNC_DB_HARD_ERROR;
1250 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
1251 0 : GNUNET_break (0);
1252 0 : return SYNC_DB_SOFT_ERROR;
1253 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
1254 0 : return SYNC_DB_ONE_RESULT;
1255 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
1256 0 : return SYNC_DB_ONE_RESULT;
1257 0 : default:
1258 0 : GNUNET_break (0);
1259 0 : return SYNC_DB_HARD_ERROR;
1260 : }
1261 : }
1262 :
1263 :
1264 : /**
1265 : * Initialize tables.
1266 : *
1267 : * @param cls the `struct PostgresClosure` with the plugin-specific state
1268 : * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
1269 : */
1270 : static enum GNUNET_GenericReturnValue
1271 0 : postgres_create_tables (void *cls)
1272 : {
1273 0 : struct PostgresClosure *pc = cls;
1274 : struct GNUNET_PQ_Context *conn;
1275 :
1276 0 : conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
1277 : "syncdb-postgres",
1278 : "sync-",
1279 : NULL,
1280 : NULL);
1281 0 : if (NULL == conn)
1282 0 : return GNUNET_SYSERR;
1283 0 : GNUNET_PQ_disconnect (conn);
1284 0 : return GNUNET_OK;
1285 : }
1286 :
1287 :
1288 : /**
1289 : * Initialize Postgres database subsystem.
1290 : *
1291 : * @param cls a configuration instance
1292 : * @return NULL on error, otherwise a `struct TALER_SYNCDB_Plugin`
1293 : */
1294 : void *
1295 1 : libsync_plugin_db_postgres_init (void *cls)
1296 : {
1297 1 : struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1298 : struct PostgresClosure *pg;
1299 : struct SYNC_DatabasePlugin *plugin;
1300 :
1301 1 : pg = GNUNET_new (struct PostgresClosure);
1302 1 : pg->cfg = cfg;
1303 1 : if (GNUNET_OK !=
1304 1 : GNUNET_CONFIGURATION_get_value_filename (cfg,
1305 : "syncdb-postgres",
1306 : "SQL_DIR",
1307 : &pg->sql_dir))
1308 : {
1309 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1310 : "syncdb-postgres",
1311 : "SQL_DIR");
1312 0 : GNUNET_free (pg);
1313 0 : return NULL;
1314 : }
1315 1 : if (GNUNET_OK !=
1316 1 : GNUNET_CONFIGURATION_get_value_string (cfg,
1317 : "taler",
1318 : "CURRENCY",
1319 : &pg->currency))
1320 : {
1321 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1322 : "taler",
1323 : "CURRENCY");
1324 0 : GNUNET_free (pg->sql_dir);
1325 0 : GNUNET_free (pg);
1326 0 : return NULL;
1327 : }
1328 1 : if (GNUNET_OK !=
1329 1 : internal_setup (pg,
1330 : true))
1331 : {
1332 1 : GNUNET_free (pg->currency);
1333 1 : GNUNET_free (pg->sql_dir);
1334 1 : GNUNET_free (pg);
1335 1 : return NULL;
1336 : }
1337 0 : plugin = GNUNET_new (struct SYNC_DatabasePlugin);
1338 0 : plugin->cls = pg;
1339 0 : plugin->create_tables = &postgres_create_tables;
1340 0 : plugin->drop_tables = &postgres_drop_tables;
1341 0 : plugin->preflight = &postgres_preflight;
1342 0 : plugin->gc = &postgres_gc;
1343 0 : plugin->store_payment_TR = &postgres_store_payment;
1344 0 : plugin->lookup_pending_payments_by_account_TR =
1345 : &postgres_lookup_pending_payments_by_account;
1346 0 : plugin->store_backup_TR = &postgres_store_backup;
1347 0 : plugin->lookup_account_TR = &postgres_lookup_account;
1348 0 : plugin->lookup_backup_TR = &postgres_lookup_backup;
1349 0 : plugin->update_backup_TR = &postgres_update_backup;
1350 0 : plugin->increment_lifetime_TR = &postgres_increment_lifetime;
1351 0 : return plugin;
1352 : }
1353 :
1354 :
1355 : /**
1356 : * Shutdown Postgres database subsystem.
1357 : *
1358 : * @param cls a `struct SYNC_DB_Plugin`
1359 : * @return NULL (always)
1360 : */
1361 : void *
1362 0 : libsync_plugin_db_postgres_done (void *cls)
1363 : {
1364 0 : struct SYNC_DatabasePlugin *plugin = cls;
1365 0 : struct PostgresClosure *pg = plugin->cls;
1366 :
1367 0 : GNUNET_PQ_disconnect (pg->conn);
1368 0 : GNUNET_free (pg->currency);
1369 0 : GNUNET_free (pg->sql_dir);
1370 0 : GNUNET_free (pg);
1371 0 : GNUNET_free (plugin);
1372 0 : return NULL;
1373 : }
1374 :
1375 :
1376 : /* end of plugin_syncdb_postgres.c */
|