Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 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 src/auditordb/start.c
18 : * @brief Implementation of the start, commit and rollback functions for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "taler/taler_pq_lib.h"
22 : #include "auditor-database/start.h"
23 : #include "auditor-database/preflight.h"
24 : #include "pg_helper.h"
25 :
26 :
27 : enum GNUNET_GenericReturnValue
28 30 : TALER_AUDITORDB_start (struct TALER_AUDITORDB_PostgresContext *pg,
29 : const char *transaction_name)
30 : {
31 30 : struct GNUNET_PQ_ExecuteStatement es[] = {
32 30 : GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
33 : GNUNET_PQ_EXECUTE_STATEMENT_END
34 : };
35 :
36 30 : GNUNET_assert (NULL != transaction_name);
37 30 : GNUNET_break (GNUNET_OK ==
38 : TALER_AUDITORDB_preflight (pg));
39 30 : if (GNUNET_OK !=
40 30 : GNUNET_PQ_exec_statements (pg->conn,
41 : es))
42 : {
43 0 : TALER_LOG_ERROR ("Failed to start transaction\n");
44 0 : GNUNET_break (0);
45 0 : return GNUNET_SYSERR;
46 : }
47 30 : pg->transaction_name = transaction_name;
48 30 : return GNUNET_OK;
49 : }
50 :
51 :
52 : void
53 12 : TALER_AUDITORDB_rollback (struct TALER_AUDITORDB_PostgresContext *pg)
54 : {
55 12 : struct GNUNET_PQ_ExecuteStatement es[] = {
56 12 : GNUNET_PQ_make_execute ("ROLLBACK"),
57 : GNUNET_PQ_EXECUTE_STATEMENT_END
58 : };
59 :
60 12 : GNUNET_break (GNUNET_OK ==
61 : GNUNET_PQ_exec_statements (pg->conn,
62 : es));
63 12 : pg->transaction_name = NULL;
64 12 : }
65 :
66 :
67 : enum GNUNET_DB_QueryStatus
68 19 : TALER_AUDITORDB_commit (struct TALER_AUDITORDB_PostgresContext *pg)
69 : {
70 19 : struct GNUNET_PQ_QueryParam params[] = {
71 : GNUNET_PQ_query_param_end
72 : };
73 :
74 : enum GNUNET_DB_QueryStatus qs;
75 : PGresult *result;
76 :
77 19 : PREPARE (pg,
78 : "commit",
79 : "COMMIT");
80 19 : result = GNUNET_PQ_exec_prepared (pg->conn,
81 : "commit",
82 : params);
83 19 : qs = GNUNET_PQ_eval_result (pg->conn,
84 : "commit",
85 : result);
86 19 : if ( (0 <= qs) &&
87 19 : (NULL != result) &&
88 19 : (0 == strcmp ("ROLLBACK",
89 19 : PQcmdStatus (result))) )
90 : {
91 : /* Postgres accepts COMMIT on an already-aborted transaction and
92 : answers PGRES_COMMAND_OK with the command tag ROLLBACK, which is
93 : otherwise indistinguishable from a successful commit. Report it
94 : as a soft error so the caller retries instead of checkpointing
95 : progress for writes that are gone. */
96 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
97 : "Transaction `%s' was rolled back by the database\n",
98 : pg->transaction_name);
99 0 : qs = GNUNET_DB_STATUS_SOFT_ERROR;
100 : }
101 19 : PQclear (result);
102 19 : pg->transaction_name = NULL;
103 19 : return qs;
104 : }
|