GNUnet  0.19.3
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
Return value of the commandline.
Definition: gnunet-abd.c:81
uint16_t status
See PRISM_STATUS_*-constants.
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:325
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:32
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:132
#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:66
Description of a DB result cell.