Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022 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 backenddb/pg_insert_transfer_details.c
18 : * @brief Implementation of the insert_transfer_details function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <taler/taler_error_codes.h>
23 : #include <taler/taler_dbevents.h>
24 : #include <taler/taler_pq_lib.h>
25 : #include "pg_insert_transfer_details.h"
26 : #include "pg_helper.h"
27 :
28 :
29 : /**
30 : * How often do we re-try if we run into a DB serialization error?
31 : */
32 : #define MAX_RETRIES 3
33 :
34 :
35 : enum GNUNET_DB_QueryStatus
36 8 : TMH_PG_insert_transfer_details (
37 : void *cls,
38 : const char *instance_id,
39 : const char *exchange_url,
40 : struct TALER_FullPayto payto_uri,
41 : const struct TALER_WireTransferIdentifierRawP *wtid,
42 : const struct TALER_EXCHANGE_TransferData *td)
43 8 : {
44 8 : struct PostgresClosure *pg = cls;
45 8 : unsigned int len = td->details_length;
46 8 : struct TALER_Amount coin_values[GNUNET_NZL (len)];
47 8 : struct TALER_Amount deposit_fees[GNUNET_NZL (len)];
48 8 : const struct TALER_CoinSpendPublicKeyP *coin_pubs[GNUNET_NZL (len)];
49 8 : const struct TALER_PrivateContractHashP *contract_terms[GNUNET_NZL (len)];
50 : enum GNUNET_DB_QueryStatus qs;
51 : bool duplicate;
52 :
53 16 : for (unsigned int i = 0; i<len; i++)
54 : {
55 8 : const struct TALER_TrackTransferDetails *tdd = &td->details[i];
56 :
57 8 : coin_values[i] = tdd->coin_value;
58 8 : deposit_fees[i] = tdd->coin_fee;
59 8 : coin_pubs[i] = &tdd->coin_pub;
60 8 : contract_terms[i] = &tdd->h_contract_terms;
61 : }
62 :
63 8 : check_connection (pg);
64 8 : PREPARE (pg,
65 : "insert_transfer_details",
66 : "SELECT"
67 : " out_no_instance"
68 : ",out_no_account"
69 : ",out_no_exchange"
70 : ",out_duplicate"
71 : ",out_conflict"
72 : " FROM merchant_do_insert_transfer_details"
73 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
74 :
75 8 : for (unsigned int retries = 0;
76 8 : retries < MAX_RETRIES;
77 0 : retries++)
78 : {
79 8 : if (GNUNET_OK !=
80 8 : TMH_PG_start (pg,
81 : "insert transfer details"))
82 : {
83 0 : GNUNET_break (0);
84 0 : return GNUNET_DB_STATUS_HARD_ERROR;
85 : }
86 :
87 : {
88 8 : struct GNUNET_PQ_QueryParam params[] = {
89 8 : GNUNET_PQ_query_param_string (instance_id),
90 8 : GNUNET_PQ_query_param_string (exchange_url),
91 8 : GNUNET_PQ_query_param_string (payto_uri.full_payto),
92 8 : GNUNET_PQ_query_param_auto_from_type (wtid),
93 8 : GNUNET_PQ_query_param_timestamp (&td->execution_time),
94 8 : GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
95 8 : GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
96 8 : TALER_PQ_query_param_amount_with_currency (pg->conn,
97 : &td->total_amount),
98 8 : TALER_PQ_query_param_amount_with_currency (pg->conn,
99 : &td->wire_fee),
100 8 : TALER_PQ_query_param_array_amount_with_currency (
101 : len,
102 : coin_values,
103 : pg->conn),
104 8 : TALER_PQ_query_param_array_amount_with_currency (
105 : len,
106 : deposit_fees,
107 : pg->conn),
108 8 : GNUNET_PQ_query_param_array_ptrs_auto_from_type (
109 : len,
110 : coin_pubs,
111 : pg->conn),
112 8 : GNUNET_PQ_query_param_array_ptrs_auto_from_type (
113 : len,
114 : contract_terms,
115 : pg->conn),
116 : GNUNET_PQ_query_param_end
117 : };
118 : bool no_instance;
119 : bool no_account;
120 : bool no_exchange;
121 : bool conflict;
122 8 : struct GNUNET_PQ_ResultSpec rs[] = {
123 8 : GNUNET_PQ_result_spec_bool ("out_no_instance",
124 : &no_instance),
125 8 : GNUNET_PQ_result_spec_bool ("out_no_account",
126 : &no_account),
127 8 : GNUNET_PQ_result_spec_bool ("out_no_exchange",
128 : &no_exchange),
129 8 : GNUNET_PQ_result_spec_bool ("out_duplicate",
130 : &duplicate),
131 8 : GNUNET_PQ_result_spec_bool ("out_conflict",
132 : &conflict),
133 : GNUNET_PQ_result_spec_end
134 : };
135 :
136 8 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
137 : "insert_transfer_details",
138 : params,
139 : rs);
140 8 : GNUNET_PQ_cleanup_query_params_closures (params);
141 8 : if (0 >= qs)
142 : {
143 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
144 0 : TMH_PG_rollback (pg);
145 0 : if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
146 0 : continue;
147 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
148 : "'insert_transfer_details' failed with status %d\n",
149 : qs);
150 0 : return qs;
151 : }
152 8 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
153 : "Transfer details inserted: %s%s%s%s%s\n",
154 : no_instance ? "no instance " : "",
155 : no_account ? "no account " : "",
156 : no_exchange ? "no exchange ": "",
157 : duplicate ? "duplicate ": "",
158 : conflict ? "conflict" : "");
159 : }
160 :
161 8 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
162 : "Committing transaction...\n");
163 8 : qs = TMH_PG_commit (pg);
164 8 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
165 8 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
166 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
167 0 : if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
168 0 : break;
169 : }
170 0 : if (duplicate)
171 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
172 0 : return qs;
173 : }
|