GNUnet  0.20.0
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 "gnunet_pq_lib.h"
29 #include "pq.h"
30 
31 
32 PGresult *
34  const char *name,
35  const struct GNUNET_PQ_QueryParam *params)
36 {
37  unsigned int len;
38 
40  "Running prepared statement `%s' on %p\n",
41  name,
42  db);
43  /* count the number of parameters */
44  len = 0;
45  for (unsigned int i = 0; 0 != params[i].num_params; i++)
46  len += params[i].num_params;
47 
48  /* new scope to allow stack allocation without alloca */
49  {
50  /* Scratch buffer for temporary storage */
51  void *scratch[GNUNET_NZL (len)];
52  /* Parameter array we are building for the query */
53  void *param_values[GNUNET_NZL (len)];
54  int param_lengths[GNUNET_NZL (len)];
55  int param_formats[GNUNET_NZL (len)];
56  unsigned int off;
57  /* How many entries in the scratch buffer are in use? */
58  unsigned int soff;
59  PGresult *res;
60  int ret;
61  ConnStatusType status;
62 
63  off = 0;
64  soff = 0;
65  for (unsigned int i = 0; 0 != params[i].num_params; i++)
66  {
67  const struct GNUNET_PQ_QueryParam *x = &params[i];
68 
69  ret = x->conv (x->conv_cls,
70  x->data,
71  x->size,
72  &param_values[off],
73  &param_lengths[off],
74  &param_formats[off],
75  x->num_params,
76  &scratch[soff],
77  len - soff);
78  if (ret < 0)
79  {
80  for (off = 0; off < soff; off++)
81  GNUNET_free (scratch[off]);
82  return NULL;
83  }
84  soff += ret;
85  off += x->num_params;
86  }
87  GNUNET_assert (off == len);
89  "pq",
90  "Executing prepared SQL statement `%s'\n",
91  name);
92  res = PQexecPrepared (db->conn,
93  name,
94  len,
95  (const char **) param_values,
96  param_lengths,
97  param_formats,
98  1);
100  "pq",
101  "Execution of prepared SQL statement `%s' finished (%s)\n",
102  name,
103  PQresStatus (PQresultStatus (res)));
104  if ( (PGRES_COMMAND_OK != PQresultStatus (res)) &&
105  (CONNECTION_OK != (status = PQstatus (db->conn))) )
106  {
108  "pq",
109  "Database disconnected on SQL statement `%s' (reconnecting)\n",
110  name);
112  res = NULL;
113  }
114 
115  for (off = 0; off < soff; off++)
116  GNUNET_free (scratch[off]);
117  return res;
118  }
119 }
120 
121 
122 void
124  const struct GNUNET_PQ_QueryParam *params)
125 {
126  for (unsigned int i = 0; 0 != params[i].num_params; i++)
127  {
128  const struct GNUNET_PQ_QueryParam *x = &params[i];
129 
130  if ((NULL != x->conv_cls) &&
131  (NULL != x->conv_cls_cleanup))
132  x->conv_cls_cleanup (x->conv_cls);
133  }
134 
135 }
136 
137 
138 void
140 {
141  for (unsigned int i = 0; NULL != rs[i].conv; i++)
142  if (NULL != rs[i].cleaner)
143  rs[i].cleaner (rs[i].cls,
144  rs[i].dst);
145 }
146 
147 
150  struct GNUNET_PQ_ResultSpec *rs,
151  int row)
152 {
153  unsigned int i;
154 
155  if (NULL == result)
156  return GNUNET_SYSERR;
157  for (i = 0; NULL != rs[i].conv; i++)
158  {
159  struct GNUNET_PQ_ResultSpec *spec;
161 
162  spec = &rs[i];
163  ret = spec->conv (spec->cls,
164  result,
165  row,
166  spec->fname,
167  &spec->dst_size,
168  spec->dst);
169  switch (ret)
170  {
171  case GNUNET_OK:
172  /* canonical case, continue below */
173  if (NULL != spec->is_null)
174  *spec->is_null = false;
175  break;
176  case GNUNET_NO:
177  if (spec->is_nullable)
178  {
179  if (NULL != spec->is_null)
180  *spec->is_null = true;
181  continue;
182  }
184  "NULL field encountered for `%s' where non-NULL was required\n",
185  spec->fname);
186  goto cleanup;
187  case GNUNET_SYSERR:
189  "Failed to extract field `%s'\n",
190  spec->fname);
191  GNUNET_break (0);
192  goto cleanup;
193  }
194  if (NULL != spec->result_size)
195  *spec->result_size = spec->dst_size;
196  }
197  return GNUNET_OK;
198 cleanup:
199  for (unsigned int j = 0; j < i; j++)
200  if (NULL != rs[j].cleaner)
201  rs[j].cleaner (rs[j].cls,
202  rs[j].dst);
203  return GNUNET_SYSERR;
204 }
205 
206 
207 /* end of pq/pq.c */
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static int res
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
uint16_t status
See PRISM_STATUS_*-constants.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static int result
Global testing status.
static struct GNUNET_FS_DirectoryBuilder * db
Definition: gnunet-search.c:97
helper functions for Postgres DB interactions
void GNUNET_PQ_reconnect(struct GNUNET_PQ_Context *db)
Reinitialize the database db.
Definition: pq_connect.c:427
#define GNUNET_log(kind,...)
#define GNUNET_log_from(kind, comp,...)
#define GNUNET_NZL(l)
Macro used to avoid using 0 for the length of a variable-size array (Non-Zero-Length).
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#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
#define GNUNET_free(ptr)
Wrapper around free.
const char * name
void GNUNET_PQ_cleanup_query_params_closures(const struct GNUNET_PQ_QueryParam *params)
Must be called to cleanup memory from closures after the query parameters have been used as much as n...
Definition: pq.c:123
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
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:139
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
shared internal data structures of libgnunetpq
Handle to Postgres database.
Definition: pq.h:36
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:83
void * conv_cls
Closure for conv.
Definition: gnunet_pq_lib.h:95
const void * data
Data or NULL.
GNUNET_PQ_QueryConverter conv
Function for how to handle this type of entry.
Definition: gnunet_pq_lib.h:87
unsigned int num_params
Number of parameters eaten by this operation.
GNUNET_PQ_QueryConverter_Cleanup conv_cls_cleanup
Function to cleanup the closure conv_cls, may be NULL.
size_t size
Size of data.
Description of a DB result cell.
const char * fname
Field name of the desired result.
bool * is_null
Points to a location where we should store "true" if the result found is NULL, and otherwise "false".
void * dst
Destination for the data.
bool is_nullable
True if NULL is allowed for a value in the database.
void * cls
Closure for conv and cleaner.
GNUNET_PQ_ResultConverter conv
What is the format of the result?
size_t * result_size
Where to store actual size of the result.
GNUNET_PQ_ResultCleanup cleaner
Function to clean up result data, NULL if cleanup is not necessary.
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...