GNUnet  0.11.x
pq.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2014, 2015, 2016, 2017, 2019, 2020 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  */
27 #include "platform.h"
28 #include "pq.h"
29 
30 
31 PGresult *
33  const char *name,
34  const struct GNUNET_PQ_QueryParam *params)
35 {
36  unsigned int len;
37 
39  "Running prepared statement `%s' on %p\n",
40  name,
41  db);
42  /* count the number of parameters */
43  len = 0;
44  for (unsigned int i = 0; 0 != params[i].num_params; i++)
45  len += params[i].num_params;
46 
47  /* new scope to allow stack allocation without alloca */
48  {
49  /* Scratch buffer for temporary storage */
50  void *scratch[len];
51  /* Parameter array we are building for the query */
52  void *param_values[len];
53  int param_lengths[len];
54  int param_formats[len];
55  unsigned int off;
56  /* How many entries in the scratch buffer are in use? */
57  unsigned int soff;
58  PGresult *res;
59  int ret;
60  ConnStatusType status;
61 
62  off = 0;
63  soff = 0;
64  for (unsigned int i = 0; 0 != params[i].num_params; i++)
65  {
66  const struct GNUNET_PQ_QueryParam *x = &params[i];
67 
68  ret = x->conv (x->conv_cls,
69  x->data,
70  x->size,
71  &param_values[off],
72  &param_lengths[off],
73  &param_formats[off],
74  x->num_params,
75  &scratch[soff],
76  len - soff);
77  if (ret < 0)
78  {
79  for (off = 0; off < soff; off++)
80  GNUNET_free (scratch[off]);
81  return NULL;
82  }
83  soff += ret;
84  off += x->num_params;
85  }
86  GNUNET_assert (off == len);
88  "pq",
89  "Executing prepared SQL statement `%s'\n",
90  name);
91  res = PQexecPrepared (db->conn,
92  name,
93  len,
94  (const char **) param_values,
95  param_lengths,
96  param_formats,
97  1);
98  if ( (PGRES_COMMAND_OK != PQresultStatus (res)) &&
99  (CONNECTION_OK != (status = PQstatus (db->conn))) )
100  {
102  "pq",
103  "Database disconnected on SQL statement `%s' (reconnecting)\n",
104  name);
105  GNUNET_PQ_reconnect (db);
106  res = NULL;
107  }
108 
109  for (off = 0; off < soff; off++)
110  GNUNET_free (scratch[off]);
111  return res;
112  }
113 }
114 
115 
116 void
118 {
119  for (unsigned int i = 0; NULL != rs[i].conv; i++)
120  if (NULL != rs[i].cleaner)
121  rs[i].cleaner (rs[i].cls,
122  rs[i].dst);
123 }
124 
125 
128  struct GNUNET_PQ_ResultSpec *rs,
129  int row)
130 {
131  unsigned int i;
132 
133  if (NULL == result)
134  return GNUNET_SYSERR;
135  for (i = 0; NULL != rs[i].conv; i++)
136  {
137  struct GNUNET_PQ_ResultSpec *spec;
139 
140  spec = &rs[i];
141  ret = spec->conv (spec->cls,
142  result,
143  row,
144  spec->fname,
145  &spec->dst_size,
146  spec->dst);
147  switch (ret)
148  {
149  case GNUNET_OK:
150  /* canonical case, continue below */
151  if (NULL != spec->is_null)
152  *spec->is_null = false;
153  break;
154  case GNUNET_NO:
155  if (spec->is_nullable)
156  {
157  if (NULL != spec->is_null)
158  *spec->is_null = true;
159  continue;
160  }
162  "NULL field encountered for `%s' where non-NULL was required\n",
163  spec->fname);
164  goto cleanup;
165  case GNUNET_SYSERR:
166  GNUNET_break (0);
167  goto cleanup;
168  }
169  if (NULL != spec->result_size)
170  *spec->result_size = spec->dst_size;
171  }
172  return GNUNET_OK;
173 cleanup:
174  for (unsigned int j = 0; j < i; j++)
175  if (NULL != rs[j].cleaner)
176  rs[j].cleaner (rs[j].cls,
177  rs[j].dst);
178  return GNUNET_SYSERR;
179 }
180 
181 
182 /* end of pq/pq.c */
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
GNUNET_PQ_QueryConverter conv
Function for how to handle this type of entry.
Definition: gnunet_pq_lib.h:69
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
void GNUNET_PQ_reconnect(struct GNUNET_PQ_Context *db)
Reinitialize the database db.
Definition: pq_connect.c:295
const char * fname
Field name of the desired result.
Description of a DB result cell.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:83
bool is_nullable
True if NULL is allowed for a value in the database.
const void * data
Data or NULL.
Definition: gnunet_pq_lib.h:79
void GNUNET_PQ_cleanup_result(struct GNUNET_PQ_ResultSpec *rs)
Free all memory that was allocated in rs during GNUNET_PQ_extract_result().
Definition: pq.c:117
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
PGconn * conn
Actual connection.
Definition: pq.h:39
shared internal data structures of libgnunetpq
void * cls
Closure for conv and cleaner.
uint16_t status
See PRISM_STATUS_*-constants.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
void * conv_cls
Closure for conv.
Definition: gnunet_pq_lib.h:74
static int result
Global testing status.
size_t dst_size
Allowed size for the data, 0 for variable-size (in this case, the type of dst is a void ** and we nee...
static int res
bool * is_null
Points to a location where we should store "true" if the result found is NULL, and otherwise "false"...
GNUNET_PQ_ResultCleanup cleaner
Function to clean up result data, NULL if cleanup is not necessary.
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:127
unsigned int num_params
Number of parameters eaten by this operation.
Definition: gnunet_pq_lib.h:89
static struct GNUNET_FS_DirectoryBuilder * db
Definition: gnunet-search.c:41
const char * name
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:64
#define GNUNET_log(kind,...)
void * dst
Destination for the data.
size_t size
Size of data.
Definition: gnunet_pq_lib.h:84
#define GNUNET_log_from(kind, comp,...)
size_t * result_size
Where to store actual size of the result.
GNUNET_PQ_ResultConverter conv
What is the format of the result?
Handle to Postgres database.
Definition: pq.h:34
#define GNUNET_free(ptr)
Wrapper around free.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...