GNUnet 0.21.0
pq_eval.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017, 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
25#include "platform.h"
26#include "pq.h"
27
28
32#define PQ_DIAG_SQLSTATE_DEADLOCK "40P01"
33
37#define PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION "23505"
38
42#define PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE "40001"
43
44
47 const char *statement_name,
48 PGresult *result)
49{
50 ExecStatusType est;
51
52 if (NULL == result)
54 est = PQresultStatus (result);
55 if ((PGRES_COMMAND_OK != est) &&
56 (PGRES_TUPLES_OK != est))
57 {
58 const char *sqlstate;
59 ConnStatusType status;
60
61 if (CONNECTION_OK != (status = PQstatus (db->conn)))
62 {
64 "pq",
65 "Database connection failed during query `%s': %d (reconnecting)\n",
66 statement_name,
67 status);
70 }
71
72 sqlstate = PQresultErrorField (result,
73 PG_DIAG_SQLSTATE);
74 if (NULL == sqlstate)
75 {
76 /* very unexpected... */
77 GNUNET_break (0);
79 }
80 if ((0 == strcmp (sqlstate,
82 (0 == strcmp (sqlstate,
84 {
85 /* These two can be retried and have a fair chance of working
86 the next time */
88 "pq",
89 "Query `%s' failed with result: %s/%s/%s/%s/%s\n",
90 statement_name,
91 PQresultErrorField (result,
92 PG_DIAG_MESSAGE_PRIMARY),
93 PQresultErrorField (result,
94 PG_DIAG_MESSAGE_DETAIL),
95 PQresultErrorMessage (result),
96 PQresStatus (PQresultStatus (result)),
97 PQerrorMessage (db->conn));
99 }
100 if (0 == strcmp (sqlstate,
102 {
103 /* Likely no need to retry, INSERT of "same" data. */
105 "pq",
106 "Query `%s' failed with unique violation: %s/%s/%s/%s/%s\n",
107 statement_name,
108 PQresultErrorField (result,
109 PG_DIAG_MESSAGE_PRIMARY),
110 PQresultErrorField (result,
111 PG_DIAG_MESSAGE_DETAIL),
112 PQresultErrorMessage (result),
113 PQresStatus (PQresultStatus (result)),
114 PQerrorMessage (db->conn));
116 }
118 "pq",
119 "Query `%s' failed with result: %s/%s/%s/%s/%s\n",
120 statement_name,
121 PQresultErrorField (result,
122 PG_DIAG_MESSAGE_PRIMARY),
123 PQresultErrorField (result,
124 PG_DIAG_MESSAGE_DETAIL),
125 PQresultErrorMessage (result),
126 PQresStatus (PQresultStatus (result)),
127 PQerrorMessage (db->conn));
129 }
131}
132
133
136 const char *statement_name,
137 const struct GNUNET_PQ_QueryParam *params)
138{
139 PGresult *result;
140 enum GNUNET_DB_QueryStatus qs;
141
143 statement_name,
144 params);
145 if (NULL == result)
148 statement_name,
149 result);
151 {
152 const char *tuples;
153
154 /* What an awful API, this function really does return a string */
155 tuples = PQcmdTuples (result);
156 if (NULL != tuples)
157 qs = strtol (tuples, NULL, 10);
158 }
159 PQclear (result);
160 return qs;
161}
162
163
166 const char *statement_name,
167 const struct GNUNET_PQ_QueryParam *params,
169 void *rh_cls)
170{
171 PGresult *result;
172 enum GNUNET_DB_QueryStatus qs;
173 unsigned int ret;
174
176 statement_name,
177 params);
178 if (NULL == result)
181 statement_name,
182 result);
183 if (qs < 0)
184 {
185 PQclear (result);
186 return qs;
187 }
188 ret = PQntuples (result);
189 if (NULL != rh)
190 rh (rh_cls,
191 result,
192 ret);
193 PQclear (result);
194 return ret;
195}
196
197
200 struct GNUNET_PQ_Context *db,
201 const char *statement_name,
202 const struct GNUNET_PQ_QueryParam *params,
203 struct GNUNET_PQ_ResultSpec *rs)
204{
205 PGresult *result;
206 enum GNUNET_DB_QueryStatus qs;
207 int ntuples;
208
210 statement_name,
211 params);
212 if (NULL == result)
215 statement_name,
216 result);
217 if (qs < 0)
218 {
219 PQclear (result);
220 return qs;
221 }
222 ntuples = PQntuples (result);
223 if (0 == ntuples)
224 {
225 PQclear (result);
227 }
228 if (1 != ntuples)
229 {
230 /* more than one result, but there must be at most one */
231 GNUNET_break (0);
232 PQclear (result);
234 }
235 if (GNUNET_OK !=
237 rs,
238 0))
239 {
240 PQclear (result);
242 }
243 PQclear (result);
245}
246
247
248/* end of pq/pq_eval.c */
static int ret
Final status code.
Definition: gnunet-arm.c:94
static int status
The program status; 0 for success.
Definition: gnunet-nse.c:38
static int result
Global testing status.
static struct GNUNET_FS_DirectoryBuilder * db
Definition: gnunet-search.c:97
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
Definition: gnunet_db_lib.h:37
@ GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
The transaction succeeded, and yielded one result.
Definition: gnunet_db_lib.h:60
@ GNUNET_DB_STATUS_HARD_ERROR
A hard error occurred, retrying will not help.
Definition: gnunet_db_lib.h:41
@ GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
The transaction succeeded, but yielded zero results.
Definition: gnunet_db_lib.h:55
@ GNUNET_DB_STATUS_SOFT_ERROR
A soft error occurred, retrying the transaction may succeed.
Definition: gnunet_db_lib.h:47
void(* GNUNET_PQ_PostgresResultHandler)(void *cls, PGresult *result, unsigned int num_results)
Function to be called with the results of a SELECT statement that has returned num_results results.
void GNUNET_PQ_reconnect(struct GNUNET_PQ_Context *db)
Reinitialize the database db.
Definition: pq_connect.c:427
PGresult * GNUNET_PQ_exec_prepared(struct GNUNET_PQ_Context *db, const char *name, const struct GNUNET_PQ_QueryParam *params)
Execute a prepared statement.
Definition: pq.c:33
enum GNUNET_GenericReturnValue GNUNET_PQ_extract_result(PGresult *result, struct GNUNET_PQ_ResultSpec *rs, int row)
Extract results from a query result according to the given specification.
Definition: pq.c:149
#define GNUNET_log_from(kind, comp,...)
@ GNUNET_OK
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
shared internal data structures of libgnunetpq
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_multi_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, GNUNET_PQ_PostgresResultHandler rh, void *rh_cls)
Execute a named prepared statement that is a SELECT statement which may return multiple results in co...
Definition: pq_eval.c:165
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_singleton_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, struct GNUNET_PQ_ResultSpec *rs)
Execute a named prepared statement that is a SELECT statement which must return a single result in co...
Definition: pq_eval.c:199
#define PQ_DIAG_SQLSTATE_DEADLOCK
Error code returned by Postgres for deadlock.
Definition: pq_eval.c:32
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_result(struct GNUNET_PQ_Context *db, const char *statement_name, PGresult *result)
Check the result's error code to see what happened.
Definition: pq_eval.c:46
#define PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE
Error code returned by Postgres on serialization failure.
Definition: pq_eval.c:42
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_non_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params)
Execute a named prepared statement that is NOT a SELECT statement in connection using the given param...
Definition: pq_eval.c:135
#define PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION
Error code returned by Postgres for uniqueness violation.
Definition: pq_eval.c:37
Handle to Postgres database.
Definition: pq.h:36
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:83
Description of a DB result cell.