GNUnet  0.10.x
pq_eval.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2017 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 "gnunet_util_lib.h"
27 #include "gnunet_pq_lib.h"
28 
29 
33 #define PQ_DIAG_SQLSTATE_DEADLOCK "40P01"
34 
38 #define PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION "23505"
39 
43 #define PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE "40001"
44 
45 
60 GNUNET_PQ_eval_result (PGconn *connection,
61  const char *statement_name,
62  PGresult *result)
63 {
64  ExecStatusType est;
65 
66  est = PQresultStatus (result);
67  if ( (PGRES_COMMAND_OK != est) &&
68  (PGRES_TUPLES_OK != est) )
69  {
70  const char *sqlstate;
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 (connection));
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 (connection));
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 (connection));
129  }
131 }
132 
133 
152  const char *statement_name,
153  const struct GNUNET_PQ_QueryParam *params)
154 {
155  PGresult *result;
156  enum GNUNET_DB_QueryStatus qs;
157 
158  result = GNUNET_PQ_exec_prepared (connection,
159  statement_name,
160  params);
161  qs = GNUNET_PQ_eval_result (connection,
162  statement_name,
163  result);
165  {
166  const char *tuples;
167 
168  /* What an awful API, this function really does return a string */
169  tuples = PQcmdTuples (result);
170  if (NULL != tuples)
171  qs = strtol (tuples, NULL, 10);
172  }
173  PQclear (result);
174  return qs;
175 }
176 
177 
195  const char *statement_name,
196  const struct GNUNET_PQ_QueryParam *params,
198  void *rh_cls)
199 {
200  PGresult *result;
201  enum GNUNET_DB_QueryStatus qs;
202  unsigned int ret;
203 
204  result = GNUNET_PQ_exec_prepared (connection,
205  statement_name,
206  params);
207  qs = GNUNET_PQ_eval_result (connection,
208  statement_name,
209  result);
210  if (qs < 0)
211  {
212  PQclear (result);
213  return qs;
214  }
215  ret = PQntuples (result);
216  if (NULL != rh)
217  rh (rh_cls,
218  result,
219  ret);
220  PQclear (result);
221  return ret;
222 }
223 
224 
242  const char *statement_name,
243  const struct GNUNET_PQ_QueryParam *params,
244  struct GNUNET_PQ_ResultSpec *rs)
245 {
246  PGresult *result;
247  enum GNUNET_DB_QueryStatus qs;
248 
249  result = GNUNET_PQ_exec_prepared (connection,
250  statement_name,
251  params);
252  qs = GNUNET_PQ_eval_result (connection,
253  statement_name,
254  result);
255  if (qs < 0)
256  {
257  PQclear (result);
258  return qs;
259  }
260  if (0 == PQntuples (result))
261  {
262  PQclear (result);
264  }
265  if (1 != PQntuples (result))
266  {
267  /* more than one result, but there must be at most one */
268  GNUNET_break (0);
269  PQclear (result);
271  }
272  if (GNUNET_OK !=
273  GNUNET_PQ_extract_result (result,
274  rs,
275  0))
276  {
277  PQclear (result);
279  }
280  PQclear (result);
282 }
283 
284 
285 /* end of pq/pq_eval.c */
#define PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE
Error code returned by Postgres on serialization failure.
Definition: pq_eval.c:43
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_singleton_select(PGconn *connection, 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:241
Description of a DB result cell.
A soft error occurred, retrying the transaction may succeed.
Definition: gnunet_db_lib.h:45
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
static int ret
Final status code.
Definition: gnunet-arm.c:89
A hard error occurred, retrying will not help.
Definition: gnunet_db_lib.h:39
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define PQ_DIAG_SQLSTATE_DEADLOCK
Error code returned by Postgres for deadlock.
Definition: pq_eval.c:33
#define PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION
Error code returned by Postgres for uniqueness violation.
Definition: pq_eval.c:38
static int result
Global testing status.
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_multi_select(PGconn *connection, 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:194
PGresult * GNUNET_PQ_exec_prepared(PGconn *db_conn, const char *name, const struct GNUNET_PQ_QueryParam *params)
Execute a prepared statement.
Definition: pq.c:41
helper functions for Postgres DB interactions
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_result(PGconn *connection, const char *statement_name, PGresult *result)
Check the result&#39;s error code to see what happened.
Definition: pq_eval.c:60
The transaction succeeded, and yielded one result.
Definition: gnunet_db_lib.h:58
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:63
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...
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
Definition: gnunet_db_lib.h:34
#define GNUNET_log_from(kind, comp,...)
The transaction succeeded, but yielded zero results.
Definition: gnunet_db_lib.h:53
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_non_select(PGconn *connection, const char *statement_name, const struct GNUNET_PQ_QueryParam *params)
Execute a named prepared statement that is NOT a SELECT statement in connnection using the given para...
Definition: pq_eval.c:151
int 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:144