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 10 : 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 10 : {
44 10 : struct PostgresClosure *pg = cls;
45 10 : unsigned int len = td->details_length;
46 10 : struct TALER_Amount coin_values[GNUNET_NZL (len)];
47 10 : struct TALER_Amount deposit_fees[GNUNET_NZL (len)];
48 10 : const struct TALER_CoinSpendPublicKeyP *coin_pubs[GNUNET_NZL (len)];
49 10 : const struct TALER_PrivateContractHashP *contract_terms[GNUNET_NZL (len)];
50 : enum GNUNET_DB_QueryStatus qs;
51 :
52 20 : for (unsigned int i = 0; i<len; i++)
53 : {
54 10 : const struct TALER_TrackTransferDetails *tdd = &td->details[i];
55 :
56 10 : coin_values[i] = tdd->coin_value;
57 10 : deposit_fees[i] = tdd->coin_fee;
58 10 : coin_pubs[i] = &tdd->coin_pub;
59 10 : contract_terms[i] = &tdd->h_contract_terms;
60 : }
61 :
62 10 : check_connection (pg);
63 10 : PREPARE (pg,
64 : "insert_transfer_details",
65 : "SELECT"
66 : " out_no_instance"
67 : ",out_no_account"
68 : ",out_no_exchange"
69 : ",out_duplicate"
70 : ",out_conflict"
71 : " FROM merchant_do_insert_transfer_details"
72 : " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13);");
73 :
74 10 : for (unsigned int retries = 0;
75 10 : retries < MAX_RETRIES;
76 0 : retries++)
77 : {
78 10 : if (GNUNET_OK !=
79 10 : TMH_PG_start (pg,
80 : "insert transfer details"))
81 : {
82 0 : GNUNET_break (0);
83 0 : return GNUNET_DB_STATUS_HARD_ERROR;
84 : }
85 :
86 : {
87 10 : struct GNUNET_PQ_QueryParam params[] = {
88 10 : GNUNET_PQ_query_param_string (instance_id),
89 10 : GNUNET_PQ_query_param_string (exchange_url),
90 10 : GNUNET_PQ_query_param_string (payto_uri.full_payto),
91 10 : GNUNET_PQ_query_param_auto_from_type (wtid),
92 10 : GNUNET_PQ_query_param_timestamp (&td->execution_time),
93 10 : GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
94 10 : GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
95 10 : TALER_PQ_query_param_amount_with_currency (pg->conn,
96 : &td->total_amount),
97 10 : TALER_PQ_query_param_amount_with_currency (pg->conn,
98 : &td->wire_fee),
99 10 : TALER_PQ_query_param_array_amount_with_currency (
100 : len,
101 : coin_values,
102 : pg->conn),
103 10 : TALER_PQ_query_param_array_amount_with_currency (
104 : len,
105 : deposit_fees,
106 : pg->conn),
107 10 : GNUNET_PQ_query_param_array_ptrs_auto_from_type (
108 : len,
109 : coin_pubs,
110 : pg->conn),
111 10 : GNUNET_PQ_query_param_array_ptrs_auto_from_type (
112 : len,
113 : contract_terms,
114 : pg->conn),
115 : GNUNET_PQ_query_param_end
116 : };
117 : bool no_instance;
118 : bool no_account;
119 : bool no_exchange;
120 : bool duplicate;
121 : bool conflict;
122 10 : struct GNUNET_PQ_ResultSpec rs[] = {
123 10 : GNUNET_PQ_result_spec_bool ("out_no_instance",
124 : &no_instance),
125 10 : GNUNET_PQ_result_spec_bool ("out_no_account",
126 : &no_account),
127 10 : GNUNET_PQ_result_spec_bool ("out_no_exchange",
128 : &no_exchange),
129 10 : GNUNET_PQ_result_spec_bool ("out_duplicate",
130 : &duplicate),
131 10 : GNUNET_PQ_result_spec_bool ("out_conflict",
132 : &conflict),
133 : GNUNET_PQ_result_spec_end
134 : };
135 :
136 10 : qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
137 : "insert_transfer_details",
138 : params,
139 : rs);
140 10 : GNUNET_PQ_cleanup_query_params_closures (params);
141 10 : 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 10 : 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 10 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
162 : "Committing transaction...\n");
163 10 : qs = TMH_PG_commit (pg);
164 10 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
165 10 : 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 : return qs;
171 : }
|