GNUnet 0.22.2
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
32PGresult *
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]);
83 "Conversion at index %u failed\n",
84 i);
85 return NULL;
86 }
87 soff += ret;
88 off += x->num_params;
89 }
90 GNUNET_assert (off == len);
92 "pq",
93 "Executing prepared SQL statement `%s'\n",
94 name);
95 res = PQexecPrepared (db->conn,
96 name,
97 len,
98 (const char **) param_values,
99 param_lengths,
100 param_formats,
101 1);
103 "pq",
104 "Execution of prepared SQL statement `%s' finished (%s)\n",
105 name,
106 PQresStatus (PQresultStatus (res)));
107 if ( (PGRES_COMMAND_OK != PQresultStatus (res)) &&
108 (CONNECTION_OK != (status = PQstatus (db->conn))) )
109 {
111 "pq",
112 "Database disconnected on SQL statement `%s' (reconnecting)\n",
113 name);
115 res = NULL;
116 }
117
118 for (off = 0; off < soff; off++)
119 GNUNET_free (scratch[off]);
120 return res;
121 }
122}
123
124
125void
127 const struct GNUNET_PQ_QueryParam *params)
128{
129 for (unsigned int i = 0; 0 != params[i].num_params; i++)
130 {
131 const struct GNUNET_PQ_QueryParam *x = &params[i];
132
133 if ((NULL != x->conv_cls) &&
134 (NULL != x->conv_cls_cleanup))
136 }
137
138}
139
140
141void
143{
144 for (unsigned int i = 0; NULL != rs[i].conv; i++)
145 if (NULL != rs[i].cleaner)
146 rs[i].cleaner (rs[i].cls,
147 rs[i].dst);
148}
149
150
153 struct GNUNET_PQ_ResultSpec *rs,
154 int row)
155{
156 unsigned int i;
157
158 if (NULL == result)
159 return GNUNET_SYSERR;
160 for (i = 0; NULL != rs[i].conv; i++)
161 {
162 struct GNUNET_PQ_ResultSpec *spec;
164
165 spec = &rs[i];
166 ret = spec->conv (spec->cls,
167 result,
168 row,
169 spec->fname,
170 &spec->dst_size,
171 spec->dst);
172 switch (ret)
173 {
174 case GNUNET_OK:
175 /* canonical case, continue below */
176 if (NULL != spec->is_null)
177 *spec->is_null = false;
178 break;
179 case GNUNET_NO:
180 if (spec->is_nullable)
181 {
182 if (NULL != spec->is_null)
183 *spec->is_null = true;
184 continue;
185 }
187 "NULL field encountered for `%s' where non-NULL was required\n",
188 spec->fname);
189 goto cleanup;
190 case GNUNET_SYSERR:
192 "Failed to extract field `%s'\n",
193 spec->fname);
194 GNUNET_break (0);
195 goto cleanup;
196 }
197 if (NULL != spec->result_size)
198 *spec->result_size = spec->dst_size;
199 }
200 return GNUNET_OK;
201cleanup:
202 for (unsigned int j = 0; j < i; j++)
203 if (NULL != rs[j].cleaner)
204 rs[j].cleaner (rs[j].cls,
205 rs[j].dst);
206 return GNUNET_SYSERR;
207}
208
209
210/* end of pq/pq.c */
static int ret
Final status code.
Definition: gnunet-arm.c:93
static void cleanup(void *cls)
Disconnect and shutdown.
Definition: gnunet-did.c:131
static char * name
Name (label) of the records to list.
static char * res
Currently read line or NULL on EOF.
static int status
The program status; 0 for success.
Definition: gnunet-nse.c:39
static int result
Global testing status.
static struct GNUNET_FS_DirectoryBuilder * db
helper functions for Postgres DB interactions
void GNUNET_PQ_reconnect(struct GNUNET_PQ_Context *db)
Reinitialize the database db.
Definition: pq_connect.c:562
#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.
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:126
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:142
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:152
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...